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:
parent
d09fb82113
commit
002ae08bbd
|
@ -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