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 destroy(); 112 113 if (!provider->is_opened()) { 114 return false; 115 } 116 117 m_size = size; 118 m_offset = 119 HostAddressSpaceDevice::get()->allocBlock( 120 provider->m_handle, size, &m_phys_addr); 121 m_handle = provider->m_handle; 122 m_is_shared_mapping = false; 123 124 return true; 125} 126 127bool GoldfishAddressSpaceBlock::claimShared(GoldfishAddressSpaceBlockProvider *provider, uint64_t offset, uint64_t size) 128{ 129 destroy(); 130 131 if (!provider->is_opened()) { 132 return false; 133 } 134 135 int claimRes = HostAddressSpaceDevice::get()->claimShared( 136 provider->m_handle, offset, size); 137 138 if (claimRes) { 139 ALOGE("%s: failed to claim shared region. Error: %d\n", __func__, claimRes); 140 return false; 141 } 142 143 m_size = size; 144 m_offset = offset; 145 m_handle = provider->m_handle; 146 m_is_shared_mapping = true; 147 m_phys_addr = HostAddressSpaceDevice::get()->offsetToPhysAddr(m_offset); 148 149 return true; 150} 151 152uint64_t GoldfishAddressSpaceBlock::physAddr() const 153{ 154 return m_phys_addr; 155} 156 157uint64_t GoldfishAddressSpaceBlock::hostAddr() const 158{ 159 return m_host_addr; 160} 161 162// In the host implementation: 163// mmap: is done by interpreting |host_addr| as the actual host address. 164void *GoldfishAddressSpaceBlock::mmap(uint64_t host_addr) 165{ 166 if (m_size == 0) { 167 ALOGE("%s: called with zero size\n", __func__); 168 return NULL; 169 } 170 171 if (m_mmaped_ptr != nullptr) { 172 ALOGE("'mmap' called for an already mmaped address block 0x%llx %d", (unsigned long long)m_mmaped_ptr, nullptr == m_mmaped_ptr); 173 ::abort(); 174 } 175 176 m_mmaped_ptr = (void*)(uintptr_t)(host_addr & (~(PAGE_SIZE - 1))); 177 m_host_addr = host_addr; 178 179 return guestPtr(); 180} 181 182void *GoldfishAddressSpaceBlock::guestPtr() const 183{ 184 return reinterpret_cast<char *>(m_mmaped_ptr) + (m_host_addr & (PAGE_SIZE - 1)); 185} 186 187void GoldfishAddressSpaceBlock::destroy() 188{ 189 if (m_mmaped_ptr && m_size) { 190 m_mmaped_ptr = NULL; 191 } 192 193 if (m_size) { 194 if (m_is_shared_mapping) { 195 HostAddressSpaceDevice::get()->unclaimShared(m_handle, m_offset); 196 } else { 197 HostAddressSpaceDevice::get()->freeBlock(m_handle, m_offset); 198 } 199 m_phys_addr = 0; 200 m_host_addr = 0; 201 m_offset = 0; 202 m_size = 0; 203 } 204} 205 206void GoldfishAddressSpaceBlock::release() 207{ 208 m_handle = 0; 209 m_mmaped_ptr = NULL; 210 m_phys_addr = 0; 211 m_host_addr = 0; 212 m_offset = 0; 213 m_size = 0; 214} 215 216int GoldfishAddressSpaceBlock::memoryMap(void *addr, 217 size_t, 218 address_space_handle_t, 219 uint64_t, 220 void** dst) { 221 *dst = addr; 222 return 0; 223} 224 225void GoldfishAddressSpaceBlock::memoryUnmap(void *ptr, size_t size) {} 226 227GoldfishAddressSpaceHostMemoryAllocator::GoldfishAddressSpaceHostMemoryAllocator(bool useSharedSlots) 228 : m_provider(useSharedSlots 229 ? GoldfishAddressSpaceSubdeviceType::SharedSlotsHostMemoryAllocator 230 : GoldfishAddressSpaceSubdeviceType::HostMemoryAllocator), 231 m_useSharedSlots(useSharedSlots) 232{} 233 234bool GoldfishAddressSpaceHostMemoryAllocator::is_opened() const { return m_provider.is_opened(); } 235 236long GoldfishAddressSpaceHostMemoryAllocator::hostMalloc(GoldfishAddressSpaceBlock *block, size_t size) 237{ 238 if (size == 0) { 239 return -EINVAL; 240 } 241 if (block->size() > 0) { 242 return -EINVAL; 243 } 244 if (!m_provider.is_opened()) { 245 return -ENODEV; 246 } 247 248 AddressSpaceDevicePingInfo request; 249 if (m_useSharedSlots) { 250 ::memset(&request, 0, sizeof(request)); 251 request.size = block->size(); 252 request.metadata = HOST_MEMORY_ALLOCATOR_COMMAND_ALLOCATE_ID; 253 254 HostAddressSpaceDevice::get()->ping(m_provider.m_handle, &request); 255 256 block->claimShared(&m_provider, request.phys_addr, request.size); 257 258 void *hostPtr = HostAddressSpaceDevice::get()->getHostAddr(block->physAddr()); 259 block->mmap(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(hostPtr))); 260 } else { 261 if (!block->allocate(&m_provider, size)) { 262 return -ENOMEM; 263 } 264 265 ::memset(&request, 0, sizeof(request)); 266 request.phys_addr = block->physAddr(); 267 request.size = block->size(); 268 request.metadata = HOST_MEMORY_ALLOCATOR_COMMAND_ALLOCATE_ID; 269 270 HostAddressSpaceDevice::get()->ping(m_provider.m_handle, &request); 271 272 void *hostPtr = HostAddressSpaceDevice::get()->getHostAddr(block->physAddr()); 273 block->mmap(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(hostPtr))); 274 } 275 276 return 0; 277} 278 279void GoldfishAddressSpaceHostMemoryAllocator::hostFree(GoldfishAddressSpaceBlock *block) 280{ 281 if (block->size() == 0) { 282 return; 283 } 284 285 if (!m_provider.is_opened()) { 286 ALOGE("%s: device is not available", __func__); 287 ::abort(); 288 } 289 290 if (block->guestPtr()) { 291 AddressSpaceDevicePingInfo request; 292 ::memset(&request, 0, sizeof(request)); 293 request.phys_addr = block->physAddr(); 294 request.metadata = HOST_MEMORY_ALLOCATOR_COMMAND_UNALLOCATE_ID; 295 296 HostAddressSpaceDevice::get()->ping(m_provider.m_handle, &request); 297 } 298 299 block->replace(NULL); 300} 301 302address_space_handle_t goldfish_address_space_open() { 303 return HostAddressSpaceDevice::get()->open(); 304} 305 306void goldfish_address_space_close(address_space_handle_t handle) { 307 HostAddressSpaceDevice::get()->close(handle); 308} 309 310bool goldfish_address_space_allocate( 311 address_space_handle_t handle, 312 size_t size, uint64_t* phys_addr, uint64_t* offset) { 313 314 *offset = 315 HostAddressSpaceDevice::get()->allocBlock( 316 handle, size, phys_addr); 317 318 return true; 319} 320 321bool goldfish_address_space_free( 322 address_space_handle_t handle, uint64_t offset) { 323 HostAddressSpaceDevice::get()->freeBlock(handle, offset); 324 return true; 325} 326 327bool goldfish_address_space_claim_shared( 328 address_space_handle_t handle, uint64_t offset, uint64_t size) { 329 330 int claimRes = HostAddressSpaceDevice::get()->claimShared( 331 handle, offset, size); 332 333 if (claimRes) { 334 ALOGE("%s: failed to claim shared region. Error: %d\n", __func__, claimRes); 335 return false; 336 } 337 338 return true; 339} 340 341bool goldfish_address_space_unclaim_shared( 342 address_space_handle_t handle, uint64_t offset) { 343 HostAddressSpaceDevice::get()->unclaimShared(handle, offset); 344 return true; 345} 346 347// pgoff is the offset into the page to return in the result 348void* goldfish_address_space_map( 349 address_space_handle_t handle, 350 uint64_t offset, uint64_t size, 351 uint64_t pgoff) { 352 353 (void)size; 354 355 void* res = HostAddressSpaceDevice::get()-> 356 getHostAddr( 357 HostAddressSpaceDevice::get()->offsetToPhysAddr(offset)); 358 359 if (!res) { 360 ALOGE("%s: failed to map. errno: %d\n", __func__, errno); 361 return nullptr; 362 } 363 364 return (void*)(((char*)res) + (uintptr_t)(pgoff & (PAGE_SIZE - 1))); 365} 366 367// same address space 368void goldfish_address_space_unmap(void*, uint64_t) { } 369 370bool goldfish_address_space_set_subdevice_type( 371 address_space_handle_t handle, GoldfishAddressSpaceSubdeviceType type, 372 address_space_handle_t* handle_out) { 373 struct address_space_ping request; 374 request.metadata = (uint64_t)type; 375 *handle_out = handle; 376 return goldfish_address_space_ping(handle, &request); 377} 378 379bool goldfish_address_space_ping( 380 address_space_handle_t handle, 381 struct address_space_ping* ping) { 382 383 AddressSpaceDevicePingInfo* asHostPingInfo = 384 reinterpret_cast<AddressSpaceDevicePingInfo*>(ping); 385 386 HostAddressSpaceDevice::get()->ping(handle, asHostPingInfo); 387 388 return true; 389} 390