From cf9d6c6f526fffb2bf414ff774c5d0281a73ecf4 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sat, 29 Sep 2018 18:47:00 -0400 Subject: kernel/process: Make data member variables private Makes the public interface consistent in terms of how accesses are done on a process object. It also makes it slightly nicer to reason about the logic of the process class, as we don't want to expose everything to external code. --- src/core/hle/kernel/process.h | 97 +++++++++++++++++++++++++---------- src/core/hle/kernel/scheduler.cpp | 2 +- src/core/hle/kernel/shared_memory.cpp | 14 ++--- src/core/hle/kernel/svc.cpp | 30 +++++------ src/core/hle/kernel/thread.cpp | 4 +- 5 files changed, 96 insertions(+), 51 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index adb03c228..2dfb88fa9 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -135,6 +135,16 @@ public: return HANDLE_TYPE; } + /// Gets a reference to the process' memory manager. + Kernel::VMManager& VMManager() { + return vm_manager; + } + + /// Gets a const reference to the process' memory manager. + const Kernel::VMManager& VMManager() const { + return vm_manager; + } + /// Gets the current status of the process ProcessStatus GetStatus() const { return status; @@ -145,6 +155,40 @@ public: return process_id; } + /// Gets the title ID corresponding to this process. + u64 GetTitleID() const { + return program_id; + } + + /// Gets the resource limit descriptor for this process + ResourceLimit& GetResourceLimit() { + return *resource_limit; + } + + /// Gets the resource limit descriptor for this process + const ResourceLimit& GetResourceLimit() const { + return *resource_limit; + } + + /// Gets the default CPU ID for this process + u8 GetDefaultProcessorID() const { + return ideal_processor; + } + + /// Gets the bitmask of allowed CPUs that this process' threads can run on. + u32 GetAllowedProcessorMask() const { + return allowed_processor_mask; + } + + /// Gets the bitmask of allowed thread priorities. + u32 GetAllowedThreadPriorityMask() const { + return allowed_thread_priority_mask; + } + + u32 IsVirtualMemoryEnabled() const { + return is_virtual_address_memory_enabled; + } + /** * Loads process-specifics configuration info with metadata provided * by an executable. @@ -153,30 +197,6 @@ public: */ void LoadFromMetadata(const FileSys::ProgramMetadata& metadata); - /// Title ID corresponding to the process - u64 program_id; - - /// 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. - unsigned int 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; - /** * Parses a list of kernel capability descriptors (as found in the ExHeader) and applies them * to this process. @@ -212,18 +232,43 @@ public: ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size); - VMManager vm_manager; - private: explicit Process(KernelCore& kernel); ~Process() override; + /// Memory manager for this process. + Kernel::VMManager vm_manager; + /// Current status of the process ProcessStatus status; /// The ID of this process u32 process_id = 0; + /// Title ID corresponding to the process + u64 program_id; + + /// 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; + // Memory used to back the allocations in the regular heap. A single vector is used to cover // the entire virtual address space extents that bound the allocations, including any holes. // This makes deallocation and reallocation of holes fast and keeps process memory contiguous diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 9faf903cf..1e82cfffb 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -88,7 +88,7 @@ void Scheduler::SwitchContext(Thread* new_thread) { if (previous_process != current_thread->owner_process) { Core::CurrentProcess() = current_thread->owner_process; - SetCurrentPageTable(&Core::CurrentProcess()->vm_manager.page_table); + SetCurrentPageTable(&Core::CurrentProcess()->VMManager().page_table); } cpu_core.LoadContext(new_thread->context); diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index 9b78c8cb5..d061e6155 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp @@ -35,11 +35,11 @@ SharedPtr SharedMemory::Create(KernelCore& kernel, SharedPtrvm_manager.RefreshMemoryBlockMappings( + Core::CurrentProcess()->VMManager().RefreshMemoryBlockMappings( shared_memory->backing_block.get()); } } else { - auto& vm_manager = shared_memory->owner_process->vm_manager; + auto& vm_manager = shared_memory->owner_process->VMManager(); // The memory is already available and mapped in the owner process. auto vma = vm_manager.FindVMA(address); @@ -73,7 +73,7 @@ SharedPtr SharedMemory::CreateForApplet( shared_memory->backing_block = std::move(heap_block); shared_memory->backing_block_offset = offset; shared_memory->base_address = - kernel.CurrentProcess()->vm_manager.GetHeapRegionBaseAddress() + offset; + kernel.CurrentProcess()->VMManager().GetHeapRegionBaseAddress() + offset; return shared_memory; } @@ -107,7 +107,7 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi VAddr target_address = address; // Map the memory block into the target process - auto result = target_process->vm_manager.MapMemoryBlock( + auto result = target_process->VMManager().MapMemoryBlock( target_address, backing_block, backing_block_offset, size, MemoryState::Shared); if (result.Failed()) { LOG_ERROR( @@ -117,14 +117,14 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi return result.Code(); } - return target_process->vm_manager.ReprotectRange(target_address, size, - ConvertPermissions(permissions)); + return target_process->VMManager().ReprotectRange(target_address, size, + ConvertPermissions(permissions)); } ResultCode SharedMemory::Unmap(Process* target_process, VAddr address) { // TODO(Subv): Verify what happens if the application tries to unmap an address that is not // mapped to a SharedMemory. - return target_process->vm_manager.UnmapRange(address, size); + return target_process->VMManager().UnmapRange(address, size); } VMAPermission SharedMemory::ConvertPermissions(MemoryPermission permission) { diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 44bbaf0c8..b76280456 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -51,7 +51,7 @@ static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) { } auto& process = *Core::CurrentProcess(); - const VAddr heap_base = process.vm_manager.GetHeapRegionBaseAddress(); + const VAddr heap_base = process.VMManager().GetHeapRegionBaseAddress(); CASCADE_RESULT(*heap_addr, process.HeapAllocate(heap_base, heap_size, VMAPermission::ReadWrite)); return RESULT_SUCCESS; @@ -327,14 +327,14 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) info_sub_id, handle); const auto& current_process = Core::CurrentProcess(); - const auto& vm_manager = current_process->vm_manager; + const auto& vm_manager = current_process->VMManager(); switch (static_cast(info_id)) { case GetInfoType::AllowedCpuIdBitmask: - *result = current_process->allowed_processor_mask; + *result = current_process->GetAllowedProcessorMask(); break; case GetInfoType::AllowedThreadPrioBitmask: - *result = current_process->allowed_thread_priority_mask; + *result = current_process->GetAllowedThreadPriorityMask(); break; case GetInfoType::MapRegionBaseAddr: *result = vm_manager.GetMapRegionBaseAddress(); @@ -386,10 +386,10 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) *result = vm_manager.GetNewMapRegionSize(); break; case GetInfoType::IsVirtualAddressMemoryEnabled: - *result = current_process->is_virtual_address_memory_enabled; + *result = current_process->IsVirtualMemoryEnabled(); break; case GetInfoType::TitleId: - *result = current_process->program_id; + *result = current_process->GetTitleID(); break; case GetInfoType::PrivilegedProcessId: LOG_WARNING(Kernel_SVC, @@ -444,8 +444,8 @@ static ResultCode SetThreadPriority(Handle handle, u32 priority) { // Note: The kernel uses the current process's resource limit instead of // the one from the thread owner's resource limit. - SharedPtr& resource_limit = Core::CurrentProcess()->resource_limit; - if (resource_limit->GetMaxResourceValue(ResourceType::Priority) > priority) { + const ResourceLimit& resource_limit = Core::CurrentProcess()->GetResourceLimit(); + if (resource_limit.GetMaxResourceValue(ResourceType::Priority) > priority) { return ERR_NOT_AUTHORIZED; } @@ -519,9 +519,9 @@ static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_i if (!process) { return ERR_INVALID_HANDLE; } - auto vma = process->vm_manager.FindVMA(addr); + auto vma = process->VMManager().FindVMA(addr); memory_info->attributes = 0; - if (vma == Core::CurrentProcess()->vm_manager.vma_map.end()) { + if (vma == Core::CurrentProcess()->VMManager().vma_map.end()) { memory_info->base_address = 0; memory_info->permission = static_cast(VMAPermission::None); memory_info->size = 0; @@ -568,14 +568,14 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V return ERR_INVALID_THREAD_PRIORITY; } - SharedPtr& resource_limit = Core::CurrentProcess()->resource_limit; - if (resource_limit->GetMaxResourceValue(ResourceType::Priority) > priority) { + const ResourceLimit& resource_limit = Core::CurrentProcess()->GetResourceLimit(); + if (resource_limit.GetMaxResourceValue(ResourceType::Priority) > priority) { return ERR_NOT_AUTHORIZED; } if (processor_id == THREADPROCESSORID_DEFAULT) { // Set the target CPU to the one specified in the process' exheader. - processor_id = Core::CurrentProcess()->ideal_processor; + processor_id = Core::CurrentProcess()->GetDefaultProcessorID(); ASSERT(processor_id != THREADPROCESSORID_DEFAULT); } @@ -902,10 +902,10 @@ static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) { } if (core == static_cast(THREADPROCESSORID_DEFAULT)) { - ASSERT(thread->owner_process->ideal_processor != + ASSERT(thread->owner_process->GetDefaultProcessorID() != static_cast(THREADPROCESSORID_DEFAULT)); // Set the target CPU to the one specified in the process' exheader. - core = thread->owner_process->ideal_processor; + core = thread->owner_process->GetDefaultProcessorID(); mask = 1ull << core; } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 064ed908d..b5c16cfbb 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -259,10 +259,10 @@ void Thread::BoostPriority(u32 priority) { SharedPtr SetupMainThread(KernelCore& kernel, VAddr entry_point, u32 priority, Process& owner_process) { // Setup page table so we can write to memory - SetCurrentPageTable(&owner_process.vm_manager.page_table); + SetCurrentPageTable(&owner_process.VMManager().page_table); // Initialize new "main" thread - const VAddr stack_top = owner_process.vm_manager.GetTLSIORegionEndAddress(); + const VAddr stack_top = owner_process.VMManager().GetTLSIORegionEndAddress(); auto thread_res = Thread::Create(kernel, "main", entry_point, priority, 0, THREADPROCESSORID_0, stack_top, &owner_process); -- cgit v1.2.3 From dccfe193a9caf5ce7aa75489f1722fee2a2073dd Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sat, 29 Sep 2018 19:13:46 -0400 Subject: kernel/process: Add a data member to determine if a process is 64-bit or not. This will be necessary for the implementation of svcGetThreadContext(), as the kernel checks whether or not the process that owns the thread that has it context being retrieved is a 64-bit or 32-bit process. If the process is 32-bit, then the upper 15 general-purpose registers and upper 16 vector registers are cleared to zero (as AArch32 only has 15 GPRs and 16 128-bit vector registers. not 31 general-purpose registers and 32 128-bit vector registers like AArch64). --- src/core/hle/kernel/process.cpp | 1 + src/core/hle/kernel/process.h | 10 ++++++++++ 2 files changed, 11 insertions(+) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index a8e3098ca..dc9fc8470 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -47,6 +47,7 @@ SharedPtr Process::Create(KernelCore& kernel, std::string&& name) { void Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) { program_id = metadata.GetTitleID(); + is_64bit_process = metadata.Is64BitProgram(); vm_manager.Reset(metadata.GetAddressSpaceType()); } diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 2dfb88fa9..590e0c73d 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -189,6 +189,11 @@ public: return is_virtual_address_memory_enabled; } + /// Whether this process is an AArch64 or AArch32 process. + bool Is64BitProcess() const { + return is_64bit_process; + } + /** * Loads process-specifics configuration info with metadata provided * by an executable. @@ -287,6 +292,11 @@ private: /// This vector will grow as more pages are allocated for new threads. std::vector> tls_slots; + /// 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. + bool is_64bit_process = true; + std::string name; }; -- cgit v1.2.3 From 541c5507538137b9cc5fd0579221aaecf59a89b1 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sat, 29 Sep 2018 19:58:21 -0400 Subject: kernel/svc: Implement svcGetThreadContext() Now that we have all of the rearranging and proper structure sizes in place, it's fairly trivial to implement svcGetThreadContext(). In the 64-bit case we can more or less just write out the context as is, minus some minor value sanitizing. In the 32-bit case we'll need to clear out the registers that wouldn't normally be accessible from a 32-bit AArch32 exectuable (or process). --- src/core/hle/kernel/errors.h | 2 ++ src/core/hle/kernel/svc.cpp | 32 ++++++++++++++++++++++++++++++-- src/core/hle/kernel/svc_wrap.h | 5 +++++ 3 files changed, 37 insertions(+), 2 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/errors.h b/src/core/hle/kernel/errors.h index 8c2be2681..e5fa67ae8 100644 --- a/src/core/hle/kernel/errors.h +++ b/src/core/hle/kernel/errors.h @@ -31,6 +31,7 @@ enum { TooLarge = 119, InvalidEnumValue = 120, NoSuchEntry = 121, + AlreadyRegistered = 122, InvalidState = 125, ResourceLimitExceeded = 132, }; @@ -58,6 +59,7 @@ constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS(ErrorModule::Kernel, constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle); constexpr ResultCode ERR_INVALID_PROCESSOR_ID(ErrorModule::Kernel, ErrCodes::InvalidProcessorId); constexpr ResultCode ERR_INVALID_SIZE(ErrorModule::Kernel, ErrCodes::InvalidSize); +constexpr ResultCode ERR_ALREADY_REGISTERED(ErrorModule::Kernel, ErrCodes::AlreadyRegistered); constexpr ResultCode ERR_INVALID_STATE(ErrorModule::Kernel, ErrCodes::InvalidState); constexpr ResultCode ERR_INVALID_THREAD_PRIORITY(ErrorModule::Kernel, ErrCodes::InvalidThreadPriority); diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index b76280456..1cdaa740a 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -415,8 +415,36 @@ static ResultCode SetThreadActivity(Handle handle, u32 unknown) { } /// Gets the thread context -static ResultCode GetThreadContext(Handle handle, VAddr addr) { - LOG_WARNING(Kernel_SVC, "(STUBBED) called, handle=0x{:08X}, addr=0x{:X}", handle, addr); +static ResultCode GetThreadContext(VAddr thread_context, Handle handle) { + LOG_DEBUG(Kernel_SVC, "called, context=0x{:08X}, thread=0x{:X}", thread_context, handle); + + auto& kernel = Core::System::GetInstance().Kernel(); + const SharedPtr thread = kernel.HandleTable().Get(handle); + if (!thread) { + return ERR_INVALID_HANDLE; + } + + const auto current_process = Core::CurrentProcess(); + if (thread->owner_process != current_process) { + return ERR_INVALID_HANDLE; + } + + if (thread == GetCurrentThread()) { + return ERR_ALREADY_REGISTERED; + } + + Core::ARM_Interface::ThreadContext ctx = thread->context; + // Mask away mode bits, interrupt bits, IL bit, and other reserved bits. + ctx.pstate &= 0xFF0FFE20; + + // If 64-bit, we can just write the context registers directly and we're good. + // However, if 32-bit, we have to ensure some registers are zeroed out. + if (!current_process->Is64BitProcess()) { + std::fill(ctx.cpu_registers.begin() + 15, ctx.cpu_registers.end(), 0); + std::fill(ctx.vector_registers.begin() + 16, ctx.vector_registers.end(), u128{}); + } + + Memory::WriteBlock(thread_context, &ctx, sizeof(ctx)); return RESULT_SUCCESS; } diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index fea9ba5ea..22712e64f 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h @@ -64,6 +64,11 @@ void SvcWrap() { FuncReturn(func(Param(0), (s32)Param(1)).raw); } +template +void SvcWrap() { + FuncReturn(func(Param(0), static_cast(Param(1))).raw); +} + template void SvcWrap() { u64 param_1 = 0; -- cgit v1.2.3