• 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 = 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