blob: 4d54eed6c9dd86e16e6a8298e44803f8748c7e99 [file] [log] [blame]
Roman Kiryanov79632592019-06-03 12:31:49 -07001// 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>
Roman Kiryanov79632592019-06-03 12:31:49 -070018#include <lib/zx/channel.h>
19#include <lib/zx/vmo.h>
David Revemanecd9e532019-06-07 09:10:06 -040020#include <log/log.h>
Roman Kiryanov79632592019-06-03 12:31:49 -070021#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"
Lingfeng Yang23fef582019-10-30 18:26:54 -070030#include "android/base/synchronization/AndroidLock.h"
John Bauman8153a442019-10-16 15:41:17 -070031#include "services/service_connector.h"
Roman Kiryanov79632592019-06-03 12:31:49 -070032
Lingfeng Yang23fef582019-10-30 18:26:54 -070033#include <unordered_map>
Lingfeng Yang37193ee2019-10-15 08:04:36 -070034
Lingfeng Yang23fef582019-10-30 18:26:54 -070035using android::base::guest::AutoLock;
36using android::base::guest::Lock;
37
38using fuchsia::hardware::goldfish::AddressSpaceDeviceSyncPtr;
39using fuchsia::hardware::goldfish::AddressSpaceChildDriverSyncPtr;
40using fuchsia::hardware::goldfish::AddressSpaceChildDriverType;
41using fuchsia::hardware::goldfish::AddressSpaceChildDriverPingMessage;
42
43GoldfishAddressSpaceBlockProvider::GoldfishAddressSpaceBlockProvider(GoldfishAddressSpaceSubdeviceType subdevice) {
44
45 if (subdevice != GoldfishAddressSpaceSubdeviceType::NoSubdevice) {
Lingfeng Yang37193ee2019-10-15 08:04:36 -070046 ALOGE("%s: Tried to use a nontrivial subdevice when support has not been added\n", __func__);
47 abort();
48 }
49
John Bauman8153a442019-10-16 15:41:17 -070050 zx::channel channel(GetConnectToServiceFunction()(GOLDFISH_ADDRESS_SPACE_DEVICE_NAME));
51 if (!channel) {
52 ALOGE("%s: failed to get service handle for " GOLDFISH_ADDRESS_SPACE_DEVICE_NAME,
53 __FUNCTION__);
Roman Kiryanov79632592019-06-03 12:31:49 -070054 return;
55 }
56 m_device.Bind(std::move(channel));
Lingfeng Yang51f58b02019-12-05 13:44:44 -080057
58 zx_status_t status = (*m_device).OpenChildDriver(
59 static_cast<fuchsia::hardware::goldfish::AddressSpaceChildDriverType>(0 /* graphics */),
60 m_child_driver.NewRequest());
61
62 if (status != ZX_OK) {
63 ALOGE("%s: failed to open child driver: %d",
64 __FUNCTION__, status);
65 return;
66 }
Roman Kiryanov79632592019-06-03 12:31:49 -070067}
68
69GoldfishAddressSpaceBlockProvider::~GoldfishAddressSpaceBlockProvider()
70{
71}
72
73bool GoldfishAddressSpaceBlockProvider::is_opened() const
74{
75 return m_device.is_bound();
76}
77
78// void GoldfishAddressSpaceBlockProvider::close() - not implemented
Roman Kiryanov754c3eb2019-10-10 14:09:23 -070079// address_space_handle_t GoldfishAddressSpaceBlockProvider::release() - not imeplemented
Roman Kiryanov79632592019-06-03 12:31:49 -070080
81GoldfishAddressSpaceBlock::GoldfishAddressSpaceBlock()
Lingfeng Yang51f58b02019-12-05 13:44:44 -080082 : m_driver(NULL)
Roman Kiryanov79632592019-06-03 12:31:49 -070083 , m_vmo(ZX_HANDLE_INVALID)
84 , m_mmaped_ptr(NULL)
85 , m_phys_addr(0)
86 , m_host_addr(0)
87 , m_offset(0)
88 , m_size(0) {}
89
90GoldfishAddressSpaceBlock::~GoldfishAddressSpaceBlock()
91{
92 destroy();
93}
94
95GoldfishAddressSpaceBlock &GoldfishAddressSpaceBlock::operator=(const GoldfishAddressSpaceBlock &rhs)
96{
97 m_vmo = rhs.m_vmo;
98 m_mmaped_ptr = rhs.m_mmaped_ptr;
99 m_phys_addr = rhs.m_phys_addr;
100 m_host_addr = rhs.m_host_addr;
101 m_offset = rhs.m_offset;
102 m_size = rhs.m_size;
Lingfeng Yang51f58b02019-12-05 13:44:44 -0800103 m_driver = rhs.m_driver;
Roman Kiryanov79632592019-06-03 12:31:49 -0700104
105 return *this;
106}
107
108bool GoldfishAddressSpaceBlock::allocate(GoldfishAddressSpaceBlockProvider *provider, size_t size)
109{
110 ALOGD("%s: Ask for block of size 0x%llx\n", __func__,
111 (unsigned long long)size);
112
113 destroy();
114
115 if (!provider->is_opened()) {
116 return false;
117 }
118
Lingfeng Yang51f58b02019-12-05 13:44:44 -0800119 fuchsia::hardware::goldfish::AddressSpaceChildDriverSyncPtr* driver = &provider->m_child_driver;
Roman Kiryanov79632592019-06-03 12:31:49 -0700120
121 int32_t res = ZX_OK;
122 zx::vmo vmo;
Lingfeng Yang51f58b02019-12-05 13:44:44 -0800123 zx_status_t status = (*driver)->AllocateBlock(size, &res, &m_phys_addr, &vmo);
Roman Kiryanov79632592019-06-03 12:31:49 -0700124 if (status != ZX_OK || res != ZX_OK) {
125 ALOGE("%s: allocate block failed: %d:%d", __func__, status, res);
126 return false;
127 }
128
Roman Kiryanov79632592019-06-03 12:31:49 -0700129 m_size = size;
130 m_vmo = vmo.release();
Lingfeng Yang23fef582019-10-30 18:26:54 -0700131 m_offset = 0;
Lingfeng Yang47475b72019-12-18 15:41:22 -0800132 m_is_shared_mapping = false;
Roman Kiryanov79632592019-06-03 12:31:49 -0700133
134 ALOGD("%s: allocate returned offset 0x%llx size 0x%llx\n", __func__,
135 (unsigned long long)m_offset,
136 (unsigned long long)m_size);
137
Lingfeng Yang51f58b02019-12-05 13:44:44 -0800138 m_driver = driver;
Roman Kiryanov79632592019-06-03 12:31:49 -0700139 return true;
140}
141
Lingfeng Yang8d04bdd2019-10-19 10:59:53 -0700142bool GoldfishAddressSpaceBlock::claimShared(GoldfishAddressSpaceBlockProvider *provider, uint64_t offset, uint64_t size)
143{
Lingfeng Yang23fef582019-10-30 18:26:54 -0700144 ALOGE("%s: FATAL: not supported\n", __func__);
Lingfeng Yang8d04bdd2019-10-19 10:59:53 -0700145 abort();
146}
147
Roman Kiryanov79632592019-06-03 12:31:49 -0700148uint64_t GoldfishAddressSpaceBlock::physAddr() const
149{
150 return m_phys_addr;
151}
152
153uint64_t GoldfishAddressSpaceBlock::hostAddr() const
154{
155 return m_host_addr;
156}
157
158void *GoldfishAddressSpaceBlock::mmap(uint64_t host_addr)
159{
160 if (m_size == 0) {
161 ALOGE("%s: called with zero size\n", __func__);
162 return NULL;
163 }
164 if (m_mmaped_ptr) {
165 ALOGE("'mmap' called for an already mmaped address block");
166 ::abort();
167 }
168
169 zx_vaddr_t ptr = 0;
170 zx_status_t status = zx_vmar_map(zx_vmar_root_self(),
171 ZX_VM_PERM_READ | ZX_VM_PERM_WRITE,
172 0, m_vmo,
173 m_offset,
174 m_size,
175 &ptr);
176 if (status != ZX_OK) {
177 ALOGE("%s: host memory map failed with size 0x%llx "
178 "off 0x%llx status %d\n",
179 __func__,
180 (unsigned long long)m_size,
181 (unsigned long long)m_offset, status);
182 return NULL;
183 } else {
184 m_mmaped_ptr = (void*)ptr;
185 m_host_addr = host_addr;
186 return guestPtr();
187 }
188}
189
190void *GoldfishAddressSpaceBlock::guestPtr() const
191{
192 return reinterpret_cast<char *>(m_mmaped_ptr) + (m_host_addr & (PAGE_SIZE - 1));
193}
194
195void GoldfishAddressSpaceBlock::destroy()
196{
197 if (m_mmaped_ptr && m_size) {
198 zx_vmar_unmap(zx_vmar_root_self(),
199 (zx_vaddr_t)m_mmaped_ptr,
200 m_size);
201 m_mmaped_ptr = NULL;
202 }
203
204 if (m_size) {
205 zx_handle_close(m_vmo);
206 m_vmo = ZX_HANDLE_INVALID;
Lingfeng Yang23fef582019-10-30 18:26:54 -0700207 if (m_is_shared_mapping) {
208 // TODO
209 ALOGE("%s: unsupported: GoldfishAddressSpaceBlock destroy() for shared regions\n", __func__);
210 abort();
211 // int32_t res = ZX_OK;
Lingfeng Yang51f58b02019-12-05 13:44:44 -0800212 // zx_status_t status = (*m_driver)->UnclaimShared(m_offset, &res);
Lingfeng Yang23fef582019-10-30 18:26:54 -0700213 // if (status != ZX_OK || res != ZX_OK) {
214 // ALOGE("%s: unclaim shared block failed: %d:%d", __func__, status, res);
215 // }
216 } else {
217 int32_t res = ZX_OK;
Lingfeng Yang51f58b02019-12-05 13:44:44 -0800218 zx_status_t status = (*m_driver)->DeallocateBlock(m_phys_addr, &res);
Lingfeng Yang23fef582019-10-30 18:26:54 -0700219 if (status != ZX_OK || res != ZX_OK) {
220 ALOGE("%s: deallocate block failed: %d:%d", __func__, status, res);
221 }
Roman Kiryanov79632592019-06-03 12:31:49 -0700222 }
Lingfeng Yang51f58b02019-12-05 13:44:44 -0800223 m_driver = NULL;
Roman Kiryanov79632592019-06-03 12:31:49 -0700224 m_phys_addr = 0;
225 m_host_addr = 0;
226 m_offset = 0;
227 m_size = 0;
228 }
229}
230
231GoldfishAddressSpaceHostMemoryAllocator::GoldfishAddressSpaceHostMemoryAllocator()
Lingfeng Yang23fef582019-10-30 18:26:54 -0700232 : m_provider(GoldfishAddressSpaceSubdeviceType::HostMemoryAllocator) { }
Roman Kiryanov79632592019-06-03 12:31:49 -0700233
David Revemanecd9e532019-06-07 09:10:06 -0400234long GoldfishAddressSpaceHostMemoryAllocator::hostMalloc(GoldfishAddressSpaceBlock *block, size_t size)
Roman Kiryanov79632592019-06-03 12:31:49 -0700235{
236 return 0;
237}
238
David Revemanecd9e532019-06-07 09:10:06 -0400239void GoldfishAddressSpaceHostMemoryAllocator::hostFree(GoldfishAddressSpaceBlock *block)
Roman Kiryanov79632592019-06-03 12:31:49 -0700240{
241}
Lingfeng Yang6000a8e2019-10-19 11:56:56 -0700242
Lingfeng Yang23fef582019-10-30 18:26:54 -0700243class VmoStore {
244public:
245 struct Info {
246 zx_handle_t vmo = ZX_HANDLE_INVALID;
247 uint64_t phys_addr = 0;
248 };
249
250 void add(uint64_t offset, const Info& info) {
251 AutoLock lock(mLock);
252 mInfo[offset] = info;
253 }
254
255 void remove(uint64_t offset) {
256 AutoLock lock(mLock);
257 mInfo.erase(offset);
258 }
259
260 Info get(uint64_t offset) {
261 Info res;
262 AutoLock lock(mLock);
263 auto it = mInfo.find(offset);
264 if (it == mInfo.end()) {
265 ALOGE("VmoStore::%s cannot find info on offset 0x%llx\n", __func__,
266 (unsigned long long)offset);
267 return res;
268 }
269 res = it->second;
270 return res;
271 }
272
273private:
274 Lock mLock;
275 std::unordered_map<uint64_t, Info> mInfo;
276};
277
278static Lock sVmoStoreInitLock;
279static VmoStore* sVmoStore = nullptr;
280
281static VmoStore* getVmoStore() {
282 AutoLock lock(sVmoStoreInitLock);
283 if (!sVmoStore) sVmoStore = new VmoStore;
284 return sVmoStore;
285}
286
Lingfeng Yang6000a8e2019-10-19 11:56:56 -0700287address_space_handle_t goldfish_address_space_open() {
Lingfeng Yang23fef582019-10-30 18:26:54 -0700288 zx::channel channel(GetConnectToServiceFunction()(GOLDFISH_ADDRESS_SPACE_DEVICE_NAME));
289 if (!channel) {
290 ALOGE("%s: failed to get service handle for " GOLDFISH_ADDRESS_SPACE_DEVICE_NAME,
291 __FUNCTION__);
292 return 0;
293 }
294 fuchsia::hardware::goldfish::AddressSpaceDeviceSyncPtr*
295 deviceSync = new fuchsia::hardware::goldfish::AddressSpaceDeviceSyncPtr;
296 deviceSync->Bind(std::move(channel));
297 return (address_space_handle_t)deviceSync;
Lingfeng Yang6000a8e2019-10-19 11:56:56 -0700298}
299
300void goldfish_address_space_close(address_space_handle_t handle) {
Lingfeng Yang23fef582019-10-30 18:26:54 -0700301 fuchsia::hardware::goldfish::AddressSpaceDeviceSyncPtr* deviceSync =
302 reinterpret_cast<
303 fuchsia::hardware::goldfish::AddressSpaceDeviceSyncPtr*>(handle);
304 delete deviceSync;
305}
306
307bool goldfish_address_space_set_subdevice_type(
308 address_space_handle_t handle, GoldfishAddressSpaceSubdeviceType type,
309 address_space_handle_t* handle_out) {
310
311 fuchsia::hardware::goldfish::AddressSpaceDeviceSyncPtr* deviceSync =
312 reinterpret_cast<
313 fuchsia::hardware::goldfish::AddressSpaceDeviceSyncPtr*>(handle);
314
315 fuchsia::hardware::goldfish::AddressSpaceChildDriverSyncPtr*
316 childSync = new fuchsia::hardware::goldfish::AddressSpaceChildDriverSyncPtr;
317
318 zx_status_t res = (*(*deviceSync)).OpenChildDriver(
319 static_cast<fuchsia::hardware::goldfish::AddressSpaceChildDriverType>(type),
320 (*childSync).NewRequest());
321
322 // On creating a subdevice, in our use cases we wont be needing the
323 // original device sync anymore, so get rid of it.
324 delete deviceSync;
325
326 *handle_out = (void*)childSync;
327
328 return true;
Lingfeng Yang6000a8e2019-10-19 11:56:56 -0700329}
330
331bool goldfish_address_space_allocate(
Lingfeng Yang23fef582019-10-30 18:26:54 -0700332 address_space_handle_t handle,
333 size_t size, uint64_t* phys_addr, uint64_t* offset) {
334 fuchsia::hardware::goldfish::AddressSpaceChildDriverSyncPtr* deviceSync =
335 reinterpret_cast<
336 fuchsia::hardware::goldfish::AddressSpaceChildDriverSyncPtr*>(handle);
337
338 int32_t res = ZX_OK;
339 zx::vmo vmo;
340 zx_status_t status = (*(*deviceSync)).AllocateBlock(size, &res, phys_addr, &vmo);
341 if (status != ZX_OK || res != ZX_OK) {
342 ALOGE("%s: allocate block failed: %d:%d", __func__, status, res);
343 return false;
344 }
345
346 *offset = 0;
347
348 VmoStore::Info info = {
349 vmo.release(),
350 *phys_addr,
351 };
352
353 getVmoStore()->add(*offset, info);
354 return true;
Lingfeng Yang6000a8e2019-10-19 11:56:56 -0700355}
356
357bool goldfish_address_space_free(
Lingfeng Yang23fef582019-10-30 18:26:54 -0700358 address_space_handle_t handle, uint64_t offset) {
359 auto info = getVmoStore()->get(offset);
360 if (info.vmo == ZX_HANDLE_INVALID) return false;
361 zx_handle_close(info.vmo);
362
363 fuchsia::hardware::goldfish::AddressSpaceChildDriverSyncPtr* deviceSync =
364 reinterpret_cast<
365 fuchsia::hardware::goldfish::AddressSpaceChildDriverSyncPtr*>(handle);
366
367 int32_t res = ZX_OK;
368 zx_status_t status = (*(*deviceSync)).DeallocateBlock(info.phys_addr, &res);
369 if (status != ZX_OK || res != ZX_OK) {
370 ALOGE("%s: deallocate block failed: %d:%d", __func__, status, res);
371 return false;
372 }
373
374 return true;
Lingfeng Yang6000a8e2019-10-19 11:56:56 -0700375}
376
377bool goldfish_address_space_claim_shared(
Lingfeng Yang23fef582019-10-30 18:26:54 -0700378 address_space_handle_t handle, uint64_t offset, uint64_t size) {
379
380 fuchsia::hardware::goldfish::AddressSpaceChildDriverSyncPtr* deviceSync =
381 reinterpret_cast<
382 fuchsia::hardware::goldfish::AddressSpaceChildDriverSyncPtr*>(handle);
383 zx::vmo vmo;
384 zx_status_t res;
385 zx_status_t status = (*(*deviceSync)).ClaimSharedBlock(offset, size, &res, &vmo);
386
387 VmoStore::Info info = {
388 vmo.release(),
389 };
390
391 getVmoStore()->add(offset, info);
392
393 if (status != ZX_OK) return false;
394
395 return true;
Lingfeng Yang6000a8e2019-10-19 11:56:56 -0700396}
397
398bool goldfish_address_space_unclaim_shared(
Lingfeng Yang23fef582019-10-30 18:26:54 -0700399 address_space_handle_t handle, uint64_t offset) {
400 fuchsia::hardware::goldfish::AddressSpaceChildDriverSyncPtr* deviceSync =
401 reinterpret_cast<
402 fuchsia::hardware::goldfish::AddressSpaceChildDriverSyncPtr*>(handle);
403 zx::vmo vmo;
404 zx_status_t res;
405 zx_status_t status = (*(*deviceSync)).UnclaimSharedBlock(offset, &res);
406
407 if (status != ZX_OK) return false;
408
409 getVmoStore()->remove(offset);
410 return true;
Lingfeng Yang6000a8e2019-10-19 11:56:56 -0700411}
412
413// pgoff is the offset into the page to return in the result
414void* goldfish_address_space_map(
Lingfeng Yang23fef582019-10-30 18:26:54 -0700415 address_space_handle_t handle,
416 uint64_t offset, uint64_t size,
417 uint64_t pgoff) {
418
419 auto info = getVmoStore()->get(offset);
420 if (info.vmo == ZX_HANDLE_INVALID) return nullptr;
421
422 zx_vaddr_t ptr = 0;
423 zx_status_t status =
424 zx_vmar_map(zx_vmar_root_self(),
425 ZX_VM_PERM_READ | ZX_VM_PERM_WRITE,
426 0, info.vmo,
427 0, size,
428 &ptr);
429 return (void*)(((char*)ptr) + (uintptr_t)(pgoff & (PAGE_SIZE - 1)));
Lingfeng Yang6000a8e2019-10-19 11:56:56 -0700430}
431
Lingfeng Yang23fef582019-10-30 18:26:54 -0700432void goldfish_address_space_unmap(void* ptr, uint64_t size) {
433 zx_vmar_unmap(zx_vmar_root_self(),
434 (zx_vaddr_t)(((uintptr_t)ptr) & (uintptr_t)(~(PAGE_SIZE - 1))),
435 size);
Lingfeng Yang6000a8e2019-10-19 11:56:56 -0700436}
437
438bool goldfish_address_space_ping(
439 address_space_handle_t handle,
440 struct goldfish_address_space_ping* ping) {
Lingfeng Yang23fef582019-10-30 18:26:54 -0700441
442 AddressSpaceChildDriverPingMessage fuchsiaPing =
443 *(AddressSpaceChildDriverPingMessage*)ping;
444
445 AddressSpaceChildDriverSyncPtr* deviceSync =
446 reinterpret_cast<
447 AddressSpaceChildDriverSyncPtr*>(handle);
448
449 AddressSpaceChildDriverPingMessage res;
450 zx_status_t pingStatus;
451 zx_status_t status = (*(*deviceSync)).Ping(fuchsiaPing, &pingStatus, &res);
452
453 if (pingStatus != ZX_OK) {
454 return false;
455 }
456
457 *ping = *(struct goldfish_address_space_ping*)(&res);
458 return true;
Lingfeng Yang6000a8e2019-10-19 11:56:56 -0700459}