From 002ae08bbd3e5e851d8a682203462efbcf59e3dd Mon Sep 17 00:00:00 2001 From: Lioncash Date: Wed, 19 Dec 2018 23:50:20 -0500 Subject: [PATCH] kernel/process: Hook up the process capability parser to the process itself While we're at it, we can also toss out the leftover capability parsing from Citra. --- src/core/file_sys/program_metadata.cpp | 11 +++ src/core/file_sys/program_metadata.h | 6 ++ src/core/hle/kernel/process.cpp | 80 ++----------------- src/core/hle/kernel/process.h | 58 +++----------- .../loader/deconstructed_rom_directory.cpp | 5 +- src/core/loader/loader.cpp | 4 +- src/core/loader/loader.h | 2 + 7 files changed, 44 insertions(+), 122 deletions(-) diff --git a/src/core/file_sys/program_metadata.cpp b/src/core/file_sys/program_metadata.cpp index 8903ed1d3..e90c8c2de 100644 --- a/src/core/file_sys/program_metadata.cpp +++ b/src/core/file_sys/program_metadata.cpp @@ -40,6 +40,13 @@ Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) { if (sizeof(FileAccessHeader) != file->ReadObject(&aci_file_access, aci_header.fah_offset)) return Loader::ResultStatus::ErrorBadFileAccessHeader; + aci_kernel_capabilities.resize(aci_header.kac_size / sizeof(u32)); + const u64 read_size = aci_header.kac_size; + const u64 read_offset = npdm_header.aci_offset + aci_header.kac_offset; + if (file->ReadBytes(aci_kernel_capabilities.data(), read_size, read_offset) != read_size) { + return Loader::ResultStatus::ErrorBadKernelCapabilityDescriptors; + } + return Loader::ResultStatus::Success; } @@ -71,6 +78,10 @@ u64 ProgramMetadata::GetFilesystemPermissions() const { return aci_file_access.permissions; } +const ProgramMetadata::KernelCapabilityDescriptors& ProgramMetadata::GetKernelCapabilities() const { + return aci_kernel_capabilities; +} + void ProgramMetadata::Print() const { LOG_DEBUG(Service_FS, "Magic: {:.4}", npdm_header.magic.data()); LOG_DEBUG(Service_FS, "Main thread priority: 0x{:02X}", npdm_header.main_thread_priority); diff --git a/src/core/file_sys/program_metadata.h b/src/core/file_sys/program_metadata.h index e4470d6f0..0033ba347 100644 --- a/src/core/file_sys/program_metadata.h +++ b/src/core/file_sys/program_metadata.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include "common/bit_field.h" #include "common/common_types.h" #include "common/swap.h" @@ -38,6 +39,8 @@ enum class ProgramFilePermission : u64 { */ class ProgramMetadata { public: + using KernelCapabilityDescriptors = std::vector; + ProgramMetadata(); ~ProgramMetadata(); @@ -50,6 +53,7 @@ public: u32 GetMainThreadStackSize() const; u64 GetTitleID() const; u64 GetFilesystemPermissions() const; + const KernelCapabilityDescriptors& GetKernelCapabilities() const; void Print() const; @@ -154,6 +158,8 @@ private: FileAccessControl acid_file_access; FileAccessHeader aci_file_access; + + KernelCapabilityDescriptors aci_kernel_capabilities; }; } // namespace FileSys diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 5356a4a3f..4f209a979 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -28,13 +28,11 @@ SharedPtr Process::Create(KernelCore& kernel, std::string&& name) { SharedPtr process(new Process(kernel)); process->name = std::move(name); - process->flags.raw = 0; - process->flags.memory_region.Assign(MemoryRegion::APPLICATION); process->resource_limit = kernel.GetSystemResourceLimit(); process->status = ProcessStatus::Created; process->program_id = 0; process->process_id = kernel.CreateNewProcessID(); - process->svc_access_mask.set(); + process->capabilities.InitializeForMetadatalessProcess(); std::mt19937 rng(Settings::values.rng_seed.value_or(0)); std::uniform_int_distribution distribution; @@ -64,83 +62,15 @@ ResultCode Process::ClearSignalState() { return RESULT_SUCCESS; } -void Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) { +ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) { program_id = metadata.GetTitleID(); ideal_processor = metadata.GetMainThreadCore(); is_64bit_process = metadata.Is64BitProgram(); + 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]; - u32 type = descriptor >> 20; - - if (descriptor == 0xFFFFFFFF) { - // Unused descriptor entry - continue; - } else if ((type & 0xF00) == 0xE00) { // 0x0FFF - // Allowed interrupts list - LOG_WARNING(Loader, "ExHeader allowed interrupts list ignored"); - } else if ((type & 0xF80) == 0xF00) { // 0x07FF - // Allowed syscalls mask - unsigned int index = ((descriptor >> 24) & 7) * 24; - u32 bits = descriptor & 0xFFFFFF; - - while (bits && index < svc_access_mask.size()) { - svc_access_mask.set(index, bits & 1); - ++index; - bits >>= 1; - } - } else if ((type & 0xFF0) == 0xFE0) { // 0x00FF - // Handle table size - handle_table_size = descriptor & 0x3FF; - } else if ((type & 0xFF8) == 0xFF0) { // 0x007F - // Misc. flags - flags.raw = descriptor & 0xFFFF; - } else if ((type & 0xFFE) == 0xFF8) { // 0x001F - // Mapped memory range - if (i + 1 >= len || ((kernel_caps[i + 1] >> 20) & 0xFFE) != 0xFF8) { - LOG_WARNING(Loader, "Incomplete exheader memory range descriptor ignored."); - continue; - } - u32 end_desc = kernel_caps[i + 1]; - ++i; // Skip over the second descriptor on the next iteration - - AddressMapping mapping; - mapping.address = descriptor << 12; - VAddr end_address = end_desc << 12; - - if (mapping.address < end_address) { - mapping.size = end_address - mapping.address; - } else { - mapping.size = 0; - } - - mapping.read_only = (descriptor & (1 << 20)) != 0; - mapping.unk_flag = (end_desc & (1 << 20)) != 0; - - address_mappings.push_back(mapping); - } else if ((type & 0xFFF) == 0xFFE) { // 0x000F - // Mapped memory page - AddressMapping mapping; - mapping.address = descriptor << 12; - mapping.size = Memory::PAGE_SIZE; - mapping.read_only = false; - mapping.unk_flag = false; - - address_mappings.push_back(mapping); - } else if ((type & 0xFE0) == 0xFC0) { // 0x01FF - // Kernel version - kernel_version = descriptor & 0xFFFF; - - int minor = kernel_version & 0xFF; - int major = (kernel_version >> 8) & 0xFF; - LOG_INFO(Loader, "ExHeader kernel version: {}.{}", major, minor); - } else { - LOG_ERROR(Loader, "Unhandled kernel caps descriptor: 0x{:08X}", descriptor); - } - } + const auto& caps = metadata.GetKernelCapabilities(); + return capabilities.InitializeForUserProcess(caps.data(), caps.size(), vm_manager); } void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) { diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 459eedfa6..f6fb72770 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -11,9 +11,9 @@ #include #include #include -#include "common/bit_field.h" #include "common/common_types.h" #include "core/hle/kernel/handle_table.h" +#include "core/hle/kernel/process_capability.h" #include "core/hle/kernel/thread.h" #include "core/hle/kernel/vm_manager.h" #include "core/hle/kernel/wait_object.h" @@ -42,24 +42,6 @@ enum class MemoryRegion : u16 { BASE = 3, }; -union ProcessFlags { - u16 raw; - - BitField<0, 1, u16> - allow_debug; ///< Allows other processes to attach to and debug this process. - BitField<1, 1, u16> force_debug; ///< Allows this process to attach to processes even if they - /// don't have allow_debug set. - BitField<2, 1, u16> allow_nonalphanum; - BitField<3, 1, u16> shared_page_writable; ///< Shared page is mapped with write permissions. - BitField<4, 1, u16> privileged_priority; ///< Can use priority levels higher than 24. - BitField<5, 1, u16> allow_main_args; - BitField<6, 1, u16> shared_device_mem; - BitField<7, 1, u16> runnable_on_sleep; - BitField<8, 4, MemoryRegion> - memory_region; ///< Default region for memory allocations for this process - BitField<12, 1, u16> loaded_high; ///< Application loaded high (not at 0x00100000). -}; - /** * Indicates the status of a Process instance. * @@ -180,13 +162,13 @@ public: } /// Gets the bitmask of allowed CPUs that this process' threads can run on. - u32 GetAllowedProcessorMask() const { - return allowed_processor_mask; + u64 GetAllowedProcessorMask() const { + return capabilities.GetCoreMask(); } /// Gets the bitmask of allowed thread priorities. - u32 GetAllowedThreadPriorityMask() const { - return allowed_thread_priority_mask; + u64 GetAllowedThreadPriorityMask() const { + return capabilities.GetPriorityMask(); } u32 IsVirtualMemoryEnabled() const { @@ -227,15 +209,12 @@ public: * Loads process-specifics configuration info with metadata provided * by an executable. * - * @param metadata The provided metadata to load process specific info. + * @param metadata The provided metadata to load process specific info from. + * + * @returns RESULT_SUCCESS if all relevant metadata was able to be + * loaded and parsed. Otherwise, an error code is returned. */ - void LoadFromMetadata(const FileSys::ProgramMetadata& metadata); - - /** - * Parses a list of kernel capability descriptors (as found in the ExHeader) and applies them - * to this process. - */ - void ParseKernelCaps(const u32* kernel_caps, std::size_t len); + ResultCode LoadFromMetadata(const FileSys::ProgramMetadata& metadata); /** * Applies address space changes and launches the process main thread. @@ -296,22 +275,8 @@ private: /// Resource limit descriptor for this process SharedPtr resource_limit; - /// The process may only call SVCs which have the corresponding bit set. - std::bitset<0x80> svc_access_mask; - /// Maximum size of the handle table for the process. - u32 handle_table_size = 0x200; - /// Special memory ranges mapped into this processes address space. This is used to give - /// processes access to specific I/O regions and device memory. - boost::container::static_vector address_mappings; - ProcessFlags flags; - /// Kernel compatibility version for this process - u16 kernel_version = 0; /// The default CPU for this process, threads are scheduled on this cpu by default. u8 ideal_processor = 0; - /// Bitmask of allowed CPUs that this process' threads can run on. TODO(Subv): Actually parse - /// this value from the process header. - u32 allowed_processor_mask = THREADPROCESSORID_DEFAULT_MASK; - u32 allowed_thread_priority_mask = 0xFFFFFFFF; u32 is_virtual_address_memory_enabled = 0; /// The Thread Local Storage area is allocated as processes create threads, @@ -321,6 +286,9 @@ private: /// This vector will grow as more pages are allocated for new threads. std::vector> tls_slots; + /// Contains the parsed process capability descriptors. + ProcessCapabilities capabilities; + /// Whether or not this process is AArch64, or AArch32. /// By default, we currently assume this is true, unless otherwise /// specified by metadata provided to the process during loading. diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index ac04d72d7..07aa7a1cd 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -129,7 +129,10 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(Kernel::Process& process) return ResultStatus::Error32BitISA; } - process.LoadFromMetadata(metadata); + if (process.LoadFromMetadata(metadata).IsError()) { + return ResultStatus::ErrorUnableToParseKernelMetadata; + } + const FileSys::PatchManager pm(metadata.GetTitleID()); // Load NSO modules diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 9cd0b0ccd..d8cc30959 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp @@ -93,7 +93,7 @@ std::string GetFileTypeString(FileType type) { return "unknown"; } -constexpr std::array RESULT_MESSAGES{ +constexpr std::array RESULT_MESSAGES{ "The operation completed successfully.", "The loader requested to load is already loaded.", "The operation is not implemented.", @@ -103,6 +103,7 @@ constexpr std::array RESULT_MESSAGES{ "The NPDM has a bad ACI header,", "The NPDM file has a bad file access control.", "The NPDM has a bad file access header.", + "The NPDM has bad kernel capability descriptors.", "The PFS/HFS partition has a bad header.", "The PFS/HFS partition has incorrect size as determined by the header.", "The NCA file has a bad header.", @@ -125,6 +126,7 @@ constexpr std::array RESULT_MESSAGES{ "The file could not be found or does not exist.", "The game is missing a program metadata file (main.npdm).", "The game uses the currently-unimplemented 32-bit architecture.", + "Unable to completely parse the kernel metadata when loading the emulated process", "The RomFS could not be found.", "The ELF file has incorrect size as determined by the header.", "There was a general error loading the NRO into emulated memory.", diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index 0838e303b..a39cb812d 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h @@ -67,6 +67,7 @@ enum class ResultStatus : u16 { ErrorBadACIHeader, ErrorBadFileAccessControl, ErrorBadFileAccessHeader, + ErrorBadKernelCapabilityDescriptors, ErrorBadPFSHeader, ErrorIncorrectPFSFileSize, ErrorBadNCAHeader, @@ -89,6 +90,7 @@ enum class ResultStatus : u16 { ErrorNullFile, ErrorMissingNPDM, Error32BitISA, + ErrorUnableToParseKernelMetadata, ErrorNoRomFS, ErrorIncorrectELFFileSize, ErrorLoadingNRO,