Merge pull request #12394 from liamwhite/per-process-memory
general: properly support multiple memory instances
This commit is contained in:
		@@ -9,7 +9,7 @@
 | 
			
		||||
 | 
			
		||||
namespace Core {
 | 
			
		||||
 | 
			
		||||
void ArmInterface::LogBacktrace(const Kernel::KProcess* process) const {
 | 
			
		||||
void ArmInterface::LogBacktrace(Kernel::KProcess* process) const {
 | 
			
		||||
    Kernel::Svc::ThreadContext ctx;
 | 
			
		||||
    this->GetContext(ctx);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -95,7 +95,7 @@ public:
 | 
			
		||||
    virtual void SignalInterrupt(Kernel::KThread* thread) = 0;
 | 
			
		||||
 | 
			
		||||
    // Stack trace generation.
 | 
			
		||||
    void LogBacktrace(const Kernel::KProcess* process) const;
 | 
			
		||||
    void LogBacktrace(Kernel::KProcess* process) const;
 | 
			
		||||
 | 
			
		||||
    // Debug functionality.
 | 
			
		||||
    virtual const Kernel::DebugWatchpoint* HaltedWatchpoint() const = 0;
 | 
			
		||||
 
 | 
			
		||||
@@ -79,7 +79,7 @@ constexpr std::array<u64, 2> SegmentBases{
 | 
			
		||||
    0x7100000000ULL,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void SymbolicateBacktrace(const Kernel::KProcess* process, std::vector<BacktraceEntry>& out) {
 | 
			
		||||
void SymbolicateBacktrace(Kernel::KProcess* process, std::vector<BacktraceEntry>& out) {
 | 
			
		||||
    auto modules = FindModules(process);
 | 
			
		||||
 | 
			
		||||
    const bool is_64 = process->Is64Bit();
 | 
			
		||||
@@ -118,7 +118,7 @@ void SymbolicateBacktrace(const Kernel::KProcess* process, std::vector<Backtrace
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::vector<BacktraceEntry> GetAArch64Backtrace(const Kernel::KProcess* process,
 | 
			
		||||
std::vector<BacktraceEntry> GetAArch64Backtrace(Kernel::KProcess* process,
 | 
			
		||||
                                                const Kernel::Svc::ThreadContext& ctx) {
 | 
			
		||||
    std::vector<BacktraceEntry> out;
 | 
			
		||||
    auto& memory = process->GetMemory();
 | 
			
		||||
@@ -144,7 +144,7 @@ std::vector<BacktraceEntry> GetAArch64Backtrace(const Kernel::KProcess* process,
 | 
			
		||||
    return out;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::vector<BacktraceEntry> GetAArch32Backtrace(const Kernel::KProcess* process,
 | 
			
		||||
std::vector<BacktraceEntry> GetAArch32Backtrace(Kernel::KProcess* process,
 | 
			
		||||
                                                const Kernel::Svc::ThreadContext& ctx) {
 | 
			
		||||
    std::vector<BacktraceEntry> out;
 | 
			
		||||
    auto& memory = process->GetMemory();
 | 
			
		||||
@@ -173,7 +173,7 @@ std::vector<BacktraceEntry> GetAArch32Backtrace(const Kernel::KProcess* process,
 | 
			
		||||
} // namespace
 | 
			
		||||
 | 
			
		||||
std::optional<std::string> GetThreadName(const Kernel::KThread* thread) {
 | 
			
		||||
    const auto* process = thread->GetOwnerProcess();
 | 
			
		||||
    auto* process = thread->GetOwnerProcess();
 | 
			
		||||
    if (process->Is64Bit()) {
 | 
			
		||||
        return GetNameFromThreadType64(process->GetMemory(), *thread);
 | 
			
		||||
    } else {
 | 
			
		||||
@@ -248,7 +248,7 @@ Kernel::KProcessAddress GetModuleEnd(const Kernel::KProcess* process,
 | 
			
		||||
    return cur_addr - 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Loader::AppLoader::Modules FindModules(const Kernel::KProcess* process) {
 | 
			
		||||
Loader::AppLoader::Modules FindModules(Kernel::KProcess* process) {
 | 
			
		||||
    Loader::AppLoader::Modules modules;
 | 
			
		||||
 | 
			
		||||
    auto& page_table = process->GetPageTable();
 | 
			
		||||
@@ -312,7 +312,7 @@ Loader::AppLoader::Modules FindModules(const Kernel::KProcess* process) {
 | 
			
		||||
    return modules;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Kernel::KProcessAddress FindMainModuleEntrypoint(const Kernel::KProcess* process) {
 | 
			
		||||
Kernel::KProcessAddress FindMainModuleEntrypoint(Kernel::KProcess* process) {
 | 
			
		||||
    // Do we have any loaded executable sections?
 | 
			
		||||
    auto modules = FindModules(process);
 | 
			
		||||
 | 
			
		||||
@@ -337,7 +337,7 @@ void InvalidateInstructionCacheRange(const Kernel::KProcess* process, u64 addres
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::vector<BacktraceEntry> GetBacktraceFromContext(const Kernel::KProcess* process,
 | 
			
		||||
std::vector<BacktraceEntry> GetBacktraceFromContext(Kernel::KProcess* process,
 | 
			
		||||
                                                    const Kernel::Svc::ThreadContext& ctx) {
 | 
			
		||||
    if (process->Is64Bit()) {
 | 
			
		||||
        return GetAArch64Backtrace(process, ctx);
 | 
			
		||||
 
 | 
			
		||||
@@ -14,9 +14,9 @@ std::optional<std::string> GetThreadName(const Kernel::KThread* thread);
 | 
			
		||||
std::string_view GetThreadWaitReason(const Kernel::KThread* thread);
 | 
			
		||||
std::string GetThreadState(const Kernel::KThread* thread);
 | 
			
		||||
 | 
			
		||||
Loader::AppLoader::Modules FindModules(const Kernel::KProcess* process);
 | 
			
		||||
Loader::AppLoader::Modules FindModules(Kernel::KProcess* process);
 | 
			
		||||
Kernel::KProcessAddress GetModuleEnd(const Kernel::KProcess* process, Kernel::KProcessAddress base);
 | 
			
		||||
Kernel::KProcessAddress FindMainModuleEntrypoint(const Kernel::KProcess* process);
 | 
			
		||||
Kernel::KProcessAddress FindMainModuleEntrypoint(Kernel::KProcess* process);
 | 
			
		||||
 | 
			
		||||
void InvalidateInstructionCacheRange(const Kernel::KProcess* process, u64 address, u64 size);
 | 
			
		||||
 | 
			
		||||
@@ -28,7 +28,7 @@ struct BacktraceEntry {
 | 
			
		||||
    std::string name;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
std::vector<BacktraceEntry> GetBacktraceFromContext(const Kernel::KProcess* process,
 | 
			
		||||
std::vector<BacktraceEntry> GetBacktraceFromContext(Kernel::KProcess* process,
 | 
			
		||||
                                                    const Kernel::Svc::ThreadContext& ctx);
 | 
			
		||||
std::vector<BacktraceEntry> GetBacktrace(const Kernel::KThread* thread);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,7 @@ using namespace Common::Literals;
 | 
			
		||||
 | 
			
		||||
class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks {
 | 
			
		||||
public:
 | 
			
		||||
    explicit DynarmicCallbacks32(ArmDynarmic32& parent, const Kernel::KProcess* process)
 | 
			
		||||
    explicit DynarmicCallbacks32(ArmDynarmic32& parent, Kernel::KProcess* process)
 | 
			
		||||
        : m_parent{parent}, m_memory(process->GetMemory()),
 | 
			
		||||
          m_process(process), m_debugger_enabled{parent.m_system.DebuggerEnabled()},
 | 
			
		||||
          m_check_memory_access{m_debugger_enabled ||
 | 
			
		||||
@@ -169,7 +169,7 @@ public:
 | 
			
		||||
 | 
			
		||||
    ArmDynarmic32& m_parent;
 | 
			
		||||
    Core::Memory::Memory& m_memory;
 | 
			
		||||
    const Kernel::KProcess* m_process{};
 | 
			
		||||
    Kernel::KProcess* m_process{};
 | 
			
		||||
    const bool m_debugger_enabled{};
 | 
			
		||||
    const bool m_check_memory_access{};
 | 
			
		||||
    static constexpr u64 MinimumRunCycles = 10000U;
 | 
			
		||||
@@ -370,7 +370,7 @@ void ArmDynarmic32::RewindBreakpointInstruction() {
 | 
			
		||||
    this->SetContext(m_breakpoint_context);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ArmDynarmic32::ArmDynarmic32(System& system, bool uses_wall_clock, const Kernel::KProcess* process,
 | 
			
		||||
ArmDynarmic32::ArmDynarmic32(System& system, bool uses_wall_clock, Kernel::KProcess* process,
 | 
			
		||||
                             DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index)
 | 
			
		||||
    : ArmInterface{uses_wall_clock}, m_system{system}, m_exclusive_monitor{exclusive_monitor},
 | 
			
		||||
      m_cb(std::make_unique<DynarmicCallbacks32>(*this, process)),
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,7 @@ class System;
 | 
			
		||||
 | 
			
		||||
class ArmDynarmic32 final : public ArmInterface {
 | 
			
		||||
public:
 | 
			
		||||
    ArmDynarmic32(System& system, bool uses_wall_clock, const Kernel::KProcess* process,
 | 
			
		||||
    ArmDynarmic32(System& system, bool uses_wall_clock, Kernel::KProcess* process,
 | 
			
		||||
                  DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index);
 | 
			
		||||
    ~ArmDynarmic32() override;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,7 @@ using namespace Common::Literals;
 | 
			
		||||
 | 
			
		||||
class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks {
 | 
			
		||||
public:
 | 
			
		||||
    explicit DynarmicCallbacks64(ArmDynarmic64& parent, const Kernel::KProcess* process)
 | 
			
		||||
    explicit DynarmicCallbacks64(ArmDynarmic64& parent, Kernel::KProcess* process)
 | 
			
		||||
        : m_parent{parent}, m_memory(process->GetMemory()),
 | 
			
		||||
          m_process(process), m_debugger_enabled{parent.m_system.DebuggerEnabled()},
 | 
			
		||||
          m_check_memory_access{m_debugger_enabled ||
 | 
			
		||||
@@ -216,7 +216,7 @@ public:
 | 
			
		||||
    Core::Memory::Memory& m_memory;
 | 
			
		||||
    u64 m_tpidrro_el0{};
 | 
			
		||||
    u64 m_tpidr_el0{};
 | 
			
		||||
    const Kernel::KProcess* m_process{};
 | 
			
		||||
    Kernel::KProcess* m_process{};
 | 
			
		||||
    const bool m_debugger_enabled{};
 | 
			
		||||
    const bool m_check_memory_access{};
 | 
			
		||||
    static constexpr u64 MinimumRunCycles = 10000U;
 | 
			
		||||
@@ -399,7 +399,7 @@ void ArmDynarmic64::RewindBreakpointInstruction() {
 | 
			
		||||
    this->SetContext(m_breakpoint_context);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ArmDynarmic64::ArmDynarmic64(System& system, bool uses_wall_clock, const Kernel::KProcess* process,
 | 
			
		||||
ArmDynarmic64::ArmDynarmic64(System& system, bool uses_wall_clock, Kernel::KProcess* process,
 | 
			
		||||
                             DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index)
 | 
			
		||||
    : ArmInterface{uses_wall_clock}, m_system{system}, m_exclusive_monitor{exclusive_monitor},
 | 
			
		||||
      m_cb(std::make_unique<DynarmicCallbacks64>(*this, process)), m_core_index{core_index} {
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,7 @@ class System;
 | 
			
		||||
 | 
			
		||||
class ArmDynarmic64 final : public ArmInterface {
 | 
			
		||||
public:
 | 
			
		||||
    ArmDynarmic64(System& system, bool uses_wall_clock, const Kernel::KProcess* process,
 | 
			
		||||
    ArmDynarmic64(System& system, bool uses_wall_clock, Kernel::KProcess* process,
 | 
			
		||||
                  DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index);
 | 
			
		||||
    ~ArmDynarmic64() override;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,6 @@
 | 
			
		||||
#include "core/file_sys/savedata_factory.h"
 | 
			
		||||
#include "core/file_sys/vfs_concat.h"
 | 
			
		||||
#include "core/file_sys/vfs_real.h"
 | 
			
		||||
#include "core/gpu_dirty_memory_manager.h"
 | 
			
		||||
#include "core/hid/hid_core.h"
 | 
			
		||||
#include "core/hle/kernel/k_memory_manager.h"
 | 
			
		||||
#include "core/hle/kernel/k_process.h"
 | 
			
		||||
@@ -130,11 +129,8 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
 | 
			
		||||
 | 
			
		||||
struct System::Impl {
 | 
			
		||||
    explicit Impl(System& system)
 | 
			
		||||
        : kernel{system}, fs_controller{system}, memory{system}, hid_core{}, room_network{},
 | 
			
		||||
          cpu_manager{system}, reporter{system}, applet_manager{system}, profile_manager{},
 | 
			
		||||
          time_manager{system}, gpu_dirty_memory_write_manager{} {
 | 
			
		||||
        memory.SetGPUDirtyManagers(gpu_dirty_memory_write_manager);
 | 
			
		||||
    }
 | 
			
		||||
        : kernel{system}, fs_controller{system}, hid_core{}, room_network{}, cpu_manager{system},
 | 
			
		||||
          reporter{system}, applet_manager{system}, profile_manager{}, time_manager{system} {}
 | 
			
		||||
 | 
			
		||||
    void Initialize(System& system) {
 | 
			
		||||
        device_memory = std::make_unique<Core::DeviceMemory>();
 | 
			
		||||
@@ -241,17 +237,17 @@ struct System::Impl {
 | 
			
		||||
        debugger = std::make_unique<Debugger>(system, port);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    SystemResultStatus SetupForApplicationProcess(System& system, Frontend::EmuWindow& emu_window) {
 | 
			
		||||
    void InitializeKernel(System& system) {
 | 
			
		||||
        LOG_DEBUG(Core, "initialized OK");
 | 
			
		||||
 | 
			
		||||
        // Setting changes may require a full system reinitialization (e.g., disabling multicore).
 | 
			
		||||
        ReinitializeIfNecessary(system);
 | 
			
		||||
 | 
			
		||||
        memory.SetGPUDirtyManagers(gpu_dirty_memory_write_manager);
 | 
			
		||||
 | 
			
		||||
        kernel.Initialize();
 | 
			
		||||
        cpu_manager.Initialize();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    SystemResultStatus SetupForApplicationProcess(System& system, Frontend::EmuWindow& emu_window) {
 | 
			
		||||
        /// Reset all glue registrations
 | 
			
		||||
        arp_manager.ResetAll();
 | 
			
		||||
 | 
			
		||||
@@ -300,17 +296,9 @@ struct System::Impl {
 | 
			
		||||
            return SystemResultStatus::ErrorGetLoader;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        SystemResultStatus init_result{SetupForApplicationProcess(system, emu_window)};
 | 
			
		||||
        if (init_result != SystemResultStatus::Success) {
 | 
			
		||||
            LOG_CRITICAL(Core, "Failed to initialize system (Error {})!",
 | 
			
		||||
                         static_cast<int>(init_result));
 | 
			
		||||
            ShutdownMainProcess();
 | 
			
		||||
            return init_result;
 | 
			
		||||
        }
 | 
			
		||||
        InitializeKernel(system);
 | 
			
		||||
 | 
			
		||||
        telemetry_session->AddInitialInfo(*app_loader, fs_controller, *content_provider);
 | 
			
		||||
 | 
			
		||||
        // Create the process.
 | 
			
		||||
        // Create the application process.
 | 
			
		||||
        auto main_process = Kernel::KProcess::Create(system.Kernel());
 | 
			
		||||
        Kernel::KProcess::Register(system.Kernel(), main_process);
 | 
			
		||||
        kernel.AppendNewProcess(main_process);
 | 
			
		||||
@@ -323,7 +311,18 @@ struct System::Impl {
 | 
			
		||||
            return static_cast<SystemResultStatus>(
 | 
			
		||||
                static_cast<u32>(SystemResultStatus::ErrorLoader) + static_cast<u32>(load_result));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Set up the rest of the system.
 | 
			
		||||
        SystemResultStatus init_result{SetupForApplicationProcess(system, emu_window)};
 | 
			
		||||
        if (init_result != SystemResultStatus::Success) {
 | 
			
		||||
            LOG_CRITICAL(Core, "Failed to initialize system (Error {})!",
 | 
			
		||||
                         static_cast<int>(init_result));
 | 
			
		||||
            ShutdownMainProcess();
 | 
			
		||||
            return init_result;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        AddGlueRegistrationForProcess(*app_loader, *main_process);
 | 
			
		||||
        telemetry_session->AddInitialInfo(*app_loader, fs_controller, *content_provider);
 | 
			
		||||
 | 
			
		||||
        // Initialize cheat engine
 | 
			
		||||
        if (cheat_engine) {
 | 
			
		||||
@@ -426,7 +425,6 @@ struct System::Impl {
 | 
			
		||||
        cpu_manager.Shutdown();
 | 
			
		||||
        debugger.reset();
 | 
			
		||||
        kernel.Shutdown();
 | 
			
		||||
        memory.Reset();
 | 
			
		||||
        Network::RestartSocketOperations();
 | 
			
		||||
 | 
			
		||||
        if (auto room_member = room_network.GetRoomMember().lock()) {
 | 
			
		||||
@@ -507,7 +505,6 @@ struct System::Impl {
 | 
			
		||||
    std::unique_ptr<Tegra::Host1x::Host1x> host1x_core;
 | 
			
		||||
    std::unique_ptr<Core::DeviceMemory> device_memory;
 | 
			
		||||
    std::unique_ptr<AudioCore::AudioCore> audio_core;
 | 
			
		||||
    Core::Memory::Memory memory;
 | 
			
		||||
    Core::HID::HIDCore hid_core;
 | 
			
		||||
    Network::RoomNetwork room_network;
 | 
			
		||||
 | 
			
		||||
@@ -567,9 +564,6 @@ struct System::Impl {
 | 
			
		||||
    std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{};
 | 
			
		||||
    std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_cpu{};
 | 
			
		||||
 | 
			
		||||
    std::array<Core::GPUDirtyMemoryManager, Core::Hardware::NUM_CPU_CORES>
 | 
			
		||||
        gpu_dirty_memory_write_manager{};
 | 
			
		||||
 | 
			
		||||
    std::deque<std::vector<u8>> user_channel;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -652,29 +646,12 @@ void System::PrepareReschedule(const u32 core_index) {
 | 
			
		||||
    impl->kernel.PrepareReschedule(core_index);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Core::GPUDirtyMemoryManager& System::CurrentGPUDirtyMemoryManager() {
 | 
			
		||||
    const std::size_t core = impl->kernel.GetCurrentHostThreadID();
 | 
			
		||||
    return impl->gpu_dirty_memory_write_manager[core < Core::Hardware::NUM_CPU_CORES
 | 
			
		||||
                                                    ? core
 | 
			
		||||
                                                    : Core::Hardware::NUM_CPU_CORES - 1];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Provides a constant reference to the current gou dirty memory manager.
 | 
			
		||||
const Core::GPUDirtyMemoryManager& System::CurrentGPUDirtyMemoryManager() const {
 | 
			
		||||
    const std::size_t core = impl->kernel.GetCurrentHostThreadID();
 | 
			
		||||
    return impl->gpu_dirty_memory_write_manager[core < Core::Hardware::NUM_CPU_CORES
 | 
			
		||||
                                                    ? core
 | 
			
		||||
                                                    : Core::Hardware::NUM_CPU_CORES - 1];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t System::GetCurrentHostThreadID() const {
 | 
			
		||||
    return impl->kernel.GetCurrentHostThreadID();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void System::GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback) {
 | 
			
		||||
    for (auto& manager : impl->gpu_dirty_memory_write_manager) {
 | 
			
		||||
        manager.Gather(callback);
 | 
			
		||||
    }
 | 
			
		||||
    return this->ApplicationProcess()->GatherGPUDirtyMemory(callback);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PerfStatsResults System::GetAndResetPerfStats() {
 | 
			
		||||
@@ -723,20 +700,12 @@ const Kernel::KProcess* System::ApplicationProcess() const {
 | 
			
		||||
    return impl->kernel.ApplicationProcess();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ExclusiveMonitor& System::Monitor() {
 | 
			
		||||
    return impl->kernel.GetExclusiveMonitor();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const ExclusiveMonitor& System::Monitor() const {
 | 
			
		||||
    return impl->kernel.GetExclusiveMonitor();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Memory::Memory& System::ApplicationMemory() {
 | 
			
		||||
    return impl->memory;
 | 
			
		||||
    return impl->kernel.ApplicationProcess()->GetMemory();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const Core::Memory::Memory& System::ApplicationMemory() const {
 | 
			
		||||
    return impl->memory;
 | 
			
		||||
    return impl->kernel.ApplicationProcess()->GetMemory();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Tegra::GPU& System::GPU() {
 | 
			
		||||
 
 | 
			
		||||
@@ -116,7 +116,6 @@ class CpuManager;
 | 
			
		||||
class Debugger;
 | 
			
		||||
class DeviceMemory;
 | 
			
		||||
class ExclusiveMonitor;
 | 
			
		||||
class GPUDirtyMemoryManager;
 | 
			
		||||
class PerfStats;
 | 
			
		||||
class Reporter;
 | 
			
		||||
class SpeedLimiter;
 | 
			
		||||
@@ -225,12 +224,6 @@ public:
 | 
			
		||||
    /// Prepare the core emulation for a reschedule
 | 
			
		||||
    void PrepareReschedule(u32 core_index);
 | 
			
		||||
 | 
			
		||||
    /// Provides a reference to the gou dirty memory manager.
 | 
			
		||||
    [[nodiscard]] Core::GPUDirtyMemoryManager& CurrentGPUDirtyMemoryManager();
 | 
			
		||||
 | 
			
		||||
    /// Provides a constant reference to the current gou dirty memory manager.
 | 
			
		||||
    [[nodiscard]] const Core::GPUDirtyMemoryManager& CurrentGPUDirtyMemoryManager() const;
 | 
			
		||||
 | 
			
		||||
    void GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback);
 | 
			
		||||
 | 
			
		||||
    [[nodiscard]] size_t GetCurrentHostThreadID() const;
 | 
			
		||||
@@ -250,12 +243,6 @@ public:
 | 
			
		||||
    /// Gets a const reference to the underlying CPU manager
 | 
			
		||||
    [[nodiscard]] const CpuManager& GetCpuManager() const;
 | 
			
		||||
 | 
			
		||||
    /// Gets a reference to the exclusive monitor
 | 
			
		||||
    [[nodiscard]] ExclusiveMonitor& Monitor();
 | 
			
		||||
 | 
			
		||||
    /// Gets a constant reference to the exclusive monitor
 | 
			
		||||
    [[nodiscard]] const ExclusiveMonitor& Monitor() const;
 | 
			
		||||
 | 
			
		||||
    /// Gets a mutable reference to the system memory instance.
 | 
			
		||||
    [[nodiscard]] Core::Memory::Memory& ApplicationMemory();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -166,6 +166,10 @@ u32 ProgramMetadata::GetSystemResourceSize() const {
 | 
			
		||||
    return npdm_header.system_resource_size;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PoolPartition ProgramMetadata::GetPoolPartition() const {
 | 
			
		||||
    return acid_header.pool_partition;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const ProgramMetadata::KernelCapabilityDescriptors& ProgramMetadata::GetKernelCapabilities() const {
 | 
			
		||||
    return aci_kernel_capabilities;
 | 
			
		||||
}
 | 
			
		||||
@@ -201,7 +205,7 @@ void ProgramMetadata::Print() const {
 | 
			
		||||
    // Begin ACID printing (potential perms, signed)
 | 
			
		||||
    LOG_DEBUG(Service_FS, "Magic:                  {:.4}", acid_header.magic.data());
 | 
			
		||||
    LOG_DEBUG(Service_FS, "Flags:                  0x{:02X}", acid_header.flags);
 | 
			
		||||
    LOG_DEBUG(Service_FS, " > Is Retail:           {}", acid_header.is_retail ? "YES" : "NO");
 | 
			
		||||
    LOG_DEBUG(Service_FS, " > Is Retail:           {}", acid_header.production_flag ? "YES" : "NO");
 | 
			
		||||
    LOG_DEBUG(Service_FS, "Title ID Min:           0x{:016X}", acid_header.title_id_min);
 | 
			
		||||
    LOG_DEBUG(Service_FS, "Title ID Max:           0x{:016X}", acid_header.title_id_max);
 | 
			
		||||
    LOG_DEBUG(Service_FS, "Filesystem Access:      0x{:016X}\n", acid_file_access.permissions);
 | 
			
		||||
 
 | 
			
		||||
@@ -34,6 +34,13 @@ enum class ProgramFilePermission : u64 {
 | 
			
		||||
    Everything = 1ULL << 63,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class PoolPartition : u32 {
 | 
			
		||||
    Application = 0,
 | 
			
		||||
    Applet = 1,
 | 
			
		||||
    System = 2,
 | 
			
		||||
    SystemNonSecure = 3,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Helper which implements an interface to parse Program Description Metadata (NPDM)
 | 
			
		||||
 * Data can either be loaded from a file path or with data and an offset into it.
 | 
			
		||||
@@ -72,6 +79,7 @@ public:
 | 
			
		||||
    u64 GetTitleID() const;
 | 
			
		||||
    u64 GetFilesystemPermissions() const;
 | 
			
		||||
    u32 GetSystemResourceSize() const;
 | 
			
		||||
    PoolPartition GetPoolPartition() const;
 | 
			
		||||
    const KernelCapabilityDescriptors& GetKernelCapabilities() const;
 | 
			
		||||
    const std::array<u8, 0x10>& GetName() const {
 | 
			
		||||
        return npdm_header.application_name;
 | 
			
		||||
@@ -116,8 +124,9 @@ private:
 | 
			
		||||
        union {
 | 
			
		||||
            u32 flags;
 | 
			
		||||
 | 
			
		||||
            BitField<0, 1, u32> is_retail;
 | 
			
		||||
            BitField<1, 31, u32> flags_unk;
 | 
			
		||||
            BitField<0, 1, u32> production_flag;
 | 
			
		||||
            BitField<1, 1, u32> unqualified_approval;
 | 
			
		||||
            BitField<2, 4, PoolPartition> pool_partition;
 | 
			
		||||
        };
 | 
			
		||||
        u64_le title_id_min;
 | 
			
		||||
        u64_le title_id_max;
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@
 | 
			
		||||
#include "core/arm/exclusive_monitor.h"
 | 
			
		||||
#include "core/core.h"
 | 
			
		||||
#include "core/hle/kernel/k_address_arbiter.h"
 | 
			
		||||
#include "core/hle/kernel/k_process.h"
 | 
			
		||||
#include "core/hle/kernel/k_scheduler.h"
 | 
			
		||||
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
 | 
			
		||||
#include "core/hle/kernel/k_thread.h"
 | 
			
		||||
@@ -26,9 +27,9 @@ bool ReadFromUser(KernelCore& kernel, s32* out, KProcessAddress address) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool DecrementIfLessThan(Core::System& system, s32* out, KProcessAddress address, s32 value) {
 | 
			
		||||
    auto& monitor = system.Monitor();
 | 
			
		||||
    const auto current_core = system.Kernel().CurrentPhysicalCoreIndex();
 | 
			
		||||
bool DecrementIfLessThan(KernelCore& kernel, s32* out, KProcessAddress address, s32 value) {
 | 
			
		||||
    auto& monitor = GetCurrentProcess(kernel).GetExclusiveMonitor();
 | 
			
		||||
    const auto current_core = kernel.CurrentPhysicalCoreIndex();
 | 
			
		||||
 | 
			
		||||
    // NOTE: If scheduler lock is not held here, interrupt disable is required.
 | 
			
		||||
    // KScopedInterruptDisable di;
 | 
			
		||||
@@ -66,10 +67,10 @@ bool DecrementIfLessThan(Core::System& system, s32* out, KProcessAddress address
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool UpdateIfEqual(Core::System& system, s32* out, KProcessAddress address, s32 value,
 | 
			
		||||
bool UpdateIfEqual(KernelCore& kernel, s32* out, KProcessAddress address, s32 value,
 | 
			
		||||
                   s32 new_value) {
 | 
			
		||||
    auto& monitor = system.Monitor();
 | 
			
		||||
    const auto current_core = system.Kernel().CurrentPhysicalCoreIndex();
 | 
			
		||||
    auto& monitor = GetCurrentProcess(kernel).GetExclusiveMonitor();
 | 
			
		||||
    const auto current_core = kernel.CurrentPhysicalCoreIndex();
 | 
			
		||||
 | 
			
		||||
    // NOTE: If scheduler lock is not held here, interrupt disable is required.
 | 
			
		||||
    // KScopedInterruptDisable di;
 | 
			
		||||
@@ -159,7 +160,7 @@ Result KAddressArbiter::SignalAndIncrementIfEqual(uint64_t addr, s32 value, s32
 | 
			
		||||
 | 
			
		||||
        // Check the userspace value.
 | 
			
		||||
        s32 user_value{};
 | 
			
		||||
        R_UNLESS(UpdateIfEqual(m_system, std::addressof(user_value), addr, value, value + 1),
 | 
			
		||||
        R_UNLESS(UpdateIfEqual(m_kernel, std::addressof(user_value), addr, value, value + 1),
 | 
			
		||||
                 ResultInvalidCurrentMemory);
 | 
			
		||||
        R_UNLESS(user_value == value, ResultInvalidState);
 | 
			
		||||
 | 
			
		||||
@@ -219,7 +220,7 @@ Result KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(uint64_t addr, s32
 | 
			
		||||
        s32 user_value{};
 | 
			
		||||
        bool succeeded{};
 | 
			
		||||
        if (value != new_value) {
 | 
			
		||||
            succeeded = UpdateIfEqual(m_system, std::addressof(user_value), addr, value, new_value);
 | 
			
		||||
            succeeded = UpdateIfEqual(m_kernel, std::addressof(user_value), addr, value, new_value);
 | 
			
		||||
        } else {
 | 
			
		||||
            succeeded = ReadFromUser(m_kernel, std::addressof(user_value), addr);
 | 
			
		||||
        }
 | 
			
		||||
@@ -262,7 +263,7 @@ Result KAddressArbiter::WaitIfLessThan(uint64_t addr, s32 value, bool decrement,
 | 
			
		||||
        s32 user_value{};
 | 
			
		||||
        bool succeeded{};
 | 
			
		||||
        if (decrement) {
 | 
			
		||||
            succeeded = DecrementIfLessThan(m_system, std::addressof(user_value), addr, value);
 | 
			
		||||
            succeeded = DecrementIfLessThan(m_kernel, std::addressof(user_value), addr, value);
 | 
			
		||||
        } else {
 | 
			
		||||
            succeeded = ReadFromUser(m_kernel, std::addressof(user_value), addr);
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -58,9 +58,8 @@ Result KClientPort::CreateSession(KClientSession** out) {
 | 
			
		||||
    KSession* session{};
 | 
			
		||||
 | 
			
		||||
    // Reserve a new session from the resource limit.
 | 
			
		||||
    //! FIXME: we are reserving this from the wrong resource limit!
 | 
			
		||||
    KScopedResourceReservation session_reservation(
 | 
			
		||||
        m_kernel.ApplicationProcess()->GetResourceLimit(), LimitableResource::SessionCountMax);
 | 
			
		||||
    KScopedResourceReservation session_reservation(GetCurrentProcessPointer(m_kernel),
 | 
			
		||||
                                                   LimitableResource::SessionCountMax);
 | 
			
		||||
    R_UNLESS(session_reservation.Succeeded(), ResultLimitReached);
 | 
			
		||||
 | 
			
		||||
    // Allocate a session normally.
 | 
			
		||||
 
 | 
			
		||||
@@ -28,10 +28,10 @@ bool WriteToUser(KernelCore& kernel, KProcessAddress address, const u32* p) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool UpdateLockAtomic(Core::System& system, u32* out, KProcessAddress address, u32 if_zero,
 | 
			
		||||
bool UpdateLockAtomic(KernelCore& kernel, u32* out, KProcessAddress address, u32 if_zero,
 | 
			
		||||
                      u32 new_orr_mask) {
 | 
			
		||||
    auto& monitor = system.Monitor();
 | 
			
		||||
    const auto current_core = system.Kernel().CurrentPhysicalCoreIndex();
 | 
			
		||||
    auto& monitor = GetCurrentProcess(kernel).GetExclusiveMonitor();
 | 
			
		||||
    const auto current_core = kernel.CurrentPhysicalCoreIndex();
 | 
			
		||||
 | 
			
		||||
    u32 expected{};
 | 
			
		||||
 | 
			
		||||
@@ -208,7 +208,7 @@ void KConditionVariable::SignalImpl(KThread* thread) {
 | 
			
		||||
        // TODO(bunnei): We should call CanAccessAtomic(..) here.
 | 
			
		||||
        can_access = true;
 | 
			
		||||
        if (can_access) [[likely]] {
 | 
			
		||||
            UpdateLockAtomic(m_system, std::addressof(prev_tag), address, own_tag,
 | 
			
		||||
            UpdateLockAtomic(m_kernel, std::addressof(prev_tag), address, own_tag,
 | 
			
		||||
                             Svc::HandleWaitMask);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -30,7 +30,7 @@ public:
 | 
			
		||||
public:
 | 
			
		||||
    explicit KHandleTable(KernelCore& kernel) : m_kernel(kernel) {}
 | 
			
		||||
 | 
			
		||||
    Result Initialize(s32 size) {
 | 
			
		||||
    Result Initialize(KProcess* owner, s32 size) {
 | 
			
		||||
        // Check that the table size is valid.
 | 
			
		||||
        R_UNLESS(size <= static_cast<s32>(MaxTableSize), ResultOutOfMemory);
 | 
			
		||||
 | 
			
		||||
@@ -44,6 +44,7 @@ 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) {
 | 
			
		||||
@@ -90,8 +91,8 @@ public:
 | 
			
		||||
        // Handle pseudo-handles.
 | 
			
		||||
        if constexpr (std::derived_from<KProcess, T>) {
 | 
			
		||||
            if (handle == Svc::PseudoHandle::CurrentProcess) {
 | 
			
		||||
                //! FIXME: this is the wrong process!
 | 
			
		||||
                auto* const cur_process = m_kernel.ApplicationProcess();
 | 
			
		||||
                // TODO: this should be the current process
 | 
			
		||||
                auto* const cur_process = m_owner;
 | 
			
		||||
                ASSERT(cur_process != nullptr);
 | 
			
		||||
                return cur_process;
 | 
			
		||||
            }
 | 
			
		||||
@@ -301,6 +302,7 @@ 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;
 | 
			
		||||
 
 | 
			
		||||
@@ -306,12 +306,16 @@ Result KProcess::Initialize(const Svc::CreateProcessParameter& params, const KPa
 | 
			
		||||
            False(params.flags & Svc::CreateProcessFlag::DisableDeviceAddressSpaceMerge);
 | 
			
		||||
        R_TRY(m_page_table.Initialize(as_type, enable_aslr, enable_das_merge, !enable_aslr, pool,
 | 
			
		||||
                                      params.code_address, params.code_num_pages * PageSize,
 | 
			
		||||
                                      m_system_resource, res_limit, this->GetMemory(), 0));
 | 
			
		||||
                                      m_system_resource, res_limit, m_memory, 0));
 | 
			
		||||
    }
 | 
			
		||||
    ON_RESULT_FAILURE_2 {
 | 
			
		||||
        m_page_table.Finalize();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // Ensure our memory is initialized.
 | 
			
		||||
    m_memory.SetCurrentPageTable(*this);
 | 
			
		||||
    m_memory.SetGPUDirtyManagers(m_dirty_memory_managers);
 | 
			
		||||
 | 
			
		||||
    // Ensure we can insert the code region.
 | 
			
		||||
    R_UNLESS(m_page_table.CanContain(params.code_address, params.code_num_pages * PageSize,
 | 
			
		||||
                                     KMemoryState::Code),
 | 
			
		||||
@@ -399,12 +403,16 @@ Result KProcess::Initialize(const Svc::CreateProcessParameter& params,
 | 
			
		||||
            False(params.flags & Svc::CreateProcessFlag::DisableDeviceAddressSpaceMerge);
 | 
			
		||||
        R_TRY(m_page_table.Initialize(as_type, enable_aslr, enable_das_merge, !enable_aslr, pool,
 | 
			
		||||
                                      params.code_address, code_size, m_system_resource, res_limit,
 | 
			
		||||
                                      this->GetMemory(), aslr_space_start));
 | 
			
		||||
                                      m_memory, aslr_space_start));
 | 
			
		||||
    }
 | 
			
		||||
    ON_RESULT_FAILURE_2 {
 | 
			
		||||
        m_page_table.Finalize();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // Ensure our memory is initialized.
 | 
			
		||||
    m_memory.SetCurrentPageTable(*this);
 | 
			
		||||
    m_memory.SetGPUDirtyManagers(m_dirty_memory_managers);
 | 
			
		||||
 | 
			
		||||
    // Ensure we can insert the code region.
 | 
			
		||||
    R_UNLESS(m_page_table.CanContain(params.code_address, code_size, KMemoryState::Code),
 | 
			
		||||
             ResultInvalidMemoryRegion);
 | 
			
		||||
@@ -1094,8 +1102,7 @@ void KProcess::UnpinThread(KThread* thread) {
 | 
			
		||||
 | 
			
		||||
Result KProcess::GetThreadList(s32* out_num_threads, KProcessAddress out_thread_ids,
 | 
			
		||||
                               s32 max_out_count) {
 | 
			
		||||
    // TODO: use current memory reference
 | 
			
		||||
    auto& memory = m_kernel.System().ApplicationMemory();
 | 
			
		||||
    auto& memory = this->GetMemory();
 | 
			
		||||
 | 
			
		||||
    // Lock the list.
 | 
			
		||||
    KScopedLightLock lk(m_list_lock);
 | 
			
		||||
@@ -1128,14 +1135,15 @@ void KProcess::Switch(KProcess* cur_process, KProcess* next_process) {}
 | 
			
		||||
KProcess::KProcess(KernelCore& kernel)
 | 
			
		||||
    : KAutoObjectWithSlabHeapAndContainer(kernel), m_page_table{kernel}, m_state_lock{kernel},
 | 
			
		||||
      m_list_lock{kernel}, m_cond_var{kernel.System()}, m_address_arbiter{kernel.System()},
 | 
			
		||||
      m_handle_table{kernel} {}
 | 
			
		||||
      m_handle_table{kernel}, m_dirty_memory_managers{},
 | 
			
		||||
      m_exclusive_monitor{}, m_memory{kernel.System()} {}
 | 
			
		||||
KProcess::~KProcess() = default;
 | 
			
		||||
 | 
			
		||||
Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size,
 | 
			
		||||
                                  KProcessAddress aslr_space_start, bool is_hbl) {
 | 
			
		||||
    // Create a resource limit for the process.
 | 
			
		||||
    const auto physical_memory_size =
 | 
			
		||||
        m_kernel.MemoryManager().GetSize(Kernel::KMemoryManager::Pool::Application);
 | 
			
		||||
    const auto pool = static_cast<KMemoryManager::Pool>(metadata.GetPoolPartition());
 | 
			
		||||
    const auto physical_memory_size = m_kernel.MemoryManager().GetSize(pool);
 | 
			
		||||
    auto* res_limit =
 | 
			
		||||
        Kernel::CreateResourceLimitForProcess(m_kernel.System(), physical_memory_size);
 | 
			
		||||
 | 
			
		||||
@@ -1146,8 +1154,10 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
 | 
			
		||||
    Svc::CreateProcessFlag flag{};
 | 
			
		||||
    u64 code_address{};
 | 
			
		||||
 | 
			
		||||
    // We are an application.
 | 
			
		||||
    flag |= Svc::CreateProcessFlag::IsApplication;
 | 
			
		||||
    // Determine if we are an application.
 | 
			
		||||
    if (pool == KMemoryManager::Pool::Application) {
 | 
			
		||||
        flag |= Svc::CreateProcessFlag::IsApplication;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // If we are 64-bit, create as such.
 | 
			
		||||
    if (metadata.Is64BitProgram()) {
 | 
			
		||||
@@ -1196,8 +1206,8 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
 | 
			
		||||
    std::memcpy(params.name.data(), name.data(), sizeof(params.name));
 | 
			
		||||
 | 
			
		||||
    // Initialize for application process.
 | 
			
		||||
    R_TRY(this->Initialize(params, metadata.GetKernelCapabilities(), res_limit,
 | 
			
		||||
                           KMemoryManager::Pool::Application, aslr_space_start));
 | 
			
		||||
    R_TRY(this->Initialize(params, metadata.GetKernelCapabilities(), res_limit, pool,
 | 
			
		||||
                           aslr_space_start));
 | 
			
		||||
 | 
			
		||||
    // Assign remaining properties.
 | 
			
		||||
    m_is_hbl = is_hbl;
 | 
			
		||||
@@ -1223,7 +1233,7 @@ void KProcess::LoadModule(CodeSet code_set, KProcessAddress base_addr) {
 | 
			
		||||
    ReprotectSegment(code_set.DataSegment(), Svc::MemoryPermission::ReadWrite);
 | 
			
		||||
 | 
			
		||||
#ifdef HAS_NCE
 | 
			
		||||
    if (Settings::IsNceEnabled()) {
 | 
			
		||||
    if (this->IsApplication() && Settings::IsNceEnabled()) {
 | 
			
		||||
        auto& buffer = m_kernel.System().DeviceMemory().buffer;
 | 
			
		||||
        const auto& code = code_set.CodeSegment();
 | 
			
		||||
        const auto& patch = code_set.PatchSegment();
 | 
			
		||||
@@ -1235,10 +1245,11 @@ void KProcess::LoadModule(CodeSet code_set, KProcessAddress base_addr) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void KProcess::InitializeInterfaces() {
 | 
			
		||||
    this->GetMemory().SetCurrentPageTable(*this);
 | 
			
		||||
    m_exclusive_monitor =
 | 
			
		||||
        Core::MakeExclusiveMonitor(this->GetMemory(), Core::Hardware::NUM_CPU_CORES);
 | 
			
		||||
 | 
			
		||||
#ifdef HAS_NCE
 | 
			
		||||
    if (this->Is64Bit() && Settings::IsNceEnabled()) {
 | 
			
		||||
    if (this->IsApplication() && Settings::IsNceEnabled()) {
 | 
			
		||||
        for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
 | 
			
		||||
            m_arm_interfaces[i] = std::make_unique<Core::ArmNce>(m_kernel.System(), true, i);
 | 
			
		||||
        }
 | 
			
		||||
@@ -1248,13 +1259,13 @@ void KProcess::InitializeInterfaces() {
 | 
			
		||||
        for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
 | 
			
		||||
            m_arm_interfaces[i] = std::make_unique<Core::ArmDynarmic64>(
 | 
			
		||||
                m_kernel.System(), m_kernel.IsMulticore(), this,
 | 
			
		||||
                static_cast<Core::DynarmicExclusiveMonitor&>(m_kernel.GetExclusiveMonitor()), i);
 | 
			
		||||
                static_cast<Core::DynarmicExclusiveMonitor&>(*m_exclusive_monitor), i);
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
 | 
			
		||||
            m_arm_interfaces[i] = std::make_unique<Core::ArmDynarmic32>(
 | 
			
		||||
                m_kernel.System(), m_kernel.IsMulticore(), this,
 | 
			
		||||
                static_cast<Core::DynarmicExclusiveMonitor&>(m_kernel.GetExclusiveMonitor()), i);
 | 
			
		||||
                static_cast<Core::DynarmicExclusiveMonitor&>(*m_exclusive_monitor), i);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1305,9 +1316,10 @@ bool KProcess::RemoveWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointT
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Core::Memory::Memory& KProcess::GetMemory() const {
 | 
			
		||||
    // TODO: per-process memory
 | 
			
		||||
    return m_kernel.System().ApplicationMemory();
 | 
			
		||||
void KProcess::GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback) {
 | 
			
		||||
    for (auto& manager : m_dirty_memory_managers) {
 | 
			
		||||
        manager.Gather(callback);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace Kernel
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@
 | 
			
		||||
 | 
			
		||||
#include "core/arm/arm_interface.h"
 | 
			
		||||
#include "core/file_sys/program_metadata.h"
 | 
			
		||||
#include "core/gpu_dirty_memory_manager.h"
 | 
			
		||||
#include "core/hle/kernel/code_set.h"
 | 
			
		||||
#include "core/hle/kernel/k_address_arbiter.h"
 | 
			
		||||
#include "core/hle/kernel/k_capabilities.h"
 | 
			
		||||
@@ -17,6 +18,7 @@
 | 
			
		||||
#include "core/hle/kernel/k_system_resource.h"
 | 
			
		||||
#include "core/hle/kernel/k_thread.h"
 | 
			
		||||
#include "core/hle/kernel/k_thread_local_page.h"
 | 
			
		||||
#include "core/memory.h"
 | 
			
		||||
 | 
			
		||||
namespace Kernel {
 | 
			
		||||
 | 
			
		||||
@@ -126,6 +128,9 @@ private:
 | 
			
		||||
#ifdef HAS_NCE
 | 
			
		||||
    std::unordered_map<u64, u64> m_post_handlers{};
 | 
			
		||||
#endif
 | 
			
		||||
    std::array<Core::GPUDirtyMemoryManager, Core::Hardware::NUM_CPU_CORES> m_dirty_memory_managers;
 | 
			
		||||
    std::unique_ptr<Core::ExclusiveMonitor> m_exclusive_monitor;
 | 
			
		||||
    Core::Memory::Memory m_memory;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    Result StartTermination();
 | 
			
		||||
@@ -502,7 +507,15 @@ public:
 | 
			
		||||
 | 
			
		||||
    void InitializeInterfaces();
 | 
			
		||||
 | 
			
		||||
    Core::Memory::Memory& GetMemory() const;
 | 
			
		||||
    Core::Memory::Memory& GetMemory() {
 | 
			
		||||
        return m_memory;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback);
 | 
			
		||||
 | 
			
		||||
    Core::ExclusiveMonitor& GetExclusiveMonitor() const {
 | 
			
		||||
        return *m_exclusive_monitor;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    // Overridden parent functions.
 | 
			
		||||
@@ -539,7 +552,7 @@ private:
 | 
			
		||||
 | 
			
		||||
    Result InitializeHandleTable(s32 size) {
 | 
			
		||||
        // Try to initialize the handle table.
 | 
			
		||||
        R_TRY(m_handle_table.Initialize(size));
 | 
			
		||||
        R_TRY(m_handle_table.Initialize(this, size));
 | 
			
		||||
 | 
			
		||||
        // We succeeded, so note that we did.
 | 
			
		||||
        m_is_handle_table_initialized = true;
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -49,14 +49,21 @@ public:
 | 
			
		||||
    bool IsSignaled() const override;
 | 
			
		||||
    void OnClientClosed();
 | 
			
		||||
 | 
			
		||||
    /// TODO: flesh these out to match the real kernel
 | 
			
		||||
    Result OnRequest(KSessionRequest* request);
 | 
			
		||||
    Result SendReply(bool is_hle = false);
 | 
			
		||||
    Result ReceiveRequest(std::shared_ptr<Service::HLERequestContext>* out_context = nullptr,
 | 
			
		||||
    Result SendReply(uintptr_t server_message, uintptr_t server_buffer_size,
 | 
			
		||||
                     KPhysicalAddress server_message_paddr, bool is_hle = false);
 | 
			
		||||
    Result ReceiveRequest(uintptr_t server_message, uintptr_t server_buffer_size,
 | 
			
		||||
                          KPhysicalAddress server_message_paddr,
 | 
			
		||||
                          std::shared_ptr<Service::HLERequestContext>* out_context = nullptr,
 | 
			
		||||
                          std::weak_ptr<Service::SessionRequestManager> manager = {});
 | 
			
		||||
 | 
			
		||||
    Result SendReplyHLE() {
 | 
			
		||||
        return SendReply(true);
 | 
			
		||||
        R_RETURN(this->SendReply(0, 0, 0, true));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Result ReceiveRequestHLE(std::shared_ptr<Service::HLERequestContext>* out_context,
 | 
			
		||||
                             std::weak_ptr<Service::SessionRequestManager> manager) {
 | 
			
		||||
        R_RETURN(this->ReceiveRequest(0, 0, 0, out_context, manager));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
 
 | 
			
		||||
@@ -33,8 +33,7 @@ void KSession::Initialize(KClientPort* client_port, uintptr_t name) {
 | 
			
		||||
    m_name = name;
 | 
			
		||||
 | 
			
		||||
    // Set our owner process.
 | 
			
		||||
    //! FIXME: this is the wrong process!
 | 
			
		||||
    m_process = m_kernel.ApplicationProcess();
 | 
			
		||||
    m_process = GetCurrentProcessPointer(m_kernel);
 | 
			
		||||
    m_process->Open();
 | 
			
		||||
 | 
			
		||||
    // Set our port.
 | 
			
		||||
 
 | 
			
		||||
@@ -1422,8 +1422,7 @@ s32 GetCurrentCoreId(KernelCore& kernel) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Core::Memory::Memory& GetCurrentMemory(KernelCore& kernel) {
 | 
			
		||||
    // TODO: per-process memory
 | 
			
		||||
    return kernel.System().ApplicationMemory();
 | 
			
		||||
    return GetCurrentProcess(kernel).GetMemory();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
KScopedDisableDispatch::~KScopedDisableDispatch() {
 | 
			
		||||
 
 | 
			
		||||
@@ -314,11 +314,7 @@ public:
 | 
			
		||||
        m_current_core_id = core;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    KProcess* GetOwnerProcess() {
 | 
			
		||||
        return m_parent;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const KProcess* GetOwnerProcess() const {
 | 
			
		||||
    KProcess* GetOwnerProcess() const {
 | 
			
		||||
        return m_parent;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -68,8 +68,6 @@ struct KernelCore::Impl {
 | 
			
		||||
 | 
			
		||||
        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);
 | 
			
		||||
        global_handle_table->Initialize(KHandleTable::MaxTableSize);
 | 
			
		||||
 | 
			
		||||
        is_phantom_mode_for_singlecore = false;
 | 
			
		||||
 | 
			
		||||
@@ -121,13 +119,8 @@ struct KernelCore::Impl {
 | 
			
		||||
        next_user_process_id = KProcess::ProcessIdMin;
 | 
			
		||||
        next_thread_id = 1;
 | 
			
		||||
 | 
			
		||||
        global_handle_table->Finalize();
 | 
			
		||||
        global_handle_table.reset();
 | 
			
		||||
 | 
			
		||||
        preemption_event = nullptr;
 | 
			
		||||
 | 
			
		||||
        exclusive_monitor.reset();
 | 
			
		||||
 | 
			
		||||
        // Cleanup persistent kernel objects
 | 
			
		||||
        auto CleanupObject = [](KAutoObject* obj) {
 | 
			
		||||
            if (obj) {
 | 
			
		||||
@@ -191,8 +184,6 @@ struct KernelCore::Impl {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void InitializePhysicalCores() {
 | 
			
		||||
        exclusive_monitor =
 | 
			
		||||
            Core::MakeExclusiveMonitor(system.ApplicationMemory(), Core::Hardware::NUM_CPU_CORES);
 | 
			
		||||
        for (u32 i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
 | 
			
		||||
            const s32 core{static_cast<s32>(i)};
 | 
			
		||||
 | 
			
		||||
@@ -791,10 +782,6 @@ struct KernelCore::Impl {
 | 
			
		||||
 | 
			
		||||
    std::shared_ptr<Core::Timing::EventType> preemption_event;
 | 
			
		||||
 | 
			
		||||
    // This is the kernel's handle table or supervisor handle table which
 | 
			
		||||
    // stores all the objects in place.
 | 
			
		||||
    std::unique_ptr<KHandleTable> global_handle_table;
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr<KAutoObjectWithListContainer> global_object_list_container;
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr<KObjectNameGlobalData> object_name_global_data;
 | 
			
		||||
@@ -805,7 +792,6 @@ struct KernelCore::Impl {
 | 
			
		||||
    std::mutex server_lock;
 | 
			
		||||
    std::vector<std::unique_ptr<Service::ServerManager>> server_managers;
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor;
 | 
			
		||||
    std::array<std::unique_ptr<Kernel::PhysicalCore>, Core::Hardware::NUM_CPU_CORES> cores;
 | 
			
		||||
 | 
			
		||||
    // Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others
 | 
			
		||||
@@ -882,10 +868,6 @@ KResourceLimit* KernelCore::GetSystemResourceLimit() {
 | 
			
		||||
    return impl->system_resource_limit;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
KScopedAutoObject<KThread> KernelCore::RetrieveThreadFromGlobalHandleTable(Handle handle) const {
 | 
			
		||||
    return impl->global_handle_table->GetObject<KThread>(handle);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void KernelCore::AppendNewProcess(KProcess* process) {
 | 
			
		||||
    impl->process_list.push_back(process);
 | 
			
		||||
}
 | 
			
		||||
@@ -959,14 +941,6 @@ Kernel::KHardwareTimer& KernelCore::HardwareTimer() {
 | 
			
		||||
    return *impl->hardware_timer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() {
 | 
			
		||||
    return *impl->exclusive_monitor;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() const {
 | 
			
		||||
    return *impl->exclusive_monitor;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
KAutoObjectWithListContainer& KernelCore::ObjectListContainer() {
 | 
			
		||||
    return *impl->global_object_list_container;
 | 
			
		||||
}
 | 
			
		||||
@@ -1030,14 +1004,6 @@ u64 KernelCore::CreateNewUserProcessID() {
 | 
			
		||||
    return impl->next_user_process_id++;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
KHandleTable& KernelCore::GlobalHandleTable() {
 | 
			
		||||
    return *impl->global_handle_table;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const KHandleTable& KernelCore::GlobalHandleTable() const {
 | 
			
		||||
    return *impl->global_handle_table;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void KernelCore::RegisterCoreThread(std::size_t core_id) {
 | 
			
		||||
    impl->RegisterCoreThread(core_id);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -116,9 +116,6 @@ public:
 | 
			
		||||
    /// Retrieves a shared pointer to the system resource limit instance.
 | 
			
		||||
    KResourceLimit* GetSystemResourceLimit();
 | 
			
		||||
 | 
			
		||||
    /// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table.
 | 
			
		||||
    KScopedAutoObject<KThread> RetrieveThreadFromGlobalHandleTable(Handle handle) const;
 | 
			
		||||
 | 
			
		||||
    /// Adds the given shared pointer to an internal list of active processes.
 | 
			
		||||
    void AppendNewProcess(KProcess* process);
 | 
			
		||||
 | 
			
		||||
@@ -170,10 +167,6 @@ public:
 | 
			
		||||
    /// Stops execution of 'id' core, in order to reschedule a new thread.
 | 
			
		||||
    void PrepareReschedule(std::size_t id);
 | 
			
		||||
 | 
			
		||||
    Core::ExclusiveMonitor& GetExclusiveMonitor();
 | 
			
		||||
 | 
			
		||||
    const Core::ExclusiveMonitor& GetExclusiveMonitor() const;
 | 
			
		||||
 | 
			
		||||
    KAutoObjectWithListContainer& ObjectListContainer();
 | 
			
		||||
 | 
			
		||||
    const KAutoObjectWithListContainer& ObjectListContainer() const;
 | 
			
		||||
 
 | 
			
		||||
@@ -18,13 +18,13 @@ public:
 | 
			
		||||
        static constexpr inline u64 NullTag = 0;
 | 
			
		||||
 | 
			
		||||
    public:
 | 
			
		||||
        enum class ReceiveListCountType : u32 {
 | 
			
		||||
            None = 0,
 | 
			
		||||
            ToMessageBuffer = 1,
 | 
			
		||||
            ToSingleBuffer = 2,
 | 
			
		||||
        enum ReceiveListCountType : u32 {
 | 
			
		||||
            ReceiveListCountType_None = 0,
 | 
			
		||||
            ReceiveListCountType_ToMessageBuffer = 1,
 | 
			
		||||
            ReceiveListCountType_ToSingleBuffer = 2,
 | 
			
		||||
 | 
			
		||||
            CountOffset = 2,
 | 
			
		||||
            CountMax = 13,
 | 
			
		||||
            ReceiveListCountType_CountOffset = 2,
 | 
			
		||||
            ReceiveListCountType_CountMax = 13,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
@@ -591,16 +591,16 @@ public:
 | 
			
		||||
        // Add the size of the receive list.
 | 
			
		||||
        const auto count = hdr.GetReceiveListCount();
 | 
			
		||||
        switch (count) {
 | 
			
		||||
        case MessageHeader::ReceiveListCountType::None:
 | 
			
		||||
        case MessageHeader::ReceiveListCountType_None:
 | 
			
		||||
            break;
 | 
			
		||||
        case MessageHeader::ReceiveListCountType::ToMessageBuffer:
 | 
			
		||||
        case MessageHeader::ReceiveListCountType_ToMessageBuffer:
 | 
			
		||||
            break;
 | 
			
		||||
        case MessageHeader::ReceiveListCountType::ToSingleBuffer:
 | 
			
		||||
        case MessageHeader::ReceiveListCountType_ToSingleBuffer:
 | 
			
		||||
            msg_size += ReceiveListEntry::GetDataSize();
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            msg_size += (static_cast<s32>(count) -
 | 
			
		||||
                         static_cast<s32>(MessageHeader::ReceiveListCountType::CountOffset)) *
 | 
			
		||||
                         static_cast<s32>(MessageHeader::ReceiveListCountType_CountOffset)) *
 | 
			
		||||
                        ReceiveListEntry::GetDataSize();
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -118,7 +118,6 @@ Result GetInfo(Core::System& system, u64* result, InfoType info_id_type, Handle
 | 
			
		||||
            R_SUCCEED();
 | 
			
		||||
 | 
			
		||||
        case InfoType::IsApplication:
 | 
			
		||||
            LOG_WARNING(Kernel_SVC, "(STUBBED) Assuming process is application");
 | 
			
		||||
            *result = process->IsApplication();
 | 
			
		||||
            R_SUCCEED();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -48,8 +48,7 @@ Result ReplyAndReceiveImpl(KernelCore& kernel, int32_t* out_index, uintptr_t mes
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Send the reply.
 | 
			
		||||
        R_TRY(session->SendReply());
 | 
			
		||||
        // R_TRY(session->SendReply(message, buffer_size, message_paddr));
 | 
			
		||||
        R_TRY(session->SendReply(message, buffer_size, message_paddr));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Receive a message.
 | 
			
		||||
@@ -85,8 +84,7 @@ Result ReplyAndReceiveImpl(KernelCore& kernel, int32_t* out_index, uintptr_t mes
 | 
			
		||||
            if (R_SUCCEEDED(result)) {
 | 
			
		||||
                KServerSession* session = objs[index]->DynamicCast<KServerSession*>();
 | 
			
		||||
                if (session != nullptr) {
 | 
			
		||||
                    // result = session->ReceiveRequest(message, buffer_size, message_paddr);
 | 
			
		||||
                    result = session->ReceiveRequest();
 | 
			
		||||
                    result = session->ReceiveRequest(message, buffer_size, message_paddr);
 | 
			
		||||
                    if (ResultNotFound == result) {
 | 
			
		||||
                        continue;
 | 
			
		||||
                    }
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,9 @@ constexpr Result ResultInvalidState{ErrorModule::Kernel, 125};
 | 
			
		||||
constexpr Result ResultReservedUsed{ErrorModule::Kernel, 126};
 | 
			
		||||
constexpr Result ResultPortClosed{ErrorModule::Kernel, 131};
 | 
			
		||||
constexpr Result ResultLimitReached{ErrorModule::Kernel, 132};
 | 
			
		||||
constexpr Result ResultReceiveListBroken{ErrorModule::Kernel, 258};
 | 
			
		||||
constexpr Result ResultOutOfAddressSpace{ErrorModule::Kernel, 259};
 | 
			
		||||
constexpr Result ResultMessageTooLarge{ErrorModule::Kernel, 260};
 | 
			
		||||
constexpr Result ResultInvalidId{ErrorModule::Kernel, 519};
 | 
			
		||||
 | 
			
		||||
} // namespace Kernel
 | 
			
		||||
 
 | 
			
		||||
@@ -89,7 +89,7 @@ static void GenerateErrorReport(Core::System& system, Result error_code, const F
 | 
			
		||||
        crash_report += fmt::format("    ESR:                         {:016x}\n", info.esr);
 | 
			
		||||
        crash_report += fmt::format("    FAR:                         {:016x}\n", info.far);
 | 
			
		||||
        crash_report += "\nBacktrace:\n";
 | 
			
		||||
        for (size_t i = 0; i < info.backtrace_size; i++) {
 | 
			
		||||
        for (u32 i = 0; i < std::min<u32>(info.backtrace_size, 32); i++) {
 | 
			
		||||
            crash_report +=
 | 
			
		||||
                fmt::format("    Backtrace[{:02d}]:               {:016x}\n", i, info.backtrace[i]);
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -151,8 +151,8 @@ public:
 | 
			
		||||
        if (manager->IsDomain()) {
 | 
			
		||||
            context->AddDomainObject(std::move(iface));
 | 
			
		||||
        } else {
 | 
			
		||||
            kernel.ApplicationProcess()->GetResourceLimit()->Reserve(
 | 
			
		||||
                Kernel::LimitableResource::SessionCountMax, 1);
 | 
			
		||||
            ASSERT(Kernel::GetCurrentProcess(kernel).GetResourceLimit()->Reserve(
 | 
			
		||||
                Kernel::LimitableResource::SessionCountMax, 1));
 | 
			
		||||
 | 
			
		||||
            auto* session = Kernel::KSession::Create(kernel);
 | 
			
		||||
            session->Initialize(nullptr, 0);
 | 
			
		||||
 
 | 
			
		||||
@@ -47,7 +47,7 @@ ServerManager::~ServerManager() {
 | 
			
		||||
    m_stopped.Wait();
 | 
			
		||||
    m_threads.clear();
 | 
			
		||||
 | 
			
		||||
    // Clean up ports.
 | 
			
		||||
    // Clean up server ports.
 | 
			
		||||
    for (const auto& [port, handler] : m_ports) {
 | 
			
		||||
        port->Close();
 | 
			
		||||
    }
 | 
			
		||||
@@ -97,22 +97,15 @@ Result ServerManager::RegisterNamedService(const std::string& service_name,
 | 
			
		||||
                                           u32 max_sessions) {
 | 
			
		||||
    ASSERT(m_sessions.size() + m_ports.size() < MaximumWaitObjects);
 | 
			
		||||
 | 
			
		||||
    // Add the new server to sm:.
 | 
			
		||||
    ASSERT(R_SUCCEEDED(
 | 
			
		||||
        m_system.ServiceManager().RegisterService(service_name, max_sessions, handler_factory)));
 | 
			
		||||
 | 
			
		||||
    // Get the registered port.
 | 
			
		||||
    Kernel::KPort* port{};
 | 
			
		||||
    ASSERT(
 | 
			
		||||
        R_SUCCEEDED(m_system.ServiceManager().GetServicePort(std::addressof(port), service_name)));
 | 
			
		||||
 | 
			
		||||
    // Open a new reference to the server port.
 | 
			
		||||
    port->GetServerPort().Open();
 | 
			
		||||
    // Add the new server to sm: and get the moved server port.
 | 
			
		||||
    Kernel::KServerPort* server_port{};
 | 
			
		||||
    R_ASSERT(m_system.ServiceManager().RegisterService(std::addressof(server_port), service_name,
 | 
			
		||||
                                                       max_sessions, handler_factory));
 | 
			
		||||
 | 
			
		||||
    // Begin tracking the server port.
 | 
			
		||||
    {
 | 
			
		||||
        std::scoped_lock ll{m_list_mutex};
 | 
			
		||||
        m_ports.emplace(std::addressof(port->GetServerPort()), std::move(handler_factory));
 | 
			
		||||
        m_ports.emplace(server_port, std::move(handler_factory));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Signal the wakeup event.
 | 
			
		||||
@@ -372,7 +365,7 @@ Result ServerManager::OnSessionEvent(Kernel::KServerSession* session,
 | 
			
		||||
 | 
			
		||||
    // Try to receive a message.
 | 
			
		||||
    std::shared_ptr<HLERequestContext> context;
 | 
			
		||||
    rc = session->ReceiveRequest(&context, manager);
 | 
			
		||||
    rc = session->ReceiveRequestHLE(&context, manager);
 | 
			
		||||
 | 
			
		||||
    // If the session has been closed, we're done.
 | 
			
		||||
    if (rc == Kernel::ResultSessionClosed) {
 | 
			
		||||
 
 | 
			
		||||
@@ -507,6 +507,14 @@ void SET_SYS::SetTvSettings(HLERequestContext& ctx) {
 | 
			
		||||
    rb.Push(ResultSuccess);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SET_SYS::GetDebugModeFlag(HLERequestContext& ctx) {
 | 
			
		||||
    LOG_DEBUG(Service_SET, "called");
 | 
			
		||||
 | 
			
		||||
    IPC::ResponseBuilder rb{ctx, 3};
 | 
			
		||||
    rb.Push(ResultSuccess);
 | 
			
		||||
    rb.Push<u32>(0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SET_SYS::GetQuestFlag(HLERequestContext& ctx) {
 | 
			
		||||
    LOG_WARNING(Service_SET, "(STUBBED) called");
 | 
			
		||||
 | 
			
		||||
@@ -926,7 +934,7 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"},
 | 
			
		||||
        {59, &SET_SYS::SetNetworkSystemClockContext, "SetNetworkSystemClockContext"},
 | 
			
		||||
        {60, &SET_SYS::IsUserSystemClockAutomaticCorrectionEnabled, "IsUserSystemClockAutomaticCorrectionEnabled"},
 | 
			
		||||
        {61, &SET_SYS::SetUserSystemClockAutomaticCorrectionEnabled, "SetUserSystemClockAutomaticCorrectionEnabled"},
 | 
			
		||||
        {62, nullptr, "GetDebugModeFlag"},
 | 
			
		||||
        {62, &SET_SYS::GetDebugModeFlag, "GetDebugModeFlag"},
 | 
			
		||||
        {63, &SET_SYS::GetPrimaryAlbumStorage, "GetPrimaryAlbumStorage"},
 | 
			
		||||
        {64, nullptr, "SetPrimaryAlbumStorage"},
 | 
			
		||||
        {65, nullptr, "GetUsb30EnableFlag"},
 | 
			
		||||
@@ -1143,6 +1151,8 @@ void SET_SYS::StoreSettings() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SET_SYS::StoreSettingsThreadFunc(std::stop_token stop_token) {
 | 
			
		||||
    Common::SetCurrentThreadName("SettingsStore");
 | 
			
		||||
 | 
			
		||||
    while (Common::StoppableTimedWait(stop_token, std::chrono::minutes(1))) {
 | 
			
		||||
        std::scoped_lock l{m_save_needed_mutex};
 | 
			
		||||
        if (!std::exchange(m_save_needed, false)) {
 | 
			
		||||
 
 | 
			
		||||
@@ -98,6 +98,7 @@ private:
 | 
			
		||||
    void GetSettingsItemValue(HLERequestContext& ctx);
 | 
			
		||||
    void GetTvSettings(HLERequestContext& ctx);
 | 
			
		||||
    void SetTvSettings(HLERequestContext& ctx);
 | 
			
		||||
    void GetDebugModeFlag(HLERequestContext& ctx);
 | 
			
		||||
    void GetQuestFlag(HLERequestContext& ctx);
 | 
			
		||||
    void GetDeviceTimeZoneLocationName(HLERequestContext& ctx);
 | 
			
		||||
    void SetDeviceTimeZoneLocationName(HLERequestContext& ctx);
 | 
			
		||||
 
 | 
			
		||||
@@ -29,8 +29,7 @@ ServiceManager::ServiceManager(Kernel::KernelCore& kernel_) : kernel{kernel_} {
 | 
			
		||||
 | 
			
		||||
ServiceManager::~ServiceManager() {
 | 
			
		||||
    for (auto& [name, port] : service_ports) {
 | 
			
		||||
        port->GetClientPort().Close();
 | 
			
		||||
        port->GetServerPort().Close();
 | 
			
		||||
        port->Close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (deferral_event) {
 | 
			
		||||
@@ -50,8 +49,8 @@ static Result ValidateServiceName(const std::string& name) {
 | 
			
		||||
    return ResultSuccess;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Result ServiceManager::RegisterService(std::string name, u32 max_sessions,
 | 
			
		||||
                                       SessionRequestHandlerFactory handler) {
 | 
			
		||||
Result ServiceManager::RegisterService(Kernel::KServerPort** out_server_port, std::string name,
 | 
			
		||||
                                       u32 max_sessions, SessionRequestHandlerFactory handler) {
 | 
			
		||||
    R_TRY(ValidateServiceName(name));
 | 
			
		||||
 | 
			
		||||
    std::scoped_lock lk{lock};
 | 
			
		||||
@@ -66,13 +65,17 @@ Result ServiceManager::RegisterService(std::string name, u32 max_sessions,
 | 
			
		||||
    // Register the port.
 | 
			
		||||
    Kernel::KPort::Register(kernel, port);
 | 
			
		||||
 | 
			
		||||
    service_ports.emplace(name, port);
 | 
			
		||||
    service_ports.emplace(name, std::addressof(port->GetClientPort()));
 | 
			
		||||
    registered_services.emplace(name, handler);
 | 
			
		||||
    if (deferral_event) {
 | 
			
		||||
        deferral_event->Signal();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return ResultSuccess;
 | 
			
		||||
    // Set our output.
 | 
			
		||||
    *out_server_port = std::addressof(port->GetServerPort());
 | 
			
		||||
 | 
			
		||||
    // We succeeded.
 | 
			
		||||
    R_SUCCEED();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Result ServiceManager::UnregisterService(const std::string& name) {
 | 
			
		||||
@@ -91,7 +94,8 @@ Result ServiceManager::UnregisterService(const std::string& name) {
 | 
			
		||||
    return ResultSuccess;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Result ServiceManager::GetServicePort(Kernel::KPort** out_port, const std::string& name) {
 | 
			
		||||
Result ServiceManager::GetServicePort(Kernel::KClientPort** out_client_port,
 | 
			
		||||
                                      const std::string& name) {
 | 
			
		||||
    R_TRY(ValidateServiceName(name));
 | 
			
		||||
 | 
			
		||||
    std::scoped_lock lk{lock};
 | 
			
		||||
@@ -101,7 +105,7 @@ Result ServiceManager::GetServicePort(Kernel::KPort** out_port, const std::strin
 | 
			
		||||
        return Service::SM::ResultNotRegistered;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    *out_port = it->second;
 | 
			
		||||
    *out_client_port = it->second;
 | 
			
		||||
    return ResultSuccess;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -172,8 +176,8 @@ Result SM::GetServiceImpl(Kernel::KClientSession** out_client_session, HLEReques
 | 
			
		||||
    std::string name(PopServiceName(rp));
 | 
			
		||||
 | 
			
		||||
    // Find the named port.
 | 
			
		||||
    Kernel::KPort* port{};
 | 
			
		||||
    auto port_result = service_manager.GetServicePort(&port, name);
 | 
			
		||||
    Kernel::KClientPort* client_port{};
 | 
			
		||||
    auto port_result = service_manager.GetServicePort(&client_port, name);
 | 
			
		||||
    if (port_result == Service::SM::ResultInvalidServiceName) {
 | 
			
		||||
        LOG_ERROR(Service_SM, "Invalid service name '{}'", name);
 | 
			
		||||
        return Service::SM::ResultInvalidServiceName;
 | 
			
		||||
@@ -187,7 +191,7 @@ Result SM::GetServiceImpl(Kernel::KClientSession** out_client_session, HLEReques
 | 
			
		||||
 | 
			
		||||
    // Create a new session.
 | 
			
		||||
    Kernel::KClientSession* session{};
 | 
			
		||||
    if (const auto result = port->GetClientPort().CreateSession(&session); result.IsError()) {
 | 
			
		||||
    if (const auto result = client_port->CreateSession(&session); result.IsError()) {
 | 
			
		||||
        LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.raw);
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
@@ -221,7 +225,9 @@ void SM::RegisterServiceImpl(HLERequestContext& ctx, std::string name, u32 max_s
 | 
			
		||||
    LOG_DEBUG(Service_SM, "called with name={}, max_session_count={}, is_light={}", name,
 | 
			
		||||
              max_session_count, is_light);
 | 
			
		||||
 | 
			
		||||
    if (const auto result = service_manager.RegisterService(name, max_session_count, nullptr);
 | 
			
		||||
    Kernel::KServerPort* server_port{};
 | 
			
		||||
    if (const auto result = service_manager.RegisterService(std::addressof(server_port), name,
 | 
			
		||||
                                                            max_session_count, nullptr);
 | 
			
		||||
        result.IsError()) {
 | 
			
		||||
        LOG_ERROR(Service_SM, "failed to register service with error_code={:08X}", result.raw);
 | 
			
		||||
        IPC::ResponseBuilder rb{ctx, 2};
 | 
			
		||||
@@ -229,13 +235,9 @@ void SM::RegisterServiceImpl(HLERequestContext& ctx, std::string name, u32 max_s
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    auto* port = Kernel::KPort::Create(kernel);
 | 
			
		||||
    port->Initialize(ServerSessionCountMax, is_light, 0);
 | 
			
		||||
    SCOPE_EXIT({ port->GetClientPort().Close(); });
 | 
			
		||||
 | 
			
		||||
    IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
 | 
			
		||||
    rb.Push(ResultSuccess);
 | 
			
		||||
    rb.PushMoveObjects(port->GetServerPort());
 | 
			
		||||
    rb.PushMoveObjects(server_port);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SM::UnregisterService(HLERequestContext& ctx) {
 | 
			
		||||
 
 | 
			
		||||
@@ -56,10 +56,10 @@ public:
 | 
			
		||||
    explicit ServiceManager(Kernel::KernelCore& kernel_);
 | 
			
		||||
    ~ServiceManager();
 | 
			
		||||
 | 
			
		||||
    Result RegisterService(std::string name, u32 max_sessions,
 | 
			
		||||
                           SessionRequestHandlerFactory handler_factory);
 | 
			
		||||
    Result RegisterService(Kernel::KServerPort** out_server_port, std::string name,
 | 
			
		||||
                           u32 max_sessions, SessionRequestHandlerFactory handler_factory);
 | 
			
		||||
    Result UnregisterService(const std::string& name);
 | 
			
		||||
    Result GetServicePort(Kernel::KPort** out_port, const std::string& name);
 | 
			
		||||
    Result GetServicePort(Kernel::KClientPort** out_client_port, const std::string& name);
 | 
			
		||||
 | 
			
		||||
    template <Common::DerivedFrom<SessionRequestHandler> T>
 | 
			
		||||
    std::shared_ptr<T> GetService(const std::string& service_name) const {
 | 
			
		||||
@@ -84,7 +84,7 @@ private:
 | 
			
		||||
    /// Map of registered services, retrieved using GetServicePort.
 | 
			
		||||
    std::mutex lock;
 | 
			
		||||
    std::unordered_map<std::string, SessionRequestHandlerFactory> registered_services;
 | 
			
		||||
    std::unordered_map<std::string, Kernel::KPort*> service_ports;
 | 
			
		||||
    std::unordered_map<std::string, Kernel::KClientPort*> service_ports;
 | 
			
		||||
 | 
			
		||||
    /// Kernel context
 | 
			
		||||
    Kernel::KernelCore& kernel;
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,6 @@ void Controller::ConvertCurrentObjectToDomain(HLERequestContext& ctx) {
 | 
			
		||||
void Controller::CloneCurrentObject(HLERequestContext& ctx) {
 | 
			
		||||
    LOG_DEBUG(Service, "called");
 | 
			
		||||
 | 
			
		||||
    auto& process = *ctx.GetThread().GetOwnerProcess();
 | 
			
		||||
    auto session_manager = ctx.GetManager();
 | 
			
		||||
 | 
			
		||||
    // FIXME: this is duplicated from the SVC, it should just call it instead
 | 
			
		||||
@@ -36,11 +35,11 @@ void Controller::CloneCurrentObject(HLERequestContext& ctx) {
 | 
			
		||||
 | 
			
		||||
    // Reserve a new session from the process resource limit.
 | 
			
		||||
    Kernel::KScopedResourceReservation session_reservation(
 | 
			
		||||
        &process, Kernel::LimitableResource::SessionCountMax);
 | 
			
		||||
        Kernel::GetCurrentProcessPointer(kernel), Kernel::LimitableResource::SessionCountMax);
 | 
			
		||||
    ASSERT(session_reservation.Succeeded());
 | 
			
		||||
 | 
			
		||||
    // Create the session.
 | 
			
		||||
    Kernel::KSession* session = Kernel::KSession::Create(system.Kernel());
 | 
			
		||||
    Kernel::KSession* session = Kernel::KSession::Create(kernel);
 | 
			
		||||
    ASSERT(session != nullptr);
 | 
			
		||||
 | 
			
		||||
    // Initialize the session.
 | 
			
		||||
@@ -50,7 +49,7 @@ void Controller::CloneCurrentObject(HLERequestContext& ctx) {
 | 
			
		||||
    session_reservation.Commit();
 | 
			
		||||
 | 
			
		||||
    // Register the session.
 | 
			
		||||
    Kernel::KSession::Register(system.Kernel(), session);
 | 
			
		||||
    Kernel::KSession::Register(kernel, session);
 | 
			
		||||
 | 
			
		||||
    // Register with server manager.
 | 
			
		||||
    session_manager->GetServerManager().RegisterSession(&session->GetServerSession(),
 | 
			
		||||
 
 | 
			
		||||
@@ -129,9 +129,10 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
 | 
			
		||||
    }
 | 
			
		||||
    metadata.Print();
 | 
			
		||||
 | 
			
		||||
    // Enable NCE only for programs with 39-bit address space.
 | 
			
		||||
    // Enable NCE only for applications with 39-bit address space.
 | 
			
		||||
    const bool is_39bit =
 | 
			
		||||
        metadata.GetAddressSpaceType() == FileSys::ProgramAddressSpaceType::Is39Bit;
 | 
			
		||||
    const bool is_application = metadata.GetPoolPartition() == FileSys::PoolPartition::Application;
 | 
			
		||||
    Settings::SetNceEnabled(is_39bit);
 | 
			
		||||
 | 
			
		||||
    const std::array static_modules = {"rtld",    "main",    "subsdk0", "subsdk1", "subsdk2",
 | 
			
		||||
@@ -147,7 +148,7 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
 | 
			
		||||
 | 
			
		||||
    const auto GetPatcher = [&](size_t i) -> Core::NCE::Patcher* {
 | 
			
		||||
#ifdef HAS_NCE
 | 
			
		||||
        if (Settings::IsNceEnabled()) {
 | 
			
		||||
        if (is_application && Settings::IsNceEnabled()) {
 | 
			
		||||
            return &module_patchers[i];
 | 
			
		||||
        }
 | 
			
		||||
#endif
 | 
			
		||||
@@ -175,7 +176,7 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
 | 
			
		||||
 | 
			
		||||
    // Enable direct memory mapping in case of NCE.
 | 
			
		||||
    const u64 fastmem_base = [&]() -> size_t {
 | 
			
		||||
        if (Settings::IsNceEnabled()) {
 | 
			
		||||
        if (is_application && Settings::IsNceEnabled()) {
 | 
			
		||||
            auto& buffer = system.DeviceMemory().buffer;
 | 
			
		||||
            buffer.EnableDirectMappedAddress();
 | 
			
		||||
            return reinterpret_cast<u64>(buffer.VirtualBasePointer());
 | 
			
		||||
 
 | 
			
		||||
@@ -45,7 +45,13 @@ struct Memory::Impl {
 | 
			
		||||
 | 
			
		||||
    void SetCurrentPageTable(Kernel::KProcess& process) {
 | 
			
		||||
        current_page_table = &process.GetPageTable().GetImpl();
 | 
			
		||||
        current_page_table->fastmem_arena = system.DeviceMemory().buffer.VirtualBasePointer();
 | 
			
		||||
 | 
			
		||||
        if (std::addressof(process) == system.ApplicationProcess() &&
 | 
			
		||||
            Settings::IsFastmemEnabled()) {
 | 
			
		||||
            current_page_table->fastmem_arena = system.DeviceMemory().buffer.VirtualBasePointer();
 | 
			
		||||
        } else {
 | 
			
		||||
            current_page_table->fastmem_arena = nullptr;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size,
 | 
			
		||||
@@ -57,7 +63,7 @@ struct Memory::Impl {
 | 
			
		||||
        MapPages(page_table, base / YUZU_PAGESIZE, size / YUZU_PAGESIZE, target,
 | 
			
		||||
                 Common::PageType::Memory);
 | 
			
		||||
 | 
			
		||||
        if (Settings::IsFastmemEnabled()) {
 | 
			
		||||
        if (current_page_table->fastmem_arena) {
 | 
			
		||||
            system.DeviceMemory().buffer.Map(GetInteger(base),
 | 
			
		||||
                                             GetInteger(target) - DramMemoryMap::Base, size, perms);
 | 
			
		||||
        }
 | 
			
		||||
@@ -69,7 +75,7 @@ struct Memory::Impl {
 | 
			
		||||
        MapPages(page_table, base / YUZU_PAGESIZE, size / YUZU_PAGESIZE, 0,
 | 
			
		||||
                 Common::PageType::Unmapped);
 | 
			
		||||
 | 
			
		||||
        if (Settings::IsFastmemEnabled()) {
 | 
			
		||||
        if (current_page_table->fastmem_arena) {
 | 
			
		||||
            system.DeviceMemory().buffer.Unmap(GetInteger(base), size);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -79,7 +85,7 @@ struct Memory::Impl {
 | 
			
		||||
        ASSERT_MSG((size & YUZU_PAGEMASK) == 0, "non-page aligned size: {:016X}", size);
 | 
			
		||||
        ASSERT_MSG((vaddr & YUZU_PAGEMASK) == 0, "non-page aligned base: {:016X}", vaddr);
 | 
			
		||||
 | 
			
		||||
        if (!Settings::IsFastmemEnabled()) {
 | 
			
		||||
        if (!current_page_table->fastmem_arena) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -88,11 +94,6 @@ struct Memory::Impl {
 | 
			
		||||
        const bool is_x =
 | 
			
		||||
            True(perms & Common::MemoryPermission::Execute) && Settings::IsNceEnabled();
 | 
			
		||||
 | 
			
		||||
        if (!current_page_table) {
 | 
			
		||||
            system.DeviceMemory().buffer.Protect(vaddr, size, is_r, is_w, is_x);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        u64 protect_bytes{};
 | 
			
		||||
        u64 protect_begin{};
 | 
			
		||||
        for (u64 addr = vaddr; addr < vaddr + size; addr += YUZU_PAGESIZE) {
 | 
			
		||||
@@ -239,7 +240,7 @@ struct Memory::Impl {
 | 
			
		||||
 | 
			
		||||
    bool WalkBlock(const Common::ProcessAddress addr, const std::size_t size, auto on_unmapped,
 | 
			
		||||
                   auto on_memory, auto on_rasterizer, auto increment) {
 | 
			
		||||
        const auto& page_table = system.ApplicationProcess()->GetPageTable().GetImpl();
 | 
			
		||||
        const auto& page_table = *current_page_table;
 | 
			
		||||
        std::size_t remaining_size = size;
 | 
			
		||||
        std::size_t page_index = addr >> YUZU_PAGEBITS;
 | 
			
		||||
        std::size_t page_offset = addr & YUZU_PAGEMASK;
 | 
			
		||||
@@ -484,7 +485,7 @@ struct Memory::Impl {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (Settings::IsFastmemEnabled()) {
 | 
			
		||||
        if (current_page_table->fastmem_arena) {
 | 
			
		||||
            system.DeviceMemory().buffer.Protect(vaddr, size, !debug, !debug);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -541,7 +542,7 @@ struct Memory::Impl {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (Settings::IsFastmemEnabled()) {
 | 
			
		||||
        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);
 | 
			
		||||
@@ -886,8 +887,7 @@ void Memory::ProtectRegion(Common::PageTable& page_table, Common::ProcessAddress
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Memory::IsValidVirtualAddress(const Common::ProcessAddress vaddr) const {
 | 
			
		||||
    const Kernel::KProcess& process = *system.ApplicationProcess();
 | 
			
		||||
    const auto& page_table = process.GetPageTable().GetImpl();
 | 
			
		||||
    const auto& page_table = *impl->current_page_table;
 | 
			
		||||
    const size_t page = vaddr >> YUZU_PAGEBITS;
 | 
			
		||||
    if (page >= page_table.pointers.size()) {
 | 
			
		||||
        return false;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user