yuzu/src/core/hle/kernel/k_process.h

526 lines
17 KiB
C
Raw Normal View History

2022-07-27 22:06:50 +04:00
// SPDX-FileCopyrightText: 2015 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
2021-05-02 10:03:43 +04:00
#pragma once
#include <array>
#include <cstddef>
#include <list>
2022-06-22 05:30:11 +04:00
#include <map>
2021-05-02 10:03:43 +04:00
#include <string>
#include "common/common_types.h"
#include "core/hle/kernel/k_address_arbiter.h"
#include "core/hle/kernel/k_auto_object.h"
#include "core/hle/kernel/k_condition_variable.h"
#include "core/hle/kernel/k_handle_table.h"
2022-10-20 02:52:26 +04:00
#include "core/hle/kernel/k_page_table.h"
2021-05-02 10:03:43 +04:00
#include "core/hle/kernel/k_synchronization_object.h"
2022-03-12 14:35:05 +04:00
#include "core/hle/kernel/k_thread_local_page.h"
2022-01-15 06:23:49 +04:00
#include "core/hle/kernel/k_worker_task.h"
2021-05-02 10:03:43 +04:00
#include "core/hle/kernel/process_capability.h"
#include "core/hle/kernel/slab_helpers.h"
#include "core/hle/result.h"
namespace Core {
class System;
}
namespace FileSys {
class ProgramMetadata;
}
namespace Kernel {
class KernelCore;
class KResourceLimit;
class KThread;
2021-09-29 21:55:52 +04:00
class KSharedMemoryInfo;
2021-05-02 10:03:43 +04:00
class TLSPage;
struct CodeSet;
enum class MemoryRegion : u16 {
APPLICATION = 1,
SYSTEM = 2,
BASE = 3,
};
2022-06-14 05:25:44 +04:00
enum class ProcessActivity : u32 {
Runnable,
Paused,
};
2022-06-22 05:30:11 +04:00
enum class DebugWatchpointType : u8 {
None = 0,
Read = 1 << 0,
Write = 1 << 1,
ReadOrWrite = Read | Write,
};
DECLARE_ENUM_FLAG_OPERATORS(DebugWatchpointType);
struct DebugWatchpoint {
VAddr start_address;
VAddr end_address;
DebugWatchpointType type;
};
2022-01-15 06:23:49 +04:00
class KProcess final : public KAutoObjectWithSlabHeapAndContainer<KProcess, KWorkerTask> {
2021-05-02 10:03:43 +04:00
KERNEL_AUTOOBJECT_TRAITS(KProcess, KSynchronizationObject);
public:
2021-05-10 08:07:05 +04:00
explicit KProcess(KernelCore& kernel_);
2021-05-02 10:03:43 +04:00
~KProcess() override;
2022-10-20 02:52:26 +04:00
enum class State {
Created = static_cast<u32>(Svc::ProcessState::Created),
CreatedAttached = static_cast<u32>(Svc::ProcessState::CreatedAttached),
Running = static_cast<u32>(Svc::ProcessState::Running),
Crashed = static_cast<u32>(Svc::ProcessState::Crashed),
RunningAttached = static_cast<u32>(Svc::ProcessState::RunningAttached),
Terminating = static_cast<u32>(Svc::ProcessState::Terminating),
Terminated = static_cast<u32>(Svc::ProcessState::Terminated),
DebugBreak = static_cast<u32>(Svc::ProcessState::DebugBreak),
};
2021-05-02 10:03:43 +04:00
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,
};
// Used to determine how process IDs are assigned.
enum class ProcessType {
KernelInternal,
Userland,
};
static constexpr std::size_t RANDOM_ENTROPY_SIZE = 4;
2022-06-30 05:24:05 +04:00
static Result Initialize(KProcess* process, Core::System& system, std::string process_name,
ProcessType type, KResourceLimit* res_limit);
2021-05-02 10:03:43 +04:00
/// Gets a reference to the process' page table.
KPageTable& PageTable() {
2022-10-20 02:52:26 +04:00
return page_table;
2021-05-02 10:03:43 +04:00
}
/// Gets const a reference to the process' page table.
const KPageTable& PageTable() const {
2022-10-20 02:52:26 +04:00
return page_table;
2021-05-02 10:03:43 +04:00
}
/// Gets a reference to the process' handle table.
KHandleTable& GetHandleTable() {
return handle_table;
}
/// Gets a const reference to the process' handle table.
const KHandleTable& GetHandleTable() const {
return handle_table;
}
2022-06-30 05:24:05 +04:00
Result SignalToAddress(VAddr address) {
2021-05-02 10:03:43 +04:00
return condition_var.SignalToAddress(address);
}
2022-06-30 05:24:05 +04:00
Result WaitForAddress(Handle handle, VAddr address, u32 tag) {
2021-05-02 10:03:43 +04:00
return condition_var.WaitForAddress(handle, address, tag);
}
void SignalConditionVariable(u64 cv_key, int32_t count) {
return condition_var.Signal(cv_key, count);
}
2022-06-30 05:24:05 +04:00
Result WaitConditionVariable(VAddr address, u64 cv_key, u32 tag, s64 ns) {
2022-10-20 02:52:26 +04:00
R_RETURN(condition_var.Wait(address, cv_key, tag, ns));
2021-05-02 10:03:43 +04:00
}
2022-06-30 05:24:05 +04:00
Result SignalAddressArbiter(VAddr address, Svc::SignalType signal_type, s32 value, s32 count) {
2022-10-20 02:52:26 +04:00
R_RETURN(address_arbiter.SignalToAddress(address, signal_type, value, count));
2021-05-02 10:03:43 +04:00
}
2022-06-30 05:24:05 +04:00
Result WaitAddressArbiter(VAddr address, Svc::ArbitrationType arb_type, s32 value,
s64 timeout) {
2022-10-20 02:52:26 +04:00
R_RETURN(address_arbiter.WaitForAddress(address, arb_type, value, timeout));
2021-05-02 10:03:43 +04:00
}
2022-10-20 02:52:26 +04:00
VAddr GetProcessLocalRegionAddress() const {
return plr_address;
2021-05-02 10:03:43 +04:00
}
/// Gets the current status of the process
2022-10-20 02:52:26 +04:00
State GetState() const {
return state;
2021-05-02 10:03:43 +04:00
}
/// Gets the unique ID that identifies this particular process.
u64 GetProcessID() const {
return process_id;
}
2021-11-05 19:31:40 +04:00
/// Gets the program ID corresponding to this process.
u64 GetProgramID() const {
2021-05-02 10:03:43 +04:00
return program_id;
}
/// Gets the resource limit descriptor for this process
KResourceLimit* GetResourceLimit() const;
/// Gets the ideal CPU core ID for this process
u8 GetIdealCoreId() const {
return 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 capabilities.GetCoreMask();
}
/// Gets the bitmask of allowed thread priorities.
u64 GetPriorityMask() const {
return capabilities.GetPriorityMask();
}
/// Gets the amount of secure memory to allocate for memory management.
u32 GetSystemResourceSize() const {
return 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 is_64bit_process;
}
[[nodiscard]] bool IsSuspended() const {
return is_suspended;
}
void SetSuspended(bool suspended) {
is_suspended = suspended;
}
/// Gets the total running time of the process instance in ticks.
u64 GetCPUTimeTicks() const {
return total_process_running_time_ticks;
}
/// Updates the total running time, adding the given ticks to it.
void UpdateCPUTimeTicks(u64 ticks) {
total_process_running_time_ticks += ticks;
}
/// Gets the process schedule count, used for thread yelding
s64 GetScheduledCount() const {
return schedule_count;
}
/// Increments the process schedule count, used for thread yielding.
void IncrementScheduledCount() {
++schedule_count;
}
2022-01-24 14:11:34 +04:00
void IncrementRunningThreadCount();
void DecrementRunningThreadCount();
2021-05-02 10:03:43 +04:00
void SetRunningThread(s32 core, KThread* thread, u64 idle_count) {
running_threads[core] = thread;
running_thread_idle_counts[core] = idle_count;
}
void ClearRunningThread(KThread* thread) {
for (size_t i = 0; i < running_threads.size(); ++i) {
if (running_threads[i] == thread) {
running_threads[i] = nullptr;
}
}
}
[[nodiscard]] KThread* GetRunningThread(s32 core) const {
return 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));
2021-12-01 00:23:11 +04:00
return pinned_threads[core_id];
2021-05-02 10:03:43 +04:00
}
/// Gets 8 bytes of random data for svcGetInfo RandomEntropy
u64 GetRandomEntropy(std::size_t index) const {
return random_entropy.at(index);
}
/// Retrieves the total physical memory available to this process in bytes.
2022-10-20 02:52:26 +04:00
u64 GetTotalPhysicalMemoryAvailable();
2021-05-02 10:03:43 +04:00
/// Retrieves the total physical memory available to this process in bytes,
/// without the size of the personal system resource heap added to it.
2022-10-20 02:52:26 +04:00
u64 GetTotalPhysicalMemoryAvailableWithoutSystemResource();
2021-05-02 10:03:43 +04:00
/// Retrieves the total physical memory used by this process in bytes.
2022-10-20 02:52:26 +04:00
u64 GetTotalPhysicalMemoryUsed();
2021-05-02 10:03:43 +04:00
/// Retrieves the total physical memory used by this process in bytes,
/// without the size of the personal system resource heap added to it.
2022-10-20 02:52:26 +04:00
u64 GetTotalPhysicalMemoryUsedWithoutSystemResource();
2021-05-02 10:03:43 +04:00
/// Gets the list of all threads created with this process as their owner.
2022-06-14 05:25:44 +04:00
std::list<KThread*>& GetThreadList() {
2021-05-02 10:03:43 +04:00
return thread_list;
}
/// Registers a thread as being created under this process,
/// adding it to this process' thread list.
2022-06-14 05:25:44 +04:00
void RegisterThread(KThread* thread);
2021-05-02 10:03:43 +04:00
/// Unregisters a thread from this process, removing it
/// from this process' thread list.
2022-06-14 05:25:44 +04:00
void UnregisterThread(KThread* thread);
2021-05-02 10:03:43 +04:00
/// 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 ERR_INVALID_STATE will be returned.
///
/// @pre The process must be in a signaled state. If this is called on a
/// process instance that is not signaled, ERR_INVALID_STATE will be
/// returned.
2022-06-30 05:24:05 +04:00
Result Reset();
2021-05-02 10:03:43 +04:00
/**
* Loads process-specifics configuration info with metadata provided
* by an executable.
*
* @param metadata The provided metadata to load process specific info from.
*
2021-06-03 04:36:17 +04:00
* @returns ResultSuccess if all relevant metadata was able to be
2021-05-02 10:03:43 +04:00
* loaded and parsed. Otherwise, an error code is returned.
*/
2022-06-30 05:24:05 +04:00
Result LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size);
2021-05-02 10:03:43 +04:00
/**
* 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, VAddr base_addr);
2021-05-29 14:00:09 +04:00
bool IsInitialized() const override {
2021-05-02 10:03:43 +04:00
return is_initialized;
}
static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
2021-05-29 14:00:09 +04:00
void Finalize() override;
2021-05-02 10:03:43 +04:00
2021-05-29 14:00:09 +04:00
u64 GetId() const override {
2021-05-02 10:03:43 +04:00
return GetProcessID();
}
2021-05-29 14:00:09 +04:00
bool IsSignaled() const override;
2021-05-02 10:03:43 +04:00
2022-01-15 06:23:49 +04:00
void DoWorkerTaskImpl();
2022-06-30 05:24:05 +04:00
Result SetActivity(ProcessActivity activity);
2022-06-14 05:25:44 +04:00
2021-12-31 06:09:58 +04:00
void PinCurrentThread(s32 core_id);
void UnpinCurrentThread(s32 core_id);
2021-12-07 15:04:29 +04:00
void UnpinThread(KThread* thread);
2021-05-02 10:03:43 +04:00
KLightLock& GetStateLock() {
return state_lock;
}
2022-06-30 05:24:05 +04:00
Result AddSharedMemory(KSharedMemory* shmem, VAddr address, size_t size);
2021-05-02 10:03:43 +04:00
void RemoveSharedMemory(KSharedMemory* shmem, VAddr address, size_t size);
///////////////////////////////////////////////////////////////////////////////////////////////
// Thread-local storage management
// Marks the next available region as used and returns the address of the slot.
2022-06-30 05:24:05 +04:00
[[nodiscard]] Result CreateThreadLocalRegion(VAddr* out);
2021-05-02 10:03:43 +04:00
// Frees a used TLS slot identified by the given address
2022-06-30 05:24:05 +04:00
Result DeleteThreadLocalRegion(VAddr addr);
2021-05-02 10:03:43 +04:00
2022-06-22 05:30:11 +04:00
///////////////////////////////////////////////////////////////////////////////////////////////
// Debug watchpoint management
// Attempts to insert a watchpoint into a free slot. Returns false if none are available.
bool InsertWatchpoint(Core::System& system, VAddr addr, u64 size, DebugWatchpointType type);
// Attempts to remove the watchpoint specified by the given parameters.
bool RemoveWatchpoint(Core::System& system, VAddr addr, u64 size, DebugWatchpointType type);
const std::array<DebugWatchpoint, Core::Hardware::NUM_WATCHPOINTS>& GetWatchpoints() const {
return watchpoints;
}
2021-05-02 10:03:43 +04:00
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);
2021-12-01 00:23:11 +04:00
ASSERT(pinned_threads[core_id] == nullptr);
2021-05-02 10:03:43 +04:00
pinned_threads[core_id] = thread;
}
void UnpinThread(s32 core_id, KThread* thread) {
ASSERT(0 <= core_id && core_id < static_cast<s32>(Core::Hardware::NUM_CPU_CORES));
ASSERT(thread != nullptr);
2021-12-01 00:23:11 +04:00
ASSERT(pinned_threads[core_id] == thread);
2021-05-02 10:03:43 +04:00
pinned_threads[core_id] = nullptr;
}
2022-10-20 02:52:26 +04:00
void FinalizeHandleTable() {
// Finalize the table.
handle_table.Finalize();
// Note that the table is finalized.
is_handle_table_initialized = false;
}
void ChangeState(State new_state);
2021-05-02 10:03:43 +04:00
/// Allocates the main thread stack for the process, given the stack size in bytes.
2022-06-30 05:24:05 +04:00
Result AllocateMainThreadStack(std::size_t stack_size);
2021-05-02 10:03:43 +04:00
/// Memory manager for this process
2022-10-20 02:52:26 +04:00
KPageTable page_table;
2021-05-02 10:03:43 +04:00
/// Current status of the process
2022-10-20 02:52:26 +04:00
State state{};
2021-05-02 10:03:43 +04:00
/// The ID of this process
u64 process_id = 0;
/// Title ID corresponding to the process
u64 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 system_resource_size = 0;
/// Resource limit descriptor for this process
KResourceLimit* resource_limit{};
2022-10-20 02:52:26 +04:00
VAddr system_resource_address{};
2021-05-02 10:03:43 +04:00
/// The ideal CPU core for this process, threads are scheduled on this core by default.
u8 ideal_core = 0;
/// Contains the parsed process capability descriptors.
ProcessCapabilities 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 is_64bit_process = true;
/// Total running time for the process in ticks.
2022-04-06 07:09:11 +04:00
std::atomic<u64> total_process_running_time_ticks = 0;
2021-05-02 10:03:43 +04:00
/// Per-process handle table for storing created object handles in.
KHandleTable handle_table;
/// Per-process address arbiter.
KAddressArbiter 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 condition_var;
/// Address indicating the location of the process' dedicated TLS region.
2022-10-20 02:52:26 +04:00
VAddr plr_address = 0;
2021-05-02 10:03:43 +04:00
/// Random values for svcGetInfo RandomEntropy
std::array<u64, RANDOM_ENTROPY_SIZE> random_entropy{};
/// List of threads that are running with this process as their owner.
2022-06-14 05:25:44 +04:00
std::list<KThread*> thread_list;
2021-05-02 10:03:43 +04:00
2021-09-29 21:55:52 +04:00
/// List of shared memory that are running with this process as their owner.
std::list<KSharedMemoryInfo*> shared_memory_list;
2021-05-02 10:03:43 +04:00
/// Address of the top of the main thread's stack
VAddr main_thread_stack_top{};
/// Size of the main thread's stack
std::size_t main_thread_stack_size{};
/// Memory usage capacity for the process
std::size_t memory_usage_capacity{};
/// Process total image size
std::size_t image_size{};
/// Schedule count of this process
s64 schedule_count{};
2022-10-20 02:52:26 +04:00
size_t memory_release_hint{};
2021-05-02 10:03:43 +04:00
bool is_signaled{};
bool is_suspended{};
2022-10-20 02:52:26 +04:00
bool is_immortal{};
bool is_handle_table_initialized{};
2021-05-02 10:03:43 +04:00
bool is_initialized{};
2022-01-24 14:11:34 +04:00
std::atomic<u16> num_running_threads{};
2021-05-02 10:03:43 +04:00
std::array<KThread*, Core::Hardware::NUM_CPU_CORES> running_threads{};
std::array<u64, Core::Hardware::NUM_CPU_CORES> running_thread_idle_counts{};
std::array<KThread*, Core::Hardware::NUM_CPU_CORES> pinned_threads{};
2022-06-22 05:30:11 +04:00
std::array<DebugWatchpoint, Core::Hardware::NUM_WATCHPOINTS> watchpoints{};
std::map<VAddr, u64> debug_page_refcounts;
2021-05-02 10:03:43 +04:00
KThread* exception_thread{};
KLightLock state_lock;
2022-06-14 05:25:44 +04:00
KLightLock list_lock;
2022-03-12 14:35:05 +04:00
using TLPTree =
Common::IntrusiveRedBlackTreeBaseTraits<KThreadLocalPage>::TreeType<KThreadLocalPage>;
using TLPIterator = TLPTree::iterator;
TLPTree fully_used_tlp_tree;
TLPTree partially_used_tlp_tree;
2021-05-02 10:03:43 +04:00
};
} // namespace Kernel