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:
Lioncash 2018-12-19 23:50:20 -05:00
parent d09fb82113
commit 002ae08bbd
7 changed files with 44 additions and 122 deletions

View File

@ -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);

View File

@ -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

View File

@ -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) {

View File

@ -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.

View File

@ -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

View File

@ -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.",

View File

@ -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,