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 = std::make_unique<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 = std::make_unique<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 fidl::WireSyncClient<AddressSpaceChildDriver>* driver = provider->m_child_driver.get(); 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 = 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 fidl::WireSyncClient<AddressSpaceDevice>* deviceSync = 328 reinterpret_cast< 329 fidl::WireSyncClient<AddressSpaceDevice>*>(handle); 330 331 auto child_driver_ends = 332 fidl::CreateEndpoints<::fuchsia_hardware_goldfish::AddressSpaceChildDriver>(); 333 if (!child_driver_ends.is_ok()) { 334 ALOGE("%s: zx_channel_create failed: %d", __FUNCTION__, child_driver_ends.status_value()); 335 return false; 336 } 337 338 deviceSync->OpenChildDriver( 339 static_cast<AddressSpaceChildDriverType>(type), 340 std::move(child_driver_ends->server)); 341 342 fidl::WireSyncClient<AddressSpaceChildDriver>* 343 childSync = new fidl::WireSyncClient<AddressSpaceChildDriver>(std::move(child_driver_ends->client)); 344 345 // On creating a subdevice, in our use cases we wont be needing the 346 // original device sync anymore, so get rid of it. 347 delete deviceSync; 348 349 *handle_out = (void*)childSync; 350 351 return true; 352} 353 354bool goldfish_address_space_allocate( 355 address_space_handle_t handle, 356 size_t size, uint64_t* phys_addr, uint64_t* offset) { 357 fidl::WireSyncClient<AddressSpaceChildDriver>* deviceSync = 358 reinterpret_cast< 359 fidl::WireSyncClient<AddressSpaceChildDriver>*>(handle); 360 361 zx::vmo vmo; 362 auto result = deviceSync->AllocateBlock(size); 363 if (!result.ok() || result.Unwrap()->res != ZX_OK) { 364 ALOGE("%s: allocate block failed: %d:%d", __func__, result.status(), GET_STATUS_SAFE(result, res)); 365 return false; 366 } 367 *phys_addr = result.Unwrap()->paddr; 368 vmo = std::move(result.Unwrap()->vmo); 369 370 *offset = 0; 371 372 VmoStore::Info info = { 373 vmo.release(), 374 *phys_addr, 375 }; 376 377 getVmoStore()->add(*offset, info); 378 return true; 379} 380 381bool goldfish_address_space_free( 382 address_space_handle_t handle, uint64_t offset) { 383 auto info = getVmoStore()->get(offset); 384 if (info.vmo == ZX_HANDLE_INVALID) return false; 385 zx_handle_close(info.vmo); 386 387 fidl::WireSyncClient<AddressSpaceChildDriver>* deviceSync = 388 reinterpret_cast< 389 fidl::WireSyncClient<AddressSpaceChildDriver>*>(handle); 390 391 auto result = deviceSync->DeallocateBlock(info.phys_addr); 392 if (!result.ok() || result.Unwrap()->res != ZX_OK) { 393 ALOGE("%s: deallocate block failed: %d:%d", __func__, result.status(), GET_STATUS_SAFE(result, res)); 394 return false; 395 } 396 397 return true; 398} 399 400bool goldfish_address_space_claim_shared( 401 address_space_handle_t handle, uint64_t offset, uint64_t size) { 402 403 fidl::WireSyncClient<AddressSpaceChildDriver>* deviceSync = 404 reinterpret_cast< 405 fidl::WireSyncClient<AddressSpaceChildDriver>*>(handle); 406 407 zx::vmo vmo; 408 auto result = deviceSync->ClaimSharedBlock(offset, size); 409 if (!result.ok() || result.Unwrap()->res != ZX_OK) { 410 ALOGE("%s: claim shared failed: %d:%d", __func__, result.status(), GET_STATUS_SAFE(result, res)); 411 return false; 412 } 413 vmo = std::move(result.Unwrap()->vmo); 414 415 VmoStore::Info info = { 416 vmo.release(), 417 }; 418 419 getVmoStore()->add(offset, info); 420 421 return true; 422} 423 424bool goldfish_address_space_unclaim_shared( 425 address_space_handle_t handle, uint64_t offset) { 426 fidl::WireSyncClient<AddressSpaceChildDriver>* deviceSync = 427 reinterpret_cast< 428 fidl::WireSyncClient<AddressSpaceChildDriver>*>(handle); 429 430 auto result = deviceSync->UnclaimSharedBlock(offset); 431 if (!result.ok() || result.Unwrap()->res != ZX_OK) { 432 ALOGE("%s: unclaim shared failed: %d:%d", __func__, result.status(), GET_STATUS_SAFE(result, res)); 433 return false; 434 } 435 436 getVmoStore()->remove(offset); 437 return true; 438} 439 440// pgoff is the offset into the page to return in the result 441void* goldfish_address_space_map( 442 address_space_handle_t handle, 443 uint64_t offset, uint64_t size, 444 uint64_t pgoff) { 445 446 auto info = getVmoStore()->get(offset); 447 if (info.vmo == ZX_HANDLE_INVALID) return nullptr; 448 449 zx_vaddr_t ptr = 0; 450 zx_status_t status = 451 zx_vmar_map(zx_vmar_root_self(), 452 ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 453 0, info.vmo, 454 0, size, 455 &ptr); 456 return (void*)(((char*)ptr) + (uintptr_t)(pgoff & (PAGE_SIZE - 1))); 457} 458 459void goldfish_address_space_unmap(void* ptr, uint64_t size) { 460 zx_vmar_unmap(zx_vmar_root_self(), 461 (zx_vaddr_t)(((uintptr_t)ptr) & (uintptr_t)(~(PAGE_SIZE - 1))), 462 size); 463} 464 465bool goldfish_address_space_ping( 466 address_space_handle_t handle, 467 struct address_space_ping* ping) { 468 469 AddressSpaceChildDriverPingMessage fuchsiaPing = 470 *(AddressSpaceChildDriverPingMessage*)ping; 471 472 fidl::WireSyncClient<AddressSpaceChildDriver>* deviceSync = 473 reinterpret_cast< 474 fidl::WireSyncClient<AddressSpaceChildDriver>*>(handle); 475 476 AddressSpaceChildDriverPingMessage res; 477 auto result = deviceSync->Ping(fuchsiaPing); 478 if (!result.ok() || result.Unwrap()->res != ZX_OK) { 479 return false; 480 } 481 res = std::move(result.Unwrap()->ping); 482 483 *ping = *(struct address_space_ping*)(&res); 484 return true; 485} 486