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.
This commit is contained in:
		| @@ -40,6 +40,13 @@ Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) { | |||||||
|     if (sizeof(FileAccessHeader) != file->ReadObject(&aci_file_access, aci_header.fah_offset)) |     if (sizeof(FileAccessHeader) != file->ReadObject(&aci_file_access, aci_header.fah_offset)) | ||||||
|         return Loader::ResultStatus::ErrorBadFileAccessHeader; |         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; |     return Loader::ResultStatus::Success; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -71,6 +78,10 @@ u64 ProgramMetadata::GetFilesystemPermissions() const { | |||||||
|     return aci_file_access.permissions; |     return aci_file_access.permissions; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | const ProgramMetadata::KernelCapabilityDescriptors& ProgramMetadata::GetKernelCapabilities() const { | ||||||
|  |     return aci_kernel_capabilities; | ||||||
|  | } | ||||||
|  |  | ||||||
| void ProgramMetadata::Print() const { | void ProgramMetadata::Print() const { | ||||||
|     LOG_DEBUG(Service_FS, "Magic:                  {:.4}", npdm_header.magic.data()); |     LOG_DEBUG(Service_FS, "Magic:                  {:.4}", npdm_header.magic.data()); | ||||||
|     LOG_DEBUG(Service_FS, "Main thread priority:   0x{:02X}", npdm_header.main_thread_priority); |     LOG_DEBUG(Service_FS, "Main thread priority:   0x{:02X}", npdm_header.main_thread_priority); | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include <array> | #include <array> | ||||||
|  | #include <vector> | ||||||
| #include "common/bit_field.h" | #include "common/bit_field.h" | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
| #include "common/swap.h" | #include "common/swap.h" | ||||||
| @@ -38,6 +39,8 @@ enum class ProgramFilePermission : u64 { | |||||||
|  */ |  */ | ||||||
| class ProgramMetadata { | class ProgramMetadata { | ||||||
| public: | public: | ||||||
|  |     using KernelCapabilityDescriptors = std::vector<u32>; | ||||||
|  |  | ||||||
|     ProgramMetadata(); |     ProgramMetadata(); | ||||||
|     ~ProgramMetadata(); |     ~ProgramMetadata(); | ||||||
|  |  | ||||||
| @@ -50,6 +53,7 @@ public: | |||||||
|     u32 GetMainThreadStackSize() const; |     u32 GetMainThreadStackSize() const; | ||||||
|     u64 GetTitleID() const; |     u64 GetTitleID() const; | ||||||
|     u64 GetFilesystemPermissions() const; |     u64 GetFilesystemPermissions() const; | ||||||
|  |     const KernelCapabilityDescriptors& GetKernelCapabilities() const; | ||||||
|  |  | ||||||
|     void Print() const; |     void Print() const; | ||||||
|  |  | ||||||
| @@ -154,6 +158,8 @@ private: | |||||||
|  |  | ||||||
|     FileAccessControl acid_file_access; |     FileAccessControl acid_file_access; | ||||||
|     FileAccessHeader aci_file_access; |     FileAccessHeader aci_file_access; | ||||||
|  |  | ||||||
|  |     KernelCapabilityDescriptors aci_kernel_capabilities; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| } // namespace FileSys | } // namespace FileSys | ||||||
|   | |||||||
| @@ -28,13 +28,11 @@ SharedPtr<Process> Process::Create(KernelCore& kernel, std::string&& name) { | |||||||
|     SharedPtr<Process> process(new Process(kernel)); |     SharedPtr<Process> process(new Process(kernel)); | ||||||
|  |  | ||||||
|     process->name = std::move(name); |     process->name = std::move(name); | ||||||
|     process->flags.raw = 0; |  | ||||||
|     process->flags.memory_region.Assign(MemoryRegion::APPLICATION); |  | ||||||
|     process->resource_limit = kernel.GetSystemResourceLimit(); |     process->resource_limit = kernel.GetSystemResourceLimit(); | ||||||
|     process->status = ProcessStatus::Created; |     process->status = ProcessStatus::Created; | ||||||
|     process->program_id = 0; |     process->program_id = 0; | ||||||
|     process->process_id = kernel.CreateNewProcessID(); |     process->process_id = kernel.CreateNewProcessID(); | ||||||
|     process->svc_access_mask.set(); |     process->capabilities.InitializeForMetadatalessProcess(); | ||||||
|  |  | ||||||
|     std::mt19937 rng(Settings::values.rng_seed.value_or(0)); |     std::mt19937 rng(Settings::values.rng_seed.value_or(0)); | ||||||
|     std::uniform_int_distribution<u64> distribution; |     std::uniform_int_distribution<u64> distribution; | ||||||
| @@ -64,83 +62,15 @@ ResultCode Process::ClearSignalState() { | |||||||
|     return RESULT_SUCCESS; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
|  |  | ||||||
| void Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) { | ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) { | ||||||
|     program_id = metadata.GetTitleID(); |     program_id = metadata.GetTitleID(); | ||||||
|     ideal_processor = metadata.GetMainThreadCore(); |     ideal_processor = metadata.GetMainThreadCore(); | ||||||
|     is_64bit_process = metadata.Is64BitProgram(); |     is_64bit_process = metadata.Is64BitProgram(); | ||||||
|  |  | ||||||
|     vm_manager.Reset(metadata.GetAddressSpaceType()); |     vm_manager.Reset(metadata.GetAddressSpaceType()); | ||||||
| } |  | ||||||
|  |  | ||||||
| void Process::ParseKernelCaps(const u32* kernel_caps, std::size_t len) { |     const auto& caps = metadata.GetKernelCapabilities(); | ||||||
|     for (std::size_t i = 0; i < len; ++i) { |     return capabilities.InitializeForUserProcess(caps.data(), caps.size(), vm_manager); | ||||||
|         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); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) { | void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) { | ||||||
|   | |||||||
| @@ -11,9 +11,9 @@ | |||||||
| #include <string> | #include <string> | ||||||
| #include <vector> | #include <vector> | ||||||
| #include <boost/container/static_vector.hpp> | #include <boost/container/static_vector.hpp> | ||||||
| #include "common/bit_field.h" |  | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
| #include "core/hle/kernel/handle_table.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/thread.h" | ||||||
| #include "core/hle/kernel/vm_manager.h" | #include "core/hle/kernel/vm_manager.h" | ||||||
| #include "core/hle/kernel/wait_object.h" | #include "core/hle/kernel/wait_object.h" | ||||||
| @@ -42,24 +42,6 @@ enum class MemoryRegion : u16 { | |||||||
|     BASE = 3, |     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. |  * 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. |     /// Gets the bitmask of allowed CPUs that this process' threads can run on. | ||||||
|     u32 GetAllowedProcessorMask() const { |     u64 GetAllowedProcessorMask() const { | ||||||
|         return allowed_processor_mask; |         return capabilities.GetCoreMask(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Gets the bitmask of allowed thread priorities. |     /// Gets the bitmask of allowed thread priorities. | ||||||
|     u32 GetAllowedThreadPriorityMask() const { |     u64 GetAllowedThreadPriorityMask() const { | ||||||
|         return allowed_thread_priority_mask; |         return capabilities.GetPriorityMask(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     u32 IsVirtualMemoryEnabled() const { |     u32 IsVirtualMemoryEnabled() const { | ||||||
| @@ -227,15 +209,12 @@ public: | |||||||
|      * Loads process-specifics configuration info with metadata provided |      * Loads process-specifics configuration info with metadata provided | ||||||
|      * by an executable. |      * 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); |     ResultCode 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); |  | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Applies address space changes and launches the process main thread. |      * Applies address space changes and launches the process main thread. | ||||||
| @@ -296,22 +275,8 @@ private: | |||||||
|     /// Resource limit descriptor for this process |     /// Resource limit descriptor for this process | ||||||
|     SharedPtr<ResourceLimit> resource_limit; |     SharedPtr<ResourceLimit> 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<AddressMapping, 8> 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. |     /// The default CPU for this process, threads are scheduled on this cpu by default. | ||||||
|     u8 ideal_processor = 0; |     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; |     u32 is_virtual_address_memory_enabled = 0; | ||||||
|  |  | ||||||
|     /// The Thread Local Storage area is allocated as processes create threads, |     /// 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. |     /// This vector will grow as more pages are allocated for new threads. | ||||||
|     std::vector<std::bitset<8>> tls_slots; |     std::vector<std::bitset<8>> tls_slots; | ||||||
|  |  | ||||||
|  |     /// Contains the parsed process capability descriptors. | ||||||
|  |     ProcessCapabilities capabilities; | ||||||
|  |  | ||||||
|     /// Whether or not this process is AArch64, or AArch32. |     /// Whether or not this process is AArch64, or AArch32. | ||||||
|     /// By default, we currently assume this is true, unless otherwise |     /// By default, we currently assume this is true, unless otherwise | ||||||
|     /// specified by metadata provided to the process during loading. |     /// specified by metadata provided to the process during loading. | ||||||
|   | |||||||
| @@ -129,7 +129,10 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(Kernel::Process& process) | |||||||
|         return ResultStatus::Error32BitISA; |         return ResultStatus::Error32BitISA; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     process.LoadFromMetadata(metadata); |     if (process.LoadFromMetadata(metadata).IsError()) { | ||||||
|  |         return ResultStatus::ErrorUnableToParseKernelMetadata; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     const FileSys::PatchManager pm(metadata.GetTitleID()); |     const FileSys::PatchManager pm(metadata.GetTitleID()); | ||||||
|  |  | ||||||
|     // Load NSO modules |     // Load NSO modules | ||||||
|   | |||||||
| @@ -93,7 +93,7 @@ std::string GetFileTypeString(FileType type) { | |||||||
|     return "unknown"; |     return "unknown"; | ||||||
| } | } | ||||||
|  |  | ||||||
| constexpr std::array<const char*, 60> RESULT_MESSAGES{ | constexpr std::array<const char*, 62> RESULT_MESSAGES{ | ||||||
|     "The operation completed successfully.", |     "The operation completed successfully.", | ||||||
|     "The loader requested to load is already loaded.", |     "The loader requested to load is already loaded.", | ||||||
|     "The operation is not implemented.", |     "The operation is not implemented.", | ||||||
| @@ -103,6 +103,7 @@ constexpr std::array<const char*, 60> RESULT_MESSAGES{ | |||||||
|     "The NPDM has a bad ACI header,", |     "The NPDM has a bad ACI header,", | ||||||
|     "The NPDM file has a bad file access control.", |     "The NPDM file has a bad file access control.", | ||||||
|     "The NPDM has a bad file access header.", |     "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 a bad header.", | ||||||
|     "The PFS/HFS partition has incorrect size as determined by the header.", |     "The PFS/HFS partition has incorrect size as determined by the header.", | ||||||
|     "The NCA file has a bad header.", |     "The NCA file has a bad header.", | ||||||
| @@ -125,6 +126,7 @@ constexpr std::array<const char*, 60> RESULT_MESSAGES{ | |||||||
|     "The file could not be found or does not exist.", |     "The file could not be found or does not exist.", | ||||||
|     "The game is missing a program metadata file (main.npdm).", |     "The game is missing a program metadata file (main.npdm).", | ||||||
|     "The game uses the currently-unimplemented 32-bit architecture.", |     "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 RomFS could not be found.", | ||||||
|     "The ELF file has incorrect size as determined by the header.", |     "The ELF file has incorrect size as determined by the header.", | ||||||
|     "There was a general error loading the NRO into emulated memory.", |     "There was a general error loading the NRO into emulated memory.", | ||||||
|   | |||||||
| @@ -67,6 +67,7 @@ enum class ResultStatus : u16 { | |||||||
|     ErrorBadACIHeader, |     ErrorBadACIHeader, | ||||||
|     ErrorBadFileAccessControl, |     ErrorBadFileAccessControl, | ||||||
|     ErrorBadFileAccessHeader, |     ErrorBadFileAccessHeader, | ||||||
|  |     ErrorBadKernelCapabilityDescriptors, | ||||||
|     ErrorBadPFSHeader, |     ErrorBadPFSHeader, | ||||||
|     ErrorIncorrectPFSFileSize, |     ErrorIncorrectPFSFileSize, | ||||||
|     ErrorBadNCAHeader, |     ErrorBadNCAHeader, | ||||||
| @@ -89,6 +90,7 @@ enum class ResultStatus : u16 { | |||||||
|     ErrorNullFile, |     ErrorNullFile, | ||||||
|     ErrorMissingNPDM, |     ErrorMissingNPDM, | ||||||
|     Error32BitISA, |     Error32BitISA, | ||||||
|  |     ErrorUnableToParseKernelMetadata, | ||||||
|     ErrorNoRomFS, |     ErrorNoRomFS, | ||||||
|     ErrorIncorrectELFFileSize, |     ErrorIncorrectELFFileSize, | ||||||
|     ErrorLoadingNRO, |     ErrorLoadingNRO, | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user