// Copyright 2016 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "DmaMap.h" #include "aemu/base/containers/Lookup.h" #include "aemu/base/files/StreamSerializing.h" #include "host-common/android_pipe_device.h" #include #include #include #define DEBUG 0 #if DEBUG >= 1 #define D(fmt,...) fprintf(stderr, "DmaMap: %s: " fmt "\n", __func__, ##__VA_ARGS__); #else #define D(...) (void)0 #endif #if DEBUG >= 2 #define DD(fmt,...) fprintf(stderr, "DmaMap: %s: " fmt "\n", __func__, ##__VA_ARGS__); #else #define DD(...) (void)0 #endif #define E(fmt,...) fprintf(stderr, "DmaMap: ERROR: %s: " fmt "\n", __func__, ##__VA_ARGS__); namespace android { static DmaMap* sInstance = nullptr; DmaMap* DmaMap::get() { return sInstance; } DmaMap* DmaMap::set(DmaMap* dmaMap) { DmaMap* result = sInstance; sInstance = dmaMap; return result; } void DmaMap::addBuffer(void* hwpipe, uint64_t guest_paddr, uint64_t bufferSize) { D("guest paddr 0x%llx bufferSize %llu", (unsigned long long)guest_paddr, (unsigned long long)bufferSize); DmaBufferInfo info; info.hwpipe = hwpipe; info.guestAddr = guest_paddr; // guest address info.bufferSize = bufferSize; // size of buffer info.currHostAddr = kNullopt; // no current host address android::base::AutoWriteLock lock(mLock); createMappingLocked(&info); mDmaBuffers[guest_paddr] = info; } void DmaMap::removeBuffer(uint64_t guest_paddr) { D("guest paddr 0x%llx", (unsigned long long)guest_paddr); android::base::AutoWriteLock lock(mLock); if (auto info = android::base::find(mDmaBuffers, guest_paddr)) { removeMappingLocked(info); mDmaBuffers.erase(guest_paddr); } else { E("guest addr 0x%llx not alloced!", (unsigned long long)guest_paddr); } } void* DmaMap::getHostAddr(uint64_t guest_paddr) { DD("guest paddr 0x%llx", (unsigned long long)guest_paddr); android::base::AutoReadLock rlock(mLock); if (auto info = android::base::find(mDmaBuffers, guest_paddr)) { if (info->currHostAddr) { DD("guest paddr 0x%llx -> host 0x%llx valid", (unsigned long long)guest_paddr, (unsigned long long)(*info->currHostAddr)); return *(info->currHostAddr); } else { rlock.unlockRead(); android::base::AutoWriteLock wlock(mLock); createMappingLocked(info); D("guest paddr 0x%llx -> host 0x%llx valid (new)", (unsigned long long)guest_paddr, (unsigned long long)*(info->currHostAddr)); return *(info->currHostAddr); } } else { E("guest paddr 0x%llx not alloced!", (unsigned long long)guest_paddr); return 0; } } void DmaMap::invalidateHostMappings() { android::base::AutoWriteLock lock(mLock); for (auto& it : mDmaBuffers) { removeMappingLocked(&it.second); } } void DmaMap::resetHostMappings() { android::base::AutoWriteLock lock(mLock); for (auto& it : mDmaBuffers) { removeMappingLocked(&it.second); } mDmaBuffers.clear(); } void* DmaMap::getPipeInstance(uint64_t guest_paddr) { android::base::AutoReadLock lock(mLock); if (auto info = android::base::find(mDmaBuffers, guest_paddr)) { return info->hwpipe; } else { return nullptr; } } void DmaMap::createMappingLocked(DmaBufferInfo* info) { info->currHostAddr = doMap(info->guestAddr, info->bufferSize); } void DmaMap::removeMappingLocked(DmaBufferInfo* info ) { if (info->currHostAddr) { doUnmap(*(info->currHostAddr), info->bufferSize); info->currHostAddr = kNullopt; D("guest addr 0x%llx host mapping 0x%llx removed.", (unsigned long long)info->guestAddr, (unsigned long long)info->currHostAddr); } else { D("guest addr 0x%llx has no host mapping. don't remove.", (unsigned long long)info->guestAddr); } } void DmaMap::save(android::base::Stream* stream) const { saveCollection(stream, mDmaBuffers, [](android::base::Stream* stream, const DmaBufferMap::value_type& v) { stream->putBe64(v.first); // guest paddr stream->putBe32(android_pipe_get_id(v.second.hwpipe)); stream->putBe64(v.second.guestAddr); // guest addr stream->putBe64(v.second.bufferSize); // buffer size // don't save current host addr as it is invalidated. }); } void DmaMap::load(android::base::Stream* stream) { mDmaBuffers.clear(); loadCollection(stream, &mDmaBuffers, [](android::base::Stream* stream) { uint64_t gpa = stream->getBe64(); DmaBufferInfo info; info.hwpipe = android_pipe_lookup_by_id(stream->getBe32()), info.guestAddr = stream->getBe64(), info.bufferSize = stream->getBe64(), info.currHostAddr = kNullopt; return std::make_pair(gpa, info); }); } } // namespace android