1 /*
2 * Copyright (C) 2018 The Android Open Source Project
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
17 #include "mem_map.h"
18 #include "logging.h"
19 #include "mman.h"
20
21 #include <zircon/process.h>
22 #include <zircon/syscalls.h>
23
24 namespace art {
25
26 static zx_handle_t fuchsia_lowmem_vmar = ZX_HANDLE_INVALID;
27 static zx_vaddr_t fuchsia_lowmem_base = 0;
28 static size_t fuchsia_lowmem_size = 0;
29
30 static const char map_name[] = "mmap-android";
31 static constexpr uintptr_t FUCHSIA_LOWER_MEM_START = 0x80000000;
32 static constexpr uintptr_t FUCHSIA_LOWER_MEM_SIZE = 0x60000000;
33
TargetMMapInit()34 void MemMap::TargetMMapInit() {
35 if (fuchsia_lowmem_vmar != ZX_HANDLE_INVALID) {
36 return;
37 }
38
39 zx_info_vmar_t vmarinfo;
40 CHECK_EQ(zx_object_get_info(zx_vmar_root_self(),
41 ZX_INFO_VMAR,
42 &vmarinfo,
43 sizeof(vmarinfo),
44 nullptr,
45 nullptr), ZX_OK) << "could not find info from root vmar";
46
47 uintptr_t lower_mem_start = FUCHSIA_LOWER_MEM_START - vmarinfo.base;
48 fuchsia_lowmem_size = FUCHSIA_LOWER_MEM_SIZE;
49 uint32_t allocflags = ZX_VM_FLAG_CAN_MAP_READ |
50 ZX_VM_FLAG_CAN_MAP_WRITE |
51 ZX_VM_FLAG_CAN_MAP_EXECUTE |
52 ZX_VM_FLAG_SPECIFIC;
53 CHECK_EQ(zx_vmar_allocate(zx_vmar_root_self(),
54 lower_mem_start,
55 fuchsia_lowmem_size,
56 allocflags,
57 &fuchsia_lowmem_vmar,
58 &fuchsia_lowmem_base), ZX_OK) << "could not allocate lowmem vmar";
59 }
60
TargetMMap(void * start,size_t len,int prot,int flags,int fd,off_t fd_off)61 void* MemMap::TargetMMap(void* start, size_t len, int prot, int flags, int fd, off_t fd_off) {
62 zx_status_t status;
63 uintptr_t mem = 0;
64
65 bool mmap_lower = (flags & MAP_32BIT) != 0;
66
67 // for file-based mapping use system library
68 if ((flags & MAP_ANONYMOUS) == 0) {
69 if (start != nullptr) {
70 flags |= MAP_FIXED;
71 }
72 CHECK(!mmap_lower) << "cannot map files into low memory for Fuchsia";
73 return mmap(start, len, prot, flags, fd, fd_off);
74 }
75
76 uint32_t vmarflags = 0;
77 if ((prot & PROT_READ) != 0) {
78 vmarflags |= ZX_VM_FLAG_PERM_READ;
79 }
80 if ((prot & PROT_WRITE) != 0) {
81 vmarflags |= ZX_VM_FLAG_PERM_WRITE;
82 }
83 if ((prot & PROT_EXEC) != 0) {
84 vmarflags |= ZX_VM_FLAG_PERM_EXECUTE;
85 }
86
87 if (len == 0) {
88 errno = EINVAL;
89 return MAP_FAILED;
90 }
91
92 zx_info_vmar_t vmarinfo;
93 size_t vmaroffset = 0;
94 if (start != nullptr) {
95 vmarflags |= ZX_VM_FLAG_SPECIFIC;
96 status = zx_object_get_info((mmap_lower ? fuchsia_lowmem_vmar : zx_vmar_root_self()),
97 ZX_INFO_VMAR,
98 &vmarinfo,
99 sizeof(vmarinfo),
100 nullptr,
101 nullptr);
102 if (status < 0 || reinterpret_cast<uintptr_t>(start) < vmarinfo.base) {
103 errno = EINVAL;
104 return MAP_FAILED;
105 }
106 vmaroffset = reinterpret_cast<uintptr_t>(start) - vmarinfo.base;
107 }
108
109 zx_handle_t vmo;
110 if (zx_vmo_create(len, 0, &vmo) < 0) {
111 errno = ENOMEM;
112 return MAP_FAILED;
113 }
114 zx_vmo_get_size(vmo, &len);
115 zx_object_set_property(vmo, ZX_PROP_NAME, map_name, strlen(map_name));
116
117 if (mmap_lower) {
118 status = zx_vmar_map(fuchsia_lowmem_vmar, vmaroffset, vmo, fd_off, len, vmarflags, &mem);
119 } else {
120 status = zx_vmar_map(zx_vmar_root_self(), vmaroffset, vmo, fd_off, len, vmarflags, &mem);
121 }
122 zx_handle_close(vmo);
123 if (status != ZX_OK) {
124 return MAP_FAILED;
125 }
126
127 return reinterpret_cast<void *>(mem);
128 }
129
TargetMUnmap(void * start,size_t len)130 int MemMap::TargetMUnmap(void* start, size_t len) {
131 uintptr_t addr = reinterpret_cast<uintptr_t>(start);
132 zx_handle_t alloc_vmar = zx_vmar_root_self();
133 if (addr >= fuchsia_lowmem_base && addr < fuchsia_lowmem_base + fuchsia_lowmem_size) {
134 alloc_vmar = fuchsia_lowmem_vmar;
135 }
136 zx_status_t status = zx_vmar_unmap(alloc_vmar, addr, len);
137 if (status < 0) {
138 errno = EINVAL;
139 return -1;
140 }
141 return 0;
142 }
143
144 } // namespace art
145