|
@@ -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
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
|
|
|
|
#pragma once
|
|
#pragma once
|
|
|
|
|
|
|
|
-#include <array>
|
|
|
|
|
-#include <cstddef>
|
|
|
|
|
-#include <list>
|
|
|
|
|
#include <map>
|
|
#include <map>
|
|
|
-#include <string>
|
|
|
|
|
|
|
+
|
|
|
|
|
+#include "core/hle/kernel/code_set.h"
|
|
|
#include "core/hle/kernel/k_address_arbiter.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_condition_variable.h"
|
|
|
#include "core/hle/kernel/k_handle_table.h"
|
|
#include "core/hle/kernel/k_handle_table.h"
|
|
|
#include "core/hle/kernel/k_page_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_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 {
|
|
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 {
|
|
enum class DebugWatchpointType : u8 {
|
|
|
None = 0,
|
|
None = 0,
|
|
|
Read = 1 << 0,
|
|
Read = 1 << 0,
|
|
@@ -72,9 +36,6 @@ class KProcess final : public KAutoObjectWithSlabHeapAndContainer<KProcess, KWor
|
|
|
KERNEL_AUTOOBJECT_TRAITS(KProcess, KSynchronizationObject);
|
|
KERNEL_AUTOOBJECT_TRAITS(KProcess, KSynchronizationObject);
|
|
|
|
|
|
|
|
public:
|
|
public:
|
|
|
- explicit KProcess(KernelCore& kernel);
|
|
|
|
|
- ~KProcess() override;
|
|
|
|
|
-
|
|
|
|
|
enum class State {
|
|
enum class State {
|
|
|
Created = static_cast<u32>(Svc::ProcessState::Created),
|
|
Created = static_cast<u32>(Svc::ProcessState::Created),
|
|
|
CreatedAttached = static_cast<u32>(Svc::ProcessState::CreatedAttached),
|
|
CreatedAttached = static_cast<u32>(Svc::ProcessState::CreatedAttached),
|
|
@@ -86,470 +47,493 @@ public:
|
|
|
DebugBreak = static_cast<u32>(Svc::ProcessState::DebugBreak),
|
|
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,
|
|
|
|
|
-
|
|
|
|
|
- /// Lowest allowed process ID for a userland process.
|
|
|
|
|
- ProcessIDMin = 81,
|
|
|
|
|
- /// Highest allowed process ID for a userland process.
|
|
|
|
|
- ProcessIDMax = 0xFFFFFFFFFFFFFFFF,
|
|
|
|
|
- };
|
|
|
|
|
|
|
+ using ThreadList = Common::IntrusiveListMemberTraits<&KThread::m_process_list_node>::ListType;
|
|
|
|
|
|
|
|
- // Used to determine how process IDs are assigned.
|
|
|
|
|
- enum class ProcessType {
|
|
|
|
|
- KernelInternal,
|
|
|
|
|
- Userland,
|
|
|
|
|
- };
|
|
|
|
|
|
|
+ static constexpr size_t AslrAlignment = 2_MiB;
|
|
|
|
|
|
|
|
- static constexpr std::size_t RANDOM_ENTROPY_SIZE = 4;
|
|
|
|
|
|
|
+public:
|
|
|
|
|
+ static constexpr u64 InitialProcessIdMin = 1;
|
|
|
|
|
+ static constexpr u64 InitialProcessIdMax = 0x50;
|
|
|
|
|
|
|
|
- static Result Initialize(KProcess* process, Core::System& system, std::string process_name,
|
|
|
|
|
- ProcessType type, KResourceLimit* res_limit);
|
|
|
|
|
|
|
+ static constexpr u64 ProcessIdMin = InitialProcessIdMax + 1;
|
|
|
|
|
+ static constexpr u64 ProcessIdMax = std::numeric_limits<u64>::max();
|
|
|
|
|
|
|
|
- /// Gets a reference to the process' page table.
|
|
|
|
|
- KPageTable& GetPageTable() {
|
|
|
|
|
- return m_page_table;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+private:
|
|
|
|
|
+ using SharedMemoryInfoList = Common::IntrusiveListBaseTraits<KSharedMemoryInfo>::ListType;
|
|
|
|
|
+ using TLPTree =
|
|
|
|
|
+ Common::IntrusiveRedBlackTreeBaseTraits<KThreadLocalPage>::TreeType<KThreadLocalPage>;
|
|
|
|
|
+ using TLPIterator = TLPTree::iterator;
|
|
|
|
|
|
|
|
- /// Gets const a reference to the process' page table.
|
|
|
|
|
- const KPageTable& GetPageTable() const {
|
|
|
|
|
- return m_page_table;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+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{};
|
|
|
|
|
|
|
|
- /// Gets a reference to the process' handle table.
|
|
|
|
|
- KHandleTable& GetHandleTable() {
|
|
|
|
|
- return m_handle_table;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+private:
|
|
|
|
|
+ Result StartTermination();
|
|
|
|
|
+ void FinishTermination();
|
|
|
|
|
|
|
|
- /// Gets a const reference to the process' handle table.
|
|
|
|
|
- const KHandleTable& GetHandleTable() const {
|
|
|
|
|
- return m_handle_table;
|
|
|
|
|
|
|
+ void PinThread(s32 core_id, KThread* thread) {
|
|
|
|
|
+ ASSERT(0 <= core_id && core_id < static_cast<s32>(Core::Hardware::NUM_CPU_CORES));
|
|
|
|
|
+ ASSERT(thread != nullptr);
|
|
|
|
|
+ ASSERT(m_pinned_threads[core_id] == nullptr);
|
|
|
|
|
+ m_pinned_threads[core_id] = thread;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /// Gets a reference to process's memory.
|
|
|
|
|
- Core::Memory::Memory& GetMemory() const;
|
|
|
|
|
-
|
|
|
|
|
- Result SignalToAddress(KProcessAddress address) {
|
|
|
|
|
- return m_condition_var.SignalToAddress(address);
|
|
|
|
|
|
|
+ void UnpinThread(s32 core_id, KThread* thread) {
|
|
|
|
|
+ ASSERT(0 <= core_id && core_id < static_cast<s32>(Core::Hardware::NUM_CPU_CORES));
|
|
|
|
|
+ ASSERT(thread != nullptr);
|
|
|
|
|
+ ASSERT(m_pinned_threads[core_id] == thread);
|
|
|
|
|
+ m_pinned_threads[core_id] = nullptr;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- Result WaitForAddress(Handle handle, KProcessAddress address, u32 tag) {
|
|
|
|
|
- return m_condition_var.WaitForAddress(handle, address, tag);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+public:
|
|
|
|
|
+ explicit KProcess(KernelCore& kernel);
|
|
|
|
|
+ ~KProcess() override;
|
|
|
|
|
|
|
|
- void SignalConditionVariable(u64 cv_key, int32_t count) {
|
|
|
|
|
- return m_condition_var.Signal(cv_key, count);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ Result Initialize(const Svc::CreateProcessParameter& params, KResourceLimit* res_limit,
|
|
|
|
|
+ bool is_real);
|
|
|
|
|
|
|
|
- Result WaitConditionVariable(KProcessAddress address, u64 cv_key, u32 tag, s64 ns) {
|
|
|
|
|
- R_RETURN(m_condition_var.Wait(address, cv_key, tag, ns));
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ 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();
|
|
|
|
|
|
|
|
- Result SignalAddressArbiter(uint64_t address, Svc::SignalType signal_type, s32 value,
|
|
|
|
|
- s32 count) {
|
|
|
|
|
- R_RETURN(m_address_arbiter.SignalToAddress(address, signal_type, value, count));
|
|
|
|
|
|
|
+ const char* GetName() const {
|
|
|
|
|
+ return m_name.data();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- Result WaitAddressArbiter(uint64_t address, Svc::ArbitrationType arb_type, s32 value,
|
|
|
|
|
- s64 timeout) {
|
|
|
|
|
- R_RETURN(m_address_arbiter.WaitForAddress(address, arb_type, value, timeout));
|
|
|
|
|
|
|
+ u64 GetProgramId() const {
|
|
|
|
|
+ return m_program_id;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- KProcessAddress GetProcessLocalRegionAddress() const {
|
|
|
|
|
- return m_plr_address;
|
|
|
|
|
|
|
+ u64 GetProcessId() const {
|
|
|
|
|
+ return m_process_id;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /// Gets the current status of the process
|
|
|
|
|
State GetState() const {
|
|
State GetState() const {
|
|
|
return m_state;
|
|
return m_state;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /// Gets the unique ID that identifies this particular process.
|
|
|
|
|
- u64 GetProcessId() const {
|
|
|
|
|
- return m_process_id;
|
|
|
|
|
|
|
+ u64 GetCoreMask() const {
|
|
|
|
|
+ return m_capabilities.GetCoreMask();
|
|
|
|
|
+ }
|
|
|
|
|
+ u64 GetPhysicalCoreMask() const {
|
|
|
|
|
+ return m_capabilities.GetPhysicalCoreMask();
|
|
|
|
|
+ }
|
|
|
|
|
+ u64 GetPriorityMask() const {
|
|
|
|
|
+ return m_capabilities.GetPriorityMask();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /// Gets the program ID corresponding to this process.
|
|
|
|
|
- u64 GetProgramId() const {
|
|
|
|
|
- return m_program_id;
|
|
|
|
|
|
|
+ s32 GetIdealCoreId() const {
|
|
|
|
|
+ return m_ideal_core_id;
|
|
|
|
|
+ }
|
|
|
|
|
+ void SetIdealCoreId(s32 core_id) {
|
|
|
|
|
+ m_ideal_core_id = core_id;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- KProcessAddress GetEntryPoint() const {
|
|
|
|
|
- return m_code_address;
|
|
|
|
|
|
|
+ bool CheckThreadPriority(s32 prio) const {
|
|
|
|
|
+ return ((1ULL << prio) & this->GetPriorityMask()) != 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /// Gets the resource limit descriptor for this process
|
|
|
|
|
- KResourceLimit* GetResourceLimit() const;
|
|
|
|
|
|
|
+ u32 GetCreateProcessFlags() const {
|
|
|
|
|
+ return static_cast<u32>(m_flags);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- /// Gets the ideal CPU core ID for this process
|
|
|
|
|
- u8 GetIdealCoreId() const {
|
|
|
|
|
- return m_ideal_core;
|
|
|
|
|
|
|
+ bool Is64Bit() const {
|
|
|
|
|
+ return True(m_flags & Svc::CreateProcessFlag::Is64Bit);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /// Checks if the specified thread priority is valid.
|
|
|
|
|
- bool CheckThreadPriority(s32 prio) const {
|
|
|
|
|
- return ((1ULL << prio) & GetPriorityMask()) != 0;
|
|
|
|
|
|
|
+ KProcessAddress GetEntryPoint() const {
|
|
|
|
|
+ return m_code_address;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /// Gets the bitmask of allowed cores that this process' threads can run on.
|
|
|
|
|
- u64 GetCoreMask() const {
|
|
|
|
|
- return m_capabilities.GetCoreMask();
|
|
|
|
|
|
|
+ size_t GetMainStackSize() const {
|
|
|
|
|
+ return m_main_thread_stack_size;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /// Gets the bitmask of allowed thread priorities.
|
|
|
|
|
- u64 GetPriorityMask() const {
|
|
|
|
|
- return m_capabilities.GetPriorityMask();
|
|
|
|
|
|
|
+ KMemoryManager::Pool GetMemoryPool() const {
|
|
|
|
|
+ return m_memory_pool;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /// Gets the amount of secure memory to allocate for memory management.
|
|
|
|
|
- u32 GetSystemResourceSize() const {
|
|
|
|
|
- return m_system_resource_size;
|
|
|
|
|
|
|
+ u64 GetRandomEntropy(size_t i) const {
|
|
|
|
|
+ return m_entropy[i];
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /// 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;
|
|
|
|
|
|
|
+ bool IsApplication() const {
|
|
|
|
|
+ return m_is_application;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /// Whether this process is an AArch64 or AArch32 process.
|
|
|
|
|
- bool Is64BitProcess() const {
|
|
|
|
|
- return m_is_64bit_process;
|
|
|
|
|
|
|
+ bool IsDefaultApplicationSystemResource() const {
|
|
|
|
|
+ return m_is_default_application_system_resource;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
bool IsSuspended() const {
|
|
bool IsSuspended() const {
|
|
|
return m_is_suspended;
|
|
return m_is_suspended;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
void SetSuspended(bool suspended) {
|
|
void SetSuspended(bool suspended) {
|
|
|
m_is_suspended = 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;
|
|
|
|
|
|
|
+ Result Terminate();
|
|
|
|
|
+
|
|
|
|
|
+ bool IsTerminated() const {
|
|
|
|
|
+ return m_state == State::Terminated;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /// Updates the total running time, adding the given ticks to it.
|
|
|
|
|
- void UpdateCPUTimeTicks(u64 ticks) {
|
|
|
|
|
- m_total_process_running_time_ticks += ticks;
|
|
|
|
|
|
|
+ bool IsPermittedSvc(u32 svc_id) const {
|
|
|
|
|
+ return m_capabilities.IsPermittedSvc(svc_id);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /// Gets the process schedule count, used for thread yielding
|
|
|
|
|
- s64 GetScheduledCount() const {
|
|
|
|
|
- return m_schedule_count;
|
|
|
|
|
|
|
+ bool IsPermittedInterrupt(s32 interrupt_id) const {
|
|
|
|
|
+ return m_capabilities.IsPermittedInterrupt(interrupt_id);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /// Increments the process schedule count, used for thread yielding.
|
|
|
|
|
- void IncrementScheduledCount() {
|
|
|
|
|
- ++m_schedule_count;
|
|
|
|
|
|
|
+ bool IsPermittedDebug() const {
|
|
|
|
|
+ return m_capabilities.IsPermittedDebug();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- void IncrementRunningThreadCount();
|
|
|
|
|
- void DecrementRunningThreadCount();
|
|
|
|
|
|
|
+ bool CanForceDebug() const {
|
|
|
|
|
+ return m_capabilities.CanForceDebug();
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- void SetRunningThread(s32 core, KThread* thread, u64 idle_count) {
|
|
|
|
|
- m_running_threads[core] = thread;
|
|
|
|
|
- m_running_thread_idle_counts[core] = idle_count;
|
|
|
|
|
|
|
+ bool IsHbl() const {
|
|
|
|
|
+ return m_is_hbl;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- 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;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ Kernel::KMemoryManager::Direction GetAllocateOption() const {
|
|
|
|
|
+ // TODO: property of the KPageTableBase
|
|
|
|
|
+ return KMemoryManager::Direction::FromFront;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- [[nodiscard]] KThread* GetRunningThread(s32 core) const {
|
|
|
|
|
- return m_running_threads[core];
|
|
|
|
|
|
|
+ ThreadList& GetThreadList() {
|
|
|
|
|
+ return m_thread_list;
|
|
|
|
|
+ }
|
|
|
|
|
+ const ThreadList& GetThreadList() const {
|
|
|
|
|
+ return m_thread_list;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ bool EnterUserException();
|
|
|
|
|
+ bool LeaveUserException();
|
|
|
bool ReleaseUserException(KThread* thread);
|
|
bool ReleaseUserException(KThread* thread);
|
|
|
|
|
|
|
|
- [[nodiscard]] KThread* GetPinnedThread(s32 core_id) const {
|
|
|
|
|
|
|
+ KThread* GetPinnedThread(s32 core_id) const {
|
|
|
ASSERT(0 <= core_id && core_id < static_cast<s32>(Core::Hardware::NUM_CPU_CORES));
|
|
ASSERT(0 <= core_id && core_id < static_cast<s32>(Core::Hardware::NUM_CPU_CORES));
|
|
|
return m_pinned_threads[core_id];
|
|
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);
|
|
|
|
|
|
|
+ const Svc::SvcAccessFlagSet& GetSvcPermissions() const {
|
|
|
|
|
+ return m_capabilities.GetSvcPermissions();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /// 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;
|
|
|
|
|
|
|
+ KResourceLimit* GetResourceLimit() const {
|
|
|
|
|
+ return m_resource_limit;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /// Registers a thread as being created under this process,
|
|
|
|
|
- /// adding it to this process' thread list.
|
|
|
|
|
- void RegisterThread(KThread* thread);
|
|
|
|
|
|
|
+ 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);
|
|
|
|
|
|
|
|
- /// Unregisters a thread from this process, removing it
|
|
|
|
|
- /// from this process' thread list.
|
|
|
|
|
- void UnregisterThread(KThread* thread);
|
|
|
|
|
|
|
+ KLightLock& GetStateLock() {
|
|
|
|
|
+ return m_state_lock;
|
|
|
|
|
+ }
|
|
|
|
|
+ KLightLock& GetListLock() {
|
|
|
|
|
+ return m_list_lock;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- /// 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();
|
|
|
|
|
|
|
+ KPageTable& GetPageTable() {
|
|
|
|
|
+ return m_page_table;
|
|
|
|
|
+ }
|
|
|
|
|
+ const KPageTable& GetPageTable() const {
|
|
|
|
|
+ return m_page_table;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- /**
|
|
|
|
|
- * 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);
|
|
|
|
|
|
|
+ KHandleTable& GetHandleTable() {
|
|
|
|
|
+ return m_handle_table;
|
|
|
|
|
+ }
|
|
|
|
|
+ const KHandleTable& GetHandleTable() const {
|
|
|
|
|
+ return m_handle_table;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- /**
|
|
|
|
|
- * 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);
|
|
|
|
|
|
|
+ size_t GetUsedUserPhysicalMemorySize() const;
|
|
|
|
|
+ size_t GetTotalUserPhysicalMemorySize() const;
|
|
|
|
|
+ size_t GetUsedNonSystemUserPhysicalMemorySize() const;
|
|
|
|
|
+ size_t GetTotalNonSystemUserPhysicalMemorySize() const;
|
|
|
|
|
|
|
|
- /**
|
|
|
|
|
- * Prepares a process for termination by stopping all of its threads
|
|
|
|
|
- * and clearing any other resources.
|
|
|
|
|
- */
|
|
|
|
|
- void PrepareForTermination();
|
|
|
|
|
|
|
+ Result AddSharedMemory(KSharedMemory* shmem, KProcessAddress address, size_t size);
|
|
|
|
|
+ void RemoveSharedMemory(KSharedMemory* shmem, KProcessAddress address, size_t size);
|
|
|
|
|
|
|
|
- void LoadModule(CodeSet code_set, KProcessAddress base_addr);
|
|
|
|
|
|
|
+ Result CreateThreadLocalRegion(KProcessAddress* out);
|
|
|
|
|
+ Result DeleteThreadLocalRegion(KProcessAddress addr);
|
|
|
|
|
|
|
|
- bool IsInitialized() const override {
|
|
|
|
|
- return m_is_initialized;
|
|
|
|
|
|
|
+ KProcessAddress GetProcessLocalRegionAddress() const {
|
|
|
|
|
+ return m_plr_address;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- static void PostDestroy(uintptr_t arg) {}
|
|
|
|
|
-
|
|
|
|
|
- void Finalize() override;
|
|
|
|
|
-
|
|
|
|
|
- u64 GetId() const override {
|
|
|
|
|
- return GetProcessId();
|
|
|
|
|
|
|
+ KThread* GetExceptionThread() const {
|
|
|
|
|
+ return m_exception_thread;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- bool IsHbl() const {
|
|
|
|
|
- return m_is_hbl;
|
|
|
|
|
|
|
+ void AddCpuTime(s64 diff) {
|
|
|
|
|
+ m_cpu_time += diff;
|
|
|
|
|
+ }
|
|
|
|
|
+ s64 GetCpuTime() {
|
|
|
|
|
+ return m_cpu_time.load();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- bool IsSignaled() const override;
|
|
|
|
|
-
|
|
|
|
|
- void DoWorkerTaskImpl();
|
|
|
|
|
|
|
+ s64 GetScheduledCount() const {
|
|
|
|
|
+ return m_schedule_count;
|
|
|
|
|
+ }
|
|
|
|
|
+ void IncrementScheduledCount() {
|
|
|
|
|
+ ++m_schedule_count;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- Result SetActivity(ProcessActivity activity);
|
|
|
|
|
|
|
+ void IncrementRunningThreadCount();
|
|
|
|
|
+ void DecrementRunningThreadCount();
|
|
|
|
|
|
|
|
- void PinCurrentThread(s32 core_id);
|
|
|
|
|
- void UnpinCurrentThread(s32 core_id);
|
|
|
|
|
- void UnpinThread(KThread* thread);
|
|
|
|
|
|
|
+ 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();
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- KLightLock& GetStateLock() {
|
|
|
|
|
- return m_state_lock;
|
|
|
|
|
|
|
+ return 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- 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);
|
|
|
|
|
|
|
+ size_t GetRequiredSecureMemorySize() const {
|
|
|
|
|
+ if (m_system_resource->IsSecureResource()) {
|
|
|
|
|
+ auto* secure_system_resource = static_cast<KSecureSystemResource*>(m_system_resource);
|
|
|
|
|
+ return secure_system_resource->CalculateRequiredSecureMemorySize();
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // Frees a used TLS slot identified by the given address
|
|
|
|
|
- Result DeleteThreadLocalRegion(KProcessAddress addr);
|
|
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- ///////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
- // Debug watchpoint management
|
|
|
|
|
|
|
+ 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();
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // Attempts to insert a watchpoint into a free slot. Returns false if none are available.
|
|
|
|
|
- bool InsertWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointType type);
|
|
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // Attempts to remove the watchpoint specified by the given parameters.
|
|
|
|
|
- bool RemoveWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointType type);
|
|
|
|
|
|
|
+ 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();
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- const std::array<DebugWatchpoint, Core::Hardware::NUM_WATCHPOINTS>& GetWatchpoints() const {
|
|
|
|
|
- return m_watchpoints;
|
|
|
|
|
|
|
+ return 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- const std::string& GetName() {
|
|
|
|
|
- return name;
|
|
|
|
|
|
|
+ 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;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-private:
|
|
|
|
|
- void PinThread(s32 core_id, KThread* thread) {
|
|
|
|
|
- ASSERT(0 <= core_id && core_id < static_cast<s32>(Core::Hardware::NUM_CPU_CORES));
|
|
|
|
|
- ASSERT(thread != nullptr);
|
|
|
|
|
- ASSERT(m_pinned_threads[core_id] == nullptr);
|
|
|
|
|
- m_pinned_threads[core_id] = thread;
|
|
|
|
|
|
|
+ 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;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- void UnpinThread(s32 core_id, KThread* thread) {
|
|
|
|
|
- ASSERT(0 <= core_id && core_id < static_cast<s32>(Core::Hardware::NUM_CPU_CORES));
|
|
|
|
|
- ASSERT(thread != nullptr);
|
|
|
|
|
- ASSERT(m_pinned_threads[core_id] == thread);
|
|
|
|
|
- m_pinned_threads[core_id] = nullptr;
|
|
|
|
|
|
|
+ const KSystemResource& GetSystemResource() const {
|
|
|
|
|
+ return *m_system_resource;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- void FinalizeHandleTable() {
|
|
|
|
|
- // Finalize the table.
|
|
|
|
|
- m_handle_table.Finalize();
|
|
|
|
|
-
|
|
|
|
|
- // Note that the table is finalized.
|
|
|
|
|
- m_is_handle_table_initialized = false;
|
|
|
|
|
|
|
+ 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();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- 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{};
|
|
|
|
|
|
|
+ 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];
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- /// The ID of this process
|
|
|
|
|
- u64 m_process_id = 0;
|
|
|
|
|
|
|
+ void RegisterThread(KThread* thread);
|
|
|
|
|
+ void UnregisterThread(KThread* thread);
|
|
|
|
|
|
|
|
- /// Title ID corresponding to the process
|
|
|
|
|
- u64 m_program_id = 0;
|
|
|
|
|
|
|
+ Result Run(s32 priority, size_t stack_size);
|
|
|
|
|
|
|
|
- /// 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;
|
|
|
|
|
|
|
+ Result Reset();
|
|
|
|
|
|
|
|
- /// Resource limit descriptor for this process
|
|
|
|
|
- KResourceLimit* m_resource_limit{};
|
|
|
|
|
|
|
+ void SetDebugBreak() {
|
|
|
|
|
+ if (m_state == State::RunningAttached) {
|
|
|
|
|
+ this->ChangeState(State::DebugBreak);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- KVirtualAddress m_system_resource_address{};
|
|
|
|
|
|
|
+ void SetAttached() {
|
|
|
|
|
+ if (m_state == State::DebugBreak) {
|
|
|
|
|
+ this->ChangeState(State::RunningAttached);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- /// The ideal CPU core for this process, threads are scheduled on this core by default.
|
|
|
|
|
- u8 m_ideal_core = 0;
|
|
|
|
|
|
|
+ Result SetActivity(Svc::ProcessActivity activity);
|
|
|
|
|
|
|
|
- /// Contains the parsed process capability descriptors.
|
|
|
|
|
- ProcessCapabilities m_capabilities;
|
|
|
|
|
|
|
+ void PinCurrentThread();
|
|
|
|
|
+ void UnpinCurrentThread();
|
|
|
|
|
+ void UnpinThread(KThread* thread);
|
|
|
|
|
|
|
|
- /// 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;
|
|
|
|
|
|
|
+ void SignalConditionVariable(uintptr_t cv_key, int32_t count) {
|
|
|
|
|
+ return m_cond_var.Signal(cv_key, count);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- /// Total running time for the process in ticks.
|
|
|
|
|
- std::atomic<u64> m_total_process_running_time_ticks = 0;
|
|
|
|
|
|
|
+ Result WaitConditionVariable(KProcessAddress address, uintptr_t cv_key, u32 tag, s64 ns) {
|
|
|
|
|
+ R_RETURN(m_cond_var.Wait(address, cv_key, tag, ns));
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- /// Per-process handle table for storing created object handles in.
|
|
|
|
|
- KHandleTable m_handle_table;
|
|
|
|
|
|
|
+ Result SignalAddressArbiter(uintptr_t address, Svc::SignalType signal_type, s32 value,
|
|
|
|
|
+ s32 count) {
|
|
|
|
|
+ R_RETURN(m_address_arbiter.SignalToAddress(address, signal_type, value, count));
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- /// Per-process address arbiter.
|
|
|
|
|
- KAddressArbiter m_address_arbiter;
|
|
|
|
|
|
|
+ Result WaitAddressArbiter(uintptr_t address, Svc::ArbitrationType arb_type, s32 value,
|
|
|
|
|
+ s64 timeout) {
|
|
|
|
|
+ R_RETURN(m_address_arbiter.WaitForAddress(address, arb_type, value, timeout));
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- /// 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;
|
|
|
|
|
|
|
+ Result GetThreadList(s32* out_num_threads, KProcessAddress out_thread_ids, s32 max_out_count);
|
|
|
|
|
|
|
|
- /// Address indicating the location of the process' dedicated TLS region.
|
|
|
|
|
- KProcessAddress m_plr_address = 0;
|
|
|
|
|
|
|
+ static void Switch(KProcess* cur_process, KProcess* next_process);
|
|
|
|
|
|
|
|
- /// Address indicating the location of the process's entry point.
|
|
|
|
|
- KProcessAddress m_code_address = 0;
|
|
|
|
|
|
|
+public:
|
|
|
|
|
+ // Attempts to insert a watchpoint into a free slot. Returns false if none are available.
|
|
|
|
|
+ bool InsertWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointType type);
|
|
|
|
|
|
|
|
- /// Random values for svcGetInfo RandomEntropy
|
|
|
|
|
- std::array<u64, RANDOM_ENTROPY_SIZE> m_random_entropy{};
|
|
|
|
|
|
|
+ // Attempts to remove the watchpoint specified by the given parameters.
|
|
|
|
|
+ bool RemoveWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointType type);
|
|
|
|
|
|
|
|
- /// List of threads that are running with this process as their owner.
|
|
|
|
|
- std::list<KThread*> m_thread_list;
|
|
|
|
|
|
|
+ const std::array<DebugWatchpoint, Core::Hardware::NUM_WATCHPOINTS>& GetWatchpoints() const {
|
|
|
|
|
+ return m_watchpoints;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- /// List of shared memory that are running with this process as their owner.
|
|
|
|
|
- std::list<KSharedMemoryInfo*> m_shared_memory_list;
|
|
|
|
|
|
|
+public:
|
|
|
|
|
+ Result LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size,
|
|
|
|
|
+ bool is_hbl);
|
|
|
|
|
|
|
|
- /// Address of the top of the main thread's stack
|
|
|
|
|
- KProcessAddress m_main_thread_stack_top{};
|
|
|
|
|
|
|
+ void LoadModule(CodeSet code_set, KProcessAddress base_addr);
|
|
|
|
|
|
|
|
- /// Size of the main thread's stack
|
|
|
|
|
- std::size_t m_main_thread_stack_size{};
|
|
|
|
|
|
|
+ Core::Memory::Memory& GetMemory() const;
|
|
|
|
|
|
|
|
- /// Memory usage capacity for the process
|
|
|
|
|
- std::size_t m_memory_usage_capacity{};
|
|
|
|
|
|
|
+public:
|
|
|
|
|
+ // Overridden parent functions.
|
|
|
|
|
+ bool IsInitialized() const override {
|
|
|
|
|
+ return m_is_initialized;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- /// Process total image size
|
|
|
|
|
- std::size_t m_image_size{};
|
|
|
|
|
|
|
+ static void PostDestroy(uintptr_t arg) {}
|
|
|
|
|
|
|
|
- /// Schedule count of this process
|
|
|
|
|
- s64 m_schedule_count{};
|
|
|
|
|
|
|
+ void Finalize() override;
|
|
|
|
|
|
|
|
- size_t m_memory_release_hint{};
|
|
|
|
|
|
|
+ u64 GetIdImpl() const {
|
|
|
|
|
+ return this->GetProcessId();
|
|
|
|
|
+ }
|
|
|
|
|
+ u64 GetId() const override {
|
|
|
|
|
+ return this->GetIdImpl();
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- std::string name{};
|
|
|
|
|
|
|
+ virtual bool IsSignaled() const override {
|
|
|
|
|
+ ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(m_kernel));
|
|
|
|
|
+ return m_is_signaled;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- 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{};
|
|
|
|
|
|
|
+ void DoWorkerTaskImpl();
|
|
|
|
|
|
|
|
- std::atomic<u16> m_num_running_threads{};
|
|
|
|
|
|
|
+private:
|
|
|
|
|
+ void ChangeState(State new_state) {
|
|
|
|
|
+ if (m_state != new_state) {
|
|
|
|
|
+ m_state = new_state;
|
|
|
|
|
+ m_is_signaled = true;
|
|
|
|
|
+ this->NotifyAvailable();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- 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;
|
|
|
|
|
|
|
+ Result InitializeHandleTable(s32 size) {
|
|
|
|
|
+ // Try to initialize the handle table.
|
|
|
|
|
+ R_TRY(m_handle_table.Initialize(size));
|
|
|
|
|
|
|
|
- KThread* m_exception_thread{};
|
|
|
|
|
|
|
+ // We succeeded, so note that we did.
|
|
|
|
|
+ m_is_handle_table_initialized = true;
|
|
|
|
|
+ R_SUCCEED();
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- KLightLock m_state_lock;
|
|
|
|
|
- KLightLock m_list_lock;
|
|
|
|
|
|
|
+ void FinalizeHandleTable() {
|
|
|
|
|
+ // Finalize the table.
|
|
|
|
|
+ m_handle_table.Finalize();
|
|
|
|
|
|
|
|
- using TLPTree =
|
|
|
|
|
- Common::IntrusiveRedBlackTreeBaseTraits<KThreadLocalPage>::TreeType<KThreadLocalPage>;
|
|
|
|
|
- using TLPIterator = TLPTree::iterator;
|
|
|
|
|
- TLPTree m_fully_used_tlp_tree;
|
|
|
|
|
- TLPTree m_partially_used_tlp_tree;
|
|
|
|
|
|
|
+ // Note that the table is finalized.
|
|
|
|
|
+ m_is_handle_table_initialized = false;
|
|
|
|
|
+ }
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
} // namespace Kernel
|
|
} // namespace Kernel
|