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 <memory> 17#include <fcntl.h> 18#include <lib/zx/channel.h> 19#include <lib/zx/vmo.h> 20#include <log/log.h> 21#include <stdlib.h> 22#include <sys/stat.h> 23#include <sys/types.h> 24#include <unistd.h> 25#include <zircon/process.h> 26#include <zircon/syscalls.h> 27#include <zircon/syscalls/object.h> 28 29#include "goldfish_address_space.h" 30#include "android/base/synchronization/AndroidLock.h" 31#include "services/service_connector.h" 32 33#include <unordered_map> 34 35#define GET_STATUS_SAFE(result, member) \ 36 ((result).ok() ? ((result).Unwrap()->member) : ZX_OK) 37 38using android::base::guest::AutoLock; 39using android::base::guest::Lock; 40 41using fuchsia_hardware_goldfish::AddressSpaceChildDriver; 42using fuchsia_hardware_goldfish::AddressSpaceDevice; 43using fuchsia_hardware_goldfish::wire::AddressSpaceChildDriverType; 44using fuchsia_hardware_goldfish::wire::AddressSpaceChildDriverPingMessage; 45 46GoldfishAddressSpaceBlockProvider::GoldfishAddressSpaceBlockProvider(GoldfishAddressSpaceSubdeviceType subdevice) { 47 48 if (subdevice != GoldfishAddressSpaceSubdeviceType::NoSubdevice) { 49 ALOGE("%s: Tried to use a nontrivial subdevice when support has not been added\n", __func__); 50 abort(); 51 } 52 53 fidl::ClientEnd<AddressSpaceDevice> channel{ 54 zx::channel(GetConnectToServiceFunction()(GOLDFISH_ADDRESS_SPACE_DEVICE_NAME))}; 55 if (!channel) { 56 ALOGE("%s: failed to get service handle for " GOLDFISH_ADDRESS_SPACE_DEVICE_NAME, 57 __FUNCTION__); 58 return; 59 } 60 m_device = fidl::WireSyncClient<AddressSpaceDevice>(std::move(channel)); 61 62 auto child_driver_ends = 63 fidl::CreateEndpoints<::fuchsia_hardware_goldfish::AddressSpaceChildDriver>(); 64 if (!child_driver_ends.is_ok()) { 65 ALOGE("%s: zx_channel_create failed: %d", __FUNCTION__, child_driver_ends.status_value()); 66 return; 67 } 68 69 auto result = m_device->OpenChildDriver( 70 static_cast<AddressSpaceChildDriverType>(0 /* graphics */), 71 std::move(child_driver_ends->server)); 72 if (!result.ok()) { 73 ALOGE("%s: failed to open child driver: %d", 74 __FUNCTION__, result.status()); 75 return; 76 } 77 m_child_driver = fidl::WireSyncClient<AddressSpaceChildDriver>( 78 std::move(child_driver_ends->client)); 79} 80 81GoldfishAddressSpaceBlockProvider::~GoldfishAddressSpaceBlockProvider() 82{ 83} 84 85bool GoldfishAddressSpaceBlockProvider::is_opened() const 86{ 87 return !!m_device; 88} 89 90// void GoldfishAddressSpaceBlockProvider::close() - not implemented 91// address_space_handle_t GoldfishAddressSpaceBlockProvider::release() - not imeplemented 92 93GoldfishAddressSpaceBlock::GoldfishAddressSpaceBlock() 94 : m_driver(NULL) 95 , m_vmo(ZX_HANDLE_INVALID) 96 , m_mmaped_ptr(NULL) 97 , m_phys_addr(0) 98 , m_host_addr(0) 99 , m_offset(0) 100 , m_size(0) {} 101 102GoldfishAddressSpaceBlock::~GoldfishAddressSpaceBlock() 103{ 104 destroy(); 105} 106 107GoldfishAddressSpaceBlock &GoldfishAddressSpaceBlock::operator=(const GoldfishAddressSpaceBlock &rhs) 108{ 109 m_vmo = rhs.m_vmo; 110 m_mmaped_ptr = rhs.m_mmaped_ptr; 111 m_phys_addr = rhs.m_phys_addr; 112 m_host_addr = rhs.m_host_addr; 113 m_offset = rhs.m_offset; 114 m_size = rhs.m_size; 115 m_driver = rhs.m_driver; 116 117 return *this; 118} 119 120bool GoldfishAddressSpaceBlock::allocate(GoldfishAddressSpaceBlockProvider *provider, size_t size) 121{ 122 ALOGD("%s: Ask for block of size 0x%llx\n", __func__, 123 (unsigned long long)size); 124 125 destroy(); 126 127 if (!provider->is_opened()) { 128 return false; 129 } 130 131 const fidl::WireSyncClient<AddressSpaceChildDriver>& driver = provider->m_child_driver; 132 133 auto result = driver->AllocateBlock(size); 134 if (!result.ok() || result.Unwrap()->res != ZX_OK) { 135 ALOGE("%s: allocate block failed: %d:%d", __func__, result.status(), GET_STATUS_SAFE(result, res)); 136 return false; 137 } 138 m_phys_addr = result.Unwrap()->paddr; 139 m_vmo = result.Unwrap()->vmo.release(); 140 141 m_size = size; 142 m_offset = 0; 143 m_is_shared_mapping = false; 144 145 ALOGD("%s: allocate returned offset 0x%llx size 0x%llx\n", __func__, 146 (unsigned long long)m_offset, 147 (unsigned long long)m_size); 148 149 m_driver = &provider->m_child_driver; 150 return true; 151} 152 153bool GoldfishAddressSpaceBlock::claimShared(GoldfishAddressSpaceBlockProvider *provider, uint64_t offset, uint64_t size) 154{ 155 ALOGE("%s: FATAL: not supported\n", __func__); 156 abort(); 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 169void *GoldfishAddressSpaceBlock::mmap(uint64_t host_addr) 170{ 171 if (m_size == 0) { 172 ALOGE("%s: called with zero size\n", __func__); 173 return NULL; 174 } 175 if (m_mmaped_ptr) { 176 ALOGE("'mmap' called for an already mmaped address block"); 177 ::abort(); 178 } 179 180 bool nonzeroOffsetInPage = host_addr & (PAGE_SIZE - 1); 181 uint64_t extraBytes = nonzeroOffsetInPage ? PAGE_SIZE : 0; 182 m_size += extraBytes; 183 184 zx_vaddr_t ptr = 0; 185 zx_status_t status = zx_vmar_map(zx_vmar_root_self(), 186 ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 187 0, m_vmo, 188 m_offset, 189 m_size, 190 &ptr); 191 if (status != ZX_OK) { 192 ALOGE("%s: host memory map failed with size 0x%llx " 193 "off 0x%llx status %d\n", 194 __func__, 195 (unsigned long long)m_size, 196 (unsigned long long)m_offset, status); 197 return NULL; 198 } 199 200 m_mmaped_ptr = (void*)ptr; 201 m_host_addr = host_addr; 202 return guestPtr(); 203} 204 205void *GoldfishAddressSpaceBlock::guestPtr() const 206{ 207 return reinterpret_cast<char *>(m_mmaped_ptr) + (m_host_addr & (PAGE_SIZE - 1)); 208} 209 210void GoldfishAddressSpaceBlock::destroy() 211{ 212 if (m_mmaped_ptr && m_size) { 213 zx_vmar_unmap(zx_vmar_root_self(), 214 (zx_vaddr_t)m_mmaped_ptr, 215 m_size); 216 m_mmaped_ptr = NULL; 217 } 218 219 if (m_size) { 220 zx_handle_close(m_vmo); 221 m_vmo = ZX_HANDLE_INVALID; 222 if (m_is_shared_mapping) { 223 // TODO 224 ALOGE("%s: unsupported: GoldfishAddressSpaceBlock destroy() for shared regions\n", __func__); 225 abort(); 226 // int32_t res = ZX_OK; 227 // auto result = m_driver->UnclaimShared(m_offset); 228 // if (!result.ok() || result.Unwrap()->res != ZX_OK) { 229 // ALOGE("%s: unclaim shared block failed: %d:%d", __func__, 230 // result.status(), GET_STATUS_SAFE(result, res)); 231 // } 232 } else { 233 auto result = (*m_driver)->DeallocateBlock(m_phys_addr); 234 if (!result.ok() || result.Unwrap()->res != ZX_OK) { 235 ALOGE("%s: deallocate block failed: %d:%d", __func__, 236 result.status(), GET_STATUS_SAFE(result, res)); 237 } 238 } 239 m_driver = NULL; 240 m_phys_addr = 0; 241 m_host_addr = 0; 242 m_offset = 0; 243 m_size = 0; 244 } 245} 246 247GoldfishAddressSpaceHostMemoryAllocator::GoldfishAddressSpaceHostMemoryAllocator(bool useSharedSlots) 248 : m_provider(GoldfishAddressSpaceSubdeviceType::HostMemoryAllocator) { } 249 250long GoldfishAddressSpaceHostMemoryAllocator::hostMalloc(GoldfishAddressSpaceBlock *block, size_t size) 251{ 252 return 0; 253} 254 255void GoldfishAddressSpaceHostMemoryAllocator::hostFree(GoldfishAddressSpaceBlock *block) 256{ 257} 258 259class VmoStore { 260public: 261 struct Info { 262 zx_handle_t vmo = ZX_HANDLE_INVALID; 263 uint64_t phys_addr = 0; 264 }; 265 266 void add(uint64_t offset, const Info& info) { 267 AutoLock lock(mLock); 268 mInfo[offset] = info; 269 } 270 271 void remove(uint64_t offset) { 272 AutoLock lock(mLock); 273 mInfo.erase(offset); 274 } 275 276 Info get(uint64_t offset) { 277 Info res; 278 AutoLock lock(mLock); 279 auto it = mInfo.find(offset); 280 if (it == mInfo.end()) { 281 ALOGE("VmoStore::%s cannot find info on offset 0x%llx\n", __func__, 282 (unsigned long long)offset); 283 return res; 284 } 285 res = it->second; 286 return res; 287 } 288 289private: 290 Lock mLock; 291 std::unordered_map<uint64_t, Info> mInfo; 292}; 293 294static Lock sVmoStoreInitLock; 295static VmoStore* sVmoStore = nullptr; 296 297static VmoStore* getVmoStore() { 298 AutoLock lock(sVmoStoreInitLock); 299 if (!sVmoStore) sVmoStore = new VmoStore; 300 return sVmoStore; 301} 302 303address_space_handle_t goldfish_address_space_open() { 304 fidl::ClientEnd<AddressSpaceDevice> channel{ 305 zx::channel(GetConnectToServiceFunction()(GOLDFISH_ADDRESS_SPACE_DEVICE_NAME))}; 306 if (!channel) { 307 ALOGE("%s: failed to get service handle for " GOLDFISH_ADDRESS_SPACE_DEVICE_NAME, 308 __FUNCTION__); 309 return 0; 310 } 311 fidl::WireSyncClient<AddressSpaceDevice>* 312 deviceSync = new fidl::WireSyncClient<AddressSpaceDevice>(std::move(channel)); 313 return (address_space_handle_t)deviceSync; 314} 315 316void goldfish_address_space_close(address_space_handle_t handle) { 317 fidl::WireSyncClient<AddressSpaceDevice>* deviceSync = 318 reinterpret_cast< 319 fidl::WireSyncClient<AddressSpaceDevice>*>(handle); 320 delete deviceSync; 321} 322 323bool goldfish_address_space_set_subdevice_type( 324 address_space_handle_t handle, GoldfishAddressSpaceSubdeviceType type, 325 address_space_handle_t* handle_out) { 326 327 auto* deviceSync = 328 reinterpret_cast<fidl::WireSyncClient<AddressSpaceDevice>*>(handle); 329 330 auto child_driver_ends = 331 fidl::CreateEndpoints<::fuchsia_hardware_goldfish::AddressSpaceChildDriver>(); 332 if (!child_driver_ends.is_ok()) { 333 ALOGE("%s: zx_channel_create failed: %d", __FUNCTION__, child_driver_ends.status_value()); 334 return false; 335 } 336 337 (*deviceSync)->OpenChildDriver( 338 static_cast<AddressSpaceChildDriverType>(type), 339 std::move(child_driver_ends->server)); 340 341 fidl::WireSyncClient<AddressSpaceChildDriver>* 342 childSync = new fidl::WireSyncClient<AddressSpaceChildDriver>(std::move(child_driver_ends->client)); 343 344 // On creating a subdevice, in our use cases we wont be needing the 345 // original device sync anymore, so get rid of it. 346 delete deviceSync; 347 348 *handle_out = (void*)childSync; 349 350 return true; 351} 352 353bool goldfish_address_space_allocate( 354 address_space_handle_t handle, 355 size_t size, uint64_t* phys_addr, uint64_t* offset) { 356 const auto& deviceSync = 357 *reinterpret_cast< 358 fidl::WireSyncClient<AddressSpaceChildDriver>*>(handle); 359 360 zx::vmo vmo; 361 auto result = deviceSync->AllocateBlock(size); 362 if (!result.ok() || result.Unwrap()->res != ZX_OK) { 363 ALOGE("%s: allocate block failed: %d:%d", __func__, result.status(), GET_STATUS_SAFE(result, res)); 364 return false; 365 } 366 *phys_addr = result.Unwrap()->paddr; 367 vmo = std::move(result.Unwrap()->vmo); 368 369 *offset = 0; 370 371 VmoStore::Info info = { 372 vmo.release(), 373 *phys_addr, 374 }; 375 376 getVmoStore()->add(*offset, info); 377 return true; 378} 379 380bool goldfish_address_space_free( 381 address_space_handle_t handle, uint64_t offset) { 382 auto info = getVmoStore()->get(offset); 383 if (info.vmo == ZX_HANDLE_INVALID) return false; 384 zx_handle_close(info.vmo); 385 386 const auto& deviceSync = 387 *reinterpret_cast< 388 fidl::WireSyncClient<AddressSpaceChildDriver>*>(handle); 389 390 auto result = deviceSync->DeallocateBlock(info.phys_addr); 391 if (!result.ok() || result.Unwrap()->res != ZX_OK) { 392 ALOGE("%s: deallocate block failed: %d:%d", __func__, result.status(), GET_STATUS_SAFE(result, res)); 393 return false; 394 } 395 396 return true; 397} 398 399bool goldfish_address_space_claim_shared( 400 address_space_handle_t handle, uint64_t offset, uint64_t size) { 401 402 const auto& deviceSync = 403 *reinterpret_cast< 404 fidl::WireSyncClient<AddressSpaceChildDriver>*>(handle); 405 406 zx::vmo vmo; 407 auto result = deviceSync->ClaimSharedBlock(offset, size); 408 if (!result.ok() || result.Unwrap()->res != ZX_OK) { 409 ALOGE("%s: claim shared failed: %d:%d", __func__, result.status(), GET_STATUS_SAFE(result, res)); 410 return false; 411 } 412 vmo = std::move(result.Unwrap()->vmo); 413 414 VmoStore::Info info = { 415 vmo.release(), 416 }; 417 418 getVmoStore()->add(offset, info); 419 420 return true; 421} 422 423bool goldfish_address_space_unclaim_shared( 424 address_space_handle_t handle, uint64_t offset) { 425 const auto& deviceSync = 426 *reinterpret_cast< 427 fidl::WireSyncClient<AddressSpaceChildDriver>*>(handle); 428 429 auto result = deviceSync->UnclaimSharedBlock(offset); 430 if (!result.ok() || result.Unwrap()->res != ZX_OK) { 431 ALOGE("%s: unclaim shared failed: %d:%d", __func__, result.status(), GET_STATUS_SAFE(result, res)); 432 return false; 433 } 434 435 getVmoStore()->remove(offset); 436 return true; 437} 438 439// pgoff is the offset into the page to return in the result 440void* goldfish_address_space_map( 441 address_space_handle_t handle, 442 uint64_t offset, uint64_t size, 443 uint64_t pgoff) { 444 445 auto info = getVmoStore()->get(offset); 446 if (info.vmo == ZX_HANDLE_INVALID) return nullptr; 447 448 zx_vaddr_t ptr = 0; 449 zx_status_t status = 450 zx_vmar_map(zx_vmar_root_self(), 451 ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 452 0, info.vmo, 453 0, size, 454 &ptr); 455 return (void*)(((char*)ptr) + (uintptr_t)(pgoff & (PAGE_SIZE - 1))); 456} 457 458void goldfish_address_space_unmap(void* ptr, uint64_t size) { 459 zx_vmar_unmap(zx_vmar_root_self(), 460 (zx_vaddr_t)(((uintptr_t)ptr) & (uintptr_t)(~(PAGE_SIZE - 1))), 461 size); 462} 463 464bool goldfish_address_space_ping( 465 address_space_handle_t handle, 466 struct address_space_ping* ping) { 467 468 AddressSpaceChildDriverPingMessage fuchsiaPing = 469 *(AddressSpaceChildDriverPingMessage*)ping; 470 471 const auto& deviceSync = 472 *reinterpret_cast< 473 fidl::WireSyncClient<AddressSpaceChildDriver>*>(handle); 474 475 AddressSpaceChildDriverPingMessage res; 476 auto result = deviceSync->Ping(fuchsiaPing); 477 if (!result.ok() || result.Unwrap()->res != ZX_OK) { 478 return false; 479 } 480 res = std::move(result.Unwrap()->ping); 481 482 *ping = *(struct address_space_ping*)(&res); 483 return true; 484} 485