diff options
| -rw-r--r-- | src/core/file_sys/ips_layer.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/process.cpp | 6 | ||||
| -rw-r--r-- | src/core/hle/kernel/vm_manager.cpp | 20 | ||||
| -rw-r--r-- | src/core/hle/kernel/vm_manager.h | 8 | ||||
| -rw-r--r-- | src/core/hle/service/ldr/ldr.cpp | 52 | ||||
| -rw-r--r-- | src/core/loader/nro.cpp | 21 | ||||
| -rw-r--r-- | src/core/loader/nro.h | 3 | 
7 files changed, 102 insertions, 10 deletions
diff --git a/src/core/file_sys/ips_layer.cpp b/src/core/file_sys/ips_layer.cpp index 554eae9bc..999939d5a 100644 --- a/src/core/file_sys/ips_layer.cpp +++ b/src/core/file_sys/ips_layer.cpp @@ -99,7 +99,7 @@ VirtualFile PatchIPS(const VirtualFile& in, const VirtualFile& ips) {              u16 rle_size{};              if (ips->ReadObject(&rle_size, offset) != sizeof(u16))                  return nullptr; -            rle_size = Common::swap16(data_size); +            rle_size = Common::swap16(rle_size);              offset += sizeof(u16);              const auto data = ips->ReadByte(offset++); diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 073dd5a7d..420218d59 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -232,6 +232,12 @@ void Process::LoadModule(CodeSet module_, VAddr base_addr) {      MapSegment(module_.CodeSegment(), VMAPermission::ReadExecute, MemoryState::CodeStatic);      MapSegment(module_.RODataSegment(), VMAPermission::Read, MemoryState::CodeMutable);      MapSegment(module_.DataSegment(), VMAPermission::ReadWrite, MemoryState::CodeMutable); + +    // Clear instruction cache in CPU JIT +    Core::System::GetInstance().ArmInterface(0).ClearInstructionCache(); +    Core::System::GetInstance().ArmInterface(1).ClearInstructionCache(); +    Core::System::GetInstance().ArmInterface(2).ClearInstructionCache(); +    Core::System::GetInstance().ArmInterface(3).ClearInstructionCache();  }  ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) { diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index e1a34eef1..1a92c8f70 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp @@ -143,6 +143,26 @@ ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8* me      return MakeResult<VMAHandle>(MergeAdjacent(vma_handle));  } +ResultVal<VAddr> VMManager::FindFreeRegion(u64 size) const { +    // Find the first Free VMA. +    const VAddr base = GetASLRRegionBaseAddress(); +    const VMAHandle vma_handle = std::find_if(vma_map.begin(), vma_map.end(), [&](const auto& vma) { +        if (vma.second.type != VMAType::Free) +            return false; + +        const VAddr vma_end = vma.second.base + vma.second.size; +        return vma_end > base && vma_end >= base + size; +    }); + +    if (vma_handle == vma_map.end()) { +        // TODO(Subv): Find the correct error code here. +        return ResultCode(-1); +    } + +    const VAddr target = std::max(base, vma_handle->second.base); +    return MakeResult<VAddr>(target); +} +  ResultVal<VMManager::VMAHandle> VMManager::MapMMIO(VAddr target, PAddr paddr, u64 size,                                                     MemoryState state,                                                     Memory::MemoryHookPointer mmio_handler) { diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h index 84c890224..2447cbb8f 100644 --- a/src/core/hle/kernel/vm_manager.h +++ b/src/core/hle/kernel/vm_manager.h @@ -158,6 +158,14 @@ public:      ResultVal<VMAHandle> MapBackingMemory(VAddr target, u8* memory, u64 size, MemoryState state);      /** +     * Finds the first free address that can hold a region of the desired size. +     * +     * @param size Size of the desired region. +     * @return The found free address. +     */ +    ResultVal<VAddr> FindFreeRegion(u64 size) const; + +    /**       * Maps a memory-mapped IO region at a given address.       *       * @param target The guest address to start the mapping at. diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index ec32faf15..d607d985e 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp @@ -3,9 +3,13 @@  // Refer to the license.txt file included.  #include <memory> +#include <fmt/format.h> +#include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/process.h"  #include "core/hle/service/ldr/ldr.h"  #include "core/hle/service/service.h" +#include "core/loader/nro.h"  namespace Service::LDR { @@ -59,16 +63,58 @@ public:      explicit RelocatableObject() : ServiceFramework{"ldr:ro"} {          // clang-format off          static const FunctionInfo functions[] = { -            {0, nullptr, "LoadNro"}, +            {0, &RelocatableObject::LoadNro, "LoadNro"},              {1, nullptr, "UnloadNro"}, -            {2, nullptr, "LoadNrr"}, +            {2, &RelocatableObject::LoadNrr, "LoadNrr"},              {3, nullptr, "UnloadNrr"}, -            {4, nullptr, "Initialize"}, +            {4, &RelocatableObject::Initialize, "Initialize"},          };          // clang-format on          RegisterHandlers(functions);      } + +    void LoadNrr(Kernel::HLERequestContext& ctx) { +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(RESULT_SUCCESS); +        LOG_WARNING(Service_LDR, "(STUBBED) called"); +    } + +    void LoadNro(Kernel::HLERequestContext& ctx) { +        IPC::RequestParser rp{ctx}; +        rp.Skip(2, false); +        const VAddr nro_addr{rp.Pop<VAddr>()}; +        const u64 nro_size{rp.Pop<u64>()}; +        const VAddr bss_addr{rp.Pop<VAddr>()}; +        const u64 bss_size{rp.Pop<u64>()}; + +        // Read NRO data from memory +        std::vector<u8> nro_data(nro_size); +        Memory::ReadBlock(nro_addr, nro_data.data(), nro_size); + +        // Load NRO as new executable module +        const VAddr addr{*Core::CurrentProcess()->VMManager().FindFreeRegion(nro_size + bss_size)}; +        Loader::AppLoader_NRO::LoadNro(nro_data, fmt::format("nro-{:08x}", addr), addr); + +        // TODO(bunnei): This is an incomplete implementation. It was tested with Super Mario Party. +        // It is currently missing: +        // - Signature checks with LoadNRR +        // - Checking if a module has already been loaded +        // - Using/validating BSS, etc. params (these are used from NRO header instead) +        // - Error checking +        // - ...Probably other things + +        IPC::ResponseBuilder rb{ctx, 4}; +        rb.Push(RESULT_SUCCESS); +        rb.Push(addr); +        LOG_WARNING(Service_LDR, "(STUBBED) called"); +    } + +    void Initialize(Kernel::HLERequestContext& ctx) { +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(RESULT_SUCCESS); +        LOG_WARNING(Service_LDR, "(STUBBED) called"); +    }  };  void InstallInterfaces(SM::ServiceManager& sm) { diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index 243b499f2..bc8e402a8 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp @@ -127,18 +127,23 @@ static constexpr u32 PageAlignSize(u32 size) {      return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK;  } -bool AppLoader_NRO::LoadNro(const FileSys::VfsFile& file, VAddr load_base) { -    // Read NSO header -    NroHeader nro_header{}; -    if (sizeof(NroHeader) != file.ReadObject(&nro_header)) { +/*static*/ bool AppLoader_NRO::LoadNro(const std::vector<u8>& data, const std::string& name, +                                       VAddr load_base) { + +    if (data.size() < sizeof(NroHeader)) {          return {};      } + +    // Read NSO header +    NroHeader nro_header{}; +    std::memcpy(&nro_header, data.data(), sizeof(NroHeader));      if (nro_header.magic != Common::MakeMagic('N', 'R', 'O', '0')) {          return {};      }      // Build program image -    std::vector<u8> program_image = file.ReadBytes(PageAlignSize(nro_header.file_size)); +    std::vector<u8> program_image(PageAlignSize(nro_header.file_size)); +    std::memcpy(program_image.data(), data.data(), program_image.size());      if (program_image.size() != PageAlignSize(nro_header.file_size)) {          return {};      } @@ -182,11 +187,15 @@ bool AppLoader_NRO::LoadNro(const FileSys::VfsFile& file, VAddr load_base) {      Core::CurrentProcess()->LoadModule(std::move(codeset), load_base);      // Register module with GDBStub -    GDBStub::RegisterModule(file.GetName(), load_base, load_base); +    GDBStub::RegisterModule(name, load_base, load_base);      return true;  } +bool AppLoader_NRO::LoadNro(const FileSys::VfsFile& file, VAddr load_base) { +    return AppLoader_NRO::LoadNro(file.ReadAllBytes(), file.GetName(), load_base); +} +  ResultStatus AppLoader_NRO::Load(Kernel::Process& process) {      if (is_loaded) {          return ResultStatus::ErrorAlreadyLoaded; diff --git a/src/core/loader/nro.h b/src/core/loader/nro.h index 50ee5a78a..3e6959302 100644 --- a/src/core/loader/nro.h +++ b/src/core/loader/nro.h @@ -5,6 +5,7 @@  #pragma once  #include <string> +#include <vector>  #include "common/common_types.h"  #include "core/loader/linker.h"  #include "core/loader/loader.h" @@ -40,6 +41,8 @@ public:      ResultStatus ReadTitle(std::string& title) override;      bool IsRomFSUpdatable() const override; +    static bool LoadNro(const std::vector<u8>& data, const std::string& name, VAddr load_base); +  private:      bool LoadNro(const FileSys::VfsFile& file, VAddr load_base);  | 
