Serenity Operating System
at master 327 lines 9.9 kB view raw
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}