| // 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 "android/emulation/DmaMap.h" |
| |
| #include "android/base/containers/Lookup.h" |
| #include "android/base/memory/LazyInstance.h" |
| |
| #include <type_traits> |
| #include <inttypes.h> |
| #include <stdio.h> |
| |
| #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 { |
| E("guest paddr 0x%llx not alloced!", |
| (unsigned long long)guest_paddr); |
| 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); |
| } |
| } |
| |
| } // namespace android |
| |
| |