2015-05-04 05:01:16 +02:00
|
|
|
// Copyright 2015 Citra Emulator Project
|
|
|
|
// Licensed under GPLv2 or any later version
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
2018-08-03 20:42:28 +02:00
|
|
|
#include <array>
|
2015-05-04 05:01:16 +02:00
|
|
|
#include <bitset>
|
2015-06-21 16:44:11 +02:00
|
|
|
#include <cstddef>
|
2015-07-12 23:10:37 +02:00
|
|
|
#include <memory>
|
2015-06-21 16:44:11 +02:00
|
|
|
#include <string>
|
2018-01-01 20:38:34 +01:00
|
|
|
#include <vector>
|
2015-05-04 05:01:16 +02:00
|
|
|
#include <boost/container/static_vector.hpp>
|
2015-05-08 22:53:19 +02:00
|
|
|
#include "common/common_types.h"
|
2018-10-20 20:34:41 +02:00
|
|
|
#include "core/hle/kernel/handle_table.h"
|
2018-12-20 05:50:20 +01:00
|
|
|
#include "core/hle/kernel/process_capability.h"
|
2018-01-10 06:58:25 +01:00
|
|
|
#include "core/hle/kernel/thread.h"
|
2015-07-18 04:19:16 +02:00
|
|
|
#include "core/hle/kernel/vm_manager.h"
|
2018-12-05 01:08:56 +01:00
|
|
|
#include "core/hle/kernel/wait_object.h"
|
|
|
|
#include "core/hle/result.h"
|
2015-05-04 05:01:16 +02:00
|
|
|
|
2018-09-23 02:09:32 +02:00
|
|
|
namespace FileSys {
|
|
|
|
class ProgramMetadata;
|
|
|
|
}
|
|
|
|
|
2015-05-04 05:01:16 +02:00
|
|
|
namespace Kernel {
|
|
|
|
|
2018-08-28 18:30:33 +02:00
|
|
|
class KernelCore;
|
2018-10-13 20:31:46 +02:00
|
|
|
class ResourceLimit;
|
2018-08-28 18:30:33 +02:00
|
|
|
|
2015-05-08 23:12:25 +02:00
|
|
|
struct AddressMapping {
|
2015-05-08 21:51:48 +02:00
|
|
|
// Address and size must be page-aligned
|
2015-05-04 05:01:16 +02:00
|
|
|
VAddr address;
|
2017-12-29 19:27:58 +01:00
|
|
|
u64 size;
|
2017-05-06 08:11:06 +02:00
|
|
|
bool read_only;
|
2015-05-08 21:51:48 +02:00
|
|
|
bool unk_flag;
|
2015-05-04 05:01:16 +02:00
|
|
|
};
|
|
|
|
|
2015-05-08 22:53:19 +02:00
|
|
|
enum class MemoryRegion : u16 {
|
2015-05-04 05:01:16 +02:00
|
|
|
APPLICATION = 1,
|
|
|
|
SYSTEM = 2,
|
|
|
|
BASE = 3,
|
|
|
|
};
|
|
|
|
|
2018-10-13 20:31:46 +02:00
|
|
|
/**
|
|
|
|
* Indicates the status of a Process instance.
|
|
|
|
*
|
|
|
|
* @note These match the values as used by kernel,
|
|
|
|
* so new entries should only be added if RE
|
|
|
|
* shows that a new value has been introduced.
|
|
|
|
*/
|
|
|
|
enum class ProcessStatus {
|
|
|
|
Created,
|
|
|
|
CreatedWithDebuggerAttached,
|
|
|
|
Running,
|
|
|
|
WaitingForDebuggerToAttach,
|
|
|
|
DebuggerAttached,
|
|
|
|
Exiting,
|
|
|
|
Exited,
|
|
|
|
DebugBreak,
|
|
|
|
};
|
2015-07-10 03:52:15 +02:00
|
|
|
|
2018-10-12 17:36:31 +02:00
|
|
|
struct CodeSet final {
|
2018-08-03 20:33:59 +02:00
|
|
|
struct Segment {
|
2018-09-15 15:21:06 +02:00
|
|
|
std::size_t offset = 0;
|
2018-08-03 20:33:59 +02:00
|
|
|
VAddr addr = 0;
|
|
|
|
u32 size = 0;
|
|
|
|
};
|
|
|
|
|
2018-10-12 17:36:31 +02:00
|
|
|
explicit CodeSet();
|
|
|
|
~CodeSet();
|
2015-07-10 03:52:15 +02:00
|
|
|
|
2018-08-03 20:33:59 +02:00
|
|
|
Segment& CodeSegment() {
|
|
|
|
return segments[0];
|
|
|
|
}
|
2015-07-10 03:52:15 +02:00
|
|
|
|
2018-08-03 20:33:59 +02:00
|
|
|
const Segment& CodeSegment() const {
|
|
|
|
return segments[0];
|
|
|
|
}
|
2015-07-10 03:52:15 +02:00
|
|
|
|
2018-08-03 20:33:59 +02:00
|
|
|
Segment& RODataSegment() {
|
|
|
|
return segments[1];
|
|
|
|
}
|
2015-07-10 03:52:15 +02:00
|
|
|
|
2018-08-03 20:33:59 +02:00
|
|
|
const Segment& RODataSegment() const {
|
|
|
|
return segments[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
Segment& DataSegment() {
|
|
|
|
return segments[2];
|
|
|
|
}
|
|
|
|
|
|
|
|
const Segment& DataSegment() const {
|
|
|
|
return segments[2];
|
|
|
|
}
|
|
|
|
|
|
|
|
std::shared_ptr<std::vector<u8>> memory;
|
2017-09-24 17:12:16 +02:00
|
|
|
|
2018-08-03 20:42:28 +02:00
|
|
|
std::array<Segment, 3> segments;
|
2018-10-12 17:36:31 +02:00
|
|
|
VAddr entrypoint = 0;
|
2015-07-10 03:52:15 +02:00
|
|
|
};
|
2015-05-12 22:25:15 +02:00
|
|
|
|
2018-12-05 01:08:56 +01:00
|
|
|
class Process final : public WaitObject {
|
2015-05-04 05:01:16 +02:00
|
|
|
public:
|
2018-12-19 04:53:58 +01: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,
|
|
|
|
};
|
|
|
|
|
2018-11-13 18:25:43 +01:00
|
|
|
static constexpr std::size_t RANDOM_ENTROPY_SIZE = 4;
|
|
|
|
|
2018-08-28 18:30:33 +02:00
|
|
|
static SharedPtr<Process> Create(KernelCore& kernel, std::string&& name);
|
2015-05-04 05:01:16 +02:00
|
|
|
|
2016-09-18 02:38:01 +02:00
|
|
|
std::string GetTypeName() const override {
|
|
|
|
return "Process";
|
|
|
|
}
|
|
|
|
std::string GetName() const override {
|
2017-09-30 20:15:09 +02:00
|
|
|
return name;
|
2016-09-18 02:38:01 +02:00
|
|
|
}
|
2015-05-04 05:01:16 +02:00
|
|
|
|
|
|
|
static const HandleType HANDLE_TYPE = HandleType::Process;
|
2016-09-18 02:38:01 +02:00
|
|
|
HandleType GetHandleType() const override {
|
|
|
|
return HANDLE_TYPE;
|
|
|
|
}
|
2015-05-04 05:01:16 +02:00
|
|
|
|
2018-09-30 00:47:00 +02:00
|
|
|
/// Gets a reference to the process' memory manager.
|
|
|
|
Kernel::VMManager& VMManager() {
|
|
|
|
return vm_manager;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Gets a const reference to the process' memory manager.
|
|
|
|
const Kernel::VMManager& VMManager() const {
|
|
|
|
return vm_manager;
|
|
|
|
}
|
|
|
|
|
2018-10-20 20:34:41 +02:00
|
|
|
/// Gets a reference to the process' handle table.
|
|
|
|
HandleTable& GetHandleTable() {
|
|
|
|
return handle_table;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Gets a const reference to the process' handle table.
|
|
|
|
const HandleTable& GetHandleTable() const {
|
|
|
|
return handle_table;
|
|
|
|
}
|
|
|
|
|
2018-09-21 08:06:47 +02:00
|
|
|
/// Gets the current status of the process
|
|
|
|
ProcessStatus GetStatus() const {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Gets the unique ID that identifies this particular process.
|
2018-12-19 04:16:53 +01:00
|
|
|
u64 GetProcessID() const {
|
2018-09-21 08:06:47 +02:00
|
|
|
return process_id;
|
|
|
|
}
|
|
|
|
|
2018-09-30 00:47:00 +02:00
|
|
|
/// Gets the title ID corresponding to this process.
|
|
|
|
u64 GetTitleID() const {
|
|
|
|
return program_id;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Gets the resource limit descriptor for this process
|
2018-12-04 06:29:15 +01:00
|
|
|
SharedPtr<ResourceLimit> GetResourceLimit() const;
|
2018-09-30 00:47:00 +02:00
|
|
|
|
|
|
|
/// Gets the default CPU ID for this process
|
|
|
|
u8 GetDefaultProcessorID() const {
|
|
|
|
return ideal_processor;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Gets the bitmask of allowed CPUs that this process' threads can run on.
|
2018-12-20 05:50:20 +01:00
|
|
|
u64 GetAllowedProcessorMask() const {
|
|
|
|
return capabilities.GetCoreMask();
|
2018-09-30 00:47:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Gets the bitmask of allowed thread priorities.
|
2018-12-20 05:50:20 +01:00
|
|
|
u64 GetAllowedThreadPriorityMask() const {
|
|
|
|
return capabilities.GetPriorityMask();
|
2018-09-30 00:47:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
u32 IsVirtualMemoryEnabled() const {
|
|
|
|
return is_virtual_address_memory_enabled;
|
|
|
|
}
|
|
|
|
|
2018-09-30 01:13:46 +02:00
|
|
|
/// Whether this process is an AArch64 or AArch32 process.
|
|
|
|
bool Is64BitProcess() const {
|
|
|
|
return is_64bit_process;
|
|
|
|
}
|
|
|
|
|
2018-10-26 00:42:50 +02:00
|
|
|
/// 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;
|
|
|
|
}
|
|
|
|
|
2018-11-13 18:25:43 +01:00
|
|
|
/// Gets 8 bytes of random data for svcGetInfo RandomEntropy
|
|
|
|
u64 GetRandomEntropy(std::size_t index) const {
|
|
|
|
return random_entropy.at(index);
|
|
|
|
}
|
|
|
|
|
2018-12-05 01:08:56 +01: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.
|
|
|
|
ResultCode ClearSignalState();
|
|
|
|
|
2018-09-23 02:09:32 +02:00
|
|
|
/**
|
|
|
|
* Loads process-specifics configuration info with metadata provided
|
|
|
|
* by an executable.
|
|
|
|
*
|
2018-12-20 05:50:20 +01:00
|
|
|
* @param metadata The provided metadata to load process specific info from.
|
|
|
|
*
|
|
|
|
* @returns RESULT_SUCCESS if all relevant metadata was able to be
|
|
|
|
* loaded and parsed. Otherwise, an error code is returned.
|
2015-05-08 23:11:06 +02:00
|
|
|
*/
|
2018-12-20 05:50:20 +01:00
|
|
|
ResultCode LoadFromMetadata(const FileSys::ProgramMetadata& metadata);
|
2015-05-08 23:11:06 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Applies address space changes and launches the process main thread.
|
|
|
|
*/
|
2017-09-30 20:15:09 +02:00
|
|
|
void Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size);
|
2015-05-04 05:01:16 +02:00
|
|
|
|
2018-09-21 08:06:47 +02:00
|
|
|
/**
|
|
|
|
* Prepares a process for termination by stopping all of its threads
|
|
|
|
* and clearing any other resources.
|
|
|
|
*/
|
|
|
|
void PrepareForTermination();
|
|
|
|
|
2018-10-12 17:36:31 +02:00
|
|
|
void LoadModule(CodeSet module_, VAddr base_addr);
|
2017-09-24 17:12:16 +02:00
|
|
|
|
2015-07-18 04:19:16 +02:00
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Memory Management
|
|
|
|
|
2018-09-21 07:26:29 +02:00
|
|
|
// Marks the next available region as used and returns the address of the slot.
|
|
|
|
VAddr MarkNextAvailableTLSSlotAsUsed(Thread& thread);
|
|
|
|
|
|
|
|
// Frees a used TLS slot identified by the given address
|
|
|
|
void FreeTLSSlot(VAddr tls_address);
|
|
|
|
|
|
|
|
ResultVal<VAddr> HeapAllocate(VAddr target, u64 size, VMAPermission perms);
|
|
|
|
ResultCode HeapFree(VAddr target, u32 size);
|
|
|
|
|
2018-12-12 16:08:46 +01:00
|
|
|
ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size, MemoryState state);
|
2018-09-21 07:26:29 +02:00
|
|
|
|
|
|
|
ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size);
|
|
|
|
|
|
|
|
private:
|
|
|
|
explicit Process(KernelCore& kernel);
|
|
|
|
~Process() override;
|
|
|
|
|
2018-12-05 01:08:56 +01:00
|
|
|
/// Checks if the specified thread should wait until this process is available.
|
|
|
|
bool ShouldWait(Thread* thread) const override;
|
|
|
|
|
|
|
|
/// Acquires/locks this process for the specified thread if it's available.
|
|
|
|
void Acquire(Thread* thread) override;
|
|
|
|
|
|
|
|
/// Changes the process status. If the status is different
|
|
|
|
/// from the current process status, then this will trigger
|
|
|
|
/// a process signal.
|
|
|
|
void ChangeStatus(ProcessStatus new_status);
|
|
|
|
|
2018-09-30 00:47:00 +02:00
|
|
|
/// Memory manager for this process.
|
|
|
|
Kernel::VMManager vm_manager;
|
|
|
|
|
2018-09-21 08:06:47 +02:00
|
|
|
/// Current status of the process
|
|
|
|
ProcessStatus status;
|
|
|
|
|
|
|
|
/// The ID of this process
|
2018-12-19 04:16:53 +01:00
|
|
|
u64 process_id = 0;
|
2018-09-21 08:06:47 +02:00
|
|
|
|
2018-09-30 00:47:00 +02:00
|
|
|
/// Title ID corresponding to the process
|
2018-12-19 04:16:53 +01:00
|
|
|
u64 program_id = 0;
|
2018-09-30 00:47:00 +02:00
|
|
|
|
|
|
|
/// Resource limit descriptor for this process
|
|
|
|
SharedPtr<ResourceLimit> resource_limit;
|
|
|
|
|
|
|
|
/// The default CPU for this process, threads are scheduled on this cpu by default.
|
|
|
|
u8 ideal_processor = 0;
|
|
|
|
u32 is_virtual_address_memory_enabled = 0;
|
|
|
|
|
2016-04-20 00:12:48 +02:00
|
|
|
/// The Thread Local Storage area is allocated as processes create threads,
|
|
|
|
/// each TLS area is 0x200 bytes, so one page (0x1000) is split up in 8 parts, and each part
|
2016-09-18 02:38:01 +02:00
|
|
|
/// holds the TLS for a specific thread. This vector contains which parts are in use for each
|
|
|
|
/// page as a bitmask.
|
2016-04-20 00:12:48 +02:00
|
|
|
/// This vector will grow as more pages are allocated for new threads.
|
|
|
|
std::vector<std::bitset<8>> tls_slots;
|
2015-07-18 04:19:16 +02:00
|
|
|
|
2018-12-20 05:50:20 +01:00
|
|
|
/// Contains the parsed process capability descriptors.
|
|
|
|
ProcessCapabilities capabilities;
|
|
|
|
|
2018-09-30 01:13:46 +02:00
|
|
|
/// 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;
|
|
|
|
|
2018-12-05 01:08:56 +01:00
|
|
|
/// Whether or not this process is signaled. This occurs
|
|
|
|
/// upon the process changing to a different state.
|
|
|
|
bool is_signaled = false;
|
|
|
|
|
2018-10-26 00:42:50 +02:00
|
|
|
/// Total running time for the process in ticks.
|
|
|
|
u64 total_process_running_time_ticks = 0;
|
|
|
|
|
2018-10-20 20:34:41 +02:00
|
|
|
/// Per-process handle table for storing created object handles in.
|
|
|
|
HandleTable handle_table;
|
|
|
|
|
2018-11-13 18:25:43 +01:00
|
|
|
/// Random values for svcGetInfo RandomEntropy
|
|
|
|
std::array<u64, RANDOM_ENTROPY_SIZE> random_entropy;
|
|
|
|
|
2017-09-30 20:15:09 +02:00
|
|
|
std::string name;
|
2015-05-04 05:01:16 +02:00
|
|
|
};
|
|
|
|
|
2018-01-01 20:38:34 +01:00
|
|
|
} // namespace Kernel
|