• 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 "android/emulation/hostdevices/HostAddressSpace.h"
17
18#include <memory>
19
20#if PLATFORM_SDK_VERSION < 26
21#include <cutils/log.h>
22#else
23#include <log/log.h>
24#endif
25
26#include <errno.h>
27#include "goldfish_address_space.h"
28
29namespace {
30
31const int HOST_MEMORY_ALLOCATOR_COMMAND_ALLOCATE_ID = 1;
32const int HOST_MEMORY_ALLOCATOR_COMMAND_UNALLOCATE_ID = 2;
33
34}  // namsepace
35
36using android::HostAddressSpaceDevice;
37using android::emulation::AddressSpaceDevicePingInfo;
38
39GoldfishAddressSpaceBlockProvider::GoldfishAddressSpaceBlockProvider(GoldfishAddressSpaceSubdeviceType subdevice)
40    : m_handle(HostAddressSpaceDevice::get()->open())
41{
42    if ((subdevice != GoldfishAddressSpaceSubdeviceType::NoSubdevice) && is_opened()) {
43        AddressSpaceDevicePingInfo request;
44        ::memset(&request, 0, sizeof(request));
45        request.metadata = subdevice;
46
47        HostAddressSpaceDevice::get()->ping(m_handle, &request);
48    }
49}
50
51GoldfishAddressSpaceBlockProvider::~GoldfishAddressSpaceBlockProvider()
52{
53    if (is_opened()) {
54        HostAddressSpaceDevice::get()->close(m_handle);
55    }
56}
57
58bool GoldfishAddressSpaceBlockProvider::is_opened() const
59{
60    return m_handle > 0;
61}
62
63void GoldfishAddressSpaceBlockProvider::close()
64{
65    if (is_opened()) {
66        HostAddressSpaceDevice::get()->close(m_handle);
67        m_handle = 0;
68    }
69}
70
71address_space_handle_t GoldfishAddressSpaceBlockProvider::release()
72{
73    address_space_handle_t handle = m_handle;
74    m_handle = 0;
75    return handle;
76}
77
78void GoldfishAddressSpaceBlockProvider::closeHandle(address_space_handle_t handle)
79{
80    HostAddressSpaceDevice::get()->close(handle);
81}
82
83GoldfishAddressSpaceBlock::GoldfishAddressSpaceBlock()
84    : m_handle(0)
85    , m_mmaped_ptr(NULL)
86    , m_phys_addr(0)
87    , m_host_addr(0)
88    , m_offset(0)
89    , m_size(0)
90    , m_is_shared_mapping(false) {}
91
92GoldfishAddressSpaceBlock::~GoldfishAddressSpaceBlock()
93{
94    destroy();
95}
96
97GoldfishAddressSpaceBlock &GoldfishAddressSpaceBlock::operator=(const GoldfishAddressSpaceBlock &rhs)
98{
99    m_mmaped_ptr = rhs.m_mmaped_ptr;
100    m_phys_addr = rhs.m_phys_addr;
101    m_host_addr = rhs.m_host_addr;
102    m_offset = rhs.m_offset;
103    m_size = rhs.m_size;
104    m_is_shared_mapping = rhs.m_is_shared_mapping;
105    m_handle = rhs.m_handle;
106    return *this;
107}
108
109bool GoldfishAddressSpaceBlock::allocate(GoldfishAddressSpaceBlockProvider *provider, size_t size)
110{
111    destroy();
112
113    if (!provider->is_opened()) {
114        return false;
115    }
116
117    m_size = size;
118    m_offset =
119        HostAddressSpaceDevice::get()->allocBlock(
120            provider->m_handle, size, &m_phys_addr);
121    m_handle = provider->m_handle;
122    m_is_shared_mapping = false;
123
124    return true;
125}
126
127bool GoldfishAddressSpaceBlock::claimShared(GoldfishAddressSpaceBlockProvider *provider, uint64_t offset, uint64_t size)
128{
129    destroy();
130
131    if (!provider->is_opened()) {
132        return false;
133    }
134
135    int claimRes = HostAddressSpaceDevice::get()->claimShared(
136            provider->m_handle, offset, size);
137
138    if (claimRes) {
139        ALOGE("%s: failed to claim shared region. Error: %d\n", __func__, claimRes);
140        return false;
141    }
142
143    m_size = size;
144    m_offset = offset;
145    m_handle = provider->m_handle;
146    m_is_shared_mapping = true;
147    m_phys_addr = HostAddressSpaceDevice::get()->offsetToPhysAddr(m_offset);
148
149    return true;
150}
151
152uint64_t GoldfishAddressSpaceBlock::physAddr() const
153{
154    return m_phys_addr;
155}
156
157uint64_t GoldfishAddressSpaceBlock::hostAddr() const
158{
159    return m_host_addr;
160}
161
162// In the host implementation:
163// mmap: is done by interpreting |host_addr| as the actual host address.
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
171    if (m_mmaped_ptr != nullptr) {
172        ALOGE("'mmap' called for an already mmaped address block 0x%llx %d", (unsigned long long)m_mmaped_ptr, nullptr == m_mmaped_ptr);
173        ::abort();
174    }
175
176    m_mmaped_ptr = (void*)(uintptr_t)(host_addr & (~(PAGE_SIZE - 1)));
177    m_host_addr = host_addr;
178
179    return guestPtr();
180}
181
182void *GoldfishAddressSpaceBlock::guestPtr() const
183{
184    return reinterpret_cast<char *>(m_mmaped_ptr) + (m_host_addr & (PAGE_SIZE - 1));
185}
186
187void GoldfishAddressSpaceBlock::destroy()
188{
189    if (m_mmaped_ptr && m_size) {
190        m_mmaped_ptr = NULL;
191    }
192
193    if (m_size) {
194        if (m_is_shared_mapping) {
195            HostAddressSpaceDevice::get()->unclaimShared(m_handle, m_offset);
196        } else {
197            HostAddressSpaceDevice::get()->freeBlock(m_handle, m_offset);
198        }
199        m_phys_addr = 0;
200        m_host_addr = 0;
201        m_offset = 0;
202        m_size = 0;
203    }
204}
205
206void GoldfishAddressSpaceBlock::release()
207{
208    m_handle = 0;
209    m_mmaped_ptr = NULL;
210    m_phys_addr = 0;
211    m_host_addr = 0;
212    m_offset = 0;
213    m_size = 0;
214}
215
216int GoldfishAddressSpaceBlock::memoryMap(void *addr,
217                                         size_t,
218                                         address_space_handle_t,
219                                         uint64_t,
220                                         void** dst) {
221    *dst = addr;
222    return 0;
223}
224
225void GoldfishAddressSpaceBlock::memoryUnmap(void *ptr, size_t size) {}
226
227GoldfishAddressSpaceHostMemoryAllocator::GoldfishAddressSpaceHostMemoryAllocator(bool useSharedSlots)
228  : m_provider(useSharedSlots
229        ? GoldfishAddressSpaceSubdeviceType::SharedSlotsHostMemoryAllocator
230        : GoldfishAddressSpaceSubdeviceType::HostMemoryAllocator),
231    m_useSharedSlots(useSharedSlots)
232{}
233
234bool GoldfishAddressSpaceHostMemoryAllocator::is_opened() const { return m_provider.is_opened(); }
235
236long GoldfishAddressSpaceHostMemoryAllocator::hostMalloc(GoldfishAddressSpaceBlock *block, size_t size)
237{
238    if (size == 0) {
239        return -EINVAL;
240    }
241    if (block->size() > 0) {
242        return -EINVAL;
243    }
244    if (!m_provider.is_opened()) {
245        return -ENODEV;
246    }
247
248    AddressSpaceDevicePingInfo request;
249    if (m_useSharedSlots) {
250        ::memset(&request, 0, sizeof(request));
251        request.size = block->size();
252        request.metadata = HOST_MEMORY_ALLOCATOR_COMMAND_ALLOCATE_ID;
253
254        HostAddressSpaceDevice::get()->ping(m_provider.m_handle, &request);
255
256        block->claimShared(&m_provider, request.phys_addr, request.size);
257
258        void *hostPtr = HostAddressSpaceDevice::get()->getHostAddr(block->physAddr());
259        block->mmap(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(hostPtr)));
260    } else {
261        if (!block->allocate(&m_provider, size)) {
262            return -ENOMEM;
263        }
264
265        ::memset(&request, 0, sizeof(request));
266        request.phys_addr = block->physAddr();
267        request.size = block->size();
268        request.metadata = HOST_MEMORY_ALLOCATOR_COMMAND_ALLOCATE_ID;
269
270        HostAddressSpaceDevice::get()->ping(m_provider.m_handle, &request);
271
272        void *hostPtr = HostAddressSpaceDevice::get()->getHostAddr(block->physAddr());
273        block->mmap(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(hostPtr)));
274    }
275
276    return 0;
277}
278
279void GoldfishAddressSpaceHostMemoryAllocator::hostFree(GoldfishAddressSpaceBlock *block)
280{
281    if (block->size() == 0) {
282        return;
283    }
284
285    if (!m_provider.is_opened()) {
286        ALOGE("%s: device is not available", __func__);
287        ::abort();
288    }
289
290    if (block->guestPtr()) {
291        AddressSpaceDevicePingInfo request;
292        ::memset(&request, 0, sizeof(request));
293        request.phys_addr = block->physAddr();
294        request.metadata = HOST_MEMORY_ALLOCATOR_COMMAND_UNALLOCATE_ID;
295
296        HostAddressSpaceDevice::get()->ping(m_provider.m_handle, &request);
297    }
298
299    block->replace(NULL);
300}
301
302address_space_handle_t goldfish_address_space_open() {
303    return HostAddressSpaceDevice::get()->open();
304}
305
306void goldfish_address_space_close(address_space_handle_t handle) {
307    HostAddressSpaceDevice::get()->close(handle);
308}
309
310bool goldfish_address_space_allocate(
311    address_space_handle_t handle,
312    size_t size, uint64_t* phys_addr, uint64_t* offset) {
313
314    *offset =
315        HostAddressSpaceDevice::get()->allocBlock(
316            handle, size, phys_addr);
317
318    return true;
319}
320
321bool goldfish_address_space_free(
322    address_space_handle_t handle, uint64_t offset) {
323    HostAddressSpaceDevice::get()->freeBlock(handle, offset);
324    return true;
325}
326
327bool goldfish_address_space_claim_shared(
328    address_space_handle_t handle, uint64_t offset, uint64_t size) {
329
330    int claimRes = HostAddressSpaceDevice::get()->claimShared(
331        handle, offset, size);
332
333    if (claimRes) {
334        ALOGE("%s: failed to claim shared region. Error: %d\n", __func__, claimRes);
335        return false;
336    }
337
338    return true;
339}
340
341bool goldfish_address_space_unclaim_shared(
342        address_space_handle_t handle, uint64_t offset) {
343    HostAddressSpaceDevice::get()->unclaimShared(handle, offset);
344    return true;
345}
346
347// pgoff is the offset into the page to return in the result
348void* goldfish_address_space_map(
349    address_space_handle_t handle,
350    uint64_t offset, uint64_t size,
351    uint64_t pgoff) {
352
353    (void)size;
354
355    void* res = HostAddressSpaceDevice::get()->
356        getHostAddr(
357            HostAddressSpaceDevice::get()->offsetToPhysAddr(offset));
358
359    if (!res) {
360        ALOGE("%s: failed to map. errno: %d\n", __func__, errno);
361        return nullptr;
362    }
363
364    return (void*)(((char*)res) + (uintptr_t)(pgoff & (PAGE_SIZE - 1)));
365}
366
367// same address space
368void goldfish_address_space_unmap(void*, uint64_t) { }
369
370bool goldfish_address_space_set_subdevice_type(
371    address_space_handle_t handle, GoldfishAddressSpaceSubdeviceType type,
372    address_space_handle_t* handle_out) {
373    struct address_space_ping request;
374    request.metadata = (uint64_t)type;
375    *handle_out = handle;
376    return goldfish_address_space_ping(handle, &request);
377}
378
379bool goldfish_address_space_ping(
380    address_space_handle_t handle,
381    struct address_space_ping* ping) {
382
383    AddressSpaceDevicePingInfo* asHostPingInfo =
384        reinterpret_cast<AddressSpaceDevicePingInfo*>(ping);
385
386    HostAddressSpaceDevice::get()->ping(handle, asHostPingInfo);
387
388    return true;
389}
390