diff options
Diffstat (limited to 'src/core/hle/kernel')
26 files changed, 747 insertions, 430 deletions
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 06010b8d1..738b6d0f1 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -167,6 +167,9 @@ void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32 } if (incoming) { // Populate the object lists with the data in the IPC request. + incoming_copy_handles.reserve(handle_descriptor_header->num_handles_to_copy); + incoming_move_handles.reserve(handle_descriptor_header->num_handles_to_move); + for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_copy; ++handle) { incoming_copy_handles.push_back(rp.Pop<Handle>()); } @@ -181,6 +184,11 @@ void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32 } } + buffer_x_desciptors.reserve(command_header->num_buf_x_descriptors); + buffer_a_desciptors.reserve(command_header->num_buf_a_descriptors); + buffer_b_desciptors.reserve(command_header->num_buf_b_descriptors); + buffer_w_desciptors.reserve(command_header->num_buf_w_descriptors); + for (u32 i = 0; i < command_header->num_buf_x_descriptors; ++i) { buffer_x_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorX>()); } @@ -318,25 +326,23 @@ Result HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_threa } std::vector<u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const { - std::vector<u8> buffer{}; const bool is_buffer_a{BufferDescriptorA().size() > buffer_index && BufferDescriptorA()[buffer_index].Size()}; - if (is_buffer_a) { ASSERT_OR_EXECUTE_MSG( - BufferDescriptorA().size() > buffer_index, { return buffer; }, + BufferDescriptorA().size() > buffer_index, { return {}; }, "BufferDescriptorA invalid buffer_index {}", buffer_index); - buffer.resize(BufferDescriptorA()[buffer_index].Size()); + std::vector<u8> buffer(BufferDescriptorA()[buffer_index].Size()); memory.ReadBlock(BufferDescriptorA()[buffer_index].Address(), buffer.data(), buffer.size()); + return buffer; } else { ASSERT_OR_EXECUTE_MSG( - BufferDescriptorX().size() > buffer_index, { return buffer; }, + BufferDescriptorX().size() > buffer_index, { return {}; }, "BufferDescriptorX invalid buffer_index {}", buffer_index); - buffer.resize(BufferDescriptorX()[buffer_index].Size()); + std::vector<u8> buffer(BufferDescriptorX()[buffer_index].Size()); memory.ReadBlock(BufferDescriptorX()[buffer_index].Address(), buffer.data(), buffer.size()); + return buffer; } - - return buffer; } std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size, diff --git a/src/core/hle/kernel/k_address_arbiter.cpp b/src/core/hle/kernel/k_address_arbiter.cpp index f85b11557..a442a3b98 100644 --- a/src/core/hle/kernel/k_address_arbiter.cpp +++ b/src/core/hle/kernel/k_address_arbiter.cpp @@ -10,7 +10,6 @@ #include "core/hle/kernel/k_thread_queue.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/svc_results.h" -#include "core/hle/kernel/time_manager.h" #include "core/memory.h" namespace Kernel { diff --git a/src/core/hle/kernel/k_code_memory.cpp b/src/core/hle/kernel/k_code_memory.cpp index 4b1c134d4..d9da1e600 100644 --- a/src/core/hle/kernel/k_code_memory.cpp +++ b/src/core/hle/kernel/k_code_memory.cpp @@ -27,13 +27,13 @@ Result KCodeMemory::Initialize(Core::DeviceMemory& device_memory, VAddr addr, si auto& page_table = m_owner->PageTable(); // Construct the page group. - m_page_group = {}; + m_page_group.emplace(kernel, page_table.GetBlockInfoManager()); // Lock the memory. - R_TRY(page_table.LockForCodeMemory(&m_page_group, addr, size)) + R_TRY(page_table.LockForCodeMemory(std::addressof(*m_page_group), addr, size)) // Clear the memory. - for (const auto& block : m_page_group.Nodes()) { + for (const auto& block : *m_page_group) { std::memset(device_memory.GetPointer<void>(block.GetAddress()), 0xFF, block.GetSize()); } @@ -51,12 +51,13 @@ Result KCodeMemory::Initialize(Core::DeviceMemory& device_memory, VAddr addr, si void KCodeMemory::Finalize() { // Unlock. if (!m_is_mapped && !m_is_owner_mapped) { - const size_t size = m_page_group.GetNumPages() * PageSize; - m_owner->PageTable().UnlockForCodeMemory(m_address, size, m_page_group); + const size_t size = m_page_group->GetNumPages() * PageSize; + m_owner->PageTable().UnlockForCodeMemory(m_address, size, *m_page_group); } // Close the page group. - m_page_group = {}; + m_page_group->Close(); + m_page_group->Finalize(); // Close our reference to our owner. m_owner->Close(); @@ -64,7 +65,7 @@ void KCodeMemory::Finalize() { Result KCodeMemory::Map(VAddr address, size_t size) { // Validate the size. - R_UNLESS(m_page_group.GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize); + R_UNLESS(m_page_group->GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize); // Lock ourselves. KScopedLightLock lk(m_lock); @@ -74,7 +75,7 @@ Result KCodeMemory::Map(VAddr address, size_t size) { // Map the memory. R_TRY(kernel.CurrentProcess()->PageTable().MapPages( - address, m_page_group, KMemoryState::CodeOut, KMemoryPermission::UserReadWrite)); + address, *m_page_group, KMemoryState::CodeOut, KMemoryPermission::UserReadWrite)); // Mark ourselves as mapped. m_is_mapped = true; @@ -84,13 +85,13 @@ Result KCodeMemory::Map(VAddr address, size_t size) { Result KCodeMemory::Unmap(VAddr address, size_t size) { // Validate the size. - R_UNLESS(m_page_group.GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize); + R_UNLESS(m_page_group->GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize); // Lock ourselves. KScopedLightLock lk(m_lock); // Unmap the memory. - R_TRY(kernel.CurrentProcess()->PageTable().UnmapPages(address, m_page_group, + R_TRY(kernel.CurrentProcess()->PageTable().UnmapPages(address, *m_page_group, KMemoryState::CodeOut)); // Mark ourselves as unmapped. @@ -101,7 +102,7 @@ Result KCodeMemory::Unmap(VAddr address, size_t size) { Result KCodeMemory::MapToOwner(VAddr address, size_t size, Svc::MemoryPermission perm) { // Validate the size. - R_UNLESS(m_page_group.GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize); + R_UNLESS(m_page_group->GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize); // Lock ourselves. KScopedLightLock lk(m_lock); @@ -125,7 +126,7 @@ Result KCodeMemory::MapToOwner(VAddr address, size_t size, Svc::MemoryPermission // Map the memory. R_TRY( - m_owner->PageTable().MapPages(address, m_page_group, KMemoryState::GeneratedCode, k_perm)); + m_owner->PageTable().MapPages(address, *m_page_group, KMemoryState::GeneratedCode, k_perm)); // Mark ourselves as mapped. m_is_owner_mapped = true; @@ -135,13 +136,13 @@ Result KCodeMemory::MapToOwner(VAddr address, size_t size, Svc::MemoryPermission Result KCodeMemory::UnmapFromOwner(VAddr address, size_t size) { // Validate the size. - R_UNLESS(m_page_group.GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize); + R_UNLESS(m_page_group->GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize); // Lock ourselves. KScopedLightLock lk(m_lock); // Unmap the memory. - R_TRY(m_owner->PageTable().UnmapPages(address, m_page_group, KMemoryState::GeneratedCode)); + R_TRY(m_owner->PageTable().UnmapPages(address, *m_page_group, KMemoryState::GeneratedCode)); // Mark ourselves as unmapped. m_is_owner_mapped = false; diff --git a/src/core/hle/kernel/k_code_memory.h b/src/core/hle/kernel/k_code_memory.h index 2e7e1436a..5b260b385 100644 --- a/src/core/hle/kernel/k_code_memory.h +++ b/src/core/hle/kernel/k_code_memory.h @@ -3,6 +3,8 @@ #pragma once +#include <optional> + #include "common/common_types.h" #include "core/device_memory.h" #include "core/hle/kernel/k_auto_object.h" @@ -49,11 +51,11 @@ public: return m_address; } size_t GetSize() const { - return m_is_initialized ? m_page_group.GetNumPages() * PageSize : 0; + return m_is_initialized ? m_page_group->GetNumPages() * PageSize : 0; } private: - KPageGroup m_page_group{}; + std::optional<KPageGroup> m_page_group{}; KProcess* m_owner{}; VAddr m_address{}; KLightLock m_lock; diff --git a/src/core/hle/kernel/k_hardware_timer.cpp b/src/core/hle/kernel/k_hardware_timer.cpp new file mode 100644 index 000000000..6bba79ea0 --- /dev/null +++ b/src/core/hle/kernel/k_hardware_timer.cpp @@ -0,0 +1,74 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/core_timing.h" +#include "core/hle/kernel/k_hardware_timer.h" +#include "core/hle/kernel/k_scheduler.h" + +namespace Kernel { + +void KHardwareTimer::Initialize() { + // Create the timing callback to register with CoreTiming. + m_event_type = Core::Timing::CreateEvent( + "KHardwareTimer::Callback", [](std::uintptr_t timer_handle, s64, std::chrono::nanoseconds) { + reinterpret_cast<KHardwareTimer*>(timer_handle)->DoTask(); + return std::nullopt; + }); +} + +void KHardwareTimer::Finalize() { + this->DisableInterrupt(); + m_event_type.reset(); +} + +void KHardwareTimer::DoTask() { + // Handle the interrupt. + { + KScopedSchedulerLock slk{m_kernel}; + KScopedSpinLock lk(this->GetLock()); + + //! Ignore this event if needed. + if (!this->GetInterruptEnabled()) { + return; + } + + // Disable the timer interrupt while we handle this. + this->DisableInterrupt(); + + if (const s64 next_time = this->DoInterruptTaskImpl(GetTick()); + 0 < next_time && next_time <= m_wakeup_time) { + // We have a next time, so we should set the time to interrupt and turn the interrupt + // on. + this->EnableInterrupt(next_time); + } + } + + // Clear the timer interrupt. + // Kernel::GetInterruptManager().ClearInterrupt(KInterruptName_NonSecurePhysicalTimer, + // GetCurrentCoreId()); +} + +void KHardwareTimer::EnableInterrupt(s64 wakeup_time) { + this->DisableInterrupt(); + + m_wakeup_time = wakeup_time; + m_kernel.System().CoreTiming().ScheduleEvent(std::chrono::nanoseconds{m_wakeup_time}, + m_event_type, reinterpret_cast<uintptr_t>(this), + true); +} + +void KHardwareTimer::DisableInterrupt() { + m_kernel.System().CoreTiming().UnscheduleEvent(m_event_type, reinterpret_cast<uintptr_t>(this)); + m_wakeup_time = std::numeric_limits<s64>::max(); +} + +s64 KHardwareTimer::GetTick() const { + return m_kernel.System().CoreTiming().GetGlobalTimeNs().count(); +} + +bool KHardwareTimer::GetInterruptEnabled() { + return m_wakeup_time != std::numeric_limits<s64>::max(); +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_hardware_timer.h b/src/core/hle/kernel/k_hardware_timer.h new file mode 100644 index 000000000..00bef6ea1 --- /dev/null +++ b/src/core/hle/kernel/k_hardware_timer.h @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/kernel/k_hardware_timer_base.h" + +namespace Core::Timing { +struct EventType; +} // namespace Core::Timing + +namespace Kernel { + +class KHardwareTimer : /* public KInterruptTask, */ public KHardwareTimerBase { +public: + explicit KHardwareTimer(KernelCore& kernel) : KHardwareTimerBase{kernel} {} + + // Public API. + void Initialize(); + void Finalize(); + + s64 GetCount() const { + return GetTick(); + } + + void RegisterTask(KTimerTask* task, s64 time_from_now) { + this->RegisterAbsoluteTask(task, GetTick() + time_from_now); + } + + void RegisterAbsoluteTask(KTimerTask* task, s64 task_time) { + KScopedDisableDispatch dd{m_kernel}; + KScopedSpinLock lk{this->GetLock()}; + + if (this->RegisterAbsoluteTaskImpl(task, task_time)) { + if (task_time <= m_wakeup_time) { + this->EnableInterrupt(task_time); + } + } + } + +private: + void EnableInterrupt(s64 wakeup_time); + void DisableInterrupt(); + bool GetInterruptEnabled(); + s64 GetTick() const; + void DoTask(); + +private: + // Absolute time in nanoseconds + s64 m_wakeup_time{std::numeric_limits<s64>::max()}; + std::shared_ptr<Core::Timing::EventType> m_event_type{}; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_hardware_timer_base.h b/src/core/hle/kernel/k_hardware_timer_base.h new file mode 100644 index 000000000..6318b35bd --- /dev/null +++ b/src/core/hle/kernel/k_hardware_timer_base.h @@ -0,0 +1,92 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/kernel/k_spin_lock.h" +#include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/k_timer_task.h" + +namespace Kernel { + +class KHardwareTimerBase { +public: + explicit KHardwareTimerBase(KernelCore& kernel) : m_kernel{kernel} {} + + void CancelTask(KTimerTask* task) { + KScopedDisableDispatch dd{m_kernel}; + KScopedSpinLock lk{m_lock}; + + if (const s64 task_time = task->GetTime(); task_time > 0) { + this->RemoveTaskFromTree(task); + } + } + +protected: + KSpinLock& GetLock() { + return m_lock; + } + + s64 DoInterruptTaskImpl(s64 cur_time) { + // We want to handle all tasks, returning the next time that a task is scheduled. + while (true) { + // Get the next task. If there isn't one, return 0. + KTimerTask* task = m_next_task; + if (task == nullptr) { + return 0; + } + + // If the task needs to be done in the future, do it in the future and not now. + if (const s64 task_time = task->GetTime(); task_time > cur_time) { + return task_time; + } + + // Remove the task from the tree of tasks, and update our next task. + this->RemoveTaskFromTree(task); + + // Handle the task. + task->OnTimer(); + } + } + + bool RegisterAbsoluteTaskImpl(KTimerTask* task, s64 task_time) { + ASSERT(task_time > 0); + + // Set the task's time, and insert it into our tree. + task->SetTime(task_time); + m_task_tree.insert(*task); + + // Update our next task if relevant. + if (m_next_task != nullptr && m_next_task->GetTime() <= task_time) { + return false; + } + m_next_task = task; + return true; + } + +private: + void RemoveTaskFromTree(KTimerTask* task) { + // Erase from the tree. + auto it = m_task_tree.erase(m_task_tree.iterator_to(*task)); + + // Clear the task's scheduled time. + task->SetTime(0); + + // Update our next task if relevant. + if (m_next_task == task) { + m_next_task = (it != m_task_tree.end()) ? std::addressof(*it) : nullptr; + } + } + +protected: + KernelCore& m_kernel; + +private: + using TimerTaskTree = Common::IntrusiveRedBlackTreeBaseTraits<KTimerTask>::TreeType<KTimerTask>; + + KSpinLock m_lock{}; + TimerTaskTree m_task_tree{}; + KTimerTask* m_next_task{}; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_memory_manager.cpp b/src/core/hle/kernel/k_memory_manager.cpp index bd33571da..cd6ea388e 100644 --- a/src/core/hle/kernel/k_memory_manager.cpp +++ b/src/core/hle/kernel/k_memory_manager.cpp @@ -223,7 +223,7 @@ Result KMemoryManager::AllocatePageGroupImpl(KPageGroup* out, size_t num_pages, // Ensure that we don't leave anything un-freed. ON_RESULT_FAILURE { - for (const auto& it : out->Nodes()) { + for (const auto& it : *out) { auto& manager = this->GetManager(it.GetAddress()); const size_t node_num_pages = std::min<u64>( it.GetNumPages(), (manager.GetEndAddress() - it.GetAddress()) / PageSize); @@ -285,7 +285,7 @@ Result KMemoryManager::AllocateAndOpen(KPageGroup* out, size_t num_pages, u32 op m_has_optimized_process[static_cast<size_t>(pool)], true)); // Open the first reference to the pages. - for (const auto& block : out->Nodes()) { + for (const auto& block : *out) { PAddr cur_address = block.GetAddress(); size_t remaining_pages = block.GetNumPages(); while (remaining_pages > 0) { @@ -335,7 +335,7 @@ Result KMemoryManager::AllocateForProcess(KPageGroup* out, size_t num_pages, u32 // Perform optimized memory tracking, if we should. if (optimized) { // Iterate over the allocated blocks. - for (const auto& block : out->Nodes()) { + for (const auto& block : *out) { // Get the block extents. const PAddr block_address = block.GetAddress(); const size_t block_pages = block.GetNumPages(); @@ -391,7 +391,7 @@ Result KMemoryManager::AllocateForProcess(KPageGroup* out, size_t num_pages, u32 } } else { // Set all the allocated memory. - for (const auto& block : out->Nodes()) { + for (const auto& block : *out) { std::memset(m_system.DeviceMemory().GetPointer<void>(block.GetAddress()), fill_pattern, block.GetSize()); } diff --git a/src/core/hle/kernel/k_page_group.cpp b/src/core/hle/kernel/k_page_group.cpp new file mode 100644 index 000000000..d8c644a33 --- /dev/null +++ b/src/core/hle/kernel/k_page_group.cpp @@ -0,0 +1,121 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/kernel/k_dynamic_resource_manager.h" +#include "core/hle/kernel/k_memory_manager.h" +#include "core/hle/kernel/k_page_group.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/svc_results.h" + +namespace Kernel { + +void KPageGroup::Finalize() { + KBlockInfo* cur = m_first_block; + while (cur != nullptr) { + KBlockInfo* next = cur->GetNext(); + m_manager->Free(cur); + cur = next; + } + + m_first_block = nullptr; + m_last_block = nullptr; +} + +void KPageGroup::CloseAndReset() { + auto& mm = m_kernel.MemoryManager(); + + KBlockInfo* cur = m_first_block; + while (cur != nullptr) { + KBlockInfo* next = cur->GetNext(); + mm.Close(cur->GetAddress(), cur->GetNumPages()); + m_manager->Free(cur); + cur = next; + } + + m_first_block = nullptr; + m_last_block = nullptr; +} + +size_t KPageGroup::GetNumPages() const { + size_t num_pages = 0; + + for (const auto& it : *this) { + num_pages += it.GetNumPages(); + } + + return num_pages; +} + +Result KPageGroup::AddBlock(KPhysicalAddress addr, size_t num_pages) { + // Succeed immediately if we're adding no pages. + R_SUCCEED_IF(num_pages == 0); + + // Check for overflow. + ASSERT(addr < addr + num_pages * PageSize); + + // Try to just append to the last block. + if (m_last_block != nullptr) { + R_SUCCEED_IF(m_last_block->TryConcatenate(addr, num_pages)); + } + + // Allocate a new block. + KBlockInfo* new_block = m_manager->Allocate(); + R_UNLESS(new_block != nullptr, ResultOutOfResource); + + // Initialize the block. + new_block->Initialize(addr, num_pages); + + // Add the block to our list. + if (m_last_block != nullptr) { + m_last_block->SetNext(new_block); + } else { + m_first_block = new_block; + } + m_last_block = new_block; + + R_SUCCEED(); +} + +void KPageGroup::Open() const { + auto& mm = m_kernel.MemoryManager(); + + for (const auto& it : *this) { + mm.Open(it.GetAddress(), it.GetNumPages()); + } +} + +void KPageGroup::OpenFirst() const { + auto& mm = m_kernel.MemoryManager(); + + for (const auto& it : *this) { + mm.OpenFirst(it.GetAddress(), it.GetNumPages()); + } +} + +void KPageGroup::Close() const { + auto& mm = m_kernel.MemoryManager(); + + for (const auto& it : *this) { + mm.Close(it.GetAddress(), it.GetNumPages()); + } +} + +bool KPageGroup::IsEquivalentTo(const KPageGroup& rhs) const { + auto lit = this->begin(); + auto rit = rhs.begin(); + auto lend = this->end(); + auto rend = rhs.end(); + + while (lit != lend && rit != rend) { + if (*lit != *rit) { + return false; + } + + ++lit; + ++rit; + } + + return lit == lend && rit == rend; +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_page_group.h b/src/core/hle/kernel/k_page_group.h index 316f172f2..c07f17663 100644 --- a/src/core/hle/kernel/k_page_group.h +++ b/src/core/hle/kernel/k_page_group.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -13,24 +13,23 @@ namespace Kernel { +class KBlockInfoManager; +class KernelCore; class KPageGroup; class KBlockInfo { -private: - friend class KPageGroup; - public: - constexpr KBlockInfo() = default; + constexpr explicit KBlockInfo() : m_next(nullptr) {} - constexpr void Initialize(PAddr addr, size_t np) { + constexpr void Initialize(KPhysicalAddress addr, size_t np) { ASSERT(Common::IsAligned(addr, PageSize)); ASSERT(static_cast<u32>(np) == np); - m_page_index = static_cast<u32>(addr) / PageSize; + m_page_index = static_cast<u32>(addr / PageSize); m_num_pages = static_cast<u32>(np); } - constexpr PAddr GetAddress() const { + constexpr KPhysicalAddress GetAddress() const { return m_page_index * PageSize; } constexpr size_t GetNumPages() const { @@ -39,10 +38,10 @@ public: constexpr size_t GetSize() const { return this->GetNumPages() * PageSize; } - constexpr PAddr GetEndAddress() const { + constexpr KPhysicalAddress GetEndAddress() const { return (m_page_index + m_num_pages) * PageSize; } - constexpr PAddr GetLastAddress() const { + constexpr KPhysicalAddress GetLastAddress() const { return this->GetEndAddress() - 1; } @@ -62,8 +61,8 @@ public: return !(*this == rhs); } - constexpr bool IsStrictlyBefore(PAddr addr) const { - const PAddr end = this->GetEndAddress(); + constexpr bool IsStrictlyBefore(KPhysicalAddress addr) const { + const KPhysicalAddress end = this->GetEndAddress(); if (m_page_index != 0 && end == 0) { return false; @@ -72,11 +71,11 @@ public: return end < addr; } - constexpr bool operator<(PAddr addr) const { + constexpr bool operator<(KPhysicalAddress addr) const { return this->IsStrictlyBefore(addr); } - constexpr bool TryConcatenate(PAddr addr, size_t np) { + constexpr bool TryConcatenate(KPhysicalAddress addr, size_t np) { if (addr != 0 && addr == this->GetEndAddress()) { m_num_pages += static_cast<u32>(np); return true; @@ -90,96 +89,118 @@ private: } private: + friend class KPageGroup; + KBlockInfo* m_next{}; u32 m_page_index{}; u32 m_num_pages{}; }; static_assert(sizeof(KBlockInfo) <= 0x10); -class KPageGroup final { +class KPageGroup { public: - class Node final { + class Iterator { public: - constexpr Node(u64 addr_, std::size_t num_pages_) : addr{addr_}, num_pages{num_pages_} {} + using iterator_category = std::forward_iterator_tag; + using value_type = const KBlockInfo; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + + constexpr explicit Iterator(pointer n) : m_node(n) {} + + constexpr bool operator==(const Iterator& rhs) const { + return m_node == rhs.m_node; + } + constexpr bool operator!=(const Iterator& rhs) const { + return !(*this == rhs); + } - constexpr u64 GetAddress() const { - return addr; + constexpr pointer operator->() const { + return m_node; + } + constexpr reference operator*() const { + return *m_node; } - constexpr std::size_t GetNumPages() const { - return num_pages; + constexpr Iterator& operator++() { + m_node = m_node->GetNext(); + return *this; } - constexpr std::size_t GetSize() const { - return GetNumPages() * PageSize; + constexpr Iterator operator++(int) { + const Iterator it{*this}; + ++(*this); + return it; } private: - u64 addr{}; - std::size_t num_pages{}; + pointer m_node{}; }; -public: - KPageGroup() = default; - KPageGroup(u64 address, u64 num_pages) { - ASSERT(AddBlock(address, num_pages).IsSuccess()); + explicit KPageGroup(KernelCore& kernel, KBlockInfoManager* m) + : m_kernel{kernel}, m_manager{m} {} + ~KPageGroup() { + this->Finalize(); } - constexpr std::list<Node>& Nodes() { - return nodes; - } + void CloseAndReset(); + void Finalize(); - constexpr const std::list<Node>& Nodes() const { - return nodes; + Iterator begin() const { + return Iterator{m_first_block}; + } + Iterator end() const { + return Iterator{nullptr}; + } + bool empty() const { + return m_first_block == nullptr; } - std::size_t GetNumPages() const { - std::size_t num_pages = 0; - for (const Node& node : nodes) { - num_pages += node.GetNumPages(); - } - return num_pages; - } - - bool IsEqual(KPageGroup& other) const { - auto this_node = nodes.begin(); - auto other_node = other.nodes.begin(); - while (this_node != nodes.end() && other_node != other.nodes.end()) { - if (this_node->GetAddress() != other_node->GetAddress() || - this_node->GetNumPages() != other_node->GetNumPages()) { - return false; - } - this_node = std::next(this_node); - other_node = std::next(other_node); - } + Result AddBlock(KPhysicalAddress addr, size_t num_pages); + void Open() const; + void OpenFirst() const; + void Close() const; + + size_t GetNumPages() const; + + bool IsEquivalentTo(const KPageGroup& rhs) const; + + bool operator==(const KPageGroup& rhs) const { + return this->IsEquivalentTo(rhs); + } - return this_node == nodes.end() && other_node == other.nodes.end(); + bool operator!=(const KPageGroup& rhs) const { + return !(*this == rhs); } - Result AddBlock(u64 address, u64 num_pages) { - if (!num_pages) { - return ResultSuccess; +private: + KernelCore& m_kernel; + KBlockInfo* m_first_block{}; + KBlockInfo* m_last_block{}; + KBlockInfoManager* m_manager{}; +}; + +class KScopedPageGroup { +public: + explicit KScopedPageGroup(const KPageGroup* gp) : m_pg(gp) { + if (m_pg) { + m_pg->Open(); } - if (!nodes.empty()) { - const auto node = nodes.back(); - if (node.GetAddress() + node.GetNumPages() * PageSize == address) { - address = node.GetAddress(); - num_pages += node.GetNumPages(); - nodes.pop_back(); - } + } + explicit KScopedPageGroup(const KPageGroup& gp) : KScopedPageGroup(std::addressof(gp)) {} + ~KScopedPageGroup() { + if (m_pg) { + m_pg->Close(); } - nodes.push_back({address, num_pages}); - return ResultSuccess; } - bool Empty() const { - return nodes.empty(); + void CancelClose() { + m_pg = nullptr; } - void Finalize() {} - private: - std::list<Node> nodes; + const KPageGroup* m_pg{}; }; } // namespace Kernel diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp index 612fc76fa..9c7ac22dc 100644 --- a/src/core/hle/kernel/k_page_table.cpp +++ b/src/core/hle/kernel/k_page_table.cpp @@ -100,7 +100,7 @@ constexpr size_t GetAddressSpaceWidthFromType(FileSys::ProgramAddressSpaceType a KPageTable::KPageTable(Core::System& system_) : m_general_lock{system_.Kernel()}, - m_map_physical_memory_lock{system_.Kernel()}, m_system{system_} {} + m_map_physical_memory_lock{system_.Kernel()}, m_system{system_}, m_kernel{system_.Kernel()} {} KPageTable::~KPageTable() = default; @@ -373,7 +373,7 @@ Result KPageTable::MapProcessCode(VAddr addr, size_t num_pages, KMemoryState sta m_memory_block_slab_manager); // Allocate and open. - KPageGroup pg; + KPageGroup pg{m_kernel, m_block_info_manager}; R_TRY(m_system.Kernel().MemoryManager().AllocateAndOpen( &pg, num_pages, KMemoryManager::EncodeOption(KMemoryManager::Pool::Application, m_allocation_option))); @@ -432,7 +432,7 @@ Result KPageTable::MapCodeMemory(VAddr dst_address, VAddr src_address, size_t si const size_t num_pages = size / PageSize; // Create page groups for the memory being mapped. - KPageGroup pg; + KPageGroup pg{m_kernel, m_block_info_manager}; AddRegionToPages(src_address, num_pages, pg); // Reprotect the source as kernel-read/not mapped. @@ -593,7 +593,7 @@ Result KPageTable::MakePageGroup(KPageGroup& pg, VAddr addr, size_t num_pages) { const size_t size = num_pages * PageSize; // We're making a new group, not adding to an existing one. - R_UNLESS(pg.Empty(), ResultInvalidCurrentMemory); + R_UNLESS(pg.empty(), ResultInvalidCurrentMemory); // Begin traversal. Common::PageTable::TraversalContext context; @@ -640,11 +640,10 @@ Result KPageTable::MakePageGroup(KPageGroup& pg, VAddr addr, size_t num_pages) { R_SUCCEED(); } -bool KPageTable::IsValidPageGroup(const KPageGroup& pg_ll, VAddr addr, size_t num_pages) { +bool KPageTable::IsValidPageGroup(const KPageGroup& pg, VAddr addr, size_t num_pages) { ASSERT(this->IsLockedByCurrentThread()); const size_t size = num_pages * PageSize; - const auto& pg = pg_ll.Nodes(); const auto& memory_layout = m_system.Kernel().MemoryLayout(); // Empty groups are necessarily invalid. @@ -942,9 +941,6 @@ Result KPageTable::SetupForIpcServer(VAddr* out_addr, size_t size, VAddr src_add ON_RESULT_FAILURE { if (cur_mapped_addr != dst_addr) { - // HACK: Manually close the pages. - HACK_ClosePages(dst_addr, (cur_mapped_addr - dst_addr) / PageSize); - ASSERT(Operate(dst_addr, (cur_mapped_addr - dst_addr) / PageSize, KMemoryPermission::None, OperationType::Unmap) .IsSuccess()); @@ -1020,9 +1016,6 @@ Result KPageTable::SetupForIpcServer(VAddr* out_addr, size_t size, VAddr src_add // Map the page. R_TRY(Operate(cur_mapped_addr, 1, test_perm, OperationType::Map, start_partial_page)); - // HACK: Manually open the pages. - HACK_OpenPages(start_partial_page, 1); - // Update tracking extents. cur_mapped_addr += PageSize; cur_block_addr += PageSize; @@ -1051,9 +1044,6 @@ Result KPageTable::SetupForIpcServer(VAddr* out_addr, size_t size, VAddr src_add R_TRY(Operate(cur_mapped_addr, cur_block_size / PageSize, test_perm, OperationType::Map, cur_block_addr)); - // HACK: Manually open the pages. - HACK_OpenPages(cur_block_addr, cur_block_size / PageSize); - // Update tracking extents. cur_mapped_addr += cur_block_size; cur_block_addr = next_entry.phys_addr; @@ -1073,9 +1063,6 @@ Result KPageTable::SetupForIpcServer(VAddr* out_addr, size_t size, VAddr src_add R_TRY(Operate(cur_mapped_addr, last_block_size / PageSize, test_perm, OperationType::Map, cur_block_addr)); - // HACK: Manually open the pages. - HACK_OpenPages(cur_block_addr, last_block_size / PageSize); - // Update tracking extents. cur_mapped_addr += last_block_size; cur_block_addr += last_block_size; @@ -1107,9 +1094,6 @@ Result KPageTable::SetupForIpcServer(VAddr* out_addr, size_t size, VAddr src_add // Map the page. R_TRY(Operate(cur_mapped_addr, 1, test_perm, OperationType::Map, end_partial_page)); - - // HACK: Manually open the pages. - HACK_OpenPages(end_partial_page, 1); } // Update memory blocks to reflect our changes @@ -1211,9 +1195,6 @@ Result KPageTable::CleanupForIpcServer(VAddr address, size_t size, KMemoryState const size_t aligned_size = aligned_end - aligned_start; const size_t aligned_num_pages = aligned_size / PageSize; - // HACK: Manually close the pages. - HACK_ClosePages(aligned_start, aligned_num_pages); - // Unmap the pages. R_TRY(Operate(aligned_start, aligned_num_pages, KMemoryPermission::None, OperationType::Unmap)); @@ -1501,17 +1482,6 @@ void KPageTable::CleanupForIpcClientOnServerSetupFailure([[maybe_unused]] PageLi } } -void KPageTable::HACK_OpenPages(PAddr phys_addr, size_t num_pages) { - m_system.Kernel().MemoryManager().OpenFirst(phys_addr, num_pages); -} - -void KPageTable::HACK_ClosePages(VAddr virt_addr, size_t num_pages) { - for (size_t index = 0; index < num_pages; ++index) { - const auto paddr = GetPhysicalAddr(virt_addr + (index * PageSize)); - m_system.Kernel().MemoryManager().Close(paddr, 1); - } -} - Result KPageTable::MapPhysicalMemory(VAddr address, size_t size) { // Lock the physical memory lock. KScopedLightLock phys_lk(m_map_physical_memory_lock); @@ -1572,7 +1542,7 @@ Result KPageTable::MapPhysicalMemory(VAddr address, size_t size) { R_UNLESS(memory_reservation.Succeeded(), ResultLimitReached); // Allocate pages for the new memory. - KPageGroup pg; + KPageGroup pg{m_kernel, m_block_info_manager}; R_TRY(m_system.Kernel().MemoryManager().AllocateForProcess( &pg, (size - mapped_size) / PageSize, m_allocate_option, 0, 0)); @@ -1650,7 +1620,7 @@ Result KPageTable::MapPhysicalMemory(VAddr address, size_t size) { KScopedPageTableUpdater updater(this); // Prepare to iterate over the memory. - auto pg_it = pg.Nodes().begin(); + auto pg_it = pg.begin(); PAddr pg_phys_addr = pg_it->GetAddress(); size_t pg_pages = pg_it->GetNumPages(); @@ -1680,9 +1650,6 @@ Result KPageTable::MapPhysicalMemory(VAddr address, size_t size) { last_unmap_address + 1 - cur_address) / PageSize; - // HACK: Manually close the pages. - HACK_ClosePages(cur_address, cur_pages); - // Unmap. ASSERT(Operate(cur_address, cur_pages, KMemoryPermission::None, OperationType::Unmap) @@ -1703,7 +1670,7 @@ Result KPageTable::MapPhysicalMemory(VAddr address, size_t size) { // Release any remaining unmapped memory. m_system.Kernel().MemoryManager().OpenFirst(pg_phys_addr, pg_pages); m_system.Kernel().MemoryManager().Close(pg_phys_addr, pg_pages); - for (++pg_it; pg_it != pg.Nodes().end(); ++pg_it) { + for (++pg_it; pg_it != pg.end(); ++pg_it) { m_system.Kernel().MemoryManager().OpenFirst(pg_it->GetAddress(), pg_it->GetNumPages()); m_system.Kernel().MemoryManager().Close(pg_it->GetAddress(), @@ -1731,7 +1698,7 @@ Result KPageTable::MapPhysicalMemory(VAddr address, size_t size) { // Check if we're at the end of the physical block. if (pg_pages == 0) { // Ensure there are more pages to map. - ASSERT(pg_it != pg.Nodes().end()); + ASSERT(pg_it != pg.end()); // Advance our physical block. ++pg_it; @@ -1742,10 +1709,7 @@ Result KPageTable::MapPhysicalMemory(VAddr address, size_t size) { // Map whatever we can. const size_t cur_pages = std::min(pg_pages, map_pages); R_TRY(Operate(cur_address, cur_pages, KMemoryPermission::UserReadWrite, - OperationType::Map, pg_phys_addr)); - - // HACK: Manually open the pages. - HACK_OpenPages(pg_phys_addr, cur_pages); + OperationType::MapFirst, pg_phys_addr)); // Advance. cur_address += cur_pages * PageSize; @@ -1888,9 +1852,6 @@ Result KPageTable::UnmapPhysicalMemory(VAddr address, size_t size) { last_address + 1 - cur_address) / PageSize; - // HACK: Manually close the pages. - HACK_ClosePages(cur_address, cur_pages); - // Unmap. ASSERT(Operate(cur_address, cur_pages, KMemoryPermission::None, OperationType::Unmap) .IsSuccess()); @@ -1955,7 +1916,7 @@ Result KPageTable::MapMemory(VAddr dst_address, VAddr src_address, size_t size) R_TRY(dst_allocator_result); // Map the memory. - KPageGroup page_linked_list; + KPageGroup page_linked_list{m_kernel, m_block_info_manager}; const size_t num_pages{size / PageSize}; const KMemoryPermission new_src_perm = static_cast<KMemoryPermission>( KMemoryPermission::KernelRead | KMemoryPermission::NotMapped); @@ -2022,14 +1983,14 @@ Result KPageTable::UnmapMemory(VAddr dst_address, VAddr src_address, size_t size num_dst_allocator_blocks); R_TRY(dst_allocator_result); - KPageGroup src_pages; - KPageGroup dst_pages; + KPageGroup src_pages{m_kernel, m_block_info_manager}; + KPageGroup dst_pages{m_kernel, m_block_info_manager}; const size_t num_pages{size / PageSize}; AddRegionToPages(src_address, num_pages, src_pages); AddRegionToPages(dst_address, num_pages, dst_pages); - R_UNLESS(dst_pages.IsEqual(src_pages), ResultInvalidMemoryRegion); + R_UNLESS(dst_pages.IsEquivalentTo(src_pages), ResultInvalidMemoryRegion); { auto block_guard = detail::ScopeExit([&] { MapPages(dst_address, dst_pages, dst_perm); }); @@ -2060,7 +2021,7 @@ Result KPageTable::MapPages(VAddr addr, const KPageGroup& page_linked_list, VAddr cur_addr{addr}; - for (const auto& node : page_linked_list.Nodes()) { + for (const auto& node : page_linked_list) { if (const auto result{ Operate(cur_addr, node.GetNumPages(), perm, OperationType::Map, node.GetAddress())}; result.IsError()) { @@ -2160,7 +2121,7 @@ Result KPageTable::UnmapPages(VAddr addr, const KPageGroup& page_linked_list) { VAddr cur_addr{addr}; - for (const auto& node : page_linked_list.Nodes()) { + for (const auto& node : page_linked_list) { if (const auto result{Operate(cur_addr, node.GetNumPages(), KMemoryPermission::None, OperationType::Unmap)}; result.IsError()) { @@ -2527,13 +2488,13 @@ Result KPageTable::SetHeapSize(VAddr* out, size_t size) { R_UNLESS(memory_reservation.Succeeded(), ResultLimitReached); // Allocate pages for the heap extension. - KPageGroup pg; + KPageGroup pg{m_kernel, m_block_info_manager}; R_TRY(m_system.Kernel().MemoryManager().AllocateAndOpen( &pg, allocation_size / PageSize, KMemoryManager::EncodeOption(m_memory_pool, m_allocation_option))); // Clear all the newly allocated pages. - for (const auto& it : pg.Nodes()) { + for (const auto& it : pg) { std::memset(m_system.DeviceMemory().GetPointer<void>(it.GetAddress()), m_heap_fill_value, it.GetSize()); } @@ -2610,11 +2571,23 @@ ResultVal<VAddr> KPageTable::AllocateAndMapMemory(size_t needed_num_pages, size_ if (is_map_only) { R_TRY(Operate(addr, needed_num_pages, perm, OperationType::Map, map_addr)); } else { - KPageGroup page_group; - R_TRY(m_system.Kernel().MemoryManager().AllocateForProcess( - &page_group, needed_num_pages, - KMemoryManager::EncodeOption(m_memory_pool, m_allocation_option), 0, 0)); - R_TRY(Operate(addr, needed_num_pages, page_group, OperationType::MapGroup)); + // Create a page group tohold the pages we allocate. + KPageGroup pg{m_kernel, m_block_info_manager}; + + R_TRY(m_system.Kernel().MemoryManager().AllocateAndOpen( + &pg, needed_num_pages, + KMemoryManager::EncodeOption(m_memory_pool, m_allocation_option))); + + // Ensure that the page group is closed when we're done working with it. + SCOPE_EXIT({ pg.Close(); }); + + // Clear all pages. + for (const auto& it : pg) { + std::memset(m_system.DeviceMemory().GetPointer<void>(it.GetAddress()), + m_heap_fill_value, it.GetSize()); + } + + R_TRY(Operate(addr, needed_num_pages, pg, OperationType::MapGroup)); } // Update the blocks. @@ -2795,19 +2768,28 @@ Result KPageTable::Operate(VAddr addr, size_t num_pages, const KPageGroup& page_ ASSERT(num_pages > 0); ASSERT(num_pages == page_group.GetNumPages()); - for (const auto& node : page_group.Nodes()) { - const size_t size{node.GetNumPages() * PageSize}; + switch (operation) { + case OperationType::MapGroup: { + // We want to maintain a new reference to every page in the group. + KScopedPageGroup spg(page_group); + + for (const auto& node : page_group) { + const size_t size{node.GetNumPages() * PageSize}; - switch (operation) { - case OperationType::MapGroup: + // Map the pages. m_system.Memory().MapMemoryRegion(*m_page_table_impl, addr, size, node.GetAddress()); - break; - default: - ASSERT(false); - break; + + addr += size; } - addr += size; + // We succeeded! We want to persist the reference to the pages. + spg.CancelClose(); + + break; + } + default: + ASSERT(false); + break; } R_SUCCEED(); @@ -2822,13 +2804,29 @@ Result KPageTable::Operate(VAddr addr, size_t num_pages, KMemoryPermission perm, ASSERT(ContainsPages(addr, num_pages)); switch (operation) { - case OperationType::Unmap: + case OperationType::Unmap: { + // Ensure that any pages we track close on exit. + KPageGroup pages_to_close{m_kernel, this->GetBlockInfoManager()}; + SCOPE_EXIT({ pages_to_close.CloseAndReset(); }); + + this->AddRegionToPages(addr, num_pages, pages_to_close); m_system.Memory().UnmapRegion(*m_page_table_impl, addr, num_pages * PageSize); break; + } + case OperationType::MapFirst: case OperationType::Map: { ASSERT(map_addr); ASSERT(Common::IsAligned(map_addr, PageSize)); m_system.Memory().MapMemoryRegion(*m_page_table_impl, addr, num_pages * PageSize, map_addr); + + // Open references to pages, if we should. + if (IsHeapPhysicalAddress(m_kernel.MemoryLayout(), map_addr)) { + if (operation == OperationType::MapFirst) { + m_kernel.MemoryManager().OpenFirst(map_addr, num_pages); + } else { + m_kernel.MemoryManager().Open(map_addr, num_pages); + } + } break; } case OperationType::Separate: { diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h index f1ca785d7..0a454b05b 100644 --- a/src/core/hle/kernel/k_page_table.h +++ b/src/core/hle/kernel/k_page_table.h @@ -107,6 +107,10 @@ public: return *m_page_table_impl; } + KBlockInfoManager* GetBlockInfoManager() { + return m_block_info_manager; + } + bool CanContain(VAddr addr, size_t size, KMemoryState state) const; protected: @@ -261,10 +265,6 @@ private: void CleanupForIpcClientOnServerSetupFailure(PageLinkedList* page_list, VAddr address, size_t size, KMemoryPermission prot_perm); - // HACK: These will be removed once we automatically manage page reference counts. - void HACK_OpenPages(PAddr phys_addr, size_t num_pages); - void HACK_ClosePages(VAddr virt_addr, size_t num_pages); - mutable KLightLock m_general_lock; mutable KLightLock m_map_physical_memory_lock; @@ -488,6 +488,7 @@ private: std::unique_ptr<Common::PageTable> m_page_table_impl; Core::System& m_system; + KernelCore& m_kernel; }; } // namespace Kernel diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index d1dc62401..a1abf5d68 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp @@ -285,6 +285,17 @@ void KProcess::UnregisterThread(KThread* thread) { thread_list.remove(thread); } +u64 KProcess::GetFreeThreadCount() const { + if (resource_limit != nullptr) { + const auto current_value = + resource_limit->GetCurrentValue(LimitableResource::ThreadCountMax); + const auto limit_value = resource_limit->GetLimitValue(LimitableResource::ThreadCountMax); + return limit_value - current_value; + } else { + return 0; + } +} + Result KProcess::Reset() { // Lock the process and the scheduler. KScopedLightLock lk(state_lock); diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h index 2e0cc3d0b..09bf2f1d0 100644 --- a/src/core/hle/kernel/k_process.h +++ b/src/core/hle/kernel/k_process.h @@ -304,6 +304,9 @@ public: /// from this process' thread list. void UnregisterThread(KThread* thread); + /// Retrieves the number of available threads for this process. + u64 GetFreeThreadCount() const; + /// Clears the signaled state of the process if and only if it's signaled. /// /// @pre The process must not be already terminated. If this is called on a diff --git a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h index 76c095e69..76db65a4d 100644 --- a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h +++ b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h @@ -5,9 +5,9 @@ #include "common/common_types.h" #include "core/hle/kernel/global_scheduler_context.h" +#include "core/hle/kernel/k_hardware_timer.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/time_manager.h" namespace Kernel { @@ -22,7 +22,7 @@ public: ~KScopedSchedulerLockAndSleep() { // Register the sleep. if (timeout_tick > 0) { - kernel.TimeManager().ScheduleTimeEvent(thread, timeout_tick); + kernel.HardwareTimer().RegisterTask(thread, timeout_tick); } // Unlock the scheduler. diff --git a/src/core/hle/kernel/k_shared_memory.cpp b/src/core/hle/kernel/k_shared_memory.cpp index 10cd4c43d..3cf2b5d91 100644 --- a/src/core/hle/kernel/k_shared_memory.cpp +++ b/src/core/hle/kernel/k_shared_memory.cpp @@ -6,31 +6,29 @@ #include "core/hle/kernel/k_page_table.h" #include "core/hle/kernel/k_scoped_resource_reservation.h" #include "core/hle/kernel/k_shared_memory.h" +#include "core/hle/kernel/k_system_resource.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/svc_results.h" namespace Kernel { KSharedMemory::KSharedMemory(KernelCore& kernel_) : KAutoObjectWithSlabHeapAndContainer{kernel_} {} - -KSharedMemory::~KSharedMemory() { - kernel.GetSystemResourceLimit()->Release(LimitableResource::PhysicalMemoryMax, size); -} +KSharedMemory::~KSharedMemory() = default; Result KSharedMemory::Initialize(Core::DeviceMemory& device_memory_, KProcess* owner_process_, - KPageGroup&& page_list_, Svc::MemoryPermission owner_permission_, - Svc::MemoryPermission user_permission_, PAddr physical_address_, - std::size_t size_, std::string name_) { + Svc::MemoryPermission owner_permission_, + Svc::MemoryPermission user_permission_, std::size_t size_, + std::string name_) { // Set members. owner_process = owner_process_; device_memory = &device_memory_; - page_list = std::move(page_list_); owner_permission = owner_permission_; user_permission = user_permission_; - physical_address = physical_address_; - size = size_; + size = Common::AlignUp(size_, PageSize); name = std::move(name_); + const size_t num_pages = Common::DivideUp(size, PageSize); + // Get the resource limit. KResourceLimit* reslimit = kernel.GetSystemResourceLimit(); @@ -39,6 +37,18 @@ Result KSharedMemory::Initialize(Core::DeviceMemory& device_memory_, KProcess* o size_); R_UNLESS(memory_reservation.Succeeded(), ResultLimitReached); + // Allocate the memory. + + //! HACK: Open continuous mapping from sysmodule pool. + auto option = KMemoryManager::EncodeOption(KMemoryManager::Pool::Secure, + KMemoryManager::Direction::FromBack); + physical_address = kernel.MemoryManager().AllocateAndOpenContinuous(num_pages, 1, option); + R_UNLESS(physical_address != 0, ResultOutOfMemory); + + //! Insert the result into our page group. + page_group.emplace(kernel, &kernel.GetSystemSystemResource().GetBlockInfoManager()); + page_group->AddBlock(physical_address, num_pages); + // Commit our reservation. memory_reservation.Commit(); @@ -50,12 +60,18 @@ Result KSharedMemory::Initialize(Core::DeviceMemory& device_memory_, KProcess* o is_initialized = true; // Clear all pages in the memory. - std::memset(device_memory_.GetPointer<void>(physical_address_), 0, size_); + for (const auto& block : *page_group) { + std::memset(device_memory_.GetPointer<void>(block.GetAddress()), 0, block.GetSize()); + } return ResultSuccess; } void KSharedMemory::Finalize() { + // Close and finalize the page group. + page_group->Close(); + page_group->Finalize(); + // Release the memory reservation. resource_limit->Release(LimitableResource::PhysicalMemoryMax, size); resource_limit->Close(); @@ -65,32 +81,28 @@ void KSharedMemory::Finalize() { } Result KSharedMemory::Map(KProcess& target_process, VAddr address, std::size_t map_size, - Svc::MemoryPermission permissions) { - const u64 page_count{(map_size + PageSize - 1) / PageSize}; - - if (page_list.GetNumPages() != page_count) { - UNIMPLEMENTED_MSG("Page count does not match"); - } + Svc::MemoryPermission map_perm) { + // Validate the size. + R_UNLESS(size == map_size, ResultInvalidSize); - const Svc::MemoryPermission expected = + // Validate the permission. + const Svc::MemoryPermission test_perm = &target_process == owner_process ? owner_permission : user_permission; - - if (permissions != expected) { - UNIMPLEMENTED_MSG("Permission does not match"); + if (test_perm == Svc::MemoryPermission::DontCare) { + ASSERT(map_perm == Svc::MemoryPermission::Read || map_perm == Svc::MemoryPermission::Write); + } else { + R_UNLESS(map_perm == test_perm, ResultInvalidNewMemoryPermission); } - return target_process.PageTable().MapPages(address, page_list, KMemoryState::Shared, - ConvertToKMemoryPermission(permissions)); + return target_process.PageTable().MapPages(address, *page_group, KMemoryState::Shared, + ConvertToKMemoryPermission(map_perm)); } Result KSharedMemory::Unmap(KProcess& target_process, VAddr address, std::size_t unmap_size) { - const u64 page_count{(unmap_size + PageSize - 1) / PageSize}; - - if (page_list.GetNumPages() != page_count) { - UNIMPLEMENTED_MSG("Page count does not match"); - } + // Validate the size. + R_UNLESS(size == unmap_size, ResultInvalidSize); - return target_process.PageTable().UnmapPages(address, page_list, KMemoryState::Shared); + return target_process.PageTable().UnmapPages(address, *page_group, KMemoryState::Shared); } } // namespace Kernel diff --git a/src/core/hle/kernel/k_shared_memory.h b/src/core/hle/kernel/k_shared_memory.h index a96c55a3e..8b29f0b4a 100644 --- a/src/core/hle/kernel/k_shared_memory.h +++ b/src/core/hle/kernel/k_shared_memory.h @@ -3,6 +3,7 @@ #pragma once +#include <optional> #include <string> #include "common/common_types.h" @@ -26,9 +27,8 @@ public: ~KSharedMemory() override; Result Initialize(Core::DeviceMemory& device_memory_, KProcess* owner_process_, - KPageGroup&& page_list_, Svc::MemoryPermission owner_permission_, - Svc::MemoryPermission user_permission_, PAddr physical_address_, - std::size_t size_, std::string name_); + Svc::MemoryPermission owner_permission_, + Svc::MemoryPermission user_permission_, std::size_t size_, std::string name_); /** * Maps a shared memory block to an address in the target process' address space @@ -76,7 +76,7 @@ public: private: Core::DeviceMemory* device_memory{}; KProcess* owner_process{}; - KPageGroup page_list; + std::optional<KPageGroup> page_group{}; Svc::MemoryPermission owner_permission{}; Svc::MemoryPermission user_permission{}; PAddr physical_address{}; diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index dc52b4ed3..7cd94a340 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h @@ -22,6 +22,7 @@ #include "core/hle/kernel/k_light_lock.h" #include "core/hle/kernel/k_spin_lock.h" #include "core/hle/kernel/k_synchronization_object.h" +#include "core/hle/kernel/k_timer_task.h" #include "core/hle/kernel/k_worker_task.h" #include "core/hle/kernel/slab_helpers.h" #include "core/hle/kernel/svc_common.h" @@ -112,7 +113,8 @@ void SetCurrentThread(KernelCore& kernel, KThread* thread); [[nodiscard]] s32 GetCurrentCoreId(KernelCore& kernel); class KThread final : public KAutoObjectWithSlabHeapAndContainer<KThread, KWorkerTask>, - public boost::intrusive::list_base_hook<> { + public boost::intrusive::list_base_hook<>, + public KTimerTask { KERNEL_AUTOOBJECT_TRAITS(KThread, KSynchronizationObject); private: @@ -840,4 +842,8 @@ private: KernelCore& kernel; }; +inline void KTimerTask::OnTimer() { + static_cast<KThread*>(this)->OnTimer(); +} + } // namespace Kernel diff --git a/src/core/hle/kernel/k_thread_queue.cpp b/src/core/hle/kernel/k_thread_queue.cpp index 9f4e081ba..5f1dc97eb 100644 --- a/src/core/hle/kernel/k_thread_queue.cpp +++ b/src/core/hle/kernel/k_thread_queue.cpp @@ -1,9 +1,9 @@ // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "core/hle/kernel/k_hardware_timer.h" #include "core/hle/kernel/k_thread_queue.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/time_manager.h" namespace Kernel { @@ -22,7 +22,7 @@ void KThreadQueue::EndWait(KThread* waiting_thread, Result wait_result) { waiting_thread->ClearWaitQueue(); // Cancel the thread task. - kernel.TimeManager().UnscheduleTimeEvent(waiting_thread); + kernel.HardwareTimer().CancelTask(waiting_thread); } void KThreadQueue::CancelWait(KThread* waiting_thread, Result wait_result, bool cancel_timer_task) { @@ -37,7 +37,7 @@ void KThreadQueue::CancelWait(KThread* waiting_thread, Result wait_result, bool // Cancel the thread task. if (cancel_timer_task) { - kernel.TimeManager().UnscheduleTimeEvent(waiting_thread); + kernel.HardwareTimer().CancelTask(waiting_thread); } } diff --git a/src/core/hle/kernel/k_timer_task.h b/src/core/hle/kernel/k_timer_task.h new file mode 100644 index 000000000..66f0a5a90 --- /dev/null +++ b/src/core/hle/kernel/k_timer_task.h @@ -0,0 +1,40 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/intrusive_red_black_tree.h" + +namespace Kernel { + +class KTimerTask : public Common::IntrusiveRedBlackTreeBaseNode<KTimerTask> { +public: + static constexpr int Compare(const KTimerTask& lhs, const KTimerTask& rhs) { + if (lhs.GetTime() < rhs.GetTime()) { + return -1; + } else { + return 1; + } + } + + constexpr explicit KTimerTask() = default; + + constexpr void SetTime(s64 t) { + m_time = t; + } + + constexpr s64 GetTime() const { + return m_time; + } + + // NOTE: This is virtual in Nintendo's kernel. Prior to 13.0.0, KWaitObject was also a + // TimerTask; this is no longer the case. Since this is now KThread exclusive, we have + // devirtualized (see inline declaration for this inside k_thread.h). + void OnTimer(); + +private: + // Absolute time in nanoseconds + s64 m_time{}; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 288f97df5..1fb25f221 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -26,6 +26,7 @@ #include "core/hle/kernel/k_client_port.h" #include "core/hle/kernel/k_dynamic_resource_manager.h" #include "core/hle/kernel/k_handle_table.h" +#include "core/hle/kernel/k_hardware_timer.h" #include "core/hle/kernel/k_memory_layout.h" #include "core/hle/kernel/k_memory_manager.h" #include "core/hle/kernel/k_page_buffer.h" @@ -39,7 +40,6 @@ #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/physical_core.h" #include "core/hle/kernel/service_thread.h" -#include "core/hle/kernel/time_manager.h" #include "core/hle/result.h" #include "core/hle/service/sm/sm.h" #include "core/memory.h" @@ -55,7 +55,7 @@ struct KernelCore::Impl { static constexpr size_t ReservedDynamicPageCount = 64; explicit Impl(Core::System& system_, KernelCore& kernel_) - : time_manager{system_}, service_threads_manager{1, "ServiceThreadsManager"}, + : service_threads_manager{1, "ServiceThreadsManager"}, service_thread_barrier{2}, system{system_} {} void SetMulticore(bool is_multi) { @@ -63,6 +63,9 @@ struct KernelCore::Impl { } void Initialize(KernelCore& kernel) { + hardware_timer = std::make_unique<Kernel::KHardwareTimer>(kernel); + hardware_timer->Initialize(); + global_object_list_container = std::make_unique<KAutoObjectWithListContainer>(kernel); global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel); global_handle_table = std::make_unique<Kernel::KHandleTable>(kernel); @@ -91,6 +94,7 @@ struct KernelCore::Impl { pt_heap_region.GetSize()); } + InitializeHackSharedMemory(); RegisterHostThread(nullptr); default_service_thread = &CreateServiceThread(kernel, "DefaultServiceThread"); @@ -104,12 +108,16 @@ struct KernelCore::Impl { } void CloseCurrentProcess() { - (*current_process).Finalize(); - // current_process->Close(); - // TODO: The current process should be destroyed based on accurate ref counting after + KProcess* old_process = current_process.exchange(nullptr); + if (old_process == nullptr) { + return; + } + + // old_process->Close(); + // TODO: The process should be destroyed based on accurate ref counting after // calling Close(). Adding a manual Destroy() call instead to avoid a memory leak. - (*current_process).Destroy(); - current_process = nullptr; + old_process->Finalize(); + old_process->Destroy(); } void Shutdown() { @@ -189,6 +197,9 @@ struct KernelCore::Impl { // Ensure that the object list container is finalized and properly shutdown. global_object_list_container->Finalize(); global_object_list_container.reset(); + + hardware_timer->Finalize(); + hardware_timer.reset(); } void CloseServices() { @@ -716,14 +727,14 @@ struct KernelCore::Impl { } void InitializeMemoryLayout() { - const auto system_pool = memory_layout->GetKernelSystemPoolRegionPhysicalExtents(); - // Initialize the memory manager. memory_manager = std::make_unique<KMemoryManager>(system); const auto& management_region = memory_layout->GetPoolManagementRegion(); ASSERT(management_region.GetEndAddress() != 0); memory_manager->Initialize(management_region.GetAddress(), management_region.GetSize()); + } + void InitializeHackSharedMemory() { // Setup memory regions for emulated processes // TODO(bunnei): These should not be hardcoded regions initialized within the kernel constexpr std::size_t hid_size{0x40000}; @@ -732,39 +743,23 @@ struct KernelCore::Impl { constexpr std::size_t time_size{0x1000}; constexpr std::size_t hidbus_size{0x1000}; - const PAddr hid_phys_addr{system_pool.GetAddress()}; - const PAddr font_phys_addr{system_pool.GetAddress() + hid_size}; - const PAddr irs_phys_addr{system_pool.GetAddress() + hid_size + font_size}; - const PAddr time_phys_addr{system_pool.GetAddress() + hid_size + font_size + irs_size}; - const PAddr hidbus_phys_addr{system_pool.GetAddress() + hid_size + font_size + irs_size + - time_size}; - hid_shared_mem = KSharedMemory::Create(system.Kernel()); font_shared_mem = KSharedMemory::Create(system.Kernel()); irs_shared_mem = KSharedMemory::Create(system.Kernel()); time_shared_mem = KSharedMemory::Create(system.Kernel()); hidbus_shared_mem = KSharedMemory::Create(system.Kernel()); - hid_shared_mem->Initialize(system.DeviceMemory(), nullptr, - {hid_phys_addr, hid_size / PageSize}, - Svc::MemoryPermission::None, Svc::MemoryPermission::Read, - hid_phys_addr, hid_size, "HID:SharedMemory"); - font_shared_mem->Initialize(system.DeviceMemory(), nullptr, - {font_phys_addr, font_size / PageSize}, - Svc::MemoryPermission::None, Svc::MemoryPermission::Read, - font_phys_addr, font_size, "Font:SharedMemory"); - irs_shared_mem->Initialize(system.DeviceMemory(), nullptr, - {irs_phys_addr, irs_size / PageSize}, - Svc::MemoryPermission::None, Svc::MemoryPermission::Read, - irs_phys_addr, irs_size, "IRS:SharedMemory"); - time_shared_mem->Initialize(system.DeviceMemory(), nullptr, - {time_phys_addr, time_size / PageSize}, - Svc::MemoryPermission::None, Svc::MemoryPermission::Read, - time_phys_addr, time_size, "Time:SharedMemory"); - hidbus_shared_mem->Initialize(system.DeviceMemory(), nullptr, - {hidbus_phys_addr, hidbus_size / PageSize}, - Svc::MemoryPermission::None, Svc::MemoryPermission::Read, - hidbus_phys_addr, hidbus_size, "HidBus:SharedMemory"); + hid_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None, + Svc::MemoryPermission::Read, hid_size, "HID:SharedMemory"); + font_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None, + Svc::MemoryPermission::Read, font_size, "Font:SharedMemory"); + irs_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None, + Svc::MemoryPermission::Read, irs_size, "IRS:SharedMemory"); + time_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None, + Svc::MemoryPermission::Read, time_size, "Time:SharedMemory"); + hidbus_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None, + Svc::MemoryPermission::Read, hidbus_size, + "HidBus:SharedMemory"); } KClientPort* CreateNamedServicePort(std::string name) { @@ -828,7 +823,7 @@ struct KernelCore::Impl { std::vector<KProcess*> process_list; std::atomic<KProcess*> current_process{}; std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context; - Kernel::TimeManager time_manager; + std::unique_ptr<Kernel::KHardwareTimer> hardware_timer; Init::KSlabResourceCounts slab_resource_counts{}; KResourceLimit* system_resource_limit{}; @@ -1015,12 +1010,8 @@ Kernel::KScheduler* KernelCore::CurrentScheduler() { return impl->schedulers[core_id].get(); } -Kernel::TimeManager& KernelCore::TimeManager() { - return impl->time_manager; -} - -const Kernel::TimeManager& KernelCore::TimeManager() const { - return impl->time_manager; +Kernel::KHardwareTimer& KernelCore::HardwareTimer() { + return *impl->hardware_timer; } Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() { diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 2e22fe0f6..8d22f8d2c 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -39,6 +39,7 @@ class KDynamicPageManager; class KEvent; class KEventInfo; class KHandleTable; +class KHardwareTimer; class KLinkedListNode; class KMemoryLayout; class KMemoryManager; @@ -63,7 +64,6 @@ class KCodeMemory; class PhysicalCore; class ServiceThread; class Synchronization; -class TimeManager; using ServiceInterfaceFactory = std::function<KClientPort&(Service::SM::ServiceManager&, Core::System&)>; @@ -175,11 +175,8 @@ public: /// Gets the an instance of the current physical CPU core. const Kernel::PhysicalCore& CurrentPhysicalCore() const; - /// Gets the an instance of the TimeManager Interface. - Kernel::TimeManager& TimeManager(); - - /// Gets the an instance of the TimeManager Interface. - const Kernel::TimeManager& TimeManager() const; + /// Gets the an instance of the hardware timer. + Kernel::KHardwareTimer& HardwareTimer(); /// Stops execution of 'id' core, in order to reschedule a new thread. void PrepareReschedule(std::size_t id); diff --git a/src/core/hle/kernel/memory_types.h b/src/core/hle/kernel/memory_types.h index 3975507bd..92b8b37ac 100644 --- a/src/core/hle/kernel/memory_types.h +++ b/src/core/hle/kernel/memory_types.h @@ -14,4 +14,7 @@ constexpr std::size_t PageSize{1 << PageBits}; using Page = std::array<u8, PageSize>; +using KPhysicalAddress = PAddr; +using KProcessAddress = VAddr; + } // namespace Kernel diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index e520cab47..aca442196 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -784,63 +784,29 @@ static Result GetInfo(Core::System& system, u64* result, u64 info_id, Handle han LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id, info_sub_id, handle); - enum class GetInfoType : u64 { - // 1.0.0+ - AllowedCPUCoreMask = 0, - AllowedThreadPriorityMask = 1, - MapRegionBaseAddr = 2, - MapRegionSize = 3, - HeapRegionBaseAddr = 4, - HeapRegionSize = 5, - TotalPhysicalMemoryAvailable = 6, - TotalPhysicalMemoryUsed = 7, - IsCurrentProcessBeingDebugged = 8, - RegisterResourceLimit = 9, - IdleTickCount = 10, - RandomEntropy = 11, - ThreadTickCount = 0xF0000002, - // 2.0.0+ - ASLRRegionBaseAddr = 12, - ASLRRegionSize = 13, - StackRegionBaseAddr = 14, - StackRegionSize = 15, - // 3.0.0+ - SystemResourceSize = 16, - SystemResourceUsage = 17, - TitleId = 18, - // 4.0.0+ - PrivilegedProcessId = 19, - // 5.0.0+ - UserExceptionContextAddr = 20, - // 6.0.0+ - TotalPhysicalMemoryAvailableWithoutSystemResource = 21, - TotalPhysicalMemoryUsedWithoutSystemResource = 22, - - // Homebrew only - MesosphereCurrentProcess = 65001, - }; - - const auto info_id_type = static_cast<GetInfoType>(info_id); + const auto info_id_type = static_cast<InfoType>(info_id); switch (info_id_type) { - case GetInfoType::AllowedCPUCoreMask: - case GetInfoType::AllowedThreadPriorityMask: - case GetInfoType::MapRegionBaseAddr: - case GetInfoType::MapRegionSize: - case GetInfoType::HeapRegionBaseAddr: - case GetInfoType::HeapRegionSize: - case GetInfoType::ASLRRegionBaseAddr: - case GetInfoType::ASLRRegionSize: - case GetInfoType::StackRegionBaseAddr: - case GetInfoType::StackRegionSize: - case GetInfoType::TotalPhysicalMemoryAvailable: - case GetInfoType::TotalPhysicalMemoryUsed: - case GetInfoType::SystemResourceSize: - case GetInfoType::SystemResourceUsage: - case GetInfoType::TitleId: - case GetInfoType::UserExceptionContextAddr: - case GetInfoType::TotalPhysicalMemoryAvailableWithoutSystemResource: - case GetInfoType::TotalPhysicalMemoryUsedWithoutSystemResource: { + case InfoType::CoreMask: + case InfoType::PriorityMask: + case InfoType::AliasRegionAddress: + case InfoType::AliasRegionSize: + case InfoType::HeapRegionAddress: + case InfoType::HeapRegionSize: + case InfoType::AslrRegionAddress: + case InfoType::AslrRegionSize: + case InfoType::StackRegionAddress: + case InfoType::StackRegionSize: + case InfoType::TotalMemorySize: + case InfoType::UsedMemorySize: + case InfoType::SystemResourceSizeTotal: + case InfoType::SystemResourceSizeUsed: + case InfoType::ProgramId: + case InfoType::UserExceptionContextAddress: + case InfoType::TotalNonSystemMemorySize: + case InfoType::UsedNonSystemMemorySize: + case InfoType::IsApplication: + case InfoType::FreeThreadCount: { if (info_sub_id != 0) { LOG_ERROR(Kernel_SVC, "Info sub id is non zero! info_id={}, info_sub_id={}", info_id, info_sub_id); @@ -856,79 +822,83 @@ static Result GetInfo(Core::System& system, u64* result, u64 info_id, Handle han } switch (info_id_type) { - case GetInfoType::AllowedCPUCoreMask: + case InfoType::CoreMask: *result = process->GetCoreMask(); return ResultSuccess; - case GetInfoType::AllowedThreadPriorityMask: + case InfoType::PriorityMask: *result = process->GetPriorityMask(); return ResultSuccess; - case GetInfoType::MapRegionBaseAddr: + case InfoType::AliasRegionAddress: *result = process->PageTable().GetAliasRegionStart(); return ResultSuccess; - case GetInfoType::MapRegionSize: + case InfoType::AliasRegionSize: *result = process->PageTable().GetAliasRegionSize(); return ResultSuccess; - case GetInfoType::HeapRegionBaseAddr: + case InfoType::HeapRegionAddress: *result = process->PageTable().GetHeapRegionStart(); return ResultSuccess; - case GetInfoType::HeapRegionSize: + case InfoType::HeapRegionSize: *result = process->PageTable().GetHeapRegionSize(); return ResultSuccess; - case GetInfoType::ASLRRegionBaseAddr: + case InfoType::AslrRegionAddress: *result = process->PageTable().GetAliasCodeRegionStart(); return ResultSuccess; - case GetInfoType::ASLRRegionSize: + case InfoType::AslrRegionSize: *result = process->PageTable().GetAliasCodeRegionSize(); return ResultSuccess; - case GetInfoType::StackRegionBaseAddr: + case InfoType::StackRegionAddress: *result = process->PageTable().GetStackRegionStart(); return ResultSuccess; - case GetInfoType::StackRegionSize: + case InfoType::StackRegionSize: *result = process->PageTable().GetStackRegionSize(); return ResultSuccess; - case GetInfoType::TotalPhysicalMemoryAvailable: + case InfoType::TotalMemorySize: *result = process->GetTotalPhysicalMemoryAvailable(); return ResultSuccess; - case GetInfoType::TotalPhysicalMemoryUsed: + case InfoType::UsedMemorySize: *result = process->GetTotalPhysicalMemoryUsed(); return ResultSuccess; - case GetInfoType::SystemResourceSize: + case InfoType::SystemResourceSizeTotal: *result = process->GetSystemResourceSize(); return ResultSuccess; - case GetInfoType::SystemResourceUsage: + case InfoType::SystemResourceSizeUsed: LOG_WARNING(Kernel_SVC, "(STUBBED) Attempted to query system resource usage"); *result = process->GetSystemResourceUsage(); return ResultSuccess; - case GetInfoType::TitleId: + case InfoType::ProgramId: *result = process->GetProgramID(); return ResultSuccess; - case GetInfoType::UserExceptionContextAddr: + case InfoType::UserExceptionContextAddress: *result = process->GetProcessLocalRegionAddress(); return ResultSuccess; - case GetInfoType::TotalPhysicalMemoryAvailableWithoutSystemResource: + case InfoType::TotalNonSystemMemorySize: *result = process->GetTotalPhysicalMemoryAvailableWithoutSystemResource(); return ResultSuccess; - case GetInfoType::TotalPhysicalMemoryUsedWithoutSystemResource: + case InfoType::UsedNonSystemMemorySize: *result = process->GetTotalPhysicalMemoryUsedWithoutSystemResource(); return ResultSuccess; + case InfoType::FreeThreadCount: + *result = process->GetFreeThreadCount(); + return ResultSuccess; + default: break; } @@ -937,11 +907,11 @@ static Result GetInfo(Core::System& system, u64* result, u64 info_id, Handle han return ResultInvalidEnumValue; } - case GetInfoType::IsCurrentProcessBeingDebugged: + case InfoType::DebuggerAttached: *result = 0; return ResultSuccess; - case GetInfoType::RegisterResourceLimit: { + case InfoType::ResourceLimit: { if (handle != 0) { LOG_ERROR(Kernel, "Handle is non zero! handle={:08X}", handle); return ResultInvalidHandle; @@ -969,7 +939,7 @@ static Result GetInfo(Core::System& system, u64* result, u64 info_id, Handle han return ResultSuccess; } - case GetInfoType::RandomEntropy: + case InfoType::RandomEntropy: if (handle != 0) { LOG_ERROR(Kernel_SVC, "Process Handle is non zero, expected 0 result but got {:016X}", handle); @@ -985,13 +955,13 @@ static Result GetInfo(Core::System& system, u64* result, u64 info_id, Handle han *result = system.Kernel().CurrentProcess()->GetRandomEntropy(info_sub_id); return ResultSuccess; - case GetInfoType::PrivilegedProcessId: + case InfoType::InitialProcessIdRange: LOG_WARNING(Kernel_SVC, "(STUBBED) Attempted to query privileged process id bounds, returned 0"); *result = 0; return ResultSuccess; - case GetInfoType::ThreadTickCount: { + case InfoType::ThreadTickCount: { constexpr u64 num_cpus = 4; if (info_sub_id != 0xFFFFFFFFFFFFFFFF && info_sub_id >= num_cpus) { LOG_ERROR(Kernel_SVC, "Core count is out of range, expected {} but got {}", num_cpus, @@ -1026,7 +996,7 @@ static Result GetInfo(Core::System& system, u64* result, u64 info_id, Handle han *result = out_ticks; return ResultSuccess; } - case GetInfoType::IdleTickCount: { + case InfoType::IdleTickCount: { // Verify the input handle is invalid. R_UNLESS(handle == InvalidHandle, ResultInvalidHandle); @@ -1040,7 +1010,7 @@ static Result GetInfo(Core::System& system, u64* result, u64 info_id, Handle han *result = system.Kernel().CurrentScheduler()->GetIdleThread()->GetCpuTime(); return ResultSuccess; } - case GetInfoType::MesosphereCurrentProcess: { + case InfoType::MesosphereCurrentProcess: { // Verify the input handle is invalid. R_UNLESS(handle == InvalidHandle, ResultInvalidHandle); @@ -1515,7 +1485,7 @@ static Result MapProcessMemory(Core::System& system, VAddr dst_address, Handle p ResultInvalidMemoryRegion); // Create a new page group. - KPageGroup pg; + KPageGroup pg{system.Kernel(), dst_pt.GetBlockInfoManager()}; R_TRY(src_pt.MakeAndOpenPageGroup( std::addressof(pg), src_address, size / PageSize, KMemoryState::FlagCanMapProcess, KMemoryState::FlagCanMapProcess, KMemoryPermission::None, KMemoryPermission::None, diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp deleted file mode 100644 index 5ee72c432..000000000 --- a/src/core/hle/kernel/time_manager.cpp +++ /dev/null @@ -1,44 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "common/assert.h" -#include "core/core.h" -#include "core/core_timing.h" -#include "core/hle/kernel/k_scheduler.h" -#include "core/hle/kernel/k_thread.h" -#include "core/hle/kernel/time_manager.h" - -namespace Kernel { - -TimeManager::TimeManager(Core::System& system_) : system{system_} { - time_manager_event_type = Core::Timing::CreateEvent( - "Kernel::TimeManagerCallback", - [this](std::uintptr_t thread_handle, s64 time, - std::chrono::nanoseconds) -> std::optional<std::chrono::nanoseconds> { - KThread* thread = reinterpret_cast<KThread*>(thread_handle); - { - KScopedSchedulerLock sl(system.Kernel()); - thread->OnTimer(); - } - return std::nullopt; - }); -} - -void TimeManager::ScheduleTimeEvent(KThread* thread, s64 nanoseconds) { - std::scoped_lock lock{mutex}; - if (nanoseconds > 0) { - ASSERT(thread); - ASSERT(thread->GetState() != ThreadState::Runnable); - system.CoreTiming().ScheduleEvent(std::chrono::nanoseconds{nanoseconds}, - time_manager_event_type, - reinterpret_cast<uintptr_t>(thread)); - } -} - -void TimeManager::UnscheduleTimeEvent(KThread* thread) { - std::scoped_lock lock{mutex}; - system.CoreTiming().UnscheduleEvent(time_manager_event_type, - reinterpret_cast<uintptr_t>(thread)); -} - -} // namespace Kernel diff --git a/src/core/hle/kernel/time_manager.h b/src/core/hle/kernel/time_manager.h deleted file mode 100644 index 94d16b3b4..000000000 --- a/src/core/hle/kernel/time_manager.h +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include <memory> -#include <mutex> - -namespace Core { -class System; -} // namespace Core - -namespace Core::Timing { -struct EventType; -} // namespace Core::Timing - -namespace Kernel { - -class KThread; - -/** - * The `TimeManager` takes care of scheduling time events on threads and executes their TimeUp - * method when the event is triggered. - */ -class TimeManager { -public: - explicit TimeManager(Core::System& system); - - /// Schedule a time event on `timetask` thread that will expire in 'nanoseconds' - void ScheduleTimeEvent(KThread* time_task, s64 nanoseconds); - - /// Unschedule an existing time event - void UnscheduleTimeEvent(KThread* thread); - -private: - Core::System& system; - std::shared_ptr<Core::Timing::EventType> time_manager_event_type; - std::mutex mutex; -}; - -} // namespace Kernel |