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