1// Copyright (C) 2019 The Android Open Source Project 2// Copyright (C) 2019 Google Inc. 3// 4// Licensed under the Apache License, Version 2.0 (the "License"); 5// you may not use this file except in compliance with the License. 6// You may obtain a copy of the License at 7// 8// http://www.apache.org/licenses/LICENSE-2.0 9// 10// Unless required by applicable law or agreed to in writing, software 11// distributed under the License is distributed on an "AS IS" BASIS, 12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13// See the License for the specific language governing permissions and 14// limitations under the License. 15 16#include "android/emulation/hostdevices/HostAddressSpace.h" 17 18#include <memory> 19 20#if PLATFORM_SDK_VERSION < 26 21#include <cutils/log.h> 22#else 23#include <log/log.h> 24#endif 25 26#include <errno.h> 27#include "goldfish_address_space.h" 28 29namespace { 30 31const int HOST_MEMORY_ALLOCATOR_COMMAND_ALLOCATE_ID = 1; 32const int HOST_MEMORY_ALLOCATOR_COMMAND_UNALLOCATE_ID = 2; 33 34} // namsepace 35 36using android::HostAddressSpaceDevice; 37using android::emulation::AddressSpaceDevicePingInfo; 38 39GoldfishAddressSpaceBlockProvider::GoldfishAddressSpaceBlockProvider(GoldfishAddressSpaceSubdeviceType subdevice) 40 : m_handle(HostAddressSpaceDevice::get()->open()) 41{ 42 if ((subdevice != GoldfishAddressSpaceSubdeviceType::NoSubdevice) && is_opened()) { 43 AddressSpaceDevicePingInfo request; 44 ::memset(&request, 0, sizeof(request)); 45 request.metadata = subdevice; 46 47 HostAddressSpaceDevice::get()->ping(m_handle, &request); 48 } 49} 50 51GoldfishAddressSpaceBlockProvider::~GoldfishAddressSpaceBlockProvider() 52{ 53 if (is_opened()) { 54 HostAddressSpaceDevice::get()->close(m_handle); 55 } 56} 57 58bool GoldfishAddressSpaceBlockProvider::is_opened() const 59{ 60 return m_handle > 0; 61} 62 63void GoldfishAddressSpaceBlockProvider::close() 64{ 65 if (is_opened()) { 66 HostAddressSpaceDevice::get()->close(m_handle); 67 m_handle = 0; 68 } 69} 70 71address_space_handle_t GoldfishAddressSpaceBlockProvider::release() 72{ 73 address_space_handle_t handle = m_handle; 74 m_handle = 0; 75 return handle; 76} 77 78void GoldfishAddressSpaceBlockProvider::closeHandle(address_space_handle_t handle) 79{ 80 HostAddressSpaceDevice::get()->close(handle); 81} 82 83GoldfishAddressSpaceBlock::GoldfishAddressSpaceBlock() 84 : m_handle(0) 85 , m_mmaped_ptr(NULL) 86 , m_phys_addr(0) 87 , m_host_addr(0) 88 , m_offset(0) 89 , m_size(0) 90 , m_is_shared_mapping(false) {} 91 92GoldfishAddressSpaceBlock::~GoldfishAddressSpaceBlock() 93{ 94 destroy(); 95} 96 97GoldfishAddressSpaceBlock &GoldfishAddressSpaceBlock::operator=(const GoldfishAddressSpaceBlock &rhs) 98{ 99 m_mmaped_ptr = rhs.m_mmaped_ptr; 100 m_phys_addr = rhs.m_phys_addr; 101 m_host_addr = rhs.m_host_addr; 102 m_offset = rhs.m_offset; 103 m_size = rhs.m_size; 104 m_is_shared_mapping = rhs.m_is_shared_mapping; 105 m_handle = rhs.m_handle; 106 return *this; 107} 108 109bool GoldfishAddressSpaceBlock::allocate(GoldfishAddressSpaceBlockProvider *provider, size_t size) 110{ 111 ALOGD("%s: Ask for block of size 0x%llx\n", __func__, 112 (unsigned long long)size); 113 114 destroy(); 115 116 if (!provider->is_opened()) { 117 return false; 118 } 119 120 m_size = size; 121 m_offset = 122 HostAddressSpaceDevice::get()->allocBlock( 123 provider->m_handle, size, &m_phys_addr); 124 m_handle = provider->m_handle; 125 m_is_shared_mapping = false; 126 127 return true; 128} 129 130bool GoldfishAddressSpaceBlock::claimShared(GoldfishAddressSpaceBlockProvider *provider, uint64_t offset, uint64_t size) 131{ 132 ALOGD("%s: Ask to claim region [0x%llx 0x%llx]\n", __func__, 133 (unsigned long long)offset, 134 (unsigned long long)offset + size); 135 136 destroy(); 137 138 if (!provider->is_opened()) { 139 return false; 140 } 141 142 int claimRes = HostAddressSpaceDevice::get()->claimShared( 143 provider->m_handle, offset, size); 144 145 if (claimRes) { 146 ALOGE("%s: failed to claim shared region. Error: %d\n", __func__, claimRes); 147 return false; 148 } 149 150 m_size = size; 151 m_offset = offset; 152 m_handle = provider->m_handle; 153 m_is_shared_mapping = true; 154 m_phys_addr = HostAddressSpaceDevice::get()->offsetToPhysAddr(m_offset); 155 156 return true; 157} 158 159uint64_t GoldfishAddressSpaceBlock::physAddr() const 160{ 161 return m_phys_addr; 162} 163 164uint64_t GoldfishAddressSpaceBlock::hostAddr() const 165{ 166 return m_host_addr; 167} 168 169// In the host implementation: 170// mmap: is done by interpreting |host_addr| as the actual host address. 171void *GoldfishAddressSpaceBlock::mmap(uint64_t host_addr) 172{ 173 if (m_size == 0) { 174 ALOGE("%s: called with zero size\n", __func__); 175 return NULL; 176 } 177 178 if (m_mmaped_ptr != nullptr) { 179 ALOGE("'mmap' called for an already mmaped address block 0x%llx %d", (unsigned long long)m_mmaped_ptr, nullptr == m_mmaped_ptr); 180 ::abort(); 181 } 182 183 m_mmaped_ptr = (void*)(uintptr_t)(host_addr & (~(PAGE_SIZE - 1))); 184 m_host_addr = host_addr; 185 186 return guestPtr(); 187} 188 189void *GoldfishAddressSpaceBlock::guestPtr() const 190{ 191 return reinterpret_cast<char *>(m_mmaped_ptr) + (m_host_addr & (PAGE_SIZE - 1)); 192} 193 194void GoldfishAddressSpaceBlock::destroy() 195{ 196 if (m_mmaped_ptr && m_size) { 197 m_mmaped_ptr = NULL; 198 } 199 200 if (m_size) { 201 if (m_is_shared_mapping) { 202 HostAddressSpaceDevice::get()->unclaimShared(m_handle, m_offset); 203 } else { 204 HostAddressSpaceDevice::get()->freeBlock(m_handle, m_offset); 205 } 206 m_phys_addr = 0; 207 m_host_addr = 0; 208 m_offset = 0; 209 m_size = 0; 210 } 211} 212 213void GoldfishAddressSpaceBlock::release() 214{ 215 m_handle = 0; 216 m_mmaped_ptr = NULL; 217 m_phys_addr = 0; 218 m_host_addr = 0; 219 m_offset = 0; 220 m_size = 0; 221} 222 223int GoldfishAddressSpaceBlock::memoryMap(void *addr, 224 size_t, 225 address_space_handle_t, 226 uint64_t, 227 void** dst) { 228 *dst = addr; 229 return 0; 230} 231 232void GoldfishAddressSpaceBlock::memoryUnmap(void *ptr, size_t size) {} 233 234GoldfishAddressSpaceHostMemoryAllocator::GoldfishAddressSpaceHostMemoryAllocator(bool useSharedSlots) 235 : m_provider(useSharedSlots 236 ? GoldfishAddressSpaceSubdeviceType::SharedSlotsHostMemoryAllocator 237 : GoldfishAddressSpaceSubdeviceType::HostMemoryAllocator), 238 m_useSharedSlots(useSharedSlots) 239{} 240 241bool GoldfishAddressSpaceHostMemoryAllocator::is_opened() const { return m_provider.is_opened(); } 242 243long GoldfishAddressSpaceHostMemoryAllocator::hostMalloc(GoldfishAddressSpaceBlock *block, size_t size) 244{ 245 if (size == 0) { 246 return -EINVAL; 247 } 248 if (block->size() > 0) { 249 return -EINVAL; 250 } 251 if (!m_provider.is_opened()) { 252 return -ENODEV; 253 } 254 255 AddressSpaceDevicePingInfo request; 256 if (m_useSharedSlots) { 257 ::memset(&request, 0, sizeof(request)); 258 request.size = block->size(); 259 request.metadata = HOST_MEMORY_ALLOCATOR_COMMAND_ALLOCATE_ID; 260 261 HostAddressSpaceDevice::get()->ping(m_provider.m_handle, &request); 262 263 block->claimShared(&m_provider, request.phys_addr, request.size); 264 265 void *hostPtr = HostAddressSpaceDevice::get()->getHostAddr(block->physAddr()); 266 block->mmap(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(hostPtr))); 267 } else { 268 if (!block->allocate(&m_provider, size)) { 269 return -ENOMEM; 270 } 271 272 ::memset(&request, 0, sizeof(request)); 273 request.phys_addr = block->physAddr(); 274 request.size = block->size(); 275 request.metadata = HOST_MEMORY_ALLOCATOR_COMMAND_ALLOCATE_ID; 276 277 HostAddressSpaceDevice::get()->ping(m_provider.m_handle, &request); 278 279 void *hostPtr = HostAddressSpaceDevice::get()->getHostAddr(block->physAddr()); 280 block->mmap(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(hostPtr))); 281 } 282 283 return 0; 284} 285 286void GoldfishAddressSpaceHostMemoryAllocator::hostFree(GoldfishAddressSpaceBlock *block) 287{ 288 if (block->size() == 0) { 289 return; 290 } 291 292 if (!m_provider.is_opened()) { 293 ALOGE("%s: device is not available", __func__); 294 ::abort(); 295 } 296 297 if (block->guestPtr()) { 298 AddressSpaceDevicePingInfo request; 299 ::memset(&request, 0, sizeof(request)); 300 request.phys_addr = block->physAddr(); 301 request.metadata = HOST_MEMORY_ALLOCATOR_COMMAND_UNALLOCATE_ID; 302 303 HostAddressSpaceDevice::get()->ping(m_provider.m_handle, &request); 304 } 305 306 block->replace(NULL); 307} 308 309address_space_handle_t goldfish_address_space_open() { 310 return HostAddressSpaceDevice::get()->open(); 311} 312 313void goldfish_address_space_close(address_space_handle_t handle) { 314 HostAddressSpaceDevice::get()->close(handle); 315} 316 317bool goldfish_address_space_allocate( 318 address_space_handle_t handle, 319 size_t size, uint64_t* phys_addr, uint64_t* offset) { 320 321 *offset = 322 HostAddressSpaceDevice::get()->allocBlock( 323 handle, size, phys_addr); 324 325 return true; 326} 327 328bool goldfish_address_space_free( 329 address_space_handle_t handle, uint64_t offset) { 330 HostAddressSpaceDevice::get()->freeBlock(handle, offset); 331 return true; 332} 333 334bool goldfish_address_space_claim_shared( 335 address_space_handle_t handle, uint64_t offset, uint64_t size) { 336 337 int claimRes = HostAddressSpaceDevice::get()->claimShared( 338 handle, offset, size); 339 340 if (claimRes) { 341 ALOGE("%s: failed to claim shared region. Error: %d\n", __func__, claimRes); 342 return false; 343 } 344 345 return true; 346} 347 348bool goldfish_address_space_unclaim_shared( 349 address_space_handle_t handle, uint64_t offset) { 350 HostAddressSpaceDevice::get()->unclaimShared(handle, offset); 351 return true; 352} 353 354// pgoff is the offset into the page to return in the result 355void* goldfish_address_space_map( 356 address_space_handle_t handle, 357 uint64_t offset, uint64_t size, 358 uint64_t pgoff) { 359 360 (void)size; 361 362 void* res = HostAddressSpaceDevice::get()-> 363 getHostAddr( 364 HostAddressSpaceDevice::get()->offsetToPhysAddr(offset)); 365 366 if (!res) { 367 ALOGE("%s: failed to map. errno: %d\n", __func__, errno); 368 return nullptr; 369 } 370 371 return (void*)(((char*)res) + (uintptr_t)(pgoff & (PAGE_SIZE - 1))); 372} 373 374// same address space 375void goldfish_address_space_unmap(void*, uint64_t) { } 376 377bool goldfish_address_space_set_subdevice_type( 378 address_space_handle_t handle, GoldfishAddressSpaceSubdeviceType type, 379 address_space_handle_t* handle_out) { 380 struct address_space_ping request; 381 request.metadata = (uint64_t)type; 382 *handle_out = handle; 383 return goldfish_address_space_ping(handle, &request); 384} 385 386bool goldfish_address_space_ping( 387 address_space_handle_t handle, 388 struct address_space_ping* ping) { 389 390 AddressSpaceDevicePingInfo* asHostPingInfo = 391 reinterpret_cast<AddressSpaceDevicePingInfo*>(ping); 392 393 HostAddressSpaceDevice::get()->ping(handle, asHostPingInfo); 394 395 return true; 396} 397