• 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 #if PLATFORM_SDK_VERSION < 26
17 #include <cutils/log.h>
18 #else
19 #include <log/log.h>
20 #endif
21 
22 #include "goldfish_address_space.h"
23 
24 #ifdef HOST_BUILD
25 
26 #include "android/base/SubAllocator.h"
27 #include "android/base/memory/LazyInstance.h"
28 
29 // AddressSpaceHost is a global class for obtaining physical addresses
30 // for the host-side build.
31 class AddressSpaceHost {
32 public:
AddressSpaceHost()33     AddressSpaceHost() : mAlloc(0, 16ULL * 1024ULL * 1048576ULL, 4096) { }
alloc(size_t size)34     uint64_t alloc(size_t size) {
35         return (uint64_t)(uintptr_t)mAlloc.alloc(size);
36     }
free(uint64_t addr)37     void free(uint64_t addr) {
38         mAlloc.free((void*)(uintptr_t)addr);
39     }
40 private:
41     android::base::SubAllocator mAlloc;
42 };
43 
44 static android::base::LazyInstance<AddressSpaceHost> sAddressSpaceHost =
45     LAZY_INSTANCE_INIT;
46 
47 // It may seem like there should be one allocator per provider,
48 // but to properly reflect the guest behavior where there is only one
49 // allocator in the system and multiple providers are possible,
50 // we need to have a separate global object (sAddressSpaceHost).
GoldfishAddressSpaceBlockProvider()51 GoldfishAddressSpaceBlockProvider::GoldfishAddressSpaceBlockProvider()
52     : mAlloc(sAddressSpaceHost.ptr()) {}
53 
~GoldfishAddressSpaceBlockProvider()54 GoldfishAddressSpaceBlockProvider::~GoldfishAddressSpaceBlockProvider() { }
55 
allocPhys(size_t size)56 uint64_t GoldfishAddressSpaceBlockProvider::allocPhys(size_t size) {
57     AddressSpaceHost* hostAlloc = reinterpret_cast<AddressSpaceHost*>(mAlloc);
58     return hostAlloc->alloc(size);
59 }
60 
freePhys(uint64_t phys)61 void GoldfishAddressSpaceBlockProvider::freePhys(uint64_t phys) {
62     AddressSpaceHost* hostAlloc = reinterpret_cast<AddressSpaceHost*>(mAlloc);
63     return hostAlloc->free(phys);
64 }
65 
GoldfishAddressSpaceBlock()66 GoldfishAddressSpaceBlock::GoldfishAddressSpaceBlock() :
67     m_alloced(false), m_guest_ptr(NULL), m_phys_addr(0), m_provider(NULL) {}
~GoldfishAddressSpaceBlock()68 GoldfishAddressSpaceBlock::~GoldfishAddressSpaceBlock() { destroy(); }
69 
operator =(const GoldfishAddressSpaceBlock & rhs)70 GoldfishAddressSpaceBlock &GoldfishAddressSpaceBlock::operator=(const GoldfishAddressSpaceBlock &rhs)
71 {
72     m_guest_ptr = rhs.m_guest_ptr;
73     m_phys_addr = rhs.m_phys_addr;
74     m_provider = rhs.m_provider;
75     return *this;
76 }
77 
allocate(GoldfishAddressSpaceBlockProvider * provider,size_t size)78 bool GoldfishAddressSpaceBlock::allocate(GoldfishAddressSpaceBlockProvider *provider, size_t size)
79 {
80     destroy();
81     m_phys_addr = provider->allocPhys(size);
82     m_alloced = true;
83     m_provider = provider;
84     return true;
85 }
86 
physAddr() const87 uint64_t GoldfishAddressSpaceBlock::physAddr() const
88 {
89     return m_phys_addr;
90 }
91 
hostAddr() const92 uint64_t GoldfishAddressSpaceBlock::hostAddr() const
93 {
94     return 42;  // some random number, not used
95 }
96 
mmap(uint64_t opaque)97 void *GoldfishAddressSpaceBlock::mmap(uint64_t opaque)
98 {
99     m_guest_ptr = reinterpret_cast<void *>(opaque);
100     return m_guest_ptr;
101 }
102 
guestPtr() const103 void *GoldfishAddressSpaceBlock::guestPtr() const
104 {
105     return m_guest_ptr;
106 }
107 
destroy()108 void GoldfishAddressSpaceBlock::destroy()
109 {
110     if (m_alloced) {
111         m_guest_ptr = NULL;
112         if (m_provider) {
113             m_provider->freePhys(m_phys_addr);
114         }
115         m_alloced = false;
116     }
117 }
118 
replace(GoldfishAddressSpaceBlock * other)119 void GoldfishAddressSpaceBlock::replace(GoldfishAddressSpaceBlock *other)
120 {
121     if (other) {
122         this->m_guest_ptr = other->m_guest_ptr;
123         other->m_guest_ptr = NULL;
124     } else {
125         this->m_guest_ptr = NULL;
126     }
127 }
128 #elif __Fuchsia__
129 #include <fcntl.h>
130 #include <fuchsia/hardware/goldfish/address/space/c/fidl.h>
131 #include <lib/fdio/fdio.h>
132 #include <stdlib.h>
133 #include <sys/stat.h>
134 #include <sys/types.h>
135 #include <unistd.h>
136 #include <zircon/process.h>
137 #include <zircon/syscalls.h>
138 #include <zircon/syscalls/object.h>
139 
GoldfishAddressSpaceBlockProvider()140 GoldfishAddressSpaceBlockProvider::GoldfishAddressSpaceBlockProvider() {
141     fdio_get_service_handle(::open(GOLDFISH_ADDRESS_SPACE_DEVICE_NAME, O_RDWR), &m_channel);
142 }
143 
~GoldfishAddressSpaceBlockProvider()144 GoldfishAddressSpaceBlockProvider::~GoldfishAddressSpaceBlockProvider()
145 {
146     zx_handle_close(m_channel);
147 }
148 
GoldfishAddressSpaceBlock()149 GoldfishAddressSpaceBlock::GoldfishAddressSpaceBlock()
150     : m_vmo(ZX_HANDLE_INVALID)
151     , m_channel(ZX_HANDLE_INVALID)
152     , m_mmaped_ptr(NULL)
153     , m_phys_addr(0)
154     , m_host_addr(0)
155     , m_offset(0)
156     , m_size(0) {}
157 
~GoldfishAddressSpaceBlock()158 GoldfishAddressSpaceBlock::~GoldfishAddressSpaceBlock()
159 {
160     destroy();
161 }
162 
operator =(const GoldfishAddressSpaceBlock & rhs)163 GoldfishAddressSpaceBlock &GoldfishAddressSpaceBlock::operator=(const GoldfishAddressSpaceBlock &rhs)
164 {
165     m_vmo = rhs.m_vmo;
166     m_mmaped_ptr = rhs.m_mmaped_ptr;
167     m_phys_addr = rhs.m_phys_addr;
168     m_host_addr = rhs.m_host_addr;
169     m_offset = rhs.m_offset;
170     m_size = rhs.m_size;
171     m_channel = rhs.m_channel;
172 
173     return *this;
174 }
175 
allocate(GoldfishAddressSpaceBlockProvider * provider,size_t size)176 bool GoldfishAddressSpaceBlock::allocate(GoldfishAddressSpaceBlockProvider *provider, size_t size)
177 {
178     ALOGD("%s: Ask for block of size 0x%llx\n", __func__,
179          (unsigned long long)size);
180 
181     destroy();
182 
183     if (!provider->is_opened()) {
184         return false;
185     }
186 
187     int32_t res = ZX_OK;
188     zx_status_t status =
189         fuchsia_hardware_goldfish_address_space_DeviceAllocateBlock(
190             provider->m_channel, size, &res, &m_phys_addr, &m_vmo);
191     if (status != ZX_OK || res != ZX_OK) {
192         ALOGE("%s: allocate block failed: %d:%d", __func__, status, res);
193         return false;
194     }
195 
196     m_offset = 0;
197     m_size = size;
198 
199     ALOGD("%s: allocate returned offset 0x%llx size 0x%llx\n", __func__,
200           (unsigned long long)m_offset,
201           (unsigned long long)m_size);
202 
203     m_channel = provider->m_channel;
204     return true;
205 }
206 
physAddr() const207 uint64_t GoldfishAddressSpaceBlock::physAddr() const
208 {
209     return m_phys_addr;
210 }
211 
hostAddr() const212 uint64_t GoldfishAddressSpaceBlock::hostAddr() const
213 {
214     return m_host_addr;
215 }
216 
mmap(uint64_t host_addr)217 void *GoldfishAddressSpaceBlock::mmap(uint64_t host_addr)
218 {
219     if (m_size == 0) {
220         ALOGE("%s: called with zero size\n", __func__);
221         return NULL;
222     }
223     if (m_mmaped_ptr) {
224         ALOGE("'mmap' called for an already mmaped address block");
225         ::abort();
226     }
227 
228     zx_vaddr_t ptr = 0;
229     zx_status_t status = zx_vmar_map(zx_vmar_root_self(),
230                                      ZX_VM_PERM_READ | ZX_VM_PERM_WRITE,
231                                      0, m_vmo,
232                                      m_offset,
233                                      m_size,
234                                      &ptr);
235     if (status != ZX_OK) {
236         ALOGE("%s: host memory map failed with size 0x%llx "
237               "off 0x%llx status %d\n",
238               __func__,
239               (unsigned long long)m_size,
240               (unsigned long long)m_offset, status);
241         return NULL;
242     } else {
243         m_mmaped_ptr = (void*)ptr;
244         m_host_addr = host_addr;
245         return guestPtr();
246     }
247 }
248 
guestPtr() const249 void *GoldfishAddressSpaceBlock::guestPtr() const
250 {
251     return reinterpret_cast<char *>(m_mmaped_ptr) + (m_host_addr & (PAGE_SIZE - 1));
252 }
253 
destroy()254 void GoldfishAddressSpaceBlock::destroy()
255 {
256     if (m_mmaped_ptr && m_size) {
257         zx_vmar_unmap(zx_vmar_root_self(),
258                       (zx_vaddr_t)m_mmaped_ptr,
259                       m_size);
260         m_mmaped_ptr = NULL;
261     }
262 
263     if (m_size) {
264         zx_handle_close(m_vmo);
265         m_vmo = ZX_HANDLE_INVALID;
266         int32_t res = ZX_OK;
267         zx_status_t status =
268             fuchsia_hardware_goldfish_address_space_DeviceDeallocateBlock(
269                 m_channel, m_phys_addr, &res);
270         if (status != ZX_OK || res != ZX_OK) {
271             ALOGE("%s: deallocate block failed: %d:%d", __func__, status, res);
272         }
273         m_channel = ZX_HANDLE_INVALID;
274         m_phys_addr = 0;
275         m_host_addr = 0;
276         m_offset = 0;
277         m_size = 0;
278     }
279 }
280 
replace(GoldfishAddressSpaceBlock * other)281 void GoldfishAddressSpaceBlock::replace(GoldfishAddressSpaceBlock *other)
282 {
283     destroy();
284 
285     if (other) {
286         *this = *other;
287         *other = GoldfishAddressSpaceBlock();
288     }
289 }
290 
is_opened()291 bool GoldfishAddressSpaceBlockProvider::is_opened()
292 {
293     return m_channel != ZX_HANDLE_INVALID;
294 }
295 #else
296 #include <linux/types.h>
297 #include <linux/ioctl.h>
298 #include <sys/types.h>
299 #include <sys/stat.h>
300 #include <sys/mman.h>
301 #include <sys/ioctl.h>
302 #include <fcntl.h>
303 #include <unistd.h>
304 #include <cstdlib>
305 #include <errno.h>
306 
307 struct goldfish_address_space_allocate_block {
308     __u64 size;
309     __u64 offset;
310     __u64 phys_addr;
311 };
312 
313 #define GOLDFISH_ADDRESS_SPACE_IOCTL_MAGIC		'G'
314 #define GOLDFISH_ADDRESS_SPACE_IOCTL_OP(OP, T)		_IOWR(GOLDFISH_ADDRESS_SPACE_IOCTL_MAGIC, OP, T)
315 #define GOLDFISH_ADDRESS_SPACE_IOCTL_ALLOCATE_BLOCK	GOLDFISH_ADDRESS_SPACE_IOCTL_OP(10, struct goldfish_address_space_allocate_block)
316 #define GOLDFISH_ADDRESS_SPACE_IOCTL_DEALLOCATE_BLOCK	GOLDFISH_ADDRESS_SPACE_IOCTL_OP(11, __u64)
317 
318 const char GOLDFISH_ADDRESS_SPACE_DEVICE_NAME[] = "/dev/goldfish_address_space";
319 
GoldfishAddressSpaceBlockProvider()320 GoldfishAddressSpaceBlockProvider::GoldfishAddressSpaceBlockProvider()
321     : m_fd(::open(GOLDFISH_ADDRESS_SPACE_DEVICE_NAME, O_RDWR)) {}
322 
~GoldfishAddressSpaceBlockProvider()323 GoldfishAddressSpaceBlockProvider::~GoldfishAddressSpaceBlockProvider()
324 {
325     ::close(m_fd);
326 }
327 
GoldfishAddressSpaceBlock()328 GoldfishAddressSpaceBlock::GoldfishAddressSpaceBlock()
329     : m_mmaped_ptr(NULL)
330     , m_phys_addr(0)
331     , m_host_addr(0)
332     , m_offset(0)
333     , m_size(0)
334     , m_fd(-1) {}
335 
~GoldfishAddressSpaceBlock()336 GoldfishAddressSpaceBlock::~GoldfishAddressSpaceBlock()
337 {
338     destroy();
339 }
340 
operator =(const GoldfishAddressSpaceBlock & rhs)341 GoldfishAddressSpaceBlock &GoldfishAddressSpaceBlock::operator=(const GoldfishAddressSpaceBlock &rhs)
342 {
343     m_mmaped_ptr = rhs.m_mmaped_ptr;
344     m_phys_addr = rhs.m_phys_addr;
345     m_host_addr = rhs.m_host_addr;
346     m_offset = rhs.m_offset;
347     m_size = rhs.m_size;
348     m_fd = rhs.m_fd;
349 
350     return *this;
351 }
352 
allocate(GoldfishAddressSpaceBlockProvider * provider,size_t size)353 bool GoldfishAddressSpaceBlock::allocate(GoldfishAddressSpaceBlockProvider *provider, size_t size)
354 {
355 
356     ALOGD("%s: Ask for block of size 0x%llx\n", __func__,
357          (unsigned long long)size);
358 
359     destroy();
360 
361     if (!provider->is_opened()) {
362         return false;
363     }
364 
365     struct goldfish_address_space_allocate_block request;
366     long res;
367 
368     request.size = size;
369     res = ::ioctl(provider->m_fd, GOLDFISH_ADDRESS_SPACE_IOCTL_ALLOCATE_BLOCK, &request);
370     if (res) {
371         return false;
372     } else {
373         m_phys_addr = request.phys_addr;
374 
375         m_offset = request.offset;
376         m_size = request.size;
377 
378         ALOGD("%s: ioctl allocate returned offset 0x%llx size 0x%llx\n", __func__,
379                 (unsigned long long)m_offset,
380                 (unsigned long long)m_size);
381 
382         m_fd = provider->m_fd;
383         return true;
384     }
385 }
386 
physAddr() const387 uint64_t GoldfishAddressSpaceBlock::physAddr() const
388 {
389     return m_phys_addr;
390 }
391 
hostAddr() const392 uint64_t GoldfishAddressSpaceBlock::hostAddr() const
393 {
394     return m_host_addr;
395 }
396 
mmap(uint64_t host_addr)397 void *GoldfishAddressSpaceBlock::mmap(uint64_t host_addr)
398 {
399     if (m_size == 0) {
400         ALOGE("%s: called with zero size\n", __func__);
401         return NULL;
402     }
403     if (m_mmaped_ptr) {
404         ALOGE("'mmap' called for an already mmaped address block");
405         ::abort();
406     }
407 
408     void *result = ::mmap64(NULL, m_size, PROT_WRITE, MAP_SHARED, m_fd, m_offset);
409     if (result == MAP_FAILED) {
410         ALOGE("%s: host memory map failed with size 0x%llx "
411               "off 0x%llx errno %d\n",
412               __func__,
413               (unsigned long long)m_size,
414               (unsigned long long)m_offset, errno);
415         return NULL;
416     } else {
417         m_mmaped_ptr = result;
418         m_host_addr = host_addr;
419         return guestPtr();
420     }
421 }
422 
guestPtr() const423 void *GoldfishAddressSpaceBlock::guestPtr() const
424 {
425     return reinterpret_cast<char *>(m_mmaped_ptr) + (m_host_addr & (PAGE_SIZE - 1));
426 }
427 
destroy()428 void GoldfishAddressSpaceBlock::destroy()
429 {
430     if (m_mmaped_ptr && m_size) {
431         ::munmap(m_mmaped_ptr, m_size);
432         m_mmaped_ptr = NULL;
433     }
434 
435     if (m_size) {
436         ::ioctl(m_fd, GOLDFISH_ADDRESS_SPACE_IOCTL_DEALLOCATE_BLOCK, &m_offset);
437         m_phys_addr = 0;
438         m_host_addr = 0;
439         m_offset = 0;
440         m_size = 0;
441     }
442 }
443 
replace(GoldfishAddressSpaceBlock * other)444 void GoldfishAddressSpaceBlock::replace(GoldfishAddressSpaceBlock *other)
445 {
446     destroy();
447 
448     if (other) {
449         *this = *other;
450         *other = GoldfishAddressSpaceBlock();
451     }
452 }
453 
is_opened()454 bool GoldfishAddressSpaceBlockProvider::is_opened()
455 {
456     return m_fd >= 0;
457 }
458 #endif
459