Bläddra i källkod

loader: nso: Fix loader size and arguments.

bunnei 6 år sedan
förälder
incheckning
bebfb05c1b
3 ändrade filer med 47 tillägg och 25 borttagningar
  1. 34 13
      src/core/loader/deconstructed_rom_directory.cpp
  2. 12 10
      src/core/loader/nso.cpp
  3. 1 2
      src/core/loader/nso.h

+ 34 - 13
src/core/loader/deconstructed_rom_directory.cpp

@@ -14,6 +14,7 @@
 #include "core/file_sys/romfs_factory.h"
 #include "core/gdbstub/gdbstub.h"
 #include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/memory/page_table.h"
 #include "core/hle/kernel/process.h"
 #include "core/hle/service/filesystem/filesystem.h"
 #include "core/loader/deconstructed_rom_directory.h"
@@ -129,27 +130,47 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
     }
     metadata.Print();
 
-    if (process.LoadFromMetadata(metadata).IsError()) {
-        return {ResultStatus::ErrorUnableToParseKernelMetadata, {}};
+    const auto static_modules = {"rtld",    "main",    "subsdk0", "subsdk1", "subsdk2", "subsdk3",
+                                 "subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"};
+
+    // Use the NSO module loader to figure out the code layout
+    std::size_t code_size{};
+    for (const auto& module : static_modules) {
+        const FileSys::VirtualFile module_file{dir->GetFile(module)};
+        if (!module_file) {
+            continue;
+        }
+
+        const bool should_pass_arguments{std::strcmp(module, "rtld") == 0};
+        const auto tentative_next_load_addr{AppLoader_NSO::LoadModule(
+            process, *module_file, code_size, should_pass_arguments, false)};
+        if (!tentative_next_load_addr) {
+            return {ResultStatus::ErrorLoadingNSO, {}};
+        }
+
+        code_size = *tentative_next_load_addr;
     }
 
-    const FileSys::PatchManager pm(metadata.GetTitleID());
+    // Setup the process code layout
+    if (process.LoadFromMetadata(metadata, code_size).IsError()) {
+        return {ResultStatus::ErrorUnableToParseKernelMetadata, {}};
+    }
 
     // Load NSO modules
     modules.clear();
-    const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress();
-    VAddr next_load_addr = base_address;
-    for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3",
-                               "subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) {
-        const FileSys::VirtualFile module_file = dir->GetFile(module);
-        if (module_file == nullptr) {
+    const VAddr base_address{process.PageTable().GetCodeRegionStart()};
+    VAddr next_load_addr{base_address};
+    const FileSys::PatchManager pm{metadata.GetTitleID()};
+    for (const auto& module : static_modules) {
+        const FileSys::VirtualFile module_file{dir->GetFile(module)};
+        if (!module_file) {
             continue;
         }
 
-        const VAddr load_addr = next_load_addr;
-        const bool should_pass_arguments = std::strcmp(module, "rtld") == 0;
-        const auto tentative_next_load_addr =
-            AppLoader_NSO::LoadModule(process, *module_file, load_addr, should_pass_arguments, pm);
+        const VAddr load_addr{next_load_addr};
+        const bool should_pass_arguments{std::strcmp(module, "rtld") == 0};
+        const auto tentative_next_load_addr{AppLoader_NSO::LoadModule(
+            process, *module_file, load_addr, should_pass_arguments, true, pm)};
         if (!tentative_next_load_addr) {
             return {ResultStatus::ErrorLoadingNSO, {}};
         }

+ 12 - 10
src/core/loader/nso.cpp

@@ -16,8 +16,8 @@
 #include "core/file_sys/patch_manager.h"
 #include "core/gdbstub/gdbstub.h"
 #include "core/hle/kernel/code_set.h"
+#include "core/hle/kernel/memory/page_table.h"
 #include "core/hle/kernel/process.h"
-#include "core/hle/kernel/vm_manager.h"
 #include "core/loader/nso.h"
 #include "core/memory.h"
 #include "core/settings.h"
@@ -73,7 +73,7 @@ FileType AppLoader_NSO::IdentifyType(const FileSys::VirtualFile& file) {
 
 std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process,
                                                const FileSys::VfsFile& file, VAddr load_base,
-                                               bool should_pass_arguments,
+                                               bool should_pass_arguments, bool load_into_process,
                                                std::optional<FileSys::PatchManager> pm) {
     if (file.GetSize() < sizeof(NSOHeader)) {
         return {};
@@ -105,12 +105,9 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process,
         codeset.segments[i].size = nso_header.segments[i].size;
     }
 
-    if (should_pass_arguments) {
-        std::vector<u8> arg_data{Settings::values.program_args.begin(),
-                                 Settings::values.program_args.end()};
-        if (arg_data.empty()) {
-            arg_data.resize(NSO_ARGUMENT_DEFAULT_SIZE);
-        }
+    if (should_pass_arguments && !Settings::values.program_args.empty()) {
+        const auto arg_data{Settings::values.program_args};
+
         codeset.DataSegment().size += NSO_ARGUMENT_DATA_ALLOCATION_SIZE;
         NSOArgumentHeader args_header{
             NSO_ARGUMENT_DATA_ALLOCATION_SIZE, static_cast<u32_le>(arg_data.size()), {}};
@@ -144,6 +141,11 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process,
         std::copy(pi_header.begin() + sizeof(NSOHeader), pi_header.end(), program_image.data());
     }
 
+    // If we aren't actually loading (i.e. just computing the process code layout), we are done
+    if (!load_into_process) {
+        return load_base + image_size;
+    }
+
     // Apply cheats if they exist and the program has a valid title ID
     if (pm) {
         auto& system = Core::System::GetInstance();
@@ -172,8 +174,8 @@ AppLoader_NSO::LoadResult AppLoader_NSO::Load(Kernel::Process& process) {
     modules.clear();
 
     // Load module
-    const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress();
-    if (!LoadModule(process, *file, base_address, true)) {
+    const VAddr base_address = process.PageTable().GetCodeRegionStart();
+    if (!LoadModule(process, *file, base_address, true, true)) {
         return {ResultStatus::ErrorLoadingNSO, {}};
     }
 

+ 1 - 2
src/core/loader/nso.h

@@ -56,8 +56,6 @@ static_assert(sizeof(NSOHeader) == 0x100, "NSOHeader has incorrect size.");
 static_assert(std::is_trivially_copyable_v<NSOHeader>, "NSOHeader must be trivially copyable.");
 
 constexpr u64 NSO_ARGUMENT_DATA_ALLOCATION_SIZE = 0x9000;
-// NOTE: Official software default argument state is unverified.
-constexpr u64 NSO_ARGUMENT_DEFAULT_SIZE = 1;
 
 struct NSOArgumentHeader {
     u32_le allocated_size;
@@ -84,6 +82,7 @@ public:
 
     static std::optional<VAddr> LoadModule(Kernel::Process& process, const FileSys::VfsFile& file,
                                            VAddr load_base, bool should_pass_arguments,
+                                           bool load_into_process,
                                            std::optional<FileSys::PatchManager> pm = {});
 
     LoadResult Load(Kernel::Process& process) override;