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 llcpp::fuchsia::hardware::goldfish::AddressSpaceChildDriver;
42using llcpp::fuchsia::hardware::goldfish::AddressSpaceDevice;
43using llcpp::fuchsia::hardware::goldfish::AddressSpaceChildDriverType;
44using llcpp::fuchsia::hardware::goldfish::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    zx::channel channel(GetConnectToServiceFunction()(GOLDFISH_ADDRESS_SPACE_DEVICE_NAME));
54    if (!channel) {
55        ALOGE("%s: failed to get service handle for " GOLDFISH_ADDRESS_SPACE_DEVICE_NAME,
56              __FUNCTION__);
57        return;
58    }
59    m_device = std::make_unique<AddressSpaceDevice::SyncClient>(std::move(channel));
60
61    zx::channel child_driver_server, child_driver_client;
62    zx_status_t status = zx::channel::create(0, &child_driver_server, &child_driver_client);
63    if (status != ZX_OK) {
64        ALOGE("%s: zx_channel_create failed: %d", __FUNCTION__, status);
65        return;
66    }
67
68    auto result = m_device->OpenChildDriver(
69        static_cast<AddressSpaceChildDriverType>(0 /* graphics */),
70        std::move(child_driver_server));
71    if (!result.ok()) {
72        ALOGE("%s: failed to open child driver: %d",
73              __FUNCTION__, result.status());
74        return;
75    }
76    m_child_driver = std::make_unique<AddressSpaceChildDriver::SyncClient>(std::move(child_driver_client));
77}
78
79GoldfishAddressSpaceBlockProvider::~GoldfishAddressSpaceBlockProvider()
80{
81}
82
83bool GoldfishAddressSpaceBlockProvider::is_opened() const
84{
85    return !!m_device;
86}
87
88// void GoldfishAddressSpaceBlockProvider::close() - not implemented
89// address_space_handle_t GoldfishAddressSpaceBlockProvider::release() - not imeplemented
90
91GoldfishAddressSpaceBlock::GoldfishAddressSpaceBlock()
92    : m_driver(NULL)
93    , m_vmo(ZX_HANDLE_INVALID)
94    , m_mmaped_ptr(NULL)
95    , m_phys_addr(0)
96    , m_host_addr(0)
97    , m_offset(0)
98    , m_size(0) {}
99
100GoldfishAddressSpaceBlock::~GoldfishAddressSpaceBlock()
101{
102    destroy();
103}
104
105GoldfishAddressSpaceBlock &GoldfishAddressSpaceBlock::operator=(const GoldfishAddressSpaceBlock &rhs)
106{
107    m_vmo = rhs.m_vmo;
108    m_mmaped_ptr = rhs.m_mmaped_ptr;
109    m_phys_addr = rhs.m_phys_addr;
110    m_host_addr = rhs.m_host_addr;
111    m_offset = rhs.m_offset;
112    m_size = rhs.m_size;
113    m_driver = rhs.m_driver;
114
115    return *this;
116}
117
118bool GoldfishAddressSpaceBlock::allocate(GoldfishAddressSpaceBlockProvider *provider, size_t size)
119{
120    ALOGD("%s: Ask for block of size 0x%llx\n", __func__,
121         (unsigned long long)size);
122
123    destroy();
124
125    if (!provider->is_opened()) {
126        return false;
127    }
128
129    AddressSpaceChildDriver::SyncClient* driver = provider->m_child_driver.get();
130
131    auto result = driver->AllocateBlock(size);
132    if (!result.ok() || result.Unwrap()->res != ZX_OK) {
133        ALOGE("%s: allocate block failed: %d:%d", __func__, result.status(), GET_STATUS_SAFE(result, res));
134        return false;
135    }
136    m_phys_addr = result.Unwrap()->paddr;
137    m_vmo = result.Unwrap()->vmo.release();
138
139    m_size = size;
140    m_offset = 0;
141    m_is_shared_mapping = false;
142
143    ALOGD("%s: allocate returned offset 0x%llx size 0x%llx\n", __func__,
144          (unsigned long long)m_offset,
145          (unsigned long long)m_size);
146
147    m_driver = driver;
148    return true;
149}
150
151bool GoldfishAddressSpaceBlock::claimShared(GoldfishAddressSpaceBlockProvider *provider, uint64_t offset, uint64_t size)
152{
153    ALOGE("%s: FATAL: not supported\n", __func__);
154    abort();
155}
156
157uint64_t GoldfishAddressSpaceBlock::physAddr() const
158{
159    return m_phys_addr;
160}
161
162uint64_t GoldfishAddressSpaceBlock::hostAddr() const
163{
164    return m_host_addr;
165}
166
167void *GoldfishAddressSpaceBlock::mmap(uint64_t host_addr)
168{
169    if (m_size == 0) {
170        ALOGE("%s: called with zero size\n", __func__);
171        return NULL;
172    }
173    if (m_mmaped_ptr) {
174        ALOGE("'mmap' called for an already mmaped address block");
175        ::abort();
176    }
177
178    zx_vaddr_t ptr = 0;
179    zx_status_t status = zx_vmar_map(zx_vmar_root_self(),
180                                     ZX_VM_PERM_READ | ZX_VM_PERM_WRITE,
181                                     0, m_vmo,
182                                     m_offset,
183                                     m_size,
184                                     &ptr);
185    if (status != ZX_OK) {
186        ALOGE("%s: host memory map failed with size 0x%llx "
187              "off 0x%llx status %d\n",
188              __func__,
189              (unsigned long long)m_size,
190              (unsigned long long)m_offset, status);
191        return NULL;
192    }
193
194    m_mmaped_ptr = (void*)ptr;
195    m_host_addr = host_addr;
196    return guestPtr();
197}
198
199void *GoldfishAddressSpaceBlock::guestPtr() const
200{
201    return reinterpret_cast<char *>(m_mmaped_ptr) + (m_host_addr & (PAGE_SIZE - 1));
202}
203
204void GoldfishAddressSpaceBlock::destroy()
205{
206    if (m_mmaped_ptr && m_size) {
207        zx_vmar_unmap(zx_vmar_root_self(),
208                      (zx_vaddr_t)m_mmaped_ptr,
209                      m_size);
210        m_mmaped_ptr = NULL;
211    }
212
213    if (m_size) {
214        zx_handle_close(m_vmo);
215        m_vmo = ZX_HANDLE_INVALID;
216        if (m_is_shared_mapping) {
217            // TODO
218            ALOGE("%s: unsupported: GoldfishAddressSpaceBlock destroy() for shared regions\n", __func__);
219            abort();
220            // int32_t res = ZX_OK;
221            // auto result = m_driver->UnclaimShared(m_offset);
222            // if (!result.ok() || result.Unwrap()->res != ZX_OK) {
223            //     ALOGE("%s: unclaim shared block failed: %d:%d", __func__,
224            //           result.status(), GET_STATUS_SAFE(result, res));
225            // }
226        } else {
227            auto result = m_driver->DeallocateBlock(m_phys_addr);
228            if (!result.ok() || result.Unwrap()->res != ZX_OK) {
229                ALOGE("%s: deallocate block failed: %d:%d", __func__,
230                      result.status(), GET_STATUS_SAFE(result, res));
231            }
232        }
233        m_driver = NULL;
234        m_phys_addr = 0;
235        m_host_addr = 0;
236        m_offset = 0;
237        m_size = 0;
238    }
239}
240
241GoldfishAddressSpaceHostMemoryAllocator::GoldfishAddressSpaceHostMemoryAllocator(bool useSharedSlots)
242  : m_provider(GoldfishAddressSpaceSubdeviceType::HostMemoryAllocator) { }
243
244long GoldfishAddressSpaceHostMemoryAllocator::hostMalloc(GoldfishAddressSpaceBlock *block, size_t size)
245{
246    return 0;
247}
248
249void GoldfishAddressSpaceHostMemoryAllocator::hostFree(GoldfishAddressSpaceBlock *block)
250{
251}
252
253class VmoStore {
254public:
255    struct Info {
256        zx_handle_t vmo = ZX_HANDLE_INVALID;
257        uint64_t phys_addr = 0;
258    };
259
260    void add(uint64_t offset, const Info& info) {
261        AutoLock lock(mLock);
262        mInfo[offset] = info;
263    }
264
265    void remove(uint64_t offset) {
266        AutoLock lock(mLock);
267        mInfo.erase(offset);
268    }
269
270    Info get(uint64_t offset) {
271        Info res;
272        AutoLock lock(mLock);
273        auto it = mInfo.find(offset);
274        if (it == mInfo.end()) {
275            ALOGE("VmoStore::%s cannot find info on offset 0x%llx\n", __func__,
276                  (unsigned long long)offset);
277            return res;
278        }
279        res = it->second;
280        return res;
281    }
282
283private:
284    Lock mLock;
285    std::unordered_map<uint64_t, Info> mInfo;
286};
287
288static Lock sVmoStoreInitLock;
289static VmoStore* sVmoStore = nullptr;
290
291static VmoStore* getVmoStore() {
292    AutoLock lock(sVmoStoreInitLock);
293    if (!sVmoStore) sVmoStore = new VmoStore;
294    return sVmoStore;
295}
296
297address_space_handle_t goldfish_address_space_open() {
298    zx::channel channel(GetConnectToServiceFunction()(GOLDFISH_ADDRESS_SPACE_DEVICE_NAME));
299    if (!channel) {
300        ALOGE("%s: failed to get service handle for " GOLDFISH_ADDRESS_SPACE_DEVICE_NAME,
301              __FUNCTION__);
302        return 0;
303    }
304    AddressSpaceDevice::SyncClient*
305        deviceSync = new AddressSpaceDevice::SyncClient(std::move(channel));
306    return (address_space_handle_t)deviceSync;
307}
308
309void goldfish_address_space_close(address_space_handle_t handle) {
310    AddressSpaceDevice::SyncClient* deviceSync =
311        reinterpret_cast<
312            AddressSpaceDevice::SyncClient*>(handle);
313    delete deviceSync;
314}
315
316bool goldfish_address_space_set_subdevice_type(
317    address_space_handle_t handle, GoldfishAddressSpaceSubdeviceType type,
318    address_space_handle_t* handle_out) {
319
320    AddressSpaceDevice::SyncClient* deviceSync =
321        reinterpret_cast<
322            AddressSpaceDevice::SyncClient*>(handle);
323
324    zx::channel child_driver_server, child_driver_client;
325    zx_status_t status = zx::channel::create(0, &child_driver_server, &child_driver_client);
326    if (status != ZX_OK) {
327        ALOGE("%s: zx_channel_create failed: %d", __FUNCTION__, status);
328        return false;
329    }
330
331    deviceSync->OpenChildDriver(
332        static_cast<AddressSpaceChildDriverType>(type),
333        std::move(child_driver_server));
334
335    AddressSpaceChildDriver::SyncClient*
336        childSync = new AddressSpaceChildDriver::SyncClient(std::move(child_driver_client));
337
338    // On creating a subdevice, in our use cases we wont be needing the
339    // original device sync anymore, so get rid of it.
340    delete deviceSync;
341
342    *handle_out = (void*)childSync;
343
344    return true;
345}
346
347bool goldfish_address_space_allocate(
348    address_space_handle_t handle,
349    size_t size, uint64_t* phys_addr, uint64_t* offset) {
350    AddressSpaceChildDriver::SyncClient* deviceSync =
351        reinterpret_cast<
352            AddressSpaceChildDriver::SyncClient*>(handle);
353
354    zx::vmo vmo;
355    auto result = deviceSync->AllocateBlock(size);
356    if (!result.ok() || result.Unwrap()->res != ZX_OK) {
357        ALOGE("%s: allocate block failed: %d:%d", __func__, result.status(), GET_STATUS_SAFE(result, res));
358        return false;
359    }
360    *phys_addr = result.Unwrap()->paddr;
361    vmo = std::move(result.Unwrap()->vmo);
362
363    *offset = 0;
364
365    VmoStore::Info info = {
366        vmo.release(),
367        *phys_addr,
368    };
369
370    getVmoStore()->add(*offset, info);
371    return true;
372}
373
374bool goldfish_address_space_free(
375    address_space_handle_t handle, uint64_t offset) {
376    auto info = getVmoStore()->get(offset);
377    if (info.vmo == ZX_HANDLE_INVALID) return false;
378    zx_handle_close(info.vmo);
379
380    AddressSpaceChildDriver::SyncClient* deviceSync =
381        reinterpret_cast<
382            AddressSpaceChildDriver::SyncClient*>(handle);
383
384    auto result = deviceSync->DeallocateBlock(info.phys_addr);
385    if (!result.ok() || result.Unwrap()->res != ZX_OK) {
386        ALOGE("%s: deallocate block failed: %d:%d", __func__, result.status(), GET_STATUS_SAFE(result, res));
387        return false;
388    }
389
390    return true;
391}
392
393bool goldfish_address_space_claim_shared(
394    address_space_handle_t handle, uint64_t offset, uint64_t size) {
395
396    AddressSpaceChildDriver::SyncClient* deviceSync =
397        reinterpret_cast<
398            AddressSpaceChildDriver::SyncClient*>(handle);
399
400    zx::vmo vmo;
401    auto result = deviceSync->ClaimSharedBlock(offset, size);
402    if (!result.ok() || result.Unwrap()->res != ZX_OK) {
403        ALOGE("%s: claim shared failed: %d:%d", __func__, result.status(), GET_STATUS_SAFE(result, res));
404        return false;
405    }
406    vmo = std::move(result.Unwrap()->vmo);
407
408    VmoStore::Info info = {
409        vmo.release(),
410    };
411
412    getVmoStore()->add(offset, info);
413
414    return true;
415}
416
417bool goldfish_address_space_unclaim_shared(
418    address_space_handle_t handle, uint64_t offset) {
419    AddressSpaceChildDriver::SyncClient* deviceSync =
420        reinterpret_cast<
421            AddressSpaceChildDriver::SyncClient*>(handle);
422
423    auto result = deviceSync->UnclaimSharedBlock(offset);
424    if (!result.ok() || result.Unwrap()->res != ZX_OK) {
425        ALOGE("%s: unclaim shared failed: %d:%d", __func__, result.status(), GET_STATUS_SAFE(result, res));
426        return false;
427    }
428
429    getVmoStore()->remove(offset);
430    return true;
431}
432
433// pgoff is the offset into the page to return in the result
434void* goldfish_address_space_map(
435    address_space_handle_t handle,
436    uint64_t offset, uint64_t size,
437    uint64_t pgoff) {
438
439    auto info = getVmoStore()->get(offset);
440    if (info.vmo == ZX_HANDLE_INVALID) return nullptr;
441
442    zx_vaddr_t ptr = 0;
443    zx_status_t status =
444        zx_vmar_map(zx_vmar_root_self(),
445                    ZX_VM_PERM_READ | ZX_VM_PERM_WRITE,
446                    0, info.vmo,
447                    0, size,
448                    &ptr);
449    return (void*)(((char*)ptr) + (uintptr_t)(pgoff & (PAGE_SIZE - 1)));
450}
451
452void goldfish_address_space_unmap(void* ptr, uint64_t size) {
453    zx_vmar_unmap(zx_vmar_root_self(),
454                  (zx_vaddr_t)(((uintptr_t)ptr) & (uintptr_t)(~(PAGE_SIZE - 1))),
455                  size);
456}
457
458bool goldfish_address_space_ping(
459    address_space_handle_t handle,
460    struct address_space_ping* ping) {
461
462    AddressSpaceChildDriverPingMessage fuchsiaPing =
463        *(AddressSpaceChildDriverPingMessage*)ping;
464
465    AddressSpaceChildDriver::SyncClient* deviceSync =
466        reinterpret_cast<
467            AddressSpaceChildDriver::SyncClient*>(handle);
468
469    AddressSpaceChildDriverPingMessage res;
470    auto result = deviceSync->Ping(fuchsiaPing);
471    if (!result.ok() || result.Unwrap()->res != ZX_OK) {
472        return false;
473    }
474    res = std::move(result.Unwrap()->ping);
475
476    *ping = *(struct address_space_ping*)(&res);
477    return true;
478}
479