Merge pull request #8637 from liamwhite/bad-interrupts
kernel: unlayer CPU interrupt handling
This commit is contained in:
		@@ -6,8 +6,6 @@ add_library(core STATIC
 | 
			
		||||
    announce_multiplayer_session.h
 | 
			
		||||
    arm/arm_interface.h
 | 
			
		||||
    arm/arm_interface.cpp
 | 
			
		||||
    arm/cpu_interrupt_handler.cpp
 | 
			
		||||
    arm/cpu_interrupt_handler.h
 | 
			
		||||
    arm/dynarmic/arm_dynarmic_32.cpp
 | 
			
		||||
    arm/dynarmic/arm_dynarmic_32.h
 | 
			
		||||
    arm/dynarmic/arm_dynarmic_64.cpp
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,6 @@ namespace Core {
 | 
			
		||||
class System;
 | 
			
		||||
class CPUInterruptHandler;
 | 
			
		||||
 | 
			
		||||
using CPUInterrupts = std::array<CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>;
 | 
			
		||||
using WatchpointArray = std::array<Kernel::DebugWatchpoint, Core::Hardware::NUM_WATCHPOINTS>;
 | 
			
		||||
 | 
			
		||||
/// Generic ARMv8 CPU interface
 | 
			
		||||
@@ -36,10 +35,8 @@ public:
 | 
			
		||||
    YUZU_NON_COPYABLE(ARM_Interface);
 | 
			
		||||
    YUZU_NON_MOVEABLE(ARM_Interface);
 | 
			
		||||
 | 
			
		||||
    explicit ARM_Interface(System& system_, CPUInterrupts& interrupt_handlers_,
 | 
			
		||||
                           bool uses_wall_clock_)
 | 
			
		||||
        : system{system_}, interrupt_handlers{interrupt_handlers_}, uses_wall_clock{
 | 
			
		||||
                                                                        uses_wall_clock_} {}
 | 
			
		||||
    explicit ARM_Interface(System& system_, bool uses_wall_clock_)
 | 
			
		||||
        : system{system_}, uses_wall_clock{uses_wall_clock_} {}
 | 
			
		||||
    virtual ~ARM_Interface() = default;
 | 
			
		||||
 | 
			
		||||
    struct ThreadContext32 {
 | 
			
		||||
@@ -181,6 +178,9 @@ public:
 | 
			
		||||
    /// Signal an interrupt and ask the core to halt as soon as possible.
 | 
			
		||||
    virtual void SignalInterrupt() = 0;
 | 
			
		||||
 | 
			
		||||
    /// Clear a previous interrupt.
 | 
			
		||||
    virtual void ClearInterrupt() = 0;
 | 
			
		||||
 | 
			
		||||
    struct BacktraceEntry {
 | 
			
		||||
        std::string module;
 | 
			
		||||
        u64 address;
 | 
			
		||||
@@ -208,7 +208,6 @@ public:
 | 
			
		||||
protected:
 | 
			
		||||
    /// System context that this ARM interface is running under.
 | 
			
		||||
    System& system;
 | 
			
		||||
    CPUInterrupts& interrupt_handlers;
 | 
			
		||||
    const WatchpointArray* watchpoints;
 | 
			
		||||
    bool uses_wall_clock;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,24 +0,0 @@
 | 
			
		||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
			
		||||
 | 
			
		||||
#include "common/thread.h"
 | 
			
		||||
#include "core/arm/cpu_interrupt_handler.h"
 | 
			
		||||
 | 
			
		||||
namespace Core {
 | 
			
		||||
 | 
			
		||||
CPUInterruptHandler::CPUInterruptHandler() : interrupt_event{std::make_unique<Common::Event>()} {}
 | 
			
		||||
 | 
			
		||||
CPUInterruptHandler::~CPUInterruptHandler() = default;
 | 
			
		||||
 | 
			
		||||
void CPUInterruptHandler::SetInterrupt(bool is_interrupted_) {
 | 
			
		||||
    if (is_interrupted_) {
 | 
			
		||||
        interrupt_event->Set();
 | 
			
		||||
    }
 | 
			
		||||
    is_interrupted = is_interrupted_;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CPUInterruptHandler::AwaitInterrupt() {
 | 
			
		||||
    interrupt_event->Wait();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace Core
 | 
			
		||||
@@ -1,39 +0,0 @@
 | 
			
		||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <atomic>
 | 
			
		||||
#include <memory>
 | 
			
		||||
 | 
			
		||||
namespace Common {
 | 
			
		||||
class Event;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Core {
 | 
			
		||||
 | 
			
		||||
class CPUInterruptHandler {
 | 
			
		||||
public:
 | 
			
		||||
    CPUInterruptHandler();
 | 
			
		||||
    ~CPUInterruptHandler();
 | 
			
		||||
 | 
			
		||||
    CPUInterruptHandler(const CPUInterruptHandler&) = delete;
 | 
			
		||||
    CPUInterruptHandler& operator=(const CPUInterruptHandler&) = delete;
 | 
			
		||||
 | 
			
		||||
    CPUInterruptHandler(CPUInterruptHandler&&) = delete;
 | 
			
		||||
    CPUInterruptHandler& operator=(CPUInterruptHandler&&) = delete;
 | 
			
		||||
 | 
			
		||||
    bool IsInterrupted() const {
 | 
			
		||||
        return is_interrupted;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void SetInterrupt(bool is_interrupted);
 | 
			
		||||
 | 
			
		||||
    void AwaitInterrupt();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    std::unique_ptr<Common::Event> interrupt_event;
 | 
			
		||||
    std::atomic_bool is_interrupted{false};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace Core
 | 
			
		||||
@@ -11,7 +11,6 @@
 | 
			
		||||
#include "common/logging/log.h"
 | 
			
		||||
#include "common/page_table.h"
 | 
			
		||||
#include "common/settings.h"
 | 
			
		||||
#include "core/arm/cpu_interrupt_handler.h"
 | 
			
		||||
#include "core/arm/dynarmic/arm_dynarmic_32.h"
 | 
			
		||||
#include "core/arm/dynarmic/arm_dynarmic_cp15.h"
 | 
			
		||||
#include "core/arm/dynarmic/arm_exclusive_monitor.h"
 | 
			
		||||
@@ -318,11 +317,9 @@ void ARM_Dynarmic_32::RewindBreakpointInstruction() {
 | 
			
		||||
    LoadContext(breakpoint_context);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ARM_Dynarmic_32::ARM_Dynarmic_32(System& system_, CPUInterrupts& interrupt_handlers_,
 | 
			
		||||
                                 bool uses_wall_clock_, ExclusiveMonitor& exclusive_monitor_,
 | 
			
		||||
                                 std::size_t core_index_)
 | 
			
		||||
    : ARM_Interface{system_, interrupt_handlers_, uses_wall_clock_},
 | 
			
		||||
      cb(std::make_unique<DynarmicCallbacks32>(*this)),
 | 
			
		||||
ARM_Dynarmic_32::ARM_Dynarmic_32(System& system_, bool uses_wall_clock_,
 | 
			
		||||
                                 ExclusiveMonitor& exclusive_monitor_, std::size_t core_index_)
 | 
			
		||||
    : ARM_Interface{system_, uses_wall_clock_}, cb(std::make_unique<DynarmicCallbacks32>(*this)),
 | 
			
		||||
      cp15(std::make_shared<DynarmicCP15>(*this)), core_index{core_index_},
 | 
			
		||||
      exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor_)},
 | 
			
		||||
      null_jit{MakeJit(nullptr)}, jit{null_jit.get()} {}
 | 
			
		||||
@@ -401,6 +398,10 @@ void ARM_Dynarmic_32::SignalInterrupt() {
 | 
			
		||||
    jit.load()->HaltExecution(break_loop);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ARM_Dynarmic_32::ClearInterrupt() {
 | 
			
		||||
    jit.load()->ClearHalt(break_loop);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ARM_Dynarmic_32::ClearInstructionCache() {
 | 
			
		||||
    jit.load()->ClearCache();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -28,8 +28,8 @@ class System;
 | 
			
		||||
 | 
			
		||||
class ARM_Dynarmic_32 final : public ARM_Interface {
 | 
			
		||||
public:
 | 
			
		||||
    ARM_Dynarmic_32(System& system_, CPUInterrupts& interrupt_handlers_, bool uses_wall_clock_,
 | 
			
		||||
                    ExclusiveMonitor& exclusive_monitor_, std::size_t core_index_);
 | 
			
		||||
    ARM_Dynarmic_32(System& system_, bool uses_wall_clock_, ExclusiveMonitor& exclusive_monitor_,
 | 
			
		||||
                    std::size_t core_index_);
 | 
			
		||||
    ~ARM_Dynarmic_32() override;
 | 
			
		||||
 | 
			
		||||
    void SetPC(u64 pc) override;
 | 
			
		||||
@@ -56,6 +56,7 @@ public:
 | 
			
		||||
    void LoadContext(const ThreadContext64& ctx) override {}
 | 
			
		||||
 | 
			
		||||
    void SignalInterrupt() override;
 | 
			
		||||
    void ClearInterrupt() override;
 | 
			
		||||
    void ClearExclusiveState() override;
 | 
			
		||||
 | 
			
		||||
    void ClearInstructionCache() override;
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,6 @@
 | 
			
		||||
#include "common/logging/log.h"
 | 
			
		||||
#include "common/page_table.h"
 | 
			
		||||
#include "common/settings.h"
 | 
			
		||||
#include "core/arm/cpu_interrupt_handler.h"
 | 
			
		||||
#include "core/arm/dynarmic/arm_dynarmic_64.h"
 | 
			
		||||
#include "core/arm/dynarmic/arm_exclusive_monitor.h"
 | 
			
		||||
#include "core/core.h"
 | 
			
		||||
@@ -378,10 +377,9 @@ void ARM_Dynarmic_64::RewindBreakpointInstruction() {
 | 
			
		||||
    LoadContext(breakpoint_context);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ARM_Dynarmic_64::ARM_Dynarmic_64(System& system_, CPUInterrupts& interrupt_handlers_,
 | 
			
		||||
                                 bool uses_wall_clock_, ExclusiveMonitor& exclusive_monitor_,
 | 
			
		||||
                                 std::size_t core_index_)
 | 
			
		||||
    : ARM_Interface{system_, interrupt_handlers_, uses_wall_clock_},
 | 
			
		||||
ARM_Dynarmic_64::ARM_Dynarmic_64(System& system_, bool uses_wall_clock_,
 | 
			
		||||
                                 ExclusiveMonitor& exclusive_monitor_, std::size_t core_index_)
 | 
			
		||||
    : ARM_Interface{system_, uses_wall_clock_},
 | 
			
		||||
      cb(std::make_unique<DynarmicCallbacks64>(*this)), core_index{core_index_},
 | 
			
		||||
      exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor_)},
 | 
			
		||||
      null_jit{MakeJit(nullptr, 48)}, jit{null_jit.get()} {}
 | 
			
		||||
@@ -468,6 +466,10 @@ void ARM_Dynarmic_64::SignalInterrupt() {
 | 
			
		||||
    jit.load()->HaltExecution(break_loop);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ARM_Dynarmic_64::ClearInterrupt() {
 | 
			
		||||
    jit.load()->ClearHalt(break_loop);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ARM_Dynarmic_64::ClearInstructionCache() {
 | 
			
		||||
    jit.load()->ClearCache();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -20,14 +20,13 @@ class Memory;
 | 
			
		||||
namespace Core {
 | 
			
		||||
 | 
			
		||||
class DynarmicCallbacks64;
 | 
			
		||||
class CPUInterruptHandler;
 | 
			
		||||
class DynarmicExclusiveMonitor;
 | 
			
		||||
class System;
 | 
			
		||||
 | 
			
		||||
class ARM_Dynarmic_64 final : public ARM_Interface {
 | 
			
		||||
public:
 | 
			
		||||
    ARM_Dynarmic_64(System& system_, CPUInterrupts& interrupt_handlers_, bool uses_wall_clock_,
 | 
			
		||||
                    ExclusiveMonitor& exclusive_monitor_, std::size_t core_index_);
 | 
			
		||||
    ARM_Dynarmic_64(System& system_, bool uses_wall_clock_, ExclusiveMonitor& exclusive_monitor_,
 | 
			
		||||
                    std::size_t core_index_);
 | 
			
		||||
    ~ARM_Dynarmic_64() override;
 | 
			
		||||
 | 
			
		||||
    void SetPC(u64 pc) override;
 | 
			
		||||
@@ -50,6 +49,7 @@ public:
 | 
			
		||||
    void LoadContext(const ThreadContext64& ctx) override;
 | 
			
		||||
 | 
			
		||||
    void SignalInterrupt() override;
 | 
			
		||||
    void ClearInterrupt() override;
 | 
			
		||||
    void ClearExclusiveState() override;
 | 
			
		||||
 | 
			
		||||
    void ClearInstructionCache() override;
 | 
			
		||||
 
 | 
			
		||||
@@ -15,6 +15,7 @@
 | 
			
		||||
#include "core/debugger/debugger_interface.h"
 | 
			
		||||
#include "core/debugger/gdbstub.h"
 | 
			
		||||
#include "core/hle/kernel/global_scheduler_context.h"
 | 
			
		||||
#include "core/hle/kernel/k_scheduler.h"
 | 
			
		||||
 | 
			
		||||
template <typename Readable, typename Buffer, typename Callback>
 | 
			
		||||
static void AsyncReceiveInto(Readable& r, Buffer& buffer, Callback&& c) {
 | 
			
		||||
@@ -230,13 +231,12 @@ private:
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void PauseEmulation() {
 | 
			
		||||
        Kernel::KScopedSchedulerLock sl{system.Kernel()};
 | 
			
		||||
 | 
			
		||||
        // Put all threads to sleep on next scheduler round.
 | 
			
		||||
        for (auto* thread : ThreadList()) {
 | 
			
		||||
            thread->RequestSuspend(Kernel::SuspendType::Debug);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Signal an interrupt so that scheduler will fire.
 | 
			
		||||
        system.Kernel().InterruptAllPhysicalCores();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void ResumeEmulation(Kernel::KThread* except = nullptr) {
 | 
			
		||||
@@ -253,7 +253,8 @@ private:
 | 
			
		||||
 | 
			
		||||
    template <typename Callback>
 | 
			
		||||
    void MarkResumed(Callback&& cb) {
 | 
			
		||||
        std::scoped_lock lk{connection_lock};
 | 
			
		||||
        Kernel::KScopedSchedulerLock sl{system.Kernel()};
 | 
			
		||||
        std::scoped_lock cl{connection_lock};
 | 
			
		||||
        stopped = false;
 | 
			
		||||
        cb();
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,6 @@
 | 
			
		||||
#include "common/thread.h"
 | 
			
		||||
#include "common/thread_worker.h"
 | 
			
		||||
#include "core/arm/arm_interface.h"
 | 
			
		||||
#include "core/arm/cpu_interrupt_handler.h"
 | 
			
		||||
#include "core/arm/exclusive_monitor.h"
 | 
			
		||||
#include "core/core.h"
 | 
			
		||||
#include "core/core_timing.h"
 | 
			
		||||
@@ -82,7 +81,7 @@ struct KernelCore::Impl {
 | 
			
		||||
 | 
			
		||||
    void InitializeCores() {
 | 
			
		||||
        for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
 | 
			
		||||
            cores[core_id].Initialize((*current_process).Is64BitProcess());
 | 
			
		||||
            cores[core_id]->Initialize((*current_process).Is64BitProcess());
 | 
			
		||||
            system.Memory().SetCurrentPageTable(*current_process, core_id);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -100,7 +99,9 @@ struct KernelCore::Impl {
 | 
			
		||||
        next_user_process_id = KProcess::ProcessIDMin;
 | 
			
		||||
        next_thread_id = 1;
 | 
			
		||||
 | 
			
		||||
        cores.clear();
 | 
			
		||||
        for (auto& core : cores) {
 | 
			
		||||
            core = nullptr;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        global_handle_table->Finalize();
 | 
			
		||||
        global_handle_table.reset();
 | 
			
		||||
@@ -199,7 +200,7 @@ struct KernelCore::Impl {
 | 
			
		||||
            const s32 core{static_cast<s32>(i)};
 | 
			
		||||
 | 
			
		||||
            schedulers[i] = std::make_unique<Kernel::KScheduler>(system.Kernel());
 | 
			
		||||
            cores.emplace_back(i, system, *schedulers[i], interrupts);
 | 
			
		||||
            cores[i] = std::make_unique<Kernel::PhysicalCore>(i, system, *schedulers[i]);
 | 
			
		||||
 | 
			
		||||
            auto* main_thread{Kernel::KThread::Create(system.Kernel())};
 | 
			
		||||
            main_thread->SetName(fmt::format("MainThread:{}", core));
 | 
			
		||||
@@ -761,7 +762,7 @@ struct KernelCore::Impl {
 | 
			
		||||
    std::unordered_set<KAutoObject*> registered_in_use_objects;
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor;
 | 
			
		||||
    std::vector<Kernel::PhysicalCore> cores;
 | 
			
		||||
    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
 | 
			
		||||
    std::atomic<u32> next_host_thread_id{Core::Hardware::NUM_CPU_CORES};
 | 
			
		||||
@@ -785,7 +786,6 @@ struct KernelCore::Impl {
 | 
			
		||||
    Common::ThreadWorker service_threads_manager;
 | 
			
		||||
 | 
			
		||||
    std::array<KThread*, Core::Hardware::NUM_CPU_CORES> shutdown_threads;
 | 
			
		||||
    std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{};
 | 
			
		||||
    std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{};
 | 
			
		||||
 | 
			
		||||
    bool is_multicore{};
 | 
			
		||||
@@ -874,11 +874,11 @@ const Kernel::KScheduler& KernelCore::Scheduler(std::size_t id) const {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) {
 | 
			
		||||
    return impl->cores[id];
 | 
			
		||||
    return *impl->cores[id];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) const {
 | 
			
		||||
    return impl->cores[id];
 | 
			
		||||
    return *impl->cores[id];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t KernelCore::CurrentPhysicalCoreIndex() const {
 | 
			
		||||
@@ -890,11 +890,11 @@ size_t KernelCore::CurrentPhysicalCoreIndex() const {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() {
 | 
			
		||||
    return impl->cores[CurrentPhysicalCoreIndex()];
 | 
			
		||||
    return *impl->cores[CurrentPhysicalCoreIndex()];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() const {
 | 
			
		||||
    return impl->cores[CurrentPhysicalCoreIndex()];
 | 
			
		||||
    return *impl->cores[CurrentPhysicalCoreIndex()];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Kernel::KScheduler* KernelCore::CurrentScheduler() {
 | 
			
		||||
@@ -906,15 +906,6 @@ Kernel::KScheduler* KernelCore::CurrentScheduler() {
 | 
			
		||||
    return impl->schedulers[core_id].get();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& KernelCore::Interrupts() {
 | 
			
		||||
    return impl->interrupts;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& KernelCore::Interrupts()
 | 
			
		||||
    const {
 | 
			
		||||
    return impl->interrupts;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Kernel::TimeManager& KernelCore::TimeManager() {
 | 
			
		||||
    return impl->time_manager;
 | 
			
		||||
}
 | 
			
		||||
@@ -939,24 +930,18 @@ const KAutoObjectWithListContainer& KernelCore::ObjectListContainer() const {
 | 
			
		||||
    return *impl->global_object_list_container;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void KernelCore::InterruptAllPhysicalCores() {
 | 
			
		||||
    for (auto& physical_core : impl->cores) {
 | 
			
		||||
        physical_core.Interrupt();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void KernelCore::InvalidateAllInstructionCaches() {
 | 
			
		||||
    for (auto& physical_core : impl->cores) {
 | 
			
		||||
        physical_core.ArmInterface().ClearInstructionCache();
 | 
			
		||||
        physical_core->ArmInterface().ClearInstructionCache();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void KernelCore::InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size) {
 | 
			
		||||
    for (auto& physical_core : impl->cores) {
 | 
			
		||||
        if (!physical_core.IsInitialized()) {
 | 
			
		||||
        if (!physical_core->IsInitialized()) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        physical_core.ArmInterface().InvalidateCacheRange(addr, size);
 | 
			
		||||
        physical_core->ArmInterface().InvalidateCacheRange(addr, size);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -9,14 +9,12 @@
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include "core/arm/cpu_interrupt_handler.h"
 | 
			
		||||
#include "core/hardware_properties.h"
 | 
			
		||||
#include "core/hle/kernel/k_auto_object.h"
 | 
			
		||||
#include "core/hle/kernel/k_slab_heap.h"
 | 
			
		||||
#include "core/hle/kernel/svc_common.h"
 | 
			
		||||
 | 
			
		||||
namespace Core {
 | 
			
		||||
class CPUInterruptHandler;
 | 
			
		||||
class ExclusiveMonitor;
 | 
			
		||||
class System;
 | 
			
		||||
} // namespace Core
 | 
			
		||||
@@ -183,12 +181,6 @@ public:
 | 
			
		||||
 | 
			
		||||
    const KAutoObjectWithListContainer& ObjectListContainer() const;
 | 
			
		||||
 | 
			
		||||
    std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& Interrupts();
 | 
			
		||||
 | 
			
		||||
    const std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& Interrupts() const;
 | 
			
		||||
 | 
			
		||||
    void InterruptAllPhysicalCores();
 | 
			
		||||
 | 
			
		||||
    void InvalidateAllInstructionCaches();
 | 
			
		||||
 | 
			
		||||
    void InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,6 @@
 | 
			
		||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
			
		||||
 | 
			
		||||
#include "core/arm/cpu_interrupt_handler.h"
 | 
			
		||||
#include "core/arm/dynarmic/arm_dynarmic_32.h"
 | 
			
		||||
#include "core/arm/dynarmic/arm_dynarmic_64.h"
 | 
			
		||||
#include "core/core.h"
 | 
			
		||||
@@ -11,16 +10,14 @@
 | 
			
		||||
 | 
			
		||||
namespace Kernel {
 | 
			
		||||
 | 
			
		||||
PhysicalCore::PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_,
 | 
			
		||||
                           Core::CPUInterrupts& interrupts_)
 | 
			
		||||
    : core_index{core_index_}, system{system_}, scheduler{scheduler_},
 | 
			
		||||
      interrupts{interrupts_}, guard{std::make_unique<std::mutex>()} {
 | 
			
		||||
PhysicalCore::PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_)
 | 
			
		||||
    : core_index{core_index_}, system{system_}, scheduler{scheduler_} {
 | 
			
		||||
#ifdef ARCHITECTURE_x86_64
 | 
			
		||||
    // TODO(bunnei): Initialization relies on a core being available. We may later replace this with
 | 
			
		||||
    // a 32-bit instance of Dynarmic. This should be abstracted out to a CPU manager.
 | 
			
		||||
    auto& kernel = system.Kernel();
 | 
			
		||||
    arm_interface = std::make_unique<Core::ARM_Dynarmic_64>(
 | 
			
		||||
        system, interrupts, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index);
 | 
			
		||||
        system, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index);
 | 
			
		||||
#else
 | 
			
		||||
#error Platform not supported yet.
 | 
			
		||||
#endif
 | 
			
		||||
@@ -34,7 +31,7 @@ void PhysicalCore::Initialize([[maybe_unused]] bool is_64_bit) {
 | 
			
		||||
    if (!is_64_bit) {
 | 
			
		||||
        // We already initialized a 64-bit core, replace with a 32-bit one.
 | 
			
		||||
        arm_interface = std::make_unique<Core::ARM_Dynarmic_32>(
 | 
			
		||||
            system, interrupts, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index);
 | 
			
		||||
            system, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index);
 | 
			
		||||
    }
 | 
			
		||||
#else
 | 
			
		||||
#error Platform not supported yet.
 | 
			
		||||
@@ -47,24 +44,26 @@ void PhysicalCore::Run() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PhysicalCore::Idle() {
 | 
			
		||||
    interrupts[core_index].AwaitInterrupt();
 | 
			
		||||
    std::unique_lock lk{guard};
 | 
			
		||||
    on_interrupt.wait(lk, [this] { return is_interrupted; });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool PhysicalCore::IsInterrupted() const {
 | 
			
		||||
    return interrupts[core_index].IsInterrupted();
 | 
			
		||||
    return is_interrupted;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PhysicalCore::Interrupt() {
 | 
			
		||||
    guard->lock();
 | 
			
		||||
    interrupts[core_index].SetInterrupt(true);
 | 
			
		||||
    std::unique_lock lk{guard};
 | 
			
		||||
    is_interrupted = true;
 | 
			
		||||
    arm_interface->SignalInterrupt();
 | 
			
		||||
    guard->unlock();
 | 
			
		||||
    on_interrupt.notify_all();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PhysicalCore::ClearInterrupt() {
 | 
			
		||||
    guard->lock();
 | 
			
		||||
    interrupts[core_index].SetInterrupt(false);
 | 
			
		||||
    guard->unlock();
 | 
			
		||||
    std::unique_lock lk{guard};
 | 
			
		||||
    is_interrupted = false;
 | 
			
		||||
    arm_interface->ClearInterrupt();
 | 
			
		||||
    on_interrupt.notify_all();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace Kernel
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,6 @@ class KScheduler;
 | 
			
		||||
} // namespace Kernel
 | 
			
		||||
 | 
			
		||||
namespace Core {
 | 
			
		||||
class CPUInterruptHandler;
 | 
			
		||||
class ExclusiveMonitor;
 | 
			
		||||
class System;
 | 
			
		||||
} // namespace Core
 | 
			
		||||
@@ -23,15 +22,11 @@ namespace Kernel {
 | 
			
		||||
 | 
			
		||||
class PhysicalCore {
 | 
			
		||||
public:
 | 
			
		||||
    PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_,
 | 
			
		||||
                 Core::CPUInterrupts& interrupts_);
 | 
			
		||||
    PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_);
 | 
			
		||||
    ~PhysicalCore();
 | 
			
		||||
 | 
			
		||||
    PhysicalCore(const PhysicalCore&) = delete;
 | 
			
		||||
    PhysicalCore& operator=(const PhysicalCore&) = delete;
 | 
			
		||||
 | 
			
		||||
    PhysicalCore(PhysicalCore&&) = default;
 | 
			
		||||
    PhysicalCore& operator=(PhysicalCore&&) = delete;
 | 
			
		||||
    YUZU_NON_COPYABLE(PhysicalCore);
 | 
			
		||||
    YUZU_NON_MOVEABLE(PhysicalCore);
 | 
			
		||||
 | 
			
		||||
    /// Initialize the core for the specified parameters.
 | 
			
		||||
    void Initialize(bool is_64_bit);
 | 
			
		||||
@@ -86,9 +81,11 @@ private:
 | 
			
		||||
    const std::size_t core_index;
 | 
			
		||||
    Core::System& system;
 | 
			
		||||
    Kernel::KScheduler& scheduler;
 | 
			
		||||
    Core::CPUInterrupts& interrupts;
 | 
			
		||||
    std::unique_ptr<std::mutex> guard;
 | 
			
		||||
 | 
			
		||||
    std::mutex guard;
 | 
			
		||||
    std::condition_variable on_interrupt;
 | 
			
		||||
    std::unique_ptr<Core::ARM_Interface> arm_interface;
 | 
			
		||||
    bool is_interrupted;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace Kernel
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user