early-access version 4035
This commit is contained in:
@@ -978,6 +978,7 @@ endif()
|
||||
|
||||
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
|
||||
target_sources(core PRIVATE
|
||||
arm/dynarmic/arm_dynarmic.cpp
|
||||
arm/dynarmic/arm_dynarmic.h
|
||||
arm/dynarmic/arm_dynarmic_64.cpp
|
||||
arm/dynarmic/arm_dynarmic_64.h
|
||||
|
49
src/core/arm/dynarmic/arm_dynarmic.cpp
Executable file
49
src/core/arm/dynarmic/arm_dynarmic.cpp
Executable file
@@ -0,0 +1,49 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#include "common/signal_chain.h"
|
||||
|
||||
#include "core/arm/dynarmic/arm_dynarmic.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace Core {
|
||||
|
||||
namespace {
|
||||
|
||||
thread_local Core::Memory::Memory* g_current_memory{};
|
||||
std::once_flag g_registered{};
|
||||
struct sigaction g_old_segv {};
|
||||
|
||||
void HandleSigSegv(int sig, siginfo_t* info, void* ctx) {
|
||||
if (g_current_memory && g_current_memory->InvalidateSeparateHeap(info->si_addr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return g_old_segv.sa_sigaction(sig, info, ctx);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ScopedJitExecution::ScopedJitExecution(Kernel::KProcess* process) {
|
||||
g_current_memory = std::addressof(process->GetMemory());
|
||||
}
|
||||
|
||||
ScopedJitExecution::~ScopedJitExecution() {
|
||||
g_current_memory = nullptr;
|
||||
}
|
||||
|
||||
void ScopedJitExecution::RegisterHandler() {
|
||||
std::call_once(g_registered, [] {
|
||||
struct sigaction sa {};
|
||||
sa.sa_sigaction = &HandleSigSegv;
|
||||
sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
|
||||
Common::SigAction(SIGSEGV, std::addressof(sa), std::addressof(g_old_segv));
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace Core
|
||||
|
||||
#endif
|
@@ -26,4 +26,24 @@ constexpr HaltReason TranslateHaltReason(Dynarmic::HaltReason hr) {
|
||||
return static_cast<HaltReason>(hr);
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
class ScopedJitExecution {
|
||||
public:
|
||||
explicit ScopedJitExecution(Kernel::KProcess* process);
|
||||
~ScopedJitExecution();
|
||||
static void RegisterHandler();
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
class ScopedJitExecution {
|
||||
public:
|
||||
explicit ScopedJitExecution(Kernel::KProcess* process) {}
|
||||
~ScopedJitExecution() {}
|
||||
static void RegisterHandler() {}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace Core
|
||||
|
@@ -331,11 +331,15 @@ bool ArmDynarmic32::IsInThumbMode() const {
|
||||
}
|
||||
|
||||
HaltReason ArmDynarmic32::RunThread(Kernel::KThread* thread) {
|
||||
ScopedJitExecution sj(thread->GetOwnerProcess());
|
||||
|
||||
m_jit->ClearExclusiveState();
|
||||
return TranslateHaltReason(m_jit->Run());
|
||||
}
|
||||
|
||||
HaltReason ArmDynarmic32::StepThread(Kernel::KThread* thread) {
|
||||
ScopedJitExecution sj(thread->GetOwnerProcess());
|
||||
|
||||
m_jit->ClearExclusiveState();
|
||||
return TranslateHaltReason(m_jit->Step());
|
||||
}
|
||||
@@ -377,6 +381,7 @@ ArmDynarmic32::ArmDynarmic32(System& system, bool uses_wall_clock, Kernel::KProc
|
||||
m_cp15(std::make_shared<DynarmicCP15>(*this)), m_core_index{core_index} {
|
||||
auto& page_table_impl = process->GetPageTable().GetBasePageTable().GetImpl();
|
||||
m_jit = MakeJit(&page_table_impl);
|
||||
ScopedJitExecution::RegisterHandler();
|
||||
}
|
||||
|
||||
ArmDynarmic32::~ArmDynarmic32() = default;
|
||||
|
@@ -362,11 +362,15 @@ std::shared_ptr<Dynarmic::A64::Jit> ArmDynarmic64::MakeJit(Common::PageTable* pa
|
||||
}
|
||||
|
||||
HaltReason ArmDynarmic64::RunThread(Kernel::KThread* thread) {
|
||||
ScopedJitExecution sj(thread->GetOwnerProcess());
|
||||
|
||||
m_jit->ClearExclusiveState();
|
||||
return TranslateHaltReason(m_jit->Run());
|
||||
}
|
||||
|
||||
HaltReason ArmDynarmic64::StepThread(Kernel::KThread* thread) {
|
||||
ScopedJitExecution sj(thread->GetOwnerProcess());
|
||||
|
||||
m_jit->ClearExclusiveState();
|
||||
return TranslateHaltReason(m_jit->Step());
|
||||
}
|
||||
@@ -406,6 +410,7 @@ ArmDynarmic64::ArmDynarmic64(System& system, bool uses_wall_clock, Kernel::KProc
|
||||
auto& page_table = process->GetPageTable().GetBasePageTable();
|
||||
auto& page_table_impl = page_table.GetImpl();
|
||||
m_jit = MakeJit(&page_table_impl, page_table.GetAddressSpaceWidth());
|
||||
ScopedJitExecution::RegisterHandler();
|
||||
}
|
||||
|
||||
ArmDynarmic64::~ArmDynarmic64() = default;
|
||||
|
@@ -29,7 +29,6 @@ std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callbac
|
||||
struct CoreTiming::Event {
|
||||
s64 time;
|
||||
u64 fifo_order;
|
||||
std::uintptr_t user_data;
|
||||
std::weak_ptr<EventType> type;
|
||||
s64 reschedule_time;
|
||||
heap_t::handle_type handle{};
|
||||
@@ -67,17 +66,15 @@ void CoreTiming::Initialize(std::function<void()>&& on_thread_init_) {
|
||||
event_fifo_id = 0;
|
||||
shutting_down = false;
|
||||
cpu_ticks = 0;
|
||||
const auto empty_timed_callback = [](std::uintptr_t, u64, std::chrono::nanoseconds)
|
||||
-> std::optional<std::chrono::nanoseconds> { return std::nullopt; };
|
||||
ev_lost = CreateEvent("_lost_event", empty_timed_callback);
|
||||
if (is_multicore) {
|
||||
timer_thread = std::make_unique<std::jthread>(ThreadEntry, std::ref(*this));
|
||||
}
|
||||
}
|
||||
|
||||
void CoreTiming::ClearPendingEvents() {
|
||||
std::scoped_lock lock{basic_lock};
|
||||
std::scoped_lock lock{advance_lock, basic_lock};
|
||||
event_queue.clear();
|
||||
event.Set();
|
||||
}
|
||||
|
||||
void CoreTiming::Pause(bool is_paused) {
|
||||
@@ -119,14 +116,12 @@ bool CoreTiming::HasPendingEvents() const {
|
||||
}
|
||||
|
||||
void CoreTiming::ScheduleEvent(std::chrono::nanoseconds ns_into_future,
|
||||
const std::shared_ptr<EventType>& event_type,
|
||||
std::uintptr_t user_data, bool absolute_time) {
|
||||
const std::shared_ptr<EventType>& event_type, bool absolute_time) {
|
||||
{
|
||||
std::scoped_lock scope{basic_lock};
|
||||
const auto next_time{absolute_time ? ns_into_future : GetGlobalTimeNs() + ns_into_future};
|
||||
|
||||
auto h{event_queue.emplace(
|
||||
Event{next_time.count(), event_fifo_id++, user_data, event_type, 0})};
|
||||
auto h{event_queue.emplace(Event{next_time.count(), event_fifo_id++, event_type, 0})};
|
||||
(*h).handle = h;
|
||||
}
|
||||
|
||||
@@ -136,13 +131,13 @@ void CoreTiming::ScheduleEvent(std::chrono::nanoseconds ns_into_future,
|
||||
void CoreTiming::ScheduleLoopingEvent(std::chrono::nanoseconds start_time,
|
||||
std::chrono::nanoseconds resched_time,
|
||||
const std::shared_ptr<EventType>& event_type,
|
||||
std::uintptr_t user_data, bool absolute_time) {
|
||||
bool absolute_time) {
|
||||
{
|
||||
std::scoped_lock scope{basic_lock};
|
||||
const auto next_time{absolute_time ? start_time : GetGlobalTimeNs() + start_time};
|
||||
|
||||
auto h{event_queue.emplace(Event{next_time.count(), event_fifo_id++, user_data, event_type,
|
||||
resched_time.count()})};
|
||||
auto h{event_queue.emplace(
|
||||
Event{next_time.count(), event_fifo_id++, event_type, resched_time.count()})};
|
||||
(*h).handle = h;
|
||||
}
|
||||
|
||||
@@ -150,14 +145,14 @@ void CoreTiming::ScheduleLoopingEvent(std::chrono::nanoseconds start_time,
|
||||
}
|
||||
|
||||
void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type,
|
||||
std::uintptr_t user_data, bool wait) {
|
||||
UnscheduleEventType type) {
|
||||
{
|
||||
std::scoped_lock lk{basic_lock};
|
||||
|
||||
std::vector<heap_t::handle_type> to_remove;
|
||||
for (auto itr = event_queue.begin(); itr != event_queue.end(); itr++) {
|
||||
const Event& e = *itr;
|
||||
if (e.type.lock().get() == event_type.get() && e.user_data == user_data) {
|
||||
if (e.type.lock().get() == event_type.get()) {
|
||||
to_remove.push_back(itr->handle);
|
||||
}
|
||||
}
|
||||
@@ -165,10 +160,12 @@ void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type,
|
||||
for (auto h : to_remove) {
|
||||
event_queue.erase(h);
|
||||
}
|
||||
|
||||
event_type->sequence_number++;
|
||||
}
|
||||
|
||||
// Force any in-progress events to finish
|
||||
if (wait) {
|
||||
if (type == UnscheduleEventType::Wait) {
|
||||
std::scoped_lock lk{advance_lock};
|
||||
}
|
||||
}
|
||||
@@ -208,28 +205,31 @@ std::optional<s64> CoreTiming::Advance() {
|
||||
const Event& evt = event_queue.top();
|
||||
|
||||
if (const auto event_type{evt.type.lock()}) {
|
||||
if (evt.reschedule_time == 0) {
|
||||
const auto evt_user_data = evt.user_data;
|
||||
const auto evt_time = evt.time;
|
||||
const auto evt_time = evt.time;
|
||||
const auto evt_sequence_num = event_type->sequence_number;
|
||||
|
||||
if (evt.reschedule_time == 0) {
|
||||
event_queue.pop();
|
||||
|
||||
basic_lock.unlock();
|
||||
|
||||
event_type->callback(
|
||||
evt_user_data, evt_time,
|
||||
std::chrono::nanoseconds{GetGlobalTimeNs().count() - evt_time});
|
||||
evt_time, std::chrono::nanoseconds{GetGlobalTimeNs().count() - evt_time});
|
||||
|
||||
basic_lock.lock();
|
||||
} else {
|
||||
basic_lock.unlock();
|
||||
|
||||
const auto new_schedule_time{event_type->callback(
|
||||
evt.user_data, evt.time,
|
||||
std::chrono::nanoseconds{GetGlobalTimeNs().count() - evt.time})};
|
||||
evt_time, std::chrono::nanoseconds{GetGlobalTimeNs().count() - evt_time})};
|
||||
|
||||
basic_lock.lock();
|
||||
|
||||
if (evt_sequence_num != event_type->sequence_number) {
|
||||
// Heap handle is invalidated after external modification.
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto next_schedule_time{new_schedule_time.has_value()
|
||||
? new_schedule_time.value().count()
|
||||
: evt.reschedule_time};
|
||||
@@ -241,8 +241,8 @@ std::optional<s64> CoreTiming::Advance() {
|
||||
next_time = pause_end_time + next_schedule_time;
|
||||
}
|
||||
|
||||
event_queue.update(evt.handle, Event{next_time, event_fifo_id++, evt.user_data,
|
||||
evt.type, next_schedule_time, evt.handle});
|
||||
event_queue.update(evt.handle, Event{next_time, event_fifo_id++, evt.type,
|
||||
next_schedule_time, evt.handle});
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -22,17 +22,25 @@ namespace Core::Timing {
|
||||
|
||||
/// A callback that may be scheduled for a particular core timing event.
|
||||
using TimedCallback = std::function<std::optional<std::chrono::nanoseconds>(
|
||||
std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late)>;
|
||||
s64 time, std::chrono::nanoseconds ns_late)>;
|
||||
|
||||
/// Contains the characteristics of a particular event.
|
||||
struct EventType {
|
||||
explicit EventType(TimedCallback&& callback_, std::string&& name_)
|
||||
: callback{std::move(callback_)}, name{std::move(name_)} {}
|
||||
: callback{std::move(callback_)}, name{std::move(name_)}, sequence_number{0} {}
|
||||
|
||||
/// The event's callback function.
|
||||
TimedCallback callback;
|
||||
/// A pointer to the name of the event.
|
||||
const std::string name;
|
||||
/// A monotonic sequence number, incremented when this event is
|
||||
/// changed externally.
|
||||
size_t sequence_number;
|
||||
};
|
||||
|
||||
enum class UnscheduleEventType {
|
||||
Wait,
|
||||
NoWait,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -89,23 +97,17 @@ public:
|
||||
|
||||
/// Schedules an event in core timing
|
||||
void ScheduleEvent(std::chrono::nanoseconds ns_into_future,
|
||||
const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data = 0,
|
||||
bool absolute_time = false);
|
||||
const std::shared_ptr<EventType>& event_type, bool absolute_time = false);
|
||||
|
||||
/// Schedules an event which will automatically re-schedule itself with the given time, until
|
||||
/// unscheduled
|
||||
void ScheduleLoopingEvent(std::chrono::nanoseconds start_time,
|
||||
std::chrono::nanoseconds resched_time,
|
||||
const std::shared_ptr<EventType>& event_type,
|
||||
std::uintptr_t user_data = 0, bool absolute_time = false);
|
||||
bool absolute_time = false);
|
||||
|
||||
void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data,
|
||||
bool wait = true);
|
||||
|
||||
void UnscheduleEventWithoutWait(const std::shared_ptr<EventType>& event_type,
|
||||
std::uintptr_t user_data) {
|
||||
UnscheduleEvent(event_type, user_data, false);
|
||||
}
|
||||
void UnscheduleEvent(const std::shared_ptr<EventType>& event_type,
|
||||
UnscheduleEventType type = UnscheduleEventType::Wait);
|
||||
|
||||
void AddTicks(u64 ticks_to_add);
|
||||
|
||||
@@ -158,7 +160,6 @@ private:
|
||||
heap_t event_queue;
|
||||
u64 event_fifo_id = 0;
|
||||
|
||||
std::shared_ptr<EventType> ev_lost;
|
||||
Common::Event event{};
|
||||
Common::Event pause_event{};
|
||||
mutable std::mutex basic_lock;
|
||||
|
@@ -8,19 +8,22 @@
|
||||
namespace Kernel {
|
||||
|
||||
void KAutoObjectWithListContainer::Register(KAutoObjectWithList* obj) {
|
||||
KScopedLightLock lk(m_lock);
|
||||
// KScopedInterruptDisable di;
|
||||
KScopedSpinLock lk(m_lock);
|
||||
|
||||
m_object_list.insert_unique(*obj);
|
||||
}
|
||||
|
||||
void KAutoObjectWithListContainer::Unregister(KAutoObjectWithList* obj) {
|
||||
KScopedLightLock lk(m_lock);
|
||||
// KScopedInterruptDisable di;
|
||||
KScopedSpinLock lk(m_lock);
|
||||
|
||||
m_object_list.erase(*obj);
|
||||
}
|
||||
|
||||
size_t KAutoObjectWithListContainer::GetOwnedCount(KProcess* owner) {
|
||||
KScopedLightLock lk(m_lock);
|
||||
// KScopedInterruptDisable di;
|
||||
KScopedSpinLock lk(m_lock);
|
||||
|
||||
return std::count_if(m_object_list.begin(), m_object_list.end(),
|
||||
[&](const auto& obj) { return obj.GetOwner() == owner; });
|
||||
|
@@ -7,7 +7,7 @@
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "core/hle/kernel/k_auto_object.h"
|
||||
#include "core/hle/kernel/k_light_lock.h"
|
||||
#include "core/hle/kernel/k_spin_lock.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
@@ -21,32 +21,7 @@ public:
|
||||
|
||||
using ListType = boost::intrusive::rbtree<KAutoObjectWithList>;
|
||||
|
||||
class ListAccessor : public KScopedLightLock {
|
||||
public:
|
||||
explicit ListAccessor(KAutoObjectWithListContainer* container)
|
||||
: KScopedLightLock(container->m_lock), m_list(container->m_object_list) {}
|
||||
explicit ListAccessor(KAutoObjectWithListContainer& container)
|
||||
: KScopedLightLock(container.m_lock), m_list(container.m_object_list) {}
|
||||
|
||||
typename ListType::iterator begin() const {
|
||||
return m_list.begin();
|
||||
}
|
||||
|
||||
typename ListType::iterator end() const {
|
||||
return m_list.end();
|
||||
}
|
||||
|
||||
typename ListType::iterator find(typename ListType::const_reference ref) const {
|
||||
return m_list.find(ref);
|
||||
}
|
||||
|
||||
private:
|
||||
ListType& m_list;
|
||||
};
|
||||
|
||||
friend class ListAccessor;
|
||||
|
||||
KAutoObjectWithListContainer(KernelCore& kernel) : m_lock(kernel), m_object_list() {}
|
||||
KAutoObjectWithListContainer(KernelCore& kernel) : m_lock(), m_object_list() {}
|
||||
|
||||
void Initialize() {}
|
||||
void Finalize() {}
|
||||
@@ -56,7 +31,7 @@ public:
|
||||
size_t GetOwnedCount(KProcess* owner);
|
||||
|
||||
private:
|
||||
KLightLock m_lock;
|
||||
KSpinLock m_lock;
|
||||
ListType m_object_list;
|
||||
};
|
||||
|
||||
|
@@ -30,7 +30,7 @@ public:
|
||||
public:
|
||||
explicit KHandleTable(KernelCore& kernel) : m_kernel(kernel) {}
|
||||
|
||||
Result Initialize(KProcess* owner, s32 size) {
|
||||
Result Initialize(s32 size) {
|
||||
// Check that the table size is valid.
|
||||
R_UNLESS(size <= static_cast<s32>(MaxTableSize), ResultOutOfMemory);
|
||||
|
||||
@@ -44,7 +44,6 @@ public:
|
||||
m_next_linear_id = MinLinearId;
|
||||
m_count = 0;
|
||||
m_free_head_index = -1;
|
||||
m_owner = owner;
|
||||
|
||||
// Free all entries.
|
||||
for (s32 i = 0; i < static_cast<s32>(m_table_size); ++i) {
|
||||
@@ -91,8 +90,7 @@ public:
|
||||
// Handle pseudo-handles.
|
||||
if constexpr (std::derived_from<KProcess, T>) {
|
||||
if (handle == Svc::PseudoHandle::CurrentProcess) {
|
||||
// TODO: this should be the current process
|
||||
auto* const cur_process = m_owner;
|
||||
auto* const cur_process = GetCurrentProcessPointer(m_kernel);
|
||||
ASSERT(cur_process != nullptr);
|
||||
return cur_process;
|
||||
}
|
||||
@@ -302,7 +300,6 @@ private:
|
||||
|
||||
private:
|
||||
KernelCore& m_kernel;
|
||||
KProcess* m_owner{};
|
||||
std::array<EntryInfo, MaxTableSize> m_entry_infos{};
|
||||
std::array<KAutoObject*, MaxTableSize> m_objects{};
|
||||
mutable KSpinLock m_lock;
|
||||
|
@@ -10,15 +10,15 @@ 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;
|
||||
});
|
||||
m_event_type = Core::Timing::CreateEvent("KHardwareTimer::Callback",
|
||||
[this](s64, std::chrono::nanoseconds) {
|
||||
this->DoTask();
|
||||
return std::nullopt;
|
||||
});
|
||||
}
|
||||
|
||||
void KHardwareTimer::Finalize() {
|
||||
m_kernel.System().CoreTiming().UnscheduleEvent(m_event_type, reinterpret_cast<uintptr_t>(this));
|
||||
m_kernel.System().CoreTiming().UnscheduleEvent(m_event_type);
|
||||
m_wakeup_time = std::numeric_limits<s64>::max();
|
||||
m_event_type.reset();
|
||||
}
|
||||
@@ -57,13 +57,12 @@ void KHardwareTimer::EnableInterrupt(s64 wakeup_time) {
|
||||
|
||||
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);
|
||||
m_event_type, true);
|
||||
}
|
||||
|
||||
void KHardwareTimer::DisableInterrupt() {
|
||||
m_kernel.System().CoreTiming().UnscheduleEventWithoutWait(m_event_type,
|
||||
reinterpret_cast<uintptr_t>(this));
|
||||
m_kernel.System().CoreTiming().UnscheduleEvent(m_event_type,
|
||||
Core::Timing::UnscheduleEventType::NoWait);
|
||||
m_wakeup_time = std::numeric_limits<s64>::max();
|
||||
}
|
||||
|
||||
|
@@ -434,7 +434,7 @@ Result KPageTableBase::InitializeForProcess(Svc::CreateProcessFlag as_type, bool
|
||||
void KPageTableBase::Finalize() {
|
||||
auto HostUnmapCallback = [&](KProcessAddress addr, u64 size) {
|
||||
if (Settings::IsFastmemEnabled()) {
|
||||
m_system.DeviceMemory().buffer.Unmap(GetInteger(addr), size);
|
||||
m_system.DeviceMemory().buffer.Unmap(GetInteger(addr), size, false);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -5243,7 +5243,7 @@ Result KPageTableBase::MapPhysicalMemory(KProcessAddress address, size_t size) {
|
||||
// Unmap.
|
||||
R_ASSERT(this->Operate(updater.GetPageList(), cur_address,
|
||||
cur_pages, 0, false, unmap_properties,
|
||||
OperationType::Unmap, true));
|
||||
OperationType::UnmapPhysical, true));
|
||||
}
|
||||
|
||||
// Check if we're done.
|
||||
@@ -5326,7 +5326,7 @@ Result KPageTableBase::MapPhysicalMemory(KProcessAddress address, size_t size) {
|
||||
// Map the papges.
|
||||
R_TRY(this->Operate(updater.GetPageList(), cur_address, map_pages,
|
||||
cur_pg, map_properties,
|
||||
OperationType::MapFirstGroup, false));
|
||||
OperationType::MapFirstGroupPhysical, false));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5480,7 +5480,7 @@ Result KPageTableBase::UnmapPhysicalMemory(KProcessAddress address, size_t size)
|
||||
|
||||
// Unmap.
|
||||
R_ASSERT(this->Operate(updater.GetPageList(), cur_address, cur_pages, 0, false,
|
||||
unmap_properties, OperationType::Unmap, false));
|
||||
unmap_properties, OperationType::UnmapPhysical, false));
|
||||
}
|
||||
|
||||
// Check if we're done.
|
||||
@@ -5655,7 +5655,10 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a
|
||||
// or free them to the page list, and so it goes unused (along with page properties).
|
||||
|
||||
switch (operation) {
|
||||
case OperationType::Unmap: {
|
||||
case OperationType::Unmap:
|
||||
case OperationType::UnmapPhysical: {
|
||||
const bool separate_heap = operation == OperationType::UnmapPhysical;
|
||||
|
||||
// Ensure that any pages we track are closed on exit.
|
||||
KPageGroup pages_to_close(m_kernel, this->GetBlockInfoManager());
|
||||
SCOPE_EXIT({ pages_to_close.CloseAndReset(); });
|
||||
@@ -5664,7 +5667,7 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a
|
||||
this->MakePageGroup(pages_to_close, virt_addr, num_pages);
|
||||
|
||||
// Unmap.
|
||||
m_memory->UnmapRegion(*m_impl, virt_addr, num_pages * PageSize);
|
||||
m_memory->UnmapRegion(*m_impl, virt_addr, num_pages * PageSize, separate_heap);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
@@ -5672,7 +5675,7 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a
|
||||
ASSERT(virt_addr != 0);
|
||||
ASSERT(Common::IsAligned(GetInteger(virt_addr), PageSize));
|
||||
m_memory->MapMemoryRegion(*m_impl, virt_addr, num_pages * PageSize, phys_addr,
|
||||
ConvertToMemoryPermission(properties.perm));
|
||||
ConvertToMemoryPermission(properties.perm), false);
|
||||
|
||||
// Open references to pages, if we should.
|
||||
if (this->IsHeapPhysicalAddress(phys_addr)) {
|
||||
@@ -5711,16 +5714,19 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a
|
||||
|
||||
switch (operation) {
|
||||
case OperationType::MapGroup:
|
||||
case OperationType::MapFirstGroup: {
|
||||
case OperationType::MapFirstGroup:
|
||||
case OperationType::MapFirstGroupPhysical: {
|
||||
const bool separate_heap = operation == OperationType::MapFirstGroupPhysical;
|
||||
|
||||
// We want to maintain a new reference to every page in the group.
|
||||
KScopedPageGroup spg(page_group, operation != OperationType::MapFirstGroup);
|
||||
KScopedPageGroup spg(page_group, operation == OperationType::MapGroup);
|
||||
|
||||
for (const auto& node : page_group) {
|
||||
const size_t size{node.GetNumPages() * PageSize};
|
||||
|
||||
// Map the pages.
|
||||
m_memory->MapMemoryRegion(*m_impl, virt_addr, size, node.GetAddress(),
|
||||
ConvertToMemoryPermission(properties.perm));
|
||||
ConvertToMemoryPermission(properties.perm), separate_heap);
|
||||
|
||||
virt_addr += size;
|
||||
}
|
||||
|
@@ -104,6 +104,9 @@ protected:
|
||||
ChangePermissionsAndRefresh = 5,
|
||||
ChangePermissionsAndRefreshAndFlush = 6,
|
||||
Separate = 7,
|
||||
|
||||
MapFirstGroupPhysical = 65000,
|
||||
UnmapPhysical = 65001,
|
||||
};
|
||||
|
||||
static constexpr size_t MaxPhysicalMapAlignment = 1_GiB;
|
||||
|
@@ -1237,8 +1237,10 @@ void KProcess::LoadModule(CodeSet code_set, KProcessAddress base_addr) {
|
||||
auto& buffer = m_kernel.System().DeviceMemory().buffer;
|
||||
const auto& code = code_set.CodeSegment();
|
||||
const auto& patch = code_set.PatchSegment();
|
||||
buffer.Protect(GetInteger(base_addr + code.addr), code.size, true, true, true);
|
||||
buffer.Protect(GetInteger(base_addr + patch.addr), patch.size, true, true, true);
|
||||
buffer.Protect(GetInteger(base_addr + code.addr), code.size,
|
||||
Common::MemoryPermission::Read | Common::MemoryPermission::Execute);
|
||||
buffer.Protect(GetInteger(base_addr + patch.addr), patch.size,
|
||||
Common::MemoryPermission::Read | Common::MemoryPermission::Execute);
|
||||
ReprotectSegment(code_set.PatchSegment(), Svc::MemoryPermission::None);
|
||||
}
|
||||
#endif
|
||||
|
@@ -552,7 +552,7 @@ private:
|
||||
|
||||
Result InitializeHandleTable(s32 size) {
|
||||
// Try to initialize the handle table.
|
||||
R_TRY(m_handle_table.Initialize(this, size));
|
||||
R_TRY(m_handle_table.Initialize(size));
|
||||
|
||||
// We succeeded, so note that we did.
|
||||
m_is_handle_table_initialized = true;
|
||||
|
@@ -1147,8 +1147,7 @@ Result KServerSession::ReceiveRequest(uintptr_t server_message, uintptr_t server
|
||||
*out_context =
|
||||
std::make_shared<Service::HLERequestContext>(m_kernel, memory, this, client_thread);
|
||||
(*out_context)->SetSessionRequestManager(manager);
|
||||
(*out_context)
|
||||
->PopulateFromIncomingCommandBuffer(*client_thread->GetOwnerProcess(), cmd_buf);
|
||||
(*out_context)->PopulateFromIncomingCommandBuffer(cmd_buf);
|
||||
// We succeeded.
|
||||
R_SUCCEED();
|
||||
} else {
|
||||
|
@@ -5,6 +5,7 @@
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "core/hle/kernel/k_light_lock.h"
|
||||
#include "core/hle/kernel/k_page_group.h"
|
||||
#include "core/hle/kernel/slab_helpers.h"
|
||||
#include "core/hle/kernel/svc_types.h"
|
||||
|
@@ -238,7 +238,7 @@ struct KernelCore::Impl {
|
||||
void InitializePreemption(KernelCore& kernel) {
|
||||
preemption_event = Core::Timing::CreateEvent(
|
||||
"PreemptionCallback",
|
||||
[this, &kernel](std::uintptr_t, s64 time,
|
||||
[this, &kernel](s64 time,
|
||||
std::chrono::nanoseconds) -> std::optional<std::chrono::nanoseconds> {
|
||||
{
|
||||
KScopedSchedulerLock lock(kernel);
|
||||
|
@@ -1513,8 +1513,7 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(HLERequestContext& ctx)
|
||||
return;
|
||||
}
|
||||
|
||||
auto transfer_mem =
|
||||
system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(handle);
|
||||
auto transfer_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(handle);
|
||||
|
||||
if (transfer_mem.IsNull()) {
|
||||
LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
|
||||
@@ -1524,8 +1523,7 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(HLERequestContext& ctx)
|
||||
}
|
||||
|
||||
std::vector<u8> memory(transfer_mem->GetSize());
|
||||
system.ApplicationMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(),
|
||||
memory.size());
|
||||
ctx.GetMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), memory.size());
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
@@ -1547,8 +1545,7 @@ void ILibraryAppletCreator::CreateHandleStorage(HLERequestContext& ctx) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto transfer_mem =
|
||||
system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(handle);
|
||||
auto transfer_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(handle);
|
||||
|
||||
if (transfer_mem.IsNull()) {
|
||||
LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
|
||||
@@ -1558,8 +1555,7 @@ void ILibraryAppletCreator::CreateHandleStorage(HLERequestContext& ctx) {
|
||||
}
|
||||
|
||||
std::vector<u8> memory(transfer_mem->GetSize());
|
||||
system.ApplicationMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(),
|
||||
memory.size());
|
||||
ctx.GetMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), memory.size());
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
|
@@ -454,10 +454,8 @@ void AudRenU::OpenAudioRenderer(HLERequestContext& ctx) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& handle_table{system.ApplicationProcess()->GetHandleTable()};
|
||||
auto process{handle_table.GetObject<Kernel::KProcess>(process_handle)};
|
||||
auto transfer_memory{
|
||||
process->GetHandleTable().GetObject<Kernel::KTransferMemory>(transfer_memory_handle)};
|
||||
auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(process_handle)};
|
||||
auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
|
||||
|
||||
const auto session_id{impl->GetSessionId()};
|
||||
if (session_id == -1) {
|
||||
|
@@ -278,9 +278,7 @@ void HwOpus::OpenHardwareOpusDecoder(HLERequestContext& ctx) {
|
||||
auto params = rp.PopRaw<OpusParameters>();
|
||||
auto transfer_memory_size{rp.Pop<u32>()};
|
||||
auto transfer_memory_handle{ctx.GetCopyHandle(0)};
|
||||
auto transfer_memory{
|
||||
system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
|
||||
transfer_memory_handle)};
|
||||
auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
|
||||
|
||||
LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size 0x{:X}",
|
||||
params.sample_rate, params.channel_count, transfer_memory_size);
|
||||
@@ -323,9 +321,7 @@ void HwOpus::OpenHardwareOpusDecoderForMultiStream(HLERequestContext& ctx) {
|
||||
|
||||
auto transfer_memory_size{rp.Pop<u32>()};
|
||||
auto transfer_memory_handle{ctx.GetCopyHandle(0)};
|
||||
auto transfer_memory{
|
||||
system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
|
||||
transfer_memory_handle)};
|
||||
auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
|
||||
|
||||
LOG_DEBUG(Service_Audio,
|
||||
"sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
|
||||
@@ -374,9 +370,7 @@ void HwOpus::OpenHardwareOpusDecoderEx(HLERequestContext& ctx) {
|
||||
auto params = rp.PopRaw<OpusParametersEx>();
|
||||
auto transfer_memory_size{rp.Pop<u32>()};
|
||||
auto transfer_memory_handle{ctx.GetCopyHandle(0)};
|
||||
auto transfer_memory{
|
||||
system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
|
||||
transfer_memory_handle)};
|
||||
auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
|
||||
|
||||
LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size 0x{:X}",
|
||||
params.sample_rate, params.channel_count, transfer_memory_size);
|
||||
@@ -414,9 +408,7 @@ void HwOpus::OpenHardwareOpusDecoderForMultiStreamEx(HLERequestContext& ctx) {
|
||||
|
||||
auto transfer_memory_size{rp.Pop<u32>()};
|
||||
auto transfer_memory_handle{ctx.GetCopyHandle(0)};
|
||||
auto transfer_memory{
|
||||
system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
|
||||
transfer_memory_handle)};
|
||||
auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
|
||||
|
||||
LOG_DEBUG(Service_Audio,
|
||||
"sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
|
||||
|
@@ -1850,8 +1850,7 @@ void IHidServer::InitializeSevenSixAxisSensor(HLERequestContext& ctx) {
|
||||
ASSERT_MSG(t_mem_1_size == 0x1000, "t_mem_1_size is not 0x1000 bytes");
|
||||
ASSERT_MSG(t_mem_2_size == 0x7F000, "t_mem_2_size is not 0x7F000 bytes");
|
||||
|
||||
auto t_mem_1 = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
|
||||
t_mem_1_handle);
|
||||
auto t_mem_1 = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_1_handle);
|
||||
|
||||
if (t_mem_1.IsNull()) {
|
||||
LOG_ERROR(Service_HID, "t_mem_1 is a nullptr for handle=0x{:08X}", t_mem_1_handle);
|
||||
@@ -1860,8 +1859,7 @@ void IHidServer::InitializeSevenSixAxisSensor(HLERequestContext& ctx) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto t_mem_2 = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
|
||||
t_mem_2_handle);
|
||||
auto t_mem_2 = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_2_handle);
|
||||
|
||||
if (t_mem_2.IsNull()) {
|
||||
LOG_ERROR(Service_HID, "t_mem_2 is a nullptr for handle=0x{:08X}", t_mem_2_handle);
|
||||
@@ -2142,8 +2140,7 @@ void IHidServer::WritePalmaWaveEntry(HLERequestContext& ctx) {
|
||||
|
||||
ASSERT_MSG(t_mem_size == 0x3000, "t_mem_size is not 0x3000 bytes");
|
||||
|
||||
auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
|
||||
t_mem_handle);
|
||||
auto t_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_handle);
|
||||
|
||||
if (t_mem.IsNull()) {
|
||||
LOG_ERROR(Service_HID, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle);
|
||||
|
@@ -49,10 +49,10 @@ HidBus::HidBus(Core::System& system_)
|
||||
// Register update callbacks
|
||||
hidbus_update_event = Core::Timing::CreateEvent(
|
||||
"Hidbus::UpdateCallback",
|
||||
[this](std::uintptr_t user_data, s64 time,
|
||||
[this](s64 time,
|
||||
std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
|
||||
const auto guard = LockService();
|
||||
UpdateHidbus(user_data, ns_late);
|
||||
UpdateHidbus(ns_late);
|
||||
return std::nullopt;
|
||||
});
|
||||
|
||||
@@ -61,10 +61,10 @@ HidBus::HidBus(Core::System& system_)
|
||||
}
|
||||
|
||||
HidBus::~HidBus() {
|
||||
system.CoreTiming().UnscheduleEvent(hidbus_update_event, 0);
|
||||
system.CoreTiming().UnscheduleEvent(hidbus_update_event);
|
||||
}
|
||||
|
||||
void HidBus::UpdateHidbus(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
|
||||
void HidBus::UpdateHidbus(std::chrono::nanoseconds ns_late) {
|
||||
if (is_hidbus_enabled) {
|
||||
for (std::size_t i = 0; i < devices.size(); ++i) {
|
||||
if (!devices[i].is_device_initializated) {
|
||||
@@ -448,8 +448,7 @@ void HidBus::EnableJoyPollingReceiveMode(HLERequestContext& ctx) {
|
||||
|
||||
ASSERT_MSG(t_mem_size == 0x1000, "t_mem_size is not 0x1000 bytes");
|
||||
|
||||
auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
|
||||
t_mem_handle);
|
||||
auto t_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_handle);
|
||||
|
||||
if (t_mem.IsNull()) {
|
||||
LOG_ERROR(Service_HID, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle);
|
||||
|
@@ -108,7 +108,7 @@ private:
|
||||
void DisableJoyPollingReceiveMode(HLERequestContext& ctx);
|
||||
void SetStatusManagerType(HLERequestContext& ctx);
|
||||
|
||||
void UpdateHidbus(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
|
||||
void UpdateHidbus(std::chrono::nanoseconds ns_late);
|
||||
std::optional<std::size_t> GetDeviceIndexFromHandle(BusHandle handle) const;
|
||||
|
||||
template <typename T>
|
||||
|
@@ -197,8 +197,7 @@ void IRS::RunImageTransferProcessor(HLERequestContext& ctx) {
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
const auto t_mem_handle{ctx.GetCopyHandle(0)};
|
||||
|
||||
auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
|
||||
t_mem_handle);
|
||||
auto t_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_handle);
|
||||
|
||||
if (t_mem.IsNull()) {
|
||||
LOG_ERROR(Service_IRS, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle);
|
||||
@@ -444,8 +443,7 @@ void IRS::RunImageTransferExProcessor(HLERequestContext& ctx) {
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
const auto t_mem_handle{ctx.GetCopyHandle(0)};
|
||||
|
||||
auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
|
||||
t_mem_handle);
|
||||
auto t_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_handle);
|
||||
|
||||
LOG_INFO(Service_IRS,
|
||||
"called, npad_type={}, npad_id={}, transfer_memory_size={}, "
|
||||
|
@@ -227,8 +227,7 @@ void ResourceManager::EnableTouchScreen(u64 aruid, bool is_enabled) {
|
||||
applet_resource->EnableTouchScreen(aruid, is_enabled);
|
||||
}
|
||||
|
||||
void ResourceManager::UpdateControllers(std::uintptr_t user_data,
|
||||
std::chrono::nanoseconds ns_late) {
|
||||
void ResourceManager::UpdateControllers(std::chrono::nanoseconds ns_late) {
|
||||
auto& core_timing = system.CoreTiming();
|
||||
debug_pad->OnUpdate(core_timing);
|
||||
digitizer->OnUpdate(core_timing);
|
||||
@@ -241,20 +240,19 @@ void ResourceManager::UpdateControllers(std::uintptr_t user_data,
|
||||
capture_button->OnUpdate(core_timing);
|
||||
}
|
||||
|
||||
void ResourceManager::UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
|
||||
void ResourceManager::UpdateNpad(std::chrono::nanoseconds ns_late) {
|
||||
auto& core_timing = system.CoreTiming();
|
||||
npad->OnUpdate(core_timing);
|
||||
}
|
||||
|
||||
void ResourceManager::UpdateMouseKeyboard(std::uintptr_t user_data,
|
||||
std::chrono::nanoseconds ns_late) {
|
||||
void ResourceManager::UpdateMouseKeyboard(std::chrono::nanoseconds ns_late) {
|
||||
auto& core_timing = system.CoreTiming();
|
||||
mouse->OnUpdate(core_timing);
|
||||
debug_mouse->OnUpdate(core_timing);
|
||||
keyboard->OnUpdate(core_timing);
|
||||
}
|
||||
|
||||
void ResourceManager::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
|
||||
void ResourceManager::UpdateMotion(std::chrono::nanoseconds ns_late) {
|
||||
auto& core_timing = system.CoreTiming();
|
||||
six_axis->OnUpdate(core_timing);
|
||||
seven_six_axis->OnUpdate(core_timing);
|
||||
@@ -273,34 +271,34 @@ IAppletResource::IAppletResource(Core::System& system_, std::shared_ptr<Resource
|
||||
// Register update callbacks
|
||||
npad_update_event = Core::Timing::CreateEvent(
|
||||
"HID::UpdatePadCallback",
|
||||
[this, resource](std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late)
|
||||
-> std::optional<std::chrono::nanoseconds> {
|
||||
[this, resource](
|
||||
s64 time, std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
|
||||
const auto guard = LockService();
|
||||
resource->UpdateNpad(user_data, ns_late);
|
||||
resource->UpdateNpad(ns_late);
|
||||
return std::nullopt;
|
||||
});
|
||||
default_update_event = Core::Timing::CreateEvent(
|
||||
"HID::UpdateDefaultCallback",
|
||||
[this, resource](std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late)
|
||||
-> std::optional<std::chrono::nanoseconds> {
|
||||
[this, resource](
|
||||
s64 time, std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
|
||||
const auto guard = LockService();
|
||||
resource->UpdateControllers(user_data, ns_late);
|
||||
resource->UpdateControllers(ns_late);
|
||||
return std::nullopt;
|
||||
});
|
||||
mouse_keyboard_update_event = Core::Timing::CreateEvent(
|
||||
"HID::UpdateMouseKeyboardCallback",
|
||||
[this, resource](std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late)
|
||||
-> std::optional<std::chrono::nanoseconds> {
|
||||
[this, resource](
|
||||
s64 time, std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
|
||||
const auto guard = LockService();
|
||||
resource->UpdateMouseKeyboard(user_data, ns_late);
|
||||
resource->UpdateMouseKeyboard(ns_late);
|
||||
return std::nullopt;
|
||||
});
|
||||
motion_update_event = Core::Timing::CreateEvent(
|
||||
"HID::UpdateMotionCallback",
|
||||
[this, resource](std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late)
|
||||
-> std::optional<std::chrono::nanoseconds> {
|
||||
[this, resource](
|
||||
s64 time, std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
|
||||
const auto guard = LockService();
|
||||
resource->UpdateMotion(user_data, ns_late);
|
||||
resource->UpdateMotion(ns_late);
|
||||
return std::nullopt;
|
||||
});
|
||||
|
||||
@@ -314,10 +312,10 @@ IAppletResource::IAppletResource(Core::System& system_, std::shared_ptr<Resource
|
||||
}
|
||||
|
||||
IAppletResource::~IAppletResource() {
|
||||
system.CoreTiming().UnscheduleEvent(npad_update_event, 0);
|
||||
system.CoreTiming().UnscheduleEvent(default_update_event, 0);
|
||||
system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event, 0);
|
||||
system.CoreTiming().UnscheduleEvent(motion_update_event, 0);
|
||||
system.CoreTiming().UnscheduleEvent(npad_update_event);
|
||||
system.CoreTiming().UnscheduleEvent(default_update_event);
|
||||
system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event);
|
||||
system.CoreTiming().UnscheduleEvent(motion_update_event);
|
||||
resource_manager->FreeAppletResourceId(aruid);
|
||||
}
|
||||
|
||||
|
@@ -81,10 +81,10 @@ public:
|
||||
void EnablePadInput(u64 aruid, bool is_enabled);
|
||||
void EnableTouchScreen(u64 aruid, bool is_enabled);
|
||||
|
||||
void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
|
||||
void UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
|
||||
void UpdateMouseKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
|
||||
void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
|
||||
void UpdateControllers(std::chrono::nanoseconds ns_late);
|
||||
void UpdateNpad(std::chrono::nanoseconds ns_late);
|
||||
void UpdateMouseKeyboard(std::chrono::nanoseconds ns_late);
|
||||
void UpdateMotion(std::chrono::nanoseconds ns_late);
|
||||
|
||||
private:
|
||||
Result CreateAppletResourceImpl(u64 aruid);
|
||||
|
@@ -146,10 +146,7 @@ HLERequestContext::HLERequestContext(Kernel::KernelCore& kernel_, Core::Memory::
|
||||
|
||||
HLERequestContext::~HLERequestContext() = default;
|
||||
|
||||
void HLERequestContext::ParseCommandBuffer(Kernel::KProcess& process, u32_le* src_cmdbuf,
|
||||
bool incoming) {
|
||||
client_handle_table = &process.GetHandleTable();
|
||||
|
||||
void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {
|
||||
IPC::RequestParser rp(src_cmdbuf);
|
||||
command_header = rp.PopRaw<IPC::CommandHeader>();
|
||||
|
||||
@@ -162,7 +159,7 @@ void HLERequestContext::ParseCommandBuffer(Kernel::KProcess& process, u32_le* sr
|
||||
if (command_header->enable_handle_descriptor) {
|
||||
handle_descriptor_header = rp.PopRaw<IPC::HandleDescriptorHeader>();
|
||||
if (handle_descriptor_header->send_current_pid) {
|
||||
pid = process.GetProcessId();
|
||||
pid = thread->GetOwnerProcess()->GetProcessId();
|
||||
rp.Skip(2, false);
|
||||
}
|
||||
if (incoming) {
|
||||
@@ -270,9 +267,10 @@ void HLERequestContext::ParseCommandBuffer(Kernel::KProcess& process, u32_le* sr
|
||||
rp.Skip(1, false); // The command is actually an u64, but we don't use the high part.
|
||||
}
|
||||
|
||||
Result HLERequestContext::PopulateFromIncomingCommandBuffer(Kernel::KProcess& process,
|
||||
u32_le* src_cmdbuf) {
|
||||
ParseCommandBuffer(process, src_cmdbuf, true);
|
||||
Result HLERequestContext::PopulateFromIncomingCommandBuffer(u32_le* src_cmdbuf) {
|
||||
client_handle_table = &thread->GetOwnerProcess()->GetHandleTable();
|
||||
|
||||
ParseCommandBuffer(src_cmdbuf, true);
|
||||
|
||||
if (command_header->IsCloseCommand()) {
|
||||
// Close does not populate the rest of the IPC header
|
||||
@@ -284,9 +282,9 @@ Result HLERequestContext::PopulateFromIncomingCommandBuffer(Kernel::KProcess& pr
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result HLERequestContext::WriteToOutgoingCommandBuffer(Kernel::KThread& requesting_thread) {
|
||||
Result HLERequestContext::WriteToOutgoingCommandBuffer() {
|
||||
auto current_offset = handles_offset;
|
||||
auto& owner_process = *requesting_thread.GetOwnerProcess();
|
||||
auto& owner_process = *thread->GetOwnerProcess();
|
||||
auto& handle_table = owner_process.GetHandleTable();
|
||||
|
||||
for (auto& object : outgoing_copy_objects) {
|
||||
@@ -319,7 +317,7 @@ Result HLERequestContext::WriteToOutgoingCommandBuffer(Kernel::KThread& requesti
|
||||
}
|
||||
|
||||
// Copy the translated command buffer back into the thread's command buffer area.
|
||||
memory.WriteBlock(requesting_thread.GetTlsAddress(), cmd_buf.data(), write_size * sizeof(u32));
|
||||
memory.WriteBlock(thread->GetTlsAddress(), cmd_buf.data(), write_size * sizeof(u32));
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
@@ -17,6 +17,7 @@
|
||||
#include "common/concepts.h"
|
||||
#include "common/swap.h"
|
||||
#include "core/hle/ipc.h"
|
||||
#include "core/hle/kernel/k_handle_table.h"
|
||||
#include "core/hle/kernel/svc_common.h"
|
||||
|
||||
union Result;
|
||||
@@ -196,10 +197,10 @@ public:
|
||||
}
|
||||
|
||||
/// Populates this context with data from the requesting process/thread.
|
||||
Result PopulateFromIncomingCommandBuffer(Kernel::KProcess& process, u32_le* src_cmdbuf);
|
||||
Result PopulateFromIncomingCommandBuffer(u32_le* src_cmdbuf);
|
||||
|
||||
/// Writes data from this context back to the requesting process/thread.
|
||||
Result WriteToOutgoingCommandBuffer(Kernel::KThread& requesting_thread);
|
||||
Result WriteToOutgoingCommandBuffer();
|
||||
|
||||
[[nodiscard]] u32_le GetHipcCommand() const {
|
||||
return command;
|
||||
@@ -359,8 +360,17 @@ public:
|
||||
return *thread;
|
||||
}
|
||||
|
||||
Kernel::KHandleTable& GetClientHandleTable() {
|
||||
return *client_handle_table;
|
||||
[[nodiscard]] Core::Memory::Memory& GetMemory() const {
|
||||
return memory;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Kernel::KScopedAutoObject<T> GetObjectFromHandle(u32 handle) {
|
||||
auto obj = client_handle_table->GetObjectForIpc(handle, thread);
|
||||
if (obj.IsNotNull()) {
|
||||
return obj->DynamicCast<T*>();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::shared_ptr<SessionRequestManager> GetManager() const {
|
||||
@@ -378,7 +388,7 @@ public:
|
||||
private:
|
||||
friend class IPC::ResponseBuilder;
|
||||
|
||||
void ParseCommandBuffer(Kernel::KProcess& process, u32_le* src_cmdbuf, bool incoming);
|
||||
void ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming);
|
||||
|
||||
std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
|
||||
Kernel::KServerSession* server_session{};
|
||||
|
@@ -26,7 +26,7 @@ public:
|
||||
explicit IJitEnvironment(Core::System& system_, Kernel::KProcess& process_, CodeRange user_rx,
|
||||
CodeRange user_ro)
|
||||
: ServiceFramework{system_, "IJitEnvironment"}, process{&process_},
|
||||
context{system_.ApplicationMemory()} {
|
||||
context{process->GetMemory()} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IJitEnvironment::GenerateCode, "GenerateCode"},
|
||||
@@ -188,7 +188,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
auto tmem{process->GetHandleTable().GetObject<Kernel::KTransferMemory>(tmem_handle)};
|
||||
auto tmem{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(tmem_handle)};
|
||||
if (tmem.IsNull()) {
|
||||
LOG_ERROR(Service_JIT, "attempted to load plugin with invalid transfer memory handle");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
@@ -356,11 +356,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch using the handle table for the application process here,
|
||||
// since we are not multiprocess yet.
|
||||
const auto& handle_table{system.ApplicationProcess()->GetHandleTable()};
|
||||
|
||||
auto process{handle_table.GetObject<Kernel::KProcess>(process_handle)};
|
||||
auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(process_handle)};
|
||||
if (process.IsNull()) {
|
||||
LOG_ERROR(Service_JIT, "process is null for handle=0x{:08X}", process_handle);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
@@ -368,7 +364,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
auto rx_mem{handle_table.GetObject<Kernel::KCodeMemory>(rx_mem_handle)};
|
||||
auto rx_mem{ctx.GetObjectFromHandle<Kernel::KCodeMemory>(rx_mem_handle)};
|
||||
if (rx_mem.IsNull()) {
|
||||
LOG_ERROR(Service_JIT, "rx_mem is null for handle=0x{:08X}", rx_mem_handle);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
@@ -376,7 +372,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
auto ro_mem{handle_table.GetObject<Kernel::KCodeMemory>(ro_mem_handle)};
|
||||
auto ro_mem{ctx.GetObjectFromHandle<Kernel::KCodeMemory>(ro_mem_handle)};
|
||||
if (ro_mem.IsNull()) {
|
||||
LOG_ERROR(Service_JIT, "ro_mem is null for handle=0x{:08X}", ro_mem_handle);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
|
@@ -67,7 +67,7 @@ Nvnflinger::Nvnflinger(Core::System& system_, HosBinderDriverServer& hos_binder_
|
||||
// Schedule the screen composition events
|
||||
multi_composition_event = Core::Timing::CreateEvent(
|
||||
"ScreenComposition",
|
||||
[this](std::uintptr_t, s64 time,
|
||||
[this](s64 time,
|
||||
std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
|
||||
vsync_signal.Set();
|
||||
return std::chrono::nanoseconds(GetNextTicks());
|
||||
@@ -75,7 +75,7 @@ Nvnflinger::Nvnflinger(Core::System& system_, HosBinderDriverServer& hos_binder_
|
||||
|
||||
single_composition_event = Core::Timing::CreateEvent(
|
||||
"ScreenComposition",
|
||||
[this](std::uintptr_t, s64 time,
|
||||
[this](s64 time,
|
||||
std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
|
||||
const auto lock_guard = Lock();
|
||||
Compose();
|
||||
@@ -93,11 +93,11 @@ Nvnflinger::Nvnflinger(Core::System& system_, HosBinderDriverServer& hos_binder_
|
||||
|
||||
Nvnflinger::~Nvnflinger() {
|
||||
if (system.IsMulticore()) {
|
||||
system.CoreTiming().UnscheduleEvent(multi_composition_event, {});
|
||||
system.CoreTiming().UnscheduleEvent(multi_composition_event);
|
||||
vsync_thread.request_stop();
|
||||
vsync_signal.Set();
|
||||
} else {
|
||||
system.CoreTiming().UnscheduleEvent(single_composition_event, {});
|
||||
system.CoreTiming().UnscheduleEvent(single_composition_event);
|
||||
}
|
||||
|
||||
ShutdownLayers();
|
||||
|
@@ -651,10 +651,9 @@ private:
|
||||
void RegisterProcessHandle(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_LDR, "(called)");
|
||||
|
||||
auto process_h = ctx.GetClientHandleTable().GetObject(ctx.GetCopyHandle(0));
|
||||
auto process = ctx.GetObjectFromHandle<Kernel::KProcess>(ctx.GetCopyHandle(0));
|
||||
auto client_pid = ctx.GetPID();
|
||||
auto result = interface.RegisterProcessHandle(client_pid,
|
||||
process_h->DynamicCast<Kernel::KProcess*>());
|
||||
auto result = interface.RegisterProcessHandle(client_pid, process.GetPointerUnsafe());
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
@@ -671,12 +670,11 @@ private:
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto params = rp.PopRaw<InputParameters>();
|
||||
auto process_h = ctx.GetClientHandleTable().GetObject(ctx.GetCopyHandle(0));
|
||||
auto process = ctx.GetObjectFromHandle<Kernel::KProcess>(ctx.GetCopyHandle(0));
|
||||
|
||||
auto client_pid = ctx.GetPID();
|
||||
auto result =
|
||||
interface.RegisterProcessModuleInfo(client_pid, params.nrr_address, params.nrr_size,
|
||||
process_h->DynamicCast<Kernel::KProcess*>());
|
||||
auto result = interface.RegisterProcessModuleInfo(
|
||||
client_pid, params.nrr_address, params.nrr_size, process.GetPointerUnsafe());
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
|
@@ -203,7 +203,7 @@ Result ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& session,
|
||||
// If emulation was shutdown, we are closing service threads, do not write the response back to
|
||||
// memory that may be shutting down as well.
|
||||
if (system.IsPoweredOn()) {
|
||||
ctx.WriteToOutgoingCommandBuffer(ctx.GetThread());
|
||||
ctx.WriteToOutgoingCommandBuffer();
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@@ -10,6 +10,7 @@
|
||||
#include "common/assert.h"
|
||||
#include "common/atomic_ops.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/heap_tracker.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/page_table.h"
|
||||
#include "common/scope_exit.h"
|
||||
@@ -52,10 +53,18 @@ struct Memory::Impl {
|
||||
} else {
|
||||
current_page_table->fastmem_arena = nullptr;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
heap_tracker.emplace(system.DeviceMemory().buffer);
|
||||
buffer = std::addressof(*heap_tracker);
|
||||
#else
|
||||
buffer = std::addressof(system.DeviceMemory().buffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
void MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size,
|
||||
Common::PhysicalAddress target, Common::MemoryPermission perms) {
|
||||
Common::PhysicalAddress target, Common::MemoryPermission perms,
|
||||
bool separate_heap) {
|
||||
ASSERT_MSG((size & YUZU_PAGEMASK) == 0, "non-page aligned size: {:016X}", size);
|
||||
ASSERT_MSG((base & YUZU_PAGEMASK) == 0, "non-page aligned base: {:016X}", GetInteger(base));
|
||||
ASSERT_MSG(target >= DramMemoryMap::Base, "Out of bounds target: {:016X}",
|
||||
@@ -64,19 +73,20 @@ struct Memory::Impl {
|
||||
Common::PageType::Memory);
|
||||
|
||||
if (current_page_table->fastmem_arena) {
|
||||
system.DeviceMemory().buffer.Map(GetInteger(base),
|
||||
GetInteger(target) - DramMemoryMap::Base, size, perms);
|
||||
buffer->Map(GetInteger(base), GetInteger(target) - DramMemoryMap::Base, size, perms,
|
||||
separate_heap);
|
||||
}
|
||||
}
|
||||
|
||||
void UnmapRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size) {
|
||||
void UnmapRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size,
|
||||
bool separate_heap) {
|
||||
ASSERT_MSG((size & YUZU_PAGEMASK) == 0, "non-page aligned size: {:016X}", size);
|
||||
ASSERT_MSG((base & YUZU_PAGEMASK) == 0, "non-page aligned base: {:016X}", GetInteger(base));
|
||||
MapPages(page_table, base / YUZU_PAGESIZE, size / YUZU_PAGESIZE, 0,
|
||||
Common::PageType::Unmapped);
|
||||
|
||||
if (current_page_table->fastmem_arena) {
|
||||
system.DeviceMemory().buffer.Unmap(GetInteger(base), size);
|
||||
buffer->Unmap(GetInteger(base), size, separate_heap);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,11 +99,6 @@ struct Memory::Impl {
|
||||
return;
|
||||
}
|
||||
|
||||
const bool is_r = True(perms & Common::MemoryPermission::Read);
|
||||
const bool is_w = True(perms & Common::MemoryPermission::Write);
|
||||
const bool is_x =
|
||||
True(perms & Common::MemoryPermission::Execute) && Settings::IsNceEnabled();
|
||||
|
||||
u64 protect_bytes{};
|
||||
u64 protect_begin{};
|
||||
for (u64 addr = vaddr; addr < vaddr + size; addr += YUZU_PAGESIZE) {
|
||||
@@ -102,8 +107,7 @@ struct Memory::Impl {
|
||||
switch (page_type) {
|
||||
case Common::PageType::RasterizerCachedMemory:
|
||||
if (protect_bytes > 0) {
|
||||
system.DeviceMemory().buffer.Protect(protect_begin, protect_bytes, is_r, is_w,
|
||||
is_x);
|
||||
buffer->Protect(protect_begin, protect_bytes, perms);
|
||||
protect_bytes = 0;
|
||||
}
|
||||
break;
|
||||
@@ -116,7 +120,7 @@ struct Memory::Impl {
|
||||
}
|
||||
|
||||
if (protect_bytes > 0) {
|
||||
system.DeviceMemory().buffer.Protect(protect_begin, protect_bytes, is_r, is_w, is_x);
|
||||
buffer->Protect(protect_begin, protect_bytes, perms);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -486,7 +490,9 @@ struct Memory::Impl {
|
||||
}
|
||||
|
||||
if (current_page_table->fastmem_arena) {
|
||||
system.DeviceMemory().buffer.Protect(vaddr, size, !debug, !debug);
|
||||
const auto perm{debug ? Common::MemoryPermission{}
|
||||
: Common::MemoryPermission::ReadWrite};
|
||||
buffer->Protect(vaddr, size, perm);
|
||||
}
|
||||
|
||||
// Iterate over a contiguous CPU address space, marking/unmarking the region.
|
||||
@@ -543,9 +549,14 @@ struct Memory::Impl {
|
||||
}
|
||||
|
||||
if (current_page_table->fastmem_arena) {
|
||||
const bool is_read_enable =
|
||||
!Settings::values.use_reactive_flushing.GetValue() || !cached;
|
||||
system.DeviceMemory().buffer.Protect(vaddr, size, is_read_enable, !cached);
|
||||
Common::MemoryPermission perm{};
|
||||
if (!Settings::values.use_reactive_flushing.GetValue() || !cached) {
|
||||
perm |= Common::MemoryPermission::Read;
|
||||
}
|
||||
if (!cached) {
|
||||
perm |= Common::MemoryPermission::Write;
|
||||
}
|
||||
buffer->Protect(vaddr, size, perm);
|
||||
}
|
||||
|
||||
// Iterate over a contiguous CPU address space, which corresponds to the specified GPU
|
||||
@@ -856,6 +867,13 @@ struct Memory::Impl {
|
||||
std::array<GPUDirtyState, Core::Hardware::NUM_CPU_CORES> rasterizer_write_areas{};
|
||||
std::span<Core::GPUDirtyMemoryManager> gpu_dirty_managers;
|
||||
std::mutex sys_core_guard;
|
||||
|
||||
std::optional<Common::HeapTracker> heap_tracker;
|
||||
#ifdef __linux__
|
||||
Common::HeapTracker* buffer{};
|
||||
#else
|
||||
Common::HostMemory* buffer{};
|
||||
#endif
|
||||
};
|
||||
|
||||
Memory::Memory(Core::System& system_) : system{system_} {
|
||||
@@ -873,12 +891,14 @@ void Memory::SetCurrentPageTable(Kernel::KProcess& process) {
|
||||
}
|
||||
|
||||
void Memory::MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size,
|
||||
Common::PhysicalAddress target, Common::MemoryPermission perms) {
|
||||
impl->MapMemoryRegion(page_table, base, size, target, perms);
|
||||
Common::PhysicalAddress target, Common::MemoryPermission perms,
|
||||
bool separate_heap) {
|
||||
impl->MapMemoryRegion(page_table, base, size, target, perms, separate_heap);
|
||||
}
|
||||
|
||||
void Memory::UnmapRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size) {
|
||||
impl->UnmapRegion(page_table, base, size);
|
||||
void Memory::UnmapRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size,
|
||||
bool separate_heap) {
|
||||
impl->UnmapRegion(page_table, base, size, separate_heap);
|
||||
}
|
||||
|
||||
void Memory::ProtectRegion(Common::PageTable& page_table, Common::ProcessAddress vaddr, u64 size,
|
||||
@@ -1048,7 +1068,9 @@ void Memory::FlushRegion(Common::ProcessAddress dest_addr, size_t size) {
|
||||
}
|
||||
|
||||
bool Memory::InvalidateNCE(Common::ProcessAddress vaddr, size_t size) {
|
||||
bool mapped = true;
|
||||
[[maybe_unused]] bool mapped = true;
|
||||
[[maybe_unused]] bool rasterizer = false;
|
||||
|
||||
u8* const ptr = impl->GetPointerImpl(
|
||||
GetInteger(vaddr),
|
||||
[&] {
|
||||
@@ -1056,8 +1078,26 @@ bool Memory::InvalidateNCE(Common::ProcessAddress vaddr, size_t size) {
|
||||
GetInteger(vaddr));
|
||||
mapped = false;
|
||||
},
|
||||
[&] { impl->system.GPU().InvalidateRegion(GetInteger(vaddr), size); });
|
||||
[&] {
|
||||
impl->system.GPU().InvalidateRegion(GetInteger(vaddr), size);
|
||||
rasterizer = true;
|
||||
});
|
||||
|
||||
#ifdef __linux__
|
||||
if (!rasterizer && mapped) {
|
||||
impl->buffer->DeferredMapSeparateHeap(GetInteger(vaddr));
|
||||
}
|
||||
#endif
|
||||
|
||||
return mapped && ptr != nullptr;
|
||||
}
|
||||
|
||||
bool Memory::InvalidateSeparateHeap(void* fault_address) {
|
||||
#ifdef __linux__
|
||||
return impl->buffer->DeferredMapSeparateHeap(static_cast<u8*>(fault_address));
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace Core::Memory
|
||||
|
@@ -86,7 +86,8 @@ public:
|
||||
* @param perms The permissions to map the memory with.
|
||||
*/
|
||||
void MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size,
|
||||
Common::PhysicalAddress target, Common::MemoryPermission perms);
|
||||
Common::PhysicalAddress target, Common::MemoryPermission perms,
|
||||
bool separate_heap);
|
||||
|
||||
/**
|
||||
* Unmaps a region of the emulated process address space.
|
||||
@@ -95,7 +96,8 @@ public:
|
||||
* @param base The address to begin unmapping at.
|
||||
* @param size The amount of bytes to unmap.
|
||||
*/
|
||||
void UnmapRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size);
|
||||
void UnmapRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size,
|
||||
bool separate_heap);
|
||||
|
||||
/**
|
||||
* Protects a region of the emulated process address space with the new permissions.
|
||||
@@ -486,6 +488,7 @@ public:
|
||||
void SetGPUDirtyManagers(std::span<Core::GPUDirtyMemoryManager> managers);
|
||||
void InvalidateRegion(Common::ProcessAddress dest_addr, size_t size);
|
||||
bool InvalidateNCE(Common::ProcessAddress vaddr, size_t size);
|
||||
bool InvalidateSeparateHeap(void* fault_address);
|
||||
void FlushRegion(Common::ProcessAddress dest_addr, size_t size);
|
||||
|
||||
private:
|
||||
|
@@ -190,15 +190,15 @@ CheatEngine::CheatEngine(System& system_, std::vector<CheatEntry> cheats_,
|
||||
}
|
||||
|
||||
CheatEngine::~CheatEngine() {
|
||||
core_timing.UnscheduleEvent(event, 0);
|
||||
core_timing.UnscheduleEvent(event);
|
||||
}
|
||||
|
||||
void CheatEngine::Initialize() {
|
||||
event = Core::Timing::CreateEvent(
|
||||
"CheatEngine::FrameCallback::" + Common::HexToString(metadata.main_nso_build_id),
|
||||
[this](std::uintptr_t user_data, s64 time,
|
||||
[this](s64 time,
|
||||
std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
|
||||
FrameCallback(user_data, ns_late);
|
||||
FrameCallback(ns_late);
|
||||
return std::nullopt;
|
||||
});
|
||||
core_timing.ScheduleLoopingEvent(CHEAT_ENGINE_NS, CHEAT_ENGINE_NS, event);
|
||||
@@ -239,7 +239,7 @@ void CheatEngine::Reload(std::vector<CheatEntry> reload_cheats) {
|
||||
|
||||
MICROPROFILE_DEFINE(Cheat_Engine, "Add-Ons", "Cheat Engine", MP_RGB(70, 200, 70));
|
||||
|
||||
void CheatEngine::FrameCallback(std::uintptr_t, std::chrono::nanoseconds ns_late) {
|
||||
void CheatEngine::FrameCallback(std::chrono::nanoseconds ns_late) {
|
||||
if (is_pending_reload.exchange(false)) {
|
||||
vm.LoadProgram(cheats);
|
||||
}
|
||||
|
@@ -70,7 +70,7 @@ public:
|
||||
void Reload(std::vector<CheatEntry> reload_cheats);
|
||||
|
||||
private:
|
||||
void FrameCallback(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
|
||||
void FrameCallback(std::chrono::nanoseconds ns_late);
|
||||
|
||||
DmntCheatVm vm;
|
||||
CheatProcessMetadata metadata;
|
||||
|
@@ -51,18 +51,17 @@ void MemoryWriteWidth(Core::Memory::Memory& memory, u32 width, VAddr addr, u64 v
|
||||
|
||||
Freezer::Freezer(Core::Timing::CoreTiming& core_timing_, Core::Memory::Memory& memory_)
|
||||
: core_timing{core_timing_}, memory{memory_} {
|
||||
event = Core::Timing::CreateEvent(
|
||||
"MemoryFreezer::FrameCallback",
|
||||
[this](std::uintptr_t user_data, s64 time,
|
||||
std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
|
||||
FrameCallback(user_data, ns_late);
|
||||
return std::nullopt;
|
||||
});
|
||||
event = Core::Timing::CreateEvent("MemoryFreezer::FrameCallback",
|
||||
[this](s64 time, std::chrono::nanoseconds ns_late)
|
||||
-> std::optional<std::chrono::nanoseconds> {
|
||||
FrameCallback(ns_late);
|
||||
return std::nullopt;
|
||||
});
|
||||
core_timing.ScheduleEvent(memory_freezer_ns, event);
|
||||
}
|
||||
|
||||
Freezer::~Freezer() {
|
||||
core_timing.UnscheduleEvent(event, 0);
|
||||
core_timing.UnscheduleEvent(event);
|
||||
}
|
||||
|
||||
void Freezer::SetActive(bool is_active) {
|
||||
@@ -159,7 +158,7 @@ Freezer::Entries::const_iterator Freezer::FindEntry(VAddr address) const {
|
||||
[address](const Entry& entry) { return entry.address == address; });
|
||||
}
|
||||
|
||||
void Freezer::FrameCallback(std::uintptr_t, std::chrono::nanoseconds ns_late) {
|
||||
void Freezer::FrameCallback(std::chrono::nanoseconds ns_late) {
|
||||
if (!IsActive()) {
|
||||
LOG_DEBUG(Common_Memory, "Memory freezer has been deactivated, ending callback events.");
|
||||
return;
|
||||
|
@@ -77,7 +77,7 @@ private:
|
||||
Entries::iterator FindEntry(VAddr address);
|
||||
Entries::const_iterator FindEntry(VAddr address) const;
|
||||
|
||||
void FrameCallback(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
|
||||
void FrameCallback(std::chrono::nanoseconds ns_late);
|
||||
void FillEntryReads();
|
||||
|
||||
std::atomic_bool active{false};
|
||||
|
Reference in New Issue
Block a user