mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu-mainline.git
				synced 2025-03-21 01:53:15 +00:00 
			
		
		
		
	kernel/svc: Implement svcMapProcessCodeMemory
This is utilized for mapping code modules into memory. Notably, the ldr service would call this in order to map objects into memory.
This commit is contained in:
		
							parent
							
								
									ea80e2bc57
								
							
						
					
					
						commit
						76a2465655
					
				@ -1189,6 +1189,74 @@ static ResultCode QueryMemory(Core::System& system, VAddr memory_info_address,
 | 
				
			|||||||
                              query_address);
 | 
					                              query_address);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ResultCode MapProcessCodeMemory(Core::System& system, Handle process_handle, u64 dst_address,
 | 
				
			||||||
 | 
					                                       u64 src_address, u64 size) {
 | 
				
			||||||
 | 
					    LOG_DEBUG(Kernel_SVC,
 | 
				
			||||||
 | 
					              "called. process_handle=0x{:08X}, dst_address=0x{:016X}, "
 | 
				
			||||||
 | 
					              "src_address=0x{:016X}, size=0x{:016X}",
 | 
				
			||||||
 | 
					              process_handle, dst_address, src_address, size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!Common::Is4KBAligned(src_address)) {
 | 
				
			||||||
 | 
					        LOG_ERROR(Kernel_SVC, "src_address is not page-aligned (src_address=0x{:016X}).",
 | 
				
			||||||
 | 
					                  src_address);
 | 
				
			||||||
 | 
					        return ERR_INVALID_ADDRESS;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!Common::Is4KBAligned(dst_address)) {
 | 
				
			||||||
 | 
					        LOG_ERROR(Kernel_SVC, "dst_address is not page-aligned (dst_address=0x{:016X}).",
 | 
				
			||||||
 | 
					                  dst_address);
 | 
				
			||||||
 | 
					        return ERR_INVALID_ADDRESS;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (size == 0 || !Common::Is4KBAligned(size)) {
 | 
				
			||||||
 | 
					        LOG_ERROR(Kernel_SVC, "Size is zero or not page-aligned (size=0x{:016X})", size);
 | 
				
			||||||
 | 
					        return ERR_INVALID_SIZE;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!IsValidAddressRange(dst_address, size)) {
 | 
				
			||||||
 | 
					        LOG_ERROR(Kernel_SVC,
 | 
				
			||||||
 | 
					                  "Destination address range overflows the address space (dst_address=0x{:016X}, "
 | 
				
			||||||
 | 
					                  "size=0x{:016X}).",
 | 
				
			||||||
 | 
					                  dst_address, size);
 | 
				
			||||||
 | 
					        return ERR_INVALID_ADDRESS_STATE;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!IsValidAddressRange(src_address, size)) {
 | 
				
			||||||
 | 
					        LOG_ERROR(Kernel_SVC,
 | 
				
			||||||
 | 
					                  "Source address range overflows the address space (src_address=0x{:016X}, "
 | 
				
			||||||
 | 
					                  "size=0x{:016X}).",
 | 
				
			||||||
 | 
					                  src_address, size);
 | 
				
			||||||
 | 
					        return ERR_INVALID_ADDRESS_STATE;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
 | 
				
			||||||
 | 
					    auto process = handle_table.Get<Process>(process_handle);
 | 
				
			||||||
 | 
					    if (!process) {
 | 
				
			||||||
 | 
					        LOG_ERROR(Kernel_SVC, "Invalid process handle specified (handle=0x{:08X}).",
 | 
				
			||||||
 | 
					                  process_handle);
 | 
				
			||||||
 | 
					        return ERR_INVALID_HANDLE;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    auto& vm_manager = process->VMManager();
 | 
				
			||||||
 | 
					    if (!vm_manager.IsWithinAddressSpace(src_address, size)) {
 | 
				
			||||||
 | 
					        LOG_ERROR(Kernel_SVC,
 | 
				
			||||||
 | 
					                  "Source address range is not within the address space (src_address=0x{:016X}, "
 | 
				
			||||||
 | 
					                  "size=0x{:016X}).",
 | 
				
			||||||
 | 
					                  src_address, size);
 | 
				
			||||||
 | 
					        return ERR_INVALID_ADDRESS_STATE;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!vm_manager.IsWithinASLRRegion(dst_address, size)) {
 | 
				
			||||||
 | 
					        LOG_ERROR(Kernel_SVC,
 | 
				
			||||||
 | 
					                  "Destination address range is not within the ASLR region (dst_address=0x{:016X}, "
 | 
				
			||||||
 | 
					                  "size=0x{:016X}).",
 | 
				
			||||||
 | 
					                  dst_address, size);
 | 
				
			||||||
 | 
					        return ERR_INVALID_MEMORY_RANGE;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return vm_manager.MapCodeMemory(dst_address, src_address, size);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Exits the current process
 | 
					/// Exits the current process
 | 
				
			||||||
static void ExitProcess(Core::System& system) {
 | 
					static void ExitProcess(Core::System& system) {
 | 
				
			||||||
    auto* current_process = system.Kernel().CurrentProcess();
 | 
					    auto* current_process = system.Kernel().CurrentProcess();
 | 
				
			||||||
@ -2217,7 +2285,7 @@ static const FunctionDef SVC_Table[] = {
 | 
				
			|||||||
    {0x74, nullptr, "MapProcessMemory"},
 | 
					    {0x74, nullptr, "MapProcessMemory"},
 | 
				
			||||||
    {0x75, nullptr, "UnmapProcessMemory"},
 | 
					    {0x75, nullptr, "UnmapProcessMemory"},
 | 
				
			||||||
    {0x76, SvcWrap<QueryProcessMemory>, "QueryProcessMemory"},
 | 
					    {0x76, SvcWrap<QueryProcessMemory>, "QueryProcessMemory"},
 | 
				
			||||||
    {0x77, nullptr, "MapProcessCodeMemory"},
 | 
					    {0x77, SvcWrap<MapProcessCodeMemory>, "MapProcessCodeMemory"},
 | 
				
			||||||
    {0x78, nullptr, "UnmapProcessCodeMemory"},
 | 
					    {0x78, nullptr, "UnmapProcessCodeMemory"},
 | 
				
			||||||
    {0x79, nullptr, "CreateProcess"},
 | 
					    {0x79, nullptr, "CreateProcess"},
 | 
				
			||||||
    {0x7A, nullptr, "StartProcess"},
 | 
					    {0x7A, nullptr, "StartProcess"},
 | 
				
			||||||
 | 
				
			|||||||
@ -44,6 +44,13 @@ void SvcWrap(Core::System& system) {
 | 
				
			|||||||
        func(system, static_cast<u32>(Param(system, 0)), static_cast<u32>(Param(system, 1))).raw);
 | 
					        func(system, static_cast<u32>(Param(system, 0)), static_cast<u32>(Param(system, 1))).raw);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <ResultCode func(Core::System&, u32, u64, u64, u64)>
 | 
				
			||||||
 | 
					void SvcWrap(Core::System& system) {
 | 
				
			||||||
 | 
					    FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), Param(system, 1),
 | 
				
			||||||
 | 
					                            Param(system, 2), Param(system, 3))
 | 
				
			||||||
 | 
					                           .raw);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <ResultCode func(Core::System&, u32*)>
 | 
					template <ResultCode func(Core::System&, u32*)>
 | 
				
			||||||
void SvcWrap(Core::System& system) {
 | 
					void SvcWrap(Core::System& system) {
 | 
				
			||||||
    u32 param = 0;
 | 
					    u32 param = 0;
 | 
				
			||||||
 | 
				
			|||||||
@ -302,6 +302,35 @@ ResultVal<VAddr> VMManager::SetHeapSize(u64 size) {
 | 
				
			|||||||
    return MakeResult<VAddr>(heap_region_base);
 | 
					    return MakeResult<VAddr>(heap_region_base);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ResultCode VMManager::MapCodeMemory(VAddr dst_address, VAddr src_address, u64 size) {
 | 
				
			||||||
 | 
					    constexpr auto ignore_attribute = MemoryAttribute::LockedForIPC | MemoryAttribute::DeviceMapped;
 | 
				
			||||||
 | 
					    const auto src_check_result = CheckRangeState(
 | 
				
			||||||
 | 
					        src_address, size, MemoryState::All, MemoryState::Heap, VMAPermission::All,
 | 
				
			||||||
 | 
					        VMAPermission::ReadWrite, MemoryAttribute::Mask, MemoryAttribute::None, ignore_attribute);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (src_check_result.Failed()) {
 | 
				
			||||||
 | 
					        return src_check_result.Code();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const auto mirror_result =
 | 
				
			||||||
 | 
					        MirrorMemory(dst_address, src_address, size, MemoryState::ModuleCode);
 | 
				
			||||||
 | 
					    if (mirror_result.IsError()) {
 | 
				
			||||||
 | 
					        return mirror_result;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Ensure we lock the source memory region.
 | 
				
			||||||
 | 
					    const auto src_vma_result = CarveVMARange(src_address, size);
 | 
				
			||||||
 | 
					    if (src_vma_result.Failed()) {
 | 
				
			||||||
 | 
					        return src_vma_result.Code();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    auto src_vma_iter = *src_vma_result;
 | 
				
			||||||
 | 
					    src_vma_iter->second.attribute = MemoryAttribute::Locked;
 | 
				
			||||||
 | 
					    Reprotect(src_vma_iter, VMAPermission::Read);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // The destination memory region is fine as is, however we need to make it read-only.
 | 
				
			||||||
 | 
					    return ReprotectRange(dst_address, size, VMAPermission::Read);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MemoryInfo VMManager::QueryMemory(VAddr address) const {
 | 
					MemoryInfo VMManager::QueryMemory(VAddr address) const {
 | 
				
			||||||
    const auto vma = FindVMA(address);
 | 
					    const auto vma = FindVMA(address);
 | 
				
			||||||
    MemoryInfo memory_info{};
 | 
					    MemoryInfo memory_info{};
 | 
				
			||||||
 | 
				
			|||||||
@ -43,6 +43,9 @@ enum class VMAPermission : u8 {
 | 
				
			|||||||
    ReadExecute = Read | Execute,
 | 
					    ReadExecute = Read | Execute,
 | 
				
			||||||
    WriteExecute = Write | Execute,
 | 
					    WriteExecute = Write | Execute,
 | 
				
			||||||
    ReadWriteExecute = Read | Write | Execute,
 | 
					    ReadWriteExecute = Read | Write | Execute,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Used as a wildcard when checking permissions across memory ranges
 | 
				
			||||||
 | 
					    All = 0xFF,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
constexpr VMAPermission operator|(VMAPermission lhs, VMAPermission rhs) {
 | 
					constexpr VMAPermission operator|(VMAPermission lhs, VMAPermission rhs) {
 | 
				
			||||||
@ -152,6 +155,9 @@ enum class MemoryState : u32 {
 | 
				
			|||||||
    FlagUncached                    = 1U << 24,
 | 
					    FlagUncached                    = 1U << 24,
 | 
				
			||||||
    FlagCodeMemory                  = 1U << 25,
 | 
					    FlagCodeMemory                  = 1U << 25,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Wildcard used in range checking to indicate all states.
 | 
				
			||||||
 | 
					    All                             = 0xFFFFFFFF,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Convenience flag sets to reduce repetition
 | 
					    // Convenience flag sets to reduce repetition
 | 
				
			||||||
    IPCFlags = FlagIPC0 | FlagIPC3 | FlagIPC1,
 | 
					    IPCFlags = FlagIPC0 | FlagIPC3 | FlagIPC1,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -415,6 +421,26 @@ public:
 | 
				
			|||||||
    ///
 | 
					    ///
 | 
				
			||||||
    ResultVal<VAddr> SetHeapSize(u64 size);
 | 
					    ResultVal<VAddr> SetHeapSize(u64 size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Maps a region of memory as code memory.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// @param dst_address The base address of the region to create the aliasing memory region.
 | 
				
			||||||
 | 
					    /// @param src_address The base address of the region to be aliased.
 | 
				
			||||||
 | 
					    /// @param size        The total amount of memory to map in bytes.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// @pre Both memory regions lie within the actual addressable address space.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// @post After this function finishes execution, assuming success, then the address range
 | 
				
			||||||
 | 
					    ///       [dst_address, dst_address+size) will alias the memory region,
 | 
				
			||||||
 | 
					    ///       [src_address, src_address+size).
 | 
				
			||||||
 | 
					    ///       <p>
 | 
				
			||||||
 | 
					    ///       What this also entails is as follows:
 | 
				
			||||||
 | 
					    ///          1. The aliased region gains the Locked memory attribute.
 | 
				
			||||||
 | 
					    ///          2. The aliased region becomes read-only.
 | 
				
			||||||
 | 
					    ///          3. The aliasing region becomes read-only.
 | 
				
			||||||
 | 
					    ///          4. The aliasing region is created with a memory state of MemoryState::CodeModule.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    ResultCode MapCodeMemory(VAddr dst_address, VAddr src_address, u64 size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Queries the memory manager for information about the given address.
 | 
					    /// Queries the memory manager for information about the given address.
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// @param address The address to query the memory manager about for information.
 | 
					    /// @param address The address to query the memory manager about for information.
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user