Serenity Operating System
1/*
2 * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include "MmapRegion.h"
8#include "Emulator.h"
9#include <AK/ByteReader.h>
10#include <string.h>
11#include <sys/mman.h>
12
13namespace UserspaceEmulator {
14
15static void* mmap_initialized(size_t bytes, char initial_value, char const* name)
16{
17 auto* ptr = mmap_with_name(nullptr, bytes, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0, name);
18 VERIFY(ptr != MAP_FAILED);
19 memset(ptr, initial_value, bytes);
20 return ptr;
21}
22
23static void free_pages(void* ptr, size_t bytes)
24{
25 int rc = munmap(ptr, bytes);
26 VERIFY(rc == 0);
27}
28
29NonnullOwnPtr<MmapRegion> MmapRegion::create_anonymous(u32 base, u32 size, u32 prot, DeprecatedString name)
30{
31 auto* data = (u8*)mmap_initialized(size, 0, DeprecatedString::formatted("(UE) {}", name).characters());
32 auto* shadow_data = (u8*)mmap_initialized(size, 1, "MmapRegion ShadowData");
33 auto region = adopt_own(*new MmapRegion(base, size, prot, data, shadow_data));
34 region->m_name = move(name);
35 return region;
36}
37
38NonnullOwnPtr<MmapRegion> MmapRegion::create_file_backed(u32 base, u32 size, u32 prot, int flags, int fd, off_t offset, DeprecatedString name)
39{
40 // Since we put the memory to an arbitrary location, do not pass MAP_FIXED and MAP_FIXED_NOREPLACE to the Kernel.
41 auto real_flags = flags & ~(MAP_FIXED | MAP_FIXED_NOREPLACE);
42 auto* data = (u8*)mmap_with_name(nullptr, size, prot, real_flags, fd, offset, name.is_empty() ? nullptr : DeprecatedString::formatted("(UE) {}", name).characters());
43 VERIFY(data != MAP_FAILED);
44 auto* shadow_data = (u8*)mmap_initialized(size, 1, "MmapRegion ShadowData");
45 auto region = adopt_own(*new MmapRegion(base, size, prot, data, shadow_data));
46 region->m_file_backed = true;
47 region->m_name = move(name);
48 return region;
49}
50
51MmapRegion::MmapRegion(u32 base, u32 size, int prot, u8* data, u8* shadow_data)
52 : Region(base, size, true)
53 , m_data(data)
54 , m_shadow_data(shadow_data)
55{
56 set_prot(prot);
57}
58
59MmapRegion::~MmapRegion()
60{
61 free_pages(m_data, size());
62 free_pages(m_shadow_data, size());
63}
64
65ValueWithShadow<u8> MmapRegion::read8(FlatPtr offset)
66{
67 if (!is_readable()) {
68 reportln("8-bit read from unreadable MmapRegion @ {:p}"sv, base() + offset);
69 emulator().dump_backtrace();
70 TODO();
71 }
72
73 if (is_malloc_block()) {
74 if (auto* tracer = emulator().malloc_tracer())
75 tracer->audit_read(*this, base() + offset, 1);
76 }
77
78 VERIFY(offset < size());
79 return { m_data[offset], m_shadow_data[offset] };
80}
81
82ValueWithShadow<u16> MmapRegion::read16(u32 offset)
83{
84 if (!is_readable()) {
85 reportln("16-bit read from unreadable MmapRegion @ {:p}"sv, base() + offset);
86 emulator().dump_backtrace();
87 TODO();
88 }
89
90 if (is_malloc_block()) {
91 if (auto* tracer = emulator().malloc_tracer())
92 tracer->audit_read(*this, base() + offset, 2);
93 }
94
95 VERIFY(offset + 1 < size());
96 u16 value, shadow;
97 ByteReader::load(m_data + offset, value);
98 ByteReader::load(m_shadow_data + offset, shadow);
99
100 return { value, shadow };
101}
102
103ValueWithShadow<u32> MmapRegion::read32(u32 offset)
104{
105 if (!is_readable()) {
106 reportln("32-bit read from unreadable MmapRegion @ {:p}"sv, base() + offset);
107 emulator().dump_backtrace();
108 TODO();
109 }
110
111 if (is_malloc_block()) {
112 if (auto* tracer = emulator().malloc_tracer())
113 tracer->audit_read(*this, base() + offset, 4);
114 }
115
116 VERIFY(offset + 3 < size());
117 u32 value, shadow;
118 ByteReader::load(m_data + offset, value);
119 ByteReader::load(m_shadow_data + offset, shadow);
120
121 return { value, shadow };
122}
123
124ValueWithShadow<u64> MmapRegion::read64(u32 offset)
125{
126 if (!is_readable()) {
127 reportln("64-bit read from unreadable MmapRegion @ {:p}"sv, base() + offset);
128 emulator().dump_backtrace();
129 TODO();
130 }
131
132 if (is_malloc_block()) {
133 if (auto* tracer = emulator().malloc_tracer())
134 tracer->audit_read(*this, base() + offset, 8);
135 }
136
137 VERIFY(offset + 7 < size());
138 u64 value, shadow;
139 ByteReader::load(m_data + offset, value);
140 ByteReader::load(m_shadow_data + offset, shadow);
141
142 return { value, shadow };
143}
144
145ValueWithShadow<u128> MmapRegion::read128(u32 offset)
146{
147 if (!is_readable()) {
148 reportln("128-bit read from unreadable MmapRegion @ {:p}"sv, base() + offset);
149 emulator().dump_backtrace();
150 TODO();
151 }
152
153 if (is_malloc_block()) {
154 if (auto* tracer = emulator().malloc_tracer())
155 tracer->audit_read(*this, base() + offset, 16);
156 }
157
158 VERIFY(offset + 15 < size());
159 u128 value, shadow;
160 ByteReader::load(m_data + offset, value);
161 ByteReader::load(m_shadow_data + offset, shadow);
162 return { value, shadow };
163}
164
165ValueWithShadow<u256> MmapRegion::read256(u32 offset)
166{
167 if (!is_readable()) {
168 reportln("256-bit read from unreadable MmapRegion @ {:p}"sv, base() + offset);
169 emulator().dump_backtrace();
170 TODO();
171 }
172
173 if (is_malloc_block()) {
174 if (auto* tracer = emulator().malloc_tracer())
175 tracer->audit_read(*this, base() + offset, 32);
176 }
177
178 VERIFY(offset + 31 < size());
179 u256 value, shadow;
180 ByteReader::load(m_data + offset, value);
181 ByteReader::load(m_shadow_data + offset, shadow);
182 return { value, shadow };
183}
184
185void MmapRegion::write8(u32 offset, ValueWithShadow<u8> value)
186{
187 if (!is_writable()) {
188 reportln("8-bit write from unwritable MmapRegion @ {:p}"sv, base() + offset);
189 emulator().dump_backtrace();
190 TODO();
191 }
192
193 if (is_malloc_block()) {
194 if (auto* tracer = emulator().malloc_tracer())
195 tracer->audit_write(*this, base() + offset, 1);
196 }
197
198 VERIFY(offset < size());
199 m_data[offset] = value.value();
200 m_shadow_data[offset] = value.shadow()[0];
201}
202
203void MmapRegion::write16(u32 offset, ValueWithShadow<u16> value)
204{
205 if (!is_writable()) {
206 reportln("16-bit write from unwritable MmapRegion @ {:p}"sv, base() + offset);
207 emulator().dump_backtrace();
208 TODO();
209 }
210
211 if (is_malloc_block()) {
212 if (auto* tracer = emulator().malloc_tracer())
213 tracer->audit_write(*this, base() + offset, 2);
214 }
215
216 VERIFY(offset + 1 < size());
217 ByteReader::store(m_data + offset, value.value());
218 ByteReader::store(m_shadow_data + offset, value.shadow());
219}
220
221void MmapRegion::write32(u32 offset, ValueWithShadow<u32> value)
222{
223 if (!is_writable()) {
224 reportln("32-bit write from unwritable MmapRegion @ {:p}"sv, base() + offset);
225 emulator().dump_backtrace();
226 TODO();
227 }
228
229 if (is_malloc_block()) {
230 if (auto* tracer = emulator().malloc_tracer())
231 tracer->audit_write(*this, base() + offset, 4);
232 }
233
234 VERIFY(offset + 3 < size());
235 VERIFY(m_data != m_shadow_data);
236 ByteReader::store(m_data + offset, value.value());
237 ByteReader::store(m_shadow_data + offset, value.shadow());
238}
239
240void MmapRegion::write64(u32 offset, ValueWithShadow<u64> value)
241{
242 if (!is_writable()) {
243 reportln("64-bit write from unwritable MmapRegion @ {:p}"sv, base() + offset);
244 emulator().dump_backtrace();
245 TODO();
246 }
247
248 if (is_malloc_block()) {
249 if (auto* tracer = emulator().malloc_tracer())
250 tracer->audit_write(*this, base() + offset, 8);
251 }
252
253 VERIFY(offset + 7 < size());
254 VERIFY(m_data != m_shadow_data);
255 ByteReader::store(m_data + offset, value.value());
256 ByteReader::store(m_shadow_data + offset, value.shadow());
257}
258
259void MmapRegion::write128(u32 offset, ValueWithShadow<u128> value)
260{
261 if (!is_writable()) {
262 reportln("128-bit write from unwritable MmapRegion @ {:p}"sv, base() + offset);
263 emulator().dump_backtrace();
264 TODO();
265 }
266
267 if (is_malloc_block()) {
268 if (auto* tracer = emulator().malloc_tracer())
269 tracer->audit_write(*this, base() + offset, 16);
270 }
271 VERIFY(offset + 15 < size());
272 VERIFY(m_data != m_shadow_data);
273 ByteReader::store(m_data + offset, value.value());
274 ByteReader::store(m_shadow_data + offset, value.shadow());
275}
276
277void MmapRegion::write256(u32 offset, ValueWithShadow<u256> value)
278{
279 if (!is_writable()) {
280 reportln("256-bit write from unwritable MmapRegion @ {:p}"sv, base() + offset);
281 emulator().dump_backtrace();
282 TODO();
283 }
284
285 if (is_malloc_block()) {
286 if (auto* tracer = emulator().malloc_tracer())
287 tracer->audit_write(*this, base() + offset, 32);
288 }
289 VERIFY(offset + 31 < size());
290 VERIFY(m_data != m_shadow_data);
291 ByteReader::store(m_data + offset, value.value());
292 ByteReader::store(m_shadow_data + offset, value.shadow());
293}
294
295NonnullOwnPtr<MmapRegion> MmapRegion::split_at(VirtualAddress offset)
296{
297 VERIFY(!m_malloc);
298 VERIFY(!m_malloc_metadata);
299 Range new_range = range();
300 Range other_range = new_range.split_at(offset);
301 auto other_region = adopt_own(*new MmapRegion(other_range.base().get(), other_range.size(), prot(), data() + new_range.size(), shadow_data() + new_range.size()));
302 other_region->m_file_backed = m_file_backed;
303 other_region->m_name = m_name;
304 set_range(new_range);
305 return other_region;
306}
307
308void MmapRegion::set_prot(int prot)
309{
310 set_readable(prot & PROT_READ);
311 set_writable(prot & PROT_WRITE);
312 set_executable(prot & PROT_EXEC);
313 if (m_file_backed) {
314 if (mprotect(m_data, size(), prot & ~PROT_EXEC) < 0) {
315 perror("MmapRegion::set_prot: mprotect");
316 exit(1);
317 }
318 }
319}
320
321void MmapRegion::set_name(DeprecatedString name)
322{
323 m_name = move(name);
324 set_mmap_name(range().base().as_ptr(), range().size(), DeprecatedString::formatted("(UE) {}", m_name).characters());
325}
326
327}