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 "aemu/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)->member) : ZX_OK) 37 38using gfxstream::guest::AutoLock; 39using gfxstream::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 destroy(); 123 124 if (!provider->is_opened()) { 125 return false; 126 } 127 128 const fidl::WireSyncClient<AddressSpaceChildDriver>& driver = provider->m_child_driver; 129 130 auto result = driver->AllocateBlock(size); 131 if (!result.ok() || result->res != ZX_OK) { 132 ALOGE("%s: allocate block failed: %d:%d", __func__, result.status(), GET_STATUS_SAFE(result, res)); 133 return false; 134 } 135 m_phys_addr = result->paddr; 136 // TODO(fxbug.dev/42075554): Instead of storing raw handles we should 137 // consider using RAII zx::object instead. 138 m_vmo = result->vmo.release(); 139 140 m_size = size; 141 m_offset = 0; 142 m_is_shared_mapping = false; 143 m_driver = &provider->m_child_driver; 144 145 return true; 146} 147 148bool GoldfishAddressSpaceBlock::claimShared(GoldfishAddressSpaceBlockProvider *provider, uint64_t offset, uint64_t size) 149{ 150 ALOGE("%s: FATAL: not supported\n", __func__); 151 abort(); 152} 153 154uint64_t GoldfishAddressSpaceBlock::physAddr() const 155{ 156 return m_phys_addr; 157} 158 159uint64_t GoldfishAddressSpaceBlock::hostAddr() const 160{ 161 return m_host_addr; 162} 163 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 if (m_mmaped_ptr) { 171 ALOGE("'mmap' called for an already mmaped address block"); 172 ::abort(); 173 } 174 175 bool nonzeroOffsetInPage = host_addr & (PAGE_SIZE - 1); 176 uint64_t extraBytes = nonzeroOffsetInPage ? PAGE_SIZE : 0; 177 m_size += extraBytes; 178 179 zx_vaddr_t ptr = 0; 180 zx_status_t status = zx_vmar_map(zx_vmar_root_self(), 181 ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 182 0, m_vmo, 183 m_offset, 184 m_size, 185 &ptr); 186 if (status != ZX_OK) { 187 ALOGE("%s: host memory map failed with size 0x%llx " 188 "off 0x%llx status %d\n", 189 __func__, 190 (unsigned long long)m_size, 191 (unsigned long long)m_offset, status); 192 return NULL; 193 } 194 195 m_mmaped_ptr = (void*)ptr; 196 m_host_addr = host_addr; 197 return guestPtr(); 198} 199 200void *GoldfishAddressSpaceBlock::guestPtr() const 201{ 202 return reinterpret_cast<char *>(m_mmaped_ptr) + (m_host_addr & (PAGE_SIZE - 1)); 203} 204 205void GoldfishAddressSpaceBlock::destroy() 206{ 207 if (m_mmaped_ptr && m_size) { 208 zx_vmar_unmap(zx_vmar_root_self(), 209 (zx_vaddr_t)m_mmaped_ptr, 210 m_size); 211 m_mmaped_ptr = NULL; 212 } 213 214 if (m_size) { 215 zx_handle_close(m_vmo); 216 m_vmo = ZX_HANDLE_INVALID; 217 if (m_is_shared_mapping) { 218 // TODO 219 ALOGE("%s: unsupported: GoldfishAddressSpaceBlock destroy() for shared regions\n", __func__); 220 abort(); 221 // int32_t res = ZX_OK; 222 // auto result = m_driver->UnclaimShared(m_offset); 223 // if (!result.ok() || result->res != ZX_OK) { 224 // ALOGE("%s: unclaim shared block failed: %d:%d", __func__, 225 // result.status(), GET_STATUS_SAFE(result, res)); 226 // } 227 } else { 228 auto result = (*m_driver)->DeallocateBlock(m_phys_addr); 229 if (!result.ok() || result->res != ZX_OK) { 230 ALOGE("%s: deallocate block failed: %d:%d", __func__, 231 result.status(), GET_STATUS_SAFE(result, res)); 232 } 233 } 234 m_driver = NULL; 235 m_phys_addr = 0; 236 m_host_addr = 0; 237 m_offset = 0; 238 m_size = 0; 239 } 240} 241 242GoldfishAddressSpaceHostMemoryAllocator::GoldfishAddressSpaceHostMemoryAllocator(bool useSharedSlots) 243 : m_provider(GoldfishAddressSpaceSubdeviceType::HostMemoryAllocator) { } 244 245long GoldfishAddressSpaceHostMemoryAllocator::hostMalloc(GoldfishAddressSpaceBlock *block, size_t size) 246{ 247 return 0; 248} 249 250void GoldfishAddressSpaceHostMemoryAllocator::hostFree(GoldfishAddressSpaceBlock *block) 251{ 252} 253 254class VmoStore { 255public: 256 struct Info { 257 zx_handle_t vmo = ZX_HANDLE_INVALID; 258 uint64_t phys_addr = 0; 259 }; 260 261 void add(uint64_t offset, const Info& info) { 262 AutoLock lock(mLock); 263 mInfo[offset] = info; 264 } 265 266 void remove(uint64_t offset) { 267 AutoLock lock(mLock); 268 mInfo.erase(offset); 269 } 270 271 Info get(uint64_t offset) { 272 Info res; 273 AutoLock lock(mLock); 274 auto it = mInfo.find(offset); 275 if (it == mInfo.end()) { 276 ALOGE("VmoStore::%s cannot find info on offset 0x%llx\n", __func__, 277 (unsigned long long)offset); 278 return res; 279 } 280 res = it->second; 281 return res; 282 } 283 284private: 285 Lock mLock; 286 std::unordered_map<uint64_t, Info> mInfo; 287}; 288 289static Lock sVmoStoreInitLock; 290static VmoStore* sVmoStore = nullptr; 291 292static VmoStore* getVmoStore() { 293 AutoLock lock(sVmoStoreInitLock); 294 if (!sVmoStore) sVmoStore = new VmoStore; 295 return sVmoStore; 296} 297 298address_space_handle_t goldfish_address_space_open() { 299 fidl::ClientEnd<AddressSpaceDevice> channel{ 300 zx::channel(GetConnectToServiceFunction()(GOLDFISH_ADDRESS_SPACE_DEVICE_NAME))}; 301 if (!channel) { 302 ALOGE("%s: failed to get service handle for " GOLDFISH_ADDRESS_SPACE_DEVICE_NAME, 303 __FUNCTION__); 304 return 0; 305 } 306 fidl::WireSyncClient<AddressSpaceDevice>* 307 deviceSync = new fidl::WireSyncClient<AddressSpaceDevice>(std::move(channel)); 308 return (address_space_handle_t)deviceSync; 309} 310 311void goldfish_address_space_close(address_space_handle_t handle) { 312 fidl::WireSyncClient<AddressSpaceDevice>* deviceSync = 313 reinterpret_cast< 314 fidl::WireSyncClient<AddressSpaceDevice>*>(handle); 315 delete deviceSync; 316} 317 318bool goldfish_address_space_set_subdevice_type( 319 address_space_handle_t handle, GoldfishAddressSpaceSubdeviceType type, 320 address_space_handle_t* handle_out) { 321 322 auto* deviceSync = 323 reinterpret_cast<fidl::WireSyncClient<AddressSpaceDevice>*>(handle); 324 325 auto child_driver_ends = 326 fidl::CreateEndpoints<::fuchsia_hardware_goldfish::AddressSpaceChildDriver>(); 327 if (!child_driver_ends.is_ok()) { 328 ALOGE("%s: zx_channel_create failed: %d", __FUNCTION__, child_driver_ends.status_value()); 329 return false; 330 } 331 332 (*deviceSync)->OpenChildDriver( 333 static_cast<AddressSpaceChildDriverType>(type), 334 std::move(child_driver_ends->server)); 335 336 fidl::WireSyncClient<AddressSpaceChildDriver>* 337 childSync = new fidl::WireSyncClient<AddressSpaceChildDriver>(std::move(child_driver_ends->client)); 338 339 // On creating a subdevice, in our use cases we wont be needing the 340 // original device sync anymore, so get rid of it. 341 delete deviceSync; 342 343 *handle_out = (void*)childSync; 344 345 return true; 346} 347 348bool goldfish_address_space_allocate( 349 address_space_handle_t handle, 350 size_t size, uint64_t* phys_addr, uint64_t* offset) { 351 const auto& deviceSync = 352 *reinterpret_cast< 353 fidl::WireSyncClient<AddressSpaceChildDriver>*>(handle); 354 355 zx::vmo vmo; 356 auto result = deviceSync->AllocateBlock(size); 357 if (!result.ok() || result->res != ZX_OK) { 358 ALOGE("%s: allocate block failed: %d:%d", __func__, result.status(), GET_STATUS_SAFE(result, res)); 359 return false; 360 } 361 *phys_addr = result->paddr; 362 vmo = std::move(result->vmo); 363 364 *offset = 0; 365 366 // TODO(fxbug.dev/42075554): Instead of storing raw handles we should 367 // consider using RAII zx::object instead. 368 VmoStore::Info info = { 369 vmo.release(), 370 *phys_addr, 371 }; 372 373 getVmoStore()->add(*offset, info); 374 return true; 375} 376 377bool goldfish_address_space_free( 378 address_space_handle_t handle, uint64_t offset) { 379 auto info = getVmoStore()->get(offset); 380 if (info.vmo == ZX_HANDLE_INVALID) return false; 381 zx_handle_close(info.vmo); 382 383 const auto& deviceSync = 384 *reinterpret_cast< 385 fidl::WireSyncClient<AddressSpaceChildDriver>*>(handle); 386 387 auto result = deviceSync->DeallocateBlock(info.phys_addr); 388 if (!result.ok() || result->res != ZX_OK) { 389 ALOGE("%s: deallocate block failed: %d:%d", __func__, result.status(), GET_STATUS_SAFE(result, res)); 390 return false; 391 } 392 393 return true; 394} 395 396bool goldfish_address_space_claim_shared( 397 address_space_handle_t handle, uint64_t offset, uint64_t size) { 398 399 const auto& deviceSync = 400 *reinterpret_cast< 401 fidl::WireSyncClient<AddressSpaceChildDriver>*>(handle); 402 403 zx::vmo vmo; 404 auto result = deviceSync->ClaimSharedBlock(offset, size); 405 if (!result.ok() || result->res != ZX_OK) { 406 ALOGE("%s: claim shared failed: %d:%d", __func__, result.status(), GET_STATUS_SAFE(result, res)); 407 return false; 408 } 409 vmo = std::move(result->vmo); 410 411 // TODO(fxbug.dev/42075554): Instead of storing raw handles we should 412 // consider using RAII zx::object instead. 413 VmoStore::Info info = { 414 vmo.release(), 415 }; 416 417 getVmoStore()->add(offset, info); 418 419 return true; 420} 421 422bool goldfish_address_space_unclaim_shared( 423 address_space_handle_t handle, uint64_t offset) { 424 auto info = getVmoStore()->get(offset); 425 if (info.vmo == ZX_HANDLE_INVALID) { 426 return false; 427 } 428 zx_handle_close(info.vmo); 429 430 const auto& deviceSync = 431 *reinterpret_cast< 432 fidl::WireSyncClient<AddressSpaceChildDriver>*>(handle); 433 434 auto result = deviceSync->UnclaimSharedBlock(offset); 435 if (!result.ok() || result->res != ZX_OK) { 436 ALOGE("%s: unclaim shared failed: %d:%d", __func__, result.status(), GET_STATUS_SAFE(result, res)); 437 return false; 438 } 439 440 getVmoStore()->remove(offset); 441 return true; 442} 443 444// pgoff is the offset into the page to return in the result 445void* goldfish_address_space_map( 446 address_space_handle_t handle, 447 uint64_t offset, uint64_t size, 448 uint64_t pgoff) { 449 450 auto info = getVmoStore()->get(offset); 451 if (info.vmo == ZX_HANDLE_INVALID) return nullptr; 452 453 zx_vaddr_t ptr = 0; 454 zx_status_t status = 455 zx_vmar_map(zx_vmar_root_self(), 456 ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 457 0, info.vmo, 458 0, size, 459 &ptr); 460 return (void*)(((char*)ptr) + (uintptr_t)(pgoff & (PAGE_SIZE - 1))); 461} 462 463void goldfish_address_space_unmap(void* ptr, uint64_t size) { 464 zx_vmar_unmap(zx_vmar_root_self(), 465 (zx_vaddr_t)(((uintptr_t)ptr) & (uintptr_t)(~(PAGE_SIZE - 1))), 466 size); 467} 468 469bool goldfish_address_space_ping( 470 address_space_handle_t handle, 471 struct address_space_ping* ping) { 472 473 AddressSpaceChildDriverPingMessage fuchsiaPing = 474 *(AddressSpaceChildDriverPingMessage*)ping; 475 476 const auto& deviceSync = 477 *reinterpret_cast< 478 fidl::WireSyncClient<AddressSpaceChildDriver>*>(handle); 479 480 AddressSpaceChildDriverPingMessage res; 481 auto result = deviceSync->Ping(fuchsiaPing); 482 if (!result.ok() || result->res != ZX_OK) { 483 return false; 484 } 485 res = std::move(result->ping); 486 487 *ping = *(struct address_space_ping*)(&res); 488 return true; 489} 490