• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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