Merge pull request #1198 from lioncash/kernel

kernel: Eliminate kernel global state
This commit is contained in:
bunnei 2018-08-30 10:02:50 -04:00 committed by GitHub
commit 5094dfa081
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
54 changed files with 673 additions and 444 deletions

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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));

View file

@ -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.

View file

@ -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.

View file

@ -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;
}; };

View file

@ -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;

View file

@ -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

View file

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

View file

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

View file

@ -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();
} }
} }

View file

@ -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

View file

@ -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

View file

@ -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.

View file

@ -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);

View file

@ -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 {

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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";

View file

@ -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;
}; };

View file

@ -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);

View file

@ -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.

View file

@ -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);

View file

@ -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;
}; };

View file

@ -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();

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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())

View file

@ -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.

View file

@ -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");
} }

View file

@ -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(); });

View file

@ -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:

View file

@ -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;

View file

@ -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:

View file

@ -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:

View file

@ -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");

View file

@ -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

View file

@ -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) {

View file

@ -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

View file

@ -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;

View file

@ -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));

View file

@ -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());

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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

View file

@ -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 {