diff options
Diffstat (limited to 'src/core/hle/kernel')
-rw-r--r-- | src/core/hle/kernel/process.cpp | 76 | ||||
-rw-r--r-- | src/core/hle/kernel/process.h | 11 | ||||
-rw-r--r-- | src/core/hle/kernel/svc.cpp | 31 | ||||
-rw-r--r-- | src/core/hle/kernel/vm_manager.cpp | 82 | ||||
-rw-r--r-- | src/core/hle/kernel/vm_manager.h | 15 |
5 files changed, 128 insertions, 87 deletions
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 420218d59..e78e3a950 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -5,11 +5,9 @@ #include <algorithm> #include <memory> #include "common/assert.h" -#include "common/common_funcs.h" #include "common/logging/log.h" #include "core/core.h" #include "core/file_sys/program_metadata.h" -#include "core/hle/kernel/errors.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/resource_limit.h" @@ -241,83 +239,15 @@ void Process::LoadModule(CodeSet module_, VAddr base_addr) { } ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) { - if (target < vm_manager.GetHeapRegionBaseAddress() || - target + size > vm_manager.GetHeapRegionEndAddress() || target + size < target) { - return ERR_INVALID_ADDRESS; - } - - if (heap_memory == nullptr) { - // Initialize heap - heap_memory = std::make_shared<std::vector<u8>>(); - heap_start = heap_end = target; - } else { - vm_manager.UnmapRange(heap_start, heap_end - heap_start); - } - - // If necessary, expand backing vector to cover new heap extents. - if (target < heap_start) { - heap_memory->insert(begin(*heap_memory), heap_start - target, 0); - heap_start = target; - vm_manager.RefreshMemoryBlockMappings(heap_memory.get()); - } - if (target + size > heap_end) { - heap_memory->insert(end(*heap_memory), (target + size) - heap_end, 0); - heap_end = target + size; - vm_manager.RefreshMemoryBlockMappings(heap_memory.get()); - } - ASSERT(heap_end - heap_start == heap_memory->size()); - - CASCADE_RESULT(auto vma, vm_manager.MapMemoryBlock(target, heap_memory, target - heap_start, - size, MemoryState::Heap)); - vm_manager.Reprotect(vma, perms); - - heap_used = size; - - return MakeResult<VAddr>(heap_end - size); + return vm_manager.HeapAllocate(target, size, perms); } ResultCode Process::HeapFree(VAddr target, u32 size) { - if (target < vm_manager.GetHeapRegionBaseAddress() || - target + size > vm_manager.GetHeapRegionEndAddress() || target + size < target) { - return ERR_INVALID_ADDRESS; - } - - if (size == 0) { - return RESULT_SUCCESS; - } - - ResultCode result = vm_manager.UnmapRange(target, size); - if (result.IsError()) - return result; - - heap_used -= size; - - return RESULT_SUCCESS; + return vm_manager.HeapFree(target, size); } ResultCode Process::MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size) { - auto vma = vm_manager.FindVMA(src_addr); - - ASSERT_MSG(vma != vm_manager.vma_map.end(), "Invalid memory address"); - ASSERT_MSG(vma->second.backing_block, "Backing block doesn't exist for address"); - - // The returned VMA might be a bigger one encompassing the desired address. - auto vma_offset = src_addr - vma->first; - ASSERT_MSG(vma_offset + size <= vma->second.size, - "Shared memory exceeds bounds of mapped block"); - - const std::shared_ptr<std::vector<u8>>& backing_block = vma->second.backing_block; - std::size_t backing_block_offset = vma->second.offset + vma_offset; - - CASCADE_RESULT(auto new_vma, - vm_manager.MapMemoryBlock(dst_addr, backing_block, backing_block_offset, size, - MemoryState::Mapped)); - // Protect mirror with permissions from old region - vm_manager.Reprotect(new_vma, vma->second.permissions); - // Remove permissions from old region - vm_manager.Reprotect(vma, VMAPermission::None); - - return RESULT_SUCCESS; + return vm_manager.MirrorMemory(dst_addr, src_addr, size); } ResultCode Process::UnmapMemory(VAddr dst_addr, VAddr /*src_addr*/, u64 size) { diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 8d2616c79..f79f6d7a5 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -292,17 +292,6 @@ private: u32 allowed_thread_priority_mask = 0xFFFFFFFF; u32 is_virtual_address_memory_enabled = 0; - // Memory used to back the allocations in the regular heap. A single vector is used to cover - // the entire virtual address space extents that bound the allocations, including any holes. - // This makes deallocation and reallocation of holes fast and keeps process memory contiguous - // in the emulator address space, allowing Memory::GetPointer to be reasonably safe. - std::shared_ptr<std::vector<u8>> heap_memory; - - // The left/right bounds of the address space covered by heap_memory. - VAddr heap_start = 0; - VAddr heap_end = 0; - u64 heap_used = 0; - /// The Thread Local Storage area is allocated as processes create threads, /// each TLS area is 0x200 bytes, so one page (0x1000) is split up in 8 parts, and each part /// holds the TLS for a specific thread. This vector contains which parts are in use for each diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index c7c579aaf..0bfe1e3be 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -34,6 +34,7 @@ #include "core/hle/lock.h" #include "core/hle/result.h" #include "core/hle/service/service.h" +#include "core/settings.h" namespace Kernel { namespace { @@ -395,16 +396,42 @@ struct BreakReason { /// Break program execution static void Break(u32 reason, u64 info1, u64 info2) { BreakReason break_reason{reason}; + bool has_dumped_buffer{}; + const auto handle_debug_buffer = [&](VAddr addr, u64 sz) { + if (sz == 0 || addr == 0 || has_dumped_buffer) { + return; + } + + // This typically is an error code so we're going to assume this is the case + if (sz == sizeof(u32)) { + LOG_CRITICAL(Debug_Emulated, "debug_buffer_err_code={:X}", Memory::Read32(addr)); + } else { + // We don't know what's in here so we'll hexdump it + std::vector<u8> debug_buffer(sz); + Memory::ReadBlock(addr, debug_buffer.data(), sz); + std::string hexdump; + for (std::size_t i = 0; i < debug_buffer.size(); i++) { + hexdump += fmt::format("{:02X} ", debug_buffer[i]); + if (i != 0 && i % 16 == 0) { + hexdump += '\n'; + } + } + LOG_CRITICAL(Debug_Emulated, "debug_buffer=\n{}", hexdump); + } + has_dumped_buffer = true; + }; switch (break_reason.break_type) { case BreakType::Panic: LOG_CRITICAL(Debug_Emulated, "Signalling debugger, PANIC! info1=0x{:016X}, info2=0x{:016X}", info1, info2); + handle_debug_buffer(info1, info2); break; case BreakType::AssertionFailed: LOG_CRITICAL(Debug_Emulated, "Signalling debugger, Assertion failed! info1=0x{:016X}, info2=0x{:016X}", info1, info2); + handle_debug_buffer(info1, info2); break; case BreakType::PreNROLoad: LOG_WARNING( @@ -433,6 +460,7 @@ static void Break(u32 reason, u64 info1, u64 info2) { Debug_Emulated, "Signalling debugger, Unknown break reason {}, info1=0x{:016X}, info2=0x{:016X}", static_cast<u32>(break_reason.break_type.Value()), info1, info2); + handle_debug_buffer(info1, info2); break; } @@ -441,6 +469,7 @@ static void Break(u32 reason, u64 info1, u64 info2) { Debug_Emulated, "Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}", reason, info1, info2); + handle_debug_buffer(info1, info2); ASSERT(false); Core::CurrentProcess()->PrepareForTermination(); @@ -530,7 +559,7 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) *result = 0; break; case GetInfoType::RandomEntropy: - *result = 0; + *result = Settings::values.rng_seed.value_or(0); break; case GetInfoType::ASLRRegionBaseAddr: *result = vm_manager.GetASLRRegionBaseAddress(); diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index 1a92c8f70..ec7fd6150 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp @@ -243,6 +243,85 @@ ResultCode VMManager::ReprotectRange(VAddr target, u64 size, VMAPermission new_p return RESULT_SUCCESS; } +ResultVal<VAddr> VMManager::HeapAllocate(VAddr target, u64 size, VMAPermission perms) { + if (target < GetHeapRegionBaseAddress() || target + size > GetHeapRegionEndAddress() || + target + size < target) { + return ERR_INVALID_ADDRESS; + } + + if (heap_memory == nullptr) { + // Initialize heap + heap_memory = std::make_shared<std::vector<u8>>(); + heap_start = heap_end = target; + } else { + UnmapRange(heap_start, heap_end - heap_start); + } + + // If necessary, expand backing vector to cover new heap extents. + if (target < heap_start) { + heap_memory->insert(begin(*heap_memory), heap_start - target, 0); + heap_start = target; + RefreshMemoryBlockMappings(heap_memory.get()); + } + if (target + size > heap_end) { + heap_memory->insert(end(*heap_memory), (target + size) - heap_end, 0); + heap_end = target + size; + RefreshMemoryBlockMappings(heap_memory.get()); + } + ASSERT(heap_end - heap_start == heap_memory->size()); + + CASCADE_RESULT(auto vma, MapMemoryBlock(target, heap_memory, target - heap_start, size, + MemoryState::Heap)); + Reprotect(vma, perms); + + heap_used = size; + + return MakeResult<VAddr>(heap_end - size); +} + +ResultCode VMManager::HeapFree(VAddr target, u64 size) { + if (target < GetHeapRegionBaseAddress() || target + size > GetHeapRegionEndAddress() || + target + size < target) { + return ERR_INVALID_ADDRESS; + } + + if (size == 0) { + return RESULT_SUCCESS; + } + + const ResultCode result = UnmapRange(target, size); + if (result.IsError()) { + return result; + } + + heap_used -= size; + return RESULT_SUCCESS; +} + +ResultCode VMManager::MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size) { + const auto vma = FindVMA(src_addr); + + ASSERT_MSG(vma != vma_map.end(), "Invalid memory address"); + ASSERT_MSG(vma->second.backing_block, "Backing block doesn't exist for address"); + + // The returned VMA might be a bigger one encompassing the desired address. + const auto vma_offset = src_addr - vma->first; + ASSERT_MSG(vma_offset + size <= vma->second.size, + "Shared memory exceeds bounds of mapped block"); + + const std::shared_ptr<std::vector<u8>>& backing_block = vma->second.backing_block; + const std::size_t backing_block_offset = vma->second.offset + vma_offset; + + CASCADE_RESULT(auto new_vma, MapMemoryBlock(dst_addr, backing_block, backing_block_offset, size, + MemoryState::Mapped)); + // Protect mirror with permissions from old region + Reprotect(new_vma, vma->second.permissions); + // Remove permissions from old region + Reprotect(vma, VMAPermission::None); + + return RESULT_SUCCESS; +} + void VMManager::RefreshMemoryBlockMappings(const std::vector<u8>* block) { // If this ever proves to have a noticeable performance impact, allow users of the function to // specify a specific range of addresses to limit the scan to. @@ -495,8 +574,7 @@ u64 VMManager::GetTotalMemoryUsage() const { } u64 VMManager::GetTotalHeapUsage() const { - LOG_WARNING(Kernel, "(STUBBED) called"); - return 0x0; + return heap_used; } VAddr VMManager::GetAddressSpaceBaseAddress() const { diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h index 2447cbb8f..248cc46dc 100644 --- a/src/core/hle/kernel/vm_manager.h +++ b/src/core/hle/kernel/vm_manager.h @@ -186,6 +186,11 @@ public: /// Changes the permissions of a range of addresses, splitting VMAs as necessary. ResultCode ReprotectRange(VAddr target, u64 size, VMAPermission new_perms); + ResultVal<VAddr> HeapAllocate(VAddr target, u64 size, VMAPermission perms); + ResultCode HeapFree(VAddr target, u64 size); + + ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size); + /** * Scans all VMAs and updates the page table range of any that use the given vector as backing * memory. This should be called after any operation that causes reallocation of the vector. @@ -343,5 +348,15 @@ private: VAddr tls_io_region_base = 0; VAddr tls_io_region_end = 0; + + // Memory used to back the allocations in the regular heap. A single vector is used to cover + // the entire virtual address space extents that bound the allocations, including any holes. + // This makes deallocation and reallocation of holes fast and keeps process memory contiguous + // in the emulator address space, allowing Memory::GetPointer to be reasonably safe. + std::shared_ptr<std::vector<u8>> heap_memory; + // The left/right bounds of the address space covered by heap_memory. + VAddr heap_start = 0; + VAddr heap_end = 0; + u64 heap_used = 0; }; } // namespace Kernel |