Merge pull request #1198 from lioncash/kernel
kernel: Eliminate kernel global state
This commit is contained in:
commit
5094dfa081
|
@ -171,6 +171,14 @@ const std::shared_ptr<Kernel::Scheduler>& System::Scheduler(size_t core_index) {
|
||||||
return cpu_cores[core_index]->Scheduler();
|
return cpu_cores[core_index]->Scheduler();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Kernel::KernelCore& System::Kernel() {
|
||||||
|
return kernel;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Kernel::KernelCore& System::Kernel() const {
|
||||||
|
return kernel;
|
||||||
|
}
|
||||||
|
|
||||||
ARM_Interface& System::ArmInterface(size_t core_index) {
|
ARM_Interface& System::ArmInterface(size_t core_index) {
|
||||||
ASSERT(core_index < NUM_CPU_CORES);
|
ASSERT(core_index < NUM_CPU_CORES);
|
||||||
return cpu_cores[core_index]->ArmInterface();
|
return cpu_cores[core_index]->ArmInterface();
|
||||||
|
@ -185,12 +193,13 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) {
|
||||||
LOG_DEBUG(HW_Memory, "initialized OK");
|
LOG_DEBUG(HW_Memory, "initialized OK");
|
||||||
|
|
||||||
CoreTiming::Init();
|
CoreTiming::Init();
|
||||||
|
kernel.Initialize();
|
||||||
|
|
||||||
// Create a default fs if one doesn't already exist.
|
// Create a default fs if one doesn't already exist.
|
||||||
if (virtual_filesystem == nullptr)
|
if (virtual_filesystem == nullptr)
|
||||||
virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>();
|
virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>();
|
||||||
|
|
||||||
current_process = Kernel::Process::Create("main");
|
current_process = Kernel::Process::Create(kernel, "main");
|
||||||
|
|
||||||
cpu_barrier = std::make_shared<CpuBarrier>();
|
cpu_barrier = std::make_shared<CpuBarrier>();
|
||||||
cpu_exclusive_monitor = Cpu::MakeExclusiveMonitor(cpu_cores.size());
|
cpu_exclusive_monitor = Cpu::MakeExclusiveMonitor(cpu_cores.size());
|
||||||
|
@ -201,7 +210,6 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) {
|
||||||
telemetry_session = std::make_unique<Core::TelemetrySession>();
|
telemetry_session = std::make_unique<Core::TelemetrySession>();
|
||||||
service_manager = std::make_shared<Service::SM::ServiceManager>();
|
service_manager = std::make_shared<Service::SM::ServiceManager>();
|
||||||
|
|
||||||
Kernel::Init();
|
|
||||||
Service::Init(service_manager, virtual_filesystem);
|
Service::Init(service_manager, virtual_filesystem);
|
||||||
GDBStub::Init();
|
GDBStub::Init();
|
||||||
|
|
||||||
|
@ -246,7 +254,6 @@ void System::Shutdown() {
|
||||||
renderer.reset();
|
renderer.reset();
|
||||||
GDBStub::Shutdown();
|
GDBStub::Shutdown();
|
||||||
Service::Shutdown();
|
Service::Shutdown();
|
||||||
Kernel::Shutdown();
|
|
||||||
service_manager.reset();
|
service_manager.reset();
|
||||||
telemetry_session.reset();
|
telemetry_session.reset();
|
||||||
gpu_core.reset();
|
gpu_core.reset();
|
||||||
|
@ -265,7 +272,8 @@ void System::Shutdown() {
|
||||||
}
|
}
|
||||||
cpu_barrier.reset();
|
cpu_barrier.reset();
|
||||||
|
|
||||||
// Close core timing
|
// Shutdown kernel and core timing
|
||||||
|
kernel.Shutdown();
|
||||||
CoreTiming::Shutdown();
|
CoreTiming::Shutdown();
|
||||||
|
|
||||||
// Close app loader
|
// Close app loader
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "core/arm/exclusive_monitor.h"
|
#include "core/arm/exclusive_monitor.h"
|
||||||
#include "core/core_cpu.h"
|
#include "core/core_cpu.h"
|
||||||
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/kernel/object.h"
|
#include "core/hle/kernel/object.h"
|
||||||
#include "core/hle/kernel/scheduler.h"
|
#include "core/hle/kernel/scheduler.h"
|
||||||
#include "core/loader/loader.h"
|
#include "core/loader/loader.h"
|
||||||
|
@ -188,6 +189,12 @@ public:
|
||||||
return current_process;
|
return current_process;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Provides a reference to the kernel instance.
|
||||||
|
Kernel::KernelCore& Kernel();
|
||||||
|
|
||||||
|
/// Provides a constant reference to the kernel instance.
|
||||||
|
const Kernel::KernelCore& Kernel() const;
|
||||||
|
|
||||||
/// Gets the name of the current game
|
/// Gets the name of the current game
|
||||||
Loader::ResultStatus GetGameName(std::string& out) const {
|
Loader::ResultStatus GetGameName(std::string& out) const {
|
||||||
if (app_loader == nullptr)
|
if (app_loader == nullptr)
|
||||||
|
@ -246,6 +253,7 @@ private:
|
||||||
*/
|
*/
|
||||||
ResultStatus Init(Frontend::EmuWindow& emu_window);
|
ResultStatus Init(Frontend::EmuWindow& emu_window);
|
||||||
|
|
||||||
|
Kernel::KernelCore kernel;
|
||||||
/// RealVfsFilesystem instance
|
/// RealVfsFilesystem instance
|
||||||
FileSys::VirtualFilesystem virtual_filesystem;
|
FileSys::VirtualFilesystem virtual_filesystem;
|
||||||
/// AppLoader used to load the current executing application
|
/// AppLoader used to load the current executing application
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "core/core.h"
|
||||||
#include "core/hle/ipc.h"
|
#include "core/hle/ipc.h"
|
||||||
#include "core/hle/kernel/client_port.h"
|
#include "core/hle/kernel/client_port.h"
|
||||||
#include "core/hle/kernel/client_session.h"
|
#include "core/hle/kernel/client_session.h"
|
||||||
|
@ -135,7 +136,9 @@ public:
|
||||||
if (context->Session()->IsDomain()) {
|
if (context->Session()->IsDomain()) {
|
||||||
context->AddDomainObject(std::move(iface));
|
context->AddDomainObject(std::move(iface));
|
||||||
} else {
|
} else {
|
||||||
auto sessions = Kernel::ServerSession::CreateSessionPair(iface->GetServiceName());
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
|
auto sessions =
|
||||||
|
Kernel::ServerSession::CreateSessionPair(kernel, iface->GetServiceName());
|
||||||
auto server = std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions);
|
auto server = std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions);
|
||||||
auto client = std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions);
|
auto client = std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions);
|
||||||
iface->ClientConnected(server);
|
iface->ClientConnected(server);
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
ClientPort::ClientPort() = default;
|
ClientPort::ClientPort(KernelCore& kernel) : Object{kernel} {}
|
||||||
ClientPort::~ClientPort() = default;
|
ClientPort::~ClientPort() = default;
|
||||||
|
|
||||||
ResultVal<SharedPtr<ClientSession>> ClientPort::Connect() {
|
ResultVal<SharedPtr<ClientSession>> ClientPort::Connect() {
|
||||||
|
@ -27,7 +27,7 @@ ResultVal<SharedPtr<ClientSession>> ClientPort::Connect() {
|
||||||
active_sessions++;
|
active_sessions++;
|
||||||
|
|
||||||
// Create a new session pair, let the created sessions inherit the parent port's HLE handler.
|
// Create a new session pair, let the created sessions inherit the parent port's HLE handler.
|
||||||
auto sessions = ServerSession::CreateSessionPair(server_port->GetName(), this);
|
auto sessions = ServerSession::CreateSessionPair(kernel, server_port->GetName(), this);
|
||||||
|
|
||||||
if (server_port->hle_handler)
|
if (server_port->hle_handler)
|
||||||
server_port->hle_handler->ClientConnected(std::get<SharedPtr<ServerSession>>(sessions));
|
server_port->hle_handler->ClientConnected(std::get<SharedPtr<ServerSession>>(sessions));
|
||||||
|
|
|
@ -11,8 +11,9 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
class ServerPort;
|
|
||||||
class ClientSession;
|
class ClientSession;
|
||||||
|
class KernelCore;
|
||||||
|
class ServerPort;
|
||||||
|
|
||||||
class ClientPort final : public Object {
|
class ClientPort final : public Object {
|
||||||
public:
|
public:
|
||||||
|
@ -44,7 +45,7 @@ public:
|
||||||
void ConnectionClosed();
|
void ConnectionClosed();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ClientPort();
|
explicit ClientPort(KernelCore& kernel);
|
||||||
~ClientPort() override;
|
~ClientPort() override;
|
||||||
|
|
||||||
SharedPtr<ServerPort> server_port; ///< ServerPort associated with this client port.
|
SharedPtr<ServerPort> server_port; ///< ServerPort associated with this client port.
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
ClientSession::ClientSession() = default;
|
ClientSession::ClientSession(KernelCore& kernel) : Object{kernel} {}
|
||||||
ClientSession::~ClientSession() {
|
ClientSession::~ClientSession() {
|
||||||
// This destructor will be called automatically when the last ClientSession handle is closed by
|
// This destructor will be called automatically when the last ClientSession handle is closed by
|
||||||
// the emulated application.
|
// the emulated application.
|
||||||
|
|
|
@ -12,8 +12,9 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
class ServerSession;
|
class KernelCore;
|
||||||
class Session;
|
class Session;
|
||||||
|
class ServerSession;
|
||||||
class Thread;
|
class Thread;
|
||||||
|
|
||||||
class ClientSession final : public Object {
|
class ClientSession final : public Object {
|
||||||
|
@ -41,7 +42,7 @@ public:
|
||||||
std::shared_ptr<Session> parent;
|
std::shared_ptr<Session> parent;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ClientSession();
|
explicit ClientSession(KernelCore& kernel);
|
||||||
~ClientSession() override;
|
~ClientSession() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -10,11 +10,11 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
Event::Event() {}
|
Event::Event(KernelCore& kernel) : WaitObject{kernel} {}
|
||||||
Event::~Event() {}
|
Event::~Event() = default;
|
||||||
|
|
||||||
SharedPtr<Event> Event::Create(ResetType reset_type, std::string name) {
|
SharedPtr<Event> Event::Create(KernelCore& kernel, ResetType reset_type, std::string name) {
|
||||||
SharedPtr<Event> evt(new Event);
|
SharedPtr<Event> evt(new Event(kernel));
|
||||||
|
|
||||||
evt->signaled = false;
|
evt->signaled = false;
|
||||||
evt->reset_type = reset_type;
|
evt->reset_type = reset_type;
|
||||||
|
|
|
@ -10,14 +10,18 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
|
class KernelCore;
|
||||||
|
|
||||||
class Event final : public WaitObject {
|
class Event final : public WaitObject {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Creates an event
|
* Creates an event
|
||||||
|
* @param kernel The kernel instance to create this event under.
|
||||||
* @param reset_type ResetType describing how to create event
|
* @param reset_type ResetType describing how to create event
|
||||||
* @param name Optional name of event
|
* @param name Optional name of event
|
||||||
*/
|
*/
|
||||||
static SharedPtr<Event> Create(ResetType reset_type, std::string name = "Unknown");
|
static SharedPtr<Event> Create(KernelCore& kernel, ResetType reset_type,
|
||||||
|
std::string name = "Unknown");
|
||||||
|
|
||||||
std::string GetTypeName() const override {
|
std::string GetTypeName() const override {
|
||||||
return "Event";
|
return "Event";
|
||||||
|
@ -44,7 +48,7 @@ public:
|
||||||
void Clear();
|
void Clear();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Event();
|
explicit Event(KernelCore& kernel);
|
||||||
~Event() override;
|
~Event() override;
|
||||||
|
|
||||||
ResetType reset_type; ///< Current ResetType
|
ResetType reset_type; ///< Current ResetType
|
||||||
|
|
|
@ -13,8 +13,6 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
HandleTable g_handle_table;
|
|
||||||
|
|
||||||
HandleTable::HandleTable() {
|
HandleTable::HandleTable() {
|
||||||
next_generation = 1;
|
next_generation = 1;
|
||||||
Clear();
|
Clear();
|
||||||
|
|
|
@ -121,6 +121,4 @@ private:
|
||||||
u16 next_free_slot;
|
u16 next_free_slot;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern HandleTable g_handle_table;
|
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
#include "core/core.h"
|
||||||
#include "core/hle/ipc_helpers.h"
|
#include "core/hle/ipc_helpers.h"
|
||||||
#include "core/hle/kernel/event.h"
|
#include "core/hle/kernel/event.h"
|
||||||
#include "core/hle/kernel/handle_table.h"
|
#include "core/hle/kernel/handle_table.h"
|
||||||
|
@ -51,7 +52,9 @@ SharedPtr<Event> HLERequestContext::SleepClientThread(SharedPtr<Thread> thread,
|
||||||
|
|
||||||
if (!event) {
|
if (!event) {
|
||||||
// Create event if not provided
|
// Create event if not provided
|
||||||
event = Kernel::Event::Create(Kernel::ResetType::OneShot, "HLE Pause Event: " + reason);
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
|
event =
|
||||||
|
Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "HLE Pause Event: " + reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
event->Clear();
|
event->Clear();
|
||||||
|
@ -90,12 +93,14 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {
|
||||||
rp.Skip(2, false);
|
rp.Skip(2, false);
|
||||||
}
|
}
|
||||||
if (incoming) {
|
if (incoming) {
|
||||||
|
auto& handle_table = Core::System::GetInstance().Kernel().HandleTable();
|
||||||
|
|
||||||
// Populate the object lists with the data in the IPC request.
|
// Populate the object lists with the data in the IPC request.
|
||||||
for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_copy; ++handle) {
|
for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_copy; ++handle) {
|
||||||
copy_objects.push_back(Kernel::g_handle_table.GetGeneric(rp.Pop<Handle>()));
|
copy_objects.push_back(handle_table.GetGeneric(rp.Pop<Handle>()));
|
||||||
}
|
}
|
||||||
for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_move; ++handle) {
|
for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_move; ++handle) {
|
||||||
move_objects.push_back(Kernel::g_handle_table.GetGeneric(rp.Pop<Handle>()));
|
move_objects.push_back(handle_table.GetGeneric(rp.Pop<Handle>()));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// For responses we just ignore the handles, they're empty and will be populated when
|
// For responses we just ignore the handles, they're empty and will be populated when
|
||||||
|
@ -230,17 +235,19 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(const Thread& thread)
|
||||||
ASSERT(copy_objects.size() == handle_descriptor_header->num_handles_to_copy);
|
ASSERT(copy_objects.size() == handle_descriptor_header->num_handles_to_copy);
|
||||||
ASSERT(move_objects.size() == handle_descriptor_header->num_handles_to_move);
|
ASSERT(move_objects.size() == handle_descriptor_header->num_handles_to_move);
|
||||||
|
|
||||||
|
auto& handle_table = Core::System::GetInstance().Kernel().HandleTable();
|
||||||
|
|
||||||
// We don't make a distinction between copy and move handles when translating since HLE
|
// We don't make a distinction between copy and move handles when translating since HLE
|
||||||
// services don't deal with handles directly. However, the guest applications might check
|
// services don't deal with handles directly. However, the guest applications might check
|
||||||
// for specific values in each of these descriptors.
|
// for specific values in each of these descriptors.
|
||||||
for (auto& object : copy_objects) {
|
for (auto& object : copy_objects) {
|
||||||
ASSERT(object != nullptr);
|
ASSERT(object != nullptr);
|
||||||
dst_cmdbuf[current_offset++] = Kernel::g_handle_table.Create(object).Unwrap();
|
dst_cmdbuf[current_offset++] = handle_table.Create(object).Unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& object : move_objects) {
|
for (auto& object : move_objects) {
|
||||||
ASSERT(object != nullptr);
|
ASSERT(object != nullptr);
|
||||||
dst_cmdbuf[current_offset++] = Kernel::g_handle_table.Create(object).Unwrap();
|
dst_cmdbuf[current_offset++] = handle_table.Create(object).Unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,38 +2,291 @@
|
||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <atomic>
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "common/assert.h"
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
|
||||||
|
#include "core/core.h"
|
||||||
|
#include "core/core_timing.h"
|
||||||
#include "core/hle/kernel/handle_table.h"
|
#include "core/hle/kernel/handle_table.h"
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/hle/kernel/resource_limit.h"
|
#include "core/hle/kernel/resource_limit.h"
|
||||||
#include "core/hle/kernel/thread.h"
|
#include "core/hle/kernel/thread.h"
|
||||||
#include "core/hle/kernel/timer.h"
|
#include "core/hle/kernel/timer.h"
|
||||||
|
#include "core/hle/lock.h"
|
||||||
|
#include "core/hle/result.h"
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
std::atomic<u32> Object::next_object_id{0};
|
/**
|
||||||
|
* Callback that will wake up the thread it was scheduled for
|
||||||
|
* @param thread_handle The handle of the thread that's been awoken
|
||||||
|
* @param cycles_late The number of CPU cycles that have passed since the desired wakeup time
|
||||||
|
*/
|
||||||
|
static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] int cycles_late) {
|
||||||
|
const auto proper_handle = static_cast<Handle>(thread_handle);
|
||||||
|
auto& system = Core::System::GetInstance();
|
||||||
|
|
||||||
/// Initialize the kernel
|
// Lock the global kernel mutex when we enter the kernel HLE.
|
||||||
void Init() {
|
std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
|
||||||
Kernel::ResourceLimitsInit();
|
|
||||||
Kernel::ThreadingInit();
|
|
||||||
Kernel::TimersInit();
|
|
||||||
|
|
||||||
Object::next_object_id = 0;
|
SharedPtr<Thread> thread =
|
||||||
// TODO(Subv): Start the process ids from 10 for now, as lower PIDs are
|
system.Kernel().RetrieveThreadFromWakeupCallbackHandleTable(proper_handle);
|
||||||
// reserved for low-level services
|
if (thread == nullptr) {
|
||||||
Process::next_process_id = 10;
|
LOG_CRITICAL(Kernel, "Callback fired for invalid thread {:08X}", proper_handle);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool resume = true;
|
||||||
|
|
||||||
|
if (thread->status == ThreadStatus::WaitSynchAny ||
|
||||||
|
thread->status == ThreadStatus::WaitSynchAll ||
|
||||||
|
thread->status == ThreadStatus::WaitHLEEvent) {
|
||||||
|
// Remove the thread from each of its waiting objects' waitlists
|
||||||
|
for (auto& object : thread->wait_objects) {
|
||||||
|
object->RemoveWaitingThread(thread.get());
|
||||||
|
}
|
||||||
|
thread->wait_objects.clear();
|
||||||
|
|
||||||
|
// Invoke the wakeup callback before clearing the wait objects
|
||||||
|
if (thread->wakeup_callback) {
|
||||||
|
resume = thread->wakeup_callback(ThreadWakeupReason::Timeout, thread, nullptr, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (thread->mutex_wait_address != 0 || thread->condvar_wait_address != 0 ||
|
||||||
|
thread->wait_handle) {
|
||||||
|
ASSERT(thread->status == ThreadStatus::WaitMutex);
|
||||||
|
thread->mutex_wait_address = 0;
|
||||||
|
thread->condvar_wait_address = 0;
|
||||||
|
thread->wait_handle = 0;
|
||||||
|
|
||||||
|
auto lock_owner = thread->lock_owner;
|
||||||
|
// Threads waking up by timeout from WaitProcessWideKey do not perform priority inheritance
|
||||||
|
// and don't have a lock owner unless SignalProcessWideKey was called first and the thread
|
||||||
|
// wasn't awakened due to the mutex already being acquired.
|
||||||
|
if (lock_owner) {
|
||||||
|
lock_owner->RemoveMutexWaiter(thread);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (thread->arb_wait_address != 0) {
|
||||||
|
ASSERT(thread->status == ThreadStatus::WaitArb);
|
||||||
|
thread->arb_wait_address = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resume) {
|
||||||
|
thread->ResumeFromWait();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The timer callback event, called when a timer is fired
|
||||||
|
static void TimerCallback(u64 timer_handle, int cycles_late) {
|
||||||
|
const auto proper_handle = static_cast<Handle>(timer_handle);
|
||||||
|
auto& system = Core::System::GetInstance();
|
||||||
|
SharedPtr<Timer> timer = system.Kernel().RetrieveTimerFromCallbackHandleTable(proper_handle);
|
||||||
|
|
||||||
|
if (timer == nullptr) {
|
||||||
|
LOG_CRITICAL(Kernel, "Callback fired for invalid timer {:016X}", timer_handle);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
timer->Signal(cycles_late);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct KernelCore::Impl {
|
||||||
|
void Initialize(KernelCore& kernel) {
|
||||||
|
Shutdown();
|
||||||
|
|
||||||
|
InitializeResourceLimits(kernel);
|
||||||
|
InitializeThreads();
|
||||||
|
InitializeTimers();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shutdown the kernel
|
|
||||||
void Shutdown() {
|
void Shutdown() {
|
||||||
// Free all kernel objects
|
next_object_id = 0;
|
||||||
g_handle_table.Clear();
|
next_process_id = 10;
|
||||||
|
next_thread_id = 1;
|
||||||
|
|
||||||
Kernel::ThreadingShutdown();
|
process_list.clear();
|
||||||
|
|
||||||
Kernel::TimersShutdown();
|
handle_table.Clear();
|
||||||
Kernel::ResourceLimitsShutdown();
|
resource_limits.fill(nullptr);
|
||||||
|
|
||||||
|
thread_wakeup_callback_handle_table.Clear();
|
||||||
|
thread_wakeup_event_type = nullptr;
|
||||||
|
|
||||||
|
timer_callback_handle_table.Clear();
|
||||||
|
timer_callback_event_type = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitializeResourceLimits(KernelCore& kernel) {
|
||||||
|
// Create the four resource limits that the system uses
|
||||||
|
// Create the APPLICATION resource limit
|
||||||
|
SharedPtr<ResourceLimit> resource_limit = ResourceLimit::Create(kernel, "Applications");
|
||||||
|
resource_limit->max_priority = 0x18;
|
||||||
|
resource_limit->max_commit = 0x4000000;
|
||||||
|
resource_limit->max_threads = 0x20;
|
||||||
|
resource_limit->max_events = 0x20;
|
||||||
|
resource_limit->max_mutexes = 0x20;
|
||||||
|
resource_limit->max_semaphores = 0x8;
|
||||||
|
resource_limit->max_timers = 0x8;
|
||||||
|
resource_limit->max_shared_mems = 0x10;
|
||||||
|
resource_limit->max_address_arbiters = 0x2;
|
||||||
|
resource_limit->max_cpu_time = 0x1E;
|
||||||
|
resource_limits[static_cast<u8>(ResourceLimitCategory::APPLICATION)] = resource_limit;
|
||||||
|
|
||||||
|
// Create the SYS_APPLET resource limit
|
||||||
|
resource_limit = ResourceLimit::Create(kernel, "System Applets");
|
||||||
|
resource_limit->max_priority = 0x4;
|
||||||
|
resource_limit->max_commit = 0x5E00000;
|
||||||
|
resource_limit->max_threads = 0x1D;
|
||||||
|
resource_limit->max_events = 0xB;
|
||||||
|
resource_limit->max_mutexes = 0x8;
|
||||||
|
resource_limit->max_semaphores = 0x4;
|
||||||
|
resource_limit->max_timers = 0x4;
|
||||||
|
resource_limit->max_shared_mems = 0x8;
|
||||||
|
resource_limit->max_address_arbiters = 0x3;
|
||||||
|
resource_limit->max_cpu_time = 0x2710;
|
||||||
|
resource_limits[static_cast<u8>(ResourceLimitCategory::SYS_APPLET)] = resource_limit;
|
||||||
|
|
||||||
|
// Create the LIB_APPLET resource limit
|
||||||
|
resource_limit = ResourceLimit::Create(kernel, "Library Applets");
|
||||||
|
resource_limit->max_priority = 0x4;
|
||||||
|
resource_limit->max_commit = 0x600000;
|
||||||
|
resource_limit->max_threads = 0xE;
|
||||||
|
resource_limit->max_events = 0x8;
|
||||||
|
resource_limit->max_mutexes = 0x8;
|
||||||
|
resource_limit->max_semaphores = 0x4;
|
||||||
|
resource_limit->max_timers = 0x4;
|
||||||
|
resource_limit->max_shared_mems = 0x8;
|
||||||
|
resource_limit->max_address_arbiters = 0x1;
|
||||||
|
resource_limit->max_cpu_time = 0x2710;
|
||||||
|
resource_limits[static_cast<u8>(ResourceLimitCategory::LIB_APPLET)] = resource_limit;
|
||||||
|
|
||||||
|
// Create the OTHER resource limit
|
||||||
|
resource_limit = ResourceLimit::Create(kernel, "Others");
|
||||||
|
resource_limit->max_priority = 0x4;
|
||||||
|
resource_limit->max_commit = 0x2180000;
|
||||||
|
resource_limit->max_threads = 0xE1;
|
||||||
|
resource_limit->max_events = 0x108;
|
||||||
|
resource_limit->max_mutexes = 0x25;
|
||||||
|
resource_limit->max_semaphores = 0x43;
|
||||||
|
resource_limit->max_timers = 0x2C;
|
||||||
|
resource_limit->max_shared_mems = 0x1F;
|
||||||
|
resource_limit->max_address_arbiters = 0x2D;
|
||||||
|
resource_limit->max_cpu_time = 0x3E8;
|
||||||
|
resource_limits[static_cast<u8>(ResourceLimitCategory::OTHER)] = resource_limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitializeThreads() {
|
||||||
|
thread_wakeup_event_type =
|
||||||
|
CoreTiming::RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitializeTimers() {
|
||||||
|
timer_callback_handle_table.Clear();
|
||||||
|
timer_callback_event_type = CoreTiming::RegisterEvent("TimerCallback", TimerCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::atomic<u32> next_object_id{0};
|
||||||
|
// TODO(Subv): Start the process ids from 10 for now, as lower PIDs are
|
||||||
|
// reserved for low-level services
|
||||||
|
std::atomic<u32> next_process_id{10};
|
||||||
|
std::atomic<u32> next_thread_id{1};
|
||||||
|
|
||||||
|
// Lists all processes that exist in the current session.
|
||||||
|
std::vector<SharedPtr<Process>> process_list;
|
||||||
|
|
||||||
|
Kernel::HandleTable handle_table;
|
||||||
|
std::array<SharedPtr<ResourceLimit>, 4> resource_limits;
|
||||||
|
|
||||||
|
/// The event type of the generic timer callback event
|
||||||
|
CoreTiming::EventType* timer_callback_event_type = nullptr;
|
||||||
|
// TODO(yuriks): This can be removed if Timer objects are explicitly pooled in the future,
|
||||||
|
// allowing us to simply use a pool index or similar.
|
||||||
|
Kernel::HandleTable timer_callback_handle_table;
|
||||||
|
|
||||||
|
CoreTiming::EventType* thread_wakeup_event_type = nullptr;
|
||||||
|
// TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future,
|
||||||
|
// allowing us to simply use a pool index or similar.
|
||||||
|
Kernel::HandleTable thread_wakeup_callback_handle_table;
|
||||||
|
};
|
||||||
|
|
||||||
|
KernelCore::KernelCore() : impl{std::make_unique<Impl>()} {}
|
||||||
|
KernelCore::~KernelCore() {
|
||||||
|
Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
void KernelCore::Initialize() {
|
||||||
|
impl->Initialize(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KernelCore::Shutdown() {
|
||||||
|
impl->Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
Kernel::HandleTable& KernelCore::HandleTable() {
|
||||||
|
return impl->handle_table;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Kernel::HandleTable& KernelCore::HandleTable() const {
|
||||||
|
return impl->handle_table;
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedPtr<ResourceLimit> KernelCore::ResourceLimitForCategory(
|
||||||
|
ResourceLimitCategory category) const {
|
||||||
|
return impl->resource_limits.at(static_cast<std::size_t>(category));
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedPtr<Thread> KernelCore::RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const {
|
||||||
|
return impl->thread_wakeup_callback_handle_table.Get<Thread>(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedPtr<Timer> KernelCore::RetrieveTimerFromCallbackHandleTable(Handle handle) const {
|
||||||
|
return impl->timer_callback_handle_table.Get<Timer>(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KernelCore::AppendNewProcess(SharedPtr<Process> process) {
|
||||||
|
impl->process_list.push_back(std::move(process));
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 KernelCore::CreateNewObjectID() {
|
||||||
|
return impl->next_object_id++;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 KernelCore::CreateNewThreadID() {
|
||||||
|
return impl->next_thread_id++;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 KernelCore::CreateNewProcessID() {
|
||||||
|
return impl->next_process_id++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultVal<Handle> KernelCore::CreateTimerCallbackHandle(const SharedPtr<Timer>& timer) {
|
||||||
|
return impl->timer_callback_handle_table.Create(timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
CoreTiming::EventType* KernelCore::ThreadWakeupCallbackEventType() const {
|
||||||
|
return impl->thread_wakeup_event_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
CoreTiming::EventType* KernelCore::TimerCallbackEventType() const {
|
||||||
|
return impl->timer_callback_event_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
Kernel::HandleTable& KernelCore::ThreadWakeupCallbackHandleTable() {
|
||||||
|
return impl->thread_wakeup_callback_handle_table;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Kernel::HandleTable& KernelCore::ThreadWakeupCallbackHandleTable() const {
|
||||||
|
return impl->thread_wakeup_callback_handle_table;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -4,14 +4,93 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "core/hle/kernel/object.h"
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class ResultVal;
|
||||||
|
|
||||||
|
namespace CoreTiming {
|
||||||
|
struct EventType;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
/// Initialize the kernel with the specified system mode.
|
class HandleTable;
|
||||||
void Init();
|
class Process;
|
||||||
|
class ResourceLimit;
|
||||||
|
class Thread;
|
||||||
|
class Timer;
|
||||||
|
|
||||||
/// Shutdown the kernel
|
enum class ResourceLimitCategory : u8;
|
||||||
|
|
||||||
|
/// 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();
|
void Shutdown();
|
||||||
|
|
||||||
|
/// Provides a reference to the handle table.
|
||||||
|
Kernel::HandleTable& HandleTable();
|
||||||
|
|
||||||
|
/// Provides a const reference to the handle table.
|
||||||
|
const Kernel::HandleTable& HandleTable() const;
|
||||||
|
|
||||||
|
/// Retrieves a shared pointer to a ResourceLimit identified by the given category.
|
||||||
|
SharedPtr<ResourceLimit> ResourceLimitForCategory(ResourceLimitCategory category) const;
|
||||||
|
|
||||||
|
/// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table.
|
||||||
|
SharedPtr<Thread> RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const;
|
||||||
|
|
||||||
|
/// Retrieves a shared pointer to a Timer instance within the timer callback handle table.
|
||||||
|
SharedPtr<Timer> RetrieveTimerFromCallbackHandleTable(Handle handle) const;
|
||||||
|
|
||||||
|
/// Adds the given shared pointer to an internal list of active processes.
|
||||||
|
void AppendNewProcess(SharedPtr<Process> process);
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class Object;
|
||||||
|
friend class Process;
|
||||||
|
friend class Thread;
|
||||||
|
friend class Timer;
|
||||||
|
|
||||||
|
/// Creates a new object ID, incrementing the internal object ID counter.
|
||||||
|
u32 CreateNewObjectID();
|
||||||
|
|
||||||
|
/// Creates a new process ID, incrementing the internal process ID counter;
|
||||||
|
u32 CreateNewProcessID();
|
||||||
|
|
||||||
|
/// Creates a new thread ID, incrementing the internal thread ID counter.
|
||||||
|
u32 CreateNewThreadID();
|
||||||
|
|
||||||
|
/// Creates a timer callback handle for the given timer.
|
||||||
|
ResultVal<Handle> CreateTimerCallbackHandle(const SharedPtr<Timer>& timer);
|
||||||
|
|
||||||
|
/// Retrieves the event type used for thread wakeup callbacks.
|
||||||
|
CoreTiming::EventType* ThreadWakeupCallbackEventType() const;
|
||||||
|
|
||||||
|
/// Retrieves the event type used for timer callbacks.
|
||||||
|
CoreTiming::EventType* TimerCallbackEventType() const;
|
||||||
|
|
||||||
|
/// Provides a reference to the thread wakeup callback handle table.
|
||||||
|
Kernel::HandleTable& ThreadWakeupCallbackHandleTable();
|
||||||
|
|
||||||
|
/// Provides a const reference to the thread wakeup callback handle table.
|
||||||
|
const Kernel::HandleTable& ThreadWakeupCallbackHandleTable() const;
|
||||||
|
|
||||||
|
struct Impl;
|
||||||
|
std::unique_ptr<Impl> impl;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -58,15 +58,15 @@ static void TransferMutexOwnership(VAddr mutex_addr, SharedPtr<Thread> current_t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle,
|
ResultCode Mutex::TryAcquire(HandleTable& handle_table, VAddr address, Handle holding_thread_handle,
|
||||||
Handle requesting_thread_handle) {
|
Handle requesting_thread_handle) {
|
||||||
// The mutex address must be 4-byte aligned
|
// The mutex address must be 4-byte aligned
|
||||||
if ((address % sizeof(u32)) != 0) {
|
if ((address % sizeof(u32)) != 0) {
|
||||||
return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidAddress);
|
return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedPtr<Thread> holding_thread = g_handle_table.Get<Thread>(holding_thread_handle);
|
SharedPtr<Thread> holding_thread = handle_table.Get<Thread>(holding_thread_handle);
|
||||||
SharedPtr<Thread> requesting_thread = g_handle_table.Get<Thread>(requesting_thread_handle);
|
SharedPtr<Thread> requesting_thread = handle_table.Get<Thread>(requesting_thread_handle);
|
||||||
|
|
||||||
// TODO(Subv): It is currently unknown if it is possible to lock a mutex in behalf of another
|
// TODO(Subv): It is currently unknown if it is possible to lock a mutex in behalf of another
|
||||||
// thread.
|
// thread.
|
||||||
|
|
|
@ -11,6 +11,7 @@ union ResultCode;
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
|
class HandleTable;
|
||||||
class Thread;
|
class Thread;
|
||||||
|
|
||||||
class Mutex final {
|
class Mutex final {
|
||||||
|
@ -21,8 +22,8 @@ public:
|
||||||
static constexpr u32 MutexOwnerMask = 0xBFFFFFFF;
|
static constexpr u32 MutexOwnerMask = 0xBFFFFFFF;
|
||||||
|
|
||||||
/// Attempts to acquire a mutex at the specified address.
|
/// Attempts to acquire a mutex at the specified address.
|
||||||
static ResultCode TryAcquire(VAddr address, Handle holding_thread_handle,
|
static ResultCode TryAcquire(HandleTable& handle_table, VAddr address,
|
||||||
Handle requesting_thread_handle);
|
Handle holding_thread_handle, Handle requesting_thread_handle);
|
||||||
|
|
||||||
/// Releases the mutex at the specified address.
|
/// Releases the mutex at the specified address.
|
||||||
static ResultCode Release(VAddr address);
|
static ResultCode Release(VAddr address);
|
||||||
|
|
|
@ -3,10 +3,12 @@
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/kernel/object.h"
|
#include "core/hle/kernel/object.h"
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
|
Object::Object(KernelCore& kernel) : kernel{kernel}, object_id{kernel.CreateNewObjectID()} {}
|
||||||
Object::~Object() = default;
|
Object::~Object() = default;
|
||||||
|
|
||||||
bool Object::IsWaitable() const {
|
bool Object::IsWaitable() const {
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
|
class KernelCore;
|
||||||
|
|
||||||
using Handle = u32;
|
using Handle = u32;
|
||||||
|
|
||||||
enum class HandleType : u32 {
|
enum class HandleType : u32 {
|
||||||
|
@ -40,6 +42,7 @@ enum class ResetType {
|
||||||
|
|
||||||
class Object : NonCopyable {
|
class Object : NonCopyable {
|
||||||
public:
|
public:
|
||||||
|
explicit Object(KernelCore& kernel);
|
||||||
virtual ~Object();
|
virtual ~Object();
|
||||||
|
|
||||||
/// Returns a unique identifier for the object. For debugging purposes only.
|
/// Returns a unique identifier for the object. For debugging purposes only.
|
||||||
|
@ -61,15 +64,16 @@ public:
|
||||||
*/
|
*/
|
||||||
bool IsWaitable() const;
|
bool IsWaitable() const;
|
||||||
|
|
||||||
public:
|
protected:
|
||||||
static std::atomic<u32> next_object_id;
|
/// The kernel instance this object was created under.
|
||||||
|
KernelCore& kernel;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend void intrusive_ptr_add_ref(Object*);
|
friend void intrusive_ptr_add_ref(Object*);
|
||||||
friend void intrusive_ptr_release(Object*);
|
friend void intrusive_ptr_release(Object*);
|
||||||
|
|
||||||
std::atomic<u32> ref_count{0};
|
std::atomic<u32> ref_count{0};
|
||||||
std::atomic<u32> object_id{next_object_id++};
|
std::atomic<u32> object_id{0};
|
||||||
};
|
};
|
||||||
|
|
||||||
// Special functions used by boost::instrusive_ptr to do automatic ref-counting
|
// Special functions used by boost::instrusive_ptr to do automatic ref-counting
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/hle/kernel/errors.h"
|
#include "core/hle/kernel/errors.h"
|
||||||
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/hle/kernel/resource_limit.h"
|
#include "core/hle/kernel/resource_limit.h"
|
||||||
#include "core/hle/kernel/thread.h"
|
#include "core/hle/kernel/thread.h"
|
||||||
|
@ -16,30 +17,26 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
// Lists all processes that exist in the current session.
|
SharedPtr<CodeSet> CodeSet::Create(KernelCore& kernel, std::string name) {
|
||||||
static std::vector<SharedPtr<Process>> process_list;
|
SharedPtr<CodeSet> codeset(new CodeSet(kernel));
|
||||||
|
|
||||||
SharedPtr<CodeSet> CodeSet::Create(std::string name) {
|
|
||||||
SharedPtr<CodeSet> codeset(new CodeSet);
|
|
||||||
codeset->name = std::move(name);
|
codeset->name = std::move(name);
|
||||||
return codeset;
|
return codeset;
|
||||||
}
|
}
|
||||||
|
|
||||||
CodeSet::CodeSet() {}
|
CodeSet::CodeSet(KernelCore& kernel) : Object{kernel} {}
|
||||||
CodeSet::~CodeSet() {}
|
CodeSet::~CodeSet() = default;
|
||||||
|
|
||||||
u32 Process::next_process_id;
|
SharedPtr<Process> Process::Create(KernelCore& kernel, std::string&& name) {
|
||||||
|
SharedPtr<Process> process(new Process(kernel));
|
||||||
SharedPtr<Process> Process::Create(std::string&& name) {
|
|
||||||
SharedPtr<Process> process(new Process);
|
|
||||||
|
|
||||||
process->name = std::move(name);
|
process->name = std::move(name);
|
||||||
process->flags.raw = 0;
|
process->flags.raw = 0;
|
||||||
process->flags.memory_region.Assign(MemoryRegion::APPLICATION);
|
process->flags.memory_region.Assign(MemoryRegion::APPLICATION);
|
||||||
process->status = ProcessStatus::Created;
|
process->status = ProcessStatus::Created;
|
||||||
process->program_id = 0;
|
process->program_id = 0;
|
||||||
|
process->process_id = kernel.CreateNewProcessID();
|
||||||
|
|
||||||
process_list.push_back(process);
|
kernel.AppendNewProcess(process);
|
||||||
return process;
|
return process;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,7 +125,7 @@ void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) {
|
||||||
vm_manager.LogLayout();
|
vm_manager.LogLayout();
|
||||||
status = ProcessStatus::Running;
|
status = ProcessStatus::Running;
|
||||||
|
|
||||||
Kernel::SetupMainThread(entry_point, main_thread_priority, this);
|
Kernel::SetupMainThread(kernel, entry_point, main_thread_priority, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Process::LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr) {
|
void Process::LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr) {
|
||||||
|
@ -231,22 +228,7 @@ ResultCode Process::UnmapMemory(VAddr dst_addr, VAddr /*src_addr*/, u64 size) {
|
||||||
return vm_manager.UnmapRange(dst_addr, size);
|
return vm_manager.UnmapRange(dst_addr, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
Kernel::Process::Process() {}
|
Kernel::Process::Process(KernelCore& kernel) : Object{kernel} {}
|
||||||
Kernel::Process::~Process() {}
|
Kernel::Process::~Process() {}
|
||||||
|
|
||||||
void ClearProcessList() {
|
|
||||||
process_list.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
SharedPtr<Process> GetProcessById(u32 process_id) {
|
|
||||||
auto itr = std::find_if(
|
|
||||||
process_list.begin(), process_list.end(),
|
|
||||||
[&](const SharedPtr<Process>& process) { return process->process_id == process_id; });
|
|
||||||
|
|
||||||
if (itr == process_list.end())
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
return *itr;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
|
class KernelCore;
|
||||||
|
|
||||||
struct AddressMapping {
|
struct AddressMapping {
|
||||||
// Address and size must be page-aligned
|
// Address and size must be page-aligned
|
||||||
VAddr address;
|
VAddr address;
|
||||||
|
@ -62,7 +64,7 @@ struct CodeSet final : public Object {
|
||||||
u32 size = 0;
|
u32 size = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
static SharedPtr<CodeSet> Create(std::string name);
|
static SharedPtr<CodeSet> Create(KernelCore& kernel, std::string name);
|
||||||
|
|
||||||
std::string GetTypeName() const override {
|
std::string GetTypeName() const override {
|
||||||
return "CodeSet";
|
return "CodeSet";
|
||||||
|
@ -109,13 +111,13 @@ struct CodeSet final : public Object {
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CodeSet();
|
explicit CodeSet(KernelCore& kernel);
|
||||||
~CodeSet() override;
|
~CodeSet() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Process final : public Object {
|
class Process final : public Object {
|
||||||
public:
|
public:
|
||||||
static SharedPtr<Process> Create(std::string&& name);
|
static SharedPtr<Process> Create(KernelCore& kernel, std::string&& name);
|
||||||
|
|
||||||
std::string GetTypeName() const override {
|
std::string GetTypeName() const override {
|
||||||
return "Process";
|
return "Process";
|
||||||
|
@ -129,8 +131,6 @@ public:
|
||||||
return HANDLE_TYPE;
|
return HANDLE_TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 next_process_id;
|
|
||||||
|
|
||||||
/// Title ID corresponding to the process
|
/// Title ID corresponding to the process
|
||||||
u64 program_id;
|
u64 program_id;
|
||||||
|
|
||||||
|
@ -157,8 +157,8 @@ public:
|
||||||
/// Current status of the process
|
/// Current status of the process
|
||||||
ProcessStatus status;
|
ProcessStatus status;
|
||||||
|
|
||||||
/// The id of this process
|
/// The ID of this process
|
||||||
u32 process_id = next_process_id++;
|
u32 process_id = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a list of kernel capability descriptors (as found in the ExHeader) and applies them
|
* Parses a list of kernel capability descriptors (as found in the ExHeader) and applies them
|
||||||
|
@ -206,13 +206,8 @@ public:
|
||||||
ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size);
|
ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Process();
|
explicit Process(KernelCore& kernel);
|
||||||
~Process() override;
|
~Process() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
void ClearProcessList();
|
|
||||||
|
|
||||||
/// Retrieves a process from the current list of processes.
|
|
||||||
SharedPtr<Process> GetProcessById(u32 process_id);
|
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -9,31 +9,16 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
static SharedPtr<ResourceLimit> resource_limits[4];
|
ResourceLimit::ResourceLimit(KernelCore& kernel) : Object{kernel} {}
|
||||||
|
ResourceLimit::~ResourceLimit() = default;
|
||||||
|
|
||||||
ResourceLimit::ResourceLimit() {}
|
SharedPtr<ResourceLimit> ResourceLimit::Create(KernelCore& kernel, std::string name) {
|
||||||
ResourceLimit::~ResourceLimit() {}
|
SharedPtr<ResourceLimit> resource_limit(new ResourceLimit(kernel));
|
||||||
|
|
||||||
SharedPtr<ResourceLimit> ResourceLimit::Create(std::string name) {
|
|
||||||
SharedPtr<ResourceLimit> resource_limit(new ResourceLimit);
|
|
||||||
|
|
||||||
resource_limit->name = std::move(name);
|
resource_limit->name = std::move(name);
|
||||||
return resource_limit;
|
return resource_limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedPtr<ResourceLimit> ResourceLimit::GetForCategory(ResourceLimitCategory category) {
|
|
||||||
switch (category) {
|
|
||||||
case ResourceLimitCategory::APPLICATION:
|
|
||||||
case ResourceLimitCategory::SYS_APPLET:
|
|
||||||
case ResourceLimitCategory::LIB_APPLET:
|
|
||||||
case ResourceLimitCategory::OTHER:
|
|
||||||
return resource_limits[static_cast<u8>(category)];
|
|
||||||
default:
|
|
||||||
LOG_CRITICAL(Kernel, "Unknown resource limit category");
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
s32 ResourceLimit::GetCurrentResourceValue(ResourceType resource) const {
|
s32 ResourceLimit::GetCurrentResourceValue(ResourceType resource) const {
|
||||||
switch (resource) {
|
switch (resource) {
|
||||||
case ResourceType::Commit:
|
case ResourceType::Commit:
|
||||||
|
@ -89,66 +74,4 @@ u32 ResourceLimit::GetMaxResourceValue(ResourceType resource) const {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResourceLimitsInit() {
|
|
||||||
// Create the four resource limits that the system uses
|
|
||||||
// Create the APPLICATION resource limit
|
|
||||||
SharedPtr<ResourceLimit> resource_limit = ResourceLimit::Create("Applications");
|
|
||||||
resource_limit->max_priority = 0x18;
|
|
||||||
resource_limit->max_commit = 0x4000000;
|
|
||||||
resource_limit->max_threads = 0x20;
|
|
||||||
resource_limit->max_events = 0x20;
|
|
||||||
resource_limit->max_mutexes = 0x20;
|
|
||||||
resource_limit->max_semaphores = 0x8;
|
|
||||||
resource_limit->max_timers = 0x8;
|
|
||||||
resource_limit->max_shared_mems = 0x10;
|
|
||||||
resource_limit->max_address_arbiters = 0x2;
|
|
||||||
resource_limit->max_cpu_time = 0x1E;
|
|
||||||
resource_limits[static_cast<u8>(ResourceLimitCategory::APPLICATION)] = resource_limit;
|
|
||||||
|
|
||||||
// Create the SYS_APPLET resource limit
|
|
||||||
resource_limit = ResourceLimit::Create("System Applets");
|
|
||||||
resource_limit->max_priority = 0x4;
|
|
||||||
resource_limit->max_commit = 0x5E00000;
|
|
||||||
resource_limit->max_threads = 0x1D;
|
|
||||||
resource_limit->max_events = 0xB;
|
|
||||||
resource_limit->max_mutexes = 0x8;
|
|
||||||
resource_limit->max_semaphores = 0x4;
|
|
||||||
resource_limit->max_timers = 0x4;
|
|
||||||
resource_limit->max_shared_mems = 0x8;
|
|
||||||
resource_limit->max_address_arbiters = 0x3;
|
|
||||||
resource_limit->max_cpu_time = 0x2710;
|
|
||||||
resource_limits[static_cast<u8>(ResourceLimitCategory::SYS_APPLET)] = resource_limit;
|
|
||||||
|
|
||||||
// Create the LIB_APPLET resource limit
|
|
||||||
resource_limit = ResourceLimit::Create("Library Applets");
|
|
||||||
resource_limit->max_priority = 0x4;
|
|
||||||
resource_limit->max_commit = 0x600000;
|
|
||||||
resource_limit->max_threads = 0xE;
|
|
||||||
resource_limit->max_events = 0x8;
|
|
||||||
resource_limit->max_mutexes = 0x8;
|
|
||||||
resource_limit->max_semaphores = 0x4;
|
|
||||||
resource_limit->max_timers = 0x4;
|
|
||||||
resource_limit->max_shared_mems = 0x8;
|
|
||||||
resource_limit->max_address_arbiters = 0x1;
|
|
||||||
resource_limit->max_cpu_time = 0x2710;
|
|
||||||
resource_limits[static_cast<u8>(ResourceLimitCategory::LIB_APPLET)] = resource_limit;
|
|
||||||
|
|
||||||
// Create the OTHER resource limit
|
|
||||||
resource_limit = ResourceLimit::Create("Others");
|
|
||||||
resource_limit->max_priority = 0x4;
|
|
||||||
resource_limit->max_commit = 0x2180000;
|
|
||||||
resource_limit->max_threads = 0xE1;
|
|
||||||
resource_limit->max_events = 0x108;
|
|
||||||
resource_limit->max_mutexes = 0x25;
|
|
||||||
resource_limit->max_semaphores = 0x43;
|
|
||||||
resource_limit->max_timers = 0x2C;
|
|
||||||
resource_limit->max_shared_mems = 0x1F;
|
|
||||||
resource_limit->max_address_arbiters = 0x2D;
|
|
||||||
resource_limit->max_cpu_time = 0x3E8;
|
|
||||||
resource_limits[static_cast<u8>(ResourceLimitCategory::OTHER)] = resource_limit;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResourceLimitsShutdown() {}
|
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
|
class KernelCore;
|
||||||
|
|
||||||
enum class ResourceLimitCategory : u8 {
|
enum class ResourceLimitCategory : u8 {
|
||||||
APPLICATION = 0,
|
APPLICATION = 0,
|
||||||
SYS_APPLET = 1,
|
SYS_APPLET = 1,
|
||||||
|
@ -34,14 +36,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* Creates a resource limit object.
|
* Creates a resource limit object.
|
||||||
*/
|
*/
|
||||||
static SharedPtr<ResourceLimit> Create(std::string name = "Unknown");
|
static SharedPtr<ResourceLimit> Create(KernelCore& kernel, std::string name = "Unknown");
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the resource limit associated with the specified resource limit category.
|
|
||||||
* @param category The resource limit category
|
|
||||||
* @returns The resource limit associated with the category
|
|
||||||
*/
|
|
||||||
static SharedPtr<ResourceLimit> GetForCategory(ResourceLimitCategory category);
|
|
||||||
|
|
||||||
std::string GetTypeName() const override {
|
std::string GetTypeName() const override {
|
||||||
return "ResourceLimit";
|
return "ResourceLimit";
|
||||||
|
@ -113,14 +108,8 @@ public:
|
||||||
s32 current_cpu_time = 0;
|
s32 current_cpu_time = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ResourceLimit();
|
explicit ResourceLimit(KernelCore& kernel);
|
||||||
~ResourceLimit() override;
|
~ResourceLimit() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Initializes the resource limits
|
|
||||||
void ResourceLimitsInit();
|
|
||||||
|
|
||||||
// Destroys the resource limits
|
|
||||||
void ResourceLimitsShutdown();
|
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -13,8 +13,8 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
ServerPort::ServerPort() {}
|
ServerPort::ServerPort(KernelCore& kernel) : WaitObject{kernel} {}
|
||||||
ServerPort::~ServerPort() {}
|
ServerPort::~ServerPort() = default;
|
||||||
|
|
||||||
ResultVal<SharedPtr<ServerSession>> ServerPort::Accept() {
|
ResultVal<SharedPtr<ServerSession>> ServerPort::Accept() {
|
||||||
if (pending_sessions.empty()) {
|
if (pending_sessions.empty()) {
|
||||||
|
@ -36,10 +36,10 @@ void ServerPort::Acquire(Thread* thread) {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> ServerPort::CreatePortPair(
|
std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> ServerPort::CreatePortPair(
|
||||||
u32 max_sessions, std::string name) {
|
KernelCore& kernel, u32 max_sessions, std::string name) {
|
||||||
|
|
||||||
SharedPtr<ServerPort> server_port(new ServerPort);
|
SharedPtr<ServerPort> server_port(new ServerPort(kernel));
|
||||||
SharedPtr<ClientPort> client_port(new ClientPort);
|
SharedPtr<ClientPort> client_port(new ClientPort(kernel));
|
||||||
|
|
||||||
server_port->name = name + "_Server";
|
server_port->name = name + "_Server";
|
||||||
client_port->name = name + "_Client";
|
client_port->name = name + "_Client";
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
class ClientPort;
|
class ClientPort;
|
||||||
|
class KernelCore;
|
||||||
class ServerSession;
|
class ServerSession;
|
||||||
class SessionRequestHandler;
|
class SessionRequestHandler;
|
||||||
|
|
||||||
|
@ -23,12 +24,13 @@ public:
|
||||||
/**
|
/**
|
||||||
* Creates a pair of ServerPort and an associated ClientPort.
|
* Creates a pair of ServerPort and an associated ClientPort.
|
||||||
*
|
*
|
||||||
|
* @param kernel The kernel instance to create the port pair under.
|
||||||
* @param max_sessions Maximum number of sessions to the port
|
* @param max_sessions Maximum number of sessions to the port
|
||||||
* @param name Optional name of the ports
|
* @param name Optional name of the ports
|
||||||
* @return The created port tuple
|
* @return The created port tuple
|
||||||
*/
|
*/
|
||||||
static std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> CreatePortPair(
|
static std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> CreatePortPair(
|
||||||
u32 max_sessions, std::string name = "UnknownPort");
|
KernelCore& kernel, u32 max_sessions, std::string name = "UnknownPort");
|
||||||
|
|
||||||
std::string GetTypeName() const override {
|
std::string GetTypeName() const override {
|
||||||
return "ServerPort";
|
return "ServerPort";
|
||||||
|
@ -69,7 +71,7 @@ public:
|
||||||
void Acquire(Thread* thread) override;
|
void Acquire(Thread* thread) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ServerPort();
|
explicit ServerPort(KernelCore& kernel);
|
||||||
~ServerPort() override;
|
~ServerPort() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
ServerSession::ServerSession() = default;
|
ServerSession::ServerSession(KernelCore& kernel) : WaitObject{kernel} {}
|
||||||
ServerSession::~ServerSession() {
|
ServerSession::~ServerSession() {
|
||||||
// This destructor will be called automatically when the last ServerSession handle is closed by
|
// This destructor will be called automatically when the last ServerSession handle is closed by
|
||||||
// the emulated application.
|
// the emulated application.
|
||||||
|
@ -35,8 +35,8 @@ ServerSession::~ServerSession() {
|
||||||
parent->server = nullptr;
|
parent->server = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<SharedPtr<ServerSession>> ServerSession::Create(std::string name) {
|
ResultVal<SharedPtr<ServerSession>> ServerSession::Create(KernelCore& kernel, std::string name) {
|
||||||
SharedPtr<ServerSession> server_session(new ServerSession);
|
SharedPtr<ServerSession> server_session(new ServerSession(kernel));
|
||||||
|
|
||||||
server_session->name = std::move(name);
|
server_session->name = std::move(name);
|
||||||
server_session->parent = nullptr;
|
server_session->parent = nullptr;
|
||||||
|
@ -105,10 +105,10 @@ ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) {
|
||||||
// from its ClientSession, so wake up any threads that may be waiting on a svcReplyAndReceive or
|
// from its ClientSession, so wake up any threads that may be waiting on a svcReplyAndReceive or
|
||||||
// similar.
|
// similar.
|
||||||
|
|
||||||
|
auto& handle_table = Core::System::GetInstance().Kernel().HandleTable();
|
||||||
Kernel::HLERequestContext context(this);
|
Kernel::HLERequestContext context(this);
|
||||||
u32* cmd_buf = (u32*)Memory::GetPointer(thread->GetTLSAddress());
|
u32* cmd_buf = (u32*)Memory::GetPointer(thread->GetTLSAddress());
|
||||||
context.PopulateFromIncomingCommandBuffer(cmd_buf, *Core::CurrentProcess(),
|
context.PopulateFromIncomingCommandBuffer(cmd_buf, *Core::CurrentProcess(), handle_table);
|
||||||
Kernel::g_handle_table);
|
|
||||||
|
|
||||||
ResultCode result = RESULT_SUCCESS;
|
ResultCode result = RESULT_SUCCESS;
|
||||||
// If the session has been converted to a domain, handle the domain request
|
// If the session has been converted to a domain, handle the domain request
|
||||||
|
@ -160,10 +160,11 @@ ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerSession::SessionPair ServerSession::CreateSessionPair(const std::string& name,
|
ServerSession::SessionPair ServerSession::CreateSessionPair(KernelCore& kernel,
|
||||||
|
const std::string& name,
|
||||||
SharedPtr<ClientPort> port) {
|
SharedPtr<ClientPort> port) {
|
||||||
auto server_session = ServerSession::Create(name + "_Server").Unwrap();
|
auto server_session = ServerSession::Create(kernel, name + "_Server").Unwrap();
|
||||||
SharedPtr<ClientSession> client_session(new ClientSession);
|
SharedPtr<ClientSession> client_session(new ClientSession(kernel));
|
||||||
client_session->name = name + "_Client";
|
client_session->name = name + "_Client";
|
||||||
|
|
||||||
std::shared_ptr<Session> parent(new Session);
|
std::shared_ptr<Session> parent(new Session);
|
||||||
|
|
|
@ -15,13 +15,14 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
class ClientSession;
|
|
||||||
class ClientPort;
|
class ClientPort;
|
||||||
|
class ClientSession;
|
||||||
|
class HLERequestContext;
|
||||||
|
class KernelCore;
|
||||||
class ServerSession;
|
class ServerSession;
|
||||||
class Session;
|
class Session;
|
||||||
class SessionRequestHandler;
|
class SessionRequestHandler;
|
||||||
class Thread;
|
class Thread;
|
||||||
class HLERequestContext;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Kernel object representing the server endpoint of an IPC session. Sessions are the basic CTR-OS
|
* Kernel object representing the server endpoint of an IPC session. Sessions are the basic CTR-OS
|
||||||
|
@ -50,11 +51,12 @@ public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a pair of ServerSession and an associated ClientSession.
|
* Creates a pair of ServerSession and an associated ClientSession.
|
||||||
|
* @param kernel The kernal instance to create the session pair under.
|
||||||
* @param name Optional name of the ports.
|
* @param name Optional name of the ports.
|
||||||
* @param client_port Optional The ClientPort that spawned this session.
|
* @param client_port Optional The ClientPort that spawned this session.
|
||||||
* @return The created session tuple
|
* @return The created session tuple
|
||||||
*/
|
*/
|
||||||
static SessionPair CreateSessionPair(const std::string& name = "Unknown",
|
static SessionPair CreateSessionPair(KernelCore& kernel, const std::string& name = "Unknown",
|
||||||
SharedPtr<ClientPort> client_port = nullptr);
|
SharedPtr<ClientPort> client_port = nullptr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -111,16 +113,18 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ServerSession();
|
explicit ServerSession(KernelCore& kernel);
|
||||||
~ServerSession() override;
|
~ServerSession() override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a server session. The server session can have an optional HLE handler,
|
* Creates a server session. The server session can have an optional HLE handler,
|
||||||
* which will be invoked to handle the IPC requests that this session receives.
|
* which will be invoked to handle the IPC requests that this session receives.
|
||||||
|
* @param kernel The kernel instance to create this server session under.
|
||||||
* @param name Optional name of the server session.
|
* @param name Optional name of the server session.
|
||||||
* @return The created server session
|
* @return The created server session
|
||||||
*/
|
*/
|
||||||
static ResultVal<SharedPtr<ServerSession>> Create(std::string name = "Unknown");
|
static ResultVal<SharedPtr<ServerSession>> Create(KernelCore& kernel,
|
||||||
|
std::string name = "Unknown");
|
||||||
|
|
||||||
/// Handles a SyncRequest to a domain, forwarding the request to the proper object or closing an
|
/// Handles a SyncRequest to a domain, forwarding the request to the proper object or closing an
|
||||||
/// object handle.
|
/// object handle.
|
||||||
|
|
|
@ -13,14 +13,14 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
SharedMemory::SharedMemory() {}
|
SharedMemory::SharedMemory(KernelCore& kernel) : Object{kernel} {}
|
||||||
SharedMemory::~SharedMemory() {}
|
SharedMemory::~SharedMemory() = default;
|
||||||
|
|
||||||
SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u64 size,
|
SharedPtr<SharedMemory> SharedMemory::Create(KernelCore& kernel, SharedPtr<Process> owner_process,
|
||||||
MemoryPermission permissions,
|
u64 size, MemoryPermission permissions,
|
||||||
MemoryPermission other_permissions, VAddr address,
|
MemoryPermission other_permissions, VAddr address,
|
||||||
MemoryRegion region, std::string name) {
|
MemoryRegion region, std::string name) {
|
||||||
SharedPtr<SharedMemory> shared_memory(new SharedMemory);
|
SharedPtr<SharedMemory> shared_memory(new SharedMemory(kernel));
|
||||||
|
|
||||||
shared_memory->owner_process = std::move(owner_process);
|
shared_memory->owner_process = std::move(owner_process);
|
||||||
shared_memory->name = std::move(name);
|
shared_memory->name = std::move(name);
|
||||||
|
@ -59,12 +59,10 @@ SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u
|
||||||
return shared_memory;
|
return shared_memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedPtr<SharedMemory> SharedMemory::CreateForApplet(std::shared_ptr<std::vector<u8>> heap_block,
|
SharedPtr<SharedMemory> SharedMemory::CreateForApplet(
|
||||||
u32 offset, u32 size,
|
KernelCore& kernel, std::shared_ptr<std::vector<u8>> heap_block, u32 offset, u32 size,
|
||||||
MemoryPermission permissions,
|
MemoryPermission permissions, MemoryPermission other_permissions, std::string name) {
|
||||||
MemoryPermission other_permissions,
|
SharedPtr<SharedMemory> shared_memory(new SharedMemory(kernel));
|
||||||
std::string name) {
|
|
||||||
SharedPtr<SharedMemory> shared_memory(new SharedMemory);
|
|
||||||
|
|
||||||
shared_memory->owner_process = nullptr;
|
shared_memory->owner_process = nullptr;
|
||||||
shared_memory->name = std::move(name);
|
shared_memory->name = std::move(name);
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
|
class KernelCore;
|
||||||
|
|
||||||
/// Permissions for mapped shared memory blocks
|
/// Permissions for mapped shared memory blocks
|
||||||
enum class MemoryPermission : u32 {
|
enum class MemoryPermission : u32 {
|
||||||
None = 0,
|
None = 0,
|
||||||
|
@ -32,6 +34,7 @@ class SharedMemory final : public Object {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Creates a shared memory object.
|
* Creates a shared memory object.
|
||||||
|
* @param kernel The kernel instance to create a shared memory instance under.
|
||||||
* @param owner_process Process that created this shared memory object.
|
* @param owner_process Process that created this shared memory object.
|
||||||
* @param size Size of the memory block. Must be page-aligned.
|
* @param size Size of the memory block. Must be page-aligned.
|
||||||
* @param permissions Permission restrictions applied to the process which created the block.
|
* @param permissions Permission restrictions applied to the process which created the block.
|
||||||
|
@ -42,14 +45,15 @@ public:
|
||||||
* linear heap.
|
* linear heap.
|
||||||
* @param name Optional object name, used for debugging purposes.
|
* @param name Optional object name, used for debugging purposes.
|
||||||
*/
|
*/
|
||||||
static SharedPtr<SharedMemory> Create(SharedPtr<Process> owner_process, u64 size,
|
static SharedPtr<SharedMemory> Create(KernelCore& kernel, SharedPtr<Process> owner_process,
|
||||||
MemoryPermission permissions,
|
u64 size, MemoryPermission permissions,
|
||||||
MemoryPermission other_permissions, VAddr address = 0,
|
MemoryPermission other_permissions, VAddr address = 0,
|
||||||
MemoryRegion region = MemoryRegion::BASE,
|
MemoryRegion region = MemoryRegion::BASE,
|
||||||
std::string name = "Unknown");
|
std::string name = "Unknown");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a shared memory object from a block of memory managed by an HLE applet.
|
* Creates a shared memory object from a block of memory managed by an HLE applet.
|
||||||
|
* @param kernel The kernel instance to create a shared memory instance under.
|
||||||
* @param heap_block Heap block of the HLE applet.
|
* @param heap_block Heap block of the HLE applet.
|
||||||
* @param offset The offset into the heap block that the SharedMemory will map.
|
* @param offset The offset into the heap block that the SharedMemory will map.
|
||||||
* @param size Size of the memory block. Must be page-aligned.
|
* @param size Size of the memory block. Must be page-aligned.
|
||||||
|
@ -58,7 +62,8 @@ public:
|
||||||
* block.
|
* block.
|
||||||
* @param name Optional object name, used for debugging purposes.
|
* @param name Optional object name, used for debugging purposes.
|
||||||
*/
|
*/
|
||||||
static SharedPtr<SharedMemory> CreateForApplet(std::shared_ptr<std::vector<u8>> heap_block,
|
static SharedPtr<SharedMemory> CreateForApplet(KernelCore& kernel,
|
||||||
|
std::shared_ptr<std::vector<u8>> heap_block,
|
||||||
u32 offset, u32 size,
|
u32 offset, u32 size,
|
||||||
MemoryPermission permissions,
|
MemoryPermission permissions,
|
||||||
MemoryPermission other_permissions,
|
MemoryPermission other_permissions,
|
||||||
|
@ -125,7 +130,7 @@ public:
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SharedMemory();
|
explicit SharedMemory(KernelCore& kernel);
|
||||||
~SharedMemory() override;
|
~SharedMemory() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -87,13 +87,15 @@ static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address
|
||||||
CASCADE_RESULT(client_session, client_port->Connect());
|
CASCADE_RESULT(client_session, client_port->Connect());
|
||||||
|
|
||||||
// Return the client session
|
// Return the client session
|
||||||
CASCADE_RESULT(*out_handle, g_handle_table.Create(client_session));
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
|
CASCADE_RESULT(*out_handle, kernel.HandleTable().Create(client_session));
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Makes a blocking IPC call to an OS service.
|
/// Makes a blocking IPC call to an OS service.
|
||||||
static ResultCode SendSyncRequest(Handle handle) {
|
static ResultCode SendSyncRequest(Handle handle) {
|
||||||
SharedPtr<ClientSession> session = g_handle_table.Get<ClientSession>(handle);
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
|
SharedPtr<ClientSession> session = kernel.HandleTable().Get<ClientSession>(handle);
|
||||||
if (!session) {
|
if (!session) {
|
||||||
LOG_ERROR(Kernel_SVC, "called with invalid handle=0x{:08X}", handle);
|
LOG_ERROR(Kernel_SVC, "called with invalid handle=0x{:08X}", handle);
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
|
@ -112,7 +114,8 @@ static ResultCode SendSyncRequest(Handle handle) {
|
||||||
static ResultCode GetThreadId(u32* thread_id, Handle thread_handle) {
|
static ResultCode GetThreadId(u32* thread_id, Handle thread_handle) {
|
||||||
LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
|
LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
|
||||||
|
|
||||||
const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle);
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
|
const SharedPtr<Thread> thread = kernel.HandleTable().Get<Thread>(thread_handle);
|
||||||
if (!thread) {
|
if (!thread) {
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
}
|
}
|
||||||
|
@ -125,7 +128,8 @@ static ResultCode GetThreadId(u32* thread_id, Handle thread_handle) {
|
||||||
static ResultCode GetProcessId(u32* process_id, Handle process_handle) {
|
static ResultCode GetProcessId(u32* process_id, Handle process_handle) {
|
||||||
LOG_TRACE(Kernel_SVC, "called process=0x{:08X}", process_handle);
|
LOG_TRACE(Kernel_SVC, "called process=0x{:08X}", process_handle);
|
||||||
|
|
||||||
const SharedPtr<Process> process = g_handle_table.Get<Process>(process_handle);
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
|
const SharedPtr<Process> process = kernel.HandleTable().Get<Process>(process_handle);
|
||||||
if (!process) {
|
if (!process) {
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
}
|
}
|
||||||
|
@ -168,10 +172,11 @@ static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64
|
||||||
|
|
||||||
using ObjectPtr = SharedPtr<WaitObject>;
|
using ObjectPtr = SharedPtr<WaitObject>;
|
||||||
std::vector<ObjectPtr> objects(handle_count);
|
std::vector<ObjectPtr> objects(handle_count);
|
||||||
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
|
|
||||||
for (u64 i = 0; i < handle_count; ++i) {
|
for (u64 i = 0; i < handle_count; ++i) {
|
||||||
const Handle handle = Memory::Read32(handles_address + i * sizeof(Handle));
|
const Handle handle = Memory::Read32(handles_address + i * sizeof(Handle));
|
||||||
const auto object = g_handle_table.Get<WaitObject>(handle);
|
const auto object = kernel.HandleTable().Get<WaitObject>(handle);
|
||||||
|
|
||||||
if (object == nullptr) {
|
if (object == nullptr) {
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
|
@ -219,7 +224,8 @@ static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64
|
||||||
static ResultCode CancelSynchronization(Handle thread_handle) {
|
static ResultCode CancelSynchronization(Handle thread_handle) {
|
||||||
LOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle);
|
LOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle);
|
||||||
|
|
||||||
const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle);
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
|
const SharedPtr<Thread> thread = kernel.HandleTable().Get<Thread>(thread_handle);
|
||||||
if (!thread) {
|
if (!thread) {
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
}
|
}
|
||||||
|
@ -239,7 +245,9 @@ static ResultCode ArbitrateLock(Handle holding_thread_handle, VAddr mutex_addr,
|
||||||
"requesting_current_thread_handle=0x{:08X}",
|
"requesting_current_thread_handle=0x{:08X}",
|
||||||
holding_thread_handle, mutex_addr, requesting_thread_handle);
|
holding_thread_handle, mutex_addr, requesting_thread_handle);
|
||||||
|
|
||||||
return Mutex::TryAcquire(mutex_addr, holding_thread_handle, requesting_thread_handle);
|
auto& handle_table = Core::System::GetInstance().Kernel().HandleTable();
|
||||||
|
return Mutex::TryAcquire(handle_table, mutex_addr, holding_thread_handle,
|
||||||
|
requesting_thread_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unlock a mutex
|
/// Unlock a mutex
|
||||||
|
@ -352,7 +360,8 @@ static ResultCode GetThreadContext(Handle handle, VAddr addr) {
|
||||||
|
|
||||||
/// Gets the priority for the specified thread
|
/// Gets the priority for the specified thread
|
||||||
static ResultCode GetThreadPriority(u32* priority, Handle handle) {
|
static ResultCode GetThreadPriority(u32* priority, Handle handle) {
|
||||||
const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(handle);
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
|
const SharedPtr<Thread> thread = kernel.HandleTable().Get<Thread>(handle);
|
||||||
if (!thread)
|
if (!thread)
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
|
|
||||||
|
@ -366,7 +375,8 @@ static ResultCode SetThreadPriority(Handle handle, u32 priority) {
|
||||||
return ERR_OUT_OF_RANGE;
|
return ERR_OUT_OF_RANGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedPtr<Thread> thread = g_handle_table.Get<Thread>(handle);
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
|
SharedPtr<Thread> thread = kernel.HandleTable().Get<Thread>(handle);
|
||||||
if (!thread)
|
if (!thread)
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
|
|
||||||
|
@ -395,7 +405,8 @@ static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 s
|
||||||
"called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}",
|
"called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}",
|
||||||
shared_memory_handle, addr, size, permissions);
|
shared_memory_handle, addr, size, permissions);
|
||||||
|
|
||||||
SharedPtr<SharedMemory> shared_memory = g_handle_table.Get<SharedMemory>(shared_memory_handle);
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
|
auto shared_memory = kernel.HandleTable().Get<SharedMemory>(shared_memory_handle);
|
||||||
if (!shared_memory) {
|
if (!shared_memory) {
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
}
|
}
|
||||||
|
@ -423,7 +434,8 @@ static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64
|
||||||
LOG_WARNING(Kernel_SVC, "called, shared_memory_handle=0x{:08X}, addr=0x{:X}, size=0x{:X}",
|
LOG_WARNING(Kernel_SVC, "called, shared_memory_handle=0x{:08X}, addr=0x{:X}, size=0x{:X}",
|
||||||
shared_memory_handle, addr, size);
|
shared_memory_handle, addr, size);
|
||||||
|
|
||||||
SharedPtr<SharedMemory> shared_memory = g_handle_table.Get<SharedMemory>(shared_memory_handle);
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
|
auto shared_memory = kernel.HandleTable().Get<SharedMemory>(shared_memory_handle);
|
||||||
|
|
||||||
return shared_memory->Unmap(Core::CurrentProcess().get(), addr);
|
return shared_memory->Unmap(Core::CurrentProcess().get(), addr);
|
||||||
}
|
}
|
||||||
|
@ -431,7 +443,9 @@ static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64
|
||||||
/// Query process memory
|
/// Query process memory
|
||||||
static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_info*/,
|
static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_info*/,
|
||||||
Handle process_handle, u64 addr) {
|
Handle process_handle, u64 addr) {
|
||||||
SharedPtr<Process> process = g_handle_table.Get<Process>(process_handle);
|
|
||||||
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
|
SharedPtr<Process> process = kernel.HandleTable().Get<Process>(process_handle);
|
||||||
if (!process) {
|
if (!process) {
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
}
|
}
|
||||||
|
@ -528,10 +542,11 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
CASCADE_RESULT(SharedPtr<Thread> thread,
|
CASCADE_RESULT(SharedPtr<Thread> thread,
|
||||||
Thread::Create(name, entry_point, priority, arg, processor_id, stack_top,
|
Thread::Create(kernel, name, entry_point, priority, arg, processor_id, stack_top,
|
||||||
Core::CurrentProcess()));
|
Core::CurrentProcess()));
|
||||||
CASCADE_RESULT(thread->guest_handle, g_handle_table.Create(thread));
|
CASCADE_RESULT(thread->guest_handle, kernel.HandleTable().Create(thread));
|
||||||
*out_handle = thread->guest_handle;
|
*out_handle = thread->guest_handle;
|
||||||
|
|
||||||
Core::System::GetInstance().CpuCore(thread->processor_id).PrepareReschedule();
|
Core::System::GetInstance().CpuCore(thread->processor_id).PrepareReschedule();
|
||||||
|
@ -548,7 +563,8 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V
|
||||||
static ResultCode StartThread(Handle thread_handle) {
|
static ResultCode StartThread(Handle thread_handle) {
|
||||||
LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
|
LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
|
||||||
|
|
||||||
const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle);
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
|
const SharedPtr<Thread> thread = kernel.HandleTable().Get<Thread>(thread_handle);
|
||||||
if (!thread) {
|
if (!thread) {
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
}
|
}
|
||||||
|
@ -595,7 +611,8 @@ static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr condition_var
|
||||||
"called mutex_addr={:X}, condition_variable_addr={:X}, thread_handle=0x{:08X}, timeout={}",
|
"called mutex_addr={:X}, condition_variable_addr={:X}, thread_handle=0x{:08X}, timeout={}",
|
||||||
mutex_addr, condition_variable_addr, thread_handle, nano_seconds);
|
mutex_addr, condition_variable_addr, thread_handle, nano_seconds);
|
||||||
|
|
||||||
SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle);
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
|
SharedPtr<Thread> thread = kernel.HandleTable().Get<Thread>(thread_handle);
|
||||||
ASSERT(thread);
|
ASSERT(thread);
|
||||||
|
|
||||||
CASCADE_CODE(Mutex::Release(mutex_addr));
|
CASCADE_CODE(Mutex::Release(mutex_addr));
|
||||||
|
@ -704,8 +721,9 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target
|
||||||
mutex_val | Mutex::MutexHasWaitersFlag));
|
mutex_val | Mutex::MutexHasWaitersFlag));
|
||||||
|
|
||||||
// The mutex is already owned by some other thread, make this thread wait on it.
|
// The mutex is already owned by some other thread, make this thread wait on it.
|
||||||
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask);
|
Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask);
|
||||||
auto owner = g_handle_table.Get<Thread>(owner_handle);
|
auto owner = kernel.HandleTable().Get<Thread>(owner_handle);
|
||||||
ASSERT(owner);
|
ASSERT(owner);
|
||||||
ASSERT(thread->status == ThreadStatus::WaitMutex);
|
ASSERT(thread->status == ThreadStatus::WaitMutex);
|
||||||
thread->wakeup_callback = nullptr;
|
thread->wakeup_callback = nullptr;
|
||||||
|
@ -783,14 +801,20 @@ static u64 GetSystemTick() {
|
||||||
/// Close a handle
|
/// Close a handle
|
||||||
static ResultCode CloseHandle(Handle handle) {
|
static ResultCode CloseHandle(Handle handle) {
|
||||||
LOG_TRACE(Kernel_SVC, "Closing handle 0x{:08X}", handle);
|
LOG_TRACE(Kernel_SVC, "Closing handle 0x{:08X}", handle);
|
||||||
return g_handle_table.Close(handle);
|
|
||||||
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
|
return kernel.HandleTable().Close(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reset an event
|
/// Reset an event
|
||||||
static ResultCode ResetSignal(Handle handle) {
|
static ResultCode ResetSignal(Handle handle) {
|
||||||
LOG_WARNING(Kernel_SVC, "(STUBBED) called handle 0x{:08X}", handle);
|
LOG_WARNING(Kernel_SVC, "(STUBBED) called handle 0x{:08X}", handle);
|
||||||
auto event = g_handle_table.Get<Event>(handle);
|
|
||||||
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
|
auto event = kernel.HandleTable().Get<Event>(handle);
|
||||||
|
|
||||||
ASSERT(event != nullptr);
|
ASSERT(event != nullptr);
|
||||||
|
|
||||||
event->Clear();
|
event->Clear();
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -806,7 +830,8 @@ static ResultCode CreateTransferMemory(Handle* handle, VAddr addr, u64 size, u32
|
||||||
static ResultCode GetThreadCoreMask(Handle thread_handle, u32* core, u64* mask) {
|
static ResultCode GetThreadCoreMask(Handle thread_handle, u32* core, u64* mask) {
|
||||||
LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle);
|
LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle);
|
||||||
|
|
||||||
const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle);
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
|
const SharedPtr<Thread> thread = kernel.HandleTable().Get<Thread>(thread_handle);
|
||||||
if (!thread) {
|
if (!thread) {
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
}
|
}
|
||||||
|
@ -821,7 +846,8 @@ static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) {
|
||||||
LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, mask=0x{:16X}, core=0x{:X}", thread_handle,
|
LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, mask=0x{:16X}, core=0x{:X}", thread_handle,
|
||||||
mask, core);
|
mask, core);
|
||||||
|
|
||||||
const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle);
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
|
const SharedPtr<Thread> thread = kernel.HandleTable().Get<Thread>(thread_handle);
|
||||||
if (!thread) {
|
if (!thread) {
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
}
|
}
|
||||||
|
@ -861,19 +887,23 @@ static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permiss
|
||||||
u32 remote_permissions) {
|
u32 remote_permissions) {
|
||||||
LOG_TRACE(Kernel_SVC, "called, size=0x{:X}, localPerms=0x{:08X}, remotePerms=0x{:08X}", size,
|
LOG_TRACE(Kernel_SVC, "called, size=0x{:X}, localPerms=0x{:08X}, remotePerms=0x{:08X}", size,
|
||||||
local_permissions, remote_permissions);
|
local_permissions, remote_permissions);
|
||||||
auto sharedMemHandle =
|
|
||||||
SharedMemory::Create(g_handle_table.Get<Process>(KernelHandle::CurrentProcess), size,
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
|
auto& handle_table = kernel.HandleTable();
|
||||||
|
auto shared_mem_handle =
|
||||||
|
SharedMemory::Create(kernel, handle_table.Get<Process>(KernelHandle::CurrentProcess), size,
|
||||||
static_cast<MemoryPermission>(local_permissions),
|
static_cast<MemoryPermission>(local_permissions),
|
||||||
static_cast<MemoryPermission>(remote_permissions));
|
static_cast<MemoryPermission>(remote_permissions));
|
||||||
|
|
||||||
CASCADE_RESULT(*handle, g_handle_table.Create(sharedMemHandle));
|
CASCADE_RESULT(*handle, handle_table.Create(shared_mem_handle));
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ResultCode ClearEvent(Handle handle) {
|
static ResultCode ClearEvent(Handle handle) {
|
||||||
LOG_TRACE(Kernel_SVC, "called, event=0x{:08X}", handle);
|
LOG_TRACE(Kernel_SVC, "called, event=0x{:08X}", handle);
|
||||||
|
|
||||||
SharedPtr<Event> evt = g_handle_table.Get<Event>(handle);
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
|
SharedPtr<Event> evt = kernel.HandleTable().Get<Event>(handle);
|
||||||
if (evt == nullptr)
|
if (evt == nullptr)
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
evt->Clear();
|
evt->Clear();
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "core/core_timing_util.h"
|
#include "core/core_timing_util.h"
|
||||||
#include "core/hle/kernel/errors.h"
|
#include "core/hle/kernel/errors.h"
|
||||||
#include "core/hle/kernel/handle_table.h"
|
#include "core/hle/kernel/handle_table.h"
|
||||||
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/kernel/object.h"
|
#include "core/hle/kernel/object.h"
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/hle/kernel/thread.h"
|
#include "core/hle/kernel/thread.h"
|
||||||
|
@ -29,9 +30,6 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
/// Event type for the thread wake up event
|
|
||||||
static CoreTiming::EventType* ThreadWakeupEventType = nullptr;
|
|
||||||
|
|
||||||
bool Thread::ShouldWait(Thread* thread) const {
|
bool Thread::ShouldWait(Thread* thread) const {
|
||||||
return status != ThreadStatus::Dead;
|
return status != ThreadStatus::Dead;
|
||||||
}
|
}
|
||||||
|
@ -40,32 +38,17 @@ void Thread::Acquire(Thread* thread) {
|
||||||
ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
|
ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future, allowing
|
Thread::Thread(KernelCore& kernel) : WaitObject{kernel} {}
|
||||||
// us to simply use a pool index or similar.
|
Thread::~Thread() = default;
|
||||||
static Kernel::HandleTable wakeup_callback_handle_table;
|
|
||||||
|
|
||||||
// The first available thread id at startup
|
|
||||||
static u32 next_thread_id;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new thread ID
|
|
||||||
* @return The new thread ID
|
|
||||||
*/
|
|
||||||
inline static u32 const NewThreadId() {
|
|
||||||
return next_thread_id++;
|
|
||||||
}
|
|
||||||
|
|
||||||
Thread::Thread() {}
|
|
||||||
Thread::~Thread() {}
|
|
||||||
|
|
||||||
void Thread::Stop() {
|
void Thread::Stop() {
|
||||||
// Cancel any outstanding wakeup events for this thread
|
// Cancel any outstanding wakeup events for this thread
|
||||||
CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle);
|
CoreTiming::UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), callback_handle);
|
||||||
wakeup_callback_handle_table.Close(callback_handle);
|
kernel.ThreadWakeupCallbackHandleTable().Close(callback_handle);
|
||||||
callback_handle = 0;
|
callback_handle = 0;
|
||||||
|
|
||||||
// Clean up thread from ready queue
|
// Clean up thread from ready queue
|
||||||
// This is only needed when the thread is termintated forcefully (SVC TerminateProcess)
|
// This is only needed when the thread is terminated forcefully (SVC TerminateProcess)
|
||||||
if (status == ThreadStatus::Ready) {
|
if (status == ThreadStatus::Ready) {
|
||||||
scheduler->UnscheduleThread(this, current_priority);
|
scheduler->UnscheduleThread(this, current_priority);
|
||||||
}
|
}
|
||||||
|
@ -98,63 +81,6 @@ void ExitCurrentThread() {
|
||||||
Core::System::GetInstance().CurrentScheduler().RemoveThread(thread);
|
Core::System::GetInstance().CurrentScheduler().RemoveThread(thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback that will wake up the thread it was scheduled for
|
|
||||||
* @param thread_handle The handle of the thread that's been awoken
|
|
||||||
* @param cycles_late The number of CPU cycles that have passed since the desired wakeup time
|
|
||||||
*/
|
|
||||||
static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) {
|
|
||||||
const auto proper_handle = static_cast<Handle>(thread_handle);
|
|
||||||
|
|
||||||
// Lock the global kernel mutex when we enter the kernel HLE.
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
|
|
||||||
|
|
||||||
SharedPtr<Thread> thread = wakeup_callback_handle_table.Get<Thread>(proper_handle);
|
|
||||||
if (thread == nullptr) {
|
|
||||||
LOG_CRITICAL(Kernel, "Callback fired for invalid thread {:08X}", proper_handle);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool resume = true;
|
|
||||||
|
|
||||||
if (thread->status == ThreadStatus::WaitSynchAny ||
|
|
||||||
thread->status == ThreadStatus::WaitSynchAll ||
|
|
||||||
thread->status == ThreadStatus::WaitHLEEvent) {
|
|
||||||
// Remove the thread from each of its waiting objects' waitlists
|
|
||||||
for (auto& object : thread->wait_objects)
|
|
||||||
object->RemoveWaitingThread(thread.get());
|
|
||||||
thread->wait_objects.clear();
|
|
||||||
|
|
||||||
// Invoke the wakeup callback before clearing the wait objects
|
|
||||||
if (thread->wakeup_callback)
|
|
||||||
resume = thread->wakeup_callback(ThreadWakeupReason::Timeout, thread, nullptr, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (thread->mutex_wait_address != 0 || thread->condvar_wait_address != 0 ||
|
|
||||||
thread->wait_handle) {
|
|
||||||
ASSERT(thread->status == ThreadStatus::WaitMutex);
|
|
||||||
thread->mutex_wait_address = 0;
|
|
||||||
thread->condvar_wait_address = 0;
|
|
||||||
thread->wait_handle = 0;
|
|
||||||
|
|
||||||
auto lock_owner = thread->lock_owner;
|
|
||||||
// Threads waking up by timeout from WaitProcessWideKey do not perform priority inheritance
|
|
||||||
// and don't have a lock owner unless SignalProcessWideKey was called first and the thread
|
|
||||||
// wasn't awakened due to the mutex already being acquired.
|
|
||||||
if (lock_owner) {
|
|
||||||
lock_owner->RemoveMutexWaiter(thread);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (thread->arb_wait_address != 0) {
|
|
||||||
ASSERT(thread->status == ThreadStatus::WaitArb);
|
|
||||||
thread->arb_wait_address = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (resume)
|
|
||||||
thread->ResumeFromWait();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Thread::WakeAfterDelay(s64 nanoseconds) {
|
void Thread::WakeAfterDelay(s64 nanoseconds) {
|
||||||
// Don't schedule a wakeup if the thread wants to wait forever
|
// Don't schedule a wakeup if the thread wants to wait forever
|
||||||
if (nanoseconds == -1)
|
if (nanoseconds == -1)
|
||||||
|
@ -162,12 +88,12 @@ void Thread::WakeAfterDelay(s64 nanoseconds) {
|
||||||
|
|
||||||
// This function might be called from any thread so we have to be cautious and use the
|
// This function might be called from any thread so we have to be cautious and use the
|
||||||
// thread-safe version of ScheduleEvent.
|
// thread-safe version of ScheduleEvent.
|
||||||
CoreTiming::ScheduleEventThreadsafe(CoreTiming::nsToCycles(nanoseconds), ThreadWakeupEventType,
|
CoreTiming::ScheduleEventThreadsafe(CoreTiming::nsToCycles(nanoseconds),
|
||||||
callback_handle);
|
kernel.ThreadWakeupCallbackEventType(), callback_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread::CancelWakeupTimer() {
|
void Thread::CancelWakeupTimer() {
|
||||||
CoreTiming::UnscheduleEventThreadsafe(ThreadWakeupEventType, callback_handle);
|
CoreTiming::UnscheduleEventThreadsafe(kernel.ThreadWakeupCallbackEventType(), callback_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
static boost::optional<s32> GetNextProcessorId(u64 mask) {
|
static boost::optional<s32> GetNextProcessorId(u64 mask) {
|
||||||
|
@ -294,9 +220,9 @@ static void ResetThreadContext(Core::ARM_Interface::ThreadContext& context, VAdd
|
||||||
context.fpscr = 0;
|
context.fpscr = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, u32 priority,
|
ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name, VAddr entry_point,
|
||||||
u64 arg, s32 processor_id, VAddr stack_top,
|
u32 priority, u64 arg, s32 processor_id,
|
||||||
SharedPtr<Process> owner_process) {
|
VAddr stack_top, SharedPtr<Process> owner_process) {
|
||||||
// Check if priority is in ranged. Lowest priority -> highest priority id.
|
// Check if priority is in ranged. Lowest priority -> highest priority id.
|
||||||
if (priority > THREADPRIO_LOWEST) {
|
if (priority > THREADPRIO_LOWEST) {
|
||||||
LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority);
|
LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority);
|
||||||
|
@ -316,9 +242,9 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
|
||||||
return ResultCode(-1);
|
return ResultCode(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedPtr<Thread> thread(new Thread);
|
SharedPtr<Thread> thread(new Thread(kernel));
|
||||||
|
|
||||||
thread->thread_id = NewThreadId();
|
thread->thread_id = kernel.CreateNewThreadID();
|
||||||
thread->status = ThreadStatus::Dormant;
|
thread->status = ThreadStatus::Dormant;
|
||||||
thread->entry_point = entry_point;
|
thread->entry_point = entry_point;
|
||||||
thread->stack_top = stack_top;
|
thread->stack_top = stack_top;
|
||||||
|
@ -333,7 +259,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
|
||||||
thread->condvar_wait_address = 0;
|
thread->condvar_wait_address = 0;
|
||||||
thread->wait_handle = 0;
|
thread->wait_handle = 0;
|
||||||
thread->name = std::move(name);
|
thread->name = std::move(name);
|
||||||
thread->callback_handle = wakeup_callback_handle_table.Create(thread).Unwrap();
|
thread->callback_handle = kernel.ThreadWakeupCallbackHandleTable().Create(thread).Unwrap();
|
||||||
thread->owner_process = owner_process;
|
thread->owner_process = owner_process;
|
||||||
thread->scheduler = Core::System::GetInstance().Scheduler(processor_id);
|
thread->scheduler = Core::System::GetInstance().Scheduler(processor_id);
|
||||||
thread->scheduler->AddThread(thread, priority);
|
thread->scheduler->AddThread(thread, priority);
|
||||||
|
@ -383,19 +309,19 @@ void Thread::BoostPriority(u32 priority) {
|
||||||
current_priority = priority;
|
current_priority = priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedPtr<Thread> SetupMainThread(VAddr entry_point, u32 priority,
|
SharedPtr<Thread> SetupMainThread(KernelCore& kernel, VAddr entry_point, u32 priority,
|
||||||
SharedPtr<Process> owner_process) {
|
SharedPtr<Process> owner_process) {
|
||||||
// Setup page table so we can write to memory
|
// Setup page table so we can write to memory
|
||||||
SetCurrentPageTable(&Core::CurrentProcess()->vm_manager.page_table);
|
SetCurrentPageTable(&Core::CurrentProcess()->vm_manager.page_table);
|
||||||
|
|
||||||
// Initialize new "main" thread
|
// Initialize new "main" thread
|
||||||
auto thread_res = Thread::Create("main", entry_point, priority, 0, THREADPROCESSORID_0,
|
auto thread_res = Thread::Create(kernel, "main", entry_point, priority, 0, THREADPROCESSORID_0,
|
||||||
Memory::STACK_AREA_VADDR_END, std::move(owner_process));
|
Memory::STACK_AREA_VADDR_END, std::move(owner_process));
|
||||||
|
|
||||||
SharedPtr<Thread> thread = std::move(thread_res).Unwrap();
|
SharedPtr<Thread> thread = std::move(thread_res).Unwrap();
|
||||||
|
|
||||||
// Register 1 must be a handle to the main thread
|
// Register 1 must be a handle to the main thread
|
||||||
thread->guest_handle = Kernel::g_handle_table.Create(thread).Unwrap();
|
thread->guest_handle = kernel.HandleTable().Create(thread).Unwrap();
|
||||||
|
|
||||||
thread->context.cpu_registers[1] = thread->guest_handle;
|
thread->context.cpu_registers[1] = thread->guest_handle;
|
||||||
|
|
||||||
|
@ -528,13 +454,4 @@ Thread* GetCurrentThread() {
|
||||||
return Core::System::GetInstance().CurrentScheduler().GetCurrentThread();
|
return Core::System::GetInstance().CurrentScheduler().GetCurrentThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThreadingInit() {
|
|
||||||
ThreadWakeupEventType = CoreTiming::RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback);
|
|
||||||
next_thread_id = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ThreadingShutdown() {
|
|
||||||
Kernel::ClearProcessList();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -56,6 +56,7 @@ enum class ThreadWakeupReason {
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
|
class KernelCore;
|
||||||
class Process;
|
class Process;
|
||||||
class Scheduler;
|
class Scheduler;
|
||||||
|
|
||||||
|
@ -63,6 +64,7 @@ class Thread final : public WaitObject {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Creates and returns a new thread. The new thread is immediately scheduled
|
* Creates and returns a new thread. The new thread is immediately scheduled
|
||||||
|
* @param kernel The kernel instance this thread will be created under.
|
||||||
* @param name The friendly name desired for the thread
|
* @param name The friendly name desired for the thread
|
||||||
* @param entry_point The address at which the thread should start execution
|
* @param entry_point The address at which the thread should start execution
|
||||||
* @param priority The thread's priority
|
* @param priority The thread's priority
|
||||||
|
@ -72,8 +74,9 @@ public:
|
||||||
* @param owner_process The parent process for the thread
|
* @param owner_process The parent process for the thread
|
||||||
* @return A shared pointer to the newly created thread
|
* @return A shared pointer to the newly created thread
|
||||||
*/
|
*/
|
||||||
static ResultVal<SharedPtr<Thread>> Create(std::string name, VAddr entry_point, u32 priority,
|
static ResultVal<SharedPtr<Thread>> Create(KernelCore& kernel, std::string name,
|
||||||
u64 arg, s32 processor_id, VAddr stack_top,
|
VAddr entry_point, u32 priority, u64 arg,
|
||||||
|
s32 processor_id, VAddr stack_top,
|
||||||
SharedPtr<Process> owner_process);
|
SharedPtr<Process> owner_process);
|
||||||
|
|
||||||
std::string GetName() const override {
|
std::string GetName() const override {
|
||||||
|
@ -263,7 +266,7 @@ public:
|
||||||
u64 affinity_mask{0x1};
|
u64 affinity_mask{0x1};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Thread();
|
explicit Thread(KernelCore& kernel);
|
||||||
~Thread() override;
|
~Thread() override;
|
||||||
|
|
||||||
std::shared_ptr<std::vector<u8>> tls_memory = std::make_shared<std::vector<u8>>();
|
std::shared_ptr<std::vector<u8>> tls_memory = std::make_shared<std::vector<u8>>();
|
||||||
|
@ -271,12 +274,13 @@ private:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets up the primary application thread
|
* Sets up the primary application thread
|
||||||
|
* @param kernel The kernel instance to create the main thread under.
|
||||||
* @param entry_point The address at which the thread should start execution
|
* @param entry_point The address at which the thread should start execution
|
||||||
* @param priority The priority to give the main thread
|
* @param priority The priority to give the main thread
|
||||||
* @param owner_process The parent process for the main thread
|
* @param owner_process The parent process for the main thread
|
||||||
* @return A shared pointer to the main thread
|
* @return A shared pointer to the main thread
|
||||||
*/
|
*/
|
||||||
SharedPtr<Thread> SetupMainThread(VAddr entry_point, u32 priority,
|
SharedPtr<Thread> SetupMainThread(KernelCore& kernel, VAddr entry_point, u32 priority,
|
||||||
SharedPtr<Process> owner_process);
|
SharedPtr<Process> owner_process);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -294,14 +298,4 @@ void WaitCurrentThread_Sleep();
|
||||||
*/
|
*/
|
||||||
void ExitCurrentThread();
|
void ExitCurrentThread();
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize threading
|
|
||||||
*/
|
|
||||||
void ThreadingInit();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shutdown threading
|
|
||||||
*/
|
|
||||||
void ThreadingShutdown();
|
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -2,36 +2,31 @@
|
||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include <cinttypes>
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
#include "core/core.h"
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "core/core_timing_util.h"
|
#include "core/core_timing_util.h"
|
||||||
#include "core/hle/kernel/handle_table.h"
|
#include "core/hle/kernel/handle_table.h"
|
||||||
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/kernel/object.h"
|
#include "core/hle/kernel/object.h"
|
||||||
#include "core/hle/kernel/thread.h"
|
#include "core/hle/kernel/thread.h"
|
||||||
#include "core/hle/kernel/timer.h"
|
#include "core/hle/kernel/timer.h"
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
/// The event type of the generic timer callback event
|
Timer::Timer(KernelCore& kernel) : WaitObject{kernel} {}
|
||||||
static CoreTiming::EventType* timer_callback_event_type = nullptr;
|
Timer::~Timer() = default;
|
||||||
// TODO(yuriks): This can be removed if Timer objects are explicitly pooled in the future, allowing
|
|
||||||
// us to simply use a pool index or similar.
|
|
||||||
static Kernel::HandleTable timer_callback_handle_table;
|
|
||||||
|
|
||||||
Timer::Timer() {}
|
SharedPtr<Timer> Timer::Create(KernelCore& kernel, ResetType reset_type, std::string name) {
|
||||||
Timer::~Timer() {}
|
SharedPtr<Timer> timer(new Timer(kernel));
|
||||||
|
|
||||||
SharedPtr<Timer> Timer::Create(ResetType reset_type, std::string name) {
|
|
||||||
SharedPtr<Timer> timer(new Timer);
|
|
||||||
|
|
||||||
timer->reset_type = reset_type;
|
timer->reset_type = reset_type;
|
||||||
timer->signaled = false;
|
timer->signaled = false;
|
||||||
timer->name = std::move(name);
|
timer->name = std::move(name);
|
||||||
timer->initial_delay = 0;
|
timer->initial_delay = 0;
|
||||||
timer->interval_delay = 0;
|
timer->interval_delay = 0;
|
||||||
timer->callback_handle = timer_callback_handle_table.Create(timer).Unwrap();
|
timer->callback_handle = kernel.CreateTimerCallbackHandle(timer).Unwrap();
|
||||||
|
|
||||||
return timer;
|
return timer;
|
||||||
}
|
}
|
||||||
|
@ -58,13 +53,13 @@ void Timer::Set(s64 initial, s64 interval) {
|
||||||
// Immediately invoke the callback
|
// Immediately invoke the callback
|
||||||
Signal(0);
|
Signal(0);
|
||||||
} else {
|
} else {
|
||||||
CoreTiming::ScheduleEvent(CoreTiming::nsToCycles(initial), timer_callback_event_type,
|
CoreTiming::ScheduleEvent(CoreTiming::nsToCycles(initial), kernel.TimerCallbackEventType(),
|
||||||
callback_handle);
|
callback_handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Timer::Cancel() {
|
void Timer::Cancel() {
|
||||||
CoreTiming::UnscheduleEvent(timer_callback_event_type, callback_handle);
|
CoreTiming::UnscheduleEvent(kernel.TimerCallbackEventType(), callback_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Timer::Clear() {
|
void Timer::Clear() {
|
||||||
|
@ -89,28 +84,8 @@ void Timer::Signal(int cycles_late) {
|
||||||
if (interval_delay != 0) {
|
if (interval_delay != 0) {
|
||||||
// Reschedule the timer with the interval delay
|
// Reschedule the timer with the interval delay
|
||||||
CoreTiming::ScheduleEvent(CoreTiming::nsToCycles(interval_delay) - cycles_late,
|
CoreTiming::ScheduleEvent(CoreTiming::nsToCycles(interval_delay) - cycles_late,
|
||||||
timer_callback_event_type, callback_handle);
|
kernel.TimerCallbackEventType(), callback_handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The timer callback event, called when a timer is fired
|
|
||||||
static void TimerCallback(u64 timer_handle, int cycles_late) {
|
|
||||||
SharedPtr<Timer> timer =
|
|
||||||
timer_callback_handle_table.Get<Timer>(static_cast<Handle>(timer_handle));
|
|
||||||
|
|
||||||
if (timer == nullptr) {
|
|
||||||
LOG_CRITICAL(Kernel, "Callback fired for invalid timer {:016X}", timer_handle);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
timer->Signal(cycles_late);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TimersInit() {
|
|
||||||
timer_callback_handle_table.Clear();
|
|
||||||
timer_callback_event_type = CoreTiming::RegisterEvent("TimerCallback", TimerCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TimersShutdown() {}
|
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -10,15 +10,19 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
|
class KernelCore;
|
||||||
|
|
||||||
class Timer final : public WaitObject {
|
class Timer final : public WaitObject {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Creates a timer
|
* Creates a timer
|
||||||
|
* @param kernel The kernel instance to create the timer callback handle for.
|
||||||
* @param reset_type ResetType describing how to create the timer
|
* @param reset_type ResetType describing how to create the timer
|
||||||
* @param name Optional name of timer
|
* @param name Optional name of timer
|
||||||
* @return The created Timer
|
* @return The created Timer
|
||||||
*/
|
*/
|
||||||
static SharedPtr<Timer> Create(ResetType reset_type, std::string name = "Unknown");
|
static SharedPtr<Timer> Create(KernelCore& kernel, ResetType reset_type,
|
||||||
|
std::string name = "Unknown");
|
||||||
|
|
||||||
std::string GetTypeName() const override {
|
std::string GetTypeName() const override {
|
||||||
return "Timer";
|
return "Timer";
|
||||||
|
@ -68,7 +72,7 @@ public:
|
||||||
void Signal(int cycles_late);
|
void Signal(int cycles_late);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Timer();
|
explicit Timer(KernelCore& kernel);
|
||||||
~Timer() override;
|
~Timer() override;
|
||||||
|
|
||||||
ResetType reset_type; ///< The ResetType of this timer
|
ResetType reset_type; ///< The ResetType of this timer
|
||||||
|
@ -83,9 +87,4 @@ private:
|
||||||
Handle callback_handle;
|
Handle callback_handle;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Initializes the required variables for timers
|
|
||||||
void TimersInit();
|
|
||||||
/// Tears down the timer variables
|
|
||||||
void TimersShutdown();
|
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -12,6 +12,9 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
|
WaitObject::WaitObject(KernelCore& kernel) : Object{kernel} {}
|
||||||
|
WaitObject::~WaitObject() = default;
|
||||||
|
|
||||||
void WaitObject::AddWaitingThread(SharedPtr<Thread> thread) {
|
void WaitObject::AddWaitingThread(SharedPtr<Thread> thread) {
|
||||||
auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
|
auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
|
||||||
if (itr == waiting_threads.end())
|
if (itr == waiting_threads.end())
|
||||||
|
|
|
@ -11,11 +11,15 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
|
class KernelCore;
|
||||||
class Thread;
|
class Thread;
|
||||||
|
|
||||||
/// Class that represents a Kernel object that a thread can be waiting on
|
/// Class that represents a Kernel object that a thread can be waiting on
|
||||||
class WaitObject : public Object {
|
class WaitObject : public Object {
|
||||||
public:
|
public:
|
||||||
|
explicit WaitObject(KernelCore& kernel);
|
||||||
|
~WaitObject() override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the specified thread should wait until the object is available
|
* Check if the specified thread should wait until the object is available
|
||||||
* @param thread The thread about which we're deciding.
|
* @param thread The thread about which we're deciding.
|
||||||
|
|
|
@ -160,8 +160,9 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger
|
||||||
};
|
};
|
||||||
RegisterHandlers(functions);
|
RegisterHandlers(functions);
|
||||||
|
|
||||||
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
launchable_event =
|
launchable_event =
|
||||||
Kernel::Event::Create(Kernel::ResetType::Sticky, "ISelfController:LaunchableEvent");
|
Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "ISelfController:LaunchableEvent");
|
||||||
}
|
}
|
||||||
|
|
||||||
void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) {
|
void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) {
|
||||||
|
@ -332,7 +333,8 @@ ICommonStateGetter::ICommonStateGetter() : ServiceFramework("ICommonStateGetter"
|
||||||
};
|
};
|
||||||
RegisterHandlers(functions);
|
RegisterHandlers(functions);
|
||||||
|
|
||||||
event = Kernel::Event::Create(Kernel::ResetType::OneShot, "ICommonStateGetter:Event");
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
|
event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "ICommonStateGetter:Event");
|
||||||
}
|
}
|
||||||
|
|
||||||
void ICommonStateGetter::GetBootMode(Kernel::HLERequestContext& ctx) {
|
void ICommonStateGetter::GetBootMode(Kernel::HLERequestContext& ctx) {
|
||||||
|
@ -505,7 +507,8 @@ public:
|
||||||
};
|
};
|
||||||
RegisterHandlers(functions);
|
RegisterHandlers(functions);
|
||||||
|
|
||||||
state_changed_event = Kernel::Event::Create(Kernel::ResetType::OneShot,
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
|
state_changed_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
|
||||||
"ILibraryAppletAccessor:StateChangedEvent");
|
"ILibraryAppletAccessor:StateChangedEvent");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,9 @@ public:
|
||||||
RegisterHandlers(functions);
|
RegisterHandlers(functions);
|
||||||
|
|
||||||
// This is the event handle used to check if the audio buffer was released
|
// This is the event handle used to check if the audio buffer was released
|
||||||
buffer_event = Kernel::Event::Create(Kernel::ResetType::Sticky, "IAudioOutBufferReleased");
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
|
buffer_event =
|
||||||
|
Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "IAudioOutBufferReleased");
|
||||||
|
|
||||||
stream = audio_core.OpenStream(audio_params.sample_rate, audio_params.channel_count,
|
stream = audio_core.OpenStream(audio_params.sample_rate, audio_params.channel_count,
|
||||||
"IAudioOut", [=]() { buffer_event->Signal(); });
|
"IAudioOut", [=]() { buffer_event->Signal(); });
|
||||||
|
|
|
@ -35,8 +35,9 @@ public:
|
||||||
};
|
};
|
||||||
RegisterHandlers(functions);
|
RegisterHandlers(functions);
|
||||||
|
|
||||||
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
system_event =
|
system_event =
|
||||||
Kernel::Event::Create(Kernel::ResetType::Sticky, "IAudioRenderer:SystemEvent");
|
Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "IAudioRenderer:SystemEvent");
|
||||||
renderer = std::make_unique<AudioCore::AudioRenderer>(audren_params, system_event);
|
renderer = std::make_unique<AudioCore::AudioRenderer>(audren_params, system_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,8 +122,9 @@ public:
|
||||||
};
|
};
|
||||||
RegisterHandlers(functions);
|
RegisterHandlers(functions);
|
||||||
|
|
||||||
buffer_event =
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
Kernel::Event::Create(Kernel::ResetType::OneShot, "IAudioOutBufferReleasedEvent");
|
buffer_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
|
||||||
|
"IAudioOutBufferReleasedEvent");
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
#include "core/core.h"
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "core/core_timing_util.h"
|
#include "core/core_timing_util.h"
|
||||||
#include "core/frontend/emu_window.h"
|
#include "core/frontend/emu_window.h"
|
||||||
|
@ -35,9 +36,10 @@ public:
|
||||||
};
|
};
|
||||||
RegisterHandlers(functions);
|
RegisterHandlers(functions);
|
||||||
|
|
||||||
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
shared_mem = Kernel::SharedMemory::Create(
|
shared_mem = Kernel::SharedMemory::Create(
|
||||||
nullptr, 0x40000, Kernel::MemoryPermission::ReadWrite, Kernel::MemoryPermission::Read,
|
kernel, nullptr, 0x40000, Kernel::MemoryPermission::ReadWrite,
|
||||||
0, Kernel::MemoryRegion::BASE, "HID:SharedMemory");
|
Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "HID:SharedMemory");
|
||||||
|
|
||||||
// Register update callbacks
|
// Register update callbacks
|
||||||
pad_update_event = CoreTiming::RegisterEvent(
|
pad_update_event = CoreTiming::RegisterEvent(
|
||||||
|
@ -402,7 +404,8 @@ public:
|
||||||
|
|
||||||
RegisterHandlers(functions);
|
RegisterHandlers(functions);
|
||||||
|
|
||||||
event = Kernel::Event::Create(Kernel::ResetType::OneShot, "hid:EventHandle");
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
|
event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "hid:EventHandle");
|
||||||
}
|
}
|
||||||
~Hid() = default;
|
~Hid() = default;
|
||||||
|
|
||||||
|
|
|
@ -46,11 +46,13 @@ public:
|
||||||
};
|
};
|
||||||
RegisterHandlers(functions);
|
RegisterHandlers(functions);
|
||||||
|
|
||||||
activate_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "IUser:ActivateEvent");
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
|
activate_event =
|
||||||
|
Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IUser:ActivateEvent");
|
||||||
deactivate_event =
|
deactivate_event =
|
||||||
Kernel::Event::Create(Kernel::ResetType::OneShot, "IUser:DeactivateEvent");
|
Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IUser:DeactivateEvent");
|
||||||
availability_change_event =
|
availability_change_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
|
||||||
Kernel::Event::Create(Kernel::ResetType::OneShot, "IUser:AvailabilityChangeEvent");
|
"IUser:AvailabilityChangeEvent");
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "core/core.h"
|
||||||
#include "core/hle/ipc_helpers.h"
|
#include "core/hle/ipc_helpers.h"
|
||||||
#include "core/hle/kernel/event.h"
|
#include "core/hle/kernel/event.h"
|
||||||
#include "core/hle/service/nifm/nifm.h"
|
#include "core/hle/service/nifm/nifm.h"
|
||||||
|
@ -54,8 +55,9 @@ public:
|
||||||
};
|
};
|
||||||
RegisterHandlers(functions);
|
RegisterHandlers(functions);
|
||||||
|
|
||||||
event1 = Kernel::Event::Create(Kernel::ResetType::OneShot, "IRequest:Event1");
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
event2 = Kernel::Event::Create(Kernel::ResetType::OneShot, "IRequest:Event2");
|
event1 = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IRequest:Event1");
|
||||||
|
event2 = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IRequest:Event2");
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -266,8 +266,9 @@ void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
|
||||||
SHARED_FONT_MEM_VADDR, shared_font, 0, SHARED_FONT_MEM_SIZE, Kernel::MemoryState::Shared);
|
SHARED_FONT_MEM_VADDR, shared_font, 0, SHARED_FONT_MEM_SIZE, Kernel::MemoryState::Shared);
|
||||||
|
|
||||||
// Create shared font memory object
|
// Create shared font memory object
|
||||||
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
shared_font_mem = Kernel::SharedMemory::Create(
|
shared_font_mem = Kernel::SharedMemory::Create(
|
||||||
Core::CurrentProcess(), SHARED_FONT_MEM_SIZE, Kernel::MemoryPermission::ReadWrite,
|
kernel, Core::CurrentProcess(), SHARED_FONT_MEM_SIZE, Kernel::MemoryPermission::ReadWrite,
|
||||||
Kernel::MemoryPermission::Read, SHARED_FONT_MEM_VADDR, Kernel::MemoryRegion::BASE,
|
Kernel::MemoryPermission::Read, SHARED_FONT_MEM_VADDR, Kernel::MemoryRegion::BASE,
|
||||||
"PL_U:shared_font_mem");
|
"PL_U:shared_font_mem");
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
#include "core/core.h"
|
||||||
#include "core/hle/ipc_helpers.h"
|
#include "core/hle/ipc_helpers.h"
|
||||||
#include "core/hle/kernel/event.h"
|
#include "core/hle/kernel/event.h"
|
||||||
#include "core/hle/service/nvdrv/interface.h"
|
#include "core/hle/service/nvdrv/interface.h"
|
||||||
|
@ -107,7 +108,8 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name)
|
||||||
};
|
};
|
||||||
RegisterHandlers(functions);
|
RegisterHandlers(functions);
|
||||||
|
|
||||||
query_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "NVDRV::query_event");
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
|
query_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "NVDRV::query_event");
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Service::Nvidia
|
} // namespace Service::Nvidia
|
||||||
|
|
|
@ -6,14 +6,16 @@
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
#include "core/core.h"
|
||||||
#include "core/hle/service/nvflinger/buffer_queue.h"
|
#include "core/hle/service/nvflinger/buffer_queue.h"
|
||||||
|
|
||||||
namespace Service {
|
namespace Service {
|
||||||
namespace NVFlinger {
|
namespace NVFlinger {
|
||||||
|
|
||||||
BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) {
|
BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) {
|
||||||
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
buffer_wait_event =
|
buffer_wait_event =
|
||||||
Kernel::Event::Create(Kernel::ResetType::Sticky, "BufferQueue NativeHandle");
|
Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "BufferQueue NativeHandle");
|
||||||
}
|
}
|
||||||
|
|
||||||
void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) {
|
void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) {
|
||||||
|
|
|
@ -161,7 +161,8 @@ void NVFlinger::Compose() {
|
||||||
Layer::Layer(u64 id, std::shared_ptr<BufferQueue> queue) : id(id), buffer_queue(std::move(queue)) {}
|
Layer::Layer(u64 id, std::shared_ptr<BufferQueue> queue) : id(id), buffer_queue(std::move(queue)) {}
|
||||||
|
|
||||||
Display::Display(u64 id, std::string name) : id(id), name(std::move(name)) {
|
Display::Display(u64 id, std::string name) : id(id), name(std::move(name)) {
|
||||||
vsync_event = Kernel::Event::Create(Kernel::ResetType::Pulse, "Display VSync Event");
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
|
vsync_event = Kernel::Event::Create(kernel, Kernel::ResetType::Pulse, "Display VSync Event");
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Service::NVFlinger
|
} // namespace Service::NVFlinger
|
||||||
|
|
|
@ -107,19 +107,24 @@ void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager)
|
||||||
|
|
||||||
void ServiceFrameworkBase::InstallAsNamedPort() {
|
void ServiceFrameworkBase::InstallAsNamedPort() {
|
||||||
ASSERT(port == nullptr);
|
ASSERT(port == nullptr);
|
||||||
|
|
||||||
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
SharedPtr<ServerPort> server_port;
|
SharedPtr<ServerPort> server_port;
|
||||||
SharedPtr<ClientPort> client_port;
|
SharedPtr<ClientPort> client_port;
|
||||||
std::tie(server_port, client_port) = ServerPort::CreatePortPair(max_sessions, service_name);
|
std::tie(server_port, client_port) =
|
||||||
|
ServerPort::CreatePortPair(kernel, max_sessions, service_name);
|
||||||
server_port->SetHleHandler(shared_from_this());
|
server_port->SetHleHandler(shared_from_this());
|
||||||
AddNamedPort(service_name, std::move(client_port));
|
AddNamedPort(service_name, std::move(client_port));
|
||||||
}
|
}
|
||||||
|
|
||||||
Kernel::SharedPtr<Kernel::ClientPort> ServiceFrameworkBase::CreatePort() {
|
Kernel::SharedPtr<Kernel::ClientPort> ServiceFrameworkBase::CreatePort() {
|
||||||
ASSERT(port == nullptr);
|
ASSERT(port == nullptr);
|
||||||
|
|
||||||
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
Kernel::SharedPtr<Kernel::ServerPort> server_port;
|
Kernel::SharedPtr<Kernel::ServerPort> server_port;
|
||||||
Kernel::SharedPtr<Kernel::ClientPort> client_port;
|
Kernel::SharedPtr<Kernel::ClientPort> client_port;
|
||||||
std::tie(server_port, client_port) =
|
std::tie(server_port, client_port) =
|
||||||
Kernel::ServerPort::CreatePortPair(max_sessions, service_name);
|
Kernel::ServerPort::CreatePortPair(kernel, max_sessions, service_name);
|
||||||
port = MakeResult<Kernel::SharedPtr<Kernel::ServerPort>>(std::move(server_port)).Unwrap();
|
port = MakeResult<Kernel::SharedPtr<Kernel::ServerPort>>(std::move(server_port)).Unwrap();
|
||||||
port->SetHleHandler(shared_from_this());
|
port->SetHleHandler(shared_from_this());
|
||||||
return client_port;
|
return client_port;
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
#include "core/core.h"
|
||||||
#include "core/hle/ipc_helpers.h"
|
#include "core/hle/ipc_helpers.h"
|
||||||
#include "core/hle/kernel/client_port.h"
|
#include "core/hle/kernel/client_port.h"
|
||||||
#include "core/hle/kernel/client_session.h"
|
#include "core/hle/kernel/client_session.h"
|
||||||
|
@ -47,9 +48,11 @@ ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> ServiceManager::RegisterService
|
||||||
if (registered_services.find(name) != registered_services.end())
|
if (registered_services.find(name) != registered_services.end())
|
||||||
return ERR_ALREADY_REGISTERED;
|
return ERR_ALREADY_REGISTERED;
|
||||||
|
|
||||||
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
Kernel::SharedPtr<Kernel::ServerPort> server_port;
|
Kernel::SharedPtr<Kernel::ServerPort> server_port;
|
||||||
Kernel::SharedPtr<Kernel::ClientPort> client_port;
|
Kernel::SharedPtr<Kernel::ClientPort> client_port;
|
||||||
std::tie(server_port, client_port) = Kernel::ServerPort::CreatePortPair(max_sessions, name);
|
std::tie(server_port, client_port) =
|
||||||
|
Kernel::ServerPort::CreatePortPair(kernel, max_sessions, name);
|
||||||
|
|
||||||
registered_services.emplace(std::move(name), std::move(client_port));
|
registered_services.emplace(std::move(name), std::move(client_port));
|
||||||
return MakeResult<Kernel::SharedPtr<Kernel::ServerPort>>(std::move(server_port));
|
return MakeResult<Kernel::SharedPtr<Kernel::ServerPort>>(std::move(server_port));
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "common/file_util.h"
|
#include "common/file_util.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
#include "core/core.h"
|
||||||
#include "core/file_sys/content_archive.h"
|
#include "core/file_sys/content_archive.h"
|
||||||
#include "core/file_sys/control_metadata.h"
|
#include "core/file_sys/control_metadata.h"
|
||||||
#include "core/file_sys/romfs_factory.h"
|
#include "core/file_sys/romfs_factory.h"
|
||||||
|
@ -117,10 +118,11 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
process->program_id = metadata.GetTitleID();
|
process->program_id = metadata.GetTitleID();
|
||||||
process->svc_access_mask.set();
|
process->svc_access_mask.set();
|
||||||
process->resource_limit =
|
process->resource_limit =
|
||||||
Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
|
kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION);
|
||||||
process->Run(Memory::PROCESS_IMAGE_VADDR, metadata.GetMainThreadPriority(),
|
process->Run(Memory::PROCESS_IMAGE_VADDR, metadata.GetMainThreadPriority(),
|
||||||
metadata.GetMainThreadStackSize());
|
metadata.GetMainThreadStackSize());
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/file_util.h"
|
#include "common/file_util.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
#include "core/core.h"
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/hle/kernel/resource_limit.h"
|
#include "core/hle/kernel/resource_limit.h"
|
||||||
#include "core/loader/elf.h"
|
#include "core/loader/elf.h"
|
||||||
|
@ -300,7 +301,8 @@ SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) {
|
||||||
std::vector<u8> program_image(total_image_size);
|
std::vector<u8> program_image(total_image_size);
|
||||||
size_t current_image_position = 0;
|
size_t current_image_position = 0;
|
||||||
|
|
||||||
SharedPtr<CodeSet> codeset = CodeSet::Create("");
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
|
SharedPtr<CodeSet> codeset = CodeSet::Create(kernel, "");
|
||||||
|
|
||||||
for (unsigned int i = 0; i < header->e_phnum; ++i) {
|
for (unsigned int i = 0; i < header->e_phnum; ++i) {
|
||||||
Elf32_Phdr* p = &segments[i];
|
Elf32_Phdr* p = &segments[i];
|
||||||
|
@ -400,8 +402,9 @@ ResultStatus AppLoader_ELF::Load(Kernel::SharedPtr<Kernel::Process>& process) {
|
||||||
process->svc_access_mask.set();
|
process->svc_access_mask.set();
|
||||||
|
|
||||||
// Attach the default resource limit (APPLICATION) to the process
|
// Attach the default resource limit (APPLICATION) to the process
|
||||||
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
process->resource_limit =
|
process->resource_limit =
|
||||||
Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
|
kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION);
|
||||||
|
|
||||||
process->Run(codeset->entrypoint, 48, Memory::DEFAULT_STACK_SIZE);
|
process->Run(codeset->entrypoint, 48, Memory::DEFAULT_STACK_SIZE);
|
||||||
|
|
||||||
|
|
|
@ -136,7 +136,8 @@ bool AppLoader_NRO::LoadNro(FileSys::VirtualFile file, VAddr load_base) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build program image
|
// Build program image
|
||||||
Kernel::SharedPtr<Kernel::CodeSet> codeset = Kernel::CodeSet::Create("");
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
|
Kernel::SharedPtr<Kernel::CodeSet> codeset = Kernel::CodeSet::Create(kernel, "");
|
||||||
std::vector<u8> program_image = file->ReadBytes(PageAlignSize(nro_header.file_size));
|
std::vector<u8> program_image = file->ReadBytes(PageAlignSize(nro_header.file_size));
|
||||||
if (program_image.size() != PageAlignSize(nro_header.file_size)) {
|
if (program_image.size() != PageAlignSize(nro_header.file_size)) {
|
||||||
return {};
|
return {};
|
||||||
|
@ -185,9 +186,10 @@ ResultStatus AppLoader_NRO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
|
||||||
return ResultStatus::ErrorLoadingNRO;
|
return ResultStatus::ErrorLoadingNRO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
process->svc_access_mask.set();
|
process->svc_access_mask.set();
|
||||||
process->resource_limit =
|
process->resource_limit =
|
||||||
Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
|
kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION);
|
||||||
process->Run(base_addr, THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE);
|
process->Run(base_addr, THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE);
|
||||||
|
|
||||||
is_loaded = true;
|
is_loaded = true;
|
||||||
|
|
|
@ -100,7 +100,8 @@ VAddr AppLoader_NSO::LoadModule(FileSys::VirtualFile file, VAddr load_base) {
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
// Build program image
|
// Build program image
|
||||||
Kernel::SharedPtr<Kernel::CodeSet> codeset = Kernel::CodeSet::Create("");
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
|
Kernel::SharedPtr<Kernel::CodeSet> codeset = Kernel::CodeSet::Create(kernel, "");
|
||||||
std::vector<u8> program_image;
|
std::vector<u8> program_image;
|
||||||
for (std::size_t i = 0; i < nso_header.segments.size(); ++i) {
|
for (std::size_t i = 0; i < nso_header.segments.size(); ++i) {
|
||||||
const std::vector<u8> compressed_data =
|
const std::vector<u8> compressed_data =
|
||||||
|
@ -151,9 +152,10 @@ ResultStatus AppLoader_NSO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
|
||||||
LoadModule(file, Memory::PROCESS_IMAGE_VADDR);
|
LoadModule(file, Memory::PROCESS_IMAGE_VADDR);
|
||||||
LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), Memory::PROCESS_IMAGE_VADDR);
|
LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), Memory::PROCESS_IMAGE_VADDR);
|
||||||
|
|
||||||
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
process->svc_access_mask.set();
|
process->svc_access_mask.set();
|
||||||
process->resource_limit =
|
process->resource_limit =
|
||||||
Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
|
kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION);
|
||||||
process->Run(Memory::PROCESS_IMAGE_VADDR, THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE);
|
process->Run(Memory::PROCESS_IMAGE_VADDR, THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE);
|
||||||
|
|
||||||
is_loaded = true;
|
is_loaded = true;
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace ArmTests {
|
||||||
TestEnvironment::TestEnvironment(bool mutable_memory_)
|
TestEnvironment::TestEnvironment(bool mutable_memory_)
|
||||||
: mutable_memory(mutable_memory_), test_memory(std::make_shared<TestMemory>(this)) {
|
: mutable_memory(mutable_memory_), test_memory(std::make_shared<TestMemory>(this)) {
|
||||||
|
|
||||||
Core::CurrentProcess() = Kernel::Process::Create("");
|
Core::CurrentProcess() = Kernel::Process::Create(kernel, "");
|
||||||
page_table = &Core::CurrentProcess()->vm_manager.page_table;
|
page_table = &Core::CurrentProcess()->vm_manager.page_table;
|
||||||
|
|
||||||
page_table->pointers.fill(nullptr);
|
page_table->pointers.fill(nullptr);
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/memory_hook.h"
|
#include "core/memory_hook.h"
|
||||||
|
|
||||||
namespace Memory {
|
namespace Memory {
|
||||||
|
@ -86,6 +87,7 @@ private:
|
||||||
std::shared_ptr<TestMemory> test_memory;
|
std::shared_ptr<TestMemory> test_memory;
|
||||||
std::vector<WriteRecord> write_records;
|
std::vector<WriteRecord> write_records;
|
||||||
Memory::PageTable* page_table = nullptr;
|
Memory::PageTable* page_table = nullptr;
|
||||||
|
Kernel::KernelCore kernel;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ArmTests
|
} // namespace ArmTests
|
||||||
|
|
|
@ -77,9 +77,11 @@ QString WaitTreeText::GetText() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
WaitTreeMutexInfo::WaitTreeMutexInfo(VAddr mutex_address) : mutex_address(mutex_address) {
|
WaitTreeMutexInfo::WaitTreeMutexInfo(VAddr mutex_address) : mutex_address(mutex_address) {
|
||||||
|
auto& handle_table = Core::System::GetInstance().Kernel().HandleTable();
|
||||||
|
|
||||||
mutex_value = Memory::Read32(mutex_address);
|
mutex_value = Memory::Read32(mutex_address);
|
||||||
owner_handle = static_cast<Kernel::Handle>(mutex_value & Kernel::Mutex::MutexOwnerMask);
|
owner_handle = static_cast<Kernel::Handle>(mutex_value & Kernel::Mutex::MutexOwnerMask);
|
||||||
owner = Kernel::g_handle_table.Get<Kernel::Thread>(owner_handle);
|
owner = handle_table.Get<Kernel::Thread>(owner_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString WaitTreeMutexInfo::GetText() const {
|
QString WaitTreeMutexInfo::GetText() const {
|
||||||
|
|
Loading…
Reference in New Issue