summaryrefslogtreecommitdiffstats
path: root/src/core/loader
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/loader')
-rw-r--r--src/core/loader/deconstructed_rom_directory.cpp47
-rw-r--r--src/core/loader/elf.cpp6
-rw-r--r--src/core/loader/kip.cpp6
-rw-r--r--src/core/loader/nro.cpp8
-rw-r--r--src/core/loader/nso.cpp54
-rw-r--r--src/core/loader/nso.h3
6 files changed, 69 insertions, 55 deletions
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp
index 53559e8b1..134e83412 100644
--- a/src/core/loader/deconstructed_rom_directory.cpp
+++ b/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, {}};
}
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp
index 8908e5328..1e9ed2837 100644
--- a/src/core/loader/elf.cpp
+++ b/src/core/loader/elf.cpp
@@ -10,8 +10,8 @@
#include "common/file_util.h"
#include "common/logging/log.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/elf.h"
#include "core/memory.h"
@@ -393,7 +393,7 @@ AppLoader_ELF::LoadResult AppLoader_ELF::Load(Kernel::Process& process) {
return {ResultStatus::ErrorIncorrectELFFileSize, {}};
}
- const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress();
+ const VAddr base_address = process.PageTable().GetCodeRegionStart();
ElfReader elf_reader(&buffer[0]);
Kernel::CodeSet codeset = elf_reader.LoadInto(base_address);
const VAddr entry_point = codeset.entrypoint;
@@ -401,7 +401,7 @@ AppLoader_ELF::LoadResult AppLoader_ELF::Load(Kernel::Process& process) {
process.LoadModule(std::move(codeset), entry_point);
is_loaded = true;
- return {ResultStatus::Success, LoadParameters{48, Memory::DEFAULT_STACK_SIZE}};
+ return {ResultStatus::Success, LoadParameters{48, Core::Memory::DEFAULT_STACK_SIZE}};
}
} // namespace Loader
diff --git a/src/core/loader/kip.cpp b/src/core/loader/kip.cpp
index 092103abe..40fa03ad1 100644
--- a/src/core/loader/kip.cpp
+++ b/src/core/loader/kip.cpp
@@ -7,14 +7,16 @@
#include "core/file_sys/program_metadata.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/loader/kip.h"
+#include "core/memory.h"
namespace Loader {
namespace {
constexpr u32 PageAlignSize(u32 size) {
- return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK;
+ return (size + Core::Memory::PAGE_MASK) & ~Core::Memory::PAGE_MASK;
}
} // Anonymous namespace
@@ -68,7 +70,7 @@ AppLoader::LoadResult AppLoader_KIP::Load(Kernel::Process& process) {
kip->GetMainThreadCpuCore(), kip->GetMainThreadStackSize(),
kip->GetTitleID(), 0xFFFFFFFFFFFFFFFF, kip->GetKernelCapabilities());
- const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress();
+ const VAddr base_address = process.PageTable().GetCodeRegionStart();
Kernel::CodeSet codeset;
Kernel::PhysicalMemory program_image;
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index 175898b91..5d7e8136e 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -16,8 +16,8 @@
#include "core/file_sys/vfs_offset.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/hle/service/filesystem/filesystem.h"
#include "core/loader/nro.h"
#include "core/loader/nso.h"
@@ -127,7 +127,7 @@ FileType AppLoader_NRO::IdentifyType(const FileSys::VirtualFile& file) {
}
static constexpr u32 PageAlignSize(u32 size) {
- return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK;
+ return (size + Core::Memory::PAGE_MASK) & ~Core::Memory::PAGE_MASK;
}
static bool LoadNroImpl(Kernel::Process& process, const std::vector<u8>& data,
@@ -208,7 +208,7 @@ AppLoader_NRO::LoadResult AppLoader_NRO::Load(Kernel::Process& process) {
}
// Load NRO
- const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress();
+ const VAddr base_address = process.PageTable().GetCodeRegionStart();
if (!LoadNro(process, *file, base_address)) {
return {ResultStatus::ErrorLoadingNRO, {}};
@@ -221,7 +221,7 @@ AppLoader_NRO::LoadResult AppLoader_NRO::Load(Kernel::Process& process) {
is_loaded = true;
return {ResultStatus::Success,
- LoadParameters{Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE}};
+ LoadParameters{Kernel::THREADPRIO_DEFAULT, Core::Memory::DEFAULT_STACK_SIZE}};
}
ResultStatus AppLoader_NRO::ReadIcon(std::vector<u8>& buffer) {
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index 044067a5b..612ff9bf6 100644
--- a/src/core/loader/nso.cpp
+++ b/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"
@@ -47,7 +47,7 @@ std::vector<u8> DecompressSegment(const std::vector<u8>& compressed_data,
}
constexpr u32 PageAlignSize(u32 size) {
- return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK;
+ return (size + Core::Memory::PAGE_MASK) & ~Core::Memory::PAGE_MASK;
}
} // Anonymous namespace
@@ -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 {};
@@ -97,21 +97,17 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process,
if (nso_header.IsSegmentCompressed(i)) {
data = DecompressSegment(data, nso_header.segments[i]);
}
- program_image.resize(nso_header.segments[i].location +
- PageAlignSize(static_cast<u32>(data.size())));
+ program_image.resize(nso_header.segments[i].location + static_cast<u32>(data.size()));
std::memcpy(program_image.data() + nso_header.segments[i].location, data.data(),
data.size());
codeset.segments[i].addr = nso_header.segments[i].location;
codeset.segments[i].offset = nso_header.segments[i].location;
- codeset.segments[i].size = PageAlignSize(static_cast<u32>(data.size()));
+ 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()), {}};
@@ -123,24 +119,15 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process,
arg_data.size());
}
- // MOD header pointer is at .text offset + 4
- u32 module_offset;
- std::memcpy(&module_offset, program_image.data() + 4, sizeof(u32));
-
- // Read MOD header
- MODHeader mod_header{};
- // Default .bss to size in segment header if MOD0 section doesn't exist
- u32 bss_size{PageAlignSize(nso_header.segments[2].bss_size)};
- std::memcpy(&mod_header, program_image.data() + module_offset, sizeof(MODHeader));
- const bool has_mod_header{mod_header.magic == Common::MakeMagic('M', 'O', 'D', '0')};
- if (has_mod_header) {
- // Resize program image to include .bss section and page align each section
- bss_size = PageAlignSize(mod_header.bss_end_offset - mod_header.bss_start_offset);
- }
- codeset.DataSegment().size += bss_size;
- const u32 image_size{PageAlignSize(static_cast<u32>(program_image.size()) + bss_size)};
+ codeset.DataSegment().size += nso_header.segments[2].bss_size;
+ const u32 image_size{
+ PageAlignSize(static_cast<u32>(program_image.size()) + nso_header.segments[2].bss_size)};
program_image.resize(image_size);
+ for (std::size_t i = 0; i < nso_header.segments.size(); ++i) {
+ codeset.segments[i].size = PageAlignSize(codeset.segments[i].size);
+ }
+
// Apply patches if necessary
if (pm && (pm->HasNSOPatch(nso_header.build_id) || Settings::values.dump_nso)) {
std::vector<u8> pi_header;
@@ -154,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();
@@ -182,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, {}};
}
@@ -192,7 +184,7 @@ AppLoader_NSO::LoadResult AppLoader_NSO::Load(Kernel::Process& process) {
is_loaded = true;
return {ResultStatus::Success,
- LoadParameters{Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE}};
+ LoadParameters{Kernel::THREADPRIO_DEFAULT, Core::Memory::DEFAULT_STACK_SIZE}};
}
ResultStatus AppLoader_NSO::ReadNSOModules(Modules& modules) {
diff --git a/src/core/loader/nso.h b/src/core/loader/nso.h
index d2d600cd9..b210830f0 100644
--- a/src/core/loader/nso.h
+++ b/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;