Serenity Operating System
at master 384 lines 12 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 "SoftMMU.h" 8#include "Emulator.h" 9#include "MmapRegion.h" 10#include "Report.h" 11#include <AK/ByteBuffer.h> 12#include <AK/Memory.h> 13#include <AK/QuickSort.h> 14 15namespace UserspaceEmulator { 16 17SoftMMU::SoftMMU(Emulator& emulator) 18 : m_emulator(emulator) 19{ 20} 21 22void SoftMMU::add_region(NonnullOwnPtr<Region> region) 23{ 24 VERIFY(!find_region({ 0x23, region->base() })); 25 26 size_t first_page_in_region = region->base() / PAGE_SIZE; 27 size_t last_page_in_region = (region->base() + region->size() - 1) / PAGE_SIZE; 28 for (size_t page = first_page_in_region; page <= last_page_in_region; ++page) { 29 m_page_to_region_map[page] = region.ptr(); 30 } 31 32 m_regions.append(move(region)); 33 quick_sort((Vector<OwnPtr<Region>>&)m_regions, [](auto& a, auto& b) { return a->base() < b->base(); }); 34} 35 36void SoftMMU::remove_region(Region& region) 37{ 38 size_t first_page_in_region = region.base() / PAGE_SIZE; 39 for (size_t i = 0; i < ceil_div(region.size(), PAGE_SIZE); ++i) { 40 m_page_to_region_map[first_page_in_region + i] = nullptr; 41 } 42 43 m_regions.remove_first_matching([&](auto& entry) { return entry.ptr() == &region; }); 44} 45 46void SoftMMU::ensure_split_at(X86::LogicalAddress address) 47{ 48 // FIXME: If this fails, call Emulator::dump_backtrace 49 VERIFY(address.selector() != 0x2b); 50 51 u32 offset = address.offset(); 52 VERIFY((offset & (PAGE_SIZE - 1)) == 0); 53 size_t page_index = address.offset() / PAGE_SIZE; 54 55 if (!page_index) 56 return; 57 if (m_page_to_region_map[page_index - 1] != m_page_to_region_map[page_index]) 58 return; 59 if (!m_page_to_region_map[page_index]) 60 return; 61 62 // If we get here, we know that the page exists and belongs to a region, that there is 63 // a previous page, and that it belongs to the same region. 64 auto* old_region = verify_cast<MmapRegion>(m_page_to_region_map[page_index]); 65 66 // dbgln("splitting at {:p}", address.offset()); 67 // dbgln(" old region: {:p}-{:p}", old_region->base(), old_region->end() - 1); 68 69 NonnullOwnPtr<MmapRegion> new_region = old_region->split_at(VirtualAddress(offset)); 70 // dbgln(" new region: {:p}-{:p}", new_region->base(), new_region->end() - 1); 71 // dbgln(" up old region: {:p}-{:p}", old_region->base(), old_region->end() - 1); 72 73 size_t first_page_in_region = new_region->base() / PAGE_SIZE; 74 size_t last_page_in_region = (new_region->base() + new_region->size() - 1) / PAGE_SIZE; 75 76 // dbgln(" @ remapping pages {} thru {}", first_page_in_region, last_page_in_region); 77 78 for (size_t page = first_page_in_region; page <= last_page_in_region; ++page) { 79 VERIFY(m_page_to_region_map[page] == old_region); 80 m_page_to_region_map[page] = new_region.ptr(); 81 } 82 83 m_regions.append(move(new_region)); 84 quick_sort((Vector<OwnPtr<Region>>&)m_regions, [](auto& a, auto& b) { return a->base() < b->base(); }); 85} 86 87void SoftMMU::set_tls_region(NonnullOwnPtr<Region> region) 88{ 89 VERIFY(!m_tls_region); 90 m_tls_region = move(region); 91} 92 93ValueWithShadow<u8> SoftMMU::read8(X86::LogicalAddress address) 94{ 95 auto* region = find_region(address); 96 if (!region) { 97 reportln("SoftMMU::read8: No region for @ {:p}"sv, address.offset()); 98 m_emulator.dump_backtrace(); 99 TODO(); 100 } 101 102 if (!region->is_readable()) { 103 reportln("SoftMMU::read8: Non-readable region @ {:p}"sv, address.offset()); 104 m_emulator.dump_backtrace(); 105 TODO(); 106 } 107 108 return region->read8(address.offset() - region->base()); 109} 110 111ValueWithShadow<u16> SoftMMU::read16(X86::LogicalAddress address) 112{ 113 auto* region = find_region(address); 114 if (!region) { 115 reportln("SoftMMU::read16: No region for @ {:p}"sv, address.offset()); 116 m_emulator.dump_backtrace(); 117 TODO(); 118 } 119 120 if (!region->is_readable()) { 121 reportln("SoftMMU::read16: Non-readable region @ {:p}"sv, address.offset()); 122 m_emulator.dump_backtrace(); 123 TODO(); 124 } 125 126 return region->read16(address.offset() - region->base()); 127} 128 129ValueWithShadow<u32> SoftMMU::read32(X86::LogicalAddress address) 130{ 131 auto* region = find_region(address); 132 if (!region) { 133 reportln("SoftMMU::read32: No region for @ {:04x}:{:p}"sv, address.selector(), address.offset()); 134 m_emulator.dump_backtrace(); 135 TODO(); 136 } 137 138 if (!region->is_readable()) { 139 reportln("SoftMMU::read32: Non-readable region @ {:p}"sv, address.offset()); 140 m_emulator.dump_backtrace(); 141 TODO(); 142 } 143 144 return region->read32(address.offset() - region->base()); 145} 146 147ValueWithShadow<u64> SoftMMU::read64(X86::LogicalAddress address) 148{ 149 auto* region = find_region(address); 150 if (!region) { 151 reportln("SoftMMU::read64: No region for @ {:p}"sv, address.offset()); 152 m_emulator.dump_backtrace(); 153 TODO(); 154 } 155 156 if (!region->is_readable()) { 157 reportln("SoftMMU::read64: Non-readable region @ {:p}"sv, address.offset()); 158 m_emulator.dump_backtrace(); 159 TODO(); 160 } 161 162 return region->read64(address.offset() - region->base()); 163} 164 165ValueWithShadow<u128> SoftMMU::read128(X86::LogicalAddress address) 166{ 167 auto* region = find_region(address); 168 if (!region) { 169 reportln("SoftMMU::read128: No region for @ {:p}"sv, address.offset()); 170 m_emulator.dump_backtrace(); 171 TODO(); 172 } 173 174 if (!region->is_readable()) { 175 reportln("SoftMMU::read128: Non-readable region @ {:p}"sv, address.offset()); 176 m_emulator.dump_backtrace(); 177 TODO(); 178 } 179 180 return region->read128(address.offset() - region->base()); 181} 182 183ValueWithShadow<u256> SoftMMU::read256(X86::LogicalAddress address) 184{ 185 auto* region = find_region(address); 186 if (!region) { 187 reportln("SoftMMU::read256: No region for @ {:p}"sv, address.offset()); 188 m_emulator.dump_backtrace(); 189 TODO(); 190 } 191 192 if (!region->is_readable()) { 193 reportln("SoftMMU::read256: Non-readable region @ {:p}"sv, address.offset()); 194 m_emulator.dump_backtrace(); 195 TODO(); 196 } 197 198 return region->read256(address.offset() - region->base()); 199} 200 201void SoftMMU::write8(X86::LogicalAddress address, ValueWithShadow<u8> value) 202{ 203 auto* region = find_region(address); 204 if (!region) { 205 reportln("SoftMMU::write8: No region for @ {:p}"sv, address.offset()); 206 m_emulator.dump_backtrace(); 207 TODO(); 208 } 209 210 if (!region->is_writable()) { 211 reportln("SoftMMU::write8: Non-writable region @ {:p}"sv, address.offset()); 212 m_emulator.dump_backtrace(); 213 TODO(); 214 } 215 region->write8(address.offset() - region->base(), value); 216} 217 218void SoftMMU::write16(X86::LogicalAddress address, ValueWithShadow<u16> value) 219{ 220 auto* region = find_region(address); 221 if (!region) { 222 reportln("SoftMMU::write16: No region for @ {:p}"sv, address.offset()); 223 m_emulator.dump_backtrace(); 224 TODO(); 225 } 226 227 if (!region->is_writable()) { 228 reportln("SoftMMU::write16: Non-writable region @ {:p}"sv, address.offset()); 229 m_emulator.dump_backtrace(); 230 TODO(); 231 } 232 233 region->write16(address.offset() - region->base(), value); 234} 235 236void SoftMMU::write32(X86::LogicalAddress address, ValueWithShadow<u32> value) 237{ 238 auto* region = find_region(address); 239 if (!region) { 240 reportln("SoftMMU::write32: No region for @ {:p}"sv, address.offset()); 241 m_emulator.dump_backtrace(); 242 TODO(); 243 } 244 245 if (!region->is_writable()) { 246 reportln("SoftMMU::write32: Non-writable region @ {:p}"sv, address.offset()); 247 m_emulator.dump_backtrace(); 248 TODO(); 249 } 250 251 region->write32(address.offset() - region->base(), value); 252} 253 254void SoftMMU::write64(X86::LogicalAddress address, ValueWithShadow<u64> value) 255{ 256 auto* region = find_region(address); 257 if (!region) { 258 reportln("SoftMMU::write64: No region for @ {:p}"sv, address.offset()); 259 m_emulator.dump_backtrace(); 260 TODO(); 261 } 262 263 if (!region->is_writable()) { 264 reportln("SoftMMU::write64: Non-writable region @ {:p}"sv, address.offset()); 265 m_emulator.dump_backtrace(); 266 TODO(); 267 } 268 269 region->write64(address.offset() - region->base(), value); 270} 271 272void SoftMMU::write128(X86::LogicalAddress address, ValueWithShadow<u128> value) 273{ 274 auto* region = find_region(address); 275 if (!region) { 276 reportln("SoftMMU::write128: No region for @ {:p}"sv, address.offset()); 277 m_emulator.dump_backtrace(); 278 TODO(); 279 } 280 281 if (!region->is_writable()) { 282 reportln("SoftMMU::write128: Non-writable region @ {:p}"sv, address.offset()); 283 m_emulator.dump_backtrace(); 284 TODO(); 285 } 286 287 region->write128(address.offset() - region->base(), value); 288} 289 290void SoftMMU::write256(X86::LogicalAddress address, ValueWithShadow<u256> value) 291{ 292 auto* region = find_region(address); 293 if (!region) { 294 reportln("SoftMMU::write256: No region for @ {:p}"sv, address.offset()); 295 m_emulator.dump_backtrace(); 296 TODO(); 297 } 298 299 if (!region->is_writable()) { 300 reportln("SoftMMU::write256: Non-writable region @ {:p}"sv, address.offset()); 301 m_emulator.dump_backtrace(); 302 TODO(); 303 } 304 305 region->write256(address.offset() - region->base(), value); 306} 307 308void SoftMMU::copy_to_vm(FlatPtr destination, void const* source, size_t size) 309{ 310 // FIXME: We should have a way to preserve the shadow data here as well. 311 for (size_t i = 0; i < size; ++i) 312 write8({ 0x23, destination + i }, shadow_wrap_as_initialized(((u8 const*)source)[i])); 313} 314 315void SoftMMU::copy_from_vm(void* destination, const FlatPtr source, size_t size) 316{ 317 // FIXME: We should have a way to preserve the shadow data here as well. 318 for (size_t i = 0; i < size; ++i) 319 ((u8*)destination)[i] = read8({ 0x23, source + i }).value(); 320} 321 322ByteBuffer SoftMMU::copy_buffer_from_vm(const FlatPtr source, size_t size) 323{ 324 auto buffer = ByteBuffer::create_uninitialized(size).release_value_but_fixme_should_propagate_errors(); // FIXME: Handle possible OOM situation. 325 copy_from_vm(buffer.data(), source, size); 326 return buffer; 327} 328 329bool SoftMMU::fast_fill_memory8(X86::LogicalAddress address, size_t size, ValueWithShadow<u8> value) 330{ 331 if (!size) 332 return true; 333 auto* region = find_region(address); 334 if (!region) 335 return false; 336 if (!region->contains(address.offset() + size - 1)) 337 return false; 338 339 if (is<MmapRegion>(*region) && static_cast<MmapRegion const&>(*region).is_malloc_block()) { 340 if (auto* tracer = m_emulator.malloc_tracer()) { 341 // FIXME: Add a way to audit an entire range of memory instead of looping here! 342 for (size_t i = 0; i < size; ++i) { 343 tracer->audit_write(*region, address.offset() + (i * sizeof(u8)), sizeof(u8)); 344 } 345 } 346 } 347 348 size_t offset_in_region = address.offset() - region->base(); 349 memset(region->data() + offset_in_region, value.value(), size); 350 memset(region->shadow_data() + offset_in_region, value.shadow()[0], size); 351 return true; 352} 353 354bool SoftMMU::fast_fill_memory32(X86::LogicalAddress address, size_t count, ValueWithShadow<u32> value) 355{ 356 if (!count) 357 return true; 358 auto* region = find_region(address); 359 if (!region) 360 return false; 361 if (!region->contains(address.offset() + (count * sizeof(u32)) - 1)) 362 return false; 363 364 if (is<MmapRegion>(*region) && static_cast<MmapRegion const&>(*region).is_malloc_block()) { 365 if (auto* tracer = m_emulator.malloc_tracer()) { 366 // FIXME: Add a way to audit an entire range of memory instead of looping here! 367 for (size_t i = 0; i < count; ++i) { 368 tracer->audit_write(*region, address.offset() + (i * sizeof(u32)), sizeof(u32)); 369 } 370 } 371 } 372 373 size_t offset_in_region = address.offset() - region->base(); 374 fast_u32_fill((u32*)(region->data() + offset_in_region), value.value(), count); 375 fast_u32_fill((u32*)(region->shadow_data() + offset_in_region), value.shadow_as_value(), count); 376 return true; 377} 378 379void SoftMMU::dump_backtrace() 380{ 381 m_emulator.dump_backtrace(); 382} 383 384}