forked from eden-emu/eden
		
	kernel: update KProcess
This commit is contained in:
		
							parent
							
								
									d0ab5211a1
								
							
						
					
					
						commit
						62e106dbe8
					
				
					 39 changed files with 2004 additions and 1209 deletions
				
			
		|  | @ -86,9 +86,9 @@ void ARM_Interface::SymbolicateBacktrace(Core::System& system, std::vector<Backt | |||
| 
 | ||||
|     std::map<std::string, Symbols::Symbols> symbols; | ||||
|     for (const auto& module : modules) { | ||||
|         symbols.insert_or_assign( | ||||
|             module.second, Symbols::GetSymbols(module.first, system.ApplicationMemory(), | ||||
|                                                system.ApplicationProcess()->Is64BitProcess())); | ||||
|         symbols.insert_or_assign(module.second, | ||||
|                                  Symbols::GetSymbols(module.first, system.ApplicationMemory(), | ||||
|                                                      system.ApplicationProcess()->Is64Bit())); | ||||
|     } | ||||
| 
 | ||||
|     for (auto& entry : out) { | ||||
|  |  | |||
|  | @ -309,16 +309,8 @@ struct System::Impl { | |||
| 
 | ||||
|         telemetry_session->AddInitialInfo(*app_loader, fs_controller, *content_provider); | ||||
| 
 | ||||
|         // Create a resource limit for the process.
 | ||||
|         const auto physical_memory_size = | ||||
|             kernel.MemoryManager().GetSize(Kernel::KMemoryManager::Pool::Application); | ||||
|         auto* resource_limit = Kernel::CreateResourceLimitForProcess(system, physical_memory_size); | ||||
| 
 | ||||
|         // Create the process.
 | ||||
|         auto main_process = Kernel::KProcess::Create(system.Kernel()); | ||||
|         ASSERT(Kernel::KProcess::Initialize(main_process, system, "main", | ||||
|                                             Kernel::KProcess::ProcessType::Userland, resource_limit) | ||||
|                    .IsSuccess()); | ||||
|         Kernel::KProcess::Register(system.Kernel(), main_process); | ||||
|         kernel.MakeApplicationProcess(main_process); | ||||
|         const auto [load_result, load_parameters] = app_loader->Load(*main_process, system); | ||||
|  |  | |||
|  | @ -258,20 +258,20 @@ private: | |||
|         Kernel::KScopedSchedulerLock sl{system.Kernel()}; | ||||
| 
 | ||||
|         // Put all threads to sleep on next scheduler round.
 | ||||
|         for (auto* thread : ThreadList()) { | ||||
|             thread->RequestSuspend(Kernel::SuspendType::Debug); | ||||
|         for (auto& thread : ThreadList()) { | ||||
|             thread.RequestSuspend(Kernel::SuspendType::Debug); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void ResumeEmulation(Kernel::KThread* except = nullptr) { | ||||
|         // Wake up all threads.
 | ||||
|         for (auto* thread : ThreadList()) { | ||||
|             if (thread == except) { | ||||
|         for (auto& thread : ThreadList()) { | ||||
|             if (std::addressof(thread) == except) { | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             thread->SetStepState(Kernel::StepState::NotStepping); | ||||
|             thread->Resume(Kernel::SuspendType::Debug); | ||||
|             thread.SetStepState(Kernel::StepState::NotStepping); | ||||
|             thread.Resume(Kernel::SuspendType::Debug); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -283,13 +283,17 @@ private: | |||
|     } | ||||
| 
 | ||||
|     void UpdateActiveThread() { | ||||
|         const auto& threads{ThreadList()}; | ||||
|         if (std::find(threads.begin(), threads.end(), state->active_thread) == threads.end()) { | ||||
|             state->active_thread = threads.front(); | ||||
|         auto& threads{ThreadList()}; | ||||
|         for (auto& thread : threads) { | ||||
|             if (std::addressof(thread) == state->active_thread) { | ||||
|                 // Thread is still alive, no need to update.
 | ||||
|                 return; | ||||
|             } | ||||
|         } | ||||
|         state->active_thread = std::addressof(threads.front()); | ||||
|     } | ||||
| 
 | ||||
|     const std::list<Kernel::KThread*>& ThreadList() { | ||||
|     Kernel::KProcess::ThreadList& ThreadList() { | ||||
|         return system.ApplicationProcess()->GetThreadList(); | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -109,7 +109,7 @@ static std::string EscapeXML(std::string_view data) { | |||
| 
 | ||||
| GDBStub::GDBStub(DebuggerBackend& backend_, Core::System& system_) | ||||
|     : DebuggerFrontend(backend_), system{system_} { | ||||
|     if (system.ApplicationProcess()->Is64BitProcess()) { | ||||
|     if (system.ApplicationProcess()->Is64Bit()) { | ||||
|         arch = std::make_unique<GDBStubA64>(); | ||||
|     } else { | ||||
|         arch = std::make_unique<GDBStubA32>(); | ||||
|  | @ -446,10 +446,10 @@ void GDBStub::HandleBreakpointRemove(std::string_view command) { | |||
| // See osdbg_thread_local_region.os.horizon.hpp and osdbg_thread_type.os.horizon.hpp
 | ||||
| 
 | ||||
| static std::optional<std::string> GetNameFromThreadType32(Core::Memory::Memory& memory, | ||||
|                                                           const Kernel::KThread* thread) { | ||||
|                                                           const Kernel::KThread& thread) { | ||||
|     // Read thread type from TLS
 | ||||
|     const VAddr tls_thread_type{memory.Read32(thread->GetTlsAddress() + 0x1fc)}; | ||||
|     const VAddr argument_thread_type{thread->GetArgument()}; | ||||
|     const VAddr tls_thread_type{memory.Read32(thread.GetTlsAddress() + 0x1fc)}; | ||||
|     const VAddr argument_thread_type{thread.GetArgument()}; | ||||
| 
 | ||||
|     if (argument_thread_type && tls_thread_type != argument_thread_type) { | ||||
|         // Probably not created by nnsdk, no name available.
 | ||||
|  | @ -477,10 +477,10 @@ static std::optional<std::string> GetNameFromThreadType32(Core::Memory::Memory& | |||
| } | ||||
| 
 | ||||
| static std::optional<std::string> GetNameFromThreadType64(Core::Memory::Memory& memory, | ||||
|                                                           const Kernel::KThread* thread) { | ||||
|                                                           const Kernel::KThread& thread) { | ||||
|     // Read thread type from TLS
 | ||||
|     const VAddr tls_thread_type{memory.Read64(thread->GetTlsAddress() + 0x1f8)}; | ||||
|     const VAddr argument_thread_type{thread->GetArgument()}; | ||||
|     const VAddr tls_thread_type{memory.Read64(thread.GetTlsAddress() + 0x1f8)}; | ||||
|     const VAddr argument_thread_type{thread.GetArgument()}; | ||||
| 
 | ||||
|     if (argument_thread_type && tls_thread_type != argument_thread_type) { | ||||
|         // Probably not created by nnsdk, no name available.
 | ||||
|  | @ -508,16 +508,16 @@ static std::optional<std::string> GetNameFromThreadType64(Core::Memory::Memory& | |||
| } | ||||
| 
 | ||||
| static std::optional<std::string> GetThreadName(Core::System& system, | ||||
|                                                 const Kernel::KThread* thread) { | ||||
|     if (system.ApplicationProcess()->Is64BitProcess()) { | ||||
|                                                 const Kernel::KThread& thread) { | ||||
|     if (system.ApplicationProcess()->Is64Bit()) { | ||||
|         return GetNameFromThreadType64(system.ApplicationMemory(), thread); | ||||
|     } else { | ||||
|         return GetNameFromThreadType32(system.ApplicationMemory(), thread); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static std::string_view GetThreadWaitReason(const Kernel::KThread* thread) { | ||||
|     switch (thread->GetWaitReasonForDebugging()) { | ||||
| static std::string_view GetThreadWaitReason(const Kernel::KThread& thread) { | ||||
|     switch (thread.GetWaitReasonForDebugging()) { | ||||
|     case Kernel::ThreadWaitReasonForDebugging::Sleep: | ||||
|         return "Sleep"; | ||||
|     case Kernel::ThreadWaitReasonForDebugging::IPC: | ||||
|  | @ -535,8 +535,8 @@ static std::string_view GetThreadWaitReason(const Kernel::KThread* thread) { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| static std::string GetThreadState(const Kernel::KThread* thread) { | ||||
|     switch (thread->GetState()) { | ||||
| static std::string GetThreadState(const Kernel::KThread& thread) { | ||||
|     switch (thread.GetState()) { | ||||
|     case Kernel::ThreadState::Initialized: | ||||
|         return "Initialized"; | ||||
|     case Kernel::ThreadState::Waiting: | ||||
|  | @ -604,7 +604,7 @@ void GDBStub::HandleQuery(std::string_view command) { | |||
|         const auto& threads = system.ApplicationProcess()->GetThreadList(); | ||||
|         std::vector<std::string> thread_ids; | ||||
|         for (const auto& thread : threads) { | ||||
|             thread_ids.push_back(fmt::format("{:x}", thread->GetThreadId())); | ||||
|             thread_ids.push_back(fmt::format("{:x}", thread.GetThreadId())); | ||||
|         } | ||||
|         SendReply(fmt::format("m{}", fmt::join(thread_ids, ","))); | ||||
|     } else if (command.starts_with("sThreadInfo")) { | ||||
|  | @ -616,14 +616,14 @@ void GDBStub::HandleQuery(std::string_view command) { | |||
|         buffer += "<threads>"; | ||||
| 
 | ||||
|         const auto& threads = system.ApplicationProcess()->GetThreadList(); | ||||
|         for (const auto* thread : threads) { | ||||
|         for (const auto& thread : threads) { | ||||
|             auto thread_name{GetThreadName(system, thread)}; | ||||
|             if (!thread_name) { | ||||
|                 thread_name = fmt::format("Thread {:d}", thread->GetThreadId()); | ||||
|                 thread_name = fmt::format("Thread {:d}", thread.GetThreadId()); | ||||
|             } | ||||
| 
 | ||||
|             buffer += fmt::format(R"(<thread id="{:x}" core="{:d}" name="{}">{}</thread>)", | ||||
|                                   thread->GetThreadId(), thread->GetActiveCore(), | ||||
|                                   thread.GetThreadId(), thread.GetActiveCore(), | ||||
|                                   EscapeXML(*thread_name), GetThreadState(thread)); | ||||
|         } | ||||
| 
 | ||||
|  | @ -850,10 +850,10 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) { | |||
| } | ||||
| 
 | ||||
| Kernel::KThread* GDBStub::GetThreadByID(u64 thread_id) { | ||||
|     const auto& threads{system.ApplicationProcess()->GetThreadList()}; | ||||
|     for (auto* thread : threads) { | ||||
|         if (thread->GetThreadId() == thread_id) { | ||||
|             return thread; | ||||
|     auto& threads{system.ApplicationProcess()->GetThreadList()}; | ||||
|     for (auto& thread : threads) { | ||||
|         if (thread.GetThreadId() == thread_id) { | ||||
|             return std::addressof(thread); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -104,16 +104,16 @@ Loader::ResultStatus ProgramMetadata::Reload(VirtualFile file) { | |||
| } | ||||
| 
 | ||||
| /*static*/ ProgramMetadata ProgramMetadata::GetDefault() { | ||||
|     // Allow use of cores 0~3 and thread priorities 1~63.
 | ||||
|     constexpr u32 default_thread_info_capability = 0x30007F7; | ||||
|     // Allow use of cores 0~3 and thread priorities 16~63.
 | ||||
|     constexpr u32 default_thread_info_capability = 0x30043F7; | ||||
| 
 | ||||
|     ProgramMetadata result; | ||||
| 
 | ||||
|     result.LoadManual( | ||||
|         true /*is_64_bit*/, FileSys::ProgramAddressSpaceType::Is39Bit /*address_space*/, | ||||
|         0x2c /*main_thread_prio*/, 0 /*main_thread_core*/, 0x00100000 /*main_thread_stack_size*/, | ||||
|         0 /*title_id*/, 0xFFFFFFFFFFFFFFFF /*filesystem_permissions*/, | ||||
|         0x1FE00000 /*system_resource_size*/, {default_thread_info_capability} /*capabilities*/); | ||||
|         0x2c /*main_thread_prio*/, 0 /*main_thread_core*/, 0x100000 /*main_thread_stack_size*/, | ||||
|         0 /*title_id*/, 0xFFFFFFFFFFFFFFFF /*filesystem_permissions*/, 0 /*system_resource_size*/, | ||||
|         {default_thread_info_capability} /*capabilities*/); | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
|  |  | |||
|  | @ -73,6 +73,9 @@ public: | |||
|     u64 GetFilesystemPermissions() const; | ||||
|     u32 GetSystemResourceSize() const; | ||||
|     const KernelCapabilityDescriptors& GetKernelCapabilities() const; | ||||
|     const std::array<u8, 0x10>& GetName() const { | ||||
|         return npdm_header.application_name; | ||||
|     } | ||||
| 
 | ||||
|     void Print() const; | ||||
| 
 | ||||
|  | @ -164,14 +167,14 @@ private: | |||
|         u32_le unk_size_2; | ||||
|     }; | ||||
| 
 | ||||
|     Header npdm_header; | ||||
|     AciHeader aci_header; | ||||
|     AcidHeader acid_header; | ||||
|     Header npdm_header{}; | ||||
|     AciHeader aci_header{}; | ||||
|     AcidHeader acid_header{}; | ||||
| 
 | ||||
|     FileAccessControl acid_file_access; | ||||
|     FileAccessHeader aci_file_access; | ||||
|     FileAccessControl acid_file_access{}; | ||||
|     FileAccessHeader aci_file_access{}; | ||||
| 
 | ||||
|     KernelCapabilityDescriptors aci_kernel_capabilities; | ||||
|     KernelCapabilityDescriptors aci_kernel_capabilities{}; | ||||
| }; | ||||
| 
 | ||||
| } // namespace FileSys
 | ||||
|  |  | |||
|  | @ -8,7 +8,11 @@ | |||
| 
 | ||||
| #include "core/hle/kernel/board/nintendo/nx/k_system_control.h" | ||||
| #include "core/hle/kernel/board/nintendo/nx/secure_monitor.h" | ||||
| #include "core/hle/kernel/k_memory_manager.h" | ||||
| #include "core/hle/kernel/k_page_table.h" | ||||
| #include "core/hle/kernel/k_trace.h" | ||||
| #include "core/hle/kernel/kernel.h" | ||||
| #include "core/hle/kernel/svc_results.h" | ||||
| 
 | ||||
| namespace Kernel::Board::Nintendo::Nx { | ||||
| 
 | ||||
|  | @ -30,6 +34,8 @@ constexpr const std::size_t RequiredNonSecureSystemMemorySize = | |||
| constexpr const std::size_t RequiredNonSecureSystemMemorySizeWithFatal = | ||||
|     RequiredNonSecureSystemMemorySize + impl::RequiredNonSecureSystemMemorySizeViFatal; | ||||
| 
 | ||||
| constexpr const std::size_t SecureAlignment = 128_KiB; | ||||
| 
 | ||||
| namespace { | ||||
| 
 | ||||
| using namespace Common::Literals; | ||||
|  | @ -183,4 +189,57 @@ u64 KSystemControl::GenerateRandomRange(u64 min, u64 max) { | |||
|     return GenerateUniformRange(min, max, GenerateRandomU64); | ||||
| } | ||||
| 
 | ||||
| size_t KSystemControl::CalculateRequiredSecureMemorySize(size_t size, u32 pool) { | ||||
|     if (pool == static_cast<u32>(KMemoryManager::Pool::Applet)) { | ||||
|         return 0; | ||||
|     } else { | ||||
|         // return KSystemControlBase::CalculateRequiredSecureMemorySize(size, pool);
 | ||||
|         return size; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| Result KSystemControl::AllocateSecureMemory(KernelCore& kernel, KVirtualAddress* out, size_t size, | ||||
|                                             u32 pool) { | ||||
|     // Applet secure memory is handled separately.
 | ||||
|     UNIMPLEMENTED_IF(pool == static_cast<u32>(KMemoryManager::Pool::Applet)); | ||||
| 
 | ||||
|     // Ensure the size is aligned.
 | ||||
|     const size_t alignment = | ||||
|         (pool == static_cast<u32>(KMemoryManager::Pool::System) ? PageSize : SecureAlignment); | ||||
|     R_UNLESS(Common::IsAligned(size, alignment), ResultInvalidSize); | ||||
| 
 | ||||
|     // Allocate the memory.
 | ||||
|     const size_t num_pages = size / PageSize; | ||||
|     const KPhysicalAddress paddr = kernel.MemoryManager().AllocateAndOpenContinuous( | ||||
|         num_pages, alignment / PageSize, | ||||
|         KMemoryManager::EncodeOption(static_cast<KMemoryManager::Pool>(pool), | ||||
|                                      KMemoryManager::Direction::FromFront)); | ||||
|     R_UNLESS(paddr != 0, ResultOutOfMemory); | ||||
| 
 | ||||
|     // Ensure we don't leak references to the memory on error.
 | ||||
|     ON_RESULT_FAILURE { | ||||
|         kernel.MemoryManager().Close(paddr, num_pages); | ||||
|     }; | ||||
| 
 | ||||
|     // We succeeded.
 | ||||
|     *out = KPageTable::GetHeapVirtualAddress(kernel.MemoryLayout(), paddr); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| void KSystemControl::FreeSecureMemory(KernelCore& kernel, KVirtualAddress address, size_t size, | ||||
|                                       u32 pool) { | ||||
|     // Applet secure memory is handled separately.
 | ||||
|     UNIMPLEMENTED_IF(pool == static_cast<u32>(KMemoryManager::Pool::Applet)); | ||||
| 
 | ||||
|     // Ensure the size is aligned.
 | ||||
|     const size_t alignment = | ||||
|         (pool == static_cast<u32>(KMemoryManager::Pool::System) ? PageSize : SecureAlignment); | ||||
|     ASSERT(Common::IsAligned(GetInteger(address), alignment)); | ||||
|     ASSERT(Common::IsAligned(size, alignment)); | ||||
| 
 | ||||
|     // Close the secure region's pages.
 | ||||
|     kernel.MemoryManager().Close(KPageTable::GetHeapPhysicalAddress(kernel.MemoryLayout(), address), | ||||
|                                  size / PageSize); | ||||
| } | ||||
| 
 | ||||
| } // namespace Kernel::Board::Nintendo::Nx
 | ||||
|  |  | |||
|  | @ -4,6 +4,11 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include "core/hle/kernel/k_typed_address.h" | ||||
| #include "core/hle/result.h" | ||||
| 
 | ||||
| namespace Kernel { | ||||
| class KernelCore; | ||||
| } | ||||
| 
 | ||||
| namespace Kernel::Board::Nintendo::Nx { | ||||
| 
 | ||||
|  | @ -25,8 +30,16 @@ public: | |||
|         static std::size_t GetMinimumNonSecureSystemPoolSize(); | ||||
|     }; | ||||
| 
 | ||||
|     // Randomness.
 | ||||
|     static u64 GenerateRandomRange(u64 min, u64 max); | ||||
|     static u64 GenerateRandomU64(); | ||||
| 
 | ||||
|     // Secure Memory.
 | ||||
|     static size_t CalculateRequiredSecureMemorySize(size_t size, u32 pool); | ||||
|     static Result AllocateSecureMemory(KernelCore& kernel, KVirtualAddress* out, size_t size, | ||||
|                                        u32 pool); | ||||
|     static void FreeSecureMemory(KernelCore& kernel, KVirtualAddress address, size_t size, | ||||
|                                  u32 pool); | ||||
| }; | ||||
| 
 | ||||
| } // namespace Kernel::Board::Nintendo::Nx
 | ||||
|  |  | |||
|  | @ -200,8 +200,8 @@ private: | |||
| 
 | ||||
|         RawCapabilityValue raw; | ||||
|         BitField<0, 15, CapabilityType> id; | ||||
|         BitField<15, 4, u32> major_version; | ||||
|         BitField<19, 13, u32> minor_version; | ||||
|         BitField<15, 4, u32> minor_version; | ||||
|         BitField<19, 13, u32> major_version; | ||||
|     }; | ||||
| 
 | ||||
|     union HandleTable { | ||||
|  |  | |||
|  | @ -107,12 +107,12 @@ KConditionVariable::KConditionVariable(Core::System& system) | |||
| 
 | ||||
| KConditionVariable::~KConditionVariable() = default; | ||||
| 
 | ||||
| Result KConditionVariable::SignalToAddress(KProcessAddress addr) { | ||||
|     KThread* owner_thread = GetCurrentThreadPointer(m_kernel); | ||||
| Result KConditionVariable::SignalToAddress(KernelCore& kernel, KProcessAddress addr) { | ||||
|     KThread* owner_thread = GetCurrentThreadPointer(kernel); | ||||
| 
 | ||||
|     // Signal the address.
 | ||||
|     { | ||||
|         KScopedSchedulerLock sl(m_kernel); | ||||
|         KScopedSchedulerLock sl(kernel); | ||||
| 
 | ||||
|         // Remove waiter thread.
 | ||||
|         bool has_waiters{}; | ||||
|  | @ -133,7 +133,7 @@ Result KConditionVariable::SignalToAddress(KProcessAddress addr) { | |||
| 
 | ||||
|         // Write the value to userspace.
 | ||||
|         Result result{ResultSuccess}; | ||||
|         if (WriteToUser(m_kernel, addr, std::addressof(next_value))) [[likely]] { | ||||
|         if (WriteToUser(kernel, addr, std::addressof(next_value))) [[likely]] { | ||||
|             result = ResultSuccess; | ||||
|         } else { | ||||
|             result = ResultInvalidCurrentMemory; | ||||
|  | @ -148,28 +148,28 @@ Result KConditionVariable::SignalToAddress(KProcessAddress addr) { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| Result KConditionVariable::WaitForAddress(Handle handle, KProcessAddress addr, u32 value) { | ||||
|     KThread* cur_thread = GetCurrentThreadPointer(m_kernel); | ||||
|     ThreadQueueImplForKConditionVariableWaitForAddress wait_queue(m_kernel); | ||||
| Result KConditionVariable::WaitForAddress(KernelCore& kernel, Handle handle, KProcessAddress addr, | ||||
|                                           u32 value) { | ||||
|     KThread* cur_thread = GetCurrentThreadPointer(kernel); | ||||
|     ThreadQueueImplForKConditionVariableWaitForAddress wait_queue(kernel); | ||||
| 
 | ||||
|     // Wait for the address.
 | ||||
|     KThread* owner_thread{}; | ||||
|     { | ||||
|         KScopedSchedulerLock sl(m_kernel); | ||||
|         KScopedSchedulerLock sl(kernel); | ||||
| 
 | ||||
|         // Check if the thread should terminate.
 | ||||
|         R_UNLESS(!cur_thread->IsTerminationRequested(), ResultTerminationRequested); | ||||
| 
 | ||||
|         // Read the tag from userspace.
 | ||||
|         u32 test_tag{}; | ||||
|         R_UNLESS(ReadFromUser(m_kernel, std::addressof(test_tag), addr), | ||||
|                  ResultInvalidCurrentMemory); | ||||
|         R_UNLESS(ReadFromUser(kernel, std::addressof(test_tag), addr), ResultInvalidCurrentMemory); | ||||
| 
 | ||||
|         // If the tag isn't the handle (with wait mask), we're done.
 | ||||
|         R_SUCCEED_IF(test_tag != (handle | Svc::HandleWaitMask)); | ||||
| 
 | ||||
|         // Get the lock owner thread.
 | ||||
|         owner_thread = GetCurrentProcess(m_kernel) | ||||
|         owner_thread = GetCurrentProcess(kernel) | ||||
|                            .GetHandleTable() | ||||
|                            .GetObjectWithoutPseudoHandle<KThread>(handle) | ||||
|                            .ReleasePointerUnsafe(); | ||||
|  |  | |||
|  | @ -24,11 +24,12 @@ public: | |||
|     explicit KConditionVariable(Core::System& system); | ||||
|     ~KConditionVariable(); | ||||
| 
 | ||||
|     // Arbitration
 | ||||
|     Result SignalToAddress(KProcessAddress addr); | ||||
|     Result WaitForAddress(Handle handle, KProcessAddress addr, u32 value); | ||||
|     // Arbitration.
 | ||||
|     static Result SignalToAddress(KernelCore& kernel, KProcessAddress addr); | ||||
|     static Result WaitForAddress(KernelCore& kernel, Handle handle, KProcessAddress addr, | ||||
|                                  u32 value); | ||||
| 
 | ||||
|     // Condition variable
 | ||||
|     // Condition variable.
 | ||||
|     void Signal(u64 cv_key, s32 count); | ||||
|     Result Wait(KProcessAddress addr, u64 key, u32 value, s64 timeout); | ||||
| 
 | ||||
|  |  | |||
|  | @ -22,7 +22,7 @@ void HandleInterrupt(KernelCore& kernel, s32 core_id) { | |||
|             KScopedSchedulerLock sl{kernel}; | ||||
| 
 | ||||
|             // Pin the current thread.
 | ||||
|             process->PinCurrentThread(core_id); | ||||
|             process->PinCurrentThread(); | ||||
| 
 | ||||
|             // Set the interrupt flag for the thread.
 | ||||
|             GetCurrentThread(kernel).SetInterruptFlag(); | ||||
|  |  | |||
|  | @ -11,6 +11,7 @@ | |||
| #include "core/hle/kernel/initial_process.h" | ||||
| #include "core/hle/kernel/k_memory_manager.h" | ||||
| #include "core/hle/kernel/k_page_group.h" | ||||
| #include "core/hle/kernel/k_page_table.h" | ||||
| #include "core/hle/kernel/kernel.h" | ||||
| #include "core/hle/kernel/svc_results.h" | ||||
| 
 | ||||
|  | @ -168,11 +169,37 @@ void KMemoryManager::Initialize(KVirtualAddress management_region, size_t manage | |||
| } | ||||
| 
 | ||||
| Result KMemoryManager::InitializeOptimizedMemory(u64 process_id, Pool pool) { | ||||
|     UNREACHABLE(); | ||||
|     const u32 pool_index = static_cast<u32>(pool); | ||||
| 
 | ||||
|     // Lock the pool.
 | ||||
|     KScopedLightLock lk(m_pool_locks[pool_index]); | ||||
| 
 | ||||
|     // Check that we don't already have an optimized process.
 | ||||
|     R_UNLESS(!m_has_optimized_process[pool_index], ResultBusy); | ||||
| 
 | ||||
|     // Set the optimized process id.
 | ||||
|     m_optimized_process_ids[pool_index] = process_id; | ||||
|     m_has_optimized_process[pool_index] = true; | ||||
| 
 | ||||
|     // Clear the management area for the optimized process.
 | ||||
|     for (auto* manager = this->GetFirstManager(pool, Direction::FromFront); manager != nullptr; | ||||
|          manager = this->GetNextManager(manager, Direction::FromFront)) { | ||||
|         manager->InitializeOptimizedMemory(m_system.Kernel()); | ||||
|     } | ||||
| 
 | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| void KMemoryManager::FinalizeOptimizedMemory(u64 process_id, Pool pool) { | ||||
|     UNREACHABLE(); | ||||
|     const u32 pool_index = static_cast<u32>(pool); | ||||
| 
 | ||||
|     // Lock the pool.
 | ||||
|     KScopedLightLock lk(m_pool_locks[pool_index]); | ||||
| 
 | ||||
|     // If the process was optimized, clear it.
 | ||||
|     if (m_has_optimized_process[pool_index] && m_optimized_process_ids[pool_index] == process_id) { | ||||
|         m_has_optimized_process[pool_index] = false; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| KPhysicalAddress KMemoryManager::AllocateAndOpenContinuous(size_t num_pages, size_t align_pages, | ||||
|  | @ -207,7 +234,7 @@ KPhysicalAddress KMemoryManager::AllocateAndOpenContinuous(size_t num_pages, siz | |||
| 
 | ||||
|     // Maintain the optimized memory bitmap, if we should.
 | ||||
|     if (m_has_optimized_process[static_cast<size_t>(pool)]) { | ||||
|         UNIMPLEMENTED(); | ||||
|         chosen_manager->TrackUnoptimizedAllocation(m_system.Kernel(), allocated_block, num_pages); | ||||
|     } | ||||
| 
 | ||||
|     // Open the first reference to the pages.
 | ||||
|  | @ -255,7 +282,8 @@ Result KMemoryManager::AllocatePageGroupImpl(KPageGroup* out, size_t num_pages, | |||
| 
 | ||||
|                 // Maintain the optimized memory bitmap, if we should.
 | ||||
|                 if (unoptimized) { | ||||
|                     UNIMPLEMENTED(); | ||||
|                     cur_manager->TrackUnoptimizedAllocation(m_system.Kernel(), allocated_block, | ||||
|                                                             pages_per_alloc); | ||||
|                 } | ||||
| 
 | ||||
|                 num_pages -= pages_per_alloc; | ||||
|  | @ -358,8 +386,8 @@ Result KMemoryManager::AllocateForProcess(KPageGroup* out, size_t num_pages, u32 | |||
|                     // Process part or all of the block.
 | ||||
|                     const size_t cur_pages = | ||||
|                         std::min(remaining_pages, manager.GetPageOffsetToEnd(cur_address)); | ||||
|                     any_new = | ||||
|                         manager.ProcessOptimizedAllocation(cur_address, cur_pages, fill_pattern); | ||||
|                     any_new = manager.ProcessOptimizedAllocation(m_system.Kernel(), cur_address, | ||||
|                                                                  cur_pages, fill_pattern); | ||||
| 
 | ||||
|                     // Advance.
 | ||||
|                     cur_address += cur_pages * PageSize; | ||||
|  | @ -382,7 +410,7 @@ Result KMemoryManager::AllocateForProcess(KPageGroup* out, size_t num_pages, u32 | |||
|                     // Track some or all of the current pages.
 | ||||
|                     const size_t cur_pages = | ||||
|                         std::min(remaining_pages, manager.GetPageOffsetToEnd(cur_address)); | ||||
|                     manager.TrackOptimizedAllocation(cur_address, cur_pages); | ||||
|                     manager.TrackOptimizedAllocation(m_system.Kernel(), cur_address, cur_pages); | ||||
| 
 | ||||
|                     // Advance.
 | ||||
|                     cur_address += cur_pages * PageSize; | ||||
|  | @ -427,17 +455,86 @@ size_t KMemoryManager::Impl::Initialize(KPhysicalAddress address, size_t size, | |||
|     return total_management_size; | ||||
| } | ||||
| 
 | ||||
| void KMemoryManager::Impl::TrackUnoptimizedAllocation(KPhysicalAddress block, size_t num_pages) { | ||||
|     UNREACHABLE(); | ||||
| void KMemoryManager::Impl::InitializeOptimizedMemory(KernelCore& kernel) { | ||||
|     auto optimize_pa = | ||||
|         KPageTable::GetHeapPhysicalAddress(kernel.MemoryLayout(), m_management_region); | ||||
|     auto* optimize_map = kernel.System().DeviceMemory().GetPointer<u64>(optimize_pa); | ||||
| 
 | ||||
|     std::memset(optimize_map, 0, CalculateOptimizedProcessOverheadSize(m_heap.GetSize())); | ||||
| } | ||||
| 
 | ||||
| void KMemoryManager::Impl::TrackOptimizedAllocation(KPhysicalAddress block, size_t num_pages) { | ||||
|     UNREACHABLE(); | ||||
| void KMemoryManager::Impl::TrackUnoptimizedAllocation(KernelCore& kernel, KPhysicalAddress block, | ||||
|                                                       size_t num_pages) { | ||||
|     auto optimize_pa = | ||||
|         KPageTable::GetHeapPhysicalAddress(kernel.MemoryLayout(), m_management_region); | ||||
|     auto* optimize_map = kernel.System().DeviceMemory().GetPointer<u64>(optimize_pa); | ||||
| 
 | ||||
|     // Get the range we're tracking.
 | ||||
|     size_t offset = this->GetPageOffset(block); | ||||
|     const size_t last = offset + num_pages - 1; | ||||
| 
 | ||||
|     // Track.
 | ||||
|     while (offset <= last) { | ||||
|         // Mark the page as not being optimized-allocated.
 | ||||
|         optimize_map[offset / Common::BitSize<u64>()] &= | ||||
|             ~(u64(1) << (offset % Common::BitSize<u64>())); | ||||
| 
 | ||||
|         offset++; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| bool KMemoryManager::Impl::ProcessOptimizedAllocation(KPhysicalAddress block, size_t num_pages, | ||||
|                                                       u8 fill_pattern) { | ||||
|     UNREACHABLE(); | ||||
| void KMemoryManager::Impl::TrackOptimizedAllocation(KernelCore& kernel, KPhysicalAddress block, | ||||
|                                                     size_t num_pages) { | ||||
|     auto optimize_pa = | ||||
|         KPageTable::GetHeapPhysicalAddress(kernel.MemoryLayout(), m_management_region); | ||||
|     auto* optimize_map = kernel.System().DeviceMemory().GetPointer<u64>(optimize_pa); | ||||
| 
 | ||||
|     // Get the range we're tracking.
 | ||||
|     size_t offset = this->GetPageOffset(block); | ||||
|     const size_t last = offset + num_pages - 1; | ||||
| 
 | ||||
|     // Track.
 | ||||
|     while (offset <= last) { | ||||
|         // Mark the page as being optimized-allocated.
 | ||||
|         optimize_map[offset / Common::BitSize<u64>()] |= | ||||
|             (u64(1) << (offset % Common::BitSize<u64>())); | ||||
| 
 | ||||
|         offset++; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| bool KMemoryManager::Impl::ProcessOptimizedAllocation(KernelCore& kernel, KPhysicalAddress block, | ||||
|                                                       size_t num_pages, u8 fill_pattern) { | ||||
|     auto& device_memory = kernel.System().DeviceMemory(); | ||||
|     auto optimize_pa = | ||||
|         KPageTable::GetHeapPhysicalAddress(kernel.MemoryLayout(), m_management_region); | ||||
|     auto* optimize_map = device_memory.GetPointer<u64>(optimize_pa); | ||||
| 
 | ||||
|     // We want to return whether any pages were newly allocated.
 | ||||
|     bool any_new = false; | ||||
| 
 | ||||
|     // Get the range we're processing.
 | ||||
|     size_t offset = this->GetPageOffset(block); | ||||
|     const size_t last = offset + num_pages - 1; | ||||
| 
 | ||||
|     // Process.
 | ||||
|     while (offset <= last) { | ||||
|         // Check if the page has been optimized-allocated before.
 | ||||
|         if ((optimize_map[offset / Common::BitSize<u64>()] & | ||||
|              (u64(1) << (offset % Common::BitSize<u64>()))) == 0) { | ||||
|             // If not, it's new.
 | ||||
|             any_new = true; | ||||
| 
 | ||||
|             // Fill the page.
 | ||||
|             auto* ptr = device_memory.GetPointer<u8>(m_heap.GetAddress()); | ||||
|             std::memset(ptr + offset * PageSize, fill_pattern, PageSize); | ||||
|         } | ||||
| 
 | ||||
|         offset++; | ||||
|     } | ||||
| 
 | ||||
|     // Return the number of pages we processed.
 | ||||
|     return any_new; | ||||
| } | ||||
| 
 | ||||
| size_t KMemoryManager::Impl::CalculateManagementOverheadSize(size_t region_size) { | ||||
|  |  | |||
|  | @ -216,14 +216,14 @@ private: | |||
|             m_heap.SetInitialUsedSize(reserved_size); | ||||
|         } | ||||
| 
 | ||||
|         void InitializeOptimizedMemory() { | ||||
|             UNIMPLEMENTED(); | ||||
|         } | ||||
|         void InitializeOptimizedMemory(KernelCore& kernel); | ||||
| 
 | ||||
|         void TrackUnoptimizedAllocation(KPhysicalAddress block, size_t num_pages); | ||||
|         void TrackOptimizedAllocation(KPhysicalAddress block, size_t num_pages); | ||||
|         void TrackUnoptimizedAllocation(KernelCore& kernel, KPhysicalAddress block, | ||||
|                                         size_t num_pages); | ||||
|         void TrackOptimizedAllocation(KernelCore& kernel, KPhysicalAddress block, size_t num_pages); | ||||
| 
 | ||||
|         bool ProcessOptimizedAllocation(KPhysicalAddress block, size_t num_pages, u8 fill_pattern); | ||||
|         bool ProcessOptimizedAllocation(KernelCore& kernel, KPhysicalAddress block, | ||||
|                                         size_t num_pages, u8 fill_pattern); | ||||
| 
 | ||||
|         constexpr Pool GetPool() const { | ||||
|             return m_pool; | ||||
|  |  | |||
|  | @ -82,14 +82,14 @@ public: | |||
| 
 | ||||
| using namespace Common::Literals; | ||||
| 
 | ||||
| constexpr size_t GetAddressSpaceWidthFromType(FileSys::ProgramAddressSpaceType as_type) { | ||||
| constexpr size_t GetAddressSpaceWidthFromType(Svc::CreateProcessFlag as_type) { | ||||
|     switch (as_type) { | ||||
|     case FileSys::ProgramAddressSpaceType::Is32Bit: | ||||
|     case FileSys::ProgramAddressSpaceType::Is32BitNoMap: | ||||
|     case Svc::CreateProcessFlag::AddressSpace32Bit: | ||||
|     case Svc::CreateProcessFlag::AddressSpace32BitWithoutAlias: | ||||
|         return 32; | ||||
|     case FileSys::ProgramAddressSpaceType::Is36Bit: | ||||
|     case Svc::CreateProcessFlag::AddressSpace64BitDeprecated: | ||||
|         return 36; | ||||
|     case FileSys::ProgramAddressSpaceType::Is39Bit: | ||||
|     case Svc::CreateProcessFlag::AddressSpace64Bit: | ||||
|         return 39; | ||||
|     default: | ||||
|         ASSERT(false); | ||||
|  | @ -105,7 +105,7 @@ KPageTable::KPageTable(Core::System& system_) | |||
| 
 | ||||
| KPageTable::~KPageTable() = default; | ||||
| 
 | ||||
| Result KPageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_type, bool enable_aslr, | ||||
| Result KPageTable::InitializeForProcess(Svc::CreateProcessFlag as_type, bool enable_aslr, | ||||
|                                         bool enable_das_merge, bool from_back, | ||||
|                                         KMemoryManager::Pool pool, KProcessAddress code_addr, | ||||
|                                         size_t code_size, KSystemResource* system_resource, | ||||
|  | @ -133,7 +133,7 @@ Result KPageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_type | |||
|     ASSERT(code_addr + code_size - 1 <= end - 1); | ||||
| 
 | ||||
|     // Adjust heap/alias size if we don't have an alias region
 | ||||
|     if (as_type == FileSys::ProgramAddressSpaceType::Is32BitNoMap) { | ||||
|     if (as_type == Svc::CreateProcessFlag::AddressSpace32BitWithoutAlias) { | ||||
|         heap_region_size += alias_region_size; | ||||
|         alias_region_size = 0; | ||||
|     } | ||||
|  |  | |||
|  | @ -63,7 +63,7 @@ public: | |||
|     explicit KPageTable(Core::System& system_); | ||||
|     ~KPageTable(); | ||||
| 
 | ||||
|     Result InitializeForProcess(FileSys::ProgramAddressSpaceType as_type, bool enable_aslr, | ||||
|     Result InitializeForProcess(Svc::CreateProcessFlag as_type, bool enable_aslr, | ||||
|                                 bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, | ||||
|                                 KProcessAddress code_addr, size_t code_size, | ||||
|                                 KSystemResource* system_resource, KResourceLimit* resource_limit, | ||||
|  | @ -400,7 +400,7 @@ public: | |||
|     constexpr size_t GetAliasCodeRegionSize() const { | ||||
|         return m_alias_code_region_end - m_alias_code_region_start; | ||||
|     } | ||||
|     size_t GetNormalMemorySize() { | ||||
|     size_t GetNormalMemorySize() const { | ||||
|         KScopedLightLock lk(m_general_lock); | ||||
|         return GetHeapSize() + m_mapped_physical_memory_size; | ||||
|     } | ||||
|  |  | |||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -1,59 +1,23 @@ | |||
| // SPDX-FileCopyrightText: 2015 Citra Emulator Project
 | ||||
| // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <array> | ||||
| #include <cstddef> | ||||
| #include <list> | ||||
| #include <map> | ||||
| #include <string> | ||||
| 
 | ||||
| #include "core/hle/kernel/code_set.h" | ||||
| #include "core/hle/kernel/k_address_arbiter.h" | ||||
| #include "core/hle/kernel/k_auto_object.h" | ||||
| #include "core/hle/kernel/k_capabilities.h" | ||||
| #include "core/hle/kernel/k_condition_variable.h" | ||||
| #include "core/hle/kernel/k_handle_table.h" | ||||
| #include "core/hle/kernel/k_page_table.h" | ||||
| #include "core/hle/kernel/k_synchronization_object.h" | ||||
| #include "core/hle/kernel/k_page_table_manager.h" | ||||
| #include "core/hle/kernel/k_system_resource.h" | ||||
| #include "core/hle/kernel/k_thread.h" | ||||
| #include "core/hle/kernel/k_thread_local_page.h" | ||||
| #include "core/hle/kernel/k_typed_address.h" | ||||
| #include "core/hle/kernel/k_worker_task.h" | ||||
| #include "core/hle/kernel/process_capability.h" | ||||
| #include "core/hle/kernel/slab_helpers.h" | ||||
| #include "core/hle/result.h" | ||||
| 
 | ||||
| namespace Core { | ||||
| namespace Memory { | ||||
| class Memory; | ||||
| }; | ||||
| 
 | ||||
| class System; | ||||
| } // namespace Core
 | ||||
| 
 | ||||
| namespace FileSys { | ||||
| class ProgramMetadata; | ||||
| } | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
| class KernelCore; | ||||
| class KResourceLimit; | ||||
| class KThread; | ||||
| class KSharedMemoryInfo; | ||||
| class TLSPage; | ||||
| 
 | ||||
| struct CodeSet; | ||||
| 
 | ||||
| enum class MemoryRegion : u16 { | ||||
|     APPLICATION = 1, | ||||
|     SYSTEM = 2, | ||||
|     BASE = 3, | ||||
| }; | ||||
| 
 | ||||
| enum class ProcessActivity : u32 { | ||||
|     Runnable, | ||||
|     Paused, | ||||
| }; | ||||
| 
 | ||||
| enum class DebugWatchpointType : u8 { | ||||
|     None = 0, | ||||
|     Read = 1 << 0, | ||||
|  | @ -72,9 +36,6 @@ class KProcess final : public KAutoObjectWithSlabHeapAndContainer<KProcess, KWor | |||
|     KERNEL_AUTOOBJECT_TRAITS(KProcess, KSynchronizationObject); | ||||
| 
 | ||||
| public: | ||||
|     explicit KProcess(KernelCore& kernel); | ||||
|     ~KProcess() override; | ||||
| 
 | ||||
|     enum class State { | ||||
|         Created = static_cast<u32>(Svc::ProcessState::Created), | ||||
|         CreatedAttached = static_cast<u32>(Svc::ProcessState::CreatedAttached), | ||||
|  | @ -86,337 +47,83 @@ public: | |||
|         DebugBreak = static_cast<u32>(Svc::ProcessState::DebugBreak), | ||||
|     }; | ||||
| 
 | ||||
|     enum : u64 { | ||||
|         /// Lowest allowed process ID for a kernel initial process.
 | ||||
|         InitialKIPIDMin = 1, | ||||
|         /// Highest allowed process ID for a kernel initial process.
 | ||||
|         InitialKIPIDMax = 80, | ||||
|     using ThreadList = Common::IntrusiveListMemberTraits<&KThread::m_process_list_node>::ListType; | ||||
| 
 | ||||
|         /// Lowest allowed process ID for a userland process.
 | ||||
|         ProcessIDMin = 81, | ||||
|         /// Highest allowed process ID for a userland process.
 | ||||
|         ProcessIDMax = 0xFFFFFFFFFFFFFFFF, | ||||
|     }; | ||||
|     static constexpr size_t AslrAlignment = 2_MiB; | ||||
| 
 | ||||
|     // Used to determine how process IDs are assigned.
 | ||||
|     enum class ProcessType { | ||||
|         KernelInternal, | ||||
|         Userland, | ||||
|     }; | ||||
| public: | ||||
|     static constexpr u64 InitialProcessIdMin = 1; | ||||
|     static constexpr u64 InitialProcessIdMax = 0x50; | ||||
| 
 | ||||
|     static constexpr std::size_t RANDOM_ENTROPY_SIZE = 4; | ||||
| 
 | ||||
|     static Result Initialize(KProcess* process, Core::System& system, std::string process_name, | ||||
|                              ProcessType type, KResourceLimit* res_limit); | ||||
| 
 | ||||
|     /// Gets a reference to the process' page table.
 | ||||
|     KPageTable& GetPageTable() { | ||||
|         return m_page_table; | ||||
|     } | ||||
| 
 | ||||
|     /// Gets const a reference to the process' page table.
 | ||||
|     const KPageTable& GetPageTable() const { | ||||
|         return m_page_table; | ||||
|     } | ||||
| 
 | ||||
|     /// Gets a reference to the process' handle table.
 | ||||
|     KHandleTable& GetHandleTable() { | ||||
|         return m_handle_table; | ||||
|     } | ||||
| 
 | ||||
|     /// Gets a const reference to the process' handle table.
 | ||||
|     const KHandleTable& GetHandleTable() const { | ||||
|         return m_handle_table; | ||||
|     } | ||||
| 
 | ||||
|     /// Gets a reference to process's memory.
 | ||||
|     Core::Memory::Memory& GetMemory() const; | ||||
| 
 | ||||
|     Result SignalToAddress(KProcessAddress address) { | ||||
|         return m_condition_var.SignalToAddress(address); | ||||
|     } | ||||
| 
 | ||||
|     Result WaitForAddress(Handle handle, KProcessAddress address, u32 tag) { | ||||
|         return m_condition_var.WaitForAddress(handle, address, tag); | ||||
|     } | ||||
| 
 | ||||
|     void SignalConditionVariable(u64 cv_key, int32_t count) { | ||||
|         return m_condition_var.Signal(cv_key, count); | ||||
|     } | ||||
| 
 | ||||
|     Result WaitConditionVariable(KProcessAddress address, u64 cv_key, u32 tag, s64 ns) { | ||||
|         R_RETURN(m_condition_var.Wait(address, cv_key, tag, ns)); | ||||
|     } | ||||
| 
 | ||||
|     Result SignalAddressArbiter(uint64_t address, Svc::SignalType signal_type, s32 value, | ||||
|                                 s32 count) { | ||||
|         R_RETURN(m_address_arbiter.SignalToAddress(address, signal_type, value, count)); | ||||
|     } | ||||
| 
 | ||||
|     Result WaitAddressArbiter(uint64_t address, Svc::ArbitrationType arb_type, s32 value, | ||||
|                               s64 timeout) { | ||||
|         R_RETURN(m_address_arbiter.WaitForAddress(address, arb_type, value, timeout)); | ||||
|     } | ||||
| 
 | ||||
|     KProcessAddress GetProcessLocalRegionAddress() const { | ||||
|         return m_plr_address; | ||||
|     } | ||||
| 
 | ||||
|     /// Gets the current status of the process
 | ||||
|     State GetState() const { | ||||
|         return m_state; | ||||
|     } | ||||
| 
 | ||||
|     /// Gets the unique ID that identifies this particular process.
 | ||||
|     u64 GetProcessId() const { | ||||
|         return m_process_id; | ||||
|     } | ||||
| 
 | ||||
|     /// Gets the program ID corresponding to this process.
 | ||||
|     u64 GetProgramId() const { | ||||
|         return m_program_id; | ||||
|     } | ||||
| 
 | ||||
|     KProcessAddress GetEntryPoint() const { | ||||
|         return m_code_address; | ||||
|     } | ||||
| 
 | ||||
|     /// Gets the resource limit descriptor for this process
 | ||||
|     KResourceLimit* GetResourceLimit() const; | ||||
| 
 | ||||
|     /// Gets the ideal CPU core ID for this process
 | ||||
|     u8 GetIdealCoreId() const { | ||||
|         return m_ideal_core; | ||||
|     } | ||||
| 
 | ||||
|     /// Checks if the specified thread priority is valid.
 | ||||
|     bool CheckThreadPriority(s32 prio) const { | ||||
|         return ((1ULL << prio) & GetPriorityMask()) != 0; | ||||
|     } | ||||
| 
 | ||||
|     /// Gets the bitmask of allowed cores that this process' threads can run on.
 | ||||
|     u64 GetCoreMask() const { | ||||
|         return m_capabilities.GetCoreMask(); | ||||
|     } | ||||
| 
 | ||||
|     /// Gets the bitmask of allowed thread priorities.
 | ||||
|     u64 GetPriorityMask() const { | ||||
|         return m_capabilities.GetPriorityMask(); | ||||
|     } | ||||
| 
 | ||||
|     /// Gets the amount of secure memory to allocate for memory management.
 | ||||
|     u32 GetSystemResourceSize() const { | ||||
|         return m_system_resource_size; | ||||
|     } | ||||
| 
 | ||||
|     /// Gets the amount of secure memory currently in use for memory management.
 | ||||
|     u32 GetSystemResourceUsage() const { | ||||
|         // On hardware, this returns the amount of system resource memory that has
 | ||||
|         // been used by the kernel. This is problematic for Yuzu to emulate, because
 | ||||
|         // system resource memory is used for page tables -- and yuzu doesn't really
 | ||||
|         // have a way to calculate how much memory is required for page tables for
 | ||||
|         // the current process at any given time.
 | ||||
|         // TODO: Is this even worth implementing? Games may retrieve this value via
 | ||||
|         // an SDK function that gets used + available system resource size for debug
 | ||||
|         // or diagnostic purposes. However, it seems unlikely that a game would make
 | ||||
|         // decisions based on how much system memory is dedicated to its page tables.
 | ||||
|         // Is returning a value other than zero wise?
 | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
|     /// Whether this process is an AArch64 or AArch32 process.
 | ||||
|     bool Is64BitProcess() const { | ||||
|         return m_is_64bit_process; | ||||
|     } | ||||
| 
 | ||||
|     bool IsSuspended() const { | ||||
|         return m_is_suspended; | ||||
|     } | ||||
| 
 | ||||
|     void SetSuspended(bool suspended) { | ||||
|         m_is_suspended = suspended; | ||||
|     } | ||||
| 
 | ||||
|     /// Gets the total running time of the process instance in ticks.
 | ||||
|     u64 GetCPUTimeTicks() const { | ||||
|         return m_total_process_running_time_ticks; | ||||
|     } | ||||
| 
 | ||||
|     /// Updates the total running time, adding the given ticks to it.
 | ||||
|     void UpdateCPUTimeTicks(u64 ticks) { | ||||
|         m_total_process_running_time_ticks += ticks; | ||||
|     } | ||||
| 
 | ||||
|     /// Gets the process schedule count, used for thread yielding
 | ||||
|     s64 GetScheduledCount() const { | ||||
|         return m_schedule_count; | ||||
|     } | ||||
| 
 | ||||
|     /// Increments the process schedule count, used for thread yielding.
 | ||||
|     void IncrementScheduledCount() { | ||||
|         ++m_schedule_count; | ||||
|     } | ||||
| 
 | ||||
|     void IncrementRunningThreadCount(); | ||||
|     void DecrementRunningThreadCount(); | ||||
| 
 | ||||
|     void SetRunningThread(s32 core, KThread* thread, u64 idle_count) { | ||||
|         m_running_threads[core] = thread; | ||||
|         m_running_thread_idle_counts[core] = idle_count; | ||||
|     } | ||||
| 
 | ||||
|     void ClearRunningThread(KThread* thread) { | ||||
|         for (size_t i = 0; i < m_running_threads.size(); ++i) { | ||||
|             if (m_running_threads[i] == thread) { | ||||
|                 m_running_threads[i] = nullptr; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] KThread* GetRunningThread(s32 core) const { | ||||
|         return m_running_threads[core]; | ||||
|     } | ||||
| 
 | ||||
|     bool ReleaseUserException(KThread* thread); | ||||
| 
 | ||||
|     [[nodiscard]] KThread* GetPinnedThread(s32 core_id) const { | ||||
|         ASSERT(0 <= core_id && core_id < static_cast<s32>(Core::Hardware::NUM_CPU_CORES)); | ||||
|         return m_pinned_threads[core_id]; | ||||
|     } | ||||
| 
 | ||||
|     /// Gets 8 bytes of random data for svcGetInfo RandomEntropy
 | ||||
|     u64 GetRandomEntropy(std::size_t index) const { | ||||
|         return m_random_entropy.at(index); | ||||
|     } | ||||
| 
 | ||||
|     /// Retrieves the total physical memory available to this process in bytes.
 | ||||
|     u64 GetTotalPhysicalMemoryAvailable(); | ||||
| 
 | ||||
|     /// Retrieves the total physical memory available to this process in bytes,
 | ||||
|     /// without the size of the personal system resource heap added to it.
 | ||||
|     u64 GetTotalPhysicalMemoryAvailableWithoutSystemResource(); | ||||
| 
 | ||||
|     /// Retrieves the total physical memory used by this process in bytes.
 | ||||
|     u64 GetTotalPhysicalMemoryUsed(); | ||||
| 
 | ||||
|     /// Retrieves the total physical memory used by this process in bytes,
 | ||||
|     /// without the size of the personal system resource heap added to it.
 | ||||
|     u64 GetTotalPhysicalMemoryUsedWithoutSystemResource(); | ||||
| 
 | ||||
|     /// Gets the list of all threads created with this process as their owner.
 | ||||
|     std::list<KThread*>& GetThreadList() { | ||||
|         return m_thread_list; | ||||
|     } | ||||
| 
 | ||||
|     /// Registers a thread as being created under this process,
 | ||||
|     /// adding it to this process' thread list.
 | ||||
|     void RegisterThread(KThread* thread); | ||||
| 
 | ||||
|     /// Unregisters a thread from this process, removing it
 | ||||
|     /// from this process' thread list.
 | ||||
|     void UnregisterThread(KThread* thread); | ||||
| 
 | ||||
|     /// Retrieves the number of available threads for this process.
 | ||||
|     u64 GetFreeThreadCount() const; | ||||
| 
 | ||||
|     /// Clears the signaled state of the process if and only if it's signaled.
 | ||||
|     ///
 | ||||
|     /// @pre The process must not be already terminated. If this is called on a
 | ||||
|     ///      terminated process, then ResultInvalidState will be returned.
 | ||||
|     ///
 | ||||
|     /// @pre The process must be in a signaled state. If this is called on a
 | ||||
|     ///      process instance that is not signaled, ResultInvalidState will be
 | ||||
|     ///      returned.
 | ||||
|     Result Reset(); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Loads process-specifics configuration info with metadata provided | ||||
|      * by an executable. | ||||
|      * | ||||
|      * @param metadata The provided metadata to load process specific info from. | ||||
|      * | ||||
|      * @returns ResultSuccess if all relevant metadata was able to be | ||||
|      *          loaded and parsed. Otherwise, an error code is returned. | ||||
|      */ | ||||
|     Result LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size, | ||||
|                             bool is_hbl); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Starts the main application thread for this process. | ||||
|      * | ||||
|      * @param main_thread_priority The priority for the main thread. | ||||
|      * @param stack_size           The stack size for the main thread in bytes. | ||||
|      */ | ||||
|     void Run(s32 main_thread_priority, u64 stack_size); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Prepares a process for termination by stopping all of its threads | ||||
|      * and clearing any other resources. | ||||
|      */ | ||||
|     void PrepareForTermination(); | ||||
| 
 | ||||
|     void LoadModule(CodeSet code_set, KProcessAddress base_addr); | ||||
| 
 | ||||
|     bool IsInitialized() const override { | ||||
|         return m_is_initialized; | ||||
|     } | ||||
| 
 | ||||
|     static void PostDestroy(uintptr_t arg) {} | ||||
| 
 | ||||
|     void Finalize() override; | ||||
| 
 | ||||
|     u64 GetId() const override { | ||||
|         return GetProcessId(); | ||||
|     } | ||||
| 
 | ||||
|     bool IsHbl() const { | ||||
|         return m_is_hbl; | ||||
|     } | ||||
| 
 | ||||
|     bool IsSignaled() const override; | ||||
| 
 | ||||
|     void DoWorkerTaskImpl(); | ||||
| 
 | ||||
|     Result SetActivity(ProcessActivity activity); | ||||
| 
 | ||||
|     void PinCurrentThread(s32 core_id); | ||||
|     void UnpinCurrentThread(s32 core_id); | ||||
|     void UnpinThread(KThread* thread); | ||||
| 
 | ||||
|     KLightLock& GetStateLock() { | ||||
|         return m_state_lock; | ||||
|     } | ||||
| 
 | ||||
|     Result AddSharedMemory(KSharedMemory* shmem, KProcessAddress address, size_t size); | ||||
|     void RemoveSharedMemory(KSharedMemory* shmem, KProcessAddress address, size_t size); | ||||
| 
 | ||||
|     ///////////////////////////////////////////////////////////////////////////////////////////////
 | ||||
|     // Thread-local storage management
 | ||||
| 
 | ||||
|     // Marks the next available region as used and returns the address of the slot.
 | ||||
|     [[nodiscard]] Result CreateThreadLocalRegion(KProcessAddress* out); | ||||
| 
 | ||||
|     // Frees a used TLS slot identified by the given address
 | ||||
|     Result DeleteThreadLocalRegion(KProcessAddress addr); | ||||
| 
 | ||||
|     ///////////////////////////////////////////////////////////////////////////////////////////////
 | ||||
|     // Debug watchpoint management
 | ||||
| 
 | ||||
|     // Attempts to insert a watchpoint into a free slot. Returns false if none are available.
 | ||||
|     bool InsertWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointType type); | ||||
| 
 | ||||
|     // Attempts to remove the watchpoint specified by the given parameters.
 | ||||
|     bool RemoveWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointType type); | ||||
| 
 | ||||
|     const std::array<DebugWatchpoint, Core::Hardware::NUM_WATCHPOINTS>& GetWatchpoints() const { | ||||
|         return m_watchpoints; | ||||
|     } | ||||
| 
 | ||||
|     const std::string& GetName() { | ||||
|         return name; | ||||
|     } | ||||
|     static constexpr u64 ProcessIdMin = InitialProcessIdMax + 1; | ||||
|     static constexpr u64 ProcessIdMax = std::numeric_limits<u64>::max(); | ||||
| 
 | ||||
| private: | ||||
|     using SharedMemoryInfoList = Common::IntrusiveListBaseTraits<KSharedMemoryInfo>::ListType; | ||||
|     using TLPTree = | ||||
|         Common::IntrusiveRedBlackTreeBaseTraits<KThreadLocalPage>::TreeType<KThreadLocalPage>; | ||||
|     using TLPIterator = TLPTree::iterator; | ||||
| 
 | ||||
| private: | ||||
|     KPageTable m_page_table; | ||||
|     std::atomic<size_t> m_used_kernel_memory_size{}; | ||||
|     TLPTree m_fully_used_tlp_tree{}; | ||||
|     TLPTree m_partially_used_tlp_tree{}; | ||||
|     s32 m_ideal_core_id{}; | ||||
|     KResourceLimit* m_resource_limit{}; | ||||
|     KSystemResource* m_system_resource{}; | ||||
|     size_t m_memory_release_hint{}; | ||||
|     State m_state{}; | ||||
|     KLightLock m_state_lock; | ||||
|     KLightLock m_list_lock; | ||||
|     KConditionVariable m_cond_var; | ||||
|     KAddressArbiter m_address_arbiter; | ||||
|     std::array<u64, 4> m_entropy{}; | ||||
|     bool m_is_signaled{}; | ||||
|     bool m_is_initialized{}; | ||||
|     bool m_is_application{}; | ||||
|     bool m_is_default_application_system_resource{}; | ||||
|     bool m_is_hbl{}; | ||||
|     std::array<char, 13> m_name{}; | ||||
|     std::atomic<u16> m_num_running_threads{}; | ||||
|     Svc::CreateProcessFlag m_flags{}; | ||||
|     KMemoryManager::Pool m_memory_pool{}; | ||||
|     s64 m_schedule_count{}; | ||||
|     KCapabilities m_capabilities{}; | ||||
|     u64 m_program_id{}; | ||||
|     u64 m_process_id{}; | ||||
|     KProcessAddress m_code_address{}; | ||||
|     size_t m_code_size{}; | ||||
|     size_t m_main_thread_stack_size{}; | ||||
|     size_t m_max_process_memory{}; | ||||
|     u32 m_version{}; | ||||
|     KHandleTable m_handle_table; | ||||
|     KProcessAddress m_plr_address{}; | ||||
|     KThread* m_exception_thread{}; | ||||
|     ThreadList m_thread_list{}; | ||||
|     SharedMemoryInfoList m_shared_memory_list{}; | ||||
|     bool m_is_suspended{}; | ||||
|     bool m_is_immortal{}; | ||||
|     bool m_is_handle_table_initialized{}; | ||||
|     std::array<KThread*, Core::Hardware::NUM_CPU_CORES> m_running_threads{}; | ||||
|     std::array<u64, Core::Hardware::NUM_CPU_CORES> m_running_thread_idle_counts{}; | ||||
|     std::array<u64, Core::Hardware::NUM_CPU_CORES> m_running_thread_switch_counts{}; | ||||
|     std::array<KThread*, Core::Hardware::NUM_CPU_CORES> m_pinned_threads{}; | ||||
|     std::array<DebugWatchpoint, Core::Hardware::NUM_WATCHPOINTS> m_watchpoints{}; | ||||
|     std::map<KProcessAddress, u64> m_debug_page_refcounts{}; | ||||
|     std::atomic<s64> m_cpu_time{}; | ||||
|     std::atomic<s64> m_num_process_switches{}; | ||||
|     std::atomic<s64> m_num_thread_switches{}; | ||||
|     std::atomic<s64> m_num_fpu_switches{}; | ||||
|     std::atomic<s64> m_num_supervisor_calls{}; | ||||
|     std::atomic<s64> m_num_ipc_messages{}; | ||||
|     std::atomic<s64> m_num_ipc_replies{}; | ||||
|     std::atomic<s64> m_num_ipc_receives{}; | ||||
| 
 | ||||
| private: | ||||
|     Result StartTermination(); | ||||
|     void FinishTermination(); | ||||
| 
 | ||||
|     void PinThread(s32 core_id, KThread* thread) { | ||||
|         ASSERT(0 <= core_id && core_id < static_cast<s32>(Core::Hardware::NUM_CPU_CORES)); | ||||
|         ASSERT(thread != nullptr); | ||||
|  | @ -431,6 +138,395 @@ private: | |||
|         m_pinned_threads[core_id] = nullptr; | ||||
|     } | ||||
| 
 | ||||
| public: | ||||
|     explicit KProcess(KernelCore& kernel); | ||||
|     ~KProcess() override; | ||||
| 
 | ||||
|     Result Initialize(const Svc::CreateProcessParameter& params, KResourceLimit* res_limit, | ||||
|                       bool is_real); | ||||
| 
 | ||||
|     Result Initialize(const Svc::CreateProcessParameter& params, const KPageGroup& pg, | ||||
|                       std::span<const u32> caps, KResourceLimit* res_limit, | ||||
|                       KMemoryManager::Pool pool, bool immortal); | ||||
|     Result Initialize(const Svc::CreateProcessParameter& params, std::span<const u32> user_caps, | ||||
|                       KResourceLimit* res_limit, KMemoryManager::Pool pool); | ||||
|     void Exit(); | ||||
| 
 | ||||
|     const char* GetName() const { | ||||
|         return m_name.data(); | ||||
|     } | ||||
| 
 | ||||
|     u64 GetProgramId() const { | ||||
|         return m_program_id; | ||||
|     } | ||||
| 
 | ||||
|     u64 GetProcessId() const { | ||||
|         return m_process_id; | ||||
|     } | ||||
| 
 | ||||
|     State GetState() const { | ||||
|         return m_state; | ||||
|     } | ||||
| 
 | ||||
|     u64 GetCoreMask() const { | ||||
|         return m_capabilities.GetCoreMask(); | ||||
|     } | ||||
|     u64 GetPhysicalCoreMask() const { | ||||
|         return m_capabilities.GetPhysicalCoreMask(); | ||||
|     } | ||||
|     u64 GetPriorityMask() const { | ||||
|         return m_capabilities.GetPriorityMask(); | ||||
|     } | ||||
| 
 | ||||
|     s32 GetIdealCoreId() const { | ||||
|         return m_ideal_core_id; | ||||
|     } | ||||
|     void SetIdealCoreId(s32 core_id) { | ||||
|         m_ideal_core_id = core_id; | ||||
|     } | ||||
| 
 | ||||
|     bool CheckThreadPriority(s32 prio) const { | ||||
|         return ((1ULL << prio) & this->GetPriorityMask()) != 0; | ||||
|     } | ||||
| 
 | ||||
|     u32 GetCreateProcessFlags() const { | ||||
|         return static_cast<u32>(m_flags); | ||||
|     } | ||||
| 
 | ||||
|     bool Is64Bit() const { | ||||
|         return True(m_flags & Svc::CreateProcessFlag::Is64Bit); | ||||
|     } | ||||
| 
 | ||||
|     KProcessAddress GetEntryPoint() const { | ||||
|         return m_code_address; | ||||
|     } | ||||
| 
 | ||||
|     size_t GetMainStackSize() const { | ||||
|         return m_main_thread_stack_size; | ||||
|     } | ||||
| 
 | ||||
|     KMemoryManager::Pool GetMemoryPool() const { | ||||
|         return m_memory_pool; | ||||
|     } | ||||
| 
 | ||||
|     u64 GetRandomEntropy(size_t i) const { | ||||
|         return m_entropy[i]; | ||||
|     } | ||||
| 
 | ||||
|     bool IsApplication() const { | ||||
|         return m_is_application; | ||||
|     } | ||||
| 
 | ||||
|     bool IsDefaultApplicationSystemResource() const { | ||||
|         return m_is_default_application_system_resource; | ||||
|     } | ||||
| 
 | ||||
|     bool IsSuspended() const { | ||||
|         return m_is_suspended; | ||||
|     } | ||||
|     void SetSuspended(bool suspended) { | ||||
|         m_is_suspended = suspended; | ||||
|     } | ||||
| 
 | ||||
|     Result Terminate(); | ||||
| 
 | ||||
|     bool IsTerminated() const { | ||||
|         return m_state == State::Terminated; | ||||
|     } | ||||
| 
 | ||||
|     bool IsPermittedSvc(u32 svc_id) const { | ||||
|         return m_capabilities.IsPermittedSvc(svc_id); | ||||
|     } | ||||
| 
 | ||||
|     bool IsPermittedInterrupt(s32 interrupt_id) const { | ||||
|         return m_capabilities.IsPermittedInterrupt(interrupt_id); | ||||
|     } | ||||
| 
 | ||||
|     bool IsPermittedDebug() const { | ||||
|         return m_capabilities.IsPermittedDebug(); | ||||
|     } | ||||
| 
 | ||||
|     bool CanForceDebug() const { | ||||
|         return m_capabilities.CanForceDebug(); | ||||
|     } | ||||
| 
 | ||||
|     bool IsHbl() const { | ||||
|         return m_is_hbl; | ||||
|     } | ||||
| 
 | ||||
|     Kernel::KMemoryManager::Direction GetAllocateOption() const { | ||||
|         // TODO: property of the KPageTableBase
 | ||||
|         return KMemoryManager::Direction::FromFront; | ||||
|     } | ||||
| 
 | ||||
|     ThreadList& GetThreadList() { | ||||
|         return m_thread_list; | ||||
|     } | ||||
|     const ThreadList& GetThreadList() const { | ||||
|         return m_thread_list; | ||||
|     } | ||||
| 
 | ||||
|     bool EnterUserException(); | ||||
|     bool LeaveUserException(); | ||||
|     bool ReleaseUserException(KThread* thread); | ||||
| 
 | ||||
|     KThread* GetPinnedThread(s32 core_id) const { | ||||
|         ASSERT(0 <= core_id && core_id < static_cast<s32>(Core::Hardware::NUM_CPU_CORES)); | ||||
|         return m_pinned_threads[core_id]; | ||||
|     } | ||||
| 
 | ||||
|     const Svc::SvcAccessFlagSet& GetSvcPermissions() const { | ||||
|         return m_capabilities.GetSvcPermissions(); | ||||
|     } | ||||
| 
 | ||||
|     KResourceLimit* GetResourceLimit() const { | ||||
|         return m_resource_limit; | ||||
|     } | ||||
| 
 | ||||
|     bool ReserveResource(Svc::LimitableResource which, s64 value); | ||||
|     bool ReserveResource(Svc::LimitableResource which, s64 value, s64 timeout); | ||||
|     void ReleaseResource(Svc::LimitableResource which, s64 value); | ||||
|     void ReleaseResource(Svc::LimitableResource which, s64 value, s64 hint); | ||||
| 
 | ||||
|     KLightLock& GetStateLock() { | ||||
|         return m_state_lock; | ||||
|     } | ||||
|     KLightLock& GetListLock() { | ||||
|         return m_list_lock; | ||||
|     } | ||||
| 
 | ||||
|     KPageTable& GetPageTable() { | ||||
|         return m_page_table; | ||||
|     } | ||||
|     const KPageTable& GetPageTable() const { | ||||
|         return m_page_table; | ||||
|     } | ||||
| 
 | ||||
|     KHandleTable& GetHandleTable() { | ||||
|         return m_handle_table; | ||||
|     } | ||||
|     const KHandleTable& GetHandleTable() const { | ||||
|         return m_handle_table; | ||||
|     } | ||||
| 
 | ||||
|     size_t GetUsedUserPhysicalMemorySize() const; | ||||
|     size_t GetTotalUserPhysicalMemorySize() const; | ||||
|     size_t GetUsedNonSystemUserPhysicalMemorySize() const; | ||||
|     size_t GetTotalNonSystemUserPhysicalMemorySize() const; | ||||
| 
 | ||||
|     Result AddSharedMemory(KSharedMemory* shmem, KProcessAddress address, size_t size); | ||||
|     void RemoveSharedMemory(KSharedMemory* shmem, KProcessAddress address, size_t size); | ||||
| 
 | ||||
|     Result CreateThreadLocalRegion(KProcessAddress* out); | ||||
|     Result DeleteThreadLocalRegion(KProcessAddress addr); | ||||
| 
 | ||||
|     KProcessAddress GetProcessLocalRegionAddress() const { | ||||
|         return m_plr_address; | ||||
|     } | ||||
| 
 | ||||
|     KThread* GetExceptionThread() const { | ||||
|         return m_exception_thread; | ||||
|     } | ||||
| 
 | ||||
|     void AddCpuTime(s64 diff) { | ||||
|         m_cpu_time += diff; | ||||
|     } | ||||
|     s64 GetCpuTime() { | ||||
|         return m_cpu_time.load(); | ||||
|     } | ||||
| 
 | ||||
|     s64 GetScheduledCount() const { | ||||
|         return m_schedule_count; | ||||
|     } | ||||
|     void IncrementScheduledCount() { | ||||
|         ++m_schedule_count; | ||||
|     } | ||||
| 
 | ||||
|     void IncrementRunningThreadCount(); | ||||
|     void DecrementRunningThreadCount(); | ||||
| 
 | ||||
|     size_t GetRequiredSecureMemorySizeNonDefault() const { | ||||
|         if (!this->IsDefaultApplicationSystemResource() && m_system_resource->IsSecureResource()) { | ||||
|             auto* secure_system_resource = static_cast<KSecureSystemResource*>(m_system_resource); | ||||
|             return secure_system_resource->CalculateRequiredSecureMemorySize(); | ||||
|         } | ||||
| 
 | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
|     size_t GetRequiredSecureMemorySize() const { | ||||
|         if (m_system_resource->IsSecureResource()) { | ||||
|             auto* secure_system_resource = static_cast<KSecureSystemResource*>(m_system_resource); | ||||
|             return secure_system_resource->CalculateRequiredSecureMemorySize(); | ||||
|         } | ||||
| 
 | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
|     size_t GetTotalSystemResourceSize() const { | ||||
|         if (!this->IsDefaultApplicationSystemResource() && m_system_resource->IsSecureResource()) { | ||||
|             auto* secure_system_resource = static_cast<KSecureSystemResource*>(m_system_resource); | ||||
|             return secure_system_resource->GetSize(); | ||||
|         } | ||||
| 
 | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
|     size_t GetUsedSystemResourceSize() const { | ||||
|         if (!this->IsDefaultApplicationSystemResource() && m_system_resource->IsSecureResource()) { | ||||
|             auto* secure_system_resource = static_cast<KSecureSystemResource*>(m_system_resource); | ||||
|             return secure_system_resource->GetUsedSize(); | ||||
|         } | ||||
| 
 | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
|     void SetRunningThread(s32 core, KThread* thread, u64 idle_count, u64 switch_count) { | ||||
|         m_running_threads[core] = thread; | ||||
|         m_running_thread_idle_counts[core] = idle_count; | ||||
|         m_running_thread_switch_counts[core] = switch_count; | ||||
|     } | ||||
| 
 | ||||
|     void ClearRunningThread(KThread* thread) { | ||||
|         for (size_t i = 0; i < m_running_threads.size(); ++i) { | ||||
|             if (m_running_threads[i] == thread) { | ||||
|                 m_running_threads[i] = nullptr; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     const KSystemResource& GetSystemResource() const { | ||||
|         return *m_system_resource; | ||||
|     } | ||||
| 
 | ||||
|     const KMemoryBlockSlabManager& GetMemoryBlockSlabManager() const { | ||||
|         return m_system_resource->GetMemoryBlockSlabManager(); | ||||
|     } | ||||
|     const KBlockInfoManager& GetBlockInfoManager() const { | ||||
|         return m_system_resource->GetBlockInfoManager(); | ||||
|     } | ||||
|     const KPageTableManager& GetPageTableManager() const { | ||||
|         return m_system_resource->GetPageTableManager(); | ||||
|     } | ||||
| 
 | ||||
|     KThread* GetRunningThread(s32 core) const { | ||||
|         return m_running_threads[core]; | ||||
|     } | ||||
|     u64 GetRunningThreadIdleCount(s32 core) const { | ||||
|         return m_running_thread_idle_counts[core]; | ||||
|     } | ||||
|     u64 GetRunningThreadSwitchCount(s32 core) const { | ||||
|         return m_running_thread_switch_counts[core]; | ||||
|     } | ||||
| 
 | ||||
|     void RegisterThread(KThread* thread); | ||||
|     void UnregisterThread(KThread* thread); | ||||
| 
 | ||||
|     Result Run(s32 priority, size_t stack_size); | ||||
| 
 | ||||
|     Result Reset(); | ||||
| 
 | ||||
|     void SetDebugBreak() { | ||||
|         if (m_state == State::RunningAttached) { | ||||
|             this->ChangeState(State::DebugBreak); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void SetAttached() { | ||||
|         if (m_state == State::DebugBreak) { | ||||
|             this->ChangeState(State::RunningAttached); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     Result SetActivity(Svc::ProcessActivity activity); | ||||
| 
 | ||||
|     void PinCurrentThread(); | ||||
|     void UnpinCurrentThread(); | ||||
|     void UnpinThread(KThread* thread); | ||||
| 
 | ||||
|     void SignalConditionVariable(uintptr_t cv_key, int32_t count) { | ||||
|         return m_cond_var.Signal(cv_key, count); | ||||
|     } | ||||
| 
 | ||||
|     Result WaitConditionVariable(KProcessAddress address, uintptr_t cv_key, u32 tag, s64 ns) { | ||||
|         R_RETURN(m_cond_var.Wait(address, cv_key, tag, ns)); | ||||
|     } | ||||
| 
 | ||||
|     Result SignalAddressArbiter(uintptr_t address, Svc::SignalType signal_type, s32 value, | ||||
|                                 s32 count) { | ||||
|         R_RETURN(m_address_arbiter.SignalToAddress(address, signal_type, value, count)); | ||||
|     } | ||||
| 
 | ||||
|     Result WaitAddressArbiter(uintptr_t address, Svc::ArbitrationType arb_type, s32 value, | ||||
|                               s64 timeout) { | ||||
|         R_RETURN(m_address_arbiter.WaitForAddress(address, arb_type, value, timeout)); | ||||
|     } | ||||
| 
 | ||||
|     Result GetThreadList(s32* out_num_threads, KProcessAddress out_thread_ids, s32 max_out_count); | ||||
| 
 | ||||
|     static void Switch(KProcess* cur_process, KProcess* next_process); | ||||
| 
 | ||||
| public: | ||||
|     // Attempts to insert a watchpoint into a free slot. Returns false if none are available.
 | ||||
|     bool InsertWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointType type); | ||||
| 
 | ||||
|     // Attempts to remove the watchpoint specified by the given parameters.
 | ||||
|     bool RemoveWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointType type); | ||||
| 
 | ||||
|     const std::array<DebugWatchpoint, Core::Hardware::NUM_WATCHPOINTS>& GetWatchpoints() const { | ||||
|         return m_watchpoints; | ||||
|     } | ||||
| 
 | ||||
| public: | ||||
|     Result LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size, | ||||
|                             bool is_hbl); | ||||
| 
 | ||||
|     void LoadModule(CodeSet code_set, KProcessAddress base_addr); | ||||
| 
 | ||||
|     Core::Memory::Memory& GetMemory() const; | ||||
| 
 | ||||
| public: | ||||
|     // Overridden parent functions.
 | ||||
|     bool IsInitialized() const override { | ||||
|         return m_is_initialized; | ||||
|     } | ||||
| 
 | ||||
|     static void PostDestroy(uintptr_t arg) {} | ||||
| 
 | ||||
|     void Finalize() override; | ||||
| 
 | ||||
|     u64 GetIdImpl() const { | ||||
|         return this->GetProcessId(); | ||||
|     } | ||||
|     u64 GetId() const override { | ||||
|         return this->GetIdImpl(); | ||||
|     } | ||||
| 
 | ||||
|     virtual bool IsSignaled() const override { | ||||
|         ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(m_kernel)); | ||||
|         return m_is_signaled; | ||||
|     } | ||||
| 
 | ||||
|     void DoWorkerTaskImpl(); | ||||
| 
 | ||||
| private: | ||||
|     void ChangeState(State new_state) { | ||||
|         if (m_state != new_state) { | ||||
|             m_state = new_state; | ||||
|             m_is_signaled = true; | ||||
|             this->NotifyAvailable(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     Result InitializeHandleTable(s32 size) { | ||||
|         // Try to initialize the handle table.
 | ||||
|         R_TRY(m_handle_table.Initialize(size)); | ||||
| 
 | ||||
|         // We succeeded, so note that we did.
 | ||||
|         m_is_handle_table_initialized = true; | ||||
|         R_SUCCEED(); | ||||
|     } | ||||
| 
 | ||||
|     void FinalizeHandleTable() { | ||||
|         // Finalize the table.
 | ||||
|         m_handle_table.Finalize(); | ||||
|  | @ -438,118 +534,6 @@ private: | |||
|         // Note that the table is finalized.
 | ||||
|         m_is_handle_table_initialized = false; | ||||
|     } | ||||
| 
 | ||||
|     void ChangeState(State new_state); | ||||
| 
 | ||||
|     /// Allocates the main thread stack for the process, given the stack size in bytes.
 | ||||
|     Result AllocateMainThreadStack(std::size_t stack_size); | ||||
| 
 | ||||
|     /// Memory manager for this process
 | ||||
|     KPageTable m_page_table; | ||||
| 
 | ||||
|     /// Current status of the process
 | ||||
|     State m_state{}; | ||||
| 
 | ||||
|     /// The ID of this process
 | ||||
|     u64 m_process_id = 0; | ||||
| 
 | ||||
|     /// Title ID corresponding to the process
 | ||||
|     u64 m_program_id = 0; | ||||
| 
 | ||||
|     /// Specifies additional memory to be reserved for the process's memory management by the
 | ||||
|     /// system. When this is non-zero, secure memory is allocated and used for page table allocation
 | ||||
|     /// instead of using the normal global page tables/memory block management.
 | ||||
|     u32 m_system_resource_size = 0; | ||||
| 
 | ||||
|     /// Resource limit descriptor for this process
 | ||||
|     KResourceLimit* m_resource_limit{}; | ||||
| 
 | ||||
|     KVirtualAddress m_system_resource_address{}; | ||||
| 
 | ||||
|     /// The ideal CPU core for this process, threads are scheduled on this core by default.
 | ||||
|     u8 m_ideal_core = 0; | ||||
| 
 | ||||
|     /// Contains the parsed process capability descriptors.
 | ||||
|     ProcessCapabilities m_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.
 | ||||
|     bool m_is_64bit_process = true; | ||||
| 
 | ||||
|     /// Total running time for the process in ticks.
 | ||||
|     std::atomic<u64> m_total_process_running_time_ticks = 0; | ||||
| 
 | ||||
|     /// Per-process handle table for storing created object handles in.
 | ||||
|     KHandleTable m_handle_table; | ||||
| 
 | ||||
|     /// Per-process address arbiter.
 | ||||
|     KAddressArbiter m_address_arbiter; | ||||
| 
 | ||||
|     /// The per-process mutex lock instance used for handling various
 | ||||
|     /// forms of services, such as lock arbitration, and condition
 | ||||
|     /// variable related facilities.
 | ||||
|     KConditionVariable m_condition_var; | ||||
| 
 | ||||
|     /// Address indicating the location of the process' dedicated TLS region.
 | ||||
|     KProcessAddress m_plr_address = 0; | ||||
| 
 | ||||
|     /// Address indicating the location of the process's entry point.
 | ||||
|     KProcessAddress m_code_address = 0; | ||||
| 
 | ||||
|     /// Random values for svcGetInfo RandomEntropy
 | ||||
|     std::array<u64, RANDOM_ENTROPY_SIZE> m_random_entropy{}; | ||||
| 
 | ||||
|     /// List of threads that are running with this process as their owner.
 | ||||
|     std::list<KThread*> m_thread_list; | ||||
| 
 | ||||
|     /// List of shared memory that are running with this process as their owner.
 | ||||
|     std::list<KSharedMemoryInfo*> m_shared_memory_list; | ||||
| 
 | ||||
|     /// Address of the top of the main thread's stack
 | ||||
|     KProcessAddress m_main_thread_stack_top{}; | ||||
| 
 | ||||
|     /// Size of the main thread's stack
 | ||||
|     std::size_t m_main_thread_stack_size{}; | ||||
| 
 | ||||
|     /// Memory usage capacity for the process
 | ||||
|     std::size_t m_memory_usage_capacity{}; | ||||
| 
 | ||||
|     /// Process total image size
 | ||||
|     std::size_t m_image_size{}; | ||||
| 
 | ||||
|     /// Schedule count of this process
 | ||||
|     s64 m_schedule_count{}; | ||||
| 
 | ||||
|     size_t m_memory_release_hint{}; | ||||
| 
 | ||||
|     std::string name{}; | ||||
| 
 | ||||
|     bool m_is_signaled{}; | ||||
|     bool m_is_suspended{}; | ||||
|     bool m_is_immortal{}; | ||||
|     bool m_is_handle_table_initialized{}; | ||||
|     bool m_is_initialized{}; | ||||
|     bool m_is_hbl{}; | ||||
| 
 | ||||
|     std::atomic<u16> m_num_running_threads{}; | ||||
| 
 | ||||
|     std::array<KThread*, Core::Hardware::NUM_CPU_CORES> m_running_threads{}; | ||||
|     std::array<u64, Core::Hardware::NUM_CPU_CORES> m_running_thread_idle_counts{}; | ||||
|     std::array<KThread*, Core::Hardware::NUM_CPU_CORES> m_pinned_threads{}; | ||||
|     std::array<DebugWatchpoint, Core::Hardware::NUM_WATCHPOINTS> m_watchpoints{}; | ||||
|     std::map<KProcessAddress, u64> m_debug_page_refcounts; | ||||
| 
 | ||||
|     KThread* m_exception_thread{}; | ||||
| 
 | ||||
|     KLightLock m_state_lock; | ||||
|     KLightLock m_list_lock; | ||||
| 
 | ||||
|     using TLPTree = | ||||
|         Common::IntrusiveRedBlackTreeBaseTraits<KThreadLocalPage>::TreeType<KThreadLocalPage>; | ||||
|     using TLPIterator = TLPTree::iterator; | ||||
|     TLPTree m_fully_used_tlp_tree; | ||||
|     TLPTree m_partially_used_tlp_tree; | ||||
| }; | ||||
| 
 | ||||
| } // namespace Kernel
 | ||||
|  |  | |||
|  | @ -190,7 +190,7 @@ u64 KScheduler::UpdateHighestPriorityThread(KThread* highest_thread) { | |||
|         if (m_state.should_count_idle) { | ||||
|             if (highest_thread != nullptr) [[likely]] { | ||||
|                 if (KProcess* process = highest_thread->GetOwnerProcess(); process != nullptr) { | ||||
|                     process->SetRunningThread(m_core_id, highest_thread, m_state.idle_count); | ||||
|                     process->SetRunningThread(m_core_id, highest_thread, m_state.idle_count, 0); | ||||
|                 } | ||||
|             } else { | ||||
|                 m_state.idle_count++; | ||||
|  | @ -356,7 +356,7 @@ void KScheduler::SwitchThread(KThread* next_thread) { | |||
|     const s64 tick_diff = cur_tick - prev_tick; | ||||
|     cur_thread->AddCpuTime(m_core_id, tick_diff); | ||||
|     if (cur_process != nullptr) { | ||||
|         cur_process->UpdateCPUTimeTicks(tick_diff); | ||||
|         cur_process->AddCpuTime(tick_diff); | ||||
|     } | ||||
|     m_last_context_switch_time = cur_tick; | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,25 +1,100 @@ | |||
| // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #include "core/core.h" | ||||
| #include "core/hle/kernel/k_scoped_resource_reservation.h" | ||||
| #include "core/hle/kernel/k_system_resource.h" | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
| Result KSecureSystemResource::Initialize(size_t size, KResourceLimit* resource_limit, | ||||
|                                          KMemoryManager::Pool pool) { | ||||
|     // Unimplemented
 | ||||
|     UNREACHABLE(); | ||||
|     // Set members.
 | ||||
|     m_resource_limit = resource_limit; | ||||
|     m_resource_size = size; | ||||
|     m_resource_pool = pool; | ||||
| 
 | ||||
|     // Determine required size for our secure resource.
 | ||||
|     const size_t secure_size = this->CalculateRequiredSecureMemorySize(); | ||||
| 
 | ||||
|     // Reserve memory for our secure resource.
 | ||||
|     KScopedResourceReservation memory_reservation( | ||||
|         m_resource_limit, Svc::LimitableResource::PhysicalMemoryMax, secure_size); | ||||
|     R_UNLESS(memory_reservation.Succeeded(), ResultLimitReached); | ||||
| 
 | ||||
|     // Allocate secure memory.
 | ||||
|     R_TRY(KSystemControl::AllocateSecureMemory(m_kernel, std::addressof(m_resource_address), | ||||
|                                                m_resource_size, static_cast<u32>(m_resource_pool))); | ||||
|     ASSERT(m_resource_address != 0); | ||||
| 
 | ||||
|     // Ensure we clean up the secure memory, if we fail past this point.
 | ||||
|     ON_RESULT_FAILURE { | ||||
|         KSystemControl::FreeSecureMemory(m_kernel, m_resource_address, m_resource_size, | ||||
|                                          static_cast<u32>(m_resource_pool)); | ||||
|     }; | ||||
| 
 | ||||
|     // Check that our allocation is bigger than the reference counts needed for it.
 | ||||
|     const size_t rc_size = | ||||
|         Common::AlignUp(KPageTableSlabHeap::CalculateReferenceCountSize(m_resource_size), PageSize); | ||||
|     R_UNLESS(m_resource_size > rc_size, ResultOutOfMemory); | ||||
| 
 | ||||
|     // Get resource pointer.
 | ||||
|     KPhysicalAddress resource_paddr = | ||||
|         KPageTable::GetHeapPhysicalAddress(m_kernel.MemoryLayout(), m_resource_address); | ||||
|     auto* resource = | ||||
|         m_kernel.System().DeviceMemory().GetPointer<KPageTableManager::RefCount>(resource_paddr); | ||||
| 
 | ||||
|     // Initialize slab heaps.
 | ||||
|     m_dynamic_page_manager.Initialize(m_resource_address + rc_size, m_resource_size - rc_size, | ||||
|                                       PageSize); | ||||
|     m_page_table_heap.Initialize(std::addressof(m_dynamic_page_manager), 0, resource); | ||||
|     m_memory_block_heap.Initialize(std::addressof(m_dynamic_page_manager), 0); | ||||
|     m_block_info_heap.Initialize(std::addressof(m_dynamic_page_manager), 0); | ||||
| 
 | ||||
|     // Initialize managers.
 | ||||
|     m_page_table_manager.Initialize(std::addressof(m_dynamic_page_manager), | ||||
|                                     std::addressof(m_page_table_heap)); | ||||
|     m_memory_block_slab_manager.Initialize(std::addressof(m_dynamic_page_manager), | ||||
|                                            std::addressof(m_memory_block_heap)); | ||||
|     m_block_info_manager.Initialize(std::addressof(m_dynamic_page_manager), | ||||
|                                     std::addressof(m_block_info_heap)); | ||||
| 
 | ||||
|     // Set our managers.
 | ||||
|     this->SetManagers(m_memory_block_slab_manager, m_block_info_manager, m_page_table_manager); | ||||
| 
 | ||||
|     // Commit the memory reservation.
 | ||||
|     memory_reservation.Commit(); | ||||
| 
 | ||||
|     // Open reference to our resource limit.
 | ||||
|     m_resource_limit->Open(); | ||||
| 
 | ||||
|     // Set ourselves as initialized.
 | ||||
|     m_is_initialized = true; | ||||
| 
 | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| void KSecureSystemResource::Finalize() { | ||||
|     // Unimplemented
 | ||||
|     UNREACHABLE(); | ||||
|     // Check that we have no outstanding allocations.
 | ||||
|     ASSERT(m_memory_block_slab_manager.GetUsed() == 0); | ||||
|     ASSERT(m_block_info_manager.GetUsed() == 0); | ||||
|     ASSERT(m_page_table_manager.GetUsed() == 0); | ||||
| 
 | ||||
|     // Free our secure memory.
 | ||||
|     KSystemControl::FreeSecureMemory(m_kernel, m_resource_address, m_resource_size, | ||||
|                                      static_cast<u32>(m_resource_pool)); | ||||
| 
 | ||||
|     // Release the memory reservation.
 | ||||
|     m_resource_limit->Release(Svc::LimitableResource::PhysicalMemoryMax, | ||||
|                               this->CalculateRequiredSecureMemorySize()); | ||||
| 
 | ||||
|     // Close reference to our resource limit.
 | ||||
|     m_resource_limit->Close(); | ||||
| } | ||||
| 
 | ||||
| size_t KSecureSystemResource::CalculateRequiredSecureMemorySize(size_t size, | ||||
|                                                                 KMemoryManager::Pool pool) { | ||||
|     // Unimplemented
 | ||||
|     UNREACHABLE(); | ||||
|     return KSystemControl::CalculateRequiredSecureMemorySize(size, static_cast<u32>(pool)); | ||||
| } | ||||
| 
 | ||||
| } // namespace Kernel
 | ||||
|  |  | |||
|  | @ -122,16 +122,15 @@ Result KThread::Initialize(KThreadFunction func, uintptr_t arg, KProcessAddress | |||
|     case ThreadType::Main: | ||||
|         ASSERT(arg == 0); | ||||
|         [[fallthrough]]; | ||||
|     case ThreadType::HighPriority: | ||||
|         [[fallthrough]]; | ||||
|     case ThreadType::Dummy: | ||||
|         [[fallthrough]]; | ||||
|     case ThreadType::User: | ||||
|         ASSERT(((owner == nullptr) || | ||||
|                 (owner->GetCoreMask() | (1ULL << virt_core)) == owner->GetCoreMask())); | ||||
|         ASSERT(((owner == nullptr) || (prio > Svc::LowestThreadPriority) || | ||||
|                 (owner->GetPriorityMask() | (1ULL << prio)) == owner->GetPriorityMask())); | ||||
|         break; | ||||
|     case ThreadType::HighPriority: | ||||
|     case ThreadType::Dummy: | ||||
|         break; | ||||
|     case ThreadType::Kernel: | ||||
|         UNIMPLEMENTED(); | ||||
|         break; | ||||
|  | @ -403,7 +402,7 @@ void KThread::StartTermination() { | |||
|     if (m_parent != nullptr) { | ||||
|         m_parent->ReleaseUserException(this); | ||||
|         if (m_parent->GetPinnedThread(GetCurrentCoreId(m_kernel)) == this) { | ||||
|             m_parent->UnpinCurrentThread(m_core_id); | ||||
|             m_parent->UnpinCurrentThread(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -820,7 +819,7 @@ void KThread::CloneFpuStatus() { | |||
|     ASSERT(this->GetOwnerProcess() != nullptr); | ||||
|     ASSERT(this->GetOwnerProcess() == GetCurrentProcessPointer(m_kernel)); | ||||
| 
 | ||||
|     if (this->GetOwnerProcess()->Is64BitProcess()) { | ||||
|     if (this->GetOwnerProcess()->Is64Bit()) { | ||||
|         // Clone FPSR and FPCR.
 | ||||
|         ThreadContext64 cur_ctx{}; | ||||
|         m_kernel.System().CurrentArmInterface().SaveContext(cur_ctx); | ||||
|  | @ -923,7 +922,7 @@ Result KThread::GetThreadContext3(Common::ScratchBuffer<u8>& out) { | |||
| 
 | ||||
|         // If we're not terminating, get the thread's user context.
 | ||||
|         if (!this->IsTerminationRequested()) { | ||||
|             if (m_parent->Is64BitProcess()) { | ||||
|             if (m_parent->Is64Bit()) { | ||||
|                 // Mask away mode bits, interrupt bits, IL bit, and other reserved bits.
 | ||||
|                 auto context = GetContext64(); | ||||
|                 context.pstate &= 0xFF0FFE20; | ||||
|  | @ -1174,6 +1173,9 @@ Result KThread::Run() { | |||
|             owner->IncrementRunningThreadCount(); | ||||
|         } | ||||
| 
 | ||||
|         // Open a reference, now that we're running.
 | ||||
|         this->Open(); | ||||
| 
 | ||||
|         // Set our state and finish.
 | ||||
|         this->SetState(ThreadState::Runnable); | ||||
| 
 | ||||
|  |  | |||
|  | @ -721,6 +721,7 @@ private: | |||
|     // For core KThread implementation
 | ||||
|     ThreadContext32 m_thread_context_32{}; | ||||
|     ThreadContext64 m_thread_context_64{}; | ||||
|     Common::IntrusiveListNode m_process_list_node; | ||||
|     Common::IntrusiveRedBlackTreeNode m_condvar_arbiter_tree_node{}; | ||||
|     s32 m_priority{}; | ||||
|     using ConditionVariableThreadTreeTraits = | ||||
|  |  | |||
|  | @ -101,35 +101,31 @@ struct KernelCore::Impl { | |||
| 
 | ||||
|     void InitializeCores() { | ||||
|         for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { | ||||
|             cores[core_id]->Initialize((*application_process).Is64BitProcess()); | ||||
|             cores[core_id]->Initialize((*application_process).Is64Bit()); | ||||
|             system.ApplicationMemory().SetCurrentPageTable(*application_process, core_id); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void CloseApplicationProcess() { | ||||
|         KProcess* old_process = application_process.exchange(nullptr); | ||||
|         if (old_process == nullptr) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         // old_process->Close();
 | ||||
|         // TODO: The process should be destroyed based on accurate ref counting after
 | ||||
|         // calling Close(). Adding a manual Destroy() call instead to avoid a memory leak.
 | ||||
|         old_process->Finalize(); | ||||
|         old_process->Destroy(); | ||||
|     void TerminateApplicationProcess() { | ||||
|         application_process.load()->Terminate(); | ||||
|     } | ||||
| 
 | ||||
|     void Shutdown() { | ||||
|         is_shutting_down.store(true, std::memory_order_relaxed); | ||||
|         SCOPE_EXIT({ is_shutting_down.store(false, std::memory_order_relaxed); }); | ||||
| 
 | ||||
|         process_list.clear(); | ||||
| 
 | ||||
|         CloseServices(); | ||||
| 
 | ||||
|         auto* old_process = application_process.exchange(nullptr); | ||||
|         if (old_process) { | ||||
|             old_process->Close(); | ||||
|         } | ||||
| 
 | ||||
|         process_list.clear(); | ||||
| 
 | ||||
|         next_object_id = 0; | ||||
|         next_kernel_process_id = KProcess::InitialKIPIDMin; | ||||
|         next_user_process_id = KProcess::ProcessIDMin; | ||||
|         next_kernel_process_id = KProcess::InitialProcessIdMin; | ||||
|         next_user_process_id = KProcess::ProcessIdMin; | ||||
|         next_thread_id = 1; | ||||
| 
 | ||||
|         global_handle_table->Finalize(); | ||||
|  | @ -176,8 +172,6 @@ struct KernelCore::Impl { | |||
|             } | ||||
|         } | ||||
| 
 | ||||
|         CloseApplicationProcess(); | ||||
| 
 | ||||
|         // Track kernel objects that were not freed on shutdown
 | ||||
|         { | ||||
|             std::scoped_lock lk{registered_objects_lock}; | ||||
|  | @ -344,6 +338,8 @@ struct KernelCore::Impl { | |||
|         // Create the system page table managers.
 | ||||
|         app_system_resource = std::make_unique<KSystemResource>(kernel); | ||||
|         sys_system_resource = std::make_unique<KSystemResource>(kernel); | ||||
|         KAutoObject::Create(std::addressof(*app_system_resource)); | ||||
|         KAutoObject::Create(std::addressof(*sys_system_resource)); | ||||
| 
 | ||||
|         // Set the managers for the system resources.
 | ||||
|         app_system_resource->SetManagers(*app_memory_block_manager, *app_block_info_manager, | ||||
|  | @ -368,6 +364,7 @@ struct KernelCore::Impl { | |||
| 
 | ||||
|     void MakeApplicationProcess(KProcess* process) { | ||||
|         application_process = process; | ||||
|         application_process.load()->Open(); | ||||
|     } | ||||
| 
 | ||||
|     static inline thread_local u8 host_thread_id = UINT8_MAX; | ||||
|  | @ -792,8 +789,8 @@ struct KernelCore::Impl { | |||
|     std::mutex registered_in_use_objects_lock; | ||||
| 
 | ||||
|     std::atomic<u32> next_object_id{0}; | ||||
|     std::atomic<u64> next_kernel_process_id{KProcess::InitialKIPIDMin}; | ||||
|     std::atomic<u64> next_user_process_id{KProcess::ProcessIDMin}; | ||||
|     std::atomic<u64> next_kernel_process_id{KProcess::InitialProcessIdMin}; | ||||
|     std::atomic<u64> next_user_process_id{KProcess::ProcessIdMin}; | ||||
|     std::atomic<u64> next_thread_id{1}; | ||||
| 
 | ||||
|     // Lists all processes that exist in the current session.
 | ||||
|  | @ -924,10 +921,6 @@ const KProcess* KernelCore::ApplicationProcess() const { | |||
|     return impl->application_process; | ||||
| } | ||||
| 
 | ||||
| void KernelCore::CloseApplicationProcess() { | ||||
|     impl->CloseApplicationProcess(); | ||||
| } | ||||
| 
 | ||||
| const std::vector<KProcess*>& KernelCore::GetProcessList() const { | ||||
|     return impl->process_list; | ||||
| } | ||||
|  | @ -1128,8 +1121,8 @@ std::jthread KernelCore::RunOnHostCoreProcess(std::string&& process_name, | |||
|                                               std::function<void()> func) { | ||||
|     // Make a new process.
 | ||||
|     KProcess* process = KProcess::Create(*this); | ||||
|     ASSERT(R_SUCCEEDED(KProcess::Initialize(process, System(), "", KProcess::ProcessType::Userland, | ||||
|                                             GetSystemResourceLimit()))); | ||||
|     ASSERT(R_SUCCEEDED( | ||||
|         process->Initialize(Svc::CreateProcessParameter{}, GetSystemResourceLimit(), false))); | ||||
| 
 | ||||
|     // Ensure that we don't hold onto any extra references.
 | ||||
|     SCOPE_EXIT({ process->Close(); }); | ||||
|  | @ -1156,8 +1149,8 @@ void KernelCore::RunOnGuestCoreProcess(std::string&& process_name, std::function | |||
| 
 | ||||
|     // Make a new process.
 | ||||
|     KProcess* process = KProcess::Create(*this); | ||||
|     ASSERT(R_SUCCEEDED(KProcess::Initialize(process, System(), "", KProcess::ProcessType::Userland, | ||||
|                                             GetSystemResourceLimit()))); | ||||
|     ASSERT(R_SUCCEEDED( | ||||
|         process->Initialize(Svc::CreateProcessParameter{}, GetSystemResourceLimit(), false))); | ||||
| 
 | ||||
|     // Ensure that we don't hold onto any extra references.
 | ||||
|     SCOPE_EXIT({ process->Close(); }); | ||||
|  | @ -1266,7 +1259,8 @@ const Kernel::KSharedMemory& KernelCore::GetHidBusSharedMem() const { | |||
| 
 | ||||
| void KernelCore::SuspendApplication(bool suspended) { | ||||
|     const bool should_suspend{exception_exited || suspended}; | ||||
|     const auto activity = should_suspend ? ProcessActivity::Paused : ProcessActivity::Runnable; | ||||
|     const auto activity = | ||||
|         should_suspend ? Svc::ProcessActivity::Paused : Svc::ProcessActivity::Runnable; | ||||
| 
 | ||||
|     // Get the application process.
 | ||||
|     KScopedAutoObject<KProcess> process = ApplicationProcess(); | ||||
|  | @ -1300,6 +1294,8 @@ void KernelCore::SuspendApplication(bool suspended) { | |||
| } | ||||
| 
 | ||||
| void KernelCore::ShutdownCores() { | ||||
|     impl->TerminateApplicationProcess(); | ||||
| 
 | ||||
|     KScopedSchedulerLock lk{*this}; | ||||
| 
 | ||||
|     for (auto* thread : impl->shutdown_threads) { | ||||
|  |  | |||
|  | @ -134,9 +134,6 @@ public: | |||
|     /// Retrieves a const pointer to the application process.
 | ||||
|     const KProcess* ApplicationProcess() const; | ||||
| 
 | ||||
|     /// Closes the application process.
 | ||||
|     void CloseApplicationProcess(); | ||||
| 
 | ||||
|     /// Retrieves the list of processes.
 | ||||
|     const std::vector<KProcess*>& GetProcessList() const; | ||||
| 
 | ||||
|  |  | |||
|  | @ -4426,7 +4426,7 @@ void Call(Core::System& system, u32 imm) { | |||
|     auto& kernel = system.Kernel(); | ||||
|     kernel.EnterSVCProfile(); | ||||
| 
 | ||||
|     if (GetCurrentProcess(system.Kernel()).Is64BitProcess()) { | ||||
|     if (GetCurrentProcess(system.Kernel()).Is64Bit()) { | ||||
|         Call64(system, imm); | ||||
|     } else { | ||||
|         Call32(system, imm); | ||||
|  |  | |||
|  | @ -86,20 +86,19 @@ Result GetInfo(Core::System& system, u64* result, InfoType info_id_type, Handle | |||
|             R_SUCCEED(); | ||||
| 
 | ||||
|         case InfoType::TotalMemorySize: | ||||
|             *result = process->GetTotalPhysicalMemoryAvailable(); | ||||
|             *result = process->GetTotalUserPhysicalMemorySize(); | ||||
|             R_SUCCEED(); | ||||
| 
 | ||||
|         case InfoType::UsedMemorySize: | ||||
|             *result = process->GetTotalPhysicalMemoryUsed(); | ||||
|             *result = process->GetUsedUserPhysicalMemorySize(); | ||||
|             R_SUCCEED(); | ||||
| 
 | ||||
|         case InfoType::SystemResourceSizeTotal: | ||||
|             *result = process->GetSystemResourceSize(); | ||||
|             *result = process->GetTotalSystemResourceSize(); | ||||
|             R_SUCCEED(); | ||||
| 
 | ||||
|         case InfoType::SystemResourceSizeUsed: | ||||
|             LOG_WARNING(Kernel_SVC, "(STUBBED) Attempted to query system resource usage"); | ||||
|             *result = process->GetSystemResourceUsage(); | ||||
|             *result = process->GetUsedSystemResourceSize(); | ||||
|             R_SUCCEED(); | ||||
| 
 | ||||
|         case InfoType::ProgramId: | ||||
|  | @ -111,20 +110,29 @@ Result GetInfo(Core::System& system, u64* result, InfoType info_id_type, Handle | |||
|             R_SUCCEED(); | ||||
| 
 | ||||
|         case InfoType::TotalNonSystemMemorySize: | ||||
|             *result = process->GetTotalPhysicalMemoryAvailableWithoutSystemResource(); | ||||
|             *result = process->GetTotalNonSystemUserPhysicalMemorySize(); | ||||
|             R_SUCCEED(); | ||||
| 
 | ||||
|         case InfoType::UsedNonSystemMemorySize: | ||||
|             *result = process->GetTotalPhysicalMemoryUsedWithoutSystemResource(); | ||||
|             *result = process->GetUsedNonSystemUserPhysicalMemorySize(); | ||||
|             R_SUCCEED(); | ||||
| 
 | ||||
|         case InfoType::IsApplication: | ||||
|             LOG_WARNING(Kernel_SVC, "(STUBBED) Assuming process is application"); | ||||
|             *result = true; | ||||
|             *result = process->IsApplication(); | ||||
|             R_SUCCEED(); | ||||
| 
 | ||||
|         case InfoType::FreeThreadCount: | ||||
|             *result = process->GetFreeThreadCount(); | ||||
|             if (KResourceLimit* resource_limit = process->GetResourceLimit(); | ||||
|                 resource_limit != nullptr) { | ||||
|                 const auto current_value = | ||||
|                     resource_limit->GetCurrentValue(Svc::LimitableResource::ThreadCountMax); | ||||
|                 const auto limit_value = | ||||
|                     resource_limit->GetLimitValue(Svc::LimitableResource::ThreadCountMax); | ||||
|                 *result = limit_value - current_value; | ||||
|             } else { | ||||
|                 *result = 0; | ||||
|             } | ||||
|             R_SUCCEED(); | ||||
| 
 | ||||
|         default: | ||||
|  | @ -161,7 +169,7 @@ Result GetInfo(Core::System& system, u64* result, InfoType info_id_type, Handle | |||
| 
 | ||||
|     case InfoType::RandomEntropy: | ||||
|         R_UNLESS(handle == 0, ResultInvalidHandle); | ||||
|         R_UNLESS(info_sub_id < KProcess::RANDOM_ENTROPY_SIZE, ResultInvalidCombination); | ||||
|         R_UNLESS(info_sub_id < 4, ResultInvalidCombination); | ||||
| 
 | ||||
|         *result = GetCurrentProcess(system.Kernel()).GetRandomEntropy(info_sub_id); | ||||
|         R_SUCCEED(); | ||||
|  |  | |||
|  | @ -17,7 +17,7 @@ Result ArbitrateLock(Core::System& system, Handle thread_handle, u64 address, u3 | |||
|     R_UNLESS(!IsKernelAddress(address), ResultInvalidCurrentMemory); | ||||
|     R_UNLESS(Common::IsAligned(address, sizeof(u32)), ResultInvalidAddress); | ||||
| 
 | ||||
|     R_RETURN(GetCurrentProcess(system.Kernel()).WaitForAddress(thread_handle, address, tag)); | ||||
|     R_RETURN(KConditionVariable::WaitForAddress(system.Kernel(), thread_handle, address, tag)); | ||||
| } | ||||
| 
 | ||||
| /// Unlock a mutex
 | ||||
|  | @ -28,7 +28,7 @@ Result ArbitrateUnlock(Core::System& system, u64 address) { | |||
|     R_UNLESS(!IsKernelAddress(address), ResultInvalidCurrentMemory); | ||||
|     R_UNLESS(Common::IsAligned(address, sizeof(u32)), ResultInvalidAddress); | ||||
| 
 | ||||
|     R_RETURN(GetCurrentProcess(system.Kernel()).SignalToAddress(address)); | ||||
|     R_RETURN(KConditionVariable::SignalToAddress(system.Kernel(), address)); | ||||
| } | ||||
| 
 | ||||
| Result ArbitrateLock64(Core::System& system, Handle thread_handle, uint64_t address, uint32_t tag) { | ||||
|  |  | |||
|  | @ -46,7 +46,7 @@ Result MapPhysicalMemory(Core::System& system, u64 addr, u64 size) { | |||
|     KProcess* const current_process{GetCurrentProcessPointer(system.Kernel())}; | ||||
|     auto& page_table{current_process->GetPageTable()}; | ||||
| 
 | ||||
|     if (current_process->GetSystemResourceSize() == 0) { | ||||
|     if (current_process->GetTotalSystemResourceSize() == 0) { | ||||
|         LOG_ERROR(Kernel_SVC, "System Resource Size is zero"); | ||||
|         R_THROW(ResultInvalidState); | ||||
|     } | ||||
|  | @ -95,7 +95,7 @@ Result UnmapPhysicalMemory(Core::System& system, u64 addr, u64 size) { | |||
|     KProcess* const current_process{GetCurrentProcessPointer(system.Kernel())}; | ||||
|     auto& page_table{current_process->GetPageTable()}; | ||||
| 
 | ||||
|     if (current_process->GetSystemResourceSize() == 0) { | ||||
|     if (current_process->GetTotalSystemResourceSize() == 0) { | ||||
|         LOG_ERROR(Kernel_SVC, "System Resource Size is zero"); | ||||
|         R_THROW(ResultInvalidState); | ||||
|     } | ||||
|  |  | |||
|  | @ -132,7 +132,7 @@ void SynchronizePreemptionState(Core::System& system) { | |||
|         GetCurrentThread(kernel).ClearInterruptFlag(); | ||||
| 
 | ||||
|         // Unpin the current thread.
 | ||||
|         cur_process->UnpinCurrentThread(core_id); | ||||
|         cur_process->UnpinCurrentThread(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -85,10 +85,6 @@ Result StartThread(Core::System& system, Handle thread_handle) { | |||
|     // Try to start the thread.
 | ||||
|     R_TRY(thread->Run()); | ||||
| 
 | ||||
|     // If we succeeded, persist a reference to the thread.
 | ||||
|     thread->Open(); | ||||
|     system.Kernel().RegisterInUseObject(thread.GetPointerUnsafe()); | ||||
| 
 | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
|  | @ -99,7 +95,6 @@ void ExitThread(Core::System& system) { | |||
|     auto* const current_thread = GetCurrentThreadPointer(system.Kernel()); | ||||
|     system.GlobalSchedulerContext().RemoveThread(current_thread); | ||||
|     current_thread->Exit(); | ||||
|     system.Kernel().UnregisterInUseObject(current_thread); | ||||
| } | ||||
| 
 | ||||
| /// Sleep the current thread
 | ||||
|  | @ -260,7 +255,7 @@ Result GetThreadList(Core::System& system, s32* out_num_threads, u64 out_thread_ | |||
| 
 | ||||
|     auto list_iter = thread_list.cbegin(); | ||||
|     for (std::size_t i = 0; i < copy_amount; ++i, ++list_iter) { | ||||
|         memory.Write64(out_thread_ids, (*list_iter)->GetThreadId()); | ||||
|         memory.Write64(out_thread_ids, list_iter->GetThreadId()); | ||||
|         out_thread_ids += sizeof(u64); | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -592,7 +592,7 @@ void Call(Core::System& system, u32 imm) { | |||
|     auto& kernel = system.Kernel(); | ||||
|     kernel.EnterSVCProfile(); | ||||
| 
 | ||||
|     if (GetCurrentProcess(system.Kernel()).Is64BitProcess()) { | ||||
|     if (GetCurrentProcess(system.Kernel()).Is64Bit()) { | ||||
|         Call64(system, imm); | ||||
|     } else { | ||||
|         Call32(system, imm); | ||||
|  |  | |||
|  | @ -604,13 +604,57 @@ enum class ProcessActivity : u32 { | |||
|     Paused, | ||||
| }; | ||||
| 
 | ||||
| enum class CreateProcessFlag : u32 { | ||||
|     // Is 64 bit?
 | ||||
|     Is64Bit = (1 << 0), | ||||
| 
 | ||||
|     // What kind of address space?
 | ||||
|     AddressSpaceShift = 1, | ||||
|     AddressSpaceMask = (7 << AddressSpaceShift), | ||||
|     AddressSpace32Bit = (0 << AddressSpaceShift), | ||||
|     AddressSpace64BitDeprecated = (1 << AddressSpaceShift), | ||||
|     AddressSpace32BitWithoutAlias = (2 << AddressSpaceShift), | ||||
|     AddressSpace64Bit = (3 << AddressSpaceShift), | ||||
| 
 | ||||
|     // Should JIT debug be done on crash?
 | ||||
|     EnableDebug = (1 << 4), | ||||
| 
 | ||||
|     // Should ASLR be enabled for the process?
 | ||||
|     EnableAslr = (1 << 5), | ||||
| 
 | ||||
|     // Is the process an application?
 | ||||
|     IsApplication = (1 << 6), | ||||
| 
 | ||||
|     // 4.x deprecated: Should use secure memory?
 | ||||
|     DeprecatedUseSecureMemory = (1 << 7), | ||||
| 
 | ||||
|     // 5.x+ Pool partition type.
 | ||||
|     PoolPartitionShift = 7, | ||||
|     PoolPartitionMask = (0xF << PoolPartitionShift), | ||||
|     PoolPartitionApplication = (0 << PoolPartitionShift), | ||||
|     PoolPartitionApplet = (1 << PoolPartitionShift), | ||||
|     PoolPartitionSystem = (2 << PoolPartitionShift), | ||||
|     PoolPartitionSystemNonSecure = (3 << PoolPartitionShift), | ||||
| 
 | ||||
|     // 7.x+ Should memory allocation be optimized? This requires IsApplication.
 | ||||
|     OptimizeMemoryAllocation = (1 << 11), | ||||
| 
 | ||||
|     // 11.x+ DisableDeviceAddressSpaceMerge.
 | ||||
|     DisableDeviceAddressSpaceMerge = (1 << 12), | ||||
| 
 | ||||
|     // Mask of all flags.
 | ||||
|     All = Is64Bit | AddressSpaceMask | EnableDebug | EnableAslr | IsApplication | | ||||
|           PoolPartitionMask | OptimizeMemoryAllocation | DisableDeviceAddressSpaceMerge, | ||||
| }; | ||||
| DECLARE_ENUM_FLAG_OPERATORS(CreateProcessFlag); | ||||
| 
 | ||||
| struct CreateProcessParameter { | ||||
|     std::array<char, 12> name; | ||||
|     u32 version; | ||||
|     u64 program_id; | ||||
|     u64 code_address; | ||||
|     s32 code_num_pages; | ||||
|     u32 flags; | ||||
|     CreateProcessFlag flags; | ||||
|     Handle reslimit; | ||||
|     s32 system_resource_num_pages; | ||||
| }; | ||||
|  |  | |||
|  | @ -21,10 +21,8 @@ ServiceContext::ServiceContext(Core::System& system_, std::string name_) | |||
| 
 | ||||
|     // Create the process.
 | ||||
|     process = Kernel::KProcess::Create(kernel); | ||||
|     ASSERT(Kernel::KProcess::Initialize(process, system_, std::move(name_), | ||||
|                                         Kernel::KProcess::ProcessType::KernelInternal, | ||||
|                                         kernel.GetSystemResourceLimit()) | ||||
|                .IsSuccess()); | ||||
|     ASSERT(R_SUCCEEDED(process->Initialize(Kernel::Svc::CreateProcessParameter{}, | ||||
|                                            kernel.GetSystemResourceLimit(), false))); | ||||
| 
 | ||||
|     // Register the process.
 | ||||
|     Kernel::KProcess::Register(kernel, process); | ||||
|  |  | |||
|  | @ -66,7 +66,6 @@ Nvnflinger::Nvnflinger(Core::System& system_, HosBinderDriverServer& hos_binder_ | |||
|         "ScreenComposition", | ||||
|         [this](std::uintptr_t, s64 time, | ||||
|                std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { | ||||
|             { const auto lock_guard = Lock(); } | ||||
|             vsync_signal.Set(); | ||||
|             return std::chrono::nanoseconds(GetNextTicks()); | ||||
|         }); | ||||
|  | @ -99,6 +98,7 @@ Nvnflinger::~Nvnflinger() { | |||
|     } | ||||
| 
 | ||||
|     ShutdownLayers(); | ||||
|     vsync_thread = {}; | ||||
| 
 | ||||
|     if (nvdrv) { | ||||
|         nvdrv->Close(disp_fd); | ||||
|  | @ -106,6 +106,7 @@ Nvnflinger::~Nvnflinger() { | |||
| } | ||||
| 
 | ||||
| void Nvnflinger::ShutdownLayers() { | ||||
|     const auto lock_guard = Lock(); | ||||
|     for (auto& display : displays) { | ||||
|         for (size_t layer = 0; layer < display.GetNumLayers(); ++layer) { | ||||
|             display.GetLayer(layer).Core().NotifyShutdown(); | ||||
|  | @ -229,16 +230,6 @@ VI::Layer* Nvnflinger::FindLayer(u64 display_id, u64 layer_id) { | |||
|     return display->FindLayer(layer_id); | ||||
| } | ||||
| 
 | ||||
| const VI::Layer* Nvnflinger::FindLayer(u64 display_id, u64 layer_id) const { | ||||
|     const auto* const display = FindDisplay(display_id); | ||||
| 
 | ||||
|     if (display == nullptr) { | ||||
|         return nullptr; | ||||
|     } | ||||
| 
 | ||||
|     return display->FindLayer(layer_id); | ||||
| } | ||||
| 
 | ||||
| VI::Layer* Nvnflinger::FindOrCreateLayer(u64 display_id, u64 layer_id) { | ||||
|     auto* const display = FindDisplay(display_id); | ||||
| 
 | ||||
|  | @ -288,7 +279,6 @@ void Nvnflinger::Compose() { | |||
|         auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>(disp_fd); | ||||
|         ASSERT(nvdisp); | ||||
| 
 | ||||
|         guard->unlock(); | ||||
|         Common::Rectangle<int> crop_rect{ | ||||
|             static_cast<int>(buffer.crop.Left()), static_cast<int>(buffer.crop.Top()), | ||||
|             static_cast<int>(buffer.crop.Right()), static_cast<int>(buffer.crop.Bottom())}; | ||||
|  | @ -299,7 +289,6 @@ void Nvnflinger::Compose() { | |||
|                      buffer.fence.fences, buffer.fence.num_fences); | ||||
| 
 | ||||
|         MicroProfileFlip(); | ||||
|         guard->lock(); | ||||
| 
 | ||||
|         swap_interval = buffer.swap_interval; | ||||
| 
 | ||||
|  |  | |||
|  | @ -117,9 +117,6 @@ private: | |||
|     /// Finds the layer identified by the specified ID in the desired display.
 | ||||
|     [[nodiscard]] VI::Layer* FindLayer(u64 display_id, u64 layer_id); | ||||
| 
 | ||||
|     /// Finds the layer identified by the specified ID in the desired display.
 | ||||
|     [[nodiscard]] const VI::Layer* FindLayer(u64 display_id, u64 layer_id) const; | ||||
| 
 | ||||
|     /// Finds the layer identified by the specified ID in the desired display,
 | ||||
|     /// or creates the layer if it is not found.
 | ||||
|     /// To be used when the system expects the specified ID to already exist.
 | ||||
|  |  | |||
|  | @ -37,7 +37,7 @@ std::optional<Kernel::KProcess*> SearchProcessList( | |||
| void GetApplicationPidGeneric(HLERequestContext& ctx, | ||||
|                               const std::vector<Kernel::KProcess*>& process_list) { | ||||
|     const auto process = SearchProcessList(process_list, [](const auto& proc) { | ||||
|         return proc->GetProcessId() == Kernel::KProcess::ProcessIDMin; | ||||
|         return proc->GetProcessId() == Kernel::KProcess::ProcessIdMin; | ||||
|     }); | ||||
| 
 | ||||
|     IPC::ResponseBuilder rb{ctx, 4}; | ||||
|  |  | |||
|  | @ -116,7 +116,7 @@ json GetProcessorStateDataAuto(Core::System& system) { | |||
|     Core::ARM_Interface::ThreadContext64 context{}; | ||||
|     arm.SaveContext(context); | ||||
| 
 | ||||
|     return GetProcessorStateData(process->Is64BitProcess() ? "AArch64" : "AArch32", | ||||
|     return GetProcessorStateData(process->Is64Bit() ? "AArch64" : "AArch32", | ||||
|                                  GetInteger(process->GetEntryPoint()), context.sp, context.pc, | ||||
|                                  context.pstate, context.cpu_registers); | ||||
| } | ||||
|  |  | |||
|  | @ -127,7 +127,7 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() cons | |||
|         return list; | ||||
|     } | ||||
| 
 | ||||
|     if (thread.GetOwnerProcess() == nullptr || !thread.GetOwnerProcess()->Is64BitProcess()) { | ||||
|     if (thread.GetOwnerProcess() == nullptr || !thread.GetOwnerProcess()->Is64Bit()) { | ||||
|         return list; | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -2019,7 +2019,7 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t | |||
|             std::filesystem::path{Common::U16StringFromBuffer(filename.utf16(), filename.size())} | ||||
|                 .filename()); | ||||
|     } | ||||
|     const bool is_64bit = system->Kernel().ApplicationProcess()->Is64BitProcess(); | ||||
|     const bool is_64bit = system->Kernel().ApplicationProcess()->Is64Bit(); | ||||
|     const auto instruction_set_suffix = is_64bit ? tr("(64-bit)") : tr("(32-bit)"); | ||||
|     title_name = tr("%1 %2", "%1 is the title name. %2 indicates if the title is 64-bit or 32-bit") | ||||
|                      .arg(QString::fromStdString(title_name), instruction_set_suffix) | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Liam
						Liam