diff options
Diffstat (limited to 'src/core')
| -rw-r--r-- | src/core/memory.cpp | 127 | ||||
| -rw-r--r-- | src/core/memory.h | 78 |
2 files changed, 199 insertions, 6 deletions
diff --git a/src/core/memory.cpp b/src/core/memory.cpp index f0888327f..6061d37ae 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp | |||
| @@ -242,7 +242,52 @@ struct Memory::Impl { | |||
| 242 | } | 242 | } |
| 243 | case Common::PageType::RasterizerCachedMemory: { | 243 | case Common::PageType::RasterizerCachedMemory: { |
| 244 | const u8* const host_ptr = GetPointerFromVMA(process, current_vaddr); | 244 | const u8* const host_ptr = GetPointerFromVMA(process, current_vaddr); |
| 245 | system.GPU().FlushRegion(ToCacheAddr(host_ptr), copy_amount); | 245 | system.GPU().FlushRegion(current_vaddr, copy_amount); |
| 246 | std::memcpy(dest_buffer, host_ptr, copy_amount); | ||
| 247 | break; | ||
| 248 | } | ||
| 249 | default: | ||
| 250 | UNREACHABLE(); | ||
| 251 | } | ||
| 252 | |||
| 253 | page_index++; | ||
| 254 | page_offset = 0; | ||
| 255 | dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount; | ||
| 256 | remaining_size -= copy_amount; | ||
| 257 | } | ||
| 258 | } | ||
| 259 | |||
| 260 | void ReadBlockUnsafe(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer, | ||
| 261 | const std::size_t size) { | ||
| 262 | const auto& page_table = process.VMManager().page_table; | ||
| 263 | |||
| 264 | std::size_t remaining_size = size; | ||
| 265 | std::size_t page_index = src_addr >> PAGE_BITS; | ||
| 266 | std::size_t page_offset = src_addr & PAGE_MASK; | ||
| 267 | |||
| 268 | while (remaining_size > 0) { | ||
| 269 | const std::size_t copy_amount = | ||
| 270 | std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size); | ||
| 271 | const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); | ||
| 272 | |||
| 273 | switch (page_table.attributes[page_index]) { | ||
| 274 | case Common::PageType::Unmapped: { | ||
| 275 | LOG_ERROR(HW_Memory, | ||
| 276 | "Unmapped ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", | ||
| 277 | current_vaddr, src_addr, size); | ||
| 278 | std::memset(dest_buffer, 0, copy_amount); | ||
| 279 | break; | ||
| 280 | } | ||
| 281 | case Common::PageType::Memory: { | ||
| 282 | DEBUG_ASSERT(page_table.pointers[page_index]); | ||
| 283 | |||
| 284 | const u8* const src_ptr = | ||
| 285 | page_table.pointers[page_index] + page_offset + (page_index << PAGE_BITS); | ||
| 286 | std::memcpy(dest_buffer, src_ptr, copy_amount); | ||
| 287 | break; | ||
| 288 | } | ||
| 289 | case Common::PageType::RasterizerCachedMemory: { | ||
| 290 | const u8* const host_ptr = GetPointerFromVMA(process, current_vaddr); | ||
| 246 | std::memcpy(dest_buffer, host_ptr, copy_amount); | 291 | std::memcpy(dest_buffer, host_ptr, copy_amount); |
| 247 | break; | 292 | break; |
| 248 | } | 293 | } |
| @@ -261,6 +306,10 @@ struct Memory::Impl { | |||
| 261 | ReadBlock(*system.CurrentProcess(), src_addr, dest_buffer, size); | 306 | ReadBlock(*system.CurrentProcess(), src_addr, dest_buffer, size); |
| 262 | } | 307 | } |
| 263 | 308 | ||
| 309 | void ReadBlockUnsafe(const VAddr src_addr, void* dest_buffer, const std::size_t size) { | ||
| 310 | ReadBlockUnsafe(*system.CurrentProcess(), src_addr, dest_buffer, size); | ||
| 311 | } | ||
| 312 | |||
| 264 | void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_buffer, | 313 | void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_buffer, |
| 265 | const std::size_t size) { | 314 | const std::size_t size) { |
| 266 | const auto& page_table = process.VMManager().page_table; | 315 | const auto& page_table = process.VMManager().page_table; |
| @@ -290,7 +339,50 @@ struct Memory::Impl { | |||
| 290 | } | 339 | } |
| 291 | case Common::PageType::RasterizerCachedMemory: { | 340 | case Common::PageType::RasterizerCachedMemory: { |
| 292 | u8* const host_ptr = GetPointerFromVMA(process, current_vaddr); | 341 | u8* const host_ptr = GetPointerFromVMA(process, current_vaddr); |
| 293 | system.GPU().InvalidateRegion(ToCacheAddr(host_ptr), copy_amount); | 342 | system.GPU().InvalidateRegion(current_vaddr, copy_amount); |
| 343 | std::memcpy(host_ptr, src_buffer, copy_amount); | ||
| 344 | break; | ||
| 345 | } | ||
| 346 | default: | ||
| 347 | UNREACHABLE(); | ||
| 348 | } | ||
| 349 | |||
| 350 | page_index++; | ||
| 351 | page_offset = 0; | ||
| 352 | src_buffer = static_cast<const u8*>(src_buffer) + copy_amount; | ||
| 353 | remaining_size -= copy_amount; | ||
| 354 | } | ||
| 355 | } | ||
| 356 | |||
| 357 | void WriteBlockUnsafe(const Kernel::Process& process, const VAddr dest_addr, | ||
| 358 | const void* src_buffer, const std::size_t size) { | ||
| 359 | const auto& page_table = process.VMManager().page_table; | ||
| 360 | std::size_t remaining_size = size; | ||
| 361 | std::size_t page_index = dest_addr >> PAGE_BITS; | ||
| 362 | std::size_t page_offset = dest_addr & PAGE_MASK; | ||
| 363 | |||
| 364 | while (remaining_size > 0) { | ||
| 365 | const std::size_t copy_amount = | ||
| 366 | std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size); | ||
| 367 | const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); | ||
| 368 | |||
| 369 | switch (page_table.attributes[page_index]) { | ||
| 370 | case Common::PageType::Unmapped: { | ||
| 371 | LOG_ERROR(HW_Memory, | ||
| 372 | "Unmapped WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", | ||
| 373 | current_vaddr, dest_addr, size); | ||
| 374 | break; | ||
| 375 | } | ||
| 376 | case Common::PageType::Memory: { | ||
| 377 | DEBUG_ASSERT(page_table.pointers[page_index]); | ||
| 378 | |||
| 379 | u8* const dest_ptr = | ||
| 380 | page_table.pointers[page_index] + page_offset + (page_index << PAGE_BITS); | ||
| 381 | std::memcpy(dest_ptr, src_buffer, copy_amount); | ||
| 382 | break; | ||
| 383 | } | ||
| 384 | case Common::PageType::RasterizerCachedMemory: { | ||
| 385 | u8* const host_ptr = GetPointerFromVMA(process, current_vaddr); | ||
| 294 | std::memcpy(host_ptr, src_buffer, copy_amount); | 386 | std::memcpy(host_ptr, src_buffer, copy_amount); |
| 295 | break; | 387 | break; |
| 296 | } | 388 | } |
| @@ -309,6 +401,10 @@ struct Memory::Impl { | |||
| 309 | WriteBlock(*system.CurrentProcess(), dest_addr, src_buffer, size); | 401 | WriteBlock(*system.CurrentProcess(), dest_addr, src_buffer, size); |
| 310 | } | 402 | } |
| 311 | 403 | ||
| 404 | void WriteBlockUnsafe(const VAddr dest_addr, const void* src_buffer, const std::size_t size) { | ||
| 405 | WriteBlockUnsafe(*system.CurrentProcess(), dest_addr, src_buffer, size); | ||
| 406 | } | ||
| 407 | |||
| 312 | void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) { | 408 | void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) { |
| 313 | const auto& page_table = process.VMManager().page_table; | 409 | const auto& page_table = process.VMManager().page_table; |
| 314 | std::size_t remaining_size = size; | 410 | std::size_t remaining_size = size; |
| @@ -337,7 +433,7 @@ struct Memory::Impl { | |||
| 337 | } | 433 | } |
| 338 | case Common::PageType::RasterizerCachedMemory: { | 434 | case Common::PageType::RasterizerCachedMemory: { |
| 339 | u8* const host_ptr = GetPointerFromVMA(process, current_vaddr); | 435 | u8* const host_ptr = GetPointerFromVMA(process, current_vaddr); |
| 340 | system.GPU().InvalidateRegion(ToCacheAddr(host_ptr), copy_amount); | 436 | system.GPU().InvalidateRegion(current_vaddr, copy_amount); |
| 341 | std::memset(host_ptr, 0, copy_amount); | 437 | std::memset(host_ptr, 0, copy_amount); |
| 342 | break; | 438 | break; |
| 343 | } | 439 | } |
| @@ -384,7 +480,7 @@ struct Memory::Impl { | |||
| 384 | } | 480 | } |
| 385 | case Common::PageType::RasterizerCachedMemory: { | 481 | case Common::PageType::RasterizerCachedMemory: { |
| 386 | const u8* const host_ptr = GetPointerFromVMA(process, current_vaddr); | 482 | const u8* const host_ptr = GetPointerFromVMA(process, current_vaddr); |
| 387 | system.GPU().FlushRegion(ToCacheAddr(host_ptr), copy_amount); | 483 | system.GPU().FlushRegion(current_vaddr, copy_amount); |
| 388 | WriteBlock(process, dest_addr, host_ptr, copy_amount); | 484 | WriteBlock(process, dest_addr, host_ptr, copy_amount); |
| 389 | break; | 485 | break; |
| 390 | } | 486 | } |
| @@ -545,7 +641,7 @@ struct Memory::Impl { | |||
| 545 | break; | 641 | break; |
| 546 | case Common::PageType::RasterizerCachedMemory: { | 642 | case Common::PageType::RasterizerCachedMemory: { |
| 547 | const u8* const host_ptr = GetPointerFromVMA(vaddr); | 643 | const u8* const host_ptr = GetPointerFromVMA(vaddr); |
| 548 | system.GPU().FlushRegion(ToCacheAddr(host_ptr), sizeof(T)); | 644 | system.GPU().FlushRegion(vaddr, sizeof(T)); |
| 549 | T value; | 645 | T value; |
| 550 | std::memcpy(&value, host_ptr, sizeof(T)); | 646 | std::memcpy(&value, host_ptr, sizeof(T)); |
| 551 | return value; | 647 | return value; |
| @@ -587,7 +683,7 @@ struct Memory::Impl { | |||
| 587 | break; | 683 | break; |
| 588 | case Common::PageType::RasterizerCachedMemory: { | 684 | case Common::PageType::RasterizerCachedMemory: { |
| 589 | u8* const host_ptr{GetPointerFromVMA(vaddr)}; | 685 | u8* const host_ptr{GetPointerFromVMA(vaddr)}; |
| 590 | system.GPU().InvalidateRegion(ToCacheAddr(host_ptr), sizeof(T)); | 686 | system.GPU().InvalidateRegion(vaddr, sizeof(T)); |
| 591 | std::memcpy(host_ptr, &data, sizeof(T)); | 687 | std::memcpy(host_ptr, &data, sizeof(T)); |
| 592 | break; | 688 | break; |
| 593 | } | 689 | } |
| @@ -696,6 +792,15 @@ void Memory::ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_ | |||
| 696 | impl->ReadBlock(src_addr, dest_buffer, size); | 792 | impl->ReadBlock(src_addr, dest_buffer, size); |
| 697 | } | 793 | } |
| 698 | 794 | ||
| 795 | void Memory::ReadBlockUnsafe(const Kernel::Process& process, const VAddr src_addr, | ||
| 796 | void* dest_buffer, const std::size_t size) { | ||
| 797 | impl->ReadBlockUnsafe(process, src_addr, dest_buffer, size); | ||
| 798 | } | ||
| 799 | |||
| 800 | void Memory::ReadBlockUnsafe(const VAddr src_addr, void* dest_buffer, const std::size_t size) { | ||
| 801 | impl->ReadBlockUnsafe(src_addr, dest_buffer, size); | ||
| 802 | } | ||
| 803 | |||
| 699 | void Memory::WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer, | 804 | void Memory::WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer, |
| 700 | std::size_t size) { | 805 | std::size_t size) { |
| 701 | impl->WriteBlock(process, dest_addr, src_buffer, size); | 806 | impl->WriteBlock(process, dest_addr, src_buffer, size); |
| @@ -705,6 +810,16 @@ void Memory::WriteBlock(const VAddr dest_addr, const void* src_buffer, const std | |||
| 705 | impl->WriteBlock(dest_addr, src_buffer, size); | 810 | impl->WriteBlock(dest_addr, src_buffer, size); |
| 706 | } | 811 | } |
| 707 | 812 | ||
| 813 | void Memory::WriteBlockUnsafe(const Kernel::Process& process, VAddr dest_addr, | ||
| 814 | const void* src_buffer, std::size_t size) { | ||
| 815 | impl->WriteBlockUnsafe(process, dest_addr, src_buffer, size); | ||
| 816 | } | ||
| 817 | |||
| 818 | void Memory::WriteBlockUnsafe(const VAddr dest_addr, const void* src_buffer, | ||
| 819 | const std::size_t size) { | ||
| 820 | impl->WriteBlockUnsafe(dest_addr, src_buffer, size); | ||
| 821 | } | ||
| 822 | |||
| 708 | void Memory::ZeroBlock(const Kernel::Process& process, VAddr dest_addr, std::size_t size) { | 823 | void Memory::ZeroBlock(const Kernel::Process& process, VAddr dest_addr, std::size_t size) { |
| 709 | impl->ZeroBlock(process, dest_addr, size); | 824 | impl->ZeroBlock(process, dest_addr, size); |
| 710 | } | 825 | } |
diff --git a/src/core/memory.h b/src/core/memory.h index 8913a9da4..b92d678a4 100644 --- a/src/core/memory.h +++ b/src/core/memory.h | |||
| @@ -295,6 +295,27 @@ public: | |||
| 295 | std::size_t size); | 295 | std::size_t size); |
| 296 | 296 | ||
| 297 | /** | 297 | /** |
| 298 | * Reads a contiguous block of bytes from a specified process' address space. | ||
| 299 | * This unsafe version does not trigger GPU flushing. | ||
| 300 | * | ||
| 301 | * @param process The process to read the data from. | ||
| 302 | * @param src_addr The virtual address to begin reading from. | ||
| 303 | * @param dest_buffer The buffer to place the read bytes into. | ||
| 304 | * @param size The amount of data to read, in bytes. | ||
| 305 | * | ||
| 306 | * @note If a size of 0 is specified, then this function reads nothing and | ||
| 307 | * no attempts to access memory are made at all. | ||
| 308 | * | ||
| 309 | * @pre dest_buffer must be at least size bytes in length, otherwise a | ||
| 310 | * buffer overrun will occur. | ||
| 311 | * | ||
| 312 | * @post The range [dest_buffer, size) contains the read bytes from the | ||
| 313 | * process' address space. | ||
| 314 | */ | ||
| 315 | void ReadBlockUnsafe(const Kernel::Process& process, VAddr src_addr, void* dest_buffer, | ||
| 316 | std::size_t size); | ||
| 317 | |||
| 318 | /** | ||
| 298 | * Reads a contiguous block of bytes from the current process' address space. | 319 | * Reads a contiguous block of bytes from the current process' address space. |
| 299 | * | 320 | * |
| 300 | * @param src_addr The virtual address to begin reading from. | 321 | * @param src_addr The virtual address to begin reading from. |
| @@ -313,6 +334,25 @@ public: | |||
| 313 | void ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size); | 334 | void ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size); |
| 314 | 335 | ||
| 315 | /** | 336 | /** |
| 337 | * Reads a contiguous block of bytes from the current process' address space. | ||
| 338 | * This unsafe version does not trigger GPU flushing. | ||
| 339 | * | ||
| 340 | * @param src_addr The virtual address to begin reading from. | ||
| 341 | * @param dest_buffer The buffer to place the read bytes into. | ||
| 342 | * @param size The amount of data to read, in bytes. | ||
| 343 | * | ||
| 344 | * @note If a size of 0 is specified, then this function reads nothing and | ||
| 345 | * no attempts to access memory are made at all. | ||
| 346 | * | ||
| 347 | * @pre dest_buffer must be at least size bytes in length, otherwise a | ||
| 348 | * buffer overrun will occur. | ||
| 349 | * | ||
| 350 | * @post The range [dest_buffer, size) contains the read bytes from the | ||
| 351 | * current process' address space. | ||
| 352 | */ | ||
| 353 | void ReadBlockUnsafe(VAddr src_addr, void* dest_buffer, std::size_t size); | ||
| 354 | |||
| 355 | /** | ||
| 316 | * Writes a range of bytes into a given process' address space at the specified | 356 | * Writes a range of bytes into a given process' address space at the specified |
| 317 | * virtual address. | 357 | * virtual address. |
| 318 | * | 358 | * |
| @@ -336,6 +376,26 @@ public: | |||
| 336 | std::size_t size); | 376 | std::size_t size); |
| 337 | 377 | ||
| 338 | /** | 378 | /** |
| 379 | * Writes a range of bytes into a given process' address space at the specified | ||
| 380 | * virtual address. | ||
| 381 | * This unsafe version does not invalidate GPU Memory. | ||
| 382 | * | ||
| 383 | * @param process The process to write data into the address space of. | ||
| 384 | * @param dest_addr The destination virtual address to begin writing the data at. | ||
| 385 | * @param src_buffer The data to write into the process' address space. | ||
| 386 | * @param size The size of the data to write, in bytes. | ||
| 387 | * | ||
| 388 | * @post The address range [dest_addr, size) in the process' address space | ||
| 389 | * contains the data that was within src_buffer. | ||
| 390 | * | ||
| 391 | * @post If an attempt is made to write into an unmapped region of memory, the writes | ||
| 392 | * will be ignored and an error will be logged. | ||
| 393 | * | ||
| 394 | */ | ||
| 395 | void WriteBlockUnsafe(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer, | ||
| 396 | std::size_t size); | ||
| 397 | |||
| 398 | /** | ||
| 339 | * Writes a range of bytes into the current process' address space at the specified | 399 | * Writes a range of bytes into the current process' address space at the specified |
| 340 | * virtual address. | 400 | * virtual address. |
| 341 | * | 401 | * |
| @@ -357,6 +417,24 @@ public: | |||
| 357 | void WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size); | 417 | void WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size); |
| 358 | 418 | ||
| 359 | /** | 419 | /** |
| 420 | * Writes a range of bytes into the current process' address space at the specified | ||
| 421 | * virtual address. | ||
| 422 | * This unsafe version does not invalidate GPU Memory. | ||
| 423 | * | ||
| 424 | * @param dest_addr The destination virtual address to begin writing the data at. | ||
| 425 | * @param src_buffer The data to write into the current process' address space. | ||
| 426 | * @param size The size of the data to write, in bytes. | ||
| 427 | * | ||
| 428 | * @post The address range [dest_addr, size) in the current process' address space | ||
| 429 | * contains the data that was within src_buffer. | ||
| 430 | * | ||
| 431 | * @post If an attempt is made to write into an unmapped region of memory, the writes | ||
| 432 | * will be ignored and an error will be logged. | ||
| 433 | * | ||
| 434 | */ | ||
| 435 | void WriteBlockUnsafe(VAddr dest_addr, const void* src_buffer, std::size_t size); | ||
| 436 | |||
| 437 | /** | ||
| 360 | * Fills the specified address range within a process' address space with zeroes. | 438 | * Fills the specified address range within a process' address space with zeroes. |
| 361 | * | 439 | * |
| 362 | * @param process The process that will have a portion of its memory zeroed out. | 440 | * @param process The process that will have a portion of its memory zeroed out. |