From 608383ec840de6e5051934eb12f7e6f5982e168f Mon Sep 17 00:00:00 2001 From: PabloMK7 Date: Fri, 27 Sep 2024 23:00:28 +0000 Subject: [PATCH] Match changes to svcMapProcessMemoryEx from latest Luma3DS (#264) --- src/core/file_sys/plugin_3gx.cpp | 11 +++++-- src/core/file_sys/plugin_3gx.h | 3 ++ src/core/hle/kernel/svc.cpp | 40 +++++++++++++++++++++----- src/core/hle/service/plgldr/plgldr.cpp | 2 +- 4 files changed, 45 insertions(+), 11 deletions(-) diff --git a/src/core/file_sys/plugin_3gx.cpp b/src/core/file_sys/plugin_3gx.cpp index e325d7fca..e840a895f 100644 --- a/src/core/file_sys/plugin_3gx.cpp +++ b/src/core/file_sys/plugin_3gx.cpp @@ -179,6 +179,8 @@ Loader::ResultStatus FileSys::Plugin3GXLoader::Map( 4 * 1024 * 1024 // 4 MiB }; + const bool is_mem_private = header.infos.flags.use_private_memory != 0; + // Map memory block. This behaviour mimics how plugins are loaded on 3DS as much as possible. // Calculate the sizes of the different memory regions const u32 block_size = mem_region_sizes[header.infos.flags.memory_region_size.Value()]; @@ -199,7 +201,8 @@ Loader::ResultStatus FileSys::Plugin3GXLoader::Map( std::fill(backing_memory_fb.GetPtr(), backing_memory_fb.GetPtr() + _3GX_fb_size, 0); auto vma_heap_fb = process.vm_manager.MapBackingMemory( - _3GX_heap_load_addr, backing_memory_fb, _3GX_fb_size, Kernel::MemoryState::Continuous); + _3GX_heap_load_addr, backing_memory_fb, _3GX_fb_size, + is_mem_private ? Kernel::MemoryState::Private : Kernel::MemoryState::Shared); ASSERT(vma_heap_fb.Succeeded()); process.vm_manager.Reprotect(vma_heap_fb.Unwrap(), Kernel::VMAPermission::ReadWrite); @@ -217,7 +220,8 @@ Loader::ResultStatus FileSys::Plugin3GXLoader::Map( // Then we map part of the memory, which contains the executable auto vma = process.vm_manager.MapBackingMemory(_3GX_exe_load_addr, backing_memory, exe_size, - Kernel::MemoryState::Continuous); + is_mem_private ? Kernel::MemoryState::Private + : Kernel::MemoryState::Shared); ASSERT(vma.Succeeded()); process.vm_manager.Reprotect(vma.Unwrap(), Kernel::VMAPermission::ReadWriteExecute); @@ -256,7 +260,8 @@ Loader::ResultStatus FileSys::Plugin3GXLoader::Map( // Map the rest of the memory at the heap location auto vma_heap = process.vm_manager.MapBackingMemory( _3GX_heap_load_addr + _3GX_fb_size, backing_memory_heap, - block_size - exe_size - _3GX_fb_size, Kernel::MemoryState::Continuous); + block_size - exe_size - _3GX_fb_size, + is_mem_private ? Kernel::MemoryState::Private : Kernel::MemoryState::Shared); ASSERT(vma_heap.Succeeded()); process.vm_manager.Reprotect(vma_heap.Unwrap(), Kernel::VMAPermission::ReadWriteExecute); diff --git a/src/core/file_sys/plugin_3gx.h b/src/core/file_sys/plugin_3gx.h index 742db7bf9..01a9f8489 100644 --- a/src/core/file_sys/plugin_3gx.h +++ b/src/core/file_sys/plugin_3gx.h @@ -94,6 +94,9 @@ private: BitField<1, 1, u32_le> embedded_swap_func; BitField<2, 2, u32_le> memory_region_size; BitField<4, 2, u32_le> compatibility; + BitField<6, 1, u32_le> events_self_managed; + BitField<7, 1, u32_le> swap_not_needed; + BitField<8, 1, u32_le> use_private_memory; } flags; u32_le exe_load_checksum; u32_le builtin_load_exe_args[4]; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index fd798fb9e..4d8eab4e4 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -369,6 +369,16 @@ enum class ControlProcessOP { PROCESSOP_DISABLE_CREATE_THREAD_RESTRICTIONS, }; +/** + * Accepted by the custom svcMapProcessMemoryEx. + */ +enum class MapMemoryExFlag { + /** + * Maps the memory region as PRIVATE instead of SHARED + */ + MAPEXFLAGS_PRIVATE = (1 << 0), +}; + class SVC : public SVCWrapper { public: SVC(Core::System& system); @@ -460,7 +470,8 @@ private: Result InvalidateEntireInstructionCache(); u32 ConvertVaToPa(u32 addr); Result MapProcessMemoryEx(Handle dst_process_handle, u32 dst_address, Handle src_process_handle, - u32 src_address, u32 size); + u32 src_address, u32 size, MapMemoryExFlag flags, + Handle dst_process_handle_backup); Result UnmapProcessMemoryEx(Handle process, u32 dst_address, u32 size); Result ControlProcess(Handle process_handle, u32 process_OP, u32 varg2, u32 varg3); @@ -2012,7 +2023,22 @@ u32 SVC::ConvertVaToPa(u32 addr) { } Result SVC::MapProcessMemoryEx(Handle dst_process_handle, u32 dst_address, - Handle src_process_handle, u32 src_address, u32 size) { + Handle src_process_handle, u32 src_address, u32 size, + MapMemoryExFlag flags, Handle dst_process_handle_backup) { + + // Determine if this is the second version of the svc by checking the value at R0. + constexpr u32 SVC_VERSION2_MAGIC = 0xFFFFFFF2; + if (static_cast(dst_process_handle) == SVC_VERSION2_MAGIC) { + // Version 2, actual handle is provided in 6th argument + dst_process_handle = dst_process_handle_backup; + } else { + // Version 1, the flags argument is not used + flags = static_cast(0); + } + + const bool map_as_private = + (static_cast(flags) & static_cast(MapMemoryExFlag::MAPEXFLAGS_PRIVATE)) != 0; + std::shared_ptr dst_process = kernel.GetCurrentProcess()->handle_table.Get(dst_process_handle); std::shared_ptr src_process = @@ -2024,11 +2050,12 @@ Result SVC::MapProcessMemoryEx(Handle dst_process_handle, u32 dst_address, size = (size & ~0xFFF) + Memory::CITRA_PAGE_SIZE; } + // TODO(PabloMK7) Fix-up this svc. + // Only linear memory supported auto vma = src_process->vm_manager.FindVMA(src_address); R_UNLESS(vma != src_process->vm_manager.vma_map.end() && - vma->second.type == VMAType::BackingMemory && - vma->second.meminfo_state == MemoryState::Continuous, + vma->second.type == VMAType::BackingMemory, ResultInvalidAddress); const u32 offset = src_address - vma->second.base; @@ -2038,7 +2065,7 @@ Result SVC::MapProcessMemoryEx(Handle dst_process_handle, u32 dst_address, dst_address, memory.GetFCRAMRef(vma->second.backing_memory.GetPtr() + offset - kernel.memory.GetFCRAMPointer(0)), - size, Kernel::MemoryState::Continuous); + size, map_as_private ? MemoryState::Private : MemoryState::Shared); if (!vma_res.Succeeded()) { return ResultInvalidAddressState; @@ -2060,8 +2087,7 @@ Result SVC::UnmapProcessMemoryEx(Handle process, u32 dst_address, u32 size) { // Only linear memory supported auto vma = dst_process->vm_manager.FindVMA(dst_address); R_UNLESS(vma != dst_process->vm_manager.vma_map.end() && - vma->second.type == VMAType::BackingMemory && - vma->second.meminfo_state == MemoryState::Continuous, + vma->second.type == VMAType::BackingMemory, ResultInvalidAddress); dst_process->vm_manager.UnmapRange(dst_address, size); diff --git a/src/core/hle/service/plgldr/plgldr.cpp b/src/core/hle/service/plgldr/plgldr.cpp index 8e8d876cf..7203e48fb 100644 --- a/src/core/hle/service/plgldr/plgldr.cpp +++ b/src/core/hle/service/plgldr/plgldr.cpp @@ -38,7 +38,7 @@ SERVICE_CONSTRUCT_IMPL(Service::PLGLDR::PLG_LDR) namespace Service::PLGLDR { -static const Kernel::CoreVersion plgldr_version = Kernel::CoreVersion(1, 0, 0); +static const Kernel::CoreVersion plgldr_version = Kernel::CoreVersion(1, 0, 2); PLG_LDR::PLG_LDR(Core::System& system_) : ServiceFramework{"plg:ldr", 1}, system(system_) { static const FunctionInfo functions[] = {