kernel: Eliminate kernel global state

As means to pave the way for getting rid of global state within core,
This eliminates kernel global state by removing all globals. Instead
this introduces a KernelCore class which acts as a kernel instance. This
instance lives in the System class, which keeps its lifetime contained
to the lifetime of the System class.

This also forces the kernel types to actually interact with the main
kernel instance itself instead of having transient kernel state placed
all over several translation units, keeping everything together. It also
has a nice consequence of making dependencies much more explicit.

This also makes our initialization a tad bit more correct. Previously we
were creating a kernel process before the actual kernel was initialized,
which doesn't really make much sense.

The KernelCore class itself follows the PImpl idiom, which allows
keeping all the implementation details sealed away from everything else,
which forces the use of the exposed API and allows us to avoid any
unnecessary inclusions within the main kernel header.
merge-requests/60/head
Lioncash 2018-08-28 12:30:33 +07:00
parent 4d7e1662c8
commit 0cbcd6ec9a
54 changed files with 673 additions and 444 deletions

@ -171,6 +171,14 @@ const std::shared_ptr<Kernel::Scheduler>& System::Scheduler(size_t core_index) {
return cpu_cores[core_index]->Scheduler(); return cpu_cores[core_index]->Scheduler();
} }
Kernel::KernelCore& System::Kernel() {
return kernel;
}
const Kernel::KernelCore& System::Kernel() const {
return kernel;
}
ARM_Interface& System::ArmInterface(size_t core_index) { ARM_Interface& System::ArmInterface(size_t core_index) {
ASSERT(core_index < NUM_CPU_CORES); ASSERT(core_index < NUM_CPU_CORES);
return cpu_cores[core_index]->ArmInterface(); return cpu_cores[core_index]->ArmInterface();
@ -185,12 +193,13 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) {
LOG_DEBUG(HW_Memory, "initialized OK"); LOG_DEBUG(HW_Memory, "initialized OK");
CoreTiming::Init(); CoreTiming::Init();
kernel.Initialize();
// Create a default fs if one doesn't already exist. // Create a default fs if one doesn't already exist.
if (virtual_filesystem == nullptr) if (virtual_filesystem == nullptr)
virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>(); virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>();
current_process = Kernel::Process::Create("main"); current_process = Kernel::Process::Create(kernel, "main");
cpu_barrier = std::make_shared<CpuBarrier>(); cpu_barrier = std::make_shared<CpuBarrier>();
cpu_exclusive_monitor = Cpu::MakeExclusiveMonitor(cpu_cores.size()); cpu_exclusive_monitor = Cpu::MakeExclusiveMonitor(cpu_cores.size());
@ -201,7 +210,6 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) {
telemetry_session = std::make_unique<Core::TelemetrySession>(); telemetry_session = std::make_unique<Core::TelemetrySession>();
service_manager = std::make_shared<Service::SM::ServiceManager>(); service_manager = std::make_shared<Service::SM::ServiceManager>();
Kernel::Init();
Service::Init(service_manager, virtual_filesystem); Service::Init(service_manager, virtual_filesystem);
GDBStub::Init(); GDBStub::Init();
@ -246,7 +254,6 @@ void System::Shutdown() {
renderer.reset(); renderer.reset();
GDBStub::Shutdown(); GDBStub::Shutdown();
Service::Shutdown(); Service::Shutdown();
Kernel::Shutdown();
service_manager.reset(); service_manager.reset();
telemetry_session.reset(); telemetry_session.reset();
gpu_core.reset(); gpu_core.reset();
@ -265,7 +272,8 @@ void System::Shutdown() {
} }
cpu_barrier.reset(); cpu_barrier.reset();
// Close core timing // Shutdown kernel and core timing
kernel.Shutdown();
CoreTiming::Shutdown(); CoreTiming::Shutdown();
// Close app loader // Close app loader

@ -12,6 +12,7 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "core/arm/exclusive_monitor.h" #include "core/arm/exclusive_monitor.h"
#include "core/core_cpu.h" #include "core/core_cpu.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/object.h" #include "core/hle/kernel/object.h"
#include "core/hle/kernel/scheduler.h" #include "core/hle/kernel/scheduler.h"
#include "core/loader/loader.h" #include "core/loader/loader.h"
@ -188,6 +189,12 @@ public:
return current_process; return current_process;
} }
/// Provides a reference to the kernel instance.
Kernel::KernelCore& Kernel();
/// Provides a constant reference to the kernel instance.
const Kernel::KernelCore& Kernel() const;
/// Gets the name of the current game /// Gets the name of the current game
Loader::ResultStatus GetGameName(std::string& out) const { Loader::ResultStatus GetGameName(std::string& out) const {
if (app_loader == nullptr) if (app_loader == nullptr)
@ -246,6 +253,7 @@ private:
*/ */
ResultStatus Init(Frontend::EmuWindow& emu_window); ResultStatus Init(Frontend::EmuWindow& emu_window);
Kernel::KernelCore kernel;
/// RealVfsFilesystem instance /// RealVfsFilesystem instance
FileSys::VirtualFilesystem virtual_filesystem; FileSys::VirtualFilesystem virtual_filesystem;
/// AppLoader used to load the current executing application /// AppLoader used to load the current executing application

@ -12,6 +12,7 @@
#include <utility> #include <utility>
#include "common/assert.h" #include "common/assert.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "core/core.h"
#include "core/hle/ipc.h" #include "core/hle/ipc.h"
#include "core/hle/kernel/client_port.h" #include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/client_session.h" #include "core/hle/kernel/client_session.h"
@ -135,7 +136,9 @@ public:
if (context->Session()->IsDomain()) { if (context->Session()->IsDomain()) {
context->AddDomainObject(std::move(iface)); context->AddDomainObject(std::move(iface));
} else { } else {
auto sessions = Kernel::ServerSession::CreateSessionPair(iface->GetServiceName()); auto& kernel = Core::System::GetInstance().Kernel();
auto sessions =
Kernel::ServerSession::CreateSessionPair(kernel, iface->GetServiceName());
auto server = std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions); auto server = std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions);
auto client = std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions); auto client = std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions);
iface->ClientConnected(server); iface->ClientConnected(server);

