mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2025-01-08 21:47:57 +00:00
thermopshere: interrupt refactoring
This commit is contained in:
parent
1ee289f5f1
commit
2574f68484
14 changed files with 205 additions and 148 deletions
|
@ -15,7 +15,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <assert.h>
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "core_ctx.h"
|
#include "core_ctx.h"
|
||||||
|
|
||||||
|
@ -86,8 +85,8 @@ typedef struct ExceptionStackFrame {
|
||||||
u64 cntv_ctl_el0;
|
u64 cntv_ctl_el0;
|
||||||
} ExceptionStackFrame;
|
} ExceptionStackFrame;
|
||||||
|
|
||||||
static_assert(offsetof(ExceptionStackFrame, far_el2) == 0x120, "Wrong definition for ExceptionStackFrame");
|
//static_assert(offsetof(ExceptionStackFrame, far_el2) == 0x120, "Wrong definition for ExceptionStackFrame");
|
||||||
static_assert(sizeof(ExceptionStackFrame) == 0x140, "Wrong size for ExceptionStackFrame");
|
//static_assert(sizeof(ExceptionStackFrame) == 0x140, "Wrong size for ExceptionStackFrame");
|
||||||
|
|
||||||
static inline bool spsrIsA32(u64 spsr)
|
static inline bool spsrIsA32(u64 spsr)
|
||||||
{
|
{
|
||||||
|
|
|
@ -24,17 +24,11 @@ namespace ams::hvisor {
|
||||||
|
|
||||||
HwBreakpointManager HwBreakpointManager::instance{};
|
HwBreakpointManager HwBreakpointManager::instance{};
|
||||||
|
|
||||||
void HwBreakpointManager::ReloadOnAllCoresSgiHandler()
|
void HwBreakpointManager::Reload() const
|
||||||
{
|
{
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
void HwBreakpointManager::ReloadOnAllCores() const
|
|
||||||
{
|
|
||||||
cpu::dmb();
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HwBreakpointManager::FindPredicate(const cpu::DebugRegisterPair &pair, uintptr_t addr, size_t, cpu::DebugRegisterPair::LoadStoreControl) const
|
bool HwBreakpointManager::FindPredicate(const cpu::DebugRegisterPair &pair, uintptr_t addr, size_t, cpu::DebugRegisterPair::LoadStoreControl) const
|
||||||
{
|
{
|
||||||
return pair.vr == addr;
|
return pair.vr == addr;
|
||||||
|
|
|
@ -22,18 +22,15 @@ namespace ams::hvisor {
|
||||||
|
|
||||||
class HwBreakpointManager final : public HwStopPointManager {
|
class HwBreakpointManager final : public HwStopPointManager {
|
||||||
SINGLETON(HwBreakpointManager);
|
SINGLETON(HwBreakpointManager);
|
||||||
protected:
|
private:
|
||||||
virtual bool FindPredicate(const cpu::DebugRegisterPair &pair, uintptr_t addr, size_t, cpu::DebugRegisterPair::LoadStoreControl) const;
|
bool FindPredicate(const cpu::DebugRegisterPair &pair, uintptr_t addr, size_t, cpu::DebugRegisterPair::LoadStoreControl) const final;
|
||||||
|
void Reload() const final;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void ReloadOnAllCores() const;
|
|
||||||
static void ReloadOnAllCoresSgiHandler();
|
|
||||||
|
|
||||||
cpu::DebugRegisterPair RetrieveWatchpointConfig(uintptr_t addr, cpu::DebugRegisterPair::LoadStoreControl direction) const;
|
|
||||||
int Add(uintptr_t addr);
|
int Add(uintptr_t addr);
|
||||||
int Remove(uintptr_t addr);
|
int Remove(uintptr_t addr);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
constexpr HwBreakpointManager() : HwStopPointManager(MAX_BCR) {}
|
constexpr HwBreakpointManager() : HwStopPointManager(MAX_BCR, IrqManager::ReloadHwBreakpointsSgi) {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "hvisor_hw_stop_point_manager.hpp"
|
#include "hvisor_hw_stop_point_manager.hpp"
|
||||||
|
#include "cpu/hvisor_cpu_instructions.hpp"
|
||||||
|
#include "cpu/hvisor_cpu_interrupt_mask_guard.hpp"
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
#define _REENT_ONLY
|
#define _REENT_ONLY
|
||||||
|
@ -22,6 +24,16 @@
|
||||||
|
|
||||||
namespace ams::hvisor {
|
namespace ams::hvisor {
|
||||||
|
|
||||||
|
void HwStopPointManager::DoReloadOnAllCores() const
|
||||||
|
{
|
||||||
|
cpu::InterruptMaskGuard mg{};
|
||||||
|
cpu::dmb();
|
||||||
|
Reload();
|
||||||
|
m_reloadBarrier.Reset(getActiveCoreMask());
|
||||||
|
IrqManager::GenerateSgiForAllOthers(m_irqId);
|
||||||
|
m_reloadBarrier.Join();
|
||||||
|
}
|
||||||
|
|
||||||
cpu::DebugRegisterPair *HwStopPointManager::Allocate()
|
cpu::DebugRegisterPair *HwStopPointManager::Allocate()
|
||||||
{
|
{
|
||||||
size_t pos = __builtin_ffs(m_freeBitmap);
|
size_t pos = __builtin_ffs(m_freeBitmap);
|
||||||
|
@ -76,7 +88,7 @@ namespace ams::hvisor {
|
||||||
regs->vr = preconfiguredPair.vr;
|
regs->vr = preconfiguredPair.vr;
|
||||||
regs->cr.enabled = true;
|
regs->cr.enabled = true;
|
||||||
|
|
||||||
ReloadOnAllCores();
|
DoReloadOnAllCores();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,7 +110,16 @@ namespace ams::hvisor {
|
||||||
m_freeBitmap |= m_usedBitmap;
|
m_freeBitmap |= m_usedBitmap;
|
||||||
m_usedBitmap = 0;
|
m_usedBitmap = 0;
|
||||||
std::fill(m_stopPoints.begin(), m_stopPoints.end(), cpu::DebugRegisterPair{});
|
std::fill(m_stopPoints.begin(), m_stopPoints.end(), cpu::DebugRegisterPair{});
|
||||||
ReloadOnAllCores();
|
DoReloadOnAllCores();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<bool> HwStopPointManager::InterruptTopHalfHandler(u32 irqId, u32)
|
||||||
|
{
|
||||||
|
if (irqId != m_irqId) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
Reload();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,37 +17,58 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "defines.hpp"
|
#include "defines.hpp"
|
||||||
#include "hvisor_synchronization.hpp"
|
|
||||||
#include "cpu/hvisor_cpu_debug_register_pair.hpp"
|
#include "cpu/hvisor_cpu_debug_register_pair.hpp"
|
||||||
|
#include "hvisor_irq_manager.hpp"
|
||||||
|
|
||||||
namespace ams::hvisor {
|
namespace ams::hvisor {
|
||||||
|
|
||||||
class HwStopPointManager {
|
class HwStopPointManager : public IInterruptTask {
|
||||||
NON_COPYABLE(HwStopPointManager);
|
NON_COPYABLE(HwStopPointManager);
|
||||||
NON_MOVEABLE(HwStopPointManager);
|
NON_MOVEABLE(HwStopPointManager);
|
||||||
protected:
|
protected:
|
||||||
static constexpr size_t maxStopPoints = std::max(MAX_BCR, MAX_WCR);
|
static constexpr size_t maxStopPoints = std::max(MAX_BCR, MAX_WCR);
|
||||||
|
|
||||||
|
protected:
|
||||||
mutable RecursiveSpinlock m_lock{};
|
mutable RecursiveSpinlock m_lock{};
|
||||||
|
mutable Barrier m_reloadBarrier{};
|
||||||
|
|
||||||
u16 m_freeBitmap;
|
u16 m_freeBitmap;
|
||||||
u16 m_usedBitmap = 0;
|
u16 m_usedBitmap = 0;
|
||||||
std::array<cpu::DebugRegisterPair, maxStopPoints> m_stopPoints{};
|
std::array<cpu::DebugRegisterPair, maxStopPoints> m_stopPoints{};
|
||||||
|
IrqManager::ThermosphereSgi m_irqId;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
void DoReloadOnAllCores() const;
|
||||||
cpu::DebugRegisterPair *Allocate();
|
cpu::DebugRegisterPair *Allocate();
|
||||||
void Free(size_t pos);
|
void Free(size_t pos);
|
||||||
const cpu::DebugRegisterPair *Find(uintptr_t addr, size_t size, cpu::DebugRegisterPair::LoadStoreControl dir) const;
|
const cpu::DebugRegisterPair *Find(uintptr_t addr, size_t size, cpu::DebugRegisterPair::LoadStoreControl dir) const;
|
||||||
|
|
||||||
virtual bool FindPredicate(const cpu::DebugRegisterPair &pair, uintptr_t addr, size_t size, cpu::DebugRegisterPair::LoadStoreControl direction) const = 0;
|
virtual bool FindPredicate(const cpu::DebugRegisterPair &pair, uintptr_t addr, size_t size, cpu::DebugRegisterPair::LoadStoreControl direction) const = 0;
|
||||||
|
virtual void Reload() const = 0;
|
||||||
|
|
||||||
int AddImpl(uintptr_t addr, size_t size, cpu::DebugRegisterPair preconfiguredPair);
|
int AddImpl(uintptr_t addr, size_t size, cpu::DebugRegisterPair preconfiguredPair);
|
||||||
int RemoveImpl(uintptr_t addr, size_t size, cpu::DebugRegisterPair::LoadStoreControl direction);
|
int RemoveImpl(uintptr_t addr, size_t size, cpu::DebugRegisterPair::LoadStoreControl direction);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
constexpr HwStopPointManager(size_t numStopPoints) : m_freeBitmap(MASK(numStopPoints)) {}
|
constexpr HwStopPointManager(size_t numStopPoints, IrqManager::ThermosphereSgi irqId) :
|
||||||
|
m_freeBitmap(MASK(numStopPoints)), m_irqId(irqId)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void ReloadOnAllCores() const = 0;
|
|
||||||
void RemoveAll();
|
void RemoveAll();
|
||||||
|
std::optional<bool> InterruptTopHalfHandler(u32 irqId, u32) final;
|
||||||
|
|
||||||
|
void ReloadOnAllCores() const
|
||||||
|
{
|
||||||
|
m_lock.lock();
|
||||||
|
DoReloadOnAllCores();
|
||||||
|
m_lock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Initialize()
|
||||||
|
{
|
||||||
|
IrqManager::GetInstance().Register(*this, m_irqId, false);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
34
thermosphere/src/hvisor_i_interrupt_task.hpp
Normal file
34
thermosphere/src/hvisor_i_interrupt_task.hpp
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "defines.hpp"
|
||||||
|
#include <vapours/util/util_intrusive_list.hpp>
|
||||||
|
|
||||||
|
namespace ams::hvisor {
|
||||||
|
|
||||||
|
class IInterruptTask : public util::IntrusiveListBaseNode<IInterruptTask> {
|
||||||
|
NON_COPYABLE(IInterruptTask);
|
||||||
|
NON_MOVEABLE(IInterruptTask);
|
||||||
|
protected:
|
||||||
|
constexpr IInterruptTask() = default;
|
||||||
|
public:
|
||||||
|
virtual std::optional<bool> InterruptTopHalfHandler(u32 irqId, u32 srcCore) = 0;
|
||||||
|
virtual void InterruptBottomHalfHandler(u32 irqId, u32 srcCore) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -17,6 +17,8 @@
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
#include "hvisor_irq_manager.hpp"
|
#include "hvisor_irq_manager.hpp"
|
||||||
|
#include "hvisor_virtual_gic.hpp"
|
||||||
|
|
||||||
#include "cpu/hvisor_cpu_interrupt_mask_guard.hpp"
|
#include "cpu/hvisor_cpu_interrupt_mask_guard.hpp"
|
||||||
#include "platform/interrupt_config.h"
|
#include "platform/interrupt_config.h"
|
||||||
#include "core_ctx.h"
|
#include "core_ctx.h"
|
||||||
|
@ -24,7 +26,6 @@
|
||||||
#include "transport_interface.h"
|
#include "transport_interface.h"
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
|
|
||||||
#include "vgic.h"
|
|
||||||
//#include "debug_manager.h"
|
//#include "debug_manager.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -161,21 +162,20 @@ namespace ams::hvisor {
|
||||||
std::scoped_lock lk{m_lock};
|
std::scoped_lock lk{m_lock};
|
||||||
|
|
||||||
InitializeGic();
|
InitializeGic();
|
||||||
for (u32 i = 0; i < MaxSgi; i++) {
|
|
||||||
DoConfigureInterrupt(i, hostPriority, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
DoConfigureInterrupt(GIC_IRQID_MAINTENANCE, hostPriority, true);
|
DoConfigureInterrupt(GIC_IRQID_MAINTENANCE, hostPriority, true);
|
||||||
|
|
||||||
vgicInit();
|
VirtualGic::GetInstance().Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IrqManager::ConfigureInterrupt(u32 id, u8 prio, bool isLevelSensitive)
|
void IrqManager::Register(IInterruptTask &task, u32 id, bool isLevelSensitive, u8 prio)
|
||||||
{
|
{
|
||||||
cpu::InterruptMaskGuard mg{};
|
cpu::InterruptMaskGuard mg{};
|
||||||
std::scoped_lock lk{m_lock};
|
std::scoped_lock lk{m_lock};
|
||||||
|
|
||||||
DoConfigureInterrupt(id, prio, isLevelSensitive);
|
DoConfigureInterrupt(id, prio, isLevelSensitive);
|
||||||
|
if (!task.IsLinked()) {
|
||||||
|
m_interruptTaskList.push_back(task);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IrqManager::SetInterruptAffinity(u32 id, u8 affinity)
|
void IrqManager::SetInterruptAffinity(u32 id, u8 affinity)
|
||||||
|
@ -188,96 +188,53 @@ namespace ams::hvisor {
|
||||||
|
|
||||||
void IrqManager::HandleInterrupt(ExceptionStackFrame *frame)
|
void IrqManager::HandleInterrupt(ExceptionStackFrame *frame)
|
||||||
{
|
{
|
||||||
// TODO refactor c parts
|
|
||||||
|
|
||||||
// Acknowledge the interrupt. Interrupt goes from pending to active.
|
// Acknowledge the interrupt. Interrupt goes from pending to active.
|
||||||
u32 iar = AcknowledgeIrq();
|
u32 iar = AcknowledgeIrq();
|
||||||
u32 irqId = iar & 0x3FF;
|
u32 irqId = iar & 0x3FF;
|
||||||
u32 srcCore = (iar >> 10) & 7;
|
u32 srcCore = (iar >> 10) & 7;
|
||||||
|
IInterruptTask *taskForBottomHalf;
|
||||||
|
|
||||||
//DEBUG("EL2 [core %d]: Received irq %x\n", (int)currentCoreCtx->coreId, irqId);
|
//DEBUG("EL2 [core %d]: Received irq %x\n", (int)currentCoreCtx->coreId, irqId);
|
||||||
|
|
||||||
if (irqId == GicV2Distributor::spuriousIrqId) {
|
if (irqId == GicV2Distributor::spuriousIrqId) {
|
||||||
// Spurious interrupt received
|
// Spurious interrupt received
|
||||||
return;
|
return;
|
||||||
} else if (!checkGuestTimerInterrupts(frame, irqId)) {
|
} else if (!checkGuestTimerInterrupts(frame, irqId)) {
|
||||||
// Deactivate the interrupt, return early
|
// Deactivate the interrupt, return ASAP
|
||||||
DropCurrentInterruptPriority(iar);
|
DropCurrentInterruptPriority(iar);
|
||||||
DeactivateCurrentInterrupt(iar);
|
DeactivateCurrentInterrupt(iar);
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
bool isGuestInterrupt = false;
|
|
||||||
bool isMaintenanceInterrupt = false;
|
|
||||||
bool isPaused = false;
|
|
||||||
bool hasDebugEvent = false;
|
|
||||||
|
|
||||||
switch (irqId) {
|
|
||||||
case ExecuteFunctionSgi:
|
|
||||||
executeFunctionInterruptHandler(srcCore);
|
|
||||||
break;
|
|
||||||
case VgicUpdateSgi:
|
|
||||||
// Nothing in particular to do here
|
|
||||||
break;
|
|
||||||
case DebugPauseSgi:
|
|
||||||
// TODO debugManagerPauseSgiHandler();
|
|
||||||
break;
|
|
||||||
case ReportDebuggerBreakSgi:
|
|
||||||
case DebuggerContinueSgi:
|
|
||||||
// See bottom halves
|
|
||||||
// Because exceptions (other debug events) are handling w/ interrupts off, if
|
|
||||||
// we get there, there's no race condition possible with debugManagerReportEvent
|
|
||||||
break;
|
|
||||||
case GIC_IRQID_MAINTENANCE:
|
|
||||||
isMaintenanceInterrupt = true;
|
|
||||||
break;
|
|
||||||
case TIMER_IRQID(CURRENT_TIMER):
|
|
||||||
timerInterruptHandler();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
isGuestInterrupt = irqId >= 16;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
TransportInterface *transportIface = irqId >= 32 ? transportInterfaceIrqHandlerTopHalf(irqId) : NULL;
|
|
||||||
|
|
||||||
// Priority drop
|
|
||||||
DropCurrentInterruptPriority(iar);
|
|
||||||
|
|
||||||
isGuestInterrupt = isGuestInterrupt && transportIface == NULL && IsGuestInterrupt(irqId);
|
|
||||||
|
|
||||||
instance.m_lock.lock();
|
|
||||||
|
|
||||||
if (!isGuestInterrupt) {
|
|
||||||
if (isMaintenanceInterrupt) {
|
|
||||||
vgicMaintenanceInterruptHandler();
|
|
||||||
}
|
|
||||||
// Deactivate the interrupt
|
|
||||||
DeactivateCurrentInterrupt(iar);
|
|
||||||
} else {
|
} else {
|
||||||
vgicEnqueuePhysicalIrq(irqId);
|
// Everything else
|
||||||
|
std::scoped_lock lk{instance.m_lock};
|
||||||
|
VirtualGic &vgic = VirtualGic::GetInstance();
|
||||||
|
|
||||||
|
if (irqId >= 16 && IsGuestInterrupt(irqId)) {
|
||||||
|
// Guest interrupts
|
||||||
|
taskForBottomHalf = nullptr;
|
||||||
|
DropCurrentInterruptPriority(iar);
|
||||||
|
vgic.EnqueuePhysicalIrq(irqId);
|
||||||
|
} else {
|
||||||
|
// Host interrupts
|
||||||
|
// Try all handlers and see which one fits
|
||||||
|
for (IInterruptTask &task: instance.m_interruptTaskList) {
|
||||||
|
auto b = task.InterruptTopHalfHandler(irqId, srcCore);
|
||||||
|
if (b) {
|
||||||
|
taskForBottomHalf = *b ? &task : nullptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DropCurrentInterruptPriority(iar);
|
||||||
|
DeactivateCurrentInterrupt(iar);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update vgic state
|
vgic.UpdateState();
|
||||||
vgicUpdateState();
|
}
|
||||||
|
|
||||||
instance.m_lock.unlock();
|
|
||||||
|
|
||||||
// TODO
|
if (taskForBottomHalf != nullptr) {
|
||||||
|
// Unmasking the irq signal is left at the discretion of the bottom half handler
|
||||||
/*isPaused = debugManagerIsCorePaused(currentCoreCtx->coreId);
|
|
||||||
hasDebugEvent = debugManagerHasDebugEvent(currentCoreCtx->coreId);
|
|
||||||
if (irqId == ThermosphereSgi_ReportDebuggerBreak) DEBUG("debug event=%d\n", (int)debugManagerGetDebugEvent(currentCoreCtx->coreId)->type);
|
|
||||||
// Bottom half part
|
|
||||||
if (transportIface != NULL) {
|
|
||||||
exceptionEnterInterruptibleHypervisorCode();
|
exceptionEnterInterruptibleHypervisorCode();
|
||||||
unmaskIrq();
|
taskForBottomHalf->InterruptBottomHalfHandler(irqId, srcCore);
|
||||||
transportInterfaceIrqHandlerBottomHalf(transportIface);
|
}
|
||||||
} else if (irqId == ThermosphereSgi_ReportDebuggerBreak && !hasDebugEvent) {
|
|
||||||
debugManagerReportEvent(DBGEVENT_DEBUGGER_BREAK);
|
|
||||||
} else if (irqId == DebuggerContinueSgi && isPaused) {
|
|
||||||
debugManagerUnpauseCores(BIT(currentCoreCtx->coreId));
|
|
||||||
}*/
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
|
|
||||||
#include "hvisor_gicv2.hpp"
|
#include "hvisor_gicv2.hpp"
|
||||||
#include "hvisor_synchronization.hpp"
|
#include "hvisor_synchronization.hpp"
|
||||||
|
#include "hvisor_i_interrupt_task.hpp"
|
||||||
|
|
||||||
#include "memory_map.h"
|
#include "memory_map.h"
|
||||||
|
|
||||||
#include "exceptions.h" // TODO
|
#include "exceptions.h" // TODO
|
||||||
|
@ -62,7 +64,10 @@ namespace ams::hvisor {
|
||||||
static void DeactivateCurrentInterrupt(u32 iar) { gicc->dir = iar; }
|
static void DeactivateCurrentInterrupt(u32 iar) { gicc->dir = iar; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
using InterruptTaskList = util::IntrusiveListBaseTraits<IInterruptTask>::ListType;
|
||||||
|
|
||||||
mutable RecursiveSpinlock m_lock{};
|
mutable RecursiveSpinlock m_lock{};
|
||||||
|
InterruptTaskList m_interruptTaskList{};
|
||||||
u32 m_numSharedInterrupts = 0;
|
u32 m_numSharedInterrupts = 0;
|
||||||
u8 m_priorityShift = 0;
|
u8 m_priorityShift = 0;
|
||||||
u8 m_numPriorityLevels = 0;
|
u8 m_numPriorityLevels = 0;
|
||||||
|
@ -76,8 +81,12 @@ namespace ams::hvisor {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum ThermosphereSgi : u32 {
|
enum ThermosphereSgi : u32 {
|
||||||
ExecuteFunctionSgi = 0,
|
VgicUpdateSgi = 0,
|
||||||
VgicUpdateSgi,
|
|
||||||
|
ReloadHwBreakpointsSgi,
|
||||||
|
ReloadWatchpointsSgi,
|
||||||
|
ApplyRevertSwBreakpointSgi,
|
||||||
|
|
||||||
DebugPauseSgi,
|
DebugPauseSgi,
|
||||||
ReportDebuggerBreakSgi,
|
ReportDebuggerBreakSgi,
|
||||||
DebuggerContinueSgi,
|
DebuggerContinueSgi,
|
||||||
|
@ -98,7 +107,7 @@ namespace ams::hvisor {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void Initialize();
|
void Initialize();
|
||||||
void ConfigureInterrupt(u32 id, u8 prio, bool isLevelSensitive);
|
void Register(IInterruptTask &task, u32 id, bool isLevelSensitive, u8 prio = IrqManager::hostPriority);
|
||||||
void SetInterruptAffinity(u32 id, u8 affinityMask);
|
void SetInterruptAffinity(u32 id, u8 affinityMask);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
#include "hvisor_sw_breakpoint_manager.hpp"
|
#include "hvisor_sw_breakpoint_manager.hpp"
|
||||||
#include "cpu/hvisor_cpu_instructions.hpp"
|
#include "cpu/hvisor_cpu_instructions.hpp"
|
||||||
|
#include "cpu/hvisor_cpu_interrupt_mask_guard.hpp"
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
|
@ -59,7 +60,6 @@ namespace ams::hvisor {
|
||||||
|
|
||||||
size_t sz = guestReadWriteMemory(bp.address, 4, &bp.savedInstruction, &brkInst);
|
size_t sz = guestReadWriteMemory(bp.address, 4, &bp.savedInstruction, &brkInst);
|
||||||
bp.applied = sz == 4;
|
bp.applied = sz == 4;
|
||||||
m_triedToApplyOrRevertBreakpoint.store(true);
|
|
||||||
return sz == 4;
|
return sz == 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,10 +68,33 @@ namespace ams::hvisor {
|
||||||
Breakpoint &bp = m_breakpoints[id];
|
Breakpoint &bp = m_breakpoints[id];
|
||||||
size_t sz = guestWriteMemory(bp.address, 4, &bp.savedInstruction);
|
size_t sz = guestWriteMemory(bp.address, 4, &bp.savedInstruction);
|
||||||
bp.applied = sz != 4;
|
bp.applied = sz != 4;
|
||||||
m_triedToApplyOrRevertBreakpoint.store(true);
|
|
||||||
return sz == 4;
|
return sz == 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<bool> SwBreakpointManager::InterruptTopHalfHandler(u32 irqId, u32)
|
||||||
|
{
|
||||||
|
if (irqId != IrqManager::ApplyRevertSwBreakpointSgi) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
m_applyBarrier.Join();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SwBreakpointManager::ApplyOrRevert(size_t id, bool apply)
|
||||||
|
{
|
||||||
|
cpu::InterruptMaskGuard mg{};
|
||||||
|
m_applyBarrier.Reset(getActiveCoreMask());
|
||||||
|
IrqManager::GenerateSgiForAllOthers(IrqManager::ApplyRevertSwBreakpointSgi);
|
||||||
|
if (apply) {
|
||||||
|
DoApply(id);
|
||||||
|
} else {
|
||||||
|
DoRevert(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_applyBarrier.Join();
|
||||||
|
}
|
||||||
|
|
||||||
// TODO apply revert handlers
|
// TODO apply revert handlers
|
||||||
|
|
||||||
int SwBreakpointManager::Add(uintptr_t addr, bool persistent)
|
int SwBreakpointManager::Add(uintptr_t addr, bool persistent)
|
||||||
|
@ -103,7 +126,7 @@ namespace ams::hvisor {
|
||||||
bp.applied = false;
|
bp.applied = false;
|
||||||
bp.uid = static_cast<u16>(0x2000 + m_bpUniqueCounter++);
|
bp.uid = static_cast<u16>(0x2000 + m_bpUniqueCounter++);
|
||||||
|
|
||||||
return Apply(id) ? 0 : -EFAULT;
|
return ApplyOrRevert(id, true) ? 0 : -EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SwBreakpointManager::Remove(uintptr_t addr, bool keepPersistent)
|
int SwBreakpointManager::Remove(uintptr_t addr, bool keepPersistent)
|
||||||
|
@ -126,7 +149,7 @@ namespace ams::hvisor {
|
||||||
Breakpoint &bp = m_breakpoints[id];
|
Breakpoint &bp = m_breakpoints[id];
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
if (!keepPersistent || !bp.persistent) {
|
if (!keepPersistent || !bp.persistent) {
|
||||||
ok = Revert(id);
|
ok = ApplyOrRevert(id, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(size_t i = id; i < m_numBreakpoints - 1; i++) {
|
for(size_t i = id; i < m_numBreakpoints - 1; i++) {
|
||||||
|
@ -146,7 +169,7 @@ namespace ams::hvisor {
|
||||||
for (size_t id = 0; id < m_numBreakpoints; id++) {
|
for (size_t id = 0; id < m_numBreakpoints; id++) {
|
||||||
Breakpoint &bp = m_breakpoints[id];
|
Breakpoint &bp = m_breakpoints[id];
|
||||||
if (!keepPersistent || !bp.persistent) {
|
if (!keepPersistent || !bp.persistent) {
|
||||||
ok = ok && Revert(id);
|
ok = ok && ApplyOrRevert(id, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,6 +179,4 @@ namespace ams::hvisor {
|
||||||
|
|
||||||
return ok ? 0 : -EFAULT;
|
return ok ? 0 : -EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -17,13 +17,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "defines.hpp"
|
#include "defines.hpp"
|
||||||
#include "hvisor_synchronization.hpp"
|
#include "hvisor_irq_manager.hpp"
|
||||||
|
|
||||||
#define MAX_SW_BREAKPOINTS 16
|
#define MAX_SW_BREAKPOINTS 16
|
||||||
|
|
||||||
namespace ams::hvisor {
|
namespace ams::hvisor {
|
||||||
|
|
||||||
class SwBreakpointManager {
|
class SwBreakpointManager : public IInterruptTask {
|
||||||
SINGLETON(SwBreakpointManager);
|
SINGLETON(SwBreakpointManager);
|
||||||
private:
|
private:
|
||||||
struct Breakpoint {
|
struct Breakpoint {
|
||||||
|
@ -36,7 +36,7 @@ namespace ams::hvisor {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
mutable RecursiveSpinlock m_lock{};
|
mutable RecursiveSpinlock m_lock{};
|
||||||
std::atomic<bool> m_triedToApplyOrRevertBreakpoint{};
|
mutable Barrier m_applyBarrier{};
|
||||||
|
|
||||||
u32 m_bpUniqueCounter = 0;
|
u32 m_bpUniqueCounter = 0;
|
||||||
size_t m_numBreakpoints = 0;
|
size_t m_numBreakpoints = 0;
|
||||||
|
@ -48,15 +48,18 @@ namespace ams::hvisor {
|
||||||
bool DoApply(size_t id);
|
bool DoApply(size_t id);
|
||||||
bool DoRevert(size_t id);
|
bool DoRevert(size_t id);
|
||||||
|
|
||||||
// TODO apply, revert handler
|
bool ApplyOrRevert(size_t id, bool apply);
|
||||||
bool Apply(size_t id);
|
|
||||||
bool Revert(size_t id);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int Add(uintptr_t addr, bool persistent);
|
int Add(uintptr_t addr, bool persistent);
|
||||||
int Remove(uintptr_t addr, bool keepPersistent);
|
int Remove(uintptr_t addr, bool keepPersistent);
|
||||||
int RemoveAll(bool keepPersistent);
|
int RemoveAll(bool keepPersistent);
|
||||||
|
|
||||||
|
std::optional<bool> InterruptTopHalfHandler(u32 irqId, u32) final;
|
||||||
|
void Initialize()
|
||||||
|
{
|
||||||
|
IrqManager::GetInstance().Register(*this, IrqManager::ApplyRevertSwBreakpointSgi, false);
|
||||||
|
}
|
||||||
public:
|
public:
|
||||||
constexpr SwBreakpointManager() = default;
|
constexpr SwBreakpointManager() = default;
|
||||||
};
|
};
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
#include "hvisor_virtual_gic.hpp"
|
#include "hvisor_virtual_gic.hpp"
|
||||||
#include "cpu/hvisor_cpu_instructions.hpp"
|
#include "cpu/hvisor_cpu_instructions.hpp"
|
||||||
|
|
||||||
|
#include "platform/interrupt_config.h" // TODO remove
|
||||||
|
|
||||||
#define GICDOFF(field) (offsetof(GicV2Distributor, field))
|
#define GICDOFF(field) (offsetof(GicV2Distributor, field))
|
||||||
|
|
||||||
namespace ams::hvisor {
|
namespace ams::hvisor {
|
||||||
|
@ -625,8 +627,16 @@ namespace ams::hvisor {
|
||||||
gich->hcr.raw = hcr.raw;
|
gich->hcr.raw = hcr.raw;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VirtualGic::MaintenanceInterruptHandler()
|
std::optional<bool> VirtualGic::InterruptTopHalfHandler(u32 irqId, u32)
|
||||||
{
|
{
|
||||||
|
if (irqId == IrqManager::VgicUpdateSgi) {
|
||||||
|
// This SGI is just there to trigger the state update
|
||||||
|
return false;
|
||||||
|
} else if (irqId != GIC_IRQID_MAINTENANCE) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Maintenance interrupt handler:
|
||||||
GicV2VirtualInterfaceController::MaintenanceIntStatRegister misr = { .raw = gich->misr.raw };
|
GicV2VirtualInterfaceController::MaintenanceIntStatRegister misr = { .raw = gich->misr.raw };
|
||||||
|
|
||||||
// Force GICV_CTRL to behave like ns-GICC_CTLR, with group 1 being replaced by group 0
|
// Force GICV_CTRL to behave like ns-GICC_CTLR, with group 1 being replaced by group 0
|
||||||
|
@ -669,6 +679,7 @@ namespace ams::hvisor {
|
||||||
ENSURE2(!misr.lrenp, "List Register Entry Not Present maintenance interrupt!\n");
|
ENSURE2(!misr.lrenp, "List Register Entry Not Present maintenance interrupt!\n");
|
||||||
|
|
||||||
// The rest should be handled by the main loop...
|
// The rest should be handled by the main loop...
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VirtualGic::EnqueuePhysicalIrq(u32 id)
|
void VirtualGic::EnqueuePhysicalIrq(u32 id)
|
||||||
|
@ -715,6 +726,11 @@ namespace ams::hvisor {
|
||||||
// All guest SPIs are initially configured as level-sensitive with no targets
|
// All guest SPIs are initially configured as level-sensitive with no targets
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto &mgr = IrqManager::GetInstance();
|
||||||
|
|
||||||
|
mgr.Register(*this, GIC_IRQID_MAINTENANCE, true);
|
||||||
|
mgr.Register(*this, IrqManager::VgicUpdateSgi, false);
|
||||||
|
|
||||||
// Clear the list registers (they reset to 0, though)
|
// Clear the list registers (they reset to 0, though)
|
||||||
for (u8 i = 0; i < m_numListRegisters; i++) {
|
for (u8 i = 0; i < m_numListRegisters; i++) {
|
||||||
gich->lr[i].raw = 0;
|
gich->lr[i].raw = 0;
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
|
|
||||||
namespace ams::hvisor {
|
namespace ams::hvisor {
|
||||||
|
|
||||||
class VirtualGic final {
|
class VirtualGic final : public IInterruptTask {
|
||||||
SINGLETON(VirtualGic);
|
SINGLETON(VirtualGic);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -366,29 +366,19 @@ namespace ams::hvisor {
|
||||||
void PushListRegisters(VirqState *chosen[], size_t num);
|
void PushListRegisters(VirqState *chosen[], size_t num);
|
||||||
bool UpdateListRegister(volatile GicV2VirtualInterfaceController::ListRegister *lr);
|
bool UpdateListRegister(volatile GicV2VirtualInterfaceController::ListRegister *lr);
|
||||||
|
|
||||||
void UpdateState();
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static bool ValidateGicdRegisterAccess(size_t offset, size_t sz);
|
static bool ValidateGicdRegisterAccess(size_t offset, size_t sz);
|
||||||
public:
|
public:
|
||||||
void WriteGicdRegister(u32 val, size_t offset, size_t sz);
|
void WriteGicdRegister(u32 val, size_t offset, size_t sz);
|
||||||
u32 ReadGicdRegister(size_t offset, size_t sz);
|
u32 ReadGicdRegister(size_t offset, size_t sz);
|
||||||
|
|
||||||
void MaintenanceInterruptHandler();
|
// Must be called by irqManager only...
|
||||||
void EnqueuePhysicalIrq(u32 id);
|
// not sure if I should have made IrqManager a friend of this class
|
||||||
|
void UpdateState();
|
||||||
|
|
||||||
|
std::optional<bool> InterruptTopHalfHandler(u32 irqId, u32) final;
|
||||||
|
|
||||||
|
void EnqueuePhysicalIrq(u32 id);
|
||||||
void Initialize();
|
void Initialize();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*bool vgicValidateGicdRegisterAccess(size_t offset, size_t sz);
|
|
||||||
void vgicWriteGicdRegister(u32 val, size_t offset, size_t sz);
|
|
||||||
u32 vgicReadGicdRegister(size_t offset, size_t sz);
|
|
||||||
|
|
||||||
void handleVgicdMmio(ExceptionStackFrame *frame, cpu::DataAbortIss dabtIss, size_t offset);
|
|
||||||
|
|
||||||
void vgicInit(void);
|
|
||||||
void vgicUpdateState(void);
|
|
||||||
void vgicMaintenanceInterruptHandler(void);
|
|
||||||
void vgicEnqueuePhysicalIrq(u16 irqId);*/
|
|
||||||
|
|
|
@ -47,17 +47,11 @@ namespace ams::hvisor {
|
||||||
|
|
||||||
WatchpointManager WatchpointManager::instance{};
|
WatchpointManager WatchpointManager::instance{};
|
||||||
|
|
||||||
void WatchpointManager::ReloadOnAllCoresSgiHandler()
|
void WatchpointManager::Reload() const
|
||||||
{
|
{
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
void WatchpointManager::ReloadOnAllCores() const
|
|
||||||
{
|
|
||||||
cpu::dmb();
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WatchpointManager::FindPredicate(const cpu::DebugRegisterPair &pair, uintptr_t addr, size_t size, cpu::DebugRegisterPair::LoadStoreControl direction) const
|
bool WatchpointManager::FindPredicate(const cpu::DebugRegisterPair &pair, uintptr_t addr, size_t size, cpu::DebugRegisterPair::LoadStoreControl direction) const
|
||||||
{
|
{
|
||||||
size_t off;
|
size_t off;
|
||||||
|
|
|
@ -22,8 +22,9 @@ namespace ams::hvisor {
|
||||||
|
|
||||||
class WatchpointManager final : public HwStopPointManager {
|
class WatchpointManager final : public HwStopPointManager {
|
||||||
SINGLETON(WatchpointManager);
|
SINGLETON(WatchpointManager);
|
||||||
protected:
|
private:
|
||||||
virtual bool FindPredicate(const cpu::DebugRegisterPair &pair, uintptr_t addr, size_t size, cpu::DebugRegisterPair::LoadStoreControl direction) const;
|
bool FindPredicate(const cpu::DebugRegisterPair &pair, uintptr_t addr, size_t size, cpu::DebugRegisterPair::LoadStoreControl direction) const final;
|
||||||
|
void Reload() const final;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void ReloadOnAllCores() const;
|
virtual void ReloadOnAllCores() const;
|
||||||
|
@ -34,6 +35,6 @@ namespace ams::hvisor {
|
||||||
int Remove(uintptr_t addr, size_t size, cpu::DebugRegisterPair::LoadStoreControl direction);
|
int Remove(uintptr_t addr, size_t size, cpu::DebugRegisterPair::LoadStoreControl direction);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
constexpr WatchpointManager() : HwStopPointManager(MAX_WCR) {}
|
constexpr WatchpointManager() : HwStopPointManager(MAX_WCR, IrqManager::ReloadWatchpointsSgi) {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue