mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu-mainline.git
				synced 2025-03-21 01:53:15 +00:00 
			
		
		
		
	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(); | ||||
| } | ||||
| 
 | ||||
| Kernel::KernelCore& System::Kernel() { | ||||
|     return kernel; | ||||
| } | ||||
| 
 | ||||
| const Kernel::KernelCore& System::Kernel() const { | ||||
|     return kernel; | ||||
| } | ||||
| 
 | ||||
| ARM_Interface& System::ArmInterface(size_t core_index) { | ||||
|     ASSERT(core_index < NUM_CPU_CORES); | ||||
|     return cpu_cores[core_index]->ArmInterface(); | ||||
| @ -185,12 +193,13 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) { | ||||
|     LOG_DEBUG(HW_Memory, "initialized OK"); | ||||
| 
 | ||||
|     CoreTiming::Init(); | ||||
|     kernel.Initialize(); | ||||
| 
 | ||||
|     // Create a default fs if one doesn't already exist.
 | ||||
|     if (virtual_filesystem == nullptr) | ||||
|         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_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>(); | ||||
|     service_manager = std::make_shared<Service::SM::ServiceManager>(); | ||||
| 
 | ||||
|     Kernel::Init(); | ||||
|     Service::Init(service_manager, virtual_filesystem); | ||||
|     GDBStub::Init(); | ||||
| 
 | ||||
| @ -246,7 +254,6 @@ void System::Shutdown() { | ||||
|     renderer.reset(); | ||||
|     GDBStub::Shutdown(); | ||||
|     Service::Shutdown(); | ||||
|     Kernel::Shutdown(); | ||||
|     service_manager.reset(); | ||||
|     telemetry_session.reset(); | ||||
|     gpu_core.reset(); | ||||
| @ -265,7 +272,8 @@ void System::Shutdown() { | ||||
|     } | ||||
|     cpu_barrier.reset(); | ||||
| 
 | ||||
|     // Close core timing
 | ||||
|     // Shutdown kernel and core timing
 | ||||
|     kernel.Shutdown(); | ||||
|     CoreTiming::Shutdown(); | ||||
| 
 | ||||
|     // Close app loader
 | ||||
|  | ||||
| @ -12,6 +12,7 @@ | ||||
| #include "common/common_types.h" | ||||
| #include "core/arm/exclusive_monitor.h" | ||||
| #include "core/core_cpu.h" | ||||
| #include "core/hle/kernel/kernel.h" | ||||
| #include "core/hle/kernel/object.h" | ||||
| #include "core/hle/kernel/scheduler.h" | ||||
| #include "core/loader/loader.h" | ||||
| @ -188,6 +189,12 @@ public: | ||||
|         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
 | ||||
|     Loader::ResultStatus GetGameName(std::string& out) const { | ||||
|         if (app_loader == nullptr) | ||||
| @ -246,6 +253,7 @@ private: | ||||
|      */ | ||||
|     ResultStatus Init(Frontend::EmuWindow& emu_window); | ||||
| 
 | ||||
|     Kernel::KernelCore kernel; | ||||
|     /// RealVfsFilesystem instance
 | ||||
|     FileSys::VirtualFilesystem virtual_filesystem; | ||||
|     /// AppLoader used to load the current executing application
 | ||||
|  | ||||
| @ -12,6 +12,7 @@ | ||||
| #include <utility> | ||||
| #include "common/assert.h" | ||||
| #include "common/common_types.h" | ||||
| #include "core/core.h" | ||||
| #include "core/hle/ipc.h" | ||||
| #include "core/hle/kernel/client_port.h" | ||||
| #include "core/hle/kernel/client_session.h" | ||||
| @ -135,7 +136,9 @@ public: | ||||
|         if (context->Session()->IsDomain()) { | ||||
|             context->AddDomainObject(std::move(iface)); | ||||
|         } 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 client = std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions); | ||||
|             iface->ClientConnected(server); | ||||
|  | ||||
| @ -14,7 +14,7 @@ | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
| ClientPort::ClientPort() = default; | ||||
| ClientPort::ClientPort(KernelCore& kernel) : Object{kernel} {} | ||||
| ClientPort::~ClientPort() = default; | ||||
| 
 | ||||
| ResultVal<SharedPtr<ClientSession>> ClientPort::Connect() { | ||||
| @ -27,7 +27,7 @@ ResultVal<SharedPtr<ClientSession>> ClientPort::Connect() { | ||||
|     active_sessions++; | ||||
| 
 | ||||
|     // 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) | ||||
|         server_port->hle_handler->ClientConnected(std::get<SharedPtr<ServerSession>>(sessions)); | ||||
|  | ||||
| @ -11,8 +11,9 @@ | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
| class ServerPort; | ||||
| class ClientSession; | ||||
| class KernelCore; | ||||
| class ServerPort; | ||||
| 
 | ||||
| class ClientPort final : public Object { | ||||
| public: | ||||
| @ -44,7 +45,7 @@ public: | ||||
|     void ConnectionClosed(); | ||||
| 
 | ||||
| private: | ||||
|     ClientPort(); | ||||
|     explicit ClientPort(KernelCore& kernel); | ||||
|     ~ClientPort() override; | ||||
| 
 | ||||
|     SharedPtr<ServerPort> server_port; ///< ServerPort associated with this client port.
 | ||||
|  | ||||
| @ -11,7 +11,7 @@ | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
| ClientSession::ClientSession() = default; | ||||
| ClientSession::ClientSession(KernelCore& kernel) : Object{kernel} {} | ||||
| ClientSession::~ClientSession() { | ||||
|     // This destructor will be called automatically when the last ClientSession handle is closed by
 | ||||
|     // the emulated application.
 | ||||
|  | ||||
| @ -12,8 +12,9 @@ | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
| class ServerSession; | ||||
| class KernelCore; | ||||
| class Session; | ||||
| class ServerSession; | ||||
| class Thread; | ||||
| 
 | ||||
| class ClientSession final : public Object { | ||||
| @ -41,7 +42,7 @@ public: | ||||
|     std::shared_ptr<Session> parent; | ||||
| 
 | ||||
| private: | ||||
|     ClientSession(); | ||||
|     explicit ClientSession(KernelCore& kernel); | ||||
|     ~ClientSession() override; | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -10,11 +10,11 @@ | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
| Event::Event() {} | ||||
| Event::~Event() {} | ||||
| Event::Event(KernelCore& kernel) : WaitObject{kernel} {} | ||||
| Event::~Event() = default; | ||||
| 
 | ||||
| SharedPtr<Event> Event::Create(ResetType reset_type, std::string name) { | ||||
|     SharedPtr<Event> evt(new Event); | ||||
| SharedPtr<Event> Event::Create(KernelCore& kernel, ResetType reset_type, std::string name) { | ||||
|     SharedPtr<Event> evt(new Event(kernel)); | ||||
| 
 | ||||
|     evt->signaled = false; | ||||
|     evt->reset_type = reset_type; | ||||
|  | ||||
| @ -10,14 +10,18 @@ | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
| class KernelCore; | ||||
| 
 | ||||
| class Event final : public WaitObject { | ||||
| public: | ||||
|     /**
 | ||||
|      * Creates an event | ||||
|      * @param kernel The kernel instance to create this event under. | ||||
|      * @param reset_type ResetType describing how to create 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 { | ||||
|         return "Event"; | ||||
| @ -44,7 +48,7 @@ public: | ||||
|     void Clear(); | ||||
| 
 | ||||
| private: | ||||
|     Event(); | ||||
|     explicit Event(KernelCore& kernel); | ||||
|     ~Event() override; | ||||
| 
 | ||||
|     ResetType reset_type; ///< Current ResetType
 | ||||
|  | ||||
| @ -13,8 +13,6 @@ | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
| HandleTable g_handle_table; | ||||
| 
 | ||||
| HandleTable::HandleTable() { | ||||
|     next_generation = 1; | ||||
|     Clear(); | ||||
|  | ||||
| @ -121,6 +121,4 @@ private: | ||||
|     u16 next_free_slot; | ||||
| }; | ||||
| 
 | ||||
| extern HandleTable g_handle_table; | ||||
| 
 | ||||
| } // namespace Kernel
 | ||||
|  | ||||
| @ -13,6 +13,7 @@ | ||||
| #include "common/common_funcs.h" | ||||
| #include "common/common_types.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "core/core.h" | ||||
| #include "core/hle/ipc_helpers.h" | ||||
| #include "core/hle/kernel/event.h" | ||||
| #include "core/hle/kernel/handle_table.h" | ||||
| @ -51,7 +52,9 @@ SharedPtr<Event> HLERequestContext::SleepClientThread(SharedPtr<Thread> thread, | ||||
| 
 | ||||
|     if (!event) { | ||||
|         // 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(); | ||||
| @ -90,12 +93,14 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) { | ||||
|             rp.Skip(2, false); | ||||
|         } | ||||
|         if (incoming) { | ||||
|             auto& handle_table = Core::System::GetInstance().Kernel().HandleTable(); | ||||
| 
 | ||||
|             // Populate the object lists with the data in the IPC request.
 | ||||
|             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) { | ||||
|                 move_objects.push_back(Kernel::g_handle_table.GetGeneric(rp.Pop<Handle>())); | ||||
|                 move_objects.push_back(handle_table.GetGeneric(rp.Pop<Handle>())); | ||||
|             } | ||||
|         } else { | ||||
|             // 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(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
 | ||||
|         // services don't deal with handles directly. However, the guest applications might check
 | ||||
|         // for specific values in each of these descriptors.
 | ||||
|         for (auto& object : copy_objects) { | ||||
|             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) { | ||||
|             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
 | ||||
| // 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/kernel.h" | ||||
| #include "core/hle/kernel/process.h" | ||||
| #include "core/hle/kernel/resource_limit.h" | ||||
| #include "core/hle/kernel/thread.h" | ||||
| #include "core/hle/kernel/timer.h" | ||||
| #include "core/hle/lock.h" | ||||
| #include "core/hle/result.h" | ||||
| 
 | ||||
| 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
 | ||||
| void Init() { | ||||
|     Kernel::ResourceLimitsInit(); | ||||
|     Kernel::ThreadingInit(); | ||||
|     Kernel::TimersInit(); | ||||
|     // Lock the global kernel mutex when we enter the kernel HLE.
 | ||||
|     std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock); | ||||
| 
 | ||||
|     Object::next_object_id = 0; | ||||
|     // TODO(Subv): Start the process ids from 10 for now, as lower PIDs are
 | ||||
|     // reserved for low-level services
 | ||||
|     Process::next_process_id = 10; | ||||
|     SharedPtr<Thread> thread = | ||||
|         system.Kernel().RetrieveThreadFromWakeupCallbackHandleTable(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(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// Shutdown the kernel
 | ||||
| void Shutdown() { | ||||
|     // Free all kernel objects
 | ||||
|     g_handle_table.Clear(); | ||||
| /// 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); | ||||
| 
 | ||||
|     Kernel::ThreadingShutdown(); | ||||
|     if (timer == nullptr) { | ||||
|         LOG_CRITICAL(Kernel, "Callback fired for invalid timer {:016X}", timer_handle); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     Kernel::TimersShutdown(); | ||||
|     Kernel::ResourceLimitsShutdown(); | ||||
|     timer->Signal(cycles_late); | ||||
| } | ||||
| 
 | ||||
| struct KernelCore::Impl { | ||||
|     void Initialize(KernelCore& kernel) { | ||||
|         Shutdown(); | ||||
| 
 | ||||
|         InitializeResourceLimits(kernel); | ||||
|         InitializeThreads(); | ||||
|         InitializeTimers(); | ||||
|     } | ||||
| 
 | ||||
|     void Shutdown() { | ||||
|         next_object_id = 0; | ||||
|         next_process_id = 10; | ||||
|         next_thread_id = 1; | ||||
| 
 | ||||
|         process_list.clear(); | ||||
| 
 | ||||
|         handle_table.Clear(); | ||||
|         resource_limits.fill(nullptr); | ||||
| 
 | ||||
|         thread_wakeup_callback_handle_table.Clear(); | ||||
|         thread_wakeup_event_type = nullptr; | ||||
| 
 | ||||
|         timer_callback_handle_table.Clear(); | ||||
|         timer_callback_event_type = nullptr; | ||||
|     } | ||||
| 
 | ||||
|     void InitializeResourceLimits(KernelCore& kernel) { | ||||
|         // Create the four resource limits that the system uses
 | ||||
|         // Create the APPLICATION resource limit
 | ||||
|         SharedPtr<ResourceLimit> resource_limit = ResourceLimit::Create(kernel, "Applications"); | ||||
|         resource_limit->max_priority = 0x18; | ||||
|         resource_limit->max_commit = 0x4000000; | ||||
|         resource_limit->max_threads = 0x20; | ||||
|         resource_limit->max_events = 0x20; | ||||
|         resource_limit->max_mutexes = 0x20; | ||||
|         resource_limit->max_semaphores = 0x8; | ||||
|         resource_limit->max_timers = 0x8; | ||||
|         resource_limit->max_shared_mems = 0x10; | ||||
|         resource_limit->max_address_arbiters = 0x2; | ||||
|         resource_limit->max_cpu_time = 0x1E; | ||||
|         resource_limits[static_cast<u8>(ResourceLimitCategory::APPLICATION)] = resource_limit; | ||||
| 
 | ||||
|         // Create the SYS_APPLET resource limit
 | ||||
|         resource_limit = ResourceLimit::Create(kernel, "System Applets"); | ||||
|         resource_limit->max_priority = 0x4; | ||||
|         resource_limit->max_commit = 0x5E00000; | ||||
|         resource_limit->max_threads = 0x1D; | ||||
|         resource_limit->max_events = 0xB; | ||||
|         resource_limit->max_mutexes = 0x8; | ||||
|         resource_limit->max_semaphores = 0x4; | ||||
|         resource_limit->max_timers = 0x4; | ||||
|         resource_limit->max_shared_mems = 0x8; | ||||
|         resource_limit->max_address_arbiters = 0x3; | ||||
|         resource_limit->max_cpu_time = 0x2710; | ||||
|         resource_limits[static_cast<u8>(ResourceLimitCategory::SYS_APPLET)] = resource_limit; | ||||
| 
 | ||||
|         // Create the LIB_APPLET resource limit
 | ||||
|         resource_limit = ResourceLimit::Create(kernel, "Library Applets"); | ||||
|         resource_limit->max_priority = 0x4; | ||||
|         resource_limit->max_commit = 0x600000; | ||||
|         resource_limit->max_threads = 0xE; | ||||
|         resource_limit->max_events = 0x8; | ||||
|         resource_limit->max_mutexes = 0x8; | ||||
|         resource_limit->max_semaphores = 0x4; | ||||
|         resource_limit->max_timers = 0x4; | ||||
|         resource_limit->max_shared_mems = 0x8; | ||||
|         resource_limit->max_address_arbiters = 0x1; | ||||
|         resource_limit->max_cpu_time = 0x2710; | ||||
|         resource_limits[static_cast<u8>(ResourceLimitCategory::LIB_APPLET)] = resource_limit; | ||||
| 
 | ||||
|         // Create the OTHER resource limit
 | ||||
|         resource_limit = ResourceLimit::Create(kernel, "Others"); | ||||
|         resource_limit->max_priority = 0x4; | ||||
|         resource_limit->max_commit = 0x2180000; | ||||
|         resource_limit->max_threads = 0xE1; | ||||
|         resource_limit->max_events = 0x108; | ||||
|         resource_limit->max_mutexes = 0x25; | ||||
|         resource_limit->max_semaphores = 0x43; | ||||
|         resource_limit->max_timers = 0x2C; | ||||
|         resource_limit->max_shared_mems = 0x1F; | ||||
|         resource_limit->max_address_arbiters = 0x2D; | ||||
|         resource_limit->max_cpu_time = 0x3E8; | ||||
|         resource_limits[static_cast<u8>(ResourceLimitCategory::OTHER)] = resource_limit; | ||||
|     } | ||||
| 
 | ||||
|     void InitializeThreads() { | ||||
|         thread_wakeup_event_type = | ||||
|             CoreTiming::RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback); | ||||
|     } | ||||
| 
 | ||||
|     void InitializeTimers() { | ||||
|         timer_callback_handle_table.Clear(); | ||||
|         timer_callback_event_type = CoreTiming::RegisterEvent("TimerCallback", TimerCallback); | ||||
|     } | ||||
| 
 | ||||
|     std::atomic<u32> next_object_id{0}; | ||||
|     // TODO(Subv): Start the process ids from 10 for now, as lower PIDs are
 | ||||
|     // reserved for low-level services
 | ||||
|     std::atomic<u32> next_process_id{10}; | ||||
|     std::atomic<u32> next_thread_id{1}; | ||||
| 
 | ||||
|     // Lists all processes that exist in the current session.
 | ||||
|     std::vector<SharedPtr<Process>> process_list; | ||||
| 
 | ||||
|     Kernel::HandleTable handle_table; | ||||
|     std::array<SharedPtr<ResourceLimit>, 4> resource_limits; | ||||
| 
 | ||||
|     /// The event type of the generic timer callback event
 | ||||
|     CoreTiming::EventType* timer_callback_event_type = nullptr; | ||||
|     // TODO(yuriks): This can be removed if Timer objects are explicitly pooled in the future,
 | ||||
|     // allowing us to simply use a pool index or similar.
 | ||||
|     Kernel::HandleTable timer_callback_handle_table; | ||||
| 
 | ||||
|     CoreTiming::EventType* thread_wakeup_event_type = nullptr; | ||||
|     // TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future,
 | ||||
|     // allowing us to simply use a pool index or similar.
 | ||||
|     Kernel::HandleTable thread_wakeup_callback_handle_table; | ||||
| }; | ||||
| 
 | ||||
| KernelCore::KernelCore() : impl{std::make_unique<Impl>()} {} | ||||
| KernelCore::~KernelCore() { | ||||
|     Shutdown(); | ||||
| } | ||||
| 
 | ||||
| void KernelCore::Initialize() { | ||||
|     impl->Initialize(*this); | ||||
| } | ||||
| 
 | ||||
| void KernelCore::Shutdown() { | ||||
|     impl->Shutdown(); | ||||
| } | ||||
| 
 | ||||
| Kernel::HandleTable& KernelCore::HandleTable() { | ||||
|     return impl->handle_table; | ||||
| } | ||||
| 
 | ||||
| const Kernel::HandleTable& KernelCore::HandleTable() const { | ||||
|     return impl->handle_table; | ||||
| } | ||||
| 
 | ||||
| SharedPtr<ResourceLimit> KernelCore::ResourceLimitForCategory( | ||||
|     ResourceLimitCategory category) const { | ||||
|     return impl->resource_limits.at(static_cast<std::size_t>(category)); | ||||
| } | ||||
| 
 | ||||
| SharedPtr<Thread> KernelCore::RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const { | ||||
|     return impl->thread_wakeup_callback_handle_table.Get<Thread>(handle); | ||||
| } | ||||
| 
 | ||||
| SharedPtr<Timer> KernelCore::RetrieveTimerFromCallbackHandleTable(Handle handle) const { | ||||
|     return impl->timer_callback_handle_table.Get<Timer>(handle); | ||||
| } | ||||
| 
 | ||||
| void KernelCore::AppendNewProcess(SharedPtr<Process> process) { | ||||
|     impl->process_list.push_back(std::move(process)); | ||||
| } | ||||
| 
 | ||||
| u32 KernelCore::CreateNewObjectID() { | ||||
|     return impl->next_object_id++; | ||||
| } | ||||
| 
 | ||||
| u32 KernelCore::CreateNewThreadID() { | ||||
|     return impl->next_thread_id++; | ||||
| } | ||||
| 
 | ||||
| u32 KernelCore::CreateNewProcessID() { | ||||
|     return impl->next_process_id++; | ||||
| } | ||||
| 
 | ||||
| ResultVal<Handle> KernelCore::CreateTimerCallbackHandle(const SharedPtr<Timer>& timer) { | ||||
|     return impl->timer_callback_handle_table.Create(timer); | ||||
| } | ||||
| 
 | ||||
| CoreTiming::EventType* KernelCore::ThreadWakeupCallbackEventType() const { | ||||
|     return impl->thread_wakeup_event_type; | ||||
| } | ||||
| 
 | ||||
| CoreTiming::EventType* KernelCore::TimerCallbackEventType() const { | ||||
|     return impl->timer_callback_event_type; | ||||
| } | ||||
| 
 | ||||
| Kernel::HandleTable& KernelCore::ThreadWakeupCallbackHandleTable() { | ||||
|     return impl->thread_wakeup_callback_handle_table; | ||||
| } | ||||
| 
 | ||||
| const Kernel::HandleTable& KernelCore::ThreadWakeupCallbackHandleTable() const { | ||||
|     return impl->thread_wakeup_callback_handle_table; | ||||
| } | ||||
| 
 | ||||
| } // namespace Kernel
 | ||||
|  | ||||
| @ -4,14 +4,93 @@ | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include "common/common_types.h" | ||||
| #include "core/hle/kernel/object.h" | ||||
| 
 | ||||
| template <typename T> | ||||
| class ResultVal; | ||||
| 
 | ||||
| namespace CoreTiming { | ||||
| struct EventType; | ||||
| } | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
| /// Initialize the kernel with the specified system mode.
 | ||||
| void Init(); | ||||
| class HandleTable; | ||||
| class Process; | ||||
| class ResourceLimit; | ||||
| class Thread; | ||||
| class Timer; | ||||
| 
 | ||||
| /// Shutdown the kernel
 | ||||
| void Shutdown(); | ||||
| 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(); | ||||
| 
 | ||||
|     /// 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
 | ||||
|  | ||||
| @ -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) { | ||||
|     // The mutex address must be 4-byte aligned
 | ||||
|     if ((address % sizeof(u32)) != 0) { | ||||
|         return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidAddress); | ||||
|     } | ||||
| 
 | ||||
|     SharedPtr<Thread> holding_thread = g_handle_table.Get<Thread>(holding_thread_handle); | ||||
|     SharedPtr<Thread> requesting_thread = g_handle_table.Get<Thread>(requesting_thread_handle); | ||||
|     SharedPtr<Thread> holding_thread = handle_table.Get<Thread>(holding_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
 | ||||
|     // thread.
 | ||||
|  | ||||
| @ -11,6 +11,7 @@ union ResultCode; | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
| class HandleTable; | ||||
| class Thread; | ||||
| 
 | ||||
| class Mutex final { | ||||
| @ -21,8 +22,8 @@ public: | ||||
|     static constexpr u32 MutexOwnerMask = 0xBFFFFFFF; | ||||
| 
 | ||||
|     /// Attempts to acquire a mutex at the specified address.
 | ||||
|     static ResultCode TryAcquire(VAddr address, Handle holding_thread_handle, | ||||
|                                  Handle requesting_thread_handle); | ||||
|     static ResultCode TryAcquire(HandleTable& handle_table, VAddr address, | ||||
|                                  Handle holding_thread_handle, Handle requesting_thread_handle); | ||||
| 
 | ||||
|     /// Releases the mutex at the specified address.
 | ||||
|     static ResultCode Release(VAddr address); | ||||
|  | ||||
| @ -3,10 +3,12 @@ | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include "common/assert.h" | ||||
| #include "core/hle/kernel/kernel.h" | ||||
| #include "core/hle/kernel/object.h" | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
| Object::Object(KernelCore& kernel) : kernel{kernel}, object_id{kernel.CreateNewObjectID()} {} | ||||
| Object::~Object() = default; | ||||
| 
 | ||||
| bool Object::IsWaitable() const { | ||||
|  | ||||
| @ -14,6 +14,8 @@ | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
| class KernelCore; | ||||
| 
 | ||||
| using Handle = u32; | ||||
| 
 | ||||
| enum class HandleType : u32 { | ||||
| @ -40,6 +42,7 @@ enum class ResetType { | ||||
| 
 | ||||
| class Object : NonCopyable { | ||||
| public: | ||||
|     explicit Object(KernelCore& kernel); | ||||
|     virtual ~Object(); | ||||
| 
 | ||||
|     /// Returns a unique identifier for the object. For debugging purposes only.
 | ||||
| @ -61,15 +64,16 @@ public: | ||||
|      */ | ||||
|     bool IsWaitable() const; | ||||
| 
 | ||||
| public: | ||||
|     static std::atomic<u32> next_object_id; | ||||
| protected: | ||||
|     /// The kernel instance this object was created under.
 | ||||
|     KernelCore& kernel; | ||||
| 
 | ||||
| private: | ||||
|     friend void intrusive_ptr_add_ref(Object*); | ||||
|     friend void intrusive_ptr_release(Object*); | ||||
| 
 | ||||
|     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
 | ||||
|  | ||||
| @ -8,6 +8,7 @@ | ||||
| #include "common/common_funcs.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "core/hle/kernel/errors.h" | ||||
| #include "core/hle/kernel/kernel.h" | ||||
| #include "core/hle/kernel/process.h" | ||||
| #include "core/hle/kernel/resource_limit.h" | ||||
| #include "core/hle/kernel/thread.h" | ||||
| @ -16,30 +17,26 @@ | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
| // Lists all processes that exist in the current session.
 | ||||
| static std::vector<SharedPtr<Process>> process_list; | ||||
| 
 | ||||
| SharedPtr<CodeSet> CodeSet::Create(std::string name) { | ||||
|     SharedPtr<CodeSet> codeset(new CodeSet); | ||||
| SharedPtr<CodeSet> CodeSet::Create(KernelCore& kernel, std::string name) { | ||||
|     SharedPtr<CodeSet> codeset(new CodeSet(kernel)); | ||||
|     codeset->name = std::move(name); | ||||
|     return codeset; | ||||
| } | ||||
| 
 | ||||
| CodeSet::CodeSet() {} | ||||
| CodeSet::~CodeSet() {} | ||||
| CodeSet::CodeSet(KernelCore& kernel) : Object{kernel} {} | ||||
| CodeSet::~CodeSet() = default; | ||||
| 
 | ||||
| u32 Process::next_process_id; | ||||
| 
 | ||||
| SharedPtr<Process> Process::Create(std::string&& name) { | ||||
|     SharedPtr<Process> process(new Process); | ||||
| SharedPtr<Process> Process::Create(KernelCore& kernel, std::string&& name) { | ||||
|     SharedPtr<Process> process(new Process(kernel)); | ||||
| 
 | ||||
|     process->name = std::move(name); | ||||
|     process->flags.raw = 0; | ||||
|     process->flags.memory_region.Assign(MemoryRegion::APPLICATION); | ||||
|     process->status = ProcessStatus::Created; | ||||
|     process->program_id = 0; | ||||
|     process->process_id = kernel.CreateNewProcessID(); | ||||
| 
 | ||||
|     process_list.push_back(process); | ||||
|     kernel.AppendNewProcess(process); | ||||
|     return process; | ||||
| } | ||||
| 
 | ||||
| @ -128,7 +125,7 @@ void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) { | ||||
|     vm_manager.LogLayout(); | ||||
|     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) { | ||||
| @ -231,22 +228,7 @@ ResultCode Process::UnmapMemory(VAddr dst_addr, VAddr /*src_addr*/, u64 size) { | ||||
|     return vm_manager.UnmapRange(dst_addr, size); | ||||
| } | ||||
| 
 | ||||
| Kernel::Process::Process() {} | ||||
| Kernel::Process::Process(KernelCore& kernel) : Object{kernel} {} | ||||
| 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
 | ||||
|  | ||||
| @ -19,6 +19,8 @@ | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
| class KernelCore; | ||||
| 
 | ||||
| struct AddressMapping { | ||||
|     // Address and size must be page-aligned
 | ||||
|     VAddr address; | ||||
| @ -62,7 +64,7 @@ struct CodeSet final : public Object { | ||||
|         u32 size = 0; | ||||
|     }; | ||||
| 
 | ||||
|     static SharedPtr<CodeSet> Create(std::string name); | ||||
|     static SharedPtr<CodeSet> Create(KernelCore& kernel, std::string name); | ||||
| 
 | ||||
|     std::string GetTypeName() const override { | ||||
|         return "CodeSet"; | ||||
| @ -109,13 +111,13 @@ struct CodeSet final : public Object { | ||||
|     std::string name; | ||||
| 
 | ||||
| private: | ||||
|     CodeSet(); | ||||
|     explicit CodeSet(KernelCore& kernel); | ||||
|     ~CodeSet() override; | ||||
| }; | ||||
| 
 | ||||
| class Process final : public Object { | ||||
| public: | ||||
|     static SharedPtr<Process> Create(std::string&& name); | ||||
|     static SharedPtr<Process> Create(KernelCore& kernel, std::string&& name); | ||||
| 
 | ||||
|     std::string GetTypeName() const override { | ||||
|         return "Process"; | ||||
| @ -129,8 +131,6 @@ public: | ||||
|         return HANDLE_TYPE; | ||||
|     } | ||||
| 
 | ||||
|     static u32 next_process_id; | ||||
| 
 | ||||
|     /// Title ID corresponding to the process
 | ||||
|     u64 program_id; | ||||
| 
 | ||||
| @ -157,8 +157,8 @@ public: | ||||
|     /// Current status of the process
 | ||||
|     ProcessStatus status; | ||||
| 
 | ||||
|     /// The id of this process
 | ||||
|     u32 process_id = next_process_id++; | ||||
|     /// The ID of this process
 | ||||
|     u32 process_id = 0; | ||||
| 
 | ||||
|     /**
 | ||||
|      * 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); | ||||
| 
 | ||||
| private: | ||||
|     Process(); | ||||
|     explicit Process(KernelCore& kernel); | ||||
|     ~Process() override; | ||||
| }; | ||||
| 
 | ||||
| void ClearProcessList(); | ||||
| 
 | ||||
| /// Retrieves a process from the current list of processes.
 | ||||
| SharedPtr<Process> GetProcessById(u32 process_id); | ||||
| 
 | ||||
| } // namespace Kernel
 | ||||
|  | ||||
| @ -9,31 +9,16 @@ | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
| static SharedPtr<ResourceLimit> resource_limits[4]; | ||||
| ResourceLimit::ResourceLimit(KernelCore& kernel) : Object{kernel} {} | ||||
| ResourceLimit::~ResourceLimit() = default; | ||||
| 
 | ||||
| ResourceLimit::ResourceLimit() {} | ||||
| ResourceLimit::~ResourceLimit() {} | ||||
| 
 | ||||
| SharedPtr<ResourceLimit> ResourceLimit::Create(std::string name) { | ||||
|     SharedPtr<ResourceLimit> resource_limit(new ResourceLimit); | ||||
| SharedPtr<ResourceLimit> ResourceLimit::Create(KernelCore& kernel, std::string name) { | ||||
|     SharedPtr<ResourceLimit> resource_limit(new ResourceLimit(kernel)); | ||||
| 
 | ||||
|     resource_limit->name = std::move(name); | ||||
|     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 { | ||||
|     switch (resource) { | ||||
|     case ResourceType::Commit: | ||||
| @ -89,66 +74,4 @@ u32 ResourceLimit::GetMaxResourceValue(ResourceType resource) const { | ||||
|         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
 | ||||
|  | ||||
| @ -9,6 +9,8 @@ | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
| class KernelCore; | ||||
| 
 | ||||
| enum class ResourceLimitCategory : u8 { | ||||
|     APPLICATION = 0, | ||||
|     SYS_APPLET = 1, | ||||
| @ -34,14 +36,7 @@ public: | ||||
|     /**
 | ||||
|      * Creates a resource limit object. | ||||
|      */ | ||||
|     static SharedPtr<ResourceLimit> Create(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); | ||||
|     static SharedPtr<ResourceLimit> Create(KernelCore& kernel, std::string name = "Unknown"); | ||||
| 
 | ||||
|     std::string GetTypeName() const override { | ||||
|         return "ResourceLimit"; | ||||
| @ -113,14 +108,8 @@ public: | ||||
|     s32 current_cpu_time = 0; | ||||
| 
 | ||||
| private: | ||||
|     ResourceLimit(); | ||||
|     explicit ResourceLimit(KernelCore& kernel); | ||||
|     ~ResourceLimit() override; | ||||
| }; | ||||
| 
 | ||||
| /// Initializes the resource limits
 | ||||
| void ResourceLimitsInit(); | ||||
| 
 | ||||
| // Destroys the resource limits
 | ||||
| void ResourceLimitsShutdown(); | ||||
| 
 | ||||
| } // namespace Kernel
 | ||||
|  | ||||
| @ -13,8 +13,8 @@ | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
| ServerPort::ServerPort() {} | ||||
| ServerPort::~ServerPort() {} | ||||
| ServerPort::ServerPort(KernelCore& kernel) : WaitObject{kernel} {} | ||||
| ServerPort::~ServerPort() = default; | ||||
| 
 | ||||
| ResultVal<SharedPtr<ServerSession>> ServerPort::Accept() { | ||||
|     if (pending_sessions.empty()) { | ||||
| @ -36,10 +36,10 @@ void ServerPort::Acquire(Thread* thread) { | ||||
| } | ||||
| 
 | ||||
| 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<ClientPort> client_port(new ClientPort); | ||||
|     SharedPtr<ServerPort> server_port(new ServerPort(kernel)); | ||||
|     SharedPtr<ClientPort> client_port(new ClientPort(kernel)); | ||||
| 
 | ||||
|     server_port->name = name + "_Server"; | ||||
|     client_port->name = name + "_Client"; | ||||
|  | ||||
| @ -15,6 +15,7 @@ | ||||
| namespace Kernel { | ||||
| 
 | ||||
| class ClientPort; | ||||
| class KernelCore; | ||||
| class ServerSession; | ||||
| class SessionRequestHandler; | ||||
| 
 | ||||
| @ -23,12 +24,13 @@ public: | ||||
|     /**
 | ||||
|      * 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 name Optional name of the ports | ||||
|      * @return The created port tuple | ||||
|      */ | ||||
|     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 { | ||||
|         return "ServerPort"; | ||||
| @ -69,7 +71,7 @@ public: | ||||
|     void Acquire(Thread* thread) override; | ||||
| 
 | ||||
| private: | ||||
|     ServerPort(); | ||||
|     explicit ServerPort(KernelCore& kernel); | ||||
|     ~ServerPort() override; | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -20,7 +20,7 @@ | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
| ServerSession::ServerSession() = default; | ||||
| ServerSession::ServerSession(KernelCore& kernel) : WaitObject{kernel} {} | ||||
| ServerSession::~ServerSession() { | ||||
|     // This destructor will be called automatically when the last ServerSession handle is closed by
 | ||||
|     // the emulated application.
 | ||||
| @ -35,8 +35,8 @@ ServerSession::~ServerSession() { | ||||
|     parent->server = nullptr; | ||||
| } | ||||
| 
 | ||||
| ResultVal<SharedPtr<ServerSession>> ServerSession::Create(std::string name) { | ||||
|     SharedPtr<ServerSession> server_session(new ServerSession); | ||||
| ResultVal<SharedPtr<ServerSession>> ServerSession::Create(KernelCore& kernel, std::string name) { | ||||
|     SharedPtr<ServerSession> server_session(new ServerSession(kernel)); | ||||
| 
 | ||||
|     server_session->name = std::move(name); | ||||
|     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
 | ||||
|     // similar.
 | ||||
| 
 | ||||
|     auto& handle_table = Core::System::GetInstance().Kernel().HandleTable(); | ||||
|     Kernel::HLERequestContext context(this); | ||||
|     u32* cmd_buf = (u32*)Memory::GetPointer(thread->GetTLSAddress()); | ||||
|     context.PopulateFromIncomingCommandBuffer(cmd_buf, *Core::CurrentProcess(), | ||||
|                                               Kernel::g_handle_table); | ||||
|     context.PopulateFromIncomingCommandBuffer(cmd_buf, *Core::CurrentProcess(), handle_table); | ||||
| 
 | ||||
|     ResultCode result = RESULT_SUCCESS; | ||||
|     // 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; | ||||
| } | ||||
| 
 | ||||
| ServerSession::SessionPair ServerSession::CreateSessionPair(const std::string& name, | ||||
| ServerSession::SessionPair ServerSession::CreateSessionPair(KernelCore& kernel, | ||||
|                                                             const std::string& name, | ||||
|                                                             SharedPtr<ClientPort> port) { | ||||
|     auto server_session = ServerSession::Create(name + "_Server").Unwrap(); | ||||
|     SharedPtr<ClientSession> client_session(new ClientSession); | ||||
|     auto server_session = ServerSession::Create(kernel, name + "_Server").Unwrap(); | ||||
|     SharedPtr<ClientSession> client_session(new ClientSession(kernel)); | ||||
|     client_session->name = name + "_Client"; | ||||
| 
 | ||||
|     std::shared_ptr<Session> parent(new Session); | ||||
|  | ||||
| @ -15,13 +15,14 @@ | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
| class ClientSession; | ||||
| class ClientPort; | ||||
| class ClientSession; | ||||
| class HLERequestContext; | ||||
| class KernelCore; | ||||
| class ServerSession; | ||||
| class Session; | ||||
| class SessionRequestHandler; | ||||
| class Thread; | ||||
| class HLERequestContext; | ||||
| 
 | ||||
| /**
 | ||||
|  * 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. | ||||
|      * @param kernel      The kernal instance to create the session pair under. | ||||
|      * @param name        Optional name of the ports. | ||||
|      * @param client_port Optional The ClientPort that spawned this session. | ||||
|      * @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); | ||||
| 
 | ||||
|     /**
 | ||||
| @ -111,16 +113,18 @@ public: | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     ServerSession(); | ||||
|     explicit ServerSession(KernelCore& kernel); | ||||
|     ~ServerSession() override; | ||||
| 
 | ||||
|     /**
 | ||||
|      * 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. | ||||
|      * @param kernel The kernel instance to create this server session under. | ||||
|      * @param name Optional name of the 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
 | ||||
|     /// object handle.
 | ||||
|  | ||||
| @ -13,14 +13,14 @@ | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
| SharedMemory::SharedMemory() {} | ||||
| SharedMemory::~SharedMemory() {} | ||||
| SharedMemory::SharedMemory(KernelCore& kernel) : Object{kernel} {} | ||||
| SharedMemory::~SharedMemory() = default; | ||||
| 
 | ||||
| SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u64 size, | ||||
|                                              MemoryPermission permissions, | ||||
| SharedPtr<SharedMemory> SharedMemory::Create(KernelCore& kernel, SharedPtr<Process> owner_process, | ||||
|                                              u64 size, MemoryPermission permissions, | ||||
|                                              MemoryPermission other_permissions, VAddr address, | ||||
|                                              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->name = std::move(name); | ||||
| @ -59,12 +59,10 @@ SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u | ||||
|     return shared_memory; | ||||
| } | ||||
| 
 | ||||
| SharedPtr<SharedMemory> SharedMemory::CreateForApplet(std::shared_ptr<std::vector<u8>> heap_block, | ||||
|                                                       u32 offset, u32 size, | ||||
|                                                       MemoryPermission permissions, | ||||
|                                                       MemoryPermission other_permissions, | ||||
|                                                       std::string name) { | ||||
|     SharedPtr<SharedMemory> shared_memory(new SharedMemory); | ||||
| SharedPtr<SharedMemory> SharedMemory::CreateForApplet( | ||||
|     KernelCore& kernel, std::shared_ptr<std::vector<u8>> heap_block, u32 offset, u32 size, | ||||
|     MemoryPermission permissions, MemoryPermission other_permissions, std::string name) { | ||||
|     SharedPtr<SharedMemory> shared_memory(new SharedMemory(kernel)); | ||||
| 
 | ||||
|     shared_memory->owner_process = nullptr; | ||||
|     shared_memory->name = std::move(name); | ||||
|  | ||||
| @ -15,6 +15,8 @@ | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
| class KernelCore; | ||||
| 
 | ||||
| /// Permissions for mapped shared memory blocks
 | ||||
| enum class MemoryPermission : u32 { | ||||
|     None = 0, | ||||
| @ -32,6 +34,7 @@ class SharedMemory final : public Object { | ||||
| public: | ||||
|     /**
 | ||||
|      * 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 size Size of the memory block. Must be page-aligned. | ||||
|      * @param permissions Permission restrictions applied to the process which created the block. | ||||
| @ -42,14 +45,15 @@ public: | ||||
|      * linear heap. | ||||
|      * @param name Optional object name, used for debugging purposes. | ||||
|      */ | ||||
|     static SharedPtr<SharedMemory> Create(SharedPtr<Process> owner_process, u64 size, | ||||
|                                           MemoryPermission permissions, | ||||
|     static SharedPtr<SharedMemory> Create(KernelCore& kernel, SharedPtr<Process> owner_process, | ||||
|                                           u64 size, MemoryPermission permissions, | ||||
|                                           MemoryPermission other_permissions, VAddr address = 0, | ||||
|                                           MemoryRegion region = MemoryRegion::BASE, | ||||
|                                           std::string name = "Unknown"); | ||||
| 
 | ||||
|     /**
 | ||||
|      * 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 offset The offset into the heap block that the SharedMemory will map. | ||||
|      * @param size Size of the memory block. Must be page-aligned. | ||||
| @ -58,7 +62,8 @@ public: | ||||
|      * block. | ||||
|      * @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, | ||||
|                                                    MemoryPermission permissions, | ||||
|                                                    MemoryPermission other_permissions, | ||||
| @ -125,7 +130,7 @@ public: | ||||
|     std::string name; | ||||
| 
 | ||||
| private: | ||||
|     SharedMemory(); | ||||
|     explicit SharedMemory(KernelCore& kernel); | ||||
|     ~SharedMemory() override; | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -87,13 +87,15 @@ static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address | ||||
|     CASCADE_RESULT(client_session, client_port->Connect()); | ||||
| 
 | ||||
|     // 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; | ||||
| } | ||||
| 
 | ||||
| /// Makes a blocking IPC call to an OS service.
 | ||||
| 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) { | ||||
|         LOG_ERROR(Kernel_SVC, "called with invalid handle=0x{:08X}", handle); | ||||
|         return ERR_INVALID_HANDLE; | ||||
| @ -112,7 +114,8 @@ static ResultCode SendSyncRequest(Handle handle) { | ||||
| static ResultCode GetThreadId(u32* thread_id, Handle 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) { | ||||
|         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) { | ||||
|     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) { | ||||
|         return ERR_INVALID_HANDLE; | ||||
|     } | ||||
| @ -168,10 +172,11 @@ static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64 | ||||
| 
 | ||||
|     using ObjectPtr = SharedPtr<WaitObject>; | ||||
|     std::vector<ObjectPtr> objects(handle_count); | ||||
|     auto& kernel = Core::System::GetInstance().Kernel(); | ||||
| 
 | ||||
|     for (u64 i = 0; i < handle_count; ++i) { | ||||
|         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) { | ||||
|             return ERR_INVALID_HANDLE; | ||||
| @ -219,7 +224,8 @@ static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64 | ||||
| static ResultCode CancelSynchronization(Handle 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) { | ||||
|         return ERR_INVALID_HANDLE; | ||||
|     } | ||||
| @ -239,7 +245,9 @@ static ResultCode ArbitrateLock(Handle holding_thread_handle, VAddr mutex_addr, | ||||
|               "requesting_current_thread_handle=0x{:08X}", | ||||
|               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
 | ||||
| @ -352,7 +360,8 @@ static ResultCode GetThreadContext(Handle handle, VAddr addr) { | ||||
| 
 | ||||
| /// Gets the priority for the specified thread
 | ||||
| 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) | ||||
|         return ERR_INVALID_HANDLE; | ||||
| 
 | ||||
| @ -366,7 +375,8 @@ static ResultCode SetThreadPriority(Handle handle, u32 priority) { | ||||
|         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) | ||||
|         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}", | ||||
|               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) { | ||||
|         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}", | ||||
|                 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); | ||||
| } | ||||
| @ -431,7 +443,9 @@ static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 | ||||
| /// Query process memory
 | ||||
| static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_info*/, | ||||
|                                      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) { | ||||
|         return ERR_INVALID_HANDLE; | ||||
|     } | ||||
| @ -528,10 +542,11 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|     auto& kernel = Core::System::GetInstance().Kernel(); | ||||
|     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())); | ||||
|     CASCADE_RESULT(thread->guest_handle, g_handle_table.Create(thread)); | ||||
|     CASCADE_RESULT(thread->guest_handle, kernel.HandleTable().Create(thread)); | ||||
|     *out_handle = thread->guest_handle; | ||||
| 
 | ||||
|     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) { | ||||
|     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) { | ||||
|         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={}", | ||||
|         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); | ||||
| 
 | ||||
|     CASCADE_CODE(Mutex::Release(mutex_addr)); | ||||
| @ -704,8 +721,9 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target | ||||
|                                                mutex_val | Mutex::MutexHasWaitersFlag)); | ||||
| 
 | ||||
|             // 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); | ||||
|             auto owner = g_handle_table.Get<Thread>(owner_handle); | ||||
|             auto owner = kernel.HandleTable().Get<Thread>(owner_handle); | ||||
|             ASSERT(owner); | ||||
|             ASSERT(thread->status == ThreadStatus::WaitMutex); | ||||
|             thread->wakeup_callback = nullptr; | ||||
| @ -783,14 +801,20 @@ static u64 GetSystemTick() { | ||||
| /// Close a handle
 | ||||
| static ResultCode CloseHandle(Handle 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
 | ||||
| static ResultCode ResetSignal(Handle 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); | ||||
| 
 | ||||
|     event->Clear(); | ||||
|     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) { | ||||
|     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) { | ||||
|         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, | ||||
|               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) { | ||||
|         return ERR_INVALID_HANDLE; | ||||
|     } | ||||
| @ -861,19 +887,23 @@ static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permiss | ||||
|                                      u32 remote_permissions) { | ||||
|     LOG_TRACE(Kernel_SVC, "called, size=0x{:X}, localPerms=0x{:08X}, remotePerms=0x{:08X}", size, | ||||
|               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>(remote_permissions)); | ||||
| 
 | ||||
|     CASCADE_RESULT(*handle, g_handle_table.Create(sharedMemHandle)); | ||||
|     CASCADE_RESULT(*handle, handle_table.Create(shared_mem_handle)); | ||||
|     return RESULT_SUCCESS; | ||||
| } | ||||
| 
 | ||||
| static ResultCode ClearEvent(Handle 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) | ||||
|         return ERR_INVALID_HANDLE; | ||||
|     evt->Clear(); | ||||
|  | ||||
| @ -20,6 +20,7 @@ | ||||
| #include "core/core_timing_util.h" | ||||
| #include "core/hle/kernel/errors.h" | ||||
| #include "core/hle/kernel/handle_table.h" | ||||
| #include "core/hle/kernel/kernel.h" | ||||
| #include "core/hle/kernel/object.h" | ||||
| #include "core/hle/kernel/process.h" | ||||
| #include "core/hle/kernel/thread.h" | ||||
| @ -29,9 +30,6 @@ | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
| /// Event type for the thread wake up event
 | ||||
| static CoreTiming::EventType* ThreadWakeupEventType = nullptr; | ||||
| 
 | ||||
| bool Thread::ShouldWait(Thread* thread) const { | ||||
|     return status != ThreadStatus::Dead; | ||||
| } | ||||
| @ -40,32 +38,17 @@ void Thread::Acquire(Thread* thread) { | ||||
|     ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); | ||||
| } | ||||
| 
 | ||||
| // 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.
 | ||||
| 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() {} | ||||
| Thread::Thread(KernelCore& kernel) : WaitObject{kernel} {} | ||||
| Thread::~Thread() = default; | ||||
| 
 | ||||
| void Thread::Stop() { | ||||
|     // Cancel any outstanding wakeup events for this thread
 | ||||
|     CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle); | ||||
|     wakeup_callback_handle_table.Close(callback_handle); | ||||
|     CoreTiming::UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), callback_handle); | ||||
|     kernel.ThreadWakeupCallbackHandleTable().Close(callback_handle); | ||||
|     callback_handle = 0; | ||||
| 
 | ||||
|     // 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) { | ||||
|         scheduler->UnscheduleThread(this, current_priority); | ||||
|     } | ||||
| @ -98,63 +81,6 @@ void ExitCurrentThread() { | ||||
|     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) { | ||||
|     // Don't schedule a wakeup if the thread wants to wait forever
 | ||||
|     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
 | ||||
|     // thread-safe version of ScheduleEvent.
 | ||||
|     CoreTiming::ScheduleEventThreadsafe(CoreTiming::nsToCycles(nanoseconds), ThreadWakeupEventType, | ||||
|                                         callback_handle); | ||||
|     CoreTiming::ScheduleEventThreadsafe(CoreTiming::nsToCycles(nanoseconds), | ||||
|                                         kernel.ThreadWakeupCallbackEventType(), callback_handle); | ||||
| } | ||||
| 
 | ||||
| void Thread::CancelWakeupTimer() { | ||||
|     CoreTiming::UnscheduleEventThreadsafe(ThreadWakeupEventType, callback_handle); | ||||
|     CoreTiming::UnscheduleEventThreadsafe(kernel.ThreadWakeupCallbackEventType(), callback_handle); | ||||
| } | ||||
| 
 | ||||
| static boost::optional<s32> GetNextProcessorId(u64 mask) { | ||||
| @ -294,9 +220,9 @@ static void ResetThreadContext(Core::ARM_Interface::ThreadContext& context, VAdd | ||||
|     context.fpscr = 0; | ||||
| } | ||||
| 
 | ||||
| ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, u32 priority, | ||||
|                                             u64 arg, s32 processor_id, VAddr stack_top, | ||||
|                                             SharedPtr<Process> owner_process) { | ||||
| ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name, VAddr entry_point, | ||||
|                                             u32 priority, u64 arg, s32 processor_id, | ||||
|                                             VAddr stack_top, SharedPtr<Process> owner_process) { | ||||
|     // Check if priority is in ranged. Lowest priority -> highest priority id.
 | ||||
|     if (priority > THREADPRIO_LOWEST) { | ||||
|         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); | ||||
|     } | ||||
| 
 | ||||
|     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->entry_point = entry_point; | ||||
|     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->wait_handle = 0; | ||||
|     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->scheduler = Core::System::GetInstance().Scheduler(processor_id); | ||||
|     thread->scheduler->AddThread(thread, priority); | ||||
| @ -383,19 +309,19 @@ void Thread::BoostPriority(u32 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) { | ||||
|     // Setup page table so we can write to memory
 | ||||
|     SetCurrentPageTable(&Core::CurrentProcess()->vm_manager.page_table); | ||||
| 
 | ||||
|     // 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)); | ||||
| 
 | ||||
|     SharedPtr<Thread> thread = std::move(thread_res).Unwrap(); | ||||
| 
 | ||||
|     // 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; | ||||
| 
 | ||||
| @ -528,13 +454,4 @@ Thread* GetCurrentThread() { | ||||
|     return Core::System::GetInstance().CurrentScheduler().GetCurrentThread(); | ||||
| } | ||||
| 
 | ||||
| void ThreadingInit() { | ||||
|     ThreadWakeupEventType = CoreTiming::RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback); | ||||
|     next_thread_id = 1; | ||||
| } | ||||
| 
 | ||||
| void ThreadingShutdown() { | ||||
|     Kernel::ClearProcessList(); | ||||
| } | ||||
| 
 | ||||
| } // namespace Kernel
 | ||||
|  | ||||
| @ -56,6 +56,7 @@ enum class ThreadWakeupReason { | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
| class KernelCore; | ||||
| class Process; | ||||
| class Scheduler; | ||||
| 
 | ||||
| @ -63,6 +64,7 @@ class Thread final : public WaitObject { | ||||
| public: | ||||
|     /**
 | ||||
|      * 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 entry_point The address at which the thread should start execution | ||||
|      * @param priority The thread's priority | ||||
| @ -72,8 +74,9 @@ public: | ||||
|      * @param owner_process The parent process for the thread | ||||
|      * @return A shared pointer to the newly created thread | ||||
|      */ | ||||
|     static ResultVal<SharedPtr<Thread>> Create(std::string name, VAddr entry_point, u32 priority, | ||||
|                                                u64 arg, s32 processor_id, VAddr stack_top, | ||||
|     static ResultVal<SharedPtr<Thread>> Create(KernelCore& kernel, std::string name, | ||||
|                                                VAddr entry_point, u32 priority, u64 arg, | ||||
|                                                s32 processor_id, VAddr stack_top, | ||||
|                                                SharedPtr<Process> owner_process); | ||||
| 
 | ||||
|     std::string GetName() const override { | ||||
| @ -263,7 +266,7 @@ public: | ||||
|     u64 affinity_mask{0x1}; | ||||
| 
 | ||||
| private: | ||||
|     Thread(); | ||||
|     explicit Thread(KernelCore& kernel); | ||||
|     ~Thread() override; | ||||
| 
 | ||||
|     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 | ||||
|  * @param kernel The kernel instance to create the main thread under. | ||||
|  * @param entry_point The address at which the thread should start execution | ||||
|  * @param priority The priority to give the main thread | ||||
|  * @param owner_process The parent process for 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); | ||||
| 
 | ||||
| /**
 | ||||
| @ -294,14 +298,4 @@ void WaitCurrentThread_Sleep(); | ||||
|  */ | ||||
| void ExitCurrentThread(); | ||||
| 
 | ||||
| /**
 | ||||
|  * Initialize threading | ||||
|  */ | ||||
| void ThreadingInit(); | ||||
| 
 | ||||
| /**
 | ||||
|  * Shutdown threading | ||||
|  */ | ||||
| void ThreadingShutdown(); | ||||
| 
 | ||||
| } // namespace Kernel
 | ||||
|  | ||||
| @ -2,36 +2,31 @@ | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <cinttypes> | ||||
| #include "common/assert.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "core/core.h" | ||||
| #include "core/core_timing.h" | ||||
| #include "core/core_timing_util.h" | ||||
| #include "core/hle/kernel/handle_table.h" | ||||
| #include "core/hle/kernel/kernel.h" | ||||
| #include "core/hle/kernel/object.h" | ||||
| #include "core/hle/kernel/thread.h" | ||||
| #include "core/hle/kernel/timer.h" | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
| /// The event type of the generic timer callback event
 | ||||
| static CoreTiming::EventType* timer_callback_event_type = nullptr; | ||||
| // TODO(yuriks): This can be removed if Timer objects are explicitly pooled in the future, allowing
 | ||||
| //               us to simply use a pool index or similar.
 | ||||
| static Kernel::HandleTable timer_callback_handle_table; | ||||
| Timer::Timer(KernelCore& kernel) : WaitObject{kernel} {} | ||||
| Timer::~Timer() = default; | ||||
| 
 | ||||
| Timer::Timer() {} | ||||
| Timer::~Timer() {} | ||||
| 
 | ||||
| SharedPtr<Timer> Timer::Create(ResetType reset_type, std::string name) { | ||||
|     SharedPtr<Timer> timer(new Timer); | ||||
| SharedPtr<Timer> Timer::Create(KernelCore& kernel, ResetType reset_type, std::string name) { | ||||
|     SharedPtr<Timer> timer(new Timer(kernel)); | ||||
| 
 | ||||
|     timer->reset_type = reset_type; | ||||
|     timer->signaled = false; | ||||
|     timer->name = std::move(name); | ||||
|     timer->initial_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; | ||||
| } | ||||
| @ -58,13 +53,13 @@ void Timer::Set(s64 initial, s64 interval) { | ||||
|         // Immediately invoke the callback
 | ||||
|         Signal(0); | ||||
|     } else { | ||||
|         CoreTiming::ScheduleEvent(CoreTiming::nsToCycles(initial), timer_callback_event_type, | ||||
|         CoreTiming::ScheduleEvent(CoreTiming::nsToCycles(initial), kernel.TimerCallbackEventType(), | ||||
|                                   callback_handle); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void Timer::Cancel() { | ||||
|     CoreTiming::UnscheduleEvent(timer_callback_event_type, callback_handle); | ||||
|     CoreTiming::UnscheduleEvent(kernel.TimerCallbackEventType(), callback_handle); | ||||
| } | ||||
| 
 | ||||
| void Timer::Clear() { | ||||
| @ -89,28 +84,8 @@ void Timer::Signal(int cycles_late) { | ||||
|     if (interval_delay != 0) { | ||||
|         // Reschedule the timer with the interval delay
 | ||||
|         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
 | ||||
|  | ||||
| @ -10,15 +10,19 @@ | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
| class KernelCore; | ||||
| 
 | ||||
| class Timer final : public WaitObject { | ||||
| public: | ||||
|     /**
 | ||||
|      * 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 name Optional name of 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 { | ||||
|         return "Timer"; | ||||
| @ -68,7 +72,7 @@ public: | ||||
|     void Signal(int cycles_late); | ||||
| 
 | ||||
| private: | ||||
|     Timer(); | ||||
|     explicit Timer(KernelCore& kernel); | ||||
|     ~Timer() override; | ||||
| 
 | ||||
|     ResetType reset_type; ///< The ResetType of this timer
 | ||||
| @ -83,9 +87,4 @@ private: | ||||
|     Handle callback_handle; | ||||
| }; | ||||
| 
 | ||||
| /// Initializes the required variables for timers
 | ||||
| void TimersInit(); | ||||
| /// Tears down the timer variables
 | ||||
| void TimersShutdown(); | ||||
| 
 | ||||
| } // namespace Kernel
 | ||||
|  | ||||
| @ -12,6 +12,9 @@ | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
| WaitObject::WaitObject(KernelCore& kernel) : Object{kernel} {} | ||||
| WaitObject::~WaitObject() = default; | ||||
| 
 | ||||
| void WaitObject::AddWaitingThread(SharedPtr<Thread> thread) { | ||||
|     auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); | ||||
|     if (itr == waiting_threads.end()) | ||||
|  | ||||
| @ -11,11 +11,15 @@ | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
| class KernelCore; | ||||
| class Thread; | ||||
| 
 | ||||
| /// Class that represents a Kernel object that a thread can be waiting on
 | ||||
| class WaitObject : public Object { | ||||
| public: | ||||
|     explicit WaitObject(KernelCore& kernel); | ||||
|     ~WaitObject() override; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Check if the specified thread should wait until the object is available | ||||
|      * @param thread The thread about which we're deciding. | ||||
|  | ||||
| @ -160,8 +160,9 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger | ||||
|     }; | ||||
|     RegisterHandlers(functions); | ||||
| 
 | ||||
|     auto& kernel = Core::System::GetInstance().Kernel(); | ||||
|     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) { | ||||
| @ -332,7 +333,8 @@ ICommonStateGetter::ICommonStateGetter() : ServiceFramework("ICommonStateGetter" | ||||
|     }; | ||||
|     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) { | ||||
| @ -505,7 +507,8 @@ public: | ||||
|         }; | ||||
|         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"); | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -47,7 +47,9 @@ public: | ||||
|         RegisterHandlers(functions); | ||||
| 
 | ||||
|         // 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, | ||||
|                                        "IAudioOut", [=]() { buffer_event->Signal(); }); | ||||
|  | ||||
| @ -35,8 +35,9 @@ public: | ||||
|         }; | ||||
|         RegisterHandlers(functions); | ||||
| 
 | ||||
|         auto& kernel = Core::System::GetInstance().Kernel(); | ||||
|         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); | ||||
|     } | ||||
| 
 | ||||
| @ -121,8 +122,9 @@ public: | ||||
|         }; | ||||
|         RegisterHandlers(functions); | ||||
| 
 | ||||
|         buffer_event = | ||||
|             Kernel::Event::Create(Kernel::ResetType::OneShot, "IAudioOutBufferReleasedEvent"); | ||||
|         auto& kernel = Core::System::GetInstance().Kernel(); | ||||
|         buffer_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, | ||||
|                                              "IAudioOutBufferReleasedEvent"); | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|  | ||||
| @ -4,6 +4,7 @@ | ||||
| 
 | ||||
| #include <atomic> | ||||
| #include "common/logging/log.h" | ||||
| #include "core/core.h" | ||||
| #include "core/core_timing.h" | ||||
| #include "core/core_timing_util.h" | ||||
| #include "core/frontend/emu_window.h" | ||||
| @ -35,9 +36,10 @@ public: | ||||
|         }; | ||||
|         RegisterHandlers(functions); | ||||
| 
 | ||||
|         auto& kernel = Core::System::GetInstance().Kernel(); | ||||
|         shared_mem = Kernel::SharedMemory::Create( | ||||
|             nullptr, 0x40000, Kernel::MemoryPermission::ReadWrite, Kernel::MemoryPermission::Read, | ||||
|             0, Kernel::MemoryRegion::BASE, "HID:SharedMemory"); | ||||
|             kernel, nullptr, 0x40000, Kernel::MemoryPermission::ReadWrite, | ||||
|             Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "HID:SharedMemory"); | ||||
| 
 | ||||
|         // Register update callbacks
 | ||||
|         pad_update_event = CoreTiming::RegisterEvent( | ||||
| @ -402,7 +404,8 @@ public: | ||||
| 
 | ||||
|         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; | ||||
| 
 | ||||
|  | ||||
| @ -46,11 +46,13 @@ public: | ||||
|         }; | ||||
|         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 = | ||||
|             Kernel::Event::Create(Kernel::ResetType::OneShot, "IUser:DeactivateEvent"); | ||||
|         availability_change_event = | ||||
|             Kernel::Event::Create(Kernel::ResetType::OneShot, "IUser:AvailabilityChangeEvent"); | ||||
|             Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IUser:DeactivateEvent"); | ||||
|         availability_change_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, | ||||
|                                                           "IUser:AvailabilityChangeEvent"); | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|  | ||||
| @ -2,6 +2,7 @@ | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include "core/core.h" | ||||
| #include "core/hle/ipc_helpers.h" | ||||
| #include "core/hle/kernel/event.h" | ||||
| #include "core/hle/service/nifm/nifm.h" | ||||
| @ -54,8 +55,9 @@ public: | ||||
|         }; | ||||
|         RegisterHandlers(functions); | ||||
| 
 | ||||
|         event1 = Kernel::Event::Create(Kernel::ResetType::OneShot, "IRequest:Event1"); | ||||
|         event2 = Kernel::Event::Create(Kernel::ResetType::OneShot, "IRequest:Event2"); | ||||
|         auto& kernel = Core::System::GetInstance().Kernel(); | ||||
|         event1 = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IRequest:Event1"); | ||||
|         event2 = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IRequest:Event2"); | ||||
|     } | ||||
| 
 | ||||
| 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); | ||||
| 
 | ||||
|     // Create shared font memory object
 | ||||
|     auto& kernel = Core::System::GetInstance().Kernel(); | ||||
|     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, | ||||
|         "PL_U:shared_font_mem"); | ||||
| 
 | ||||
|  | ||||
| @ -4,6 +4,7 @@ | ||||
| 
 | ||||
| #include <cinttypes> | ||||
| #include "common/logging/log.h" | ||||
| #include "core/core.h" | ||||
| #include "core/hle/ipc_helpers.h" | ||||
| #include "core/hle/kernel/event.h" | ||||
| #include "core/hle/service/nvdrv/interface.h" | ||||
| @ -107,7 +108,8 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name) | ||||
|     }; | ||||
|     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
 | ||||
|  | ||||
| @ -6,14 +6,16 @@ | ||||
| 
 | ||||
| #include "common/assert.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "core/core.h" | ||||
| #include "core/hle/service/nvflinger/buffer_queue.h" | ||||
| 
 | ||||
| namespace Service { | ||||
| namespace NVFlinger { | ||||
| 
 | ||||
| BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) { | ||||
|     auto& kernel = Core::System::GetInstance().Kernel(); | ||||
|     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) { | ||||
|  | ||||
| @ -161,7 +161,8 @@ void NVFlinger::Compose() { | ||||
| 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)) { | ||||
|     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
 | ||||
|  | ||||
| @ -107,19 +107,24 @@ void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) | ||||
| 
 | ||||
| void ServiceFrameworkBase::InstallAsNamedPort() { | ||||
|     ASSERT(port == nullptr); | ||||
| 
 | ||||
|     auto& kernel = Core::System::GetInstance().Kernel(); | ||||
|     SharedPtr<ServerPort> server_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()); | ||||
|     AddNamedPort(service_name, std::move(client_port)); | ||||
| } | ||||
| 
 | ||||
| Kernel::SharedPtr<Kernel::ClientPort> ServiceFrameworkBase::CreatePort() { | ||||
|     ASSERT(port == nullptr); | ||||
| 
 | ||||
|     auto& kernel = Core::System::GetInstance().Kernel(); | ||||
|     Kernel::SharedPtr<Kernel::ServerPort> server_port; | ||||
|     Kernel::SharedPtr<Kernel::ClientPort> 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->SetHleHandler(shared_from_this()); | ||||
|     return client_port; | ||||
|  | ||||
| @ -4,6 +4,7 @@ | ||||
| 
 | ||||
| #include <tuple> | ||||
| #include "common/assert.h" | ||||
| #include "core/core.h" | ||||
| #include "core/hle/ipc_helpers.h" | ||||
| #include "core/hle/kernel/client_port.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()) | ||||
|         return ERR_ALREADY_REGISTERED; | ||||
| 
 | ||||
|     auto& kernel = Core::System::GetInstance().Kernel(); | ||||
|     Kernel::SharedPtr<Kernel::ServerPort> server_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)); | ||||
|     return MakeResult<Kernel::SharedPtr<Kernel::ServerPort>>(std::move(server_port)); | ||||
|  | ||||
| @ -6,6 +6,7 @@ | ||||
| #include "common/common_funcs.h" | ||||
| #include "common/file_util.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "core/core.h" | ||||
| #include "core/file_sys/content_archive.h" | ||||
| #include "core/file_sys/control_metadata.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->svc_access_mask.set(); | ||||
|     process->resource_limit = | ||||
|         Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); | ||||
|         kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION); | ||||
|     process->Run(Memory::PROCESS_IMAGE_VADDR, metadata.GetMainThreadPriority(), | ||||
|                  metadata.GetMainThreadStackSize()); | ||||
| 
 | ||||
|  | ||||
| @ -9,6 +9,7 @@ | ||||
| #include "common/common_types.h" | ||||
| #include "common/file_util.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "core/core.h" | ||||
| #include "core/hle/kernel/process.h" | ||||
| #include "core/hle/kernel/resource_limit.h" | ||||
| #include "core/loader/elf.h" | ||||
| @ -300,7 +301,8 @@ SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) { | ||||
|     std::vector<u8> program_image(total_image_size); | ||||
|     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) { | ||||
|         Elf32_Phdr* p = &segments[i]; | ||||
| @ -400,8 +402,9 @@ ResultStatus AppLoader_ELF::Load(Kernel::SharedPtr<Kernel::Process>& process) { | ||||
|     process->svc_access_mask.set(); | ||||
| 
 | ||||
|     // Attach the default resource limit (APPLICATION) to the process
 | ||||
|     auto& kernel = Core::System::GetInstance().Kernel(); | ||||
|     process->resource_limit = | ||||
|         Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); | ||||
|         kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION); | ||||
| 
 | ||||
|     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
 | ||||
|     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)); | ||||
|     if (program_image.size() != PageAlignSize(nro_header.file_size)) { | ||||
|         return {}; | ||||
| @ -185,9 +186,10 @@ ResultStatus AppLoader_NRO::Load(Kernel::SharedPtr<Kernel::Process>& process) { | ||||
|         return ResultStatus::ErrorLoadingNRO; | ||||
|     } | ||||
| 
 | ||||
|     auto& kernel = Core::System::GetInstance().Kernel(); | ||||
|     process->svc_access_mask.set(); | ||||
|     process->resource_limit = | ||||
|         Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); | ||||
|         kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION); | ||||
|     process->Run(base_addr, THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE); | ||||
| 
 | ||||
|     is_loaded = true; | ||||
|  | ||||
| @ -100,7 +100,8 @@ VAddr AppLoader_NSO::LoadModule(FileSys::VirtualFile file, VAddr load_base) { | ||||
|         return {}; | ||||
| 
 | ||||
|     // 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; | ||||
|     for (std::size_t i = 0; i < nso_header.segments.size(); ++i) { | ||||
|         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); | ||||
|     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->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); | ||||
| 
 | ||||
|     is_loaded = true; | ||||
|  | ||||
| @ -13,7 +13,7 @@ namespace ArmTests { | ||||
| TestEnvironment::TestEnvironment(bool mutable_memory_) | ||||
|     : 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->pointers.fill(nullptr); | ||||
|  | ||||
| @ -9,6 +9,7 @@ | ||||
| #include <vector> | ||||
| 
 | ||||
| #include "common/common_types.h" | ||||
| #include "core/hle/kernel/kernel.h" | ||||
| #include "core/memory_hook.h" | ||||
| 
 | ||||
| namespace Memory { | ||||
| @ -86,6 +87,7 @@ private: | ||||
|     std::shared_ptr<TestMemory> test_memory; | ||||
|     std::vector<WriteRecord> write_records; | ||||
|     Memory::PageTable* page_table = nullptr; | ||||
|     Kernel::KernelCore kernel; | ||||
| }; | ||||
| 
 | ||||
| } // namespace ArmTests
 | ||||
|  | ||||
| @ -77,9 +77,11 @@ QString WaitTreeText::GetText() const { | ||||
| } | ||||
| 
 | ||||
| WaitTreeMutexInfo::WaitTreeMutexInfo(VAddr mutex_address) : mutex_address(mutex_address) { | ||||
|     auto& handle_table = Core::System::GetInstance().Kernel().HandleTable(); | ||||
| 
 | ||||
|     mutex_value = Memory::Read32(mutex_address); | ||||
|     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 { | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 bunnei
						bunnei