@ -14,7 +14,7 @@
namespace Kernel { namespace Kernel {
ClientPort::ClientPort() = default; ClientPort::ClientPort(KernelCore& kernel) : Object{kernel} {}
ClientPort::~ClientPort() = default; ClientPort::~ClientPort() = default;
ResultVal<SharedPtr<ClientSession>> ClientPort::Connect() { ResultVal<SharedPtr<ClientSession>> ClientPort::Connect() {
@ -27,7 +27,7 @@ ResultVal<SharedPtr<ClientSession>> ClientPort::Connect() {
active_sessions++; active_sessions++;
// Create a new session pair, let the created sessions inherit the parent port's HLE handler. // Create a new session pair, let the created sessions inherit the parent port's HLE handler.
auto sessions = ServerSession::CreateSessionPair(server_port->GetName(), this); auto sessions = ServerSession::CreateSessionPair(kernel, server_port->GetName(), this);
if (server_port->hle_handler) if (server_port->hle_handler)
server_port->hle_handler->ClientConnected(std::get<SharedPtr<ServerSession>>(sessions)); server_port->hle_handler->ClientConnected(std::get<SharedPtr<ServerSession>>(sessions));

@ -11,8 +11,9 @@
namespace Kernel { namespace Kernel {
class ServerPort;
class ClientSession; class ClientSession;
class KernelCore;
class ServerPort;
class ClientPort final : public Object { class ClientPort final : public Object {
public: public:
@ -44,7 +45,7 @@ public:
void ConnectionClosed(); void ConnectionClosed();
private: private:
ClientPort(); explicit ClientPort(KernelCore& kernel);
~ClientPort() override; ~ClientPort() override;
SharedPtr<ServerPort> server_port; ///< ServerPort associated with this client port. SharedPtr<ServerPort> server_port; ///< ServerPort associated with this client port.

@ -11,7 +11,7 @@
namespace Kernel { namespace Kernel {
ClientSession::ClientSession() = default; ClientSession::ClientSession(KernelCore& kernel) : Object{kernel} {}
ClientSession::~ClientSession() { ClientSession::~ClientSession() {
// This destructor will be called automatically when the last ClientSession handle is closed by // This destructor will be called automatically when the last ClientSession handle is closed by
// the emulated application. // the emulated application.

@ -12,8 +12,9 @@
namespace Kernel { namespace Kernel {
class ServerSession; class KernelCore;
class Session; class Session;
class ServerSession;
class Thread; class Thread;
class ClientSession final : public Object { class ClientSession final : public Object {
@ -41,7 +42,7 @@ public:
std::shared_ptr<Session> parent; std::shared_ptr<Session> parent;
private: private:
ClientSession(); explicit ClientSession(KernelCore& kernel);
~ClientSession() override; ~ClientSession() override;
}; };

@ -10,11 +10,11 @@
namespace Kernel { namespace Kernel {
Event::Event() {} Event::Event(KernelCore& kernel) : WaitObject{kernel} {}
Event::~Event() {} Event::~Event() = default;
SharedPtr<Event> Event::Create(ResetType reset_type, std::string name) { SharedPtr<Event> Event::Create(KernelCore& kernel, ResetType reset_type, std::string name) {
SharedPtr<Event> evt(new Event); SharedPtr<Event> evt(new Event(kernel));
evt->signaled = false; evt->signaled = false;
evt->reset_type = reset_type; evt->reset_type = reset_type;

@ -10,14 +10,18 @@
namespace Kernel { namespace Kernel {
class KernelCore;
class Event final : public WaitObject { class Event final : public WaitObject {
public: public:
/** /**
* Creates an event * Creates an event
* @param kernel The kernel instance to create this event under.
* @param reset_type ResetType describing how to create event * @param reset_type ResetType describing how to create event
* @param name Optional name of event * @param name Optional name of event
*/ */
static SharedPtr<Event> Create(ResetType reset_type, std::string name = "Unknown"); static SharedPtr<Event> Create(KernelCore& kernel, ResetType reset_type,
std::string name = "Unknown");
std::string GetTypeName() const override { std::string GetTypeName() const override {
return "Event"; return "Event";
@ -44,7 +48,7 @@ public:
void Clear(); void Clear();
private: private:
Event(); explicit Event(KernelCore& kernel);
~Event() override; ~Event() override;
ResetType reset_type; ///< Current ResetType ResetType reset_type; ///< Current ResetType

@ -13,8 +13,6 @@
namespace Kernel { namespace Kernel {
HandleTable g_handle_table;
HandleTable::HandleTable() { HandleTable::HandleTable() {
next_generation = 1; next_generation = 1;
Clear(); Clear();

@ -121,6 +121,4 @@ private:
u16 next_free_slot; u16 next_free_slot;
}; };
extern HandleTable g_handle_table;
} // namespace Kernel } // namespace Kernel

@ -13,6 +13,7 @@
#include "common/common_funcs.h" #include "common/common_funcs.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/ipc_helpers.h" #include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/event.h" #include "core/hle/kernel/event.h"
#include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/handle_table.h"
@ -51,7 +52,9 @@ SharedPtr<Event> HLERequestContext::SleepClientThread(SharedPtr<Thread> thread,
if (!event) { if (!event) {
// Create event if not provided // Create event if not provided
event = Kernel::Event::Create(Kernel::ResetType::OneShot, "HLE Pause Event: " + reason); auto& kernel = Core::System::GetInstance().Kernel();
event =
Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "HLE Pause Event: " + reason);
} }
event->Clear(); event->Clear();
@ -90,12 +93,14 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {
rp.Skip(2, false); rp.Skip(2, false);
} }
if (incoming) { if (incoming) {
auto& handle_table = Core::System::GetInstance().Kernel().HandleTable();
// Populate the object lists with the data in the IPC request. // Populate the object lists with the data in the IPC request.
for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_copy; ++handle) { for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_copy; ++handle) {
copy_objects.push_back(Kernel::g_handle_table.GetGeneric(rp.Pop<Handle>())); copy_objects.push_back(handle_table.GetGeneric(rp.Pop<Handle>()));
} }
for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_move; ++handle) { for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_move; ++handle) {
move_objects.push_back(Kernel::g_handle_table.GetGeneric(rp.Pop<Handle>())); move_objects.push_back(handle_table.GetGeneric(rp.Pop<Handle>()));
} }
} else { } else {
// For responses we just ignore the handles, they're empty and will be populated when // For responses we just ignore the handles, they're empty and will be populated when
@ -230,17 +235,19 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(const Thread& thread)
ASSERT(copy_objects.size() == handle_descriptor_header->num_handles_to_copy); ASSERT(copy_objects.size() == handle_descriptor_header->num_handles_to_copy);
ASSERT(move_objects.size() == handle_descriptor_header->num_handles_to_move); ASSERT(move_objects.size() == handle_descriptor_header->num_handles_to_move);
auto& handle_table = Core::System::GetInstance().Kernel().HandleTable();
// We don't make a distinction between copy and move handles when translating since HLE // We don't make a distinction between copy and move handles when translating since HLE
// services don't deal with handles directly. However, the guest applications might check // services don't deal with handles directly. However, the guest applications might check
// for specific values in each of these descriptors. // for specific values in each of these descriptors.
for (auto& object : copy_objects) { for (auto& object : copy_objects) {
ASSERT(object != nullptr); ASSERT(object != nullptr);
dst_cmdbuf[current_offset++] = Kernel::g_handle_table.Create(object).Unwrap(); dst_cmdbuf[current_offset++] = handle_table.Create(object).Unwrap();
} }
for (auto& object : move_objects) { for (auto& object : move_objects) {
ASSERT(object != nullptr); ASSERT(object != nullptr);
dst_cmdbuf[current_offset++] = Kernel::g_handle_table.Create(object).Unwrap(); dst_cmdbuf[current_offset++] = handle_table.Create(object).Unwrap();
} }
} }

@ -2,38 +2,291 @@
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <array>
#include <atomic>
#include <memory>
#include <mutex>
#include <utility>
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/kernel.h" #include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h" #include "core/hle/kernel/process.h"
#include "core/hle/kernel/resource_limit.h" #include "core/hle/kernel/resource_limit.h"
#include "core/hle/kernel/thread.h" #include "core/hle/kernel/thread.h"
#include "core/hle/kernel/timer.h" #include "core/hle/kernel/timer.h"
#include "core/hle/lock.h"
#include "core/hle/result.h"
namespace Kernel { namespace Kernel {
std::atomic<u32> Object::next_object_id{0}; /**
* Callback that will wake up the thread it was scheduled for
* @param thread_handle The handle of the thread that's been awoken
* @param cycles_late The number of CPU cycles that have passed since the desired wakeup time
*/
static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] int cycles_late) {
const auto proper_handle = static_cast<Handle>(thread_handle);
auto& system = Core::System::GetInstance();
/// Initialize the kernel // Lock the global kernel mutex when we enter the kernel HLE.
void Init() { std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
Kernel::ResourceLimitsInit();
Kernel::ThreadingInit();
Kernel::TimersInit();
Object::next_object_id = 0; SharedPtr<Thread> thread =
// TODO(Subv): Start the process ids from 10 for now, as lower PIDs are system.Kernel().RetrieveThreadFromWakeupCallbackHandleTable(proper_handle);
// reserved for low-level services if (thread == nullptr) {
Process::next_process_id = 10; LOG_CRITICAL(Kernel, "Callback fired for invalid thread {:08X}", proper_handle);
return;
}
bool resume = true;
if (thread->status == ThreadStatus::WaitSynchAny ||
thread->status == ThreadStatus::WaitSynchAll ||
thread->status == ThreadStatus::WaitHLEEvent) {
// Remove the thread from each of its waiting objects' waitlists
for (auto& object : thread->wait_objects) {
object->RemoveWaitingThread(thread.get());
}
thread->wait_objects.clear();
// Invoke the wakeup callback before clearing the wait objects
if (thread->wakeup_callback) {
resume = thread->wakeup_callback(ThreadWakeupReason::Timeout, thread, nullptr, 0);
}
}
if (thread->mutex_wait_address != 0 || thread->condvar_wait_address != 0 ||
thread->wait_handle) {
ASSERT(thread->status == ThreadStatus::WaitMutex);
thread->mutex_wait_address = 0;
thread->condvar_wait_address = 0;
thread->wait_handle = 0;
auto lock_owner = thread->lock_owner;
// Threads waking up by timeout from WaitProcessWideKey do not perform priority inheritance
// and don't have a lock owner unless SignalProcessWideKey was called first and the thread
// wasn't awakened due to the mutex already being acquired.
if (lock_owner) {
lock_owner->RemoveMutexWaiter(thread);
}
}
if (thread->arb_wait_address != 0) {
ASSERT(thread->status == ThreadStatus::WaitArb);
thread->arb_wait_address = 0;
}
if (resume) {
thread->ResumeFromWait();
}
} }
/// Shutdown the kernel /// The timer callback event, called when a timer is fired
void Shutdown() { static void TimerCallback(u64 timer_handle, int cycles_late) {
// Free all kernel objects const auto proper_handle = static_cast<Handle>(timer_handle);
g_handle_table.Clear(); auto& system = Core::System::GetInstance();
SharedPtr<Timer> timer = system.Kernel().RetrieveTimerFromCallbackHandleTable(proper_handle);
Kernel::ThreadingShutdown(); if (timer == nullptr) {
LOG_CRITICAL(Kernel, "Callback fired for invalid timer {:016X}", timer_handle);
return;
}
Kernel::TimersShutdown(); timer->Signal(cycles_late);
Kernel::ResourceLimitsShutdown(); }
struct KernelCore::Impl {
void Initialize(KernelCore& kernel) {
Shutdown();
InitializeResourceLimits(kernel);
InitializeThreads();
InitializeTimers();
}
void Shutdown() {
next_object_id = 0;
next_process_id = 10;
next_thread_id = 1;
process_list.clear();
handle_table.Clear();
resource_limits.fill(nullptr);
thread_wakeup_callback_handle_table.Clear();
thread_wakeup_event_type = nullptr;
timer_callback_handle_table.Clear();
timer_callback_event_type = nullptr;
}
void InitializeResourceLimits(KernelCore& kernel) {
// Create the four resource limits that the system uses
// Create the APPLICATION resource limit
SharedPtr<ResourceLimit> resource_limit = ResourceLimit::Create(kernel, "Applications");
resource_limit->max_priority = 0x18;
resource_limit->max_commit = 0x4000000;
resource_limit->max_threads = 0x20;
resource_limit->max_events = 0x20;
resource_limit->max_mutexes = 0x20;
resource_limit->max_semaphores = 0x8;
resource_limit->max_timers = 0x8;
resource_limit->max_shared_mems = 0x10;
resource_limit->max_address_arbiters = 0x2;
resource_limit->max_cpu_time = 0x1E;
resource_limits[static_cast<u8>(ResourceLimitCategory::APPLICATION)] = resource_limit;
// Create the SYS_APPLET resource limit
resource_limit = ResourceLimit::Create(kernel, "System Applets");
resource_limit->max_priority = 0x4;
resource_limit->max_commit = 0x5E00000;
resource_limit->max_threads = 0x1D;
resource_limit->max_events = 0xB;
resource_limit->max_mutexes = 0x8;
resource_limit->max_semaphores = 0x4;
resource_limit->max_timers = 0x4;
resource_limit->max_shared_mems = 0x8;
resource_limit->max_address_arbiters = 0x3;
resource_limit->max_cpu_time = 0x2710;
resource_limits[static_cast<u8>(ResourceLimitCategory::SYS_APPLET)] = resource_limit;
// Create the LIB_APPLET resource limit
resource_limit = ResourceLimit::Create(kernel, "Library Applets");
resource_limit->max_priority = 0x4;
resource_limit->max_commit = 0x600000;
resource_limit->max_threads = 0xE;
resource_limit->max_events = 0x8;
resource_limit->max_mutexes = 0x8;
resource_limit->max_semaphores = 0x4;
resource_limit->max_timers = 0x4;
resource_limit->max_shared_mems = 0x8;
resource_limit->max_address_arbiters = 0x1;
resource_limit->max_cpu_time = 0x2710;
resource_limits[static_cast<u8>(ResourceLimitCategory::LIB_APPLET)] = resource_limit;
// Create the OTHER resource limit
resource_limit = ResourceLimit::Create(kernel, "Others");
resource_limit->max_priority = 0x4;
resource_limit->max_commit = 0x2180000;
resource_limit->max_threads = 0xE1;
resource_limit->max_events = 0x108;
resource_limit->max_mutexes = 0x25;
resource_limit->max_semaphores = 0x43;
resource_limit->max_timers = 0x2C;
resource_limit->max_shared_mems = 0x1F;
resource_limit->max_address_arbiters = 0x2D;
resource_limit->max_cpu_time = 0x3E8;
resource_limits[static_cast<u8>(ResourceLimitCategory::OTHER)] = resource_limit;
}
void InitializeThreads() {
thread_wakeup_event_type =
CoreTiming::RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback);
}
void InitializeTimers() {
timer_callback_handle_table.Clear();
timer_callback_event_type = CoreTiming::RegisterEvent("TimerCallback", TimerCallback);
}
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
std::atomic<u32> next_process_id{10};
std::atomic<u32> next_thread_id{1};
// Lists all processes that exist in the current session.
std::vector<SharedPtr<Process>> process_list;
Kernel::HandleTable handle_table;
std::array<SharedPtr<ResourceLimit>, 4> resource_limits;
/// The event type of the generic timer callback event
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.
Kernel::HandleTable timer_callback_handle_table;
CoreTiming::EventType* thread_wakeup_event_type = nullptr;
// TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future,
// allowing us to simply use a pool index or similar.
Kernel::HandleTable thread_wakeup_callback_handle_table;
};
KernelCore::KernelCore() : impl{std::make_unique<Impl>()} {}
KernelCore::~KernelCore() {
Shutdown();
}
void KernelCore::Initialize() {
impl->Initialize(*this);
}
void KernelCore::Shutdown() {
impl->Shutdown();
}
Kernel::HandleTable& KernelCore::HandleTable() {
return impl->handle_table;
}
const Kernel::HandleTable& KernelCore::HandleTable() const {
return impl->handle_table;
}
SharedPtr<ResourceLimit> KernelCore::ResourceLimitForCategory(
ResourceLimitCategory category) const {
return impl->resource_limits.at(static_cast<std::size_t>(category));
}
SharedPtr<Thread> KernelCore::RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const {
return impl->thread_wakeup_callback_handle_table.Get<Thread>(handle);
}
SharedPtr<Timer> KernelCore::RetrieveTimerFromCallbackHandleTable(Handle handle) const {
return impl->timer_callback_handle_table.Get<Timer>(handle);
}
void KernelCore::AppendNewProcess(SharedPtr<Process> process) {
impl->process_list.push_back(std::move(process));
}
u32 KernelCore::CreateNewObjectID() {
return impl->next_object_id++;
}
u32 KernelCore::CreateNewThreadID() {
return impl->next_thread_id++;
}
u32 KernelCore::CreateNewProcessID() {
return impl->next_process_id++;
}
ResultVal<Handle> KernelCore::CreateTimerCallbackHandle(const SharedPtr<Timer>& timer) {
return impl->timer_callback_handle_table.Create(timer);
}
CoreTiming::EventType* KernelCore::ThreadWakeupCallbackEventType() const {
return impl->thread_wakeup_event_type;
}
CoreTiming::EventType* KernelCore::TimerCallbackEventType() const {
return impl->timer_callback_event_type;
}
Kernel::HandleTable& KernelCore::ThreadWakeupCallbackHandleTable() {
return impl->thread_wakeup_callback_handle_table;
}
const Kernel::HandleTable& KernelCore::ThreadWakeupCallbackHandleTable() const {
return impl->thread_wakeup_callback_handle_table;
} }
} // namespace Kernel } // namespace Kernel

@ -4,14 +4,93 @@
#pragma once #pragma once
#include "common/common_types.h" #include "core/hle/kernel/object.h"
template <typename T>
class ResultVal;
namespace CoreTiming {
struct EventType;
}
namespace Kernel { namespace Kernel {
/// Initialize the kernel with the specified system mode. class HandleTable;
void Init(); class Process;
class ResourceLimit;
class Thread;
class Timer;
/// Shutdown the kernel enum class ResourceLimitCategory : u8;
void Shutdown();
/// Represents a single instance of the kernel.
class KernelCore {
public:
KernelCore();
~KernelCore();
KernelCore(const KernelCore&) = delete;
KernelCore& operator=(const KernelCore&) = delete;
KernelCore(KernelCore&&) = delete;
KernelCore& operator=(KernelCore&&) = delete;
/// Resets the kernel to a clean slate for use.
void Initialize();
/// Clears all resources in use by the kernel instance.
void Shutdown();
/// Provides a reference to the handle table.
Kernel::HandleTable& HandleTable();
/// Provides a const reference to the handle table.
const Kernel::HandleTable& HandleTable() const;
/// Retrieves a shared pointer to a ResourceLimit identified by the given category.
SharedPtr<ResourceLimit> ResourceLimitForCategory(ResourceLimitCategory category) const;
/// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table.
SharedPtr<Thread> RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const;
/// Retrieves a shared pointer to a Timer instance within the timer callback handle table.
SharedPtr<Timer> RetrieveTimerFromCallbackHandleTable(Handle handle) const;
/// Adds the given shared pointer to an internal list of active processes.
void AppendNewProcess(SharedPtr<Process> process);
private:
friend class Object;
friend class Process;
friend class Thread;
friend class Timer;
/// Creates a new object ID, incrementing the internal object ID counter.
u32 CreateNewObjectID();
/// Creates a new process ID, incrementing the internal process ID counter;
u32 CreateNewProcessID();
/// Creates a new thread ID, incrementing the internal thread ID counter.
u32 CreateNewThreadID();
/// Creates a timer callback handle for the given timer.
ResultVal<Handle> CreateTimerCallbackHandle(const SharedPtr<Timer>& timer);
/// Retrieves the event type used for thread wakeup callbacks.
CoreTiming::EventType* ThreadWakeupCallbackEventType() const;
/// Retrieves the event type used for timer callbacks.
CoreTiming::EventType* TimerCallbackEventType() const;
/// Provides a reference to the thread wakeup callback handle table.
Kernel::HandleTable& ThreadWakeupCallbackHandleTable();
/// Provides a const reference to the thread wakeup callback handle table.
const Kernel::HandleTable& ThreadWakeupCallbackHandleTable() const;
struct Impl;
std::unique_ptr<Impl> impl;
};
} // namespace Kernel } // namespace Kernel

@ -58,15 +58,15 @@ static void TransferMutexOwnership(VAddr mutex_addr, SharedPtr<Thread> current_t
} }
} }
ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle, ResultCode Mutex::TryAcquire(HandleTable& handle_table, VAddr address, Handle holding_thread_handle,
Handle requesting_thread_handle) { Handle requesting_thread_handle) {
// The mutex address must be 4-byte aligned // The mutex address must be 4-byte aligned
if ((address % sizeof(u32)) != 0) { if ((address % sizeof(u32)) != 0) {
return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidAddress); return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidAddress);
} }
SharedPtr<Thread> holding_thread = g_handle_table.Get<Thread>(holding_thread_handle); SharedPtr<Thread> holding_thread = handle_table.Get<Thread>(holding_thread_handle);
SharedPtr<Thread> requesting_thread = g_handle_table.Get<Thread>(requesting_thread_handle); SharedPtr<Thread> requesting_thread = handle_table.Get<Thread>(requesting_thread_handle);
// TODO(Subv): It is currently unknown if it is possible to lock a mutex in behalf of another // TODO(Subv): It is currently unknown if it is possible to lock a mutex in behalf of another
// thread. // thread.

@ -11,6 +11,7 @@ union ResultCode;
namespace Kernel { namespace Kernel {
class HandleTable;
class Thread; class Thread;
class Mutex final { class Mutex final {
@ -21,8 +22,8 @@ public:
static constexpr u32 MutexOwnerMask = 0xBFFFFFFF; static constexpr u32 MutexOwnerMask = 0xBFFFFFFF;
/// Attempts to acquire a mutex at the specified address. /// Attempts to acquire a mutex at the specified address.
static ResultCode TryAcquire(VAddr address, Handle holding_thread_handle, static ResultCode TryAcquire(HandleTable& handle_table, VAddr address,
Handle requesting_thread_handle); Handle holding_thread_handle, Handle requesting_thread_handle);
/// Releases the mutex at the specified address. /// Releases the mutex at the specified address.
static ResultCode Release(VAddr address); static ResultCode Release(VAddr address);

@ -3,10 +3,12 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include "common/assert.h" #include "common/assert.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/object.h" #include "core/hle/kernel/object.h"
namespace Kernel { namespace Kernel {
Object::Object(KernelCore& kernel) : kernel{kernel}, object_id{kernel.CreateNewObjectID()} {}
Object::~Object() = default; Object::~Object() = default;
bool Object::IsWaitable() const { bool Object::IsWaitable() const {

@ -14,6 +14,8 @@
namespace Kernel { namespace Kernel {
class KernelCore;
using Handle = u32; using Handle = u32;
enum class HandleType : u32 { enum class HandleType : u32 {
@ -40,6 +42,7 @@ enum class ResetType {
class Object : NonCopyable { class Object : NonCopyable {
public: public:
explicit Object(KernelCore& kernel);
virtual ~Object(); virtual ~Object();
/// Returns a unique identifier for the object. For debugging purposes only. /// Returns a unique identifier for the object. For debugging purposes only.
@ -61,15 +64,16 @@ public:
*/ */
bool IsWaitable() const; bool IsWaitable() const;
public: protected:
static std::atomic<u32> next_object_id; /// The kernel instance this object was created under.
KernelCore& kernel;
private: private:
friend void intrusive_ptr_add_ref(Object*); friend void intrusive_ptr_add_ref(Object*);
friend void intrusive_ptr_release(Object*); friend void intrusive_ptr_release(Object*);
std::atomic<u32> ref_count{0}; std::atomic<u32> ref_count{0};
std::atomic<u32> object_id{next_object_id++}; std::atomic<u32> object_id{0};
}; };
// Special functions used by boost::instrusive_ptr to do automatic ref-counting // Special functions used by boost::instrusive_ptr to do automatic ref-counting

@ -8,6 +8,7 @@
#include "common/common_funcs.h" #include "common/common_funcs.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/hle/kernel/errors.h" #include "core/hle/kernel/errors.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h" #include "core/hle/kernel/process.h"
#include "core/hle/kernel/resource_limit.h" #include "core/hle/kernel/resource_limit.h"
#include "core/hle/kernel/thread.h" #include "core/hle/kernel/thread.h"
@ -16,30 +17,26 @@
namespace Kernel { namespace Kernel {
// Lists all processes that exist in the current session. SharedPtr<CodeSet> CodeSet::Create(KernelCore& kernel, std::string name) {
static std::vector<SharedPtr<Process>> process_list; SharedPtr<CodeSet> codeset(new CodeSet(kernel));
SharedPtr<CodeSet> CodeSet::Create(std::string name) {
SharedPtr<CodeSet> codeset(new CodeSet);
codeset->name = std::move(name); codeset->name = std::move(name);
return codeset; return codeset;
} }
CodeSet::CodeSet() {} CodeSet::CodeSet(KernelCore& kernel) : Object{kernel} {}
CodeSet::~CodeSet() {} CodeSet::~CodeSet() = default;
u32 Process::next_process_id; SharedPtr<Process> Process::Create(KernelCore& kernel, std::string&& name) {
SharedPtr<Process> process(new Process(kernel));
SharedPtr<Process> Process::Create(std::string&& name) {
SharedPtr<Process> process(new Process);
process->name = std::move(name); process->name = std::move(name);
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->program_id = 0; process->program_id = 0;
process->process_id = kernel.CreateNewProcessID();
process_list.push_back(process); kernel.AppendNewProcess(process);
return process; return process;
} }
@ -128,7 +125,7 @@ void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) {
vm_manager.LogLayout(); vm_manager.LogLayout();
status = ProcessStatus::Running; status = ProcessStatus::Running;
Kernel::SetupMainThread(entry_point, main_thread_priority, this); Kernel::SetupMainThread(kernel, entry_point, main_thread_priority, this);
} }
void Process::LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr) { void Process::LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr) {
@ -231,22 +228,7 @@ ResultCode Process::UnmapMemory(VAddr dst_addr, VAddr /*src_addr*/, u64 size) {
return vm_manager.UnmapRange(dst_addr, size); return vm_manager.UnmapRange(dst_addr, size);
} }
Kernel::Process::Process() {} Kernel::Process::Process(KernelCore& kernel) : Object{kernel} {}
Kernel::Process::~Process() {} Kernel::Process::~Process() {}
void ClearProcessList() {
process_list.clear();
}
SharedPtr<Process> GetProcessById(u32 process_id) {
auto itr = std::find_if(
process_list.begin(), process_list.end(),
[&](const SharedPtr<Process>& process) { return process->process_id == process_id; });
if (itr == process_list.end())
return nullptr;
return *itr;
}
} // namespace Kernel } // namespace Kernel

@ -19,6 +19,8 @@
namespace Kernel { namespace Kernel {
class KernelCore;
struct AddressMapping { struct AddressMapping {
// Address and size must be page-aligned // Address and size must be page-aligned
VAddr address; VAddr address;
@ -62,7 +64,7 @@ struct CodeSet final : public Object {
u32 size = 0; u32 size = 0;
}; };
static SharedPtr<CodeSet> Create(std::string name); static SharedPtr<CodeSet> Create(KernelCore& kernel, std::string name);
std::string GetTypeName() const override { std::string GetTypeName() const override {
return "CodeSet"; return "CodeSet";
@ -109,13 +111,13 @@ struct CodeSet final : public Object {
std::string name; std::string name;
private: private:
CodeSet(); explicit CodeSet(KernelCore& kernel);
~CodeSet() override; ~CodeSet() override;
}; };
class Process final : public Object { class Process final : public Object {
public: public:
static SharedPtr<Process> Create(std::string&& name); static SharedPtr<Process> Create(KernelCore& kernel, std::string&& name);
std::string GetTypeName() const override { std::string GetTypeName() const override {
return "Process"; return "Process";
@ -129,8 +131,6 @@ public:
return HANDLE_TYPE; return HANDLE_TYPE;
} }
static u32 next_process_id;
/// Title ID corresponding to the process /// Title ID corresponding to the process
u64 program_id; u64 program_id;
@ -157,8 +157,8 @@ public:
/// Current status of the process /// Current status of the process
ProcessStatus status; ProcessStatus status;
/// The id of this process /// The ID of this process
u32 process_id = next_process_id++; u32 process_id = 0;
/** /**
* 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
@ -206,13 +206,8 @@ public:
ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size); ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size);
private: private:
Process(); explicit Process(KernelCore& kernel);
~Process() override; ~Process() override;
}; };
void ClearProcessList();
/// Retrieves a process from the current list of processes.
SharedPtr<Process> GetProcessById(u32 process_id);
} // namespace Kernel } // namespace Kernel

@ -9,31 +9,16 @@
namespace Kernel { namespace Kernel {
static SharedPtr<ResourceLimit> resource_limits[4]; ResourceLimit::ResourceLimit(KernelCore& kernel) : Object{kernel} {}
ResourceLimit::~ResourceLimit() = default;
ResourceLimit::ResourceLimit() {} SharedPtr<ResourceLimit> ResourceLimit::Create(KernelCore& kernel, std::string name) {
ResourceLimit::~ResourceLimit() {} SharedPtr<ResourceLimit> resource_limit(new ResourceLimit(kernel));
SharedPtr<ResourceLimit> ResourceLimit::Create(std::string name) {
SharedPtr<ResourceLimit> resource_limit(new ResourceLimit);
resource_limit->name = std::move(name); resource_limit->name = std::move(name);
return resource_limit; return resource_limit;
} }
SharedPtr<ResourceLimit> ResourceLimit::GetForCategory(ResourceLimitCategory category) {
switch (category) {
case ResourceLimitCategory::APPLICATION:
case ResourceLimitCategory::SYS_APPLET:
case ResourceLimitCategory::LIB_APPLET:
case ResourceLimitCategory::OTHER:
return resource_limits[static_cast<u8>(category)];
default:
LOG_CRITICAL(Kernel, "Unknown resource limit category");
UNREACHABLE();
}
}
s32 ResourceLimit::GetCurrentResourceValue(ResourceType resource) const { s32 ResourceLimit::GetCurrentResourceValue(ResourceType resource) const {
switch (resource) { switch (resource) {
case ResourceType::Commit: case ResourceType::Commit:
@ -89,66 +74,4 @@ u32 ResourceLimit::GetMaxResourceValue(ResourceType resource) const {
return 0; return 0;
} }
} }
void ResourceLimitsInit() {
// Create the four resource limits that the system uses
// Create the APPLICATION resource limit
SharedPtr<ResourceLimit> resource_limit = ResourceLimit::Create("Applications");
resource_limit->max_priority = 0x18;
resource_limit->max_commit = 0x4000000;
resource_limit->max_threads = 0x20;
resource_limit->max_events = 0x20;
resource_limit->max_mutexes = 0x20;
resource_limit->max_semaphores = 0x8;
resource_limit->max_timers = 0x8;
resource_limit->max_shared_mems = 0x10;
resource_limit->max_address_arbiters = 0x2;
resource_limit->max_cpu_time = 0x1E;
resource_limits[static_cast<u8>(ResourceLimitCategory::APPLICATION)] = resource_limit;
// Create the SYS_APPLET resource limit
resource_limit = ResourceLimit::Create("System Applets");
resource_limit->max_priority = 0x4;
resource_limit->max_commit = 0x5E00000;
resource_limit->max_threads = 0x1D;
resource_limit->max_events = 0xB;
resource_limit->max_mutexes = 0x8;
resource_limit->max_semaphores = 0x4;
resource_limit->max_timers = 0x4;
resource_limit->max_shared_mems = 0x8;
resource_limit->max_address_arbiters = 0x3;
resource_limit->max_cpu_time = 0x2710;
resource_limits[static_cast<u8>(ResourceLimitCategory::SYS_APPLET)] = resource_limit;
// Create the LIB_APPLET resource limit
resource_limit = ResourceLimit::Create("Library Applets");
resource_limit->max_priority = 0x4;
resource_limit->max_commit = 0x600000;
resource_limit->max_threads = 0xE;
resource_limit->max_events = 0x8;
resource_limit->max_mutexes = 0x8;
resource_limit->max_semaphores = 0x4;
resource_limit->max_timers = 0x4;
resource_limit->max_shared_mems = 0x8;
resource_limit->max_address_arbiters = 0x1;
resource_limit->max_cpu_time = 0x2710;
resource_limits[static_cast<u8>(ResourceLimitCategory::LIB_APPLET)] = resource_limit;
// Create the OTHER resource limit
resource_limit = ResourceLimit::Create("Others");
resource_limit->max_priority = 0x4;
resource_limit->max_commit = 0x2180000;
resource_limit->max_threads = 0xE1;
resource_limit->max_events = 0x108;
resource_limit->max_mutexes = 0x25;
resource_limit->max_semaphores = 0x43;
resource_limit->max_timers = 0x2C;
resource_limit->max_shared_mems = 0x1F;
resource_limit->max_address_arbiters = 0x2D;
resource_limit->max_cpu_time = 0x3E8;
resource_limits[static_cast<u8>(ResourceLimitCategory::OTHER)] = resource_limit;
}
void ResourceLimitsShutdown() {}
} // namespace Kernel } // namespace Kernel

@ -9,6 +9,8 @@
namespace Kernel { namespace Kernel {
class KernelCore;
enum class ResourceLimitCategory : u8 { enum class ResourceLimitCategory : u8 {
APPLICATION = 0, APPLICATION = 0,
SYS_APPLET = 1, SYS_APPLET = 1,
@ -34,14 +36,7 @@ public:
/** /**
* Creates a resource limit object. * Creates a resource limit object.
*/ */
static SharedPtr<ResourceLimit> Create(std::string name = "Unknown"); static SharedPtr<ResourceLimit> Create(KernelCore& kernel, std::string name = "Unknown");
/**
* Retrieves the resource limit associated with the specified resource limit category.
* @param category The resource limit category
* @returns The resource limit associated with the category
*/
static SharedPtr<ResourceLimit> GetForCategory(ResourceLimitCategory category);
std::string GetTypeName() const override { std::string GetTypeName() const override {
return "ResourceLimit"; return "ResourceLimit";
@ -113,14 +108,8 @@ public:
s32 current_cpu_time = 0; s32 current_cpu_time = 0;
private: private:
ResourceLimit(); explicit ResourceLimit(KernelCore& kernel);
~ResourceLimit() override; ~ResourceLimit() override;
}; };
/// Initializes the resource limits
void ResourceLimitsInit();
// Destroys the resource limits
void ResourceLimitsShutdown();
} // namespace Kernel } // namespace Kernel

@ -13,8 +13,8 @@
namespace Kernel { namespace Kernel {
ServerPort::ServerPort() {} ServerPort::ServerPort(KernelCore& kernel) : WaitObject{kernel} {}
ServerPort::~ServerPort() {} ServerPort::~ServerPort() = default;
ResultVal<SharedPtr<ServerSession>> ServerPort::Accept() { ResultVal<SharedPtr<ServerSession>> ServerPort::Accept() {
if (pending_sessions.empty()) { if (pending_sessions.empty()) {
@ -36,10 +36,10 @@ void ServerPort::Acquire(Thread* thread) {
} }
std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> ServerPort::CreatePortPair( std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> ServerPort::CreatePortPair(
u32 max_sessions, std::string name) { KernelCore& kernel, u32 max_sessions, std::string name) {
SharedPtr<ServerPort> server_port(new ServerPort); SharedPtr<ServerPort> server_port(new ServerPort(kernel));
SharedPtr<ClientPort> client_port(new ClientPort); SharedPtr<ClientPort> client_port(new ClientPort(kernel));
server_port->name = name + "_Server"; server_port->name = name + "_Server";
client_port->name = name + "_Client"; client_port->name = name + "_Client";

@ -15,6 +15,7 @@
namespace Kernel { namespace Kernel {
class ClientPort; class ClientPort;
class KernelCore;
class ServerSession; class ServerSession;
class SessionRequestHandler; class SessionRequestHandler;
@ -23,12 +24,13 @@ public:
/** /**
* Creates a pair of ServerPort and an associated ClientPort. * Creates a pair of ServerPort and an associated ClientPort.
* *
* @param kernel The kernel instance to create the port pair under.
* @param max_sessions Maximum number of sessions to the port * @param max_sessions Maximum number of sessions to the port
* @param name Optional name of the ports * @param name Optional name of the ports
* @return The created port tuple * @return The created port tuple
*/ */
static std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> CreatePortPair( static std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> CreatePortPair(
u32 max_sessions, std::string name = "UnknownPort"); KernelCore& kernel, u32 max_sessions, std::string name = "UnknownPort");
std::string GetTypeName() const override { std::string GetTypeName() const override {
return "ServerPort"; return "ServerPort";
@ -69,7 +71,7 @@ public:
void Acquire(Thread* thread) override; void Acquire(Thread* thread) override;
private: private:
ServerPort(); explicit ServerPort(KernelCore& kernel);
~ServerPort() override; ~ServerPort() override;
}; };

@ -20,7 +20,7 @@
namespace Kernel { namespace Kernel {
ServerSession::ServerSession() = default; ServerSession::ServerSession(KernelCore& kernel) : WaitObject{kernel} {}
ServerSession::~ServerSession() { ServerSession::~ServerSession() {
// This destructor will be called automatically when the last ServerSession handle is closed by // This destructor will be called automatically when the last ServerSession handle is closed by
// the emulated application. // the emulated application.
@ -35,8 +35,8 @@ ServerSession::~ServerSession() {
parent->server = nullptr; parent->server = nullptr;
} }
ResultVal<SharedPtr<ServerSession>> ServerSession::Create(std::string name) { ResultVal<SharedPtr<ServerSession>> ServerSession::Create(KernelCore& kernel, std::string name) {
SharedPtr<ServerSession> server_session(new ServerSession); SharedPtr<ServerSession> server_session(new ServerSession(kernel));
server_session->name = std::move(name); server_session->name = std::move(name);
server_session->parent = nullptr; server_session->parent = nullptr;
@ -105,10 +105,10 @@ ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) {
// from its ClientSession, so wake up any threads that may be waiting on a svcReplyAndReceive or // from its ClientSession, so wake up any threads that may be waiting on a svcReplyAndReceive or
// similar. // similar.
auto& handle_table = Core::System::GetInstance().Kernel().HandleTable();
Kernel::HLERequestContext context(this); Kernel::HLERequestContext context(this);
u32* cmd_buf = (u32*)Memory::GetPointer(thread->GetTLSAddress()); u32* cmd_buf = (u32*)Memory::GetPointer(thread->GetTLSAddress());
context.PopulateFromIncomingCommandBuffer(cmd_buf, *Core::CurrentProcess(), context.PopulateFromIncomingCommandBuffer(cmd_buf, *Core::CurrentProcess(), handle_table);
Kernel::g_handle_table);
ResultCode result = RESULT_SUCCESS; ResultCode result = RESULT_SUCCESS;
// If the session has been converted to a domain, handle the domain request // If the session has been converted to a domain, handle the domain request
@ -160,10 +160,11 @@ ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) {
return result; return result;
} }
ServerSession::SessionPair ServerSession::CreateSessionPair(const std::string& name, ServerSession::SessionPair ServerSession::CreateSessionPair(KernelCore& kernel,
const std::string& name,
SharedPtr<ClientPort> port) { SharedPtr<ClientPort> port) {
auto server_session = ServerSession::Create(name + "_Server").Unwrap(); auto server_session = ServerSession::Create(kernel, name + "_Server").Unwrap();
SharedPtr<ClientSession> client_session(new ClientSession); SharedPtr<ClientSession> client_session(new ClientSession(kernel));
client_session->name = name + "_Client"; client_session->name = name + "_Client";
std::shared_ptr<Session> parent(new Session); std::shared_ptr<Session> parent(new Session);

@ -15,13 +15,14 @@
namespace Kernel { namespace Kernel {
class ClientSession;
class ClientPort; class ClientPort;
class ClientSession;
class HLERequestContext;
class KernelCore;
class ServerSession; class ServerSession;
class Session; class Session;
class SessionRequestHandler; class SessionRequestHandler;
class Thread; class Thread;
class HLERequestContext;
/** /**
* Kernel object representing the server endpoint of an IPC session. Sessions are the basic CTR-OS * Kernel object representing the server endpoint of an IPC session. Sessions are the basic CTR-OS
@ -50,11 +51,12 @@ public:
/** /**
* Creates a pair of ServerSession and an associated ClientSession. * Creates a pair of ServerSession and an associated ClientSession.
* @param kernel The kernal instance to create the session pair under.
* @param name Optional name of the ports. * @param name Optional name of the ports.
* @param client_port Optional The ClientPort that spawned this session. * @param client_port Optional The ClientPort that spawned this session.
* @return The created session tuple * @return The created session tuple
*/ */
static SessionPair CreateSessionPair(const std::string& name = "Unknown", static SessionPair CreateSessionPair(KernelCore& kernel, const std::string& name = "Unknown",
SharedPtr<ClientPort> client_port = nullptr); SharedPtr<ClientPort> client_port = nullptr);
/** /**
@ -111,16 +113,18 @@ public:
} }
private: private:
ServerSession(); explicit ServerSession(KernelCore& kernel);
~ServerSession() override; ~ServerSession() override;
/** /**
* Creates a server session. The server session can have an optional HLE handler, * Creates a server session. The server session can have an optional HLE handler,
* which will be invoked to handle the IPC requests that this session receives. * which will be invoked to handle the IPC requests that this session receives.
* @param kernel The kernel instance to create this server session under.
* @param name Optional name of the server session. * @param name Optional name of the server session.
* @return The created server session * @return The created server session
*/ */
static ResultVal<SharedPtr<ServerSession>> Create(std::string name = "Unknown"); static ResultVal<SharedPtr<ServerSession>> Create(KernelCore& kernel,
std::string name = "Unknown");
/// Handles a SyncRequest to a domain, forwarding the request to the proper object or closing an /// Handles a SyncRequest to a domain, forwarding the request to the proper object or closing an
/// object handle. /// object handle.

@ -13,14 +13,14 @@
namespace Kernel { namespace Kernel {
SharedMemory::SharedMemory() {} SharedMemory::SharedMemory(KernelCore& kernel) : Object{kernel} {}
SharedMemory::~SharedMemory() {} SharedMemory::~SharedMemory() = default;
SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u64 size, SharedPtr<SharedMemory> SharedMemory::Create(KernelCore& kernel, SharedPtr<Process> owner_process,
MemoryPermission permissions, u64 size, MemoryPermission permissions,
MemoryPermission other_permissions, VAddr address, MemoryPermission other_permissions, VAddr address,
MemoryRegion region, std::string name) { MemoryRegion region, std::string name) {
SharedPtr<SharedMemory> shared_memory(new SharedMemory); SharedPtr<SharedMemory> shared_memory(new SharedMemory(kernel));
shared_memory->owner_process = std::move(owner_process); shared_memory->owner_process = std::move(owner_process);
shared_memory->name = std::move(name); shared_memory->name = std::move(name);
@ -59,12 +59,10 @@ SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u
return shared_memory; return shared_memory;
} }
SharedPtr<SharedMemory> SharedMemory::CreateForApplet(std::shared_ptr<std::vector<u8>> heap_block, SharedPtr<SharedMemory> SharedMemory::CreateForApplet(
u32 offset, u32 size, KernelCore& kernel, std::shared_ptr<std::vector<u8>> heap_block, u32 offset, u32 size,
MemoryPermission permissions, MemoryPermission permissions, MemoryPermission other_permissions, std::string name) {
MemoryPermission other_permissions, SharedPtr<SharedMemory> shared_memory(new SharedMemory(kernel));
std::string name) {
SharedPtr<SharedMemory> shared_memory(new SharedMemory);
shared_memory->owner_process = nullptr; shared_memory->owner_process = nullptr;
shared_memory->name = std::move(name); shared_memory->name = std::move(name);

@ -15,6 +15,8 @@
namespace Kernel { namespace Kernel {
class KernelCore;
/// Permissions for mapped shared memory blocks /// Permissions for mapped shared memory blocks
enum class MemoryPermission : u32 { enum class MemoryPermission : u32 {
None = 0, None = 0,
@ -32,6 +34,7 @@ class SharedMemory final : public Object {
public: public:
/** /**
* Creates a shared memory object. * Creates a shared memory object.
* @param kernel The kernel instance to create a shared memory instance under.
* @param owner_process Process that created this shared memory object. * @param owner_process Process that created this shared memory object.
* @param size Size of the memory block. Must be page-aligned. * @param size Size of the memory block. Must be page-aligned.
* @param permissions Permission restrictions applied to the process which created the block. * @param permissions Permission restrictions applied to the process which created the block.
@ -42,14 +45,15 @@ public:
* linear heap. * linear heap.
* @param name Optional object name, used for debugging purposes. * @param name Optional object name, used for debugging purposes.
*/ */
static SharedPtr<SharedMemory> Create(SharedPtr<Process> owner_process, u64 size, static SharedPtr<SharedMemory> Create(KernelCore& kernel, SharedPtr<Process> owner_process,
MemoryPermission permissions, u64 size, MemoryPermission permissions,
MemoryPermission other_permissions, VAddr address = 0, MemoryPermission other_permissions, VAddr address = 0,
MemoryRegion region = MemoryRegion::BASE, MemoryRegion region = MemoryRegion::BASE,
std::string name = "Unknown"); std::string name = "Unknown");
/** /**
* Creates a shared memory object from a block of memory managed by an HLE applet. * Creates a shared memory object from a block of memory managed by an HLE applet.
* @param kernel The kernel instance to create a shared memory instance under.
* @param heap_block Heap block of the HLE applet. * @param heap_block Heap block of the HLE applet.
* @param offset The offset into the heap block that the SharedMemory will map. * @param offset The offset into the heap block that the SharedMemory will map.
* @param size Size of the memory block. Must be page-aligned. * @param size Size of the memory block. Must be page-aligned.
@ -58,7 +62,8 @@ public:
* block. * block.
* @param name Optional object name, used for debugging purposes. * @param name Optional object name, used for debugging purposes.
*/ */
static SharedPtr<SharedMemory> CreateForApplet(std::shared_ptr<std::vector<u8>> heap_block, static SharedPtr<SharedMemory> CreateForApplet(KernelCore& kernel,
std::shared_ptr<std::vector<u8>> heap_block,
u32 offset, u32 size, u32 offset, u32 size,
MemoryPermission permissions, MemoryPermission permissions,
MemoryPermission other_permissions, MemoryPermission other_permissions,
@ -125,7 +130,7 @@ public:
std::string name; std::string name;
private: private:
SharedMemory(); explicit SharedMemory(KernelCore& kernel);
~SharedMemory() override; ~SharedMemory() override;
}; };

@ -87,13 +87,15 @@ static ResultCode ConnectToNamedPort(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)); auto& kernel = Core::System::GetInstance().Kernel();
CASCADE_RESULT(*out_handle, kernel.HandleTable().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); auto& kernel = Core::System::GetInstance().Kernel();
SharedPtr<ClientSession> session = kernel.HandleTable().Get<ClientSession>(handle);
if (!session) { if (!session) {
LOG_ERROR(Kernel_SVC, "called with invalid handle=0x{:08X}", handle); LOG_ERROR(Kernel_SVC, "called with invalid handle=0x{:08X}", handle);
return ERR_INVALID_HANDLE; return ERR_INVALID_HANDLE;
@ -112,7 +114,8 @@ static ResultCode SendSyncRequest(Handle handle) {
static ResultCode GetThreadId(u32* thread_id, Handle thread_handle) { static ResultCode GetThreadId(u32* thread_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); auto& kernel = Core::System::GetInstance().Kernel();
const SharedPtr<Thread> thread = kernel.HandleTable().Get<Thread>(thread_handle);
if (!thread) { if (!thread) {
return ERR_INVALID_HANDLE; return ERR_INVALID_HANDLE;
} }
@ -125,7 +128,8 @@ static ResultCode GetThreadId(u32* thread_id, Handle thread_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); auto& kernel = Core::System::GetInstance().Kernel();
const SharedPtr<Process> process = kernel.HandleTable().Get<Process>(process_handle);
if (!process) { if (!process) {
return ERR_INVALID_HANDLE; return ERR_INVALID_HANDLE;
} }
@ -168,10 +172,11 @@ static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64
using ObjectPtr = SharedPtr<WaitObject>; using ObjectPtr = SharedPtr<WaitObject>;
std::vector<ObjectPtr> objects(handle_count); std::vector<ObjectPtr> objects(handle_count);
auto& kernel = Core::System::GetInstance().Kernel();
for (u64 i = 0; i < handle_count; ++i) { for (u64 i = 0; i < handle_count; ++i) {
const Handle handle = Memory::Read32(handles_address + i * sizeof(Handle)); const Handle handle = Memory::Read32(handles_address + i * sizeof(Handle));
const auto object = g_handle_table.Get<WaitObject>(handle); const auto object = kernel.HandleTable().Get<WaitObject>(handle);
if (object == nullptr) { if (object == nullptr) {
return ERR_INVALID_HANDLE; return ERR_INVALID_HANDLE;
@ -219,7 +224,8 @@ static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64
static ResultCode CancelSynchronization(Handle thread_handle) { static ResultCode CancelSynchronization(Handle thread_handle) {
LOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle); LOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle);
const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle); auto& kernel = Core::System::GetInstance().Kernel();
const SharedPtr<Thread> thread = kernel.HandleTable().Get<Thread>(thread_handle);
if (!thread) { if (!thread) {
return ERR_INVALID_HANDLE; return ERR_INVALID_HANDLE;
} }
@ -239,7 +245,9 @@ static ResultCode ArbitrateLock(Handle holding_thread_handle, VAddr mutex_addr,
"requesting_current_thread_handle=0x{:08X}", "requesting_current_thread_handle=0x{:08X}",
holding_thread_handle, mutex_addr, requesting_thread_handle); holding_thread_handle, mutex_addr, requesting_thread_handle);
return Mutex::TryAcquire(mutex_addr, holding_thread_handle, requesting_thread_handle); auto& handle_table = Core::System::GetInstance().Kernel().HandleTable();
return Mutex::TryAcquire(handle_table, mutex_addr, holding_thread_handle,
requesting_thread_handle);
} }
/// Unlock a mutex /// Unlock a mutex
@ -352,7 +360,8 @@ static ResultCode GetThreadContext(Handle handle, VAddr addr) {
/// 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); auto& kernel = Core::System::GetInstance().Kernel();
const SharedPtr<Thread> thread = kernel.HandleTable().Get<Thread>(handle);
if (!thread) if (!thread)
return ERR_INVALID_HANDLE; return ERR_INVALID_HANDLE;
@ -366,7 +375,8 @@ 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); auto& kernel = Core::System::GetInstance().Kernel();
SharedPtr<Thread> thread = kernel.HandleTable().Get<Thread>(handle);
if (!thread) if (!thread)
return ERR_INVALID_HANDLE; return ERR_INVALID_HANDLE;
@ -395,7 +405,8 @@ static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 s
"called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}", "called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}",
shared_memory_handle, addr, size, permissions); shared_memory_handle, addr, size, permissions);
SharedPtr<SharedMemory> shared_memory = g_handle_table.Get<SharedMemory>(shared_memory_handle); auto& kernel = Core::System::GetInstance().Kernel();
auto shared_memory = kernel.HandleTable().Get<SharedMemory>(shared_memory_handle);
if (!shared_memory) { if (!shared_memory) {
return ERR_INVALID_HANDLE; return ERR_INVALID_HANDLE;
} }
@ -423,7 +434,8 @@ static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64
LOG_WARNING(Kernel_SVC, "called, shared_memory_handle=0x{:08X}, addr=0x{:X}, size=0x{:X}", LOG_WARNING(Kernel_SVC, "called, shared_memory_handle=0x{:08X}, addr=0x{:X}, size=0x{:X}",
shared_memory_handle, addr, size); shared_memory_handle, addr, size);
SharedPtr<SharedMemory> shared_memory = g_handle_table.Get<SharedMemory>(shared_memory_handle); auto& kernel = Core::System::GetInstance().Kernel();
auto shared_memory = kernel.HandleTable().Get<SharedMemory>(shared_memory_handle);
return shared_memory->Unmap(Core::CurrentProcess().get(), addr); return shared_memory->Unmap(Core::CurrentProcess().get(), addr);
} }
@ -431,7 +443,9 @@ static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64
/// 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, u64 addr) { Handle process_handle, u64 addr) {
SharedPtr<Process> process = g_handle_table.Get<Process>(process_handle);
auto& kernel = Core::System::GetInstance().Kernel();
SharedPtr<Process> process = kernel.HandleTable().Get<Process>(process_handle);
if (!process) { if (!process) {
return ERR_INVALID_HANDLE; return ERR_INVALID_HANDLE;
} }
@ -528,10 +542,11 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V
break; break;
} }
auto& kernel = Core::System::GetInstance().Kernel();
CASCADE_RESULT(SharedPtr<Thread> thread, CASCADE_RESULT(SharedPtr<Thread> thread,
Thread::Create(name, entry_point, priority, arg, processor_id, stack_top, Thread::Create(kernel, name, entry_point, priority, arg, processor_id, stack_top,
Core::CurrentProcess())); Core::CurrentProcess()));
CASCADE_RESULT(thread->guest_handle, g_handle_table.Create(thread)); CASCADE_RESULT(thread->guest_handle, kernel.HandleTable().Create(thread));
*out_handle = thread->guest_handle; *out_handle = thread->guest_handle;
Core::System::GetInstance().CpuCore(thread->processor_id).PrepareReschedule(); Core::System::GetInstance().CpuCore(thread->processor_id).PrepareReschedule();
@ -548,7 +563,8 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V
static ResultCode StartThread(Handle thread_handle) { static ResultCode StartThread(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); auto& kernel = Core::System::GetInstance().Kernel();
const SharedPtr<Thread> thread = kernel.HandleTable().Get<Thread>(thread_handle);
if (!thread) { if (!thread) {
return ERR_INVALID_HANDLE; return ERR_INVALID_HANDLE;
} }
@ -595,7 +611,8 @@ static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr condition_var
"called mutex_addr={:X}, condition_variable_addr={:X}, thread_handle=0x{:08X}, timeout={}", "called mutex_addr={:X}, condition_variable_addr={:X}, thread_handle=0x{:08X}, timeout={}",
mutex_addr, condition_variable_addr, thread_handle, nano_seconds); mutex_addr, condition_variable_addr, thread_handle, nano_seconds);
SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle); auto& kernel = Core::System::GetInstance().Kernel();
SharedPtr<Thread> thread = kernel.HandleTable().Get<Thread>(thread_handle);
ASSERT(thread); ASSERT(thread);
CASCADE_CODE(Mutex::Release(mutex_addr)); CASCADE_CODE(Mutex::Release(mutex_addr));
@ -704,8 +721,9 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target
mutex_val | Mutex::MutexHasWaitersFlag)); mutex_val | Mutex::MutexHasWaitersFlag));
// The mutex is already owned by some other thread, make this thread wait on it. // The mutex is already owned by some other thread, make this thread wait on it.
auto& kernel = Core::System::GetInstance().Kernel();
Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask); Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask);
auto owner = g_handle_table.Get<Thread>(owner_handle); auto owner = kernel.HandleTable().Get<Thread>(owner_handle);
ASSERT(owner); ASSERT(owner);
ASSERT(thread->status == ThreadStatus::WaitMutex); ASSERT(thread->status == ThreadStatus::WaitMutex);
thread->wakeup_callback = nullptr; thread->wakeup_callback = nullptr;
@ -783,14 +801,20 @@ static u64 GetSystemTick() {
/// 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);
auto& kernel = Core::System::GetInstance().Kernel();
return kernel.HandleTable().Close(handle);
} }
/// Reset an event /// Reset an event
static ResultCode ResetSignal(Handle handle) { static ResultCode ResetSignal(Handle handle) {
LOG_WARNING(Kernel_SVC, "(STUBBED) called handle 0x{:08X}", handle); LOG_WARNING(Kernel_SVC, "(STUBBED) called handle 0x{:08X}", handle);
auto event = g_handle_table.Get<Event>(handle);
auto& kernel = Core::System::GetInstance().Kernel();
auto event = kernel.HandleTable().Get<Event>(handle);
ASSERT(event != nullptr); ASSERT(event != nullptr);
event->Clear(); event->Clear();
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
@ -806,7 +830,8 @@ static ResultCode CreateTransferMemory(Handle* handle, VAddr addr, u64 size, u32
static ResultCode GetThreadCoreMask(Handle thread_handle, u32* core, u64* mask) { static ResultCode GetThreadCoreMask(Handle thread_handle, u32* core, u64* mask) {
LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle); LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle);
const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle); auto& kernel = Core::System::GetInstance().Kernel();
const SharedPtr<Thread> thread = kernel.HandleTable().Get<Thread>(thread_handle);
if (!thread) { if (!thread) {
return ERR_INVALID_HANDLE; return ERR_INVALID_HANDLE;
} }
@ -821,7 +846,8 @@ static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) {
LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, mask=0x{:16X}, core=0x{:X}", thread_handle, LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, mask=0x{:16X}, core=0x{:X}", thread_handle,
mask, core); mask, core);
const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle); auto& kernel = Core::System::GetInstance().Kernel();
const SharedPtr<Thread> thread = kernel.HandleTable().Get<Thread>(thread_handle);
if (!thread) { if (!thread) {
return ERR_INVALID_HANDLE; return ERR_INVALID_HANDLE;
} }
@ -861,19 +887,23 @@ static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permiss
u32 remote_permissions) { u32 remote_permissions) {
LOG_TRACE(Kernel_SVC, "called, size=0x{:X}, localPerms=0x{:08X}, remotePerms=0x{:08X}", size, LOG_TRACE(Kernel_SVC, "called, size=0x{:X}, localPerms=0x{:08X}, remotePerms=0x{:08X}", size,
local_permissions, remote_permissions); local_permissions, remote_permissions);
auto sharedMemHandle =
SharedMemory::Create(g_handle_table.Get<Process>(KernelHandle::CurrentProcess), size, auto& kernel = Core::System::GetInstance().Kernel();
auto& handle_table = kernel.HandleTable();
auto shared_mem_handle =
SharedMemory::Create(kernel, handle_table.Get<Process>(KernelHandle::CurrentProcess), size,
static_cast<MemoryPermission>(local_permissions), static_cast<MemoryPermission>(local_permissions),
static_cast<MemoryPermission>(remote_permissions)); static_cast<MemoryPermission>(remote_permissions));
CASCADE_RESULT(*handle, g_handle_table.Create(sharedMemHandle)); CASCADE_RESULT(*handle, handle_table.Create(shared_mem_handle));
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
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); auto& kernel = Core::System::GetInstance().Kernel();
SharedPtr<Event> evt = kernel.HandleTable().Get<Event>(handle);
if (evt == nullptr) if (evt == nullptr)
return ERR_INVALID_HANDLE; return ERR_INVALID_HANDLE;
evt->Clear(); evt->Clear();

@ -20,6 +20,7 @@
#include "core/core_timing_util.h" #include "core/core_timing_util.h"
#include "core/hle/kernel/errors.h" #include "core/hle/kernel/errors.h"
#include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/object.h" #include "core/hle/kernel/object.h"
#include "core/hle/kernel/process.h" #include "core/hle/kernel/process.h"
#include "core/hle/kernel/thread.h" #include "core/hle/kernel/thread.h"
@ -29,9 +30,6 @@
namespace Kernel { namespace Kernel {
/// Event type for the thread wake up event
static CoreTiming::EventType* ThreadWakeupEventType = nullptr;
bool Thread::ShouldWait(Thread* thread) const { bool Thread::ShouldWait(Thread* thread) const {
return status != ThreadStatus::Dead; return status != ThreadStatus::Dead;
} }
@ -40,32 +38,17 @@ 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 Thread::Thread(KernelCore& kernel) : WaitObject{kernel} {}
// us to simply use a pool index or similar. Thread::~Thread() = default;
static Kernel::HandleTable wakeup_callback_handle_table;
// The first available thread id at startup
static u32 next_thread_id;
/**
* Creates a new thread ID
* @return The new thread ID
*/
inline static u32 const NewThreadId() {
return next_thread_id++;
}
Thread::Thread() {}
Thread::~Thread() {}
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(kernel.ThreadWakeupCallbackEventType(), callback_handle);
wakeup_callback_handle_table.Close(callback_handle); kernel.ThreadWakeupCallbackHandleTable().Close(callback_handle);
callback_handle = 0; 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 terminated forcefully (SVC TerminateProcess)
if (status == ThreadStatus::Ready) { if (status == ThreadStatus::Ready) {
scheduler->UnscheduleThread(this, current_priority); scheduler->UnscheduleThread(this, current_priority);
} }
@ -98,63 +81,6 @@ void ExitCurrentThread() {
Core::System::GetInstance().CurrentScheduler().RemoveThread(thread); Core::System::GetInstance().CurrentScheduler().RemoveThread(thread);
} }
/**
* Callback that will wake up the thread it was scheduled for
* @param thread_handle The handle of the thread that's been awoken
* @param cycles_late The number of CPU cycles that have passed since the desired wakeup time
*/
static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) {
const auto proper_handle = static_cast<Handle>(thread_handle);
// Lock the global kernel mutex when we enter the kernel HLE.
std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
SharedPtr<Thread> thread = wakeup_callback_handle_table.Get<Thread>(proper_handle);
if (thread == nullptr) {
LOG_CRITICAL(Kernel, "Callback fired for invalid thread {:08X}", proper_handle);
return;
}
bool resume = true;
if (thread->status == ThreadStatus::WaitSynchAny ||
thread->status == ThreadStatus::WaitSynchAll ||
thread->status == ThreadStatus::WaitHLEEvent) {
// Remove the thread from each of its waiting objects' waitlists
for (auto& object : thread->wait_objects)
object->RemoveWaitingThread(thread.get());
thread->wait_objects.clear();
// Invoke the wakeup callback before clearing the wait objects
if (thread->wakeup_callback)
resume = thread->wakeup_callback(ThreadWakeupReason::Timeout, thread, nullptr, 0);
}
if (thread->mutex_wait_address != 0 || thread->condvar_wait_address != 0 ||
thread->wait_handle) {
ASSERT(thread->status == ThreadStatus::WaitMutex);
thread->mutex_wait_address = 0;
thread->condvar_wait_address = 0;
thread->wait_handle = 0;
auto lock_owner = thread->lock_owner;
// Threads waking up by timeout from WaitProcessWideKey do not perform priority inheritance
// and don't have a lock owner unless SignalProcessWideKey was called first and the thread
// wasn't awakened due to the mutex already being acquired.
if (lock_owner) {
lock_owner->RemoveMutexWaiter(thread);
}
}
if (thread->arb_wait_address != 0) {
ASSERT(thread->status == ThreadStatus::WaitArb);
thread->arb_wait_address = 0;
}
if (resume)
thread->ResumeFromWait();
}
void Thread::WakeAfterDelay(s64 nanoseconds) { void Thread::WakeAfterDelay(s64 nanoseconds) {
// Don't schedule a wakeup if the thread wants to wait forever // Don't schedule a wakeup if the thread wants to wait forever
if (nanoseconds == -1) if (nanoseconds == -1)
@ -162,12 +88,12 @@ void Thread::WakeAfterDelay(s64 nanoseconds) {
// This function might be called from any thread so we have to be cautious and use the // This function might be called from any thread so we have to be cautious and use the
// thread-safe version of ScheduleEvent. // thread-safe version of ScheduleEvent.
CoreTiming::ScheduleEventThreadsafe(CoreTiming::nsToCycles(nanoseconds), ThreadWakeupEventType, CoreTiming::ScheduleEventThreadsafe(CoreTiming::nsToCycles(nanoseconds),
callback_handle); kernel.ThreadWakeupCallbackEventType(), callback_handle);
} }
void Thread::CancelWakeupTimer() { void Thread::CancelWakeupTimer() {
CoreTiming::UnscheduleEventThreadsafe(ThreadWakeupEventType, callback_handle); CoreTiming::UnscheduleEventThreadsafe(kernel.ThreadWakeupCallbackEventType(), callback_handle);
} }
static boost::optional<s32> GetNextProcessorId(u64 mask) { static boost::optional<s32> GetNextProcessorId(u64 mask) {
@ -294,9 +220,9 @@ static void ResetThreadContext(Core::ARM_Interface::ThreadContext& context, VAdd
context.fpscr = 0; context.fpscr = 0;
} }
ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, u32 priority, ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name, VAddr entry_point,
u64 arg, s32 processor_id, VAddr stack_top, u32 priority, u64 arg, s32 processor_id,
SharedPtr<Process> owner_process) { VAddr stack_top, 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 > THREADPRIO_LOWEST) { if (priority > THREADPRIO_LOWEST) {
LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority); LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority);
@ -316,9 +242,9 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
return ResultCode(-1); return ResultCode(-1);
} }
SharedPtr<Thread> thread(new Thread); SharedPtr<Thread> thread(new Thread(kernel));
thread->thread_id = NewThreadId(); thread->thread_id = kernel.CreateNewThreadID();
thread->status = ThreadStatus::Dormant; thread->status = ThreadStatus::Dormant;
thread->entry_point = entry_point; thread->entry_point = entry_point;
thread->stack_top = stack_top; thread->stack_top = stack_top;
@ -333,7 +259,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
thread->condvar_wait_address = 0; thread->condvar_wait_address = 0;
thread->wait_handle = 0; thread->wait_handle = 0;
thread->name = std::move(name); thread->name = std::move(name);
thread->callback_handle = wakeup_callback_handle_table.Create(thread).Unwrap(); thread->callback_handle = kernel.ThreadWakeupCallbackHandleTable().Create(thread).Unwrap();
thread->owner_process = owner_process; thread->owner_process = owner_process;
thread->scheduler = Core::System::GetInstance().Scheduler(processor_id); thread->scheduler = Core::System::GetInstance().Scheduler(processor_id);
thread->scheduler->AddThread(thread, priority); thread->scheduler->AddThread(thread, priority);
@ -383,19 +309,19 @@ void Thread::BoostPriority(u32 priority) {
current_priority = priority; current_priority = priority;
} }
SharedPtr<Thread> SetupMainThread(VAddr entry_point, u32 priority, SharedPtr<Thread> SetupMainThread(KernelCore& kernel, VAddr entry_point, u32 priority,
SharedPtr<Process> owner_process) { SharedPtr<Process> owner_process) {
// Setup page table so we can write to memory // Setup page table so we can write to memory
SetCurrentPageTable(&Core::CurrentProcess()->vm_manager.page_table); SetCurrentPageTable(&Core::CurrentProcess()->vm_manager.page_table);
// Initialize new "main" thread // Initialize new "main" thread
auto thread_res = Thread::Create("main", entry_point, priority, 0, THREADPROCESSORID_0, auto thread_res = Thread::Create(kernel, "main", entry_point, priority, 0, THREADPROCESSORID_0,
Memory::STACK_AREA_VADDR_END, std::move(owner_process)); Memory::STACK_AREA_VADDR_END, std::move(owner_process));
SharedPtr<Thread> thread = std::move(thread_res).Unwrap(); SharedPtr<Thread> thread = std::move(thread_res).Unwrap();
// Register 1 must be a handle to the main thread // Register 1 must be a handle to the main thread
thread->guest_handle = Kernel::g_handle_table.Create(thread).Unwrap(); thread->guest_handle = kernel.HandleTable().Create(thread).Unwrap();
thread->context.cpu_registers[1] = thread->guest_handle; thread->context.cpu_registers[1] = thread->guest_handle;
@ -528,13 +454,4 @@ Thread* GetCurrentThread() {
return Core::System::GetInstance().CurrentScheduler().GetCurrentThread(); return Core::System::GetInstance().CurrentScheduler().GetCurrentThread();
} }
void ThreadingInit() {
ThreadWakeupEventType = CoreTiming::RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback);
next_thread_id = 1;
}
void ThreadingShutdown() {
Kernel::ClearProcessList();
}
} // namespace Kernel } // namespace Kernel

@ -56,6 +56,7 @@ enum class ThreadWakeupReason {
namespace Kernel { namespace Kernel {
class KernelCore;
class Process; class Process;
class Scheduler; class Scheduler;
@ -63,6 +64,7 @@ class Thread final : public WaitObject {
public: public:
/** /**
* Creates and returns a new thread. The new thread is immediately scheduled * Creates and returns a new thread. The new thread is immediately scheduled
* @param kernel The kernel instance this thread will be created under.
* @param name The friendly name desired for the thread * @param name The friendly name desired for the thread
* @param entry_point The address at which the thread should start execution * @param entry_point The address at which the thread should start execution
* @param priority The thread's priority * @param priority The thread's priority
@ -72,8 +74,9 @@ public:
* @param owner_process The parent process for the thread * @param owner_process The parent process for the thread
* @return A shared pointer to the newly created thread * @return A shared pointer to the newly created thread
*/ */
static ResultVal<SharedPtr<Thread>> Create(std::string name, VAddr entry_point, u32 priority, static ResultVal<SharedPtr<Thread>> Create(KernelCore& kernel, std::string name,
u64 arg, s32 processor_id, VAddr stack_top, VAddr entry_point, u32 priority, u64 arg,
s32 processor_id, VAddr stack_top,
SharedPtr<Process> owner_process); SharedPtr<Process> owner_process);
std::string GetName() const override { std::string GetName() const override {
@ -263,7 +266,7 @@ public:
u64 affinity_mask{0x1}; u64 affinity_mask{0x1};
private: private:
Thread(); explicit Thread(KernelCore& kernel);
~Thread() override; ~Thread() override;
std::shared_ptr<std::vector<u8>> tls_memory = std::make_shared<std::vector<u8>>(); std::shared_ptr<std::vector<u8>> tls_memory = std::make_shared<std::vector<u8>>();
@ -271,12 +274,13 @@ private:
/** /**
* Sets up the primary application thread * Sets up the primary application thread
* @param kernel The kernel instance to create the main thread under.
* @param entry_point The address at which the thread should start execution * @param entry_point The address at which the thread should start execution
* @param priority The priority to give the main thread * @param priority The priority to give the main thread
* @param owner_process The parent process for the main thread * @param owner_process The parent process for the main thread
* @return A shared pointer to the main thread * @return A shared pointer to the main thread
*/ */
SharedPtr<Thread> SetupMainThread(VAddr entry_point, u32 priority, SharedPtr<Thread> SetupMainThread(KernelCore& kernel, VAddr entry_point, u32 priority,
SharedPtr<Process> owner_process); SharedPtr<Process> owner_process);
/** /**
@ -294,14 +298,4 @@ void WaitCurrentThread_Sleep();
*/ */
void ExitCurrentThread(); void ExitCurrentThread();
/**
* Initialize threading
*/
void ThreadingInit();
/**
* Shutdown threading
*/
void ThreadingShutdown();
} // namespace Kernel } // namespace Kernel

@ -2,36 +2,31 @@
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <cinttypes>
#include "common/assert.h" #include "common/assert.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/core.h"
#include "core/core_timing.h" #include "core/core_timing.h"
#include "core/core_timing_util.h" #include "core/core_timing_util.h"
#include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/object.h" #include "core/hle/kernel/object.h"
#include "core/hle/kernel/thread.h" #include "core/hle/kernel/thread.h"
#include "core/hle/kernel/timer.h" #include "core/hle/kernel/timer.h"
namespace Kernel { namespace Kernel {
/// The event type of the generic timer callback event Timer::Timer(KernelCore& kernel) : WaitObject{kernel} {}
static CoreTiming::EventType* timer_callback_event_type = nullptr; Timer::~Timer() = default;
// 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 Kernel::HandleTable timer_callback_handle_table;
Timer::Timer() {} SharedPtr<Timer> Timer::Create(KernelCore& kernel, ResetType reset_type, std::string name) {
Timer::~Timer() {} SharedPtr<Timer> timer(new Timer(kernel));
SharedPtr<Timer> Timer::Create(ResetType reset_type, std::string name) {
SharedPtr<Timer> timer(new Timer);
timer->reset_type = reset_type; timer->reset_type = reset_type;
timer->signaled = false; timer->signaled = false;
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_handle = kernel.CreateTimerCallbackHandle(timer).Unwrap();
return timer; return timer;
} }
@ -58,13 +53,13 @@ void Timer::Set(s64 initial, s64 interval) {
// Immediately invoke the callback // Immediately invoke the callback
Signal(0); Signal(0);
} else { } else {
CoreTiming::ScheduleEvent(CoreTiming::nsToCycles(initial), timer_callback_event_type, CoreTiming::ScheduleEvent(CoreTiming::nsToCycles(initial), kernel.TimerCallbackEventType(),
callback_handle); callback_handle);
} }
} }
void Timer::Cancel() { void Timer::Cancel() {
CoreTiming::UnscheduleEvent(timer_callback_event_type, callback_handle); CoreTiming::UnscheduleEvent(kernel.TimerCallbackEventType(), callback_handle);
} }
void Timer::Clear() { void Timer::Clear() {
@ -89,28 +84,8 @@ void Timer::Signal(int 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(CoreTiming::nsToCycles(interval_delay) - cycles_late, CoreTiming::ScheduleEvent(CoreTiming::nsToCycles(interval_delay) - cycles_late,
timer_callback_event_type, callback_handle); kernel.TimerCallbackEventType(), callback_handle);
} }
} }
/// The timer callback event, called when a timer is fired
static void TimerCallback(u64 timer_handle, int cycles_late) {
SharedPtr<Timer> timer =
timer_callback_handle_table.Get<Timer>(static_cast<Handle>(timer_handle));
if (timer == nullptr) {
LOG_CRITICAL(Kernel, "Callback fired for invalid timer {:016X}", timer_handle);
return;
}
timer->Signal(cycles_late);
}
void TimersInit() {
timer_callback_handle_table.Clear();
timer_callback_event_type = CoreTiming::RegisterEvent("TimerCallback", TimerCallback);
}
void TimersShutdown() {}
} // namespace Kernel } // namespace Kernel

@ -10,15 +10,19 @@
namespace Kernel { namespace Kernel {
class KernelCore;
class Timer final : public WaitObject { class Timer final : public WaitObject {
public: public:
/** /**
* Creates a timer * Creates a timer
* @param kernel The kernel instance to create the timer callback handle for.
* @param reset_type ResetType describing how to create the timer * @param reset_type ResetType describing how to create the timer
* @param name Optional name of timer * @param name Optional name of timer
* @return The created Timer * @return The created Timer
*/ */
static SharedPtr<Timer> Create(ResetType reset_type, std::string name = "Unknown"); static SharedPtr<Timer> Create(KernelCore& kernel, ResetType reset_type,
std::string name = "Unknown");
std::string GetTypeName() const override { std::string GetTypeName() const override {
return "Timer"; return "Timer";
@ -68,7 +72,7 @@ public:
void Signal(int cycles_late); void Signal(int cycles_late);
private: private:
Timer(); explicit Timer(KernelCore& kernel);
~Timer() override; ~Timer() override;
ResetType reset_type; ///< The ResetType of this timer ResetType reset_type; ///< The ResetType of this timer
@ -83,9 +87,4 @@ private:
Handle callback_handle; Handle callback_handle;
}; };
/// Initializes the required variables for timers
void TimersInit();
/// Tears down the timer variables
void TimersShutdown();
} // namespace Kernel } // namespace Kernel

@ -12,6 +12,9 @@
namespace Kernel { namespace Kernel {
WaitObject::WaitObject(KernelCore& kernel) : Object{kernel} {}
WaitObject::~WaitObject() = default;
void WaitObject::AddWaitingThread(SharedPtr<Thread> thread) { void WaitObject::AddWaitingThread(SharedPtr<Thread> thread) {
auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
if (itr == waiting_threads.end()) if (itr == waiting_threads.end())

@ -11,11 +11,15 @@
namespace Kernel { namespace Kernel {
class KernelCore;
class Thread; class Thread;
/// Class that represents a Kernel object that a thread can be waiting on /// Class that represents a Kernel object that a thread can be waiting on
class WaitObject : public Object { class WaitObject : public Object {
public: public:
explicit WaitObject(KernelCore& kernel);
~WaitObject() override;
/** /**
* Check if the specified thread should wait until the object is available * Check if the specified thread should wait until the object is available
* @param thread The thread about which we're deciding. * @param thread The thread about which we're deciding.

@ -160,8 +160,9 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger
}; };
RegisterHandlers(functions); RegisterHandlers(functions);
auto& kernel = Core::System::GetInstance().Kernel();
launchable_event = launchable_event =
Kernel::Event::Create(Kernel::ResetType::Sticky, "ISelfController:LaunchableEvent"); Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "ISelfController:LaunchableEvent");
} }
void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) { void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) {
@ -332,7 +333,8 @@ ICommonStateGetter::ICommonStateGetter() : ServiceFramework("ICommonStateGetter"
}; };
RegisterHandlers(functions); RegisterHandlers(functions);
event = Kernel::Event::Create(Kernel::ResetType::OneShot, "ICommonStateGetter:Event"); auto& kernel = Core::System::GetInstance().Kernel();
event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "ICommonStateGetter:Event");
} }
void ICommonStateGetter::GetBootMode(Kernel::HLERequestContext& ctx) { void ICommonStateGetter::GetBootMode(Kernel::HLERequestContext& ctx) {
@ -505,7 +507,8 @@ public:
}; };
RegisterHandlers(functions); RegisterHandlers(functions);
state_changed_event = Kernel::Event::Create(Kernel::ResetType::OneShot, auto& kernel = Core::System::GetInstance().Kernel();
state_changed_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
"ILibraryAppletAccessor:StateChangedEvent"); "ILibraryAppletAccessor:StateChangedEvent");
} }

@ -47,7 +47,9 @@ public:
RegisterHandlers(functions); RegisterHandlers(functions);
// This is the event handle used to check if the audio buffer was released // This is the event handle used to check if the audio buffer was released
buffer_event = Kernel::Event::Create(Kernel::ResetType::Sticky, "IAudioOutBufferReleased"); auto& kernel = Core::System::GetInstance().Kernel();
buffer_event =
Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "IAudioOutBufferReleased");
stream = audio_core.OpenStream(audio_params.sample_rate, audio_params.channel_count, stream = audio_core.OpenStream(audio_params.sample_rate, audio_params.channel_count,
"IAudioOut", [=]() { buffer_event->Signal(); }); "IAudioOut", [=]() { buffer_event->Signal(); });

@ -35,8 +35,9 @@ public:
}; };
RegisterHandlers(functions); RegisterHandlers(functions);
auto& kernel = Core::System::GetInstance().Kernel();
system_event = system_event =
Kernel::Event::Create(Kernel::ResetType::Sticky, "IAudioRenderer:SystemEvent"); Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "IAudioRenderer:SystemEvent");
renderer = std::make_unique<AudioCore::AudioRenderer>(audren_params, system_event); renderer = std::make_unique<AudioCore::AudioRenderer>(audren_params, system_event);
} }
@ -121,8 +122,9 @@ public:
}; };
RegisterHandlers(functions); RegisterHandlers(functions);
buffer_event = auto& kernel = Core::System::GetInstance().Kernel();
Kernel::Event::Create(Kernel::ResetType::OneShot, "IAudioOutBufferReleasedEvent"); buffer_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
"IAudioOutBufferReleasedEvent");
} }
private: private:

@ -4,6 +4,7 @@
#include <atomic> #include <atomic>
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/core.h"
#include "core/core_timing.h" #include "core/core_timing.h"
#include "core/core_timing_util.h" #include "core/core_timing_util.h"
#include "core/frontend/emu_window.h" #include "core/frontend/emu_window.h"
@ -35,9 +36,10 @@ public:
}; };
RegisterHandlers(functions); RegisterHandlers(functions);
auto& kernel = Core::System::GetInstance().Kernel();
shared_mem = Kernel::SharedMemory::Create( shared_mem = Kernel::SharedMemory::Create(
nullptr, 0x40000, Kernel::MemoryPermission::ReadWrite, Kernel::MemoryPermission::Read, kernel, nullptr, 0x40000, Kernel::MemoryPermission::ReadWrite,
0, Kernel::MemoryRegion::BASE, "HID:SharedMemory"); Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "HID:SharedMemory");
// Register update callbacks // Register update callbacks
pad_update_event = CoreTiming::RegisterEvent( pad_update_event = CoreTiming::RegisterEvent(
@ -402,7 +404,8 @@ public:
RegisterHandlers(functions); RegisterHandlers(functions);
event = Kernel::Event::Create(Kernel::ResetType::OneShot, "hid:EventHandle"); auto& kernel = Core::System::GetInstance().Kernel();
event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "hid:EventHandle");
} }
~Hid() = default; ~Hid() = default;

@ -46,11 +46,13 @@ public:
}; };
RegisterHandlers(functions); RegisterHandlers(functions);
activate_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "IUser:ActivateEvent"); auto& kernel = Core::System::GetInstance().Kernel();
activate_event =
Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IUser:ActivateEvent");
deactivate_event = deactivate_event =
Kernel::Event::Create(Kernel::ResetType::OneShot, "IUser:DeactivateEvent"); Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IUser:DeactivateEvent");
availability_change_event = availability_change_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
Kernel::Event::Create(Kernel::ResetType::OneShot, "IUser:AvailabilityChangeEvent"); "IUser:AvailabilityChangeEvent");
} }
private: private:

@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include "core/core.h"
#include "core/hle/ipc_helpers.h" #include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/event.h" #include "core/hle/kernel/event.h"
#include "core/hle/service/nifm/nifm.h" #include "core/hle/service/nifm/nifm.h"
@ -54,8 +55,9 @@ public:
}; };
RegisterHandlers(functions); RegisterHandlers(functions);
event1 = Kernel::Event::Create(Kernel::ResetType::OneShot, "IRequest:Event1"); auto& kernel = Core::System::GetInstance().Kernel();
event2 = Kernel::Event::Create(Kernel::ResetType::OneShot, "IRequest:Event2"); event1 = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IRequest:Event1");
event2 = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IRequest:Event2");
} }
private: private:

@ -266,8 +266,9 @@ void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
SHARED_FONT_MEM_VADDR, shared_font, 0, SHARED_FONT_MEM_SIZE, Kernel::MemoryState::Shared); SHARED_FONT_MEM_VADDR, shared_font, 0, SHARED_FONT_MEM_SIZE, Kernel::MemoryState::Shared);
// Create shared font memory object // Create shared font memory object
auto& kernel = Core::System::GetInstance().Kernel();
shared_font_mem = Kernel::SharedMemory::Create( shared_font_mem = Kernel::SharedMemory::Create(
Core::CurrentProcess(), SHARED_FONT_MEM_SIZE, Kernel::MemoryPermission::ReadWrite, kernel, Core::CurrentProcess(), SHARED_FONT_MEM_SIZE, Kernel::MemoryPermission::ReadWrite,
Kernel::MemoryPermission::Read, SHARED_FONT_MEM_VADDR, Kernel::MemoryRegion::BASE, Kernel::MemoryPermission::Read, SHARED_FONT_MEM_VADDR, Kernel::MemoryRegion::BASE,
"PL_U:shared_font_mem"); "PL_U:shared_font_mem");

@ -4,6 +4,7 @@
#include <cinttypes> #include <cinttypes>
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/ipc_helpers.h" #include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/event.h" #include "core/hle/kernel/event.h"
#include "core/hle/service/nvdrv/interface.h" #include "core/hle/service/nvdrv/interface.h"
@ -107,7 +108,8 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name)
}; };
RegisterHandlers(functions); RegisterHandlers(functions);
query_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "NVDRV::query_event"); auto& kernel = Core::System::GetInstance().Kernel();
query_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "NVDRV::query_event");
} }
} // namespace Service::Nvidia } // namespace Service::Nvidia

@ -6,14 +6,16 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/service/nvflinger/buffer_queue.h" #include "core/hle/service/nvflinger/buffer_queue.h"
namespace Service { namespace Service {
namespace NVFlinger { namespace NVFlinger {
BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) { BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) {
auto& kernel = Core::System::GetInstance().Kernel();
buffer_wait_event = buffer_wait_event =
Kernel::Event::Create(Kernel::ResetType::Sticky, "BufferQueue NativeHandle"); Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "BufferQueue NativeHandle");
} }
void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) { void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) {

@ -161,7 +161,8 @@ void NVFlinger::Compose() {
Layer::Layer(u64 id, std::shared_ptr<BufferQueue> queue) : id(id), buffer_queue(std::move(queue)) {} Layer::Layer(u64 id, std::shared_ptr<BufferQueue> queue) : id(id), buffer_queue(std::move(queue)) {}
Display::Display(u64 id, std::string name) : id(id), name(std::move(name)) { Display::Display(u64 id, std::string name) : id(id), name(std::move(name)) {
vsync_event = Kernel::Event::Create(Kernel::ResetType::Pulse, "Display VSync Event"); auto& kernel = Core::System::GetInstance().Kernel();
vsync_event = Kernel::Event::Create(kernel, Kernel::ResetType::Pulse, "Display VSync Event");
} }
} // namespace Service::NVFlinger } // namespace Service::NVFlinger

@ -107,19 +107,24 @@ void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager)
void ServiceFrameworkBase::InstallAsNamedPort() { void ServiceFrameworkBase::InstallAsNamedPort() {
ASSERT(port == nullptr); ASSERT(port == nullptr);
auto& kernel = Core::System::GetInstance().Kernel();
SharedPtr<ServerPort> server_port; SharedPtr<ServerPort> server_port;
SharedPtr<ClientPort> client_port; SharedPtr<ClientPort> client_port;
std::tie(server_port, client_port) = ServerPort::CreatePortPair(max_sessions, service_name); std::tie(server_port, client_port) =
ServerPort::CreatePortPair(kernel, max_sessions, service_name);
server_port->SetHleHandler(shared_from_this()); server_port->SetHleHandler(shared_from_this());
AddNamedPort(service_name, std::move(client_port)); AddNamedPort(service_name, std::move(client_port));
} }
Kernel::SharedPtr<Kernel::ClientPort> ServiceFrameworkBase::CreatePort() { Kernel::SharedPtr<Kernel::ClientPort> ServiceFrameworkBase::CreatePort() {
ASSERT(port == nullptr); ASSERT(port == nullptr);
auto& kernel = Core::System::GetInstance().Kernel();
Kernel::SharedPtr<Kernel::ServerPort> server_port; Kernel::SharedPtr<Kernel::ServerPort> server_port;
Kernel::SharedPtr<Kernel::ClientPort> client_port; Kernel::SharedPtr<Kernel::ClientPort> client_port;
std::tie(server_port, client_port) = std::tie(server_port, client_port) =
Kernel::ServerPort::CreatePortPair(max_sessions, service_name); Kernel::ServerPort::CreatePortPair(kernel, max_sessions, service_name);
port = MakeResult<Kernel::SharedPtr<Kernel::ServerPort>>(std::move(server_port)).Unwrap(); port = MakeResult<Kernel::SharedPtr<Kernel::ServerPort>>(std::move(server_port)).Unwrap();
port->SetHleHandler(shared_from_this()); port->SetHleHandler(shared_from_this());
return client_port; return client_port;

@ -4,6 +4,7 @@
#include <tuple> #include <tuple>
#include "common/assert.h" #include "common/assert.h"
#include "core/core.h"
#include "core/hle/ipc_helpers.h" #include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/client_port.h" #include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/client_session.h" #include "core/hle/kernel/client_session.h"
@ -47,9 +48,11 @@ ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> ServiceManager::RegisterService
if (registered_services.find(name) != registered_services.end()) if (registered_services.find(name) != registered_services.end())
return ERR_ALREADY_REGISTERED; return ERR_ALREADY_REGISTERED;
auto& kernel = Core::System::GetInstance().Kernel();
Kernel::SharedPtr<Kernel::ServerPort> server_port; Kernel::SharedPtr<Kernel::ServerPort> server_port;
Kernel::SharedPtr<Kernel::ClientPort> client_port; Kernel::SharedPtr<Kernel::ClientPort> client_port;
std::tie(server_port, client_port) = Kernel::ServerPort::CreatePortPair(max_sessions, name); std::tie(server_port, client_port) =
Kernel::ServerPort::CreatePortPair(kernel, max_sessions, name);
registered_services.emplace(std::move(name), std::move(client_port)); registered_services.emplace(std::move(name), std::move(client_port));
return MakeResult<Kernel::SharedPtr<Kernel::ServerPort>>(std::move(server_port)); return MakeResult<Kernel::SharedPtr<Kernel::ServerPort>>(std::move(server_port));

@ -6,6 +6,7 @@
#include "common/common_funcs.h" #include "common/common_funcs.h"
#include "common/file_util.h" #include "common/file_util.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/core.h"
#include "core/file_sys/content_archive.h" #include "core/file_sys/content_archive.h"
#include "core/file_sys/control_metadata.h" #include "core/file_sys/control_metadata.h"
#include "core/file_sys/romfs_factory.h" #include "core/file_sys/romfs_factory.h"
@ -117,10 +118,11 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(
} }
} }
auto& kernel = Core::System::GetInstance().Kernel();
process->program_id = metadata.GetTitleID(); process->program_id = metadata.GetTitleID();
process->svc_access_mask.set(); process->svc_access_mask.set();
process->resource_limit = process->resource_limit =
Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION);
process->Run(Memory::PROCESS_IMAGE_VADDR, metadata.GetMainThreadPriority(), process->Run(Memory::PROCESS_IMAGE_VADDR, metadata.GetMainThreadPriority(),
metadata.GetMainThreadStackSize()); metadata.GetMainThreadStackSize());

@ -9,6 +9,7 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "common/file_util.h" #include "common/file_util.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/kernel/process.h" #include "core/hle/kernel/process.h"
#include "core/hle/kernel/resource_limit.h" #include "core/hle/kernel/resource_limit.h"
#include "core/loader/elf.h" #include "core/loader/elf.h"
@ -300,7 +301,8 @@ SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) {
std::vector<u8> program_image(total_image_size); std::vector<u8> program_image(total_image_size);
size_t current_image_position = 0; size_t current_image_position = 0;
SharedPtr<CodeSet> codeset = CodeSet::Create(""); auto& kernel = Core::System::GetInstance().Kernel();
SharedPtr<CodeSet> codeset = CodeSet::Create(kernel, "");
for (unsigned int i = 0; i < header->e_phnum; ++i) { for (unsigned int i = 0; i < header->e_phnum; ++i) {
Elf32_Phdr* p = &segments[i]; Elf32_Phdr* p = &segments[i];
@ -400,8 +402,9 @@ ResultStatus AppLoader_ELF::Load(Kernel::SharedPtr<Kernel::Process>& process) {
process->svc_access_mask.set(); process->svc_access_mask.set();
// Attach the default resource limit (APPLICATION) to the process // Attach the default resource limit (APPLICATION) to the process
auto& kernel = Core::System::GetInstance().Kernel();
process->resource_limit = process->resource_limit =
Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION);
process->Run(codeset->entrypoint, 48, Memory::DEFAULT_STACK_SIZE); process->Run(codeset->entrypoint, 48, Memory::DEFAULT_STACK_SIZE);

@ -136,7 +136,8 @@ bool AppLoader_NRO::LoadNro(FileSys::VirtualFile file, VAddr load_base) {
} }
// Build program image // Build program image
Kernel::SharedPtr<Kernel::CodeSet> codeset = Kernel::CodeSet::Create(""); auto& kernel = Core::System::GetInstance().Kernel();
Kernel::SharedPtr<Kernel::CodeSet> codeset = Kernel::CodeSet::Create(kernel, "");
std::vector<u8> program_image = file->ReadBytes(PageAlignSize(nro_header.file_size)); std::vector<u8> program_image = file->ReadBytes(PageAlignSize(nro_header.file_size));
if (program_image.size() != PageAlignSize(nro_header.file_size)) { if (program_image.size() != PageAlignSize(nro_header.file_size)) {
return {}; return {};
@ -185,9 +186,10 @@ ResultStatus AppLoader_NRO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
return ResultStatus::ErrorLoadingNRO; return ResultStatus::ErrorLoadingNRO;
} }
auto& kernel = Core::System::GetInstance().Kernel();
process->svc_access_mask.set(); process->svc_access_mask.set();
process->resource_limit = process->resource_limit =
Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION);
process->Run(base_addr, THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE); process->Run(base_addr, THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE);
is_loaded = true; is_loaded = true;

@ -100,7 +100,8 @@ VAddr AppLoader_NSO::LoadModule(FileSys::VirtualFile file, VAddr load_base) {
return {}; return {};
// Build program image // Build program image
Kernel::SharedPtr<Kernel::CodeSet> codeset = Kernel::CodeSet::Create(""); auto& kernel = Core::System::GetInstance().Kernel();
Kernel::SharedPtr<Kernel::CodeSet> codeset = Kernel::CodeSet::Create(kernel, "");
std::vector<u8> program_image; std::vector<u8> program_image;
for (std::size_t i = 0; i < nso_header.segments.size(); ++i) { for (std::size_t i = 0; i < nso_header.segments.size(); ++i) {
const std::vector<u8> compressed_data = const std::vector<u8> compressed_data =
@ -151,9 +152,10 @@ ResultStatus AppLoader_NSO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
LoadModule(file, Memory::PROCESS_IMAGE_VADDR); LoadModule(file, Memory::PROCESS_IMAGE_VADDR);
LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), Memory::PROCESS_IMAGE_VADDR); LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), Memory::PROCESS_IMAGE_VADDR);
auto& kernel = Core::System::GetInstance().Kernel();
process->svc_access_mask.set(); process->svc_access_mask.set();
process->resource_limit = process->resource_limit =
Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION);
process->Run(Memory::PROCESS_IMAGE_VADDR, THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE); process->Run(Memory::PROCESS_IMAGE_VADDR, THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE);
is_loaded = true; is_loaded = true;

@ -13,7 +13,7 @@ namespace ArmTests {
TestEnvironment::TestEnvironment(bool mutable_memory_) 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)) {
Core::CurrentProcess() = Kernel::Process::Create(""); Core::CurrentProcess() = Kernel::Process::Create(kernel, "");
page_table = &Core::CurrentProcess()->vm_manager.page_table; page_table = &Core::CurrentProcess()->vm_manager.page_table;
page_table->pointers.fill(nullptr); page_table->pointers.fill(nullptr);

@ -9,6 +9,7 @@
#include <vector> #include <vector>
#include "common/common_types.h" #include "common/common_types.h"
#include "core/hle/kernel/kernel.h"
#include "core/memory_hook.h" #include "core/memory_hook.h"
namespace Memory { namespace Memory {
@ -86,6 +87,7 @@ private:
std::shared_ptr<TestMemory> test_memory; std::shared_ptr<TestMemory> test_memory;
std::vector<WriteRecord> write_records; std::vector<WriteRecord> write_records;
Memory::PageTable* page_table = nullptr; Memory::PageTable* page_table = nullptr;
Kernel::KernelCore kernel;
}; };
} // namespace ArmTests } // namespace ArmTests

@ -77,9 +77,11 @@ QString WaitTreeText::GetText() const {
} }
WaitTreeMutexInfo::WaitTreeMutexInfo(VAddr mutex_address) : mutex_address(mutex_address) { WaitTreeMutexInfo::WaitTreeMutexInfo(VAddr mutex_address) : mutex_address(mutex_address) {
auto& handle_table = Core::System::GetInstance().Kernel().HandleTable();
mutex_value = Memory::Read32(mutex_address); mutex_value = Memory::Read32(mutex_address);
owner_handle = static_cast<Kernel::Handle>(mutex_value & Kernel::Mutex::MutexOwnerMask); owner_handle = static_cast<Kernel::Handle>(mutex_value & Kernel::Mutex::MutexOwnerMask);
owner = Kernel::g_handle_table.Get<Kernel::Thread>(owner_handle); owner = handle_table.Get<Kernel::Thread>(owner_handle);
} }
QString WaitTreeMutexInfo::GetText() const { QString WaitTreeMutexInfo::GetText() const {