diff --git a/src/core/file_sys/program_metadata.cpp b/src/core/file_sys/program_metadata.cpp index 02319ce0f6..8903ed1d3f 100644 --- a/src/core/file_sys/program_metadata.cpp +++ b/src/core/file_sys/program_metadata.cpp @@ -83,10 +83,12 @@ void ProgramMetadata::Print() const { auto address_space = "Unknown"; switch (npdm_header.address_space_type) { - case ProgramAddressSpaceType::Is64Bit: + case ProgramAddressSpaceType::Is36Bit: + case ProgramAddressSpaceType::Is39Bit: address_space = "64-bit"; break; case ProgramAddressSpaceType::Is32Bit: + case ProgramAddressSpaceType::Is32BitNoMap: address_space = "32-bit"; break; } diff --git a/src/core/file_sys/program_metadata.h b/src/core/file_sys/program_metadata.h index 1143e36c44..e4470d6f08 100644 --- a/src/core/file_sys/program_metadata.h +++ b/src/core/file_sys/program_metadata.h @@ -17,8 +17,10 @@ enum class ResultStatus : u16; namespace FileSys { enum class ProgramAddressSpaceType : u8 { - Is64Bit = 1, - Is32Bit = 2, + Is32Bit = 0, + Is36Bit = 1, + Is32BitNoMap = 2, + Is39Bit = 3, }; enum class ProgramFilePermission : u64 { diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 121f741fd1..f337f626fd 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -8,6 +8,7 @@ #include "common/common_funcs.h" #include "common/logging/log.h" #include "core/core.h" +#include "core/file_sys/program_metadata.h" #include "core/hle/kernel/errors.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" @@ -34,14 +35,21 @@ SharedPtr Process::Create(KernelCore& kernel, std::string&& name) { process->name = std::move(name); process->flags.raw = 0; process->flags.memory_region.Assign(MemoryRegion::APPLICATION); + process->resource_limit = kernel.ResourceLimitForCategory(ResourceLimitCategory::APPLICATION); process->status = ProcessStatus::Created; process->program_id = 0; process->process_id = kernel.CreateNewProcessID(); + process->svc_access_mask.set(); kernel.AppendNewProcess(process); return process; } +void Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) { + program_id = metadata.GetTitleID(); + vm_manager.Reset(metadata.GetAddressSpaceType()); +} + void Process::ParseKernelCaps(const u32* kernel_caps, std::size_t len) { for (std::size_t i = 0; i < len; ++i) { u32 descriptor = kernel_caps[i]; diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 04d74e5724..adb03c2288 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -17,6 +17,10 @@ #include "core/hle/kernel/thread.h" #include "core/hle/kernel/vm_manager.h" +namespace FileSys { +class ProgramMetadata; +} + namespace Kernel { class KernelCore; @@ -141,6 +145,14 @@ public: return process_id; } + /** + * Loads process-specifics configuration info with metadata provided + * by an executable. + * + * @param metadata The provided metadata to load process specific info. + */ + void LoadFromMetadata(const FileSys::ProgramMetadata& metadata); + /// Title ID corresponding to the process u64 program_id; diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index 608cbd57bc..337f17b7bf 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp @@ -9,6 +9,7 @@ #include "common/logging/log.h" #include "core/arm/arm_interface.h" #include "core/core.h" +#include "core/file_sys/program_metadata.h" #include "core/hle/kernel/errors.h" #include "core/hle/kernel/vm_manager.h" #include "core/memory.h" @@ -54,25 +55,24 @@ bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const { } VMManager::VMManager() { - Reset(); + // Default to assuming a 39-bit address space. This way we have a sane + // starting point with executables that don't provide metadata. + Reset(FileSys::ProgramAddressSpaceType::Is39Bit); } VMManager::~VMManager() { - Reset(); + Reset(FileSys::ProgramAddressSpaceType::Is39Bit); } -void VMManager::Reset() { - vma_map.clear(); +void VMManager::Reset(FileSys::ProgramAddressSpaceType type) { + Clear(); + InitializeMemoryRegionRanges(type); // Initialize the map with a single free region covering the entire managed space. VirtualMemoryArea initial_vma; initial_vma.size = MAX_ADDRESS; vma_map.emplace(initial_vma.base, initial_vma); - page_table.pointers.fill(nullptr); - page_table.special_regions.clear(); - page_table.attributes.fill(Memory::PageType::Unmapped); - UpdatePageTableForVMA(initial_vma); } @@ -382,6 +382,84 @@ void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) { } } +void VMManager::InitializeMemoryRegionRanges(FileSys::ProgramAddressSpaceType type) { + u64 map_region_size = 0; + u64 heap_region_size = 0; + u64 new_map_region_size = 0; + u64 tls_io_region_size = 0; + + switch (type) { + case FileSys::ProgramAddressSpaceType::Is32Bit: + address_space_width = 32; + code_region_base = 0x200000; + code_region_end = code_region_base + 0x3FE00000; + map_region_size = 0x40000000; + heap_region_size = 0x40000000; + break; + case FileSys::ProgramAddressSpaceType::Is36Bit: + address_space_width = 36; + code_region_base = 0x8000000; + code_region_end = code_region_base + 0x78000000; + map_region_size = 0x180000000; + heap_region_size = 0x180000000; + break; + case FileSys::ProgramAddressSpaceType::Is32BitNoMap: + address_space_width = 32; + code_region_base = 0x200000; + code_region_end = code_region_base + 0x3FE00000; + map_region_size = 0; + heap_region_size = 0x80000000; + break; + case FileSys::ProgramAddressSpaceType::Is39Bit: + address_space_width = 39; + code_region_base = 0x8000000; + code_region_end = code_region_base + 0x80000000; + map_region_size = 0x1000000000; + heap_region_size = 0x180000000; + new_map_region_size = 0x80000000; + tls_io_region_size = 0x1000000000; + break; + default: + UNREACHABLE_MSG("Invalid address space type specified: {}", static_cast(type)); + return; + } + + address_space_base = 0; + address_space_end = 1ULL << address_space_width; + + map_region_base = code_region_end; + map_region_end = map_region_base + map_region_size; + + heap_region_base = map_region_end; + heap_region_end = heap_region_base + heap_region_size; + + new_map_region_base = heap_region_end; + new_map_region_end = new_map_region_base + new_map_region_size; + + tls_io_region_base = new_map_region_end; + tls_io_region_end = tls_io_region_base + tls_io_region_size; + + if (new_map_region_size == 0) { + new_map_region_base = address_space_base; + new_map_region_end = address_space_end; + } +} + +void VMManager::Clear() { + ClearVMAMap(); + ClearPageTable(); +} + +void VMManager::ClearVMAMap() { + vma_map.clear(); +} + +void VMManager::ClearPageTable() { + page_table.pointers.fill(nullptr); + page_table.special_regions.clear(); + page_table.attributes.fill(Memory::PageType::Unmapped); +} + u64 VMManager::GetTotalMemoryUsage() const { LOG_WARNING(Kernel, "(STUBBED) called"); return 0xF8000000; @@ -402,4 +480,64 @@ u64 VMManager::GetAddressSpaceSize() const { return MAX_ADDRESS; } +VAddr VMManager::GetCodeRegionBaseAddress() const { + return code_region_base; +} + +VAddr VMManager::GetCodeRegionEndAddress() const { + return code_region_end; +} + +u64 VMManager::GetCodeRegionSize() const { + return code_region_end - code_region_base; +} + +VAddr VMManager::GetHeapRegionBaseAddress() const { + return heap_region_base; +} + +VAddr VMManager::GetHeapRegionEndAddress() const { + return heap_region_end; +} + +u64 VMManager::GetHeapRegionSize() const { + return heap_region_end - heap_region_base; +} + +VAddr VMManager::GetMapRegionBaseAddress() const { + return map_region_base; +} + +VAddr VMManager::GetMapRegionEndAddress() const { + return map_region_end; +} + +u64 VMManager::GetMapRegionSize() const { + return map_region_end - map_region_base; +} + +VAddr VMManager::GetNewMapRegionBaseAddress() const { + return new_map_region_base; +} + +VAddr VMManager::GetNewMapRegionEndAddress() const { + return new_map_region_end; +} + +u64 VMManager::GetNewMapRegionSize() const { + return new_map_region_end - new_map_region_base; +} + +VAddr VMManager::GetTLSIORegionBaseAddress() const { + return tls_io_region_base; +} + +VAddr VMManager::GetTLSIORegionEndAddress() const { + return tls_io_region_end; +} + +u64 VMManager::GetTLSIORegionSize() const { + return tls_io_region_end - tls_io_region_base; +} + } // namespace Kernel diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h index de75036c07..0ce240126d 100644 --- a/src/core/hle/kernel/vm_manager.h +++ b/src/core/hle/kernel/vm_manager.h @@ -12,6 +12,10 @@ #include "core/memory.h" #include "core/memory_hook.h" +namespace FileSys { +enum class ProgramAddressSpaceType : u8; +} + namespace Kernel { enum class VMAType : u8 { @@ -130,7 +134,7 @@ public: ~VMManager(); /// Clears the address space map, re-initializing with a single free area. - void Reset(); + void Reset(FileSys::ProgramAddressSpaceType type); /// Finds the VMA in which the given address is included in, or `vma_map.end()`. VMAHandle FindVMA(VAddr target) const; @@ -195,12 +199,57 @@ public: /// Gets the total heap usage, used by svcGetInfo u64 GetTotalHeapUsage() const; - /// Gets the total address space base address, used by svcGetInfo + /// Gets the address space base address, used by svcGetInfo VAddr GetAddressSpaceBaseAddr() const; /// Gets the total address space address size, used by svcGetInfo u64 GetAddressSpaceSize() const; + /// Gets the base address of the code region. + VAddr GetCodeRegionBaseAddress() const; + + /// Gets the end address of the code region. + VAddr GetCodeRegionEndAddress() const; + + /// Gets the total size of the code region in bytes. + u64 GetCodeRegionSize() const; + + /// Gets the base address of the heap region. + VAddr GetHeapRegionBaseAddress() const; + + /// Gets the end address of the heap region; + VAddr GetHeapRegionEndAddress() const; + + /// Gets the total size of the heap region in bytes. + u64 GetHeapRegionSize() const; + + /// Gets the base address of the map region. + VAddr GetMapRegionBaseAddress() const; + + /// Gets the end address of the map region. + VAddr GetMapRegionEndAddress() const; + + /// Gets the total size of the map region in bytes. + u64 GetMapRegionSize() const; + + /// Gets the base address of the new map region. + VAddr GetNewMapRegionBaseAddress() const; + + /// Gets the end address of the new map region. + VAddr GetNewMapRegionEndAddress() const; + + /// Gets the total size of the new map region in bytes. + u64 GetNewMapRegionSize() const; + + /// Gets the base address of the TLS IO region. + VAddr GetTLSIORegionBaseAddress() const; + + /// Gets the end address of the TLS IO region. + VAddr GetTLSIORegionEndAddress() const; + + /// Gets the total size of the TLS IO region in bytes. + u64 GetTLSIORegionSize() const; + /// Each VMManager has its own page table, which is set as the main one when the owning process /// is scheduled. Memory::PageTable page_table; @@ -240,5 +289,36 @@ private: /// Updates the pages corresponding to this VMA so they match the VMA's attributes. void UpdatePageTableForVMA(const VirtualMemoryArea& vma); + + /// Initializes memory region ranges to adhere to a given address space type. + void InitializeMemoryRegionRanges(FileSys::ProgramAddressSpaceType type); + + /// Clears the underlying map and page table. + void Clear(); + + /// Clears out the VMA map, unmapping any previously mapped ranges. + void ClearVMAMap(); + + /// Clears out the page table + void ClearPageTable(); + + u32 address_space_width = 0; + VAddr address_space_base = 0; + VAddr address_space_end = 0; + + VAddr code_region_base = 0; + VAddr code_region_end = 0; + + VAddr heap_region_base = 0; + VAddr heap_region_end = 0; + + VAddr map_region_base = 0; + VAddr map_region_end = 0; + + VAddr new_map_region_base = 0; + VAddr new_map_region_end = 0; + + VAddr tls_io_region_base = 0; + VAddr tls_io_region_end = 0; }; } // namespace Kernel diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index 2b8f781360..44d62ab7f4 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -14,7 +14,6 @@ #include "core/gdbstub/gdbstub.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" -#include "core/hle/kernel/resource_limit.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/loader/deconstructed_rom_directory.h" #include "core/loader/nso.h" @@ -127,10 +126,13 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load( metadata.Print(); const FileSys::ProgramAddressSpaceType arch_bits{metadata.GetAddressSpaceType()}; - if (arch_bits == FileSys::ProgramAddressSpaceType::Is32Bit) { + if (arch_bits == FileSys::ProgramAddressSpaceType::Is32Bit || + arch_bits == FileSys::ProgramAddressSpaceType::Is32BitNoMap) { return ResultStatus::Error32BitISA; } + process->LoadFromMetadata(metadata); + // Load NSO modules VAddr next_load_addr{Memory::PROCESS_IMAGE_VADDR}; for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3", @@ -145,11 +147,6 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load( } } - auto& kernel = Core::System::GetInstance().Kernel(); - process->program_id = metadata.GetTitleID(); - process->svc_access_mask.set(); - process->resource_limit = - kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION); process->Run(Memory::PROCESS_IMAGE_VADDR, metadata.GetMainThreadPriority(), metadata.GetMainThreadStackSize()); diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp index 0e2af20b40..00d8a82b89 100644 --- a/src/core/loader/elf.cpp +++ b/src/core/loader/elf.cpp @@ -12,7 +12,6 @@ #include "core/core.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" -#include "core/hle/kernel/resource_limit.h" #include "core/loader/elf.h" #include "core/memory.h" @@ -400,13 +399,6 @@ ResultStatus AppLoader_ELF::Load(Kernel::SharedPtr& process) { codeset->name = file->GetName(); process->LoadModule(codeset, codeset->entrypoint); - process->svc_access_mask.set(); - - // Attach the default resource limit (APPLICATION) to the process - auto& kernel = Core::System::GetInstance().Kernel(); - process->resource_limit = - kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION); - process->Run(codeset->entrypoint, 48, Memory::DEFAULT_STACK_SIZE); is_loaded = true; diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index c49ec34ab2..2385012eb8 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp @@ -16,7 +16,6 @@ #include "core/gdbstub/gdbstub.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" -#include "core/hle/kernel/resource_limit.h" #include "core/loader/nro.h" #include "core/memory.h" @@ -187,10 +186,6 @@ ResultStatus AppLoader_NRO::Load(Kernel::SharedPtr& process) { return ResultStatus::ErrorLoadingNRO; } - auto& kernel = Core::System::GetInstance().Kernel(); - process->svc_access_mask.set(); - process->resource_limit = - kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION); process->Run(base_addr, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE); is_loaded = true; diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index 78a4438c47..9fd9933fb4 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp @@ -13,7 +13,6 @@ #include "core/gdbstub/gdbstub.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" -#include "core/hle/kernel/resource_limit.h" #include "core/loader/nso.h" #include "core/memory.h" @@ -162,10 +161,6 @@ ResultStatus AppLoader_NSO::Load(Kernel::SharedPtr& process) { LoadModule(file, Memory::PROCESS_IMAGE_VADDR); LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), Memory::PROCESS_IMAGE_VADDR); - auto& kernel = Core::System::GetInstance().Kernel(); - process->svc_access_mask.set(); - process->resource_limit = - kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION); process->Run(Memory::PROCESS_IMAGE_VADDR, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE);