1 // Copyright 2016 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "DmaMap.h"
16
17 #include "aemu/base/containers/Lookup.h"
18 #include "aemu/base/files/StreamSerializing.h"
19 #include "host-common/android_pipe_device.h"
20
21 #include <type_traits>
22 #include <inttypes.h>
23 #include <stdio.h>
24
25 #define DEBUG 0
26
27 #if DEBUG >= 1
28 #define D(fmt,...) fprintf(stderr, "DmaMap: %s: " fmt "\n", __func__, ##__VA_ARGS__);
29 #else
30 #define D(...) (void)0
31 #endif
32
33 #if DEBUG >= 2
34 #define DD(fmt,...) fprintf(stderr, "DmaMap: %s: " fmt "\n", __func__, ##__VA_ARGS__);
35 #else
36 #define DD(...) (void)0
37 #endif
38
39 #define E(fmt,...) fprintf(stderr, "DmaMap: ERROR: %s: " fmt "\n", __func__, ##__VA_ARGS__);
40
41 namespace android {
42
43 static DmaMap* sInstance = nullptr;
44
get()45 DmaMap* DmaMap::get() {
46 return sInstance;
47 }
48
set(DmaMap * dmaMap)49 DmaMap* DmaMap::set(DmaMap* dmaMap) {
50 DmaMap* result = sInstance;
51 sInstance = dmaMap;
52 return result;
53 }
54
addBuffer(void * hwpipe,uint64_t guest_paddr,uint64_t bufferSize)55 void DmaMap::addBuffer(void* hwpipe,
56 uint64_t guest_paddr,
57 uint64_t bufferSize) {
58 D("guest paddr 0x%llx bufferSize %llu",
59 (unsigned long long)guest_paddr,
60 (unsigned long long)bufferSize);
61 DmaBufferInfo info;
62 info.hwpipe = hwpipe;
63 info.guestAddr = guest_paddr; // guest address
64 info.bufferSize = bufferSize; // size of buffer
65 info.currHostAddr = kNullopt; // no current host address
66 android::base::AutoWriteLock lock(mLock);
67 createMappingLocked(&info);
68 mDmaBuffers[guest_paddr] = info;
69 }
70
removeBuffer(uint64_t guest_paddr)71 void DmaMap::removeBuffer(uint64_t guest_paddr) {
72 D("guest paddr 0x%llx", (unsigned long long)guest_paddr);
73 android::base::AutoWriteLock lock(mLock);
74 if (auto info = android::base::find(mDmaBuffers, guest_paddr)) {
75 removeMappingLocked(info);
76 mDmaBuffers.erase(guest_paddr);
77 } else {
78 E("guest addr 0x%llx not alloced!",
79 (unsigned long long)guest_paddr);
80 }
81 }
82
getHostAddr(uint64_t guest_paddr)83 void* DmaMap::getHostAddr(uint64_t guest_paddr) {
84 DD("guest paddr 0x%llx", (unsigned long long)guest_paddr);
85 android::base::AutoReadLock rlock(mLock);
86 if (auto info = android::base::find(mDmaBuffers, guest_paddr)) {
87 if (info->currHostAddr) {
88 DD("guest paddr 0x%llx -> host 0x%llx valid",
89 (unsigned long long)guest_paddr,
90 (unsigned long long)(*info->currHostAddr));
91 return *(info->currHostAddr);
92 } else {
93 rlock.unlockRead();
94 android::base::AutoWriteLock wlock(mLock);
95 createMappingLocked(info);
96 D("guest paddr 0x%llx -> host 0x%llx valid (new)",
97 (unsigned long long)guest_paddr,
98 (unsigned long long)*(info->currHostAddr));
99 return *(info->currHostAddr);
100 }
101 } else {
102 E("guest paddr 0x%llx not alloced!",
103 (unsigned long long)guest_paddr);
104 return 0;
105 }
106 }
107
invalidateHostMappings()108 void DmaMap::invalidateHostMappings() {
109 android::base::AutoWriteLock lock(mLock);
110 for (auto& it : mDmaBuffers) {
111 removeMappingLocked(&it.second);
112 }
113 }
114
resetHostMappings()115 void DmaMap::resetHostMappings() {
116 android::base::AutoWriteLock lock(mLock);
117 for (auto& it : mDmaBuffers) {
118 removeMappingLocked(&it.second);
119 }
120 mDmaBuffers.clear();
121 }
122
getPipeInstance(uint64_t guest_paddr)123 void* DmaMap::getPipeInstance(uint64_t guest_paddr) {
124 android::base::AutoReadLock lock(mLock);
125 if (auto info = android::base::find(mDmaBuffers, guest_paddr)) {
126 return info->hwpipe;
127 } else {
128 return nullptr;
129 }
130 }
131
createMappingLocked(DmaBufferInfo * info)132 void DmaMap::createMappingLocked(DmaBufferInfo* info) {
133 info->currHostAddr = doMap(info->guestAddr, info->bufferSize);
134 }
135
removeMappingLocked(DmaBufferInfo * info)136 void DmaMap::removeMappingLocked(DmaBufferInfo* info ) {
137 if (info->currHostAddr) {
138 doUnmap(*(info->currHostAddr), info->bufferSize);
139 info->currHostAddr = kNullopt;
140 D("guest addr 0x%llx host mapping 0x%llx removed.",
141 (unsigned long long)info->guestAddr,
142 (unsigned long long)info->currHostAddr);
143 } else {
144 D("guest addr 0x%llx has no host mapping. don't remove.",
145 (unsigned long long)info->guestAddr);
146 }
147 }
148
save(android::base::Stream * stream) const149 void DmaMap::save(android::base::Stream* stream) const {
150 saveCollection(stream, mDmaBuffers,
151 [](android::base::Stream* stream,
152 const DmaBufferMap::value_type& v) {
153 stream->putBe64(v.first); // guest paddr
154 stream->putBe32(android_pipe_get_id(v.second.hwpipe));
155 stream->putBe64(v.second.guestAddr); // guest addr
156 stream->putBe64(v.second.bufferSize); // buffer size
157 // don't save current host addr as it is invalidated.
158 });
159 }
160
load(android::base::Stream * stream)161 void DmaMap::load(android::base::Stream* stream) {
162 mDmaBuffers.clear();
163 loadCollection(stream, &mDmaBuffers,
164 [](android::base::Stream* stream) {
165 uint64_t gpa = stream->getBe64();
166
167 DmaBufferInfo info;
168 info.hwpipe = android_pipe_lookup_by_id(stream->getBe32()),
169 info.guestAddr = stream->getBe64(),
170 info.bufferSize = stream->getBe64(),
171 info.currHostAddr = kNullopt;
172 return std::make_pair(gpa, info);
173 });
174 }
175
176 } // namespace android
177
178
179