Merge pull request #4358 from wwylele/kernel-global-2
kernel: Eliminate global state in process and handle_table
This commit is contained in:
commit
f3ee5feb02
|
@ -126,7 +126,9 @@ System::ResultStatus System::Load(EmuWindow& emu_window, const std::string& file
|
||||||
return init_result;
|
return init_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Loader::ResultStatus load_result{app_loader->Load(Kernel::g_current_process)};
|
Kernel::SharedPtr<Kernel::Process> process;
|
||||||
|
const Loader::ResultStatus load_result{app_loader->Load(process)};
|
||||||
|
kernel->SetCurrentProcess(process);
|
||||||
if (Loader::ResultStatus::Success != load_result) {
|
if (Loader::ResultStatus::Success != load_result) {
|
||||||
LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", static_cast<u32>(load_result));
|
LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", static_cast<u32>(load_result));
|
||||||
System::Shutdown();
|
System::Shutdown();
|
||||||
|
@ -140,7 +142,7 @@ System::ResultStatus System::Load(EmuWindow& emu_window, const std::string& file
|
||||||
return ResultStatus::ErrorLoader;
|
return ResultStatus::ErrorLoader;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Memory::SetCurrentPageTable(&Kernel::g_current_process->vm_manager.page_table);
|
Memory::SetCurrentPageTable(&kernel->GetCurrentProcess()->vm_manager.page_table);
|
||||||
status = ResultStatus::Success;
|
status = ResultStatus::Success;
|
||||||
m_emu_window = &emu_window;
|
m_emu_window = &emu_window;
|
||||||
m_filepath = filepath;
|
m_filepath = filepath;
|
||||||
|
|
|
@ -251,8 +251,11 @@ private:
|
||||||
|
|
||||||
std::unique_ptr<Service::FS::ArchiveManager> archive_manager;
|
std::unique_ptr<Service::FS::ArchiveManager> archive_manager;
|
||||||
|
|
||||||
|
public: // HACK: this is temporary exposed for tests,
|
||||||
|
// due to WIP kernel refactor causing desync state in memory
|
||||||
std::unique_ptr<Kernel::KernelSystem> kernel;
|
std::unique_ptr<Kernel::KernelSystem> kernel;
|
||||||
|
|
||||||
|
private:
|
||||||
static System s_instance;
|
static System s_instance;
|
||||||
|
|
||||||
ResultStatus status = ResultStatus::Success;
|
ResultStatus status = ResultStatus::Success;
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include "core/core.h"
|
||||||
#include "core/file_sys/archive_savedata.h"
|
#include "core/file_sys/archive_savedata.h"
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
|
|
||||||
|
@ -16,16 +17,19 @@ ArchiveFactory_SaveData::ArchiveFactory_SaveData(
|
||||||
: sd_savedata_source(std::move(sd_savedata)) {}
|
: sd_savedata_source(std::move(sd_savedata)) {}
|
||||||
|
|
||||||
ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SaveData::Open(const Path& path) {
|
ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SaveData::Open(const Path& path) {
|
||||||
return sd_savedata_source->Open(Kernel::g_current_process->codeset->program_id);
|
return sd_savedata_source->Open(
|
||||||
|
Core::System::GetInstance().Kernel().GetCurrentProcess()->codeset->program_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode ArchiveFactory_SaveData::Format(const Path& path,
|
ResultCode ArchiveFactory_SaveData::Format(const Path& path,
|
||||||
const FileSys::ArchiveFormatInfo& format_info) {
|
const FileSys::ArchiveFormatInfo& format_info) {
|
||||||
return sd_savedata_source->Format(Kernel::g_current_process->codeset->program_id, format_info);
|
return sd_savedata_source->Format(
|
||||||
|
Core::System::GetInstance().Kernel().GetCurrentProcess()->codeset->program_id, format_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<ArchiveFormatInfo> ArchiveFactory_SaveData::GetFormatInfo(const Path& path) const {
|
ResultVal<ArchiveFormatInfo> ArchiveFactory_SaveData::GetFormatInfo(const Path& path) const {
|
||||||
return sd_savedata_source->GetFormatInfo(Kernel::g_current_process->codeset->program_id);
|
return sd_savedata_source->GetFormatInfo(
|
||||||
|
Core::System::GetInstance().Kernel().GetCurrentProcess()->codeset->program_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace FileSys
|
} // namespace FileSys
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/swap.h"
|
#include "common/swap.h"
|
||||||
|
#include "core/core.h"
|
||||||
#include "core/file_sys/archive_selfncch.h"
|
#include "core/file_sys/archive_selfncch.h"
|
||||||
#include "core/file_sys/errors.h"
|
#include "core/file_sys/errors.h"
|
||||||
#include "core/file_sys/ivfc_archive.h"
|
#include "core/file_sys/ivfc_archive.h"
|
||||||
|
@ -279,7 +280,7 @@ void ArchiveFactory_SelfNCCH::Register(Loader::AppLoader& app_loader) {
|
||||||
|
|
||||||
ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SelfNCCH::Open(const Path& path) {
|
ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SelfNCCH::Open(const Path& path) {
|
||||||
auto archive = std::make_unique<SelfNCCHArchive>(
|
auto archive = std::make_unique<SelfNCCHArchive>(
|
||||||
ncch_data[Kernel::g_current_process->codeset->program_id]);
|
ncch_data[Core::System::GetInstance().Kernel().GetCurrentProcess()->codeset->program_id]);
|
||||||
return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
|
return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,9 +12,7 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
HandleTable g_handle_table;
|
HandleTable::HandleTable(KernelSystem& kernel) : kernel(kernel) {
|
||||||
|
|
||||||
HandleTable::HandleTable() {
|
|
||||||
next_generation = 1;
|
next_generation = 1;
|
||||||
Clear();
|
Clear();
|
||||||
}
|
}
|
||||||
|
@ -76,7 +74,7 @@ SharedPtr<Object> HandleTable::GetGeneric(Handle handle) const {
|
||||||
if (handle == CurrentThread) {
|
if (handle == CurrentThread) {
|
||||||
return GetCurrentThread();
|
return GetCurrentThread();
|
||||||
} else if (handle == CurrentProcess) {
|
} else if (handle == CurrentProcess) {
|
||||||
return g_current_process;
|
return kernel.GetCurrentProcess();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsValid(handle)) {
|
if (!IsValid(handle)) {
|
||||||
|
|
|
@ -42,7 +42,7 @@ enum KernelHandle : Handle {
|
||||||
*/
|
*/
|
||||||
class HandleTable final : NonCopyable {
|
class HandleTable final : NonCopyable {
|
||||||
public:
|
public:
|
||||||
HandleTable();
|
explicit HandleTable(KernelSystem& kernel);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allocates a handle for the given object.
|
* Allocates a handle for the given object.
|
||||||
|
@ -119,8 +119,8 @@ private:
|
||||||
|
|
||||||
/// Head of the free slots linked list.
|
/// Head of the free slots linked list.
|
||||||
u16 next_free_slot;
|
u16 next_free_slot;
|
||||||
|
|
||||||
|
KernelSystem& kernel;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern HandleTable g_handle_table;
|
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -50,7 +50,7 @@ SharedPtr<Event> HLERequestContext::SleepClientThread(SharedPtr<Thread> thread,
|
||||||
std::array<u32_le, IPC::COMMAND_BUFFER_LENGTH + 2 * IPC::MAX_STATIC_BUFFERS> cmd_buff;
|
std::array<u32_le, IPC::COMMAND_BUFFER_LENGTH + 2 * IPC::MAX_STATIC_BUFFERS> cmd_buff;
|
||||||
Memory::ReadBlock(*process, thread->GetCommandBufferAddress(), cmd_buff.data(),
|
Memory::ReadBlock(*process, thread->GetCommandBufferAddress(), cmd_buff.data(),
|
||||||
cmd_buff.size() * sizeof(u32));
|
cmd_buff.size() * sizeof(u32));
|
||||||
context.WriteToOutgoingCommandBuffer(cmd_buff.data(), *process, Kernel::g_handle_table);
|
context.WriteToOutgoingCommandBuffer(cmd_buff.data(), *process);
|
||||||
// Copy the translated command buffer back into the thread's command buffer area.
|
// Copy the translated command buffer back into the thread's command buffer area.
|
||||||
Memory::WriteBlock(*process, thread->GetCommandBufferAddress(), cmd_buff.data(),
|
Memory::WriteBlock(*process, thread->GetCommandBufferAddress(), cmd_buff.data(),
|
||||||
cmd_buff.size() * sizeof(u32));
|
cmd_buff.size() * sizeof(u32));
|
||||||
|
@ -98,8 +98,7 @@ void HLERequestContext::AddStaticBuffer(u8 buffer_id, std::vector<u8> data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const u32_le* src_cmdbuf,
|
ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const u32_le* src_cmdbuf,
|
||||||
Process& src_process,
|
Process& src_process) {
|
||||||
HandleTable& src_table) {
|
|
||||||
IPC::Header header{src_cmdbuf[0]};
|
IPC::Header header{src_cmdbuf[0]};
|
||||||
|
|
||||||
std::size_t untranslated_size = 1u + header.normal_params_size;
|
std::size_t untranslated_size = 1u + header.normal_params_size;
|
||||||
|
@ -122,10 +121,10 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const u32_le* sr
|
||||||
Handle handle = src_cmdbuf[i];
|
Handle handle = src_cmdbuf[i];
|
||||||
SharedPtr<Object> object = nullptr;
|
SharedPtr<Object> object = nullptr;
|
||||||
if (handle != 0) {
|
if (handle != 0) {
|
||||||
object = src_table.GetGeneric(handle);
|
object = src_process.handle_table.GetGeneric(handle);
|
||||||
ASSERT(object != nullptr); // TODO(yuriks): Return error
|
ASSERT(object != nullptr); // TODO(yuriks): Return error
|
||||||
if (descriptor == IPC::DescriptorType::MoveHandle) {
|
if (descriptor == IPC::DescriptorType::MoveHandle) {
|
||||||
src_table.Close(handle);
|
src_process.handle_table.Close(handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,8 +162,8 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const u32_le* sr
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, Process& dst_process,
|
ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf,
|
||||||
HandleTable& dst_table) const {
|
Process& dst_process) const {
|
||||||
IPC::Header header{cmd_buf[0]};
|
IPC::Header header{cmd_buf[0]};
|
||||||
|
|
||||||
std::size_t untranslated_size = 1u + header.normal_params_size;
|
std::size_t untranslated_size = 1u + header.normal_params_size;
|
||||||
|
@ -189,7 +188,7 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, P
|
||||||
Handle handle = 0;
|
Handle handle = 0;
|
||||||
if (object != nullptr) {
|
if (object != nullptr) {
|
||||||
// TODO(yuriks): Figure out the proper error handling for if this fails
|
// TODO(yuriks): Figure out the proper error handling for if this fails
|
||||||
handle = dst_table.Create(object).Unwrap();
|
handle = dst_process.handle_table.Create(object).Unwrap();
|
||||||
}
|
}
|
||||||
dst_cmdbuf[i++] = handle;
|
dst_cmdbuf[i++] = handle;
|
||||||
}
|
}
|
||||||
|
|
|
@ -226,11 +226,9 @@ public:
|
||||||
MappedBuffer& GetMappedBuffer(u32 id_from_cmdbuf);
|
MappedBuffer& GetMappedBuffer(u32 id_from_cmdbuf);
|
||||||
|
|
||||||
/// Populates this context with data from the requesting process/thread.
|
/// Populates this context with data from the requesting process/thread.
|
||||||
ResultCode PopulateFromIncomingCommandBuffer(const u32_le* src_cmdbuf, Process& src_process,
|
ResultCode PopulateFromIncomingCommandBuffer(const u32_le* src_cmdbuf, Process& src_process);
|
||||||
HandleTable& src_table);
|
|
||||||
/// Writes data from this context back to the requesting process/thread.
|
/// Writes data from this context back to the requesting process/thread.
|
||||||
ResultCode WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, Process& dst_process,
|
ResultCode WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, Process& dst_process) const;
|
||||||
HandleTable& dst_table) const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
|
std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
|
||||||
|
|
|
@ -60,9 +60,9 @@ ResultCode TranslateCommandBuffer(SharedPtr<Thread> src_thread, SharedPtr<Thread
|
||||||
} else if (handle == CurrentProcess) {
|
} else if (handle == CurrentProcess) {
|
||||||
object = src_process;
|
object = src_process;
|
||||||
} else if (handle != 0) {
|
} else if (handle != 0) {
|
||||||
object = g_handle_table.GetGeneric(handle);
|
object = src_process->handle_table.GetGeneric(handle);
|
||||||
if (descriptor == IPC::DescriptorType::MoveHandle) {
|
if (descriptor == IPC::DescriptorType::MoveHandle) {
|
||||||
g_handle_table.Close(handle);
|
src_process->handle_table.Close(handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ ResultCode TranslateCommandBuffer(SharedPtr<Thread> src_thread, SharedPtr<Thread
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto result = g_handle_table.Create(std::move(object));
|
auto result = dst_process->handle_table.Create(std::move(object));
|
||||||
cmd_buf[i++] = result.ValueOr(0);
|
cmd_buf[i++] = result.ValueOr(0);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -23,17 +23,11 @@ KernelSystem::KernelSystem(u32 system_mode) {
|
||||||
resource_limits = std::make_unique<ResourceLimitList>(*this);
|
resource_limits = std::make_unique<ResourceLimitList>(*this);
|
||||||
Kernel::ThreadingInit();
|
Kernel::ThreadingInit();
|
||||||
Kernel::TimersInit();
|
Kernel::TimersInit();
|
||||||
// TODO(Subv): Start the process ids from 10 for now, as lower PIDs are
|
|
||||||
// reserved for low-level services
|
|
||||||
Process::next_process_id = 10;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shutdown the kernel
|
/// Shutdown the kernel
|
||||||
KernelSystem::~KernelSystem() {
|
KernelSystem::~KernelSystem() {
|
||||||
g_handle_table.Clear(); // Free all kernel objects
|
|
||||||
|
|
||||||
Kernel::ThreadingShutdown();
|
Kernel::ThreadingShutdown();
|
||||||
g_current_process = nullptr;
|
|
||||||
|
|
||||||
Kernel::TimersShutdown();
|
Kernel::TimersShutdown();
|
||||||
Kernel::MemoryShutdown();
|
Kernel::MemoryShutdown();
|
||||||
|
@ -51,4 +45,12 @@ u32 KernelSystem::GenerateObjectID() {
|
||||||
return next_object_id++;
|
return next_object_id++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SharedPtr<Process> KernelSystem::GetCurrentProcess() const {
|
||||||
|
return current_process;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KernelSystem::SetCurrentProcess(SharedPtr<Process> process) {
|
||||||
|
current_process = std::move(process);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
#include <boost/smart_ptr/intrusive_ptr.hpp>
|
#include <boost/smart_ptr/intrusive_ptr.hpp>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "core/hle/result.h"
|
#include "core/hle/result.h"
|
||||||
|
@ -101,7 +102,7 @@ public:
|
||||||
*/
|
*/
|
||||||
ResultVal<SharedPtr<Thread>> CreateThread(std::string name, VAddr entry_point, u32 priority,
|
ResultVal<SharedPtr<Thread>> CreateThread(std::string name, VAddr entry_point, u32 priority,
|
||||||
u32 arg, s32 processor_id, VAddr stack_top,
|
u32 arg, s32 processor_id, VAddr stack_top,
|
||||||
SharedPtr<Process> owner_process);
|
Process& owner_process);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a semaphore.
|
* Creates a semaphore.
|
||||||
|
@ -155,7 +156,7 @@ public:
|
||||||
* linear heap.
|
* linear heap.
|
||||||
* @param name Optional object name, used for debugging purposes.
|
* @param name Optional object name, used for debugging purposes.
|
||||||
*/
|
*/
|
||||||
SharedPtr<SharedMemory> CreateSharedMemory(SharedPtr<Process> owner_process, u32 size,
|
SharedPtr<SharedMemory> CreateSharedMemory(Process* owner_process, u32 size,
|
||||||
MemoryPermission permissions,
|
MemoryPermission permissions,
|
||||||
MemoryPermission other_permissions,
|
MemoryPermission other_permissions,
|
||||||
VAddr address = 0,
|
VAddr address = 0,
|
||||||
|
@ -180,9 +181,24 @@ public:
|
||||||
|
|
||||||
u32 GenerateObjectID();
|
u32 GenerateObjectID();
|
||||||
|
|
||||||
|
/// Retrieves a process from the current list of processes.
|
||||||
|
SharedPtr<Process> GetProcessById(u32 process_id) const;
|
||||||
|
|
||||||
|
SharedPtr<Process> GetCurrentProcess() const;
|
||||||
|
void SetCurrentProcess(SharedPtr<Process> process);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<ResourceLimitList> resource_limits;
|
std::unique_ptr<ResourceLimitList> resource_limits;
|
||||||
std::atomic<u32> next_object_id{0};
|
std::atomic<u32> next_object_id{0};
|
||||||
|
|
||||||
|
// TODO(Subv): Start the process ids from 10 for now, as lower PIDs are
|
||||||
|
// reserved for low-level services
|
||||||
|
u32 next_process_id = 10;
|
||||||
|
|
||||||
|
// Lists all processes that exist in the current session.
|
||||||
|
std::vector<SharedPtr<Process>> process_list;
|
||||||
|
|
||||||
|
SharedPtr<Process> current_process;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -17,9 +17,6 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
// Lists all processes that exist in the current session.
|
|
||||||
static std::vector<SharedPtr<Process>> process_list;
|
|
||||||
|
|
||||||
SharedPtr<CodeSet> KernelSystem::CreateCodeSet(std::string name, u64 program_id) {
|
SharedPtr<CodeSet> KernelSystem::CreateCodeSet(std::string name, u64 program_id) {
|
||||||
SharedPtr<CodeSet> codeset(new CodeSet(*this));
|
SharedPtr<CodeSet> codeset(new CodeSet(*this));
|
||||||
|
|
||||||
|
@ -32,8 +29,6 @@ SharedPtr<CodeSet> KernelSystem::CreateCodeSet(std::string name, u64 program_id)
|
||||||
CodeSet::CodeSet(KernelSystem& kernel) : Object(kernel) {}
|
CodeSet::CodeSet(KernelSystem& kernel) : Object(kernel) {}
|
||||||
CodeSet::~CodeSet() {}
|
CodeSet::~CodeSet() {}
|
||||||
|
|
||||||
u32 Process::next_process_id;
|
|
||||||
|
|
||||||
SharedPtr<Process> KernelSystem::CreateProcess(SharedPtr<CodeSet> code_set) {
|
SharedPtr<Process> KernelSystem::CreateProcess(SharedPtr<CodeSet> code_set) {
|
||||||
SharedPtr<Process> process(new Process(*this));
|
SharedPtr<Process> process(new Process(*this));
|
||||||
|
|
||||||
|
@ -41,6 +36,7 @@ SharedPtr<Process> KernelSystem::CreateProcess(SharedPtr<CodeSet> code_set) {
|
||||||
process->flags.raw = 0;
|
process->flags.raw = 0;
|
||||||
process->flags.memory_region.Assign(MemoryRegion::APPLICATION);
|
process->flags.memory_region.Assign(MemoryRegion::APPLICATION);
|
||||||
process->status = ProcessStatus::Created;
|
process->status = ProcessStatus::Created;
|
||||||
|
process->process_id = ++next_process_id;
|
||||||
|
|
||||||
process_list.push_back(process);
|
process_list.push_back(process);
|
||||||
return process;
|
return process;
|
||||||
|
@ -304,14 +300,11 @@ ResultCode Process::LinearFree(VAddr target, u32 size) {
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
Kernel::Process::Process(KernelSystem& kernel) : Object(kernel), kernel(kernel) {}
|
Kernel::Process::Process(KernelSystem& kernel)
|
||||||
|
: Object(kernel), handle_table(kernel), kernel(kernel) {}
|
||||||
Kernel::Process::~Process() {}
|
Kernel::Process::~Process() {}
|
||||||
|
|
||||||
void ClearProcessList() {
|
SharedPtr<Process> KernelSystem::GetProcessById(u32 process_id) const {
|
||||||
process_list.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
SharedPtr<Process> GetProcessById(u32 process_id) {
|
|
||||||
auto itr = std::find_if(
|
auto itr = std::find_if(
|
||||||
process_list.begin(), process_list.end(),
|
process_list.begin(), process_list.end(),
|
||||||
[&](const SharedPtr<Process>& process) { return process->process_id == process_id; });
|
[&](const SharedPtr<Process>& process) { return process->process_id == process_id; });
|
||||||
|
@ -321,6 +314,4 @@ SharedPtr<Process> GetProcessById(u32 process_id) {
|
||||||
|
|
||||||
return *itr;
|
return *itr;
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedPtr<Process> g_current_process;
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <boost/container/static_vector.hpp>
|
#include <boost/container/static_vector.hpp>
|
||||||
#include "common/bit_field.h"
|
#include "common/bit_field.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "core/hle/kernel/handle_table.h"
|
||||||
#include "core/hle/kernel/object.h"
|
#include "core/hle/kernel/object.h"
|
||||||
#include "core/hle/kernel/vm_manager.h"
|
#include "core/hle/kernel/vm_manager.h"
|
||||||
|
|
||||||
|
@ -123,7 +124,7 @@ public:
|
||||||
return HANDLE_TYPE;
|
return HANDLE_TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 next_process_id;
|
HandleTable handle_table;
|
||||||
|
|
||||||
SharedPtr<CodeSet> codeset;
|
SharedPtr<CodeSet> codeset;
|
||||||
/// Resource limit descriptor for this process
|
/// Resource limit descriptor for this process
|
||||||
|
@ -145,7 +146,7 @@ public:
|
||||||
ProcessStatus status;
|
ProcessStatus status;
|
||||||
|
|
||||||
/// The id of this process
|
/// The id of this process
|
||||||
u32 process_id = next_process_id++;
|
u32 process_id;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a list of kernel capability descriptors (as found in the ExHeader) and applies them
|
* Parses a list of kernel capability descriptors (as found in the ExHeader) and applies them
|
||||||
|
@ -199,11 +200,4 @@ private:
|
||||||
friend class KernelSystem;
|
friend class KernelSystem;
|
||||||
KernelSystem& kernel;
|
KernelSystem& kernel;
|
||||||
};
|
};
|
||||||
|
|
||||||
void ClearProcessList();
|
|
||||||
|
|
||||||
/// Retrieves a process from the current list of processes.
|
|
||||||
SharedPtr<Process> GetProcessById(u32 process_id);
|
|
||||||
|
|
||||||
extern SharedPtr<Process> g_current_process;
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -14,7 +14,7 @@ namespace Kernel {
|
||||||
SharedMemory::SharedMemory(KernelSystem& kernel) : Object(kernel) {}
|
SharedMemory::SharedMemory(KernelSystem& kernel) : Object(kernel) {}
|
||||||
SharedMemory::~SharedMemory() {}
|
SharedMemory::~SharedMemory() {}
|
||||||
|
|
||||||
SharedPtr<SharedMemory> KernelSystem::CreateSharedMemory(SharedPtr<Process> owner_process, u32 size,
|
SharedPtr<SharedMemory> KernelSystem::CreateSharedMemory(Process* owner_process, u32 size,
|
||||||
MemoryPermission permissions,
|
MemoryPermission permissions,
|
||||||
MemoryPermission other_permissions,
|
MemoryPermission other_permissions,
|
||||||
VAddr address, MemoryRegion region,
|
VAddr address, MemoryRegion region,
|
||||||
|
@ -52,8 +52,8 @@ SharedPtr<SharedMemory> KernelSystem::CreateSharedMemory(SharedPtr<Process> owne
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refresh the address mappings for the current process.
|
// Refresh the address mappings for the current process.
|
||||||
if (Kernel::g_current_process != nullptr) {
|
if (current_process != nullptr) {
|
||||||
Kernel::g_current_process->vm_manager.RefreshMemoryBlockMappings(linheap_memory.get());
|
current_process->vm_manager.RefreshMemoryBlockMappings(linheap_memory.get());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
auto& vm_manager = shared_memory->owner_process->vm_manager;
|
auto& vm_manager = shared_memory->owner_process->vm_manager;
|
||||||
|
|
|
@ -58,7 +58,7 @@ public:
|
||||||
u8* GetPointer(u32 offset = 0);
|
u8* GetPointer(u32 offset = 0);
|
||||||
|
|
||||||
/// Process that created this shared memory block.
|
/// Process that created this shared memory block.
|
||||||
SharedPtr<Process> owner_process;
|
Process* owner_process;
|
||||||
/// Address of shared memory block in the owner process if specified.
|
/// Address of shared memory block in the owner process if specified.
|
||||||
VAddr base_address;
|
VAddr base_address;
|
||||||
/// Physical address of the shared memory block in the linear heap if no address was specified
|
/// Physical address of the shared memory block in the linear heap if no address was specified
|
||||||
|
|
|
@ -83,7 +83,7 @@ static ResultCode ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 add
|
||||||
}
|
}
|
||||||
VMAPermission vma_permissions = (VMAPermission)permissions;
|
VMAPermission vma_permissions = (VMAPermission)permissions;
|
||||||
|
|
||||||
auto& process = *g_current_process;
|
auto& process = *Core::System::GetInstance().Kernel().GetCurrentProcess();
|
||||||
|
|
||||||
switch (operation & MEMOP_OPERATION_MASK) {
|
switch (operation & MEMOP_OPERATION_MASK) {
|
||||||
case MEMOP_FREE: {
|
case MEMOP_FREE: {
|
||||||
|
@ -145,16 +145,17 @@ static ResultCode ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 add
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ExitProcess() {
|
static void ExitProcess() {
|
||||||
LOG_INFO(Kernel_SVC, "Process {} exiting", g_current_process->process_id);
|
SharedPtr<Process> current_process = Core::System::GetInstance().Kernel().GetCurrentProcess();
|
||||||
|
LOG_INFO(Kernel_SVC, "Process {} exiting", current_process->process_id);
|
||||||
|
|
||||||
ASSERT_MSG(g_current_process->status == ProcessStatus::Running, "Process has already exited");
|
ASSERT_MSG(current_process->status == ProcessStatus::Running, "Process has already exited");
|
||||||
|
|
||||||
g_current_process->status = ProcessStatus::Exited;
|
current_process->status = ProcessStatus::Exited;
|
||||||
|
|
||||||
// Stop all the process threads that are currently waiting for objects.
|
// Stop all the process threads that are currently waiting for objects.
|
||||||
auto& thread_list = GetThreadList();
|
auto& thread_list = GetThreadList();
|
||||||
for (auto& thread : thread_list) {
|
for (auto& thread : thread_list) {
|
||||||
if (thread->owner_process != g_current_process)
|
if (thread->owner_process != current_process)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (thread == GetCurrentThread())
|
if (thread == GetCurrentThread())
|
||||||
|
@ -181,7 +182,9 @@ static ResultCode MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 o
|
||||||
"otherpermission={}",
|
"otherpermission={}",
|
||||||
handle, addr, permissions, other_permissions);
|
handle, addr, permissions, other_permissions);
|
||||||
|
|
||||||
SharedPtr<SharedMemory> shared_memory = g_handle_table.Get<SharedMemory>(handle);
|
SharedPtr<SharedMemory> shared_memory =
|
||||||
|
Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<SharedMemory>(
|
||||||
|
handle);
|
||||||
if (shared_memory == nullptr)
|
if (shared_memory == nullptr)
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
|
|
||||||
|
@ -195,7 +198,8 @@ static ResultCode MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 o
|
||||||
case MemoryPermission::WriteExecute:
|
case MemoryPermission::WriteExecute:
|
||||||
case MemoryPermission::ReadWriteExecute:
|
case MemoryPermission::ReadWriteExecute:
|
||||||
case MemoryPermission::DontCare:
|
case MemoryPermission::DontCare:
|
||||||
return shared_memory->Map(g_current_process.get(), addr, permissions_type,
|
return shared_memory->Map(Core::System::GetInstance().Kernel().GetCurrentProcess().get(),
|
||||||
|
addr, permissions_type,
|
||||||
static_cast<MemoryPermission>(other_permissions));
|
static_cast<MemoryPermission>(other_permissions));
|
||||||
default:
|
default:
|
||||||
LOG_ERROR(Kernel_SVC, "unknown permissions=0x{:08X}", permissions);
|
LOG_ERROR(Kernel_SVC, "unknown permissions=0x{:08X}", permissions);
|
||||||
|
@ -209,11 +213,12 @@ static ResultCode UnmapMemoryBlock(Handle handle, u32 addr) {
|
||||||
|
|
||||||
// TODO(Subv): Return E0A01BF5 if the address is not in the application's heap
|
// TODO(Subv): Return E0A01BF5 if the address is not in the application's heap
|
||||||
|
|
||||||
SharedPtr<SharedMemory> shared_memory = g_handle_table.Get<SharedMemory>(handle);
|
SharedPtr<Process> current_process = Core::System::GetInstance().Kernel().GetCurrentProcess();
|
||||||
|
SharedPtr<SharedMemory> shared_memory = current_process->handle_table.Get<SharedMemory>(handle);
|
||||||
if (shared_memory == nullptr)
|
if (shared_memory == nullptr)
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
|
|
||||||
return shared_memory->Unmap(g_current_process.get(), addr);
|
return shared_memory->Unmap(current_process.get(), addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Connect to an OS service given the port name, returns the handle to the port to out
|
/// Connect to an OS service given the port name, returns the handle to the port to out
|
||||||
|
@ -241,13 +246,17 @@ static ResultCode ConnectToPort(Handle* out_handle, VAddr port_name_address) {
|
||||||
CASCADE_RESULT(client_session, client_port->Connect());
|
CASCADE_RESULT(client_session, client_port->Connect());
|
||||||
|
|
||||||
// Return the client session
|
// Return the client session
|
||||||
CASCADE_RESULT(*out_handle, g_handle_table.Create(client_session));
|
CASCADE_RESULT(*out_handle,
|
||||||
|
Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Create(
|
||||||
|
client_session));
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Makes a blocking IPC call to an OS service.
|
/// Makes a blocking IPC call to an OS service.
|
||||||
static ResultCode SendSyncRequest(Handle handle) {
|
static ResultCode SendSyncRequest(Handle handle) {
|
||||||
SharedPtr<ClientSession> session = g_handle_table.Get<ClientSession>(handle);
|
SharedPtr<ClientSession> session =
|
||||||
|
Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<ClientSession>(
|
||||||
|
handle);
|
||||||
if (session == nullptr) {
|
if (session == nullptr) {
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
}
|
}
|
||||||
|
@ -262,12 +271,14 @@ static ResultCode SendSyncRequest(Handle handle) {
|
||||||
/// Close a handle
|
/// Close a handle
|
||||||
static ResultCode CloseHandle(Handle handle) {
|
static ResultCode CloseHandle(Handle handle) {
|
||||||
LOG_TRACE(Kernel_SVC, "Closing handle 0x{:08X}", handle);
|
LOG_TRACE(Kernel_SVC, "Closing handle 0x{:08X}", handle);
|
||||||
return g_handle_table.Close(handle);
|
return Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Close(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wait for a handle to synchronize, timeout after the specified nanoseconds
|
/// Wait for a handle to synchronize, timeout after the specified nanoseconds
|
||||||
static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) {
|
static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) {
|
||||||
auto object = g_handle_table.Get<WaitObject>(handle);
|
auto object =
|
||||||
|
Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<WaitObject>(
|
||||||
|
handle);
|
||||||
Thread* thread = GetCurrentThread();
|
Thread* thread = GetCurrentThread();
|
||||||
|
|
||||||
if (object == nullptr)
|
if (object == nullptr)
|
||||||
|
@ -338,7 +349,9 @@ static ResultCode WaitSynchronizationN(s32* out, VAddr handles_address, s32 hand
|
||||||
|
|
||||||
for (int i = 0; i < handle_count; ++i) {
|
for (int i = 0; i < handle_count; ++i) {
|
||||||
Handle handle = Memory::Read32(handles_address + i * sizeof(Handle));
|
Handle handle = Memory::Read32(handles_address + i * sizeof(Handle));
|
||||||
auto object = g_handle_table.Get<WaitObject>(handle);
|
auto object =
|
||||||
|
Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<WaitObject>(
|
||||||
|
handle);
|
||||||
if (object == nullptr)
|
if (object == nullptr)
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
objects[i] = object;
|
objects[i] = object;
|
||||||
|
@ -502,9 +515,11 @@ static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_
|
||||||
using ObjectPtr = SharedPtr<WaitObject>;
|
using ObjectPtr = SharedPtr<WaitObject>;
|
||||||
std::vector<ObjectPtr> objects(handle_count);
|
std::vector<ObjectPtr> objects(handle_count);
|
||||||
|
|
||||||
|
SharedPtr<Process> current_process = Core::System::GetInstance().Kernel().GetCurrentProcess();
|
||||||
|
|
||||||
for (int i = 0; i < handle_count; ++i) {
|
for (int i = 0; i < handle_count; ++i) {
|
||||||
Handle handle = Memory::Read32(handles_address + i * sizeof(Handle));
|
Handle handle = Memory::Read32(handles_address + i * sizeof(Handle));
|
||||||
auto object = g_handle_table.Get<WaitObject>(handle);
|
auto object = current_process->handle_table.Get<WaitObject>(handle);
|
||||||
if (object == nullptr)
|
if (object == nullptr)
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
objects[i] = object;
|
objects[i] = object;
|
||||||
|
@ -515,7 +530,7 @@ static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_
|
||||||
u32* cmd_buff = GetCommandBuffer();
|
u32* cmd_buff = GetCommandBuffer();
|
||||||
IPC::Header header{cmd_buff[0]};
|
IPC::Header header{cmd_buff[0]};
|
||||||
if (reply_target != 0 && header.command_id != 0xFFFF) {
|
if (reply_target != 0 && header.command_id != 0xFFFF) {
|
||||||
auto session = g_handle_table.Get<ServerSession>(reply_target);
|
auto session = current_process->handle_table.Get<ServerSession>(reply_target);
|
||||||
if (session == nullptr)
|
if (session == nullptr)
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
|
|
||||||
|
@ -615,8 +630,10 @@ static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_
|
||||||
|
|
||||||
/// Create an address arbiter (to allocate access to shared resources)
|
/// Create an address arbiter (to allocate access to shared resources)
|
||||||
static ResultCode CreateAddressArbiter(Handle* out_handle) {
|
static ResultCode CreateAddressArbiter(Handle* out_handle) {
|
||||||
SharedPtr<AddressArbiter> arbiter = Core::System::GetInstance().Kernel().CreateAddressArbiter();
|
KernelSystem& kernel = Core::System::GetInstance().Kernel();
|
||||||
CASCADE_RESULT(*out_handle, g_handle_table.Create(std::move(arbiter)));
|
SharedPtr<AddressArbiter> arbiter = kernel.CreateAddressArbiter();
|
||||||
|
CASCADE_RESULT(*out_handle,
|
||||||
|
kernel.GetCurrentProcess()->handle_table.Create(std::move(arbiter)));
|
||||||
LOG_TRACE(Kernel_SVC, "returned handle=0x{:08X}", *out_handle);
|
LOG_TRACE(Kernel_SVC, "returned handle=0x{:08X}", *out_handle);
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -627,7 +644,9 @@ static ResultCode ArbitrateAddress(Handle handle, u32 address, u32 type, u32 val
|
||||||
LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}, address=0x{:08X}, type=0x{:08X}, value=0x{:08X}",
|
LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}, address=0x{:08X}, type=0x{:08X}, value=0x{:08X}",
|
||||||
handle, address, type, value);
|
handle, address, type, value);
|
||||||
|
|
||||||
SharedPtr<AddressArbiter> arbiter = g_handle_table.Get<AddressArbiter>(handle);
|
SharedPtr<AddressArbiter> arbiter =
|
||||||
|
Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<AddressArbiter>(
|
||||||
|
handle);
|
||||||
if (arbiter == nullptr)
|
if (arbiter == nullptr)
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
|
|
||||||
|
@ -675,11 +694,12 @@ static void OutputDebugString(VAddr address, int len) {
|
||||||
static ResultCode GetResourceLimit(Handle* resource_limit, Handle process_handle) {
|
static ResultCode GetResourceLimit(Handle* resource_limit, Handle process_handle) {
|
||||||
LOG_TRACE(Kernel_SVC, "called process=0x{:08X}", process_handle);
|
LOG_TRACE(Kernel_SVC, "called process=0x{:08X}", process_handle);
|
||||||
|
|
||||||
SharedPtr<Process> process = g_handle_table.Get<Process>(process_handle);
|
SharedPtr<Process> current_process = Core::System::GetInstance().Kernel().GetCurrentProcess();
|
||||||
|
SharedPtr<Process> process = current_process->handle_table.Get<Process>(process_handle);
|
||||||
if (process == nullptr)
|
if (process == nullptr)
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
|
|
||||||
CASCADE_RESULT(*resource_limit, g_handle_table.Create(process->resource_limit));
|
CASCADE_RESULT(*resource_limit, current_process->handle_table.Create(process->resource_limit));
|
||||||
|
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -691,7 +711,8 @@ static ResultCode GetResourceLimitCurrentValues(VAddr values, Handle resource_li
|
||||||
resource_limit_handle, names, name_count);
|
resource_limit_handle, names, name_count);
|
||||||
|
|
||||||
SharedPtr<ResourceLimit> resource_limit =
|
SharedPtr<ResourceLimit> resource_limit =
|
||||||
g_handle_table.Get<ResourceLimit>(resource_limit_handle);
|
Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<ResourceLimit>(
|
||||||
|
resource_limit_handle);
|
||||||
if (resource_limit == nullptr)
|
if (resource_limit == nullptr)
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
|
|
||||||
|
@ -711,7 +732,8 @@ static ResultCode GetResourceLimitLimitValues(VAddr values, Handle resource_limi
|
||||||
resource_limit_handle, names, name_count);
|
resource_limit_handle, names, name_count);
|
||||||
|
|
||||||
SharedPtr<ResourceLimit> resource_limit =
|
SharedPtr<ResourceLimit> resource_limit =
|
||||||
g_handle_table.Get<ResourceLimit>(resource_limit_handle);
|
Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<ResourceLimit>(
|
||||||
|
resource_limit_handle);
|
||||||
if (resource_limit == nullptr)
|
if (resource_limit == nullptr)
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
|
|
||||||
|
@ -733,14 +755,16 @@ static ResultCode CreateThread(Handle* out_handle, u32 priority, u32 entry_point
|
||||||
return ERR_OUT_OF_RANGE;
|
return ERR_OUT_OF_RANGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedPtr<ResourceLimit>& resource_limit = g_current_process->resource_limit;
|
SharedPtr<Process> current_process = Core::System::GetInstance().Kernel().GetCurrentProcess();
|
||||||
|
|
||||||
|
SharedPtr<ResourceLimit>& resource_limit = current_process->resource_limit;
|
||||||
if (resource_limit->GetMaxResourceValue(ResourceTypes::PRIORITY) > priority) {
|
if (resource_limit->GetMaxResourceValue(ResourceTypes::PRIORITY) > priority) {
|
||||||
return ERR_NOT_AUTHORIZED;
|
return ERR_NOT_AUTHORIZED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (processor_id == ThreadProcessorIdDefault) {
|
if (processor_id == ThreadProcessorIdDefault) {
|
||||||
// Set the target CPU to the one specified in the process' exheader.
|
// Set the target CPU to the one specified in the process' exheader.
|
||||||
processor_id = g_current_process->ideal_processor;
|
processor_id = current_process->ideal_processor;
|
||||||
ASSERT(processor_id != ThreadProcessorIdDefault);
|
ASSERT(processor_id != ThreadProcessorIdDefault);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -763,12 +787,12 @@ static ResultCode CreateThread(Handle* out_handle, u32 priority, u32 entry_point
|
||||||
|
|
||||||
CASCADE_RESULT(SharedPtr<Thread> thread, Core::System::GetInstance().Kernel().CreateThread(
|
CASCADE_RESULT(SharedPtr<Thread> thread, Core::System::GetInstance().Kernel().CreateThread(
|
||||||
name, entry_point, priority, arg, processor_id,
|
name, entry_point, priority, arg, processor_id,
|
||||||
stack_top, g_current_process));
|
stack_top, *current_process));
|
||||||
|
|
||||||
thread->context->SetFpscr(FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO |
|
thread->context->SetFpscr(FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO |
|
||||||
FPSCR_ROUND_TOZERO); // 0x03C00000
|
FPSCR_ROUND_TOZERO); // 0x03C00000
|
||||||
|
|
||||||
CASCADE_RESULT(*out_handle, g_handle_table.Create(std::move(thread)));
|
CASCADE_RESULT(*out_handle, current_process->handle_table.Create(std::move(thread)));
|
||||||
|
|
||||||
Core::System::GetInstance().PrepareReschedule();
|
Core::System::GetInstance().PrepareReschedule();
|
||||||
|
|
||||||
|
@ -790,7 +814,8 @@ static void ExitThread() {
|
||||||
|
|
||||||
/// Gets the priority for the specified thread
|
/// Gets the priority for the specified thread
|
||||||
static ResultCode GetThreadPriority(u32* priority, Handle handle) {
|
static ResultCode GetThreadPriority(u32* priority, Handle handle) {
|
||||||
const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(handle);
|
const SharedPtr<Thread> thread =
|
||||||
|
Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<Thread>(handle);
|
||||||
if (thread == nullptr)
|
if (thread == nullptr)
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
|
|
||||||
|
@ -804,13 +829,15 @@ static ResultCode SetThreadPriority(Handle handle, u32 priority) {
|
||||||
return ERR_OUT_OF_RANGE;
|
return ERR_OUT_OF_RANGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedPtr<Thread> thread = g_handle_table.Get<Thread>(handle);
|
SharedPtr<Thread> thread =
|
||||||
|
Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<Thread>(handle);
|
||||||
if (thread == nullptr)
|
if (thread == nullptr)
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
|
|
||||||
// Note: The kernel uses the current process's resource limit instead of
|
// Note: The kernel uses the current process's resource limit instead of
|
||||||
// the one from the thread owner's resource limit.
|
// the one from the thread owner's resource limit.
|
||||||
SharedPtr<ResourceLimit>& resource_limit = g_current_process->resource_limit;
|
SharedPtr<ResourceLimit>& resource_limit =
|
||||||
|
Core::System::GetInstance().Kernel().GetCurrentProcess()->resource_limit;
|
||||||
if (resource_limit->GetMaxResourceValue(ResourceTypes::PRIORITY) > priority) {
|
if (resource_limit->GetMaxResourceValue(ResourceTypes::PRIORITY) > priority) {
|
||||||
return ERR_NOT_AUTHORIZED;
|
return ERR_NOT_AUTHORIZED;
|
||||||
}
|
}
|
||||||
|
@ -828,9 +855,10 @@ static ResultCode SetThreadPriority(Handle handle, u32 priority) {
|
||||||
|
|
||||||
/// Create a mutex
|
/// Create a mutex
|
||||||
static ResultCode CreateMutex(Handle* out_handle, u32 initial_locked) {
|
static ResultCode CreateMutex(Handle* out_handle, u32 initial_locked) {
|
||||||
SharedPtr<Mutex> mutex = Core::System::GetInstance().Kernel().CreateMutex(initial_locked != 0);
|
KernelSystem& kernel = Core::System::GetInstance().Kernel();
|
||||||
|
SharedPtr<Mutex> mutex = kernel.CreateMutex(initial_locked != 0);
|
||||||
mutex->name = fmt::format("mutex-{:08x}", Core::CPU().GetReg(14));
|
mutex->name = fmt::format("mutex-{:08x}", Core::CPU().GetReg(14));
|
||||||
CASCADE_RESULT(*out_handle, g_handle_table.Create(std::move(mutex)));
|
CASCADE_RESULT(*out_handle, kernel.GetCurrentProcess()->handle_table.Create(std::move(mutex)));
|
||||||
|
|
||||||
LOG_TRACE(Kernel_SVC, "called initial_locked={} : created handle=0x{:08X}",
|
LOG_TRACE(Kernel_SVC, "called initial_locked={} : created handle=0x{:08X}",
|
||||||
initial_locked ? "true" : "false", *out_handle);
|
initial_locked ? "true" : "false", *out_handle);
|
||||||
|
@ -842,7 +870,8 @@ static ResultCode CreateMutex(Handle* out_handle, u32 initial_locked) {
|
||||||
static ResultCode ReleaseMutex(Handle handle) {
|
static ResultCode ReleaseMutex(Handle handle) {
|
||||||
LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}", handle);
|
LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}", handle);
|
||||||
|
|
||||||
SharedPtr<Mutex> mutex = g_handle_table.Get<Mutex>(handle);
|
SharedPtr<Mutex> mutex =
|
||||||
|
Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<Mutex>(handle);
|
||||||
if (mutex == nullptr)
|
if (mutex == nullptr)
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
|
|
||||||
|
@ -853,7 +882,9 @@ static ResultCode ReleaseMutex(Handle handle) {
|
||||||
static ResultCode GetProcessId(u32* process_id, Handle process_handle) {
|
static ResultCode GetProcessId(u32* process_id, Handle process_handle) {
|
||||||
LOG_TRACE(Kernel_SVC, "called process=0x{:08X}", process_handle);
|
LOG_TRACE(Kernel_SVC, "called process=0x{:08X}", process_handle);
|
||||||
|
|
||||||
const SharedPtr<Process> process = g_handle_table.Get<Process>(process_handle);
|
const SharedPtr<Process> process =
|
||||||
|
Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<Process>(
|
||||||
|
process_handle);
|
||||||
if (process == nullptr)
|
if (process == nullptr)
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
|
|
||||||
|
@ -865,7 +896,9 @@ static ResultCode GetProcessId(u32* process_id, Handle process_handle) {
|
||||||
static ResultCode GetProcessIdOfThread(u32* process_id, Handle thread_handle) {
|
static ResultCode GetProcessIdOfThread(u32* process_id, Handle thread_handle) {
|
||||||
LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
|
LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
|
||||||
|
|
||||||
const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle);
|
const SharedPtr<Thread> thread =
|
||||||
|
Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<Thread>(
|
||||||
|
thread_handle);
|
||||||
if (thread == nullptr)
|
if (thread == nullptr)
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
|
|
||||||
|
@ -881,7 +914,8 @@ static ResultCode GetProcessIdOfThread(u32* process_id, Handle thread_handle) {
|
||||||
static ResultCode GetThreadId(u32* thread_id, Handle handle) {
|
static ResultCode GetThreadId(u32* thread_id, Handle handle) {
|
||||||
LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", handle);
|
LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", handle);
|
||||||
|
|
||||||
const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(handle);
|
const SharedPtr<Thread> thread =
|
||||||
|
Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<Thread>(handle);
|
||||||
if (thread == nullptr)
|
if (thread == nullptr)
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
|
|
||||||
|
@ -891,10 +925,12 @@ static ResultCode GetThreadId(u32* thread_id, Handle handle) {
|
||||||
|
|
||||||
/// Creates a semaphore
|
/// Creates a semaphore
|
||||||
static ResultCode CreateSemaphore(Handle* out_handle, s32 initial_count, s32 max_count) {
|
static ResultCode CreateSemaphore(Handle* out_handle, s32 initial_count, s32 max_count) {
|
||||||
|
KernelSystem& kernel = Core::System::GetInstance().Kernel();
|
||||||
CASCADE_RESULT(SharedPtr<Semaphore> semaphore,
|
CASCADE_RESULT(SharedPtr<Semaphore> semaphore,
|
||||||
Core::System::GetInstance().Kernel().CreateSemaphore(initial_count, max_count));
|
kernel.CreateSemaphore(initial_count, max_count));
|
||||||
semaphore->name = fmt::format("semaphore-{:08x}", Core::CPU().GetReg(14));
|
semaphore->name = fmt::format("semaphore-{:08x}", Core::CPU().GetReg(14));
|
||||||
CASCADE_RESULT(*out_handle, g_handle_table.Create(std::move(semaphore)));
|
CASCADE_RESULT(*out_handle,
|
||||||
|
kernel.GetCurrentProcess()->handle_table.Create(std::move(semaphore)));
|
||||||
|
|
||||||
LOG_TRACE(Kernel_SVC, "called initial_count={}, max_count={}, created handle=0x{:08X}",
|
LOG_TRACE(Kernel_SVC, "called initial_count={}, max_count={}, created handle=0x{:08X}",
|
||||||
initial_count, max_count, *out_handle);
|
initial_count, max_count, *out_handle);
|
||||||
|
@ -905,7 +941,9 @@ static ResultCode CreateSemaphore(Handle* out_handle, s32 initial_count, s32 max
|
||||||
static ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) {
|
static ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) {
|
||||||
LOG_TRACE(Kernel_SVC, "called release_count={}, handle=0x{:08X}", release_count, handle);
|
LOG_TRACE(Kernel_SVC, "called release_count={}, handle=0x{:08X}", release_count, handle);
|
||||||
|
|
||||||
SharedPtr<Semaphore> semaphore = g_handle_table.Get<Semaphore>(handle);
|
SharedPtr<Semaphore> semaphore =
|
||||||
|
Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<Semaphore>(
|
||||||
|
handle);
|
||||||
if (semaphore == nullptr)
|
if (semaphore == nullptr)
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
|
|
||||||
|
@ -917,7 +955,9 @@ static ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count)
|
||||||
/// Query process memory
|
/// Query process memory
|
||||||
static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* page_info,
|
static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* page_info,
|
||||||
Handle process_handle, u32 addr) {
|
Handle process_handle, u32 addr) {
|
||||||
SharedPtr<Process> process = g_handle_table.Get<Process>(process_handle);
|
SharedPtr<Process> process =
|
||||||
|
Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<Process>(
|
||||||
|
process_handle);
|
||||||
if (process == nullptr)
|
if (process == nullptr)
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
|
|
||||||
|
@ -943,9 +983,10 @@ static ResultCode QueryMemory(MemoryInfo* memory_info, PageInfo* page_info, u32
|
||||||
|
|
||||||
/// Create an event
|
/// Create an event
|
||||||
static ResultCode CreateEvent(Handle* out_handle, u32 reset_type) {
|
static ResultCode CreateEvent(Handle* out_handle, u32 reset_type) {
|
||||||
SharedPtr<Event> evt = Core::System::GetInstance().Kernel().CreateEvent(
|
KernelSystem& kernel = Core::System::GetInstance().Kernel();
|
||||||
static_cast<ResetType>(reset_type), fmt::format("event-{:08x}", Core::CPU().GetReg(14)));
|
SharedPtr<Event> evt = kernel.CreateEvent(static_cast<ResetType>(reset_type),
|
||||||
CASCADE_RESULT(*out_handle, g_handle_table.Create(std::move(evt)));
|
fmt::format("event-{:08x}", Core::CPU().GetReg(14)));
|
||||||
|
CASCADE_RESULT(*out_handle, kernel.GetCurrentProcess()->handle_table.Create(std::move(evt)));
|
||||||
|
|
||||||
LOG_TRACE(Kernel_SVC, "called reset_type=0x{:08X} : created handle=0x{:08X}", reset_type,
|
LOG_TRACE(Kernel_SVC, "called reset_type=0x{:08X} : created handle=0x{:08X}", reset_type,
|
||||||
*out_handle);
|
*out_handle);
|
||||||
|
@ -954,7 +995,9 @@ static ResultCode CreateEvent(Handle* out_handle, u32 reset_type) {
|
||||||
|
|
||||||
/// Duplicates a kernel handle
|
/// Duplicates a kernel handle
|
||||||
static ResultCode DuplicateHandle(Handle* out, Handle handle) {
|
static ResultCode DuplicateHandle(Handle* out, Handle handle) {
|
||||||
CASCADE_RESULT(*out, g_handle_table.Duplicate(handle));
|
CASCADE_RESULT(
|
||||||
|
*out,
|
||||||
|
Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Duplicate(handle));
|
||||||
LOG_TRACE(Kernel_SVC, "duplicated 0x{:08X} to 0x{:08X}", handle, *out);
|
LOG_TRACE(Kernel_SVC, "duplicated 0x{:08X} to 0x{:08X}", handle, *out);
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -963,7 +1006,8 @@ static ResultCode DuplicateHandle(Handle* out, Handle handle) {
|
||||||
static ResultCode SignalEvent(Handle handle) {
|
static ResultCode SignalEvent(Handle handle) {
|
||||||
LOG_TRACE(Kernel_SVC, "called event=0x{:08X}", handle);
|
LOG_TRACE(Kernel_SVC, "called event=0x{:08X}", handle);
|
||||||
|
|
||||||
SharedPtr<Event> evt = g_handle_table.Get<Event>(handle);
|
SharedPtr<Event> evt =
|
||||||
|
Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<Event>(handle);
|
||||||
if (evt == nullptr)
|
if (evt == nullptr)
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
|
|
||||||
|
@ -976,7 +1020,8 @@ static ResultCode SignalEvent(Handle handle) {
|
||||||
static ResultCode ClearEvent(Handle handle) {
|
static ResultCode ClearEvent(Handle handle) {
|
||||||
LOG_TRACE(Kernel_SVC, "called event=0x{:08X}", handle);
|
LOG_TRACE(Kernel_SVC, "called event=0x{:08X}", handle);
|
||||||
|
|
||||||
SharedPtr<Event> evt = g_handle_table.Get<Event>(handle);
|
SharedPtr<Event> evt =
|
||||||
|
Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<Event>(handle);
|
||||||
if (evt == nullptr)
|
if (evt == nullptr)
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
|
|
||||||
|
@ -986,9 +1031,10 @@ static ResultCode ClearEvent(Handle handle) {
|
||||||
|
|
||||||
/// Creates a timer
|
/// Creates a timer
|
||||||
static ResultCode CreateTimer(Handle* out_handle, u32 reset_type) {
|
static ResultCode CreateTimer(Handle* out_handle, u32 reset_type) {
|
||||||
SharedPtr<Timer> timer = Core::System::GetInstance().Kernel().CreateTimer(
|
KernelSystem& kernel = Core::System::GetInstance().Kernel();
|
||||||
|
SharedPtr<Timer> timer = kernel.CreateTimer(
|
||||||
static_cast<ResetType>(reset_type), fmt ::format("timer-{:08x}", Core::CPU().GetReg(14)));
|
static_cast<ResetType>(reset_type), fmt ::format("timer-{:08x}", Core::CPU().GetReg(14)));
|
||||||
CASCADE_RESULT(*out_handle, g_handle_table.Create(std::move(timer)));
|
CASCADE_RESULT(*out_handle, kernel.GetCurrentProcess()->handle_table.Create(std::move(timer)));
|
||||||
|
|
||||||
LOG_TRACE(Kernel_SVC, "called reset_type=0x{:08X} : created handle=0x{:08X}", reset_type,
|
LOG_TRACE(Kernel_SVC, "called reset_type=0x{:08X} : created handle=0x{:08X}", reset_type,
|
||||||
*out_handle);
|
*out_handle);
|
||||||
|
@ -999,7 +1045,8 @@ static ResultCode CreateTimer(Handle* out_handle, u32 reset_type) {
|
||||||
static ResultCode ClearTimer(Handle handle) {
|
static ResultCode ClearTimer(Handle handle) {
|
||||||
LOG_TRACE(Kernel_SVC, "called timer=0x{:08X}", handle);
|
LOG_TRACE(Kernel_SVC, "called timer=0x{:08X}", handle);
|
||||||
|
|
||||||
SharedPtr<Timer> timer = g_handle_table.Get<Timer>(handle);
|
SharedPtr<Timer> timer =
|
||||||
|
Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<Timer>(handle);
|
||||||
if (timer == nullptr)
|
if (timer == nullptr)
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
|
|
||||||
|
@ -1015,7 +1062,8 @@ static ResultCode SetTimer(Handle handle, s64 initial, s64 interval) {
|
||||||
return ERR_OUT_OF_RANGE_KERNEL;
|
return ERR_OUT_OF_RANGE_KERNEL;
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedPtr<Timer> timer = g_handle_table.Get<Timer>(handle);
|
SharedPtr<Timer> timer =
|
||||||
|
Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<Timer>(handle);
|
||||||
if (timer == nullptr)
|
if (timer == nullptr)
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
|
|
||||||
|
@ -1028,7 +1076,8 @@ static ResultCode SetTimer(Handle handle, s64 initial, s64 interval) {
|
||||||
static ResultCode CancelTimer(Handle handle) {
|
static ResultCode CancelTimer(Handle handle) {
|
||||||
LOG_TRACE(Kernel_SVC, "called timer=0x{:08X}", handle);
|
LOG_TRACE(Kernel_SVC, "called timer=0x{:08X}", handle);
|
||||||
|
|
||||||
SharedPtr<Timer> timer = g_handle_table.Get<Timer>(handle);
|
SharedPtr<Timer> timer =
|
||||||
|
Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<Timer>(handle);
|
||||||
if (timer == nullptr)
|
if (timer == nullptr)
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
|
|
||||||
|
@ -1097,18 +1146,20 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32
|
||||||
return ERR_INVALID_ADDRESS;
|
return ERR_INVALID_ADDRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SharedPtr<Process> current_process = Core::System::GetInstance().Kernel().GetCurrentProcess();
|
||||||
|
|
||||||
// When trying to create a memory block with address = 0,
|
// When trying to create a memory block with address = 0,
|
||||||
// if the process has the Shared Device Memory flag in the exheader,
|
// if the process has the Shared Device Memory flag in the exheader,
|
||||||
// then we have to allocate from the same region as the caller process instead of the BASE
|
// then we have to allocate from the same region as the caller process instead of the BASE
|
||||||
// region.
|
// region.
|
||||||
MemoryRegion region = MemoryRegion::BASE;
|
MemoryRegion region = MemoryRegion::BASE;
|
||||||
if (addr == 0 && g_current_process->flags.shared_device_mem)
|
if (addr == 0 && current_process->flags.shared_device_mem)
|
||||||
region = g_current_process->flags.memory_region;
|
region = current_process->flags.memory_region;
|
||||||
|
|
||||||
shared_memory = Core::System::GetInstance().Kernel().CreateSharedMemory(
|
shared_memory = Core::System::GetInstance().Kernel().CreateSharedMemory(
|
||||||
g_current_process, size, static_cast<MemoryPermission>(my_permission),
|
current_process.get(), size, static_cast<MemoryPermission>(my_permission),
|
||||||
static_cast<MemoryPermission>(other_permission), addr, region);
|
static_cast<MemoryPermission>(other_permission), addr, region);
|
||||||
CASCADE_RESULT(*out_handle, g_handle_table.Create(std::move(shared_memory)));
|
CASCADE_RESULT(*out_handle, current_process->handle_table.Create(std::move(shared_memory)));
|
||||||
|
|
||||||
LOG_WARNING(Kernel_SVC, "called addr=0x{:08X}", addr);
|
LOG_WARNING(Kernel_SVC, "called addr=0x{:08X}", addr);
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
|
@ -1119,48 +1170,58 @@ static ResultCode CreatePort(Handle* server_port, Handle* client_port, VAddr nam
|
||||||
// TODO(Subv): Implement named ports.
|
// TODO(Subv): Implement named ports.
|
||||||
ASSERT_MSG(name_address == 0, "Named ports are currently unimplemented");
|
ASSERT_MSG(name_address == 0, "Named ports are currently unimplemented");
|
||||||
|
|
||||||
auto ports = Core::System::GetInstance().Kernel().CreatePortPair(max_sessions);
|
KernelSystem& kernel = Core::System::GetInstance().Kernel();
|
||||||
CASCADE_RESULT(*client_port,
|
SharedPtr<Process> current_process = kernel.GetCurrentProcess();
|
||||||
g_handle_table.Create(std::move(std::get<SharedPtr<ClientPort>>(ports))));
|
|
||||||
|
auto ports = kernel.CreatePortPair(max_sessions);
|
||||||
|
CASCADE_RESULT(*client_port, current_process->handle_table.Create(
|
||||||
|
std::move(std::get<SharedPtr<ClientPort>>(ports))));
|
||||||
// Note: The 3DS kernel also leaks the client port handle if the server port handle fails to be
|
// Note: The 3DS kernel also leaks the client port handle if the server port handle fails to be
|
||||||
// created.
|
// created.
|
||||||
CASCADE_RESULT(*server_port,
|
CASCADE_RESULT(*server_port, current_process->handle_table.Create(
|
||||||
g_handle_table.Create(std::move(std::get<SharedPtr<ServerPort>>(ports))));
|
std::move(std::get<SharedPtr<ServerPort>>(ports))));
|
||||||
|
|
||||||
LOG_TRACE(Kernel_SVC, "called max_sessions={}", max_sessions);
|
LOG_TRACE(Kernel_SVC, "called max_sessions={}", max_sessions);
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ResultCode CreateSessionToPort(Handle* out_client_session, Handle client_port_handle) {
|
static ResultCode CreateSessionToPort(Handle* out_client_session, Handle client_port_handle) {
|
||||||
SharedPtr<ClientPort> client_port = g_handle_table.Get<ClientPort>(client_port_handle);
|
SharedPtr<Process> current_process = Core::System::GetInstance().Kernel().GetCurrentProcess();
|
||||||
|
SharedPtr<ClientPort> client_port =
|
||||||
|
current_process->handle_table.Get<ClientPort>(client_port_handle);
|
||||||
if (client_port == nullptr)
|
if (client_port == nullptr)
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
|
|
||||||
CASCADE_RESULT(auto session, client_port->Connect());
|
CASCADE_RESULT(auto session, client_port->Connect());
|
||||||
CASCADE_RESULT(*out_client_session, g_handle_table.Create(std::move(session)));
|
CASCADE_RESULT(*out_client_session, current_process->handle_table.Create(std::move(session)));
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ResultCode CreateSession(Handle* server_session, Handle* client_session) {
|
static ResultCode CreateSession(Handle* server_session, Handle* client_session) {
|
||||||
auto sessions = Core::System::GetInstance().Kernel().CreateSessionPair();
|
KernelSystem& kernel = Core::System::GetInstance().Kernel();
|
||||||
|
auto sessions = kernel.CreateSessionPair();
|
||||||
|
|
||||||
|
SharedPtr<Process> current_process = kernel.GetCurrentProcess();
|
||||||
|
|
||||||
auto& server = std::get<SharedPtr<ServerSession>>(sessions);
|
auto& server = std::get<SharedPtr<ServerSession>>(sessions);
|
||||||
CASCADE_RESULT(*server_session, g_handle_table.Create(std::move(server)));
|
CASCADE_RESULT(*server_session, current_process->handle_table.Create(std::move(server)));
|
||||||
|
|
||||||
auto& client = std::get<SharedPtr<ClientSession>>(sessions);
|
auto& client = std::get<SharedPtr<ClientSession>>(sessions);
|
||||||
CASCADE_RESULT(*client_session, g_handle_table.Create(std::move(client)));
|
CASCADE_RESULT(*client_session, current_process->handle_table.Create(std::move(client)));
|
||||||
|
|
||||||
LOG_TRACE(Kernel_SVC, "called");
|
LOG_TRACE(Kernel_SVC, "called");
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ResultCode AcceptSession(Handle* out_server_session, Handle server_port_handle) {
|
static ResultCode AcceptSession(Handle* out_server_session, Handle server_port_handle) {
|
||||||
SharedPtr<ServerPort> server_port = g_handle_table.Get<ServerPort>(server_port_handle);
|
SharedPtr<Process> current_process = Core::System::GetInstance().Kernel().GetCurrentProcess();
|
||||||
|
SharedPtr<ServerPort> server_port =
|
||||||
|
current_process->handle_table.Get<ServerPort>(server_port_handle);
|
||||||
if (server_port == nullptr)
|
if (server_port == nullptr)
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
|
|
||||||
CASCADE_RESULT(auto session, server_port->Accept());
|
CASCADE_RESULT(auto session, server_port->Accept());
|
||||||
CASCADE_RESULT(*out_server_session, g_handle_table.Create(std::move(session)));
|
CASCADE_RESULT(*out_server_session, current_process->handle_table.Create(std::move(session)));
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1210,7 +1271,9 @@ static ResultCode GetSystemInfo(s64* out, u32 type, s32 param) {
|
||||||
static ResultCode GetProcessInfo(s64* out, Handle process_handle, u32 type) {
|
static ResultCode GetProcessInfo(s64* out, Handle process_handle, u32 type) {
|
||||||
LOG_TRACE(Kernel_SVC, "called process=0x{:08X} type={}", process_handle, type);
|
LOG_TRACE(Kernel_SVC, "called process=0x{:08X} type={}", process_handle, type);
|
||||||
|
|
||||||
SharedPtr<Process> process = g_handle_table.Get<Process>(process_handle);
|
SharedPtr<Process> process =
|
||||||
|
Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<Process>(
|
||||||
|
process_handle);
|
||||||
if (process == nullptr)
|
if (process == nullptr)
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
|
|
||||||
|
@ -1407,7 +1470,8 @@ void CallSVC(u32 immediate) {
|
||||||
// Lock the global kernel mutex when we enter the kernel HLE.
|
// Lock the global kernel mutex when we enter the kernel HLE.
|
||||||
std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
|
std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
|
||||||
|
|
||||||
ASSERT_MSG(g_current_process->status == ProcessStatus::Running,
|
DEBUG_ASSERT_MSG(Core::System::GetInstance().Kernel().GetCurrentProcess()->status ==
|
||||||
|
ProcessStatus::Running,
|
||||||
"Running threads from exiting processes is unimplemented");
|
"Running threads from exiting processes is unimplemented");
|
||||||
|
|
||||||
const FunctionDef* info = GetSVCInfo(immediate);
|
const FunctionDef* info = GetSVCInfo(immediate);
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
@ -37,9 +38,7 @@ void Thread::Acquire(Thread* thread) {
|
||||||
ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
|
ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future, allowing
|
static std::unordered_map<u64, Thread*> wakeup_callback_table;
|
||||||
// us to simply use a pool index or similar.
|
|
||||||
static Kernel::HandleTable wakeup_callback_handle_table;
|
|
||||||
|
|
||||||
// Lists all thread ids that aren't deleted/etc.
|
// Lists all thread ids that aren't deleted/etc.
|
||||||
static std::vector<SharedPtr<Thread>> thread_list;
|
static std::vector<SharedPtr<Thread>> thread_list;
|
||||||
|
@ -69,9 +68,8 @@ Thread* GetCurrentThread() {
|
||||||
|
|
||||||
void Thread::Stop() {
|
void Thread::Stop() {
|
||||||
// Cancel any outstanding wakeup events for this thread
|
// Cancel any outstanding wakeup events for this thread
|
||||||
CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle);
|
CoreTiming::UnscheduleEvent(ThreadWakeupEventType, thread_id);
|
||||||
wakeup_callback_handle_table.Close(callback_handle);
|
wakeup_callback_table.erase(thread_id);
|
||||||
callback_handle = 0;
|
|
||||||
|
|
||||||
// Clean up thread from ready queue
|
// Clean up thread from ready queue
|
||||||
// This is only needed when the thread is termintated forcefully (SVC TerminateProcess)
|
// This is only needed when the thread is termintated forcefully (SVC TerminateProcess)
|
||||||
|
@ -96,7 +94,7 @@ void Thread::Stop() {
|
||||||
u32 tls_page = (tls_address - Memory::TLS_AREA_VADDR) / Memory::PAGE_SIZE;
|
u32 tls_page = (tls_address - Memory::TLS_AREA_VADDR) / Memory::PAGE_SIZE;
|
||||||
u32 tls_slot =
|
u32 tls_slot =
|
||||||
((tls_address - Memory::TLS_AREA_VADDR) % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE;
|
((tls_address - Memory::TLS_AREA_VADDR) % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE;
|
||||||
Kernel::g_current_process->tls_slots[tls_page].reset(tls_slot);
|
owner_process->tls_slots[tls_page].reset(tls_slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -125,9 +123,9 @@ static void SwitchContext(Thread* new_thread) {
|
||||||
"Thread must be ready to become running.");
|
"Thread must be ready to become running.");
|
||||||
|
|
||||||
// Cancel any outstanding wakeup events for this thread
|
// Cancel any outstanding wakeup events for this thread
|
||||||
CoreTiming::UnscheduleEvent(ThreadWakeupEventType, new_thread->callback_handle);
|
CoreTiming::UnscheduleEvent(ThreadWakeupEventType, new_thread->thread_id);
|
||||||
|
|
||||||
auto previous_process = Kernel::g_current_process;
|
auto previous_process = Core::System::GetInstance().Kernel().GetCurrentProcess();
|
||||||
|
|
||||||
current_thread = new_thread;
|
current_thread = new_thread;
|
||||||
|
|
||||||
|
@ -135,8 +133,8 @@ static void SwitchContext(Thread* new_thread) {
|
||||||
new_thread->status = ThreadStatus::Running;
|
new_thread->status = ThreadStatus::Running;
|
||||||
|
|
||||||
if (previous_process != current_thread->owner_process) {
|
if (previous_process != current_thread->owner_process) {
|
||||||
Kernel::g_current_process = current_thread->owner_process;
|
Core::System::GetInstance().Kernel().SetCurrentProcess(current_thread->owner_process);
|
||||||
SetCurrentPageTable(&Kernel::g_current_process->vm_manager.page_table);
|
SetCurrentPageTable(¤t_thread->owner_process->vm_manager.page_table);
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::CPU().LoadContext(new_thread->context);
|
Core::CPU().LoadContext(new_thread->context);
|
||||||
|
@ -185,13 +183,13 @@ void ExitCurrentThread() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback that will wake up the thread it was scheduled for
|
* Callback that will wake up the thread it was scheduled for
|
||||||
* @param thread_handle The handle of the thread that's been awoken
|
* @param thread_id The ID of the thread that's been awoken
|
||||||
* @param cycles_late The number of CPU cycles that have passed since the desired wakeup time
|
* @param cycles_late The number of CPU cycles that have passed since the desired wakeup time
|
||||||
*/
|
*/
|
||||||
static void ThreadWakeupCallback(u64 thread_handle, s64 cycles_late) {
|
static void ThreadWakeupCallback(u64 thread_id, s64 cycles_late) {
|
||||||
SharedPtr<Thread> thread = wakeup_callback_handle_table.Get<Thread>((Handle)thread_handle);
|
SharedPtr<Thread> thread = wakeup_callback_table.at(thread_id);
|
||||||
if (thread == nullptr) {
|
if (thread == nullptr) {
|
||||||
LOG_CRITICAL(Kernel, "Callback fired for invalid thread {:08X}", (Handle)thread_handle);
|
LOG_CRITICAL(Kernel, "Callback fired for invalid thread {:08X}", thread_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,7 +215,7 @@ void Thread::WakeAfterDelay(s64 nanoseconds) {
|
||||||
if (nanoseconds == -1)
|
if (nanoseconds == -1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
CoreTiming::ScheduleEvent(nsToCycles(nanoseconds), ThreadWakeupEventType, callback_handle);
|
CoreTiming::ScheduleEvent(nsToCycles(nanoseconds), ThreadWakeupEventType, thread_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread::ResumeFromWait() {
|
void Thread::ResumeFromWait() {
|
||||||
|
@ -322,8 +320,7 @@ static void ResetThreadContext(const std::unique_ptr<ARM_Interface::ThreadContex
|
||||||
|
|
||||||
ResultVal<SharedPtr<Thread>> KernelSystem::CreateThread(std::string name, VAddr entry_point,
|
ResultVal<SharedPtr<Thread>> KernelSystem::CreateThread(std::string name, VAddr entry_point,
|
||||||
u32 priority, u32 arg, s32 processor_id,
|
u32 priority, u32 arg, s32 processor_id,
|
||||||
VAddr stack_top,
|
VAddr stack_top, Process& owner_process) {
|
||||||
SharedPtr<Process> owner_process) {
|
|
||||||
// Check if priority is in ranged. Lowest priority -> highest priority id.
|
// Check if priority is in ranged. Lowest priority -> highest priority id.
|
||||||
if (priority > ThreadPrioLowest) {
|
if (priority > ThreadPrioLowest) {
|
||||||
LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority);
|
LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority);
|
||||||
|
@ -337,7 +334,7 @@ ResultVal<SharedPtr<Thread>> KernelSystem::CreateThread(std::string name, VAddr
|
||||||
|
|
||||||
// TODO(yuriks): Other checks, returning 0xD9001BEA
|
// TODO(yuriks): Other checks, returning 0xD9001BEA
|
||||||
|
|
||||||
if (!Memory::IsValidVirtualAddress(*owner_process, entry_point)) {
|
if (!Memory::IsValidVirtualAddress(owner_process, entry_point)) {
|
||||||
LOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:08x}", name, entry_point);
|
LOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:08x}", name, entry_point);
|
||||||
// TODO: Verify error
|
// TODO: Verify error
|
||||||
return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
|
return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
|
||||||
|
@ -359,11 +356,11 @@ ResultVal<SharedPtr<Thread>> KernelSystem::CreateThread(std::string name, VAddr
|
||||||
thread->wait_objects.clear();
|
thread->wait_objects.clear();
|
||||||
thread->wait_address = 0;
|
thread->wait_address = 0;
|
||||||
thread->name = std::move(name);
|
thread->name = std::move(name);
|
||||||
thread->callback_handle = wakeup_callback_handle_table.Create(thread).Unwrap();
|
wakeup_callback_table[thread->thread_id] = thread.get();
|
||||||
thread->owner_process = owner_process;
|
thread->owner_process = &owner_process;
|
||||||
|
|
||||||
// Find the next available TLS index, and mark it as used
|
// Find the next available TLS index, and mark it as used
|
||||||
auto& tls_slots = owner_process->tls_slots;
|
auto& tls_slots = owner_process.tls_slots;
|
||||||
|
|
||||||
auto [available_page, available_slot, needs_allocation] = GetFreeThreadLocalSlot(tls_slots);
|
auto [available_page, available_slot, needs_allocation] = GetFreeThreadLocalSlot(tls_slots);
|
||||||
|
|
||||||
|
@ -384,13 +381,13 @@ ResultVal<SharedPtr<Thread>> KernelSystem::CreateThread(std::string name, VAddr
|
||||||
// Allocate some memory from the end of the linear heap for this region.
|
// Allocate some memory from the end of the linear heap for this region.
|
||||||
linheap_memory->insert(linheap_memory->end(), Memory::PAGE_SIZE, 0);
|
linheap_memory->insert(linheap_memory->end(), Memory::PAGE_SIZE, 0);
|
||||||
memory_region->used += Memory::PAGE_SIZE;
|
memory_region->used += Memory::PAGE_SIZE;
|
||||||
owner_process->linear_heap_used += Memory::PAGE_SIZE;
|
owner_process.linear_heap_used += Memory::PAGE_SIZE;
|
||||||
|
|
||||||
tls_slots.emplace_back(0); // The page is completely available at the start
|
tls_slots.emplace_back(0); // The page is completely available at the start
|
||||||
available_page = tls_slots.size() - 1;
|
available_page = tls_slots.size() - 1;
|
||||||
available_slot = 0; // Use the first slot in the new page
|
available_slot = 0; // Use the first slot in the new page
|
||||||
|
|
||||||
auto& vm_manager = owner_process->vm_manager;
|
auto& vm_manager = owner_process.vm_manager;
|
||||||
vm_manager.RefreshMemoryBlockMappings(linheap_memory.get());
|
vm_manager.RefreshMemoryBlockMappings(linheap_memory.get());
|
||||||
|
|
||||||
// Map the page to the current process' address space.
|
// Map the page to the current process' address space.
|
||||||
|
@ -449,7 +446,7 @@ SharedPtr<Thread> SetupMainThread(KernelSystem& kernel, u32 entry_point, u32 pri
|
||||||
// Initialize new "main" thread
|
// Initialize new "main" thread
|
||||||
auto thread_res =
|
auto thread_res =
|
||||||
kernel.CreateThread("main", entry_point, priority, 0, owner_process->ideal_processor,
|
kernel.CreateThread("main", entry_point, priority, 0, owner_process->ideal_processor,
|
||||||
Memory::HEAP_VADDR_END, owner_process);
|
Memory::HEAP_VADDR_END, *owner_process);
|
||||||
|
|
||||||
SharedPtr<Thread> thread = std::move(thread_res).Unwrap();
|
SharedPtr<Thread> thread = std::move(thread_res).Unwrap();
|
||||||
|
|
||||||
|
@ -516,7 +513,6 @@ void ThreadingShutdown() {
|
||||||
}
|
}
|
||||||
thread_list.clear();
|
thread_list.clear();
|
||||||
ready_queue.clear();
|
ready_queue.clear();
|
||||||
ClearProcessList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<SharedPtr<Thread>>& GetThreadList() {
|
const std::vector<SharedPtr<Thread>>& GetThreadList() {
|
||||||
|
|
|
@ -189,7 +189,7 @@ public:
|
||||||
/// Mutexes that this thread is currently waiting for.
|
/// Mutexes that this thread is currently waiting for.
|
||||||
boost::container::flat_set<SharedPtr<Mutex>> pending_mutexes;
|
boost::container::flat_set<SharedPtr<Mutex>> pending_mutexes;
|
||||||
|
|
||||||
SharedPtr<Process> owner_process; ///< Process that owns this thread
|
Process* owner_process; ///< Process that owns this thread
|
||||||
|
|
||||||
/// Objects that the thread is waiting on, in the same order as they were
|
/// Objects that the thread is waiting on, in the same order as they were
|
||||||
// passed to WaitSynchronization1/N.
|
// passed to WaitSynchronization1/N.
|
||||||
|
@ -199,9 +199,6 @@ public:
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
/// Handle used as userdata to reference this object when inserting into the CoreTiming queue.
|
|
||||||
Handle callback_handle;
|
|
||||||
|
|
||||||
using WakeupCallback = void(ThreadWakeupReason reason, SharedPtr<Thread> thread,
|
using WakeupCallback = void(ThreadWakeupReason reason, SharedPtr<Thread> thread,
|
||||||
SharedPtr<WaitObject> object);
|
SharedPtr<WaitObject> object);
|
||||||
// Callback that will be invoked when the thread is resumed from a waiting state. If the thread
|
// Callback that will be invoked when the thread is resumed from a waiting state. If the thread
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
|
#include <unordered_map>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
|
@ -15,12 +16,15 @@ namespace Kernel {
|
||||||
|
|
||||||
/// The event type of the generic timer callback event
|
/// The event type of the generic timer callback event
|
||||||
static CoreTiming::EventType* timer_callback_event_type = nullptr;
|
static CoreTiming::EventType* timer_callback_event_type = nullptr;
|
||||||
// TODO(yuriks): This can be removed if Timer objects are explicitly pooled in the future, allowing
|
|
||||||
// us to simply use a pool index or similar.
|
static u64 next_timer_callback_id;
|
||||||
static Kernel::HandleTable timer_callback_handle_table;
|
static std::unordered_map<u64, Timer*> timer_callback_table;
|
||||||
|
|
||||||
Timer::Timer(KernelSystem& kernel) : WaitObject(kernel) {}
|
Timer::Timer(KernelSystem& kernel) : WaitObject(kernel) {}
|
||||||
Timer::~Timer() {}
|
Timer::~Timer() {
|
||||||
|
Cancel();
|
||||||
|
timer_callback_table.erase(callback_id);
|
||||||
|
}
|
||||||
|
|
||||||
SharedPtr<Timer> KernelSystem::CreateTimer(ResetType reset_type, std::string name) {
|
SharedPtr<Timer> KernelSystem::CreateTimer(ResetType reset_type, std::string name) {
|
||||||
SharedPtr<Timer> timer(new Timer(*this));
|
SharedPtr<Timer> timer(new Timer(*this));
|
||||||
|
@ -30,7 +34,8 @@ SharedPtr<Timer> KernelSystem::CreateTimer(ResetType reset_type, std::string nam
|
||||||
timer->name = std::move(name);
|
timer->name = std::move(name);
|
||||||
timer->initial_delay = 0;
|
timer->initial_delay = 0;
|
||||||
timer->interval_delay = 0;
|
timer->interval_delay = 0;
|
||||||
timer->callback_handle = timer_callback_handle_table.Create(timer).Unwrap();
|
timer->callback_id = ++next_timer_callback_id;
|
||||||
|
timer_callback_table[timer->callback_id] = timer.get();
|
||||||
|
|
||||||
return timer;
|
return timer;
|
||||||
}
|
}
|
||||||
|
@ -57,12 +62,12 @@ void Timer::Set(s64 initial, s64 interval) {
|
||||||
// Immediately invoke the callback
|
// Immediately invoke the callback
|
||||||
Signal(0);
|
Signal(0);
|
||||||
} else {
|
} else {
|
||||||
CoreTiming::ScheduleEvent(nsToCycles(initial), timer_callback_event_type, callback_handle);
|
CoreTiming::ScheduleEvent(nsToCycles(initial), timer_callback_event_type, callback_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Timer::Cancel() {
|
void Timer::Cancel() {
|
||||||
CoreTiming::UnscheduleEvent(timer_callback_event_type, callback_handle);
|
CoreTiming::UnscheduleEvent(timer_callback_event_type, callback_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Timer::Clear() {
|
void Timer::Clear() {
|
||||||
|
@ -87,17 +92,16 @@ void Timer::Signal(s64 cycles_late) {
|
||||||
if (interval_delay != 0) {
|
if (interval_delay != 0) {
|
||||||
// Reschedule the timer with the interval delay
|
// Reschedule the timer with the interval delay
|
||||||
CoreTiming::ScheduleEvent(nsToCycles(interval_delay) - cycles_late,
|
CoreTiming::ScheduleEvent(nsToCycles(interval_delay) - cycles_late,
|
||||||
timer_callback_event_type, callback_handle);
|
timer_callback_event_type, callback_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The timer callback event, called when a timer is fired
|
/// The timer callback event, called when a timer is fired
|
||||||
static void TimerCallback(u64 timer_handle, s64 cycles_late) {
|
static void TimerCallback(u64 callback_id, s64 cycles_late) {
|
||||||
SharedPtr<Timer> timer =
|
SharedPtr<Timer> timer = timer_callback_table.at(callback_id);
|
||||||
timer_callback_handle_table.Get<Timer>(static_cast<Handle>(timer_handle));
|
|
||||||
|
|
||||||
if (timer == nullptr) {
|
if (timer == nullptr) {
|
||||||
LOG_CRITICAL(Kernel, "Callback fired for invalid timer {:08x}", timer_handle);
|
LOG_CRITICAL(Kernel, "Callback fired for invalid timer {:016x}", callback_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,7 +109,8 @@ static void TimerCallback(u64 timer_handle, s64 cycles_late) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimersInit() {
|
void TimersInit() {
|
||||||
timer_callback_handle_table.Clear();
|
next_timer_callback_id = 0;
|
||||||
|
timer_callback_table.clear();
|
||||||
timer_callback_event_type = CoreTiming::RegisterEvent("TimerCallback", TimerCallback);
|
timer_callback_event_type = CoreTiming::RegisterEvent("TimerCallback", TimerCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,8 +71,8 @@ private:
|
||||||
bool signaled; ///< Whether the timer has been signaled or not
|
bool signaled; ///< Whether the timer has been signaled or not
|
||||||
std::string name; ///< Name of timer (optional)
|
std::string name; ///< Name of timer (optional)
|
||||||
|
|
||||||
/// Handle used as userdata to reference this object when inserting into the CoreTiming queue.
|
/// ID used as userdata to reference this object when inserting into the CoreTiming queue.
|
||||||
Handle callback_handle;
|
u64 callback_id;
|
||||||
|
|
||||||
friend class KernelSystem;
|
friend class KernelSystem;
|
||||||
};
|
};
|
||||||
|
|
|
@ -258,7 +258,7 @@ ResultVal<AppletManager::InitializeResult> AppletManager::Initialize(AppletId ap
|
||||||
slot_data->applet_id = static_cast<AppletId>(app_id);
|
slot_data->applet_id = static_cast<AppletId>(app_id);
|
||||||
// Note: In the real console the title id of a given applet slot is set by the APT module when
|
// Note: In the real console the title id of a given applet slot is set by the APT module when
|
||||||
// calling StartApplication.
|
// calling StartApplication.
|
||||||
slot_data->title_id = Kernel::g_current_process->codeset->program_id;
|
slot_data->title_id = system.Kernel().GetCurrentProcess()->codeset->program_id;
|
||||||
slot_data->attributes.raw = attributes.raw;
|
slot_data->attributes.raw = attributes.raw;
|
||||||
|
|
||||||
if (slot_data->applet_id == AppletId::Application ||
|
if (slot_data->applet_id == AppletId::Application ||
|
||||||
|
|
|
@ -97,7 +97,7 @@ void Module::Interface::Open(Kernel::HLERequestContext& ctx) {
|
||||||
|
|
||||||
if (path_type == CecDataPathType::MboxProgramId) {
|
if (path_type == CecDataPathType::MboxProgramId) {
|
||||||
std::vector<u8> program_id(8);
|
std::vector<u8> program_id(8);
|
||||||
u64_le le_program_id = Kernel::g_current_process->codeset->program_id;
|
u64_le le_program_id = cecd->system.Kernel().GetCurrentProcess()->codeset->program_id;
|
||||||
std::memcpy(program_id.data(), &le_program_id, sizeof(u64));
|
std::memcpy(program_id.data(), &le_program_id, sizeof(u64));
|
||||||
session_data->file->Write(0, sizeof(u64), true, program_id.data());
|
session_data->file->Write(0, sizeof(u64), true, program_id.data());
|
||||||
session_data->file->Close();
|
session_data->file->Close();
|
||||||
|
@ -1351,7 +1351,7 @@ Module::SessionData::~SessionData() {
|
||||||
Module::Interface::Interface(std::shared_ptr<Module> cecd, const char* name, u32 max_session)
|
Module::Interface::Interface(std::shared_ptr<Module> cecd, const char* name, u32 max_session)
|
||||||
: ServiceFramework(name, max_session), cecd(std::move(cecd)) {}
|
: ServiceFramework(name, max_session), cecd(std::move(cecd)) {}
|
||||||
|
|
||||||
Module::Module(Core::System& system) {
|
Module::Module(Core::System& system) : system(system) {
|
||||||
using namespace Kernel;
|
using namespace Kernel;
|
||||||
cecinfo_event = system.Kernel().CreateEvent(Kernel::ResetType::OneShot, "CECD::cecinfo_event");
|
cecinfo_event = system.Kernel().CreateEvent(Kernel::ResetType::OneShot, "CECD::cecinfo_event");
|
||||||
change_state_event =
|
change_state_event =
|
||||||
|
|
|
@ -610,6 +610,8 @@ private:
|
||||||
|
|
||||||
Kernel::SharedPtr<Kernel::Event> cecinfo_event;
|
Kernel::SharedPtr<Kernel::Event> cecinfo_event;
|
||||||
Kernel::SharedPtr<Kernel::Event> change_state_event;
|
Kernel::SharedPtr<Kernel::Event> change_state_event;
|
||||||
|
|
||||||
|
Core::System& system;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Initialize CECD service(s)
|
/// Initialize CECD service(s)
|
||||||
|
|
|
@ -619,7 +619,7 @@ void FS_USER::GetProgramLaunchInfo(Kernel::HLERequestContext& ctx) {
|
||||||
|
|
||||||
// TODO(Subv): The real FS service manages its own process list and only checks the processes
|
// TODO(Subv): The real FS service manages its own process list and only checks the processes
|
||||||
// that were registered with the 'fs:REG' service.
|
// that were registered with the 'fs:REG' service.
|
||||||
auto process = Kernel::GetProcessById(process_id);
|
auto process = system.Kernel().GetProcessById(process_id);
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(5, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(5, 0);
|
||||||
|
|
||||||
|
|
|
@ -188,11 +188,13 @@ void ServiceFrameworkBase::HandleSyncRequest(SharedPtr<ServerSession> server_ses
|
||||||
return ReportUnimplementedFunction(cmd_buf, info);
|
return ReportUnimplementedFunction(cmd_buf, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Kernel::SharedPtr<Kernel::Process> current_process =
|
||||||
|
Core::System::GetInstance().Kernel().GetCurrentProcess();
|
||||||
|
|
||||||
// TODO(yuriks): The kernel should be the one handling this as part of translation after
|
// TODO(yuriks): The kernel should be the one handling this as part of translation after
|
||||||
// everything else is migrated
|
// everything else is migrated
|
||||||
Kernel::HLERequestContext context(std::move(server_session));
|
Kernel::HLERequestContext context(std::move(server_session));
|
||||||
context.PopulateFromIncomingCommandBuffer(cmd_buf, *Kernel::g_current_process,
|
context.PopulateFromIncomingCommandBuffer(cmd_buf, *current_process);
|
||||||
Kernel::g_handle_table);
|
|
||||||
|
|
||||||
LOG_TRACE(Service, "{}", MakeFunctionString(info->name, GetServiceName().c_str(), cmd_buf));
|
LOG_TRACE(Service, "{}", MakeFunctionString(info->name, GetServiceName().c_str(), cmd_buf));
|
||||||
handler_invoker(this, info->handler_callback, context);
|
handler_invoker(this, info->handler_callback, context);
|
||||||
|
@ -204,8 +206,7 @@ void ServiceFrameworkBase::HandleSyncRequest(SharedPtr<ServerSession> server_ses
|
||||||
// the thread to sleep then the writing of the command buffer will be deferred to the wakeup
|
// the thread to sleep then the writing of the command buffer will be deferred to the wakeup
|
||||||
// callback.
|
// callback.
|
||||||
if (thread->status == Kernel::ThreadStatus::Running) {
|
if (thread->status == Kernel::ThreadStatus::Running) {
|
||||||
context.WriteToOutgoingCommandBuffer(cmd_buf, *Kernel::g_current_process,
|
context.WriteToOutgoingCommandBuffer(cmd_buf, *current_process);
|
||||||
Kernel::g_handle_table);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -111,7 +111,7 @@ static u8* GetPointerFromVMA(const Kernel::Process& process, VAddr vaddr) {
|
||||||
* using a VMA from the current process.
|
* using a VMA from the current process.
|
||||||
*/
|
*/
|
||||||
static u8* GetPointerFromVMA(VAddr vaddr) {
|
static u8* GetPointerFromVMA(VAddr vaddr) {
|
||||||
return GetPointerFromVMA(*Kernel::g_current_process, vaddr);
|
return GetPointerFromVMA(*Core::System::GetInstance().Kernel().GetCurrentProcess(), vaddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -128,7 +128,8 @@ static MMIORegionPointer GetMMIOHandler(const PageTable& page_table, VAddr vaddr
|
||||||
}
|
}
|
||||||
|
|
||||||
static MMIORegionPointer GetMMIOHandler(VAddr vaddr) {
|
static MMIORegionPointer GetMMIOHandler(VAddr vaddr) {
|
||||||
const PageTable& page_table = Kernel::g_current_process->vm_manager.page_table;
|
const PageTable& page_table =
|
||||||
|
Core::System::GetInstance().Kernel().GetCurrentProcess()->vm_manager.page_table;
|
||||||
return GetMMIOHandler(page_table, vaddr);
|
return GetMMIOHandler(page_table, vaddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,7 +230,7 @@ bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsValidVirtualAddress(const VAddr vaddr) {
|
bool IsValidVirtualAddress(const VAddr vaddr) {
|
||||||
return IsValidVirtualAddress(*Kernel::g_current_process, vaddr);
|
return IsValidVirtualAddress(*Core::System::GetInstance().Kernel().GetCurrentProcess(), vaddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsValidPhysicalAddress(const PAddr paddr) {
|
bool IsValidPhysicalAddress(const PAddr paddr) {
|
||||||
|
@ -524,7 +525,8 @@ void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_t size) {
|
void ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_t size) {
|
||||||
ReadBlock(*Kernel::g_current_process, src_addr, dest_buffer, size);
|
ReadBlock(*Core::System::GetInstance().Kernel().GetCurrentProcess(), src_addr, dest_buffer,
|
||||||
|
size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Write8(const VAddr addr, const u8 data) {
|
void Write8(const VAddr addr, const u8 data) {
|
||||||
|
@ -592,7 +594,8 @@ void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const voi
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t size) {
|
void WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t size) {
|
||||||
WriteBlock(*Kernel::g_current_process, dest_addr, src_buffer, size);
|
WriteBlock(*Core::System::GetInstance().Kernel().GetCurrentProcess(), dest_addr, src_buffer,
|
||||||
|
size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) {
|
void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) {
|
||||||
|
@ -644,7 +647,7 @@ void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std:
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZeroBlock(const VAddr dest_addr, const std::size_t size) {
|
void ZeroBlock(const VAddr dest_addr, const std::size_t size) {
|
||||||
ZeroBlock(*Kernel::g_current_process, dest_addr, size);
|
ZeroBlock(*Core::System::GetInstance().Kernel().GetCurrentProcess(), dest_addr, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr,
|
void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr,
|
||||||
|
@ -699,7 +702,7 @@ void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr,
|
||||||
}
|
}
|
||||||
|
|
||||||
void CopyBlock(VAddr dest_addr, VAddr src_addr, const std::size_t size) {
|
void CopyBlock(VAddr dest_addr, VAddr src_addr, const std::size_t size) {
|
||||||
CopyBlock(*Kernel::g_current_process, dest_addr, src_addr, size);
|
CopyBlock(*Core::System::GetInstance().Kernel().GetCurrentProcess(), dest_addr, src_addr, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
|
@ -778,7 +781,8 @@ std::optional<VAddr> PhysicalToVirtualAddress(const PAddr addr) {
|
||||||
} else if (addr >= VRAM_PADDR && addr < VRAM_PADDR_END) {
|
} else if (addr >= VRAM_PADDR && addr < VRAM_PADDR_END) {
|
||||||
return addr - VRAM_PADDR + VRAM_VADDR;
|
return addr - VRAM_PADDR + VRAM_VADDR;
|
||||||
} else if (addr >= FCRAM_PADDR && addr < FCRAM_PADDR_END) {
|
} else if (addr >= FCRAM_PADDR && addr < FCRAM_PADDR_END) {
|
||||||
return addr - FCRAM_PADDR + Kernel::g_current_process->GetLinearHeapAreaAddress();
|
return addr - FCRAM_PADDR +
|
||||||
|
Core::System::GetInstance().Kernel().GetCurrentProcess()->GetLinearHeapAreaAddress();
|
||||||
} else if (addr >= DSP_RAM_PADDR && addr < DSP_RAM_PADDR_END) {
|
} else if (addr >= DSP_RAM_PADDR && addr < DSP_RAM_PADDR_END) {
|
||||||
return addr - DSP_RAM_PADDR + DSP_RAM_VADDR;
|
return addr - DSP_RAM_PADDR + DSP_RAM_VADDR;
|
||||||
} else if (addr >= IO_AREA_PADDR && addr < IO_AREA_PADDR_END) {
|
} else if (addr >= IO_AREA_PADDR && addr < IO_AREA_PADDR_END) {
|
||||||
|
|
|
@ -17,10 +17,14 @@ TestEnvironment::TestEnvironment(bool mutable_memory_)
|
||||||
: mutable_memory(mutable_memory_), test_memory(std::make_shared<TestMemory>(this)) {
|
: mutable_memory(mutable_memory_), test_memory(std::make_shared<TestMemory>(this)) {
|
||||||
|
|
||||||
CoreTiming::Init();
|
CoreTiming::Init();
|
||||||
kernel = std::make_unique<Kernel::KernelSystem>(0);
|
// HACK: some memory functions are currently referring kernel from the global instance,
|
||||||
|
// so we need to create the kernel object there.
|
||||||
|
// Change this when all global states are eliminated.
|
||||||
|
Core::System::GetInstance().kernel = std::make_unique<Kernel::KernelSystem>(0);
|
||||||
|
kernel = Core::System::GetInstance().kernel.get();
|
||||||
|
|
||||||
Kernel::g_current_process = kernel->CreateProcess(kernel->CreateCodeSet("", 0));
|
kernel->SetCurrentProcess(kernel->CreateProcess(kernel->CreateCodeSet("", 0)));
|
||||||
page_table = &Kernel::g_current_process->vm_manager.page_table;
|
page_table = &kernel->GetCurrentProcess()->vm_manager.page_table;
|
||||||
|
|
||||||
page_table->pointers.fill(nullptr);
|
page_table->pointers.fill(nullptr);
|
||||||
page_table->attributes.fill(Memory::PageType::Unmapped);
|
page_table->attributes.fill(Memory::PageType::Unmapped);
|
||||||
|
|
|
@ -80,7 +80,7 @@ private:
|
||||||
std::shared_ptr<TestMemory> test_memory;
|
std::shared_ptr<TestMemory> test_memory;
|
||||||
std::vector<WriteRecord> write_records;
|
std::vector<WriteRecord> write_records;
|
||||||
|
|
||||||
std::unique_ptr<Kernel::KernelSystem> kernel;
|
Kernel::KernelSystem* kernel;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ArmTests
|
} // namespace ArmTests
|
||||||
|
|
|
@ -26,14 +26,13 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
|
||||||
HLERequestContext context(std::move(session));
|
HLERequestContext context(std::move(session));
|
||||||
|
|
||||||
auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0));
|
auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0));
|
||||||
HandleTable handle_table;
|
|
||||||
|
|
||||||
SECTION("works with empty cmdbuf") {
|
SECTION("works with empty cmdbuf") {
|
||||||
const u32_le input[]{
|
const u32_le input[]{
|
||||||
IPC::MakeHeader(0x1234, 0, 0),
|
IPC::MakeHeader(0x1234, 0, 0),
|
||||||
};
|
};
|
||||||
|
|
||||||
context.PopulateFromIncomingCommandBuffer(input, *process, handle_table);
|
context.PopulateFromIncomingCommandBuffer(input, *process);
|
||||||
|
|
||||||
REQUIRE(context.CommandBuffer()[0] == 0x12340000);
|
REQUIRE(context.CommandBuffer()[0] == 0x12340000);
|
||||||
}
|
}
|
||||||
|
@ -46,7 +45,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
|
||||||
0xAABBCCDD,
|
0xAABBCCDD,
|
||||||
};
|
};
|
||||||
|
|
||||||
context.PopulateFromIncomingCommandBuffer(input, *process, handle_table);
|
context.PopulateFromIncomingCommandBuffer(input, *process);
|
||||||
|
|
||||||
auto* output = context.CommandBuffer();
|
auto* output = context.CommandBuffer();
|
||||||
REQUIRE(output[1] == 0x12345678);
|
REQUIRE(output[1] == 0x12345678);
|
||||||
|
@ -56,34 +55,34 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
|
||||||
|
|
||||||
SECTION("translates move handles") {
|
SECTION("translates move handles") {
|
||||||
auto a = MakeObject(kernel);
|
auto a = MakeObject(kernel);
|
||||||
Handle a_handle = handle_table.Create(a).Unwrap();
|
Handle a_handle = process->handle_table.Create(a).Unwrap();
|
||||||
const u32_le input[]{
|
const u32_le input[]{
|
||||||
IPC::MakeHeader(0, 0, 2),
|
IPC::MakeHeader(0, 0, 2),
|
||||||
IPC::MoveHandleDesc(1),
|
IPC::MoveHandleDesc(1),
|
||||||
a_handle,
|
a_handle,
|
||||||
};
|
};
|
||||||
|
|
||||||
context.PopulateFromIncomingCommandBuffer(input, *process, handle_table);
|
context.PopulateFromIncomingCommandBuffer(input, *process);
|
||||||
|
|
||||||
auto* output = context.CommandBuffer();
|
auto* output = context.CommandBuffer();
|
||||||
REQUIRE(context.GetIncomingHandle(output[2]) == a);
|
REQUIRE(context.GetIncomingHandle(output[2]) == a);
|
||||||
REQUIRE(handle_table.GetGeneric(a_handle) == nullptr);
|
REQUIRE(process->handle_table.GetGeneric(a_handle) == nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("translates copy handles") {
|
SECTION("translates copy handles") {
|
||||||
auto a = MakeObject(kernel);
|
auto a = MakeObject(kernel);
|
||||||
Handle a_handle = handle_table.Create(a).Unwrap();
|
Handle a_handle = process->handle_table.Create(a).Unwrap();
|
||||||
const u32_le input[]{
|
const u32_le input[]{
|
||||||
IPC::MakeHeader(0, 0, 2),
|
IPC::MakeHeader(0, 0, 2),
|
||||||
IPC::CopyHandleDesc(1),
|
IPC::CopyHandleDesc(1),
|
||||||
a_handle,
|
a_handle,
|
||||||
};
|
};
|
||||||
|
|
||||||
context.PopulateFromIncomingCommandBuffer(input, *process, handle_table);
|
context.PopulateFromIncomingCommandBuffer(input, *process);
|
||||||
|
|
||||||
auto* output = context.CommandBuffer();
|
auto* output = context.CommandBuffer();
|
||||||
REQUIRE(context.GetIncomingHandle(output[2]) == a);
|
REQUIRE(context.GetIncomingHandle(output[2]) == a);
|
||||||
REQUIRE(handle_table.GetGeneric(a_handle) == a);
|
REQUIRE(process->handle_table.GetGeneric(a_handle) == a);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("translates multi-handle descriptors") {
|
SECTION("translates multi-handle descriptors") {
|
||||||
|
@ -91,12 +90,15 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
|
||||||
auto b = MakeObject(kernel);
|
auto b = MakeObject(kernel);
|
||||||
auto c = MakeObject(kernel);
|
auto c = MakeObject(kernel);
|
||||||
const u32_le input[]{
|
const u32_le input[]{
|
||||||
IPC::MakeHeader(0, 0, 5), IPC::MoveHandleDesc(2),
|
IPC::MakeHeader(0, 0, 5),
|
||||||
handle_table.Create(a).Unwrap(), handle_table.Create(b).Unwrap(),
|
IPC::MoveHandleDesc(2),
|
||||||
IPC::MoveHandleDesc(1), handle_table.Create(c).Unwrap(),
|
process->handle_table.Create(a).Unwrap(),
|
||||||
|
process->handle_table.Create(b).Unwrap(),
|
||||||
|
IPC::MoveHandleDesc(1),
|
||||||
|
process->handle_table.Create(c).Unwrap(),
|
||||||
};
|
};
|
||||||
|
|
||||||
context.PopulateFromIncomingCommandBuffer(input, *process, handle_table);
|
context.PopulateFromIncomingCommandBuffer(input, *process);
|
||||||
|
|
||||||
auto* output = context.CommandBuffer();
|
auto* output = context.CommandBuffer();
|
||||||
REQUIRE(context.GetIncomingHandle(output[2]) == a);
|
REQUIRE(context.GetIncomingHandle(output[2]) == a);
|
||||||
|
@ -111,7 +113,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
|
||||||
0,
|
0,
|
||||||
};
|
};
|
||||||
|
|
||||||
auto result = context.PopulateFromIncomingCommandBuffer(input, *process, handle_table);
|
auto result = context.PopulateFromIncomingCommandBuffer(input, *process);
|
||||||
|
|
||||||
REQUIRE(result == RESULT_SUCCESS);
|
REQUIRE(result == RESULT_SUCCESS);
|
||||||
auto* output = context.CommandBuffer();
|
auto* output = context.CommandBuffer();
|
||||||
|
@ -125,7 +127,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
|
||||||
0x98989898,
|
0x98989898,
|
||||||
};
|
};
|
||||||
|
|
||||||
context.PopulateFromIncomingCommandBuffer(input, *process, handle_table);
|
context.PopulateFromIncomingCommandBuffer(input, *process);
|
||||||
|
|
||||||
REQUIRE(context.CommandBuffer()[2] == process->process_id);
|
REQUIRE(context.CommandBuffer()[2] == process->process_id);
|
||||||
}
|
}
|
||||||
|
@ -145,7 +147,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
|
||||||
target_address,
|
target_address,
|
||||||
};
|
};
|
||||||
|
|
||||||
context.PopulateFromIncomingCommandBuffer(input, *process, handle_table);
|
context.PopulateFromIncomingCommandBuffer(input, *process);
|
||||||
|
|
||||||
CHECK(context.GetStaticBuffer(0) == *buffer);
|
CHECK(context.GetStaticBuffer(0) == *buffer);
|
||||||
|
|
||||||
|
@ -166,7 +168,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
|
||||||
target_address,
|
target_address,
|
||||||
};
|
};
|
||||||
|
|
||||||
context.PopulateFromIncomingCommandBuffer(input, *process, handle_table);
|
context.PopulateFromIncomingCommandBuffer(input, *process);
|
||||||
|
|
||||||
std::vector<u8> other_buffer(buffer->size());
|
std::vector<u8> other_buffer(buffer->size());
|
||||||
context.GetMappedBuffer(0).Read(other_buffer.data(), 0, buffer->size());
|
context.GetMappedBuffer(0).Read(other_buffer.data(), 0, buffer->size());
|
||||||
|
@ -199,7 +201,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
|
||||||
0x12345678,
|
0x12345678,
|
||||||
0xABCDEF00,
|
0xABCDEF00,
|
||||||
IPC::MoveHandleDesc(1),
|
IPC::MoveHandleDesc(1),
|
||||||
handle_table.Create(a).Unwrap(),
|
process->handle_table.Create(a).Unwrap(),
|
||||||
IPC::CallingPidDesc(),
|
IPC::CallingPidDesc(),
|
||||||
0,
|
0,
|
||||||
IPC::StaticBufferDesc(buffer_static->size(), 0),
|
IPC::StaticBufferDesc(buffer_static->size(), 0),
|
||||||
|
@ -208,7 +210,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
|
||||||
target_address_mapped,
|
target_address_mapped,
|
||||||
};
|
};
|
||||||
|
|
||||||
context.PopulateFromIncomingCommandBuffer(input, *process, handle_table);
|
context.PopulateFromIncomingCommandBuffer(input, *process);
|
||||||
|
|
||||||
auto* output = context.CommandBuffer();
|
auto* output = context.CommandBuffer();
|
||||||
CHECK(output[1] == 0x12345678);
|
CHECK(output[1] == 0x12345678);
|
||||||
|
@ -236,14 +238,13 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") {
|
||||||
HLERequestContext context(std::move(session));
|
HLERequestContext context(std::move(session));
|
||||||
|
|
||||||
auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0));
|
auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0));
|
||||||
HandleTable handle_table;
|
|
||||||
auto* input = context.CommandBuffer();
|
auto* input = context.CommandBuffer();
|
||||||
u32_le output[IPC::COMMAND_BUFFER_LENGTH];
|
u32_le output[IPC::COMMAND_BUFFER_LENGTH];
|
||||||
|
|
||||||
SECTION("works with empty cmdbuf") {
|
SECTION("works with empty cmdbuf") {
|
||||||
input[0] = IPC::MakeHeader(0x1234, 0, 0);
|
input[0] = IPC::MakeHeader(0x1234, 0, 0);
|
||||||
|
|
||||||
context.WriteToOutgoingCommandBuffer(output, *process, handle_table);
|
context.WriteToOutgoingCommandBuffer(output, *process);
|
||||||
|
|
||||||
REQUIRE(output[0] == 0x12340000);
|
REQUIRE(output[0] == 0x12340000);
|
||||||
}
|
}
|
||||||
|
@ -254,7 +255,7 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") {
|
||||||
input[2] = 0x21122112;
|
input[2] = 0x21122112;
|
||||||
input[3] = 0xAABBCCDD;
|
input[3] = 0xAABBCCDD;
|
||||||
|
|
||||||
context.WriteToOutgoingCommandBuffer(output, *process, handle_table);
|
context.WriteToOutgoingCommandBuffer(output, *process);
|
||||||
|
|
||||||
REQUIRE(output[1] == 0x12345678);
|
REQUIRE(output[1] == 0x12345678);
|
||||||
REQUIRE(output[2] == 0x21122112);
|
REQUIRE(output[2] == 0x21122112);
|
||||||
|
@ -270,10 +271,10 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") {
|
||||||
input[3] = IPC::CopyHandleDesc(1);
|
input[3] = IPC::CopyHandleDesc(1);
|
||||||
input[4] = context.AddOutgoingHandle(b);
|
input[4] = context.AddOutgoingHandle(b);
|
||||||
|
|
||||||
context.WriteToOutgoingCommandBuffer(output, *process, handle_table);
|
context.WriteToOutgoingCommandBuffer(output, *process);
|
||||||
|
|
||||||
REQUIRE(handle_table.GetGeneric(output[2]) == a);
|
REQUIRE(process->handle_table.GetGeneric(output[2]) == a);
|
||||||
REQUIRE(handle_table.GetGeneric(output[4]) == b);
|
REQUIRE(process->handle_table.GetGeneric(output[4]) == b);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("translates null handles") {
|
SECTION("translates null handles") {
|
||||||
|
@ -281,7 +282,7 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") {
|
||||||
input[1] = IPC::MoveHandleDesc(1);
|
input[1] = IPC::MoveHandleDesc(1);
|
||||||
input[2] = context.AddOutgoingHandle(nullptr);
|
input[2] = context.AddOutgoingHandle(nullptr);
|
||||||
|
|
||||||
auto result = context.WriteToOutgoingCommandBuffer(output, *process, handle_table);
|
auto result = context.WriteToOutgoingCommandBuffer(output, *process);
|
||||||
|
|
||||||
REQUIRE(result == RESULT_SUCCESS);
|
REQUIRE(result == RESULT_SUCCESS);
|
||||||
REQUIRE(output[2] == 0);
|
REQUIRE(output[2] == 0);
|
||||||
|
@ -298,11 +299,11 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") {
|
||||||
input[4] = IPC::CopyHandleDesc(1);
|
input[4] = IPC::CopyHandleDesc(1);
|
||||||
input[5] = context.AddOutgoingHandle(c);
|
input[5] = context.AddOutgoingHandle(c);
|
||||||
|
|
||||||
context.WriteToOutgoingCommandBuffer(output, *process, handle_table);
|
context.WriteToOutgoingCommandBuffer(output, *process);
|
||||||
|
|
||||||
REQUIRE(handle_table.GetGeneric(output[2]) == a);
|
REQUIRE(process->handle_table.GetGeneric(output[2]) == a);
|
||||||
REQUIRE(handle_table.GetGeneric(output[3]) == b);
|
REQUIRE(process->handle_table.GetGeneric(output[3]) == b);
|
||||||
REQUIRE(handle_table.GetGeneric(output[5]) == c);
|
REQUIRE(process->handle_table.GetGeneric(output[5]) == c);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("translates StaticBuffer descriptors") {
|
SECTION("translates StaticBuffer descriptors") {
|
||||||
|
@ -329,7 +330,7 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") {
|
||||||
IPC::StaticBufferDesc(output_buffer->size(), 0);
|
IPC::StaticBufferDesc(output_buffer->size(), 0);
|
||||||
output_cmdbuff[IPC::COMMAND_BUFFER_LENGTH + 1] = target_address;
|
output_cmdbuff[IPC::COMMAND_BUFFER_LENGTH + 1] = target_address;
|
||||||
|
|
||||||
context.WriteToOutgoingCommandBuffer(output_cmdbuff.data(), *process, handle_table);
|
context.WriteToOutgoingCommandBuffer(output_cmdbuff.data(), *process);
|
||||||
|
|
||||||
CHECK(*output_buffer == input_buffer);
|
CHECK(*output_buffer == input_buffer);
|
||||||
REQUIRE(process->vm_manager.UnmapRange(target_address, output_buffer->size()) ==
|
REQUIRE(process->vm_manager.UnmapRange(target_address, output_buffer->size()) ==
|
||||||
|
@ -352,7 +353,7 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") {
|
||||||
target_address,
|
target_address,
|
||||||
};
|
};
|
||||||
|
|
||||||
context.PopulateFromIncomingCommandBuffer(input_cmdbuff, *process, handle_table);
|
context.PopulateFromIncomingCommandBuffer(input_cmdbuff, *process);
|
||||||
|
|
||||||
context.GetMappedBuffer(0).Write(input_buffer.data(), 0, input_buffer.size());
|
context.GetMappedBuffer(0).Write(input_buffer.data(), 0, input_buffer.size());
|
||||||
|
|
||||||
|
@ -360,7 +361,7 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") {
|
||||||
input[1] = IPC::MappedBufferDesc(output_buffer->size(), IPC::W);
|
input[1] = IPC::MappedBufferDesc(output_buffer->size(), IPC::W);
|
||||||
input[2] = 0;
|
input[2] = 0;
|
||||||
|
|
||||||
context.WriteToOutgoingCommandBuffer(output, *process, handle_table);
|
context.WriteToOutgoingCommandBuffer(output, *process);
|
||||||
|
|
||||||
CHECK(output[1] == IPC::MappedBufferDesc(output_buffer->size(), IPC::W));
|
CHECK(output[1] == IPC::MappedBufferDesc(output_buffer->size(), IPC::W));
|
||||||
CHECK(output[2] == target_address);
|
CHECK(output[2] == target_address);
|
||||||
|
|
Reference in New Issue