mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 12:21:18 +00:00
thermosphere: trap refactor WIP
This commit is contained in:
parent
874d1432be
commit
797cea0ac8
18 changed files with 311 additions and 284 deletions
|
@ -101,7 +101,7 @@ namespace ams::hvisor::cpu {
|
||||||
|
|
||||||
constexpr bool HasValidFar()
|
constexpr bool HasValidFar()
|
||||||
{
|
{
|
||||||
return isv && fnv;
|
return isv && !fnv;
|
||||||
}
|
}
|
||||||
constexpr size_t GetAccessSize()
|
constexpr size_t GetAccessSize()
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,68 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "data_abort.h"
|
|
||||||
#include "sysreg.h"
|
|
||||||
#include "debug_log.h"
|
|
||||||
#include "irq.h"
|
|
||||||
#include "vgic.h"
|
|
||||||
|
|
||||||
// Lower el
|
|
||||||
|
|
||||||
void dumpUnhandledDataAbort(DataAbortIss dabtIss, u64 far, const char *msg)
|
|
||||||
{
|
|
||||||
char s1[64], s2[32], s3[64] = "";
|
|
||||||
(void)s1; (void)s2; (void)s3;
|
|
||||||
sprintf(s1, "Unhandled%s %s", msg , dabtIss.wnr ? "write" : "read");
|
|
||||||
if (dabtIss.fnv) {
|
|
||||||
sprintf(s2, "<unk>");
|
|
||||||
} else {
|
|
||||||
sprintf(s2, "%016lx", far);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dabtIss.isv) {
|
|
||||||
sprintf(s3, ", size %u Rt=%u", BIT(dabtIss.sas), dabtIss.srt);
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG("%s at %s%s\n", s1, s2, s3);
|
|
||||||
}
|
|
||||||
|
|
||||||
void handleLowerElDataAbortException(ExceptionStackFrame *frame, ExceptionSyndromeRegister esr)
|
|
||||||
{
|
|
||||||
DataAbortIss dabtIss;
|
|
||||||
u32 iss = esr.iss;
|
|
||||||
memcpy(&dabtIss, &iss, 4);
|
|
||||||
|
|
||||||
u64 far = GET_SYSREG(far_el2);
|
|
||||||
u64 farpg = far & ~0xFFFull;
|
|
||||||
|
|
||||||
if (!dabtIss.isv || dabtIss.fnv) {
|
|
||||||
dumpUnhandledDataAbort(dabtIss, far, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (farpg == MEMORY_MAP_PA_GICD) {
|
|
||||||
handleVgicdMmio(frame, dabtIss, far & 0xFFF);
|
|
||||||
} else if (farpg == MEMORY_MAP_PA_GICH) {
|
|
||||||
dumpUnhandledDataAbort(dabtIss, far, " GICH");
|
|
||||||
} else {
|
|
||||||
dumpUnhandledDataAbort(dabtIss, far, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip instruction anyway
|
|
||||||
skipFaultingInstruction(frame, esr.il == 0 ? 2 : 4);
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019 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 "exceptions.h"
|
|
||||||
|
|
||||||
typedef struct DataAbortIss {
|
|
||||||
u32 dfsc : 6; // Fault status code
|
|
||||||
|
|
||||||
u32 wnr : 1; // Write, not Read
|
|
||||||
u32 s1ptw : 1; // Stage1 page table walk fault
|
|
||||||
u32 cm : 1; // Cache maintenance
|
|
||||||
u32 ea : 1; // External abort
|
|
||||||
u32 fnv : 1; // FAR not Valid
|
|
||||||
u32 set : 2; // Synchronous error type
|
|
||||||
u32 vncr : 1; // vncr_el2 trap
|
|
||||||
|
|
||||||
u32 ar : 1; // Acquire/release. Bit 14
|
|
||||||
u32 sf : 1; // 64-bit register used
|
|
||||||
u32 srt : 5; // Syndrome register transfer (register used)
|
|
||||||
u32 sse : 1; // Syndrome sign extend
|
|
||||||
u32 sas : 2; // Syndrome access size. Bit 23
|
|
||||||
|
|
||||||
u32 isv : 1; // Instruction syndrome valid (ISS[23:14] valid)
|
|
||||||
} DataAbortIss;
|
|
||||||
|
|
||||||
void dumpUnhandledDataAbort(DataAbortIss dabtIss, u64 far, const char *msg);
|
|
||||||
void handleLowerElDataAbortException(ExceptionStackFrame *frame, ExceptionSyndromeRegister esr);
|
|
|
@ -21,51 +21,6 @@
|
||||||
|
|
||||||
#include "debug_manager.h"
|
#include "debug_manager.h"
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
void DumpStackFrame(const ams::hvisor::ExceptionStackFrame *frame, bool sameEl)
|
|
||||||
{
|
|
||||||
#ifndef NDEBUG
|
|
||||||
uintptr_t stackTop = memoryMapGetStackTop(ams::hvisor::currentCoreCtx->GetCoreId());
|
|
||||||
|
|
||||||
for (u32 i = 0; i < 30; i += 2) {
|
|
||||||
DEBUG("x%u\t\t%016llx\t\tx%u\t\t%016llx\n", i, frame->x[i], i + 1, frame->x[i + 1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG("x30\t\t%016llx\n\n", frame->x[30]);
|
|
||||||
DEBUG("elr_el2\t\t%016llx\n", frame->elr_el2);
|
|
||||||
DEBUG("spsr_el2\t%016llx\n", frame->spsr_el2);
|
|
||||||
DEBUG("far_el2\t\t%016llx\n", frame->far_el2);
|
|
||||||
if (sameEl) {
|
|
||||||
DEBUG("sp_el2\t\t%016llx\n", frame->sp_el2);
|
|
||||||
} else {
|
|
||||||
DEBUG("sp_el1\t\t%016llx\n", frame->sp_el1);
|
|
||||||
}
|
|
||||||
DEBUG("sp_el0\t\t%016llx\n", frame->sp_el0);
|
|
||||||
DEBUG("cntpct_el0\t%016llx\n", frame->cntpct_el0);
|
|
||||||
if (frame == ams::hvisor::currentCoreCtx->GetGuestFrame()) {
|
|
||||||
DEBUG("cntp_ctl_el0\t%016llx\n", frame->cntp_ctl_el0);
|
|
||||||
DEBUG("cntv_ctl_el0\t%016llx\n", frame->cntv_ctl_el0);
|
|
||||||
} else if ((frame->sp_el2 & ~0xFFFul) + 0x1000 == stackTop) {
|
|
||||||
// Try to dump the stack (comment if this crashes)
|
|
||||||
u64 *sp = (u64 *)frame->sp_el2;
|
|
||||||
u64 *spEnd = sp + 0x20;
|
|
||||||
u64 *spMax = reinterpret_cast<u64 *>((frame->sp_el2 + 0xFFF) & ~0xFFFul);
|
|
||||||
DEBUG("Stack trace:\n");
|
|
||||||
while (sp < spEnd && sp < spMax) {
|
|
||||||
DEBUG("\t%016lx\n", *sp++);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
DEBUG("Stack overflow/double fault detected!\n");
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
(void)frame;
|
|
||||||
(void)sameEl;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace ams::hvisor {
|
namespace ams::hvisor {
|
||||||
|
|
||||||
void EnableGeneralTraps(void)
|
void EnableGeneralTraps(void)
|
||||||
|
@ -89,6 +44,47 @@ namespace ams::hvisor {
|
||||||
EnableGuestTimerTraps();
|
EnableGuestTimerTraps();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DumpStackFrame(ExceptionStackFrame *frame, bool sameEl)
|
||||||
|
{
|
||||||
|
#ifndef NDEBUG
|
||||||
|
uintptr_t stackTop = memoryMapGetStackTop(currentCoreCtx->GetCoreId());
|
||||||
|
|
||||||
|
for (u32 i = 0; i < 30; i += 2) {
|
||||||
|
DEBUG("x%u\t\t%016llx\t\tx%u\t\t%016llx\n", i, frame->x[i], i + 1, frame->x[i + 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG("x30\t\t%016llx\n\n", frame->x[30]);
|
||||||
|
DEBUG("elr_el2\t\t%016llx\n", frame->elr_el2);
|
||||||
|
DEBUG("spsr_el2\t%016llx\n", frame->spsr_el2);
|
||||||
|
DEBUG("far_el2\t\t%016llx\n", frame->far_el2);
|
||||||
|
if (sameEl) {
|
||||||
|
DEBUG("sp_el2\t\t%016llx\n", frame->sp_el2);
|
||||||
|
} else {
|
||||||
|
DEBUG("sp_el1\t\t%016llx\n", frame->sp_el1);
|
||||||
|
}
|
||||||
|
DEBUG("sp_el0\t\t%016llx\n", frame->sp_el0);
|
||||||
|
DEBUG("cntpct_el0\t%016llx\n", frame->cntpct_el0);
|
||||||
|
if (frame == currentCoreCtx->GetGuestFrame()) {
|
||||||
|
DEBUG("cntp_ctl_el0\t%016llx\n", frame->cntp_ctl_el0);
|
||||||
|
DEBUG("cntv_ctl_el0\t%016llx\n", frame->cntv_ctl_el0);
|
||||||
|
} else if ((frame->sp_el2 & ~0xFFFul) + 0x1000 == stackTop) {
|
||||||
|
// Try to dump the stack (comment if this crashes)
|
||||||
|
u64 *sp = (u64 *)frame->sp_el2;
|
||||||
|
u64 *spEnd = sp + 0x20;
|
||||||
|
u64 *spMax = reinterpret_cast<u64 *>((frame->sp_el2 + 0xFFF) & ~0xFFFul);
|
||||||
|
DEBUG("Stack trace:\n");
|
||||||
|
while (sp < spEnd && sp < spMax) {
|
||||||
|
DEBUG("\t%016lx\n", *sp++);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
DEBUG("Stack overflow/double fault detected!\n");
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
(void)frame;
|
||||||
|
(void)sameEl;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void ExceptionEntryPostprocess(ExceptionStackFrame *frame, bool isLowerEl)
|
void ExceptionEntryPostprocess(ExceptionStackFrame *frame, bool isLowerEl)
|
||||||
{
|
{
|
||||||
if (frame == currentCoreCtx->GetGuestFrame()) {
|
if (frame == currentCoreCtx->GetGuestFrame()) {
|
||||||
|
|
|
@ -23,6 +23,8 @@ namespace ams::hvisor {
|
||||||
|
|
||||||
void EnableGeneralTraps(void);
|
void EnableGeneralTraps(void);
|
||||||
|
|
||||||
|
void DumpStackFrame(const ExceptionStackFrame *frame, bool sameEl);
|
||||||
|
|
||||||
// Called on exception entry (avoids overflowing a vector section)
|
// Called on exception entry (avoids overflowing a vector section)
|
||||||
void ExceptionEntryPostprocess(ExceptionStackFrame *frame, bool isLowerEl);
|
void ExceptionEntryPostprocess(ExceptionStackFrame *frame, bool isLowerEl);
|
||||||
|
|
||||||
|
|
|
@ -369,6 +369,9 @@ namespace ams::hvisor {
|
||||||
private:
|
private:
|
||||||
constexpr VirtualGic() = default;
|
constexpr VirtualGic() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// For convenience (when trapping lower-el data aborts):
|
||||||
|
static constexpr uintptr_t gicdPhysicalAddress = 0; // fixme pls MEMORY_MAP_PA_GICD;
|
||||||
public:
|
public:
|
||||||
static bool ValidateGicdRegisterAccess(size_t offset, size_t sz);
|
static bool ValidateGicdRegisterAccess(size_t offset, size_t sz);
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -1,78 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "single_step.h"
|
|
||||||
#include "core_ctx.h"
|
|
||||||
#include "sysreg.h"
|
|
||||||
#include "debug_manager.h"
|
|
||||||
|
|
||||||
SingleStepState singleStepGetNextState(ExceptionStackFrame *frame)
|
|
||||||
{
|
|
||||||
u64 mdscr = GET_SYSREG(mdscr_el1);
|
|
||||||
bool mdscrSS = (mdscr & MDSCR_SS) != 0;
|
|
||||||
bool pstateSS = (frame->spsr_el2 & PSTATE_SS) != 0;
|
|
||||||
|
|
||||||
if (!mdscrSS) {
|
|
||||||
return SingleStepState_Inactive;
|
|
||||||
} else {
|
|
||||||
return pstateSS ? SingleStepState_ActiveNotPending : SingleStepState_ActivePending;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void singleStepSetNextState(ExceptionStackFrame *frame, SingleStepState state)
|
|
||||||
{
|
|
||||||
u64 mdscr = GET_SYSREG(mdscr_el1);
|
|
||||||
|
|
||||||
switch (state) {
|
|
||||||
case SingleStepState_Inactive:
|
|
||||||
// Unset mdscr_el1.ss
|
|
||||||
mdscr &= ~MDSCR_SS;
|
|
||||||
break;
|
|
||||||
case SingleStepState_ActiveNotPending:
|
|
||||||
// Set mdscr_el1.ss and pstate.ss
|
|
||||||
mdscr |= MDSCR_SS;
|
|
||||||
frame->spsr_el2 |= PSTATE_SS;
|
|
||||||
break;
|
|
||||||
case SingleStepState_ActivePending:
|
|
||||||
// We never use this because pstate.ss is 0 by default...
|
|
||||||
// Set mdscr_el1.ss and unset pstate.ss
|
|
||||||
mdscr |= MDSCR_SS;
|
|
||||||
frame->spsr_el2 &= ~PSTATE_SS;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
SET_SYSREG(mdscr_el1, mdscr);
|
|
||||||
__isb(); // TRM-mandated
|
|
||||||
}
|
|
||||||
|
|
||||||
void handleSingleStep(ExceptionStackFrame *frame, ExceptionSyndromeRegister esr)
|
|
||||||
{
|
|
||||||
uintptr_t addr = frame->elr_el2;
|
|
||||||
|
|
||||||
// Stepping range support;
|
|
||||||
if (addr >= currentCoreCtx->steppingRangeStartAddr && addr < currentCoreCtx->steppingRangeEndAddr) {
|
|
||||||
// Reactivate single-step
|
|
||||||
singleStepSetNextState(frame, SingleStepState_ActiveNotPending);
|
|
||||||
} else {
|
|
||||||
// Disable single-step
|
|
||||||
singleStepSetNextState(frame, SingleStepState_Inactive);
|
|
||||||
debugManagerReportEvent(DBGEVENT_EXCEPTION);
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG("Single-step exeception ELR = 0x%016llx, ISV = %u, EX = %u\n", frame->elr_el2, (esr.iss >> 24) & 1, (esr.iss >> 6) & 1);
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019 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 "utils.h"
|
|
||||||
#include "exceptions.h"
|
|
||||||
|
|
||||||
typedef enum SingleStepState {
|
|
||||||
SingleStepState_Inactive = 0, // Single step disabled OR in the debugger
|
|
||||||
SingleStepState_ActiveNotPending = 1, // Instruction not yet executed
|
|
||||||
SingleStepState_ActivePending = 2, // Instruction executed or return-from-trap, single-step exception is going to be generated soon
|
|
||||||
} SingleStepState;
|
|
||||||
|
|
||||||
/// Get the single-step state machine state (state after eret)
|
|
||||||
SingleStepState singleStepGetNextState(ExceptionStackFrame *frame);
|
|
||||||
|
|
||||||
/// Set the single-step state machine state (state after eret). Frame can be NULL iff new state is "inactive"
|
|
||||||
void singleStepSetNextState(ExceptionStackFrame *frame, SingleStepState state);
|
|
||||||
|
|
||||||
void handleSingleStep(ExceptionStackFrame *frame, ExceptionSyndromeRegister esr);
|
|
89
thermosphere/src/traps/hvisor_traps_data_abort.cpp
Normal file
89
thermosphere/src/traps/hvisor_traps_data_abort.cpp
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "hvisor_traps_data_abort.hpp"
|
||||||
|
|
||||||
|
#include "../hvisor_virtual_gic.hpp"
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include "../hvisor_core_context.hpp"
|
||||||
|
#include "../cpu/hvisor_cpu_sysreg_general.hpp"
|
||||||
|
#include "../cpu/hvisor_cpu_instructions.hpp"
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Lower el
|
||||||
|
|
||||||
|
namespace ams::hvisor::traps {
|
||||||
|
|
||||||
|
void DumpUnhandledDataAbort(cpu::DataAbortIss dabtIss, u64 far, const char *msg)
|
||||||
|
{
|
||||||
|
char s1[64], s2[32], s3[64] = "";
|
||||||
|
static_cast<void>(s1);
|
||||||
|
static_cast<void>(s2);
|
||||||
|
static_cast<void>(s3);
|
||||||
|
sprintf(s1, "Unhandled%s %s", msg , dabtIss.wnr ? "write" : "read");
|
||||||
|
if (dabtIss.fnv) {
|
||||||
|
sprintf(s2, "<unk>");
|
||||||
|
} else {
|
||||||
|
sprintf(s2, "%016lx", far);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dabtIss.isv) {
|
||||||
|
sprintf(s3, ", size %u Rt=%u", BIT(dabtIss.sas), dabtIss.srt);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG("%s at %s%s\n", s1, s2, s3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleLowerElDataAbortException(ExceptionStackFrame *frame, cpu::ExceptionSyndromeRegister esr)
|
||||||
|
{
|
||||||
|
cpu::DataAbortIss dabtIss;
|
||||||
|
u32 iss = esr.iss;
|
||||||
|
std::memcpy(&iss, &dabtIss, 4);
|
||||||
|
|
||||||
|
u64 far = frame->far_el2;
|
||||||
|
u64 farpg = far & ~0xFFFull;
|
||||||
|
size_t off = far & 0xFFF;
|
||||||
|
size_t sz = dabtIss.GetAccessSize();
|
||||||
|
|
||||||
|
// We don't support 8-byte writes for MMIO
|
||||||
|
if (!dabtIss.HasValidFar() || sz > 4) {
|
||||||
|
DumpUnhandledDataAbort(dabtIss, far, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (farpg == VirtualGic::gicdPhysicalAddress) {
|
||||||
|
if (VirtualGic::ValidateGicdRegisterAccess(off, sz)) {
|
||||||
|
if (dabtIss.wnr) {
|
||||||
|
// Register write
|
||||||
|
u32 reg = frame->ReadFrameRegister<u32>(dabtIss.srt);
|
||||||
|
VirtualGic::GetInstance().WriteGicdRegister(reg, off, sz);
|
||||||
|
} else {
|
||||||
|
// Reigster read
|
||||||
|
frame->WriteFrameRegister(dabtIss.srt, VirtualGic::GetInstance().ReadGicdRegister(off, sz));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Invalid GICD access
|
||||||
|
DumpUnhandledDataAbort(dabtIss, far, "GICD");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
DumpUnhandledDataAbort(dabtIss, far, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip instruction anyway
|
||||||
|
frame->SkipInstruction(esr.il == 0 ? 2 : 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019 Atmosphère-NX
|
* Copyright (c) 2019-2020 Atmosphère-NX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
@ -14,16 +14,13 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "hvc.h"
|
#pragma once
|
||||||
#include "debug_log.h"
|
|
||||||
|
|
||||||
void handleHypercall(ExceptionStackFrame *frame, ExceptionSyndromeRegister esr)
|
#include "../hvisor_exception_stack_frame.hpp"
|
||||||
{
|
|
||||||
u32 id = esr.iss;
|
namespace ams::hvisor::traps {
|
||||||
switch (id) {
|
|
||||||
default:
|
void DumpUnhandledDataAbort(cpu::DataAbortIss dabtIss, u64 far, const char *msg);
|
||||||
DEBUG("Unhandled hypercall: 0x%x.\n");
|
void HandleLowerElDataAbort(ExceptionStackFrame *frame, cpu::ExceptionSyndromeRegister esr);
|
||||||
dumpStackFrame(frame, false);
|
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
}
|
|
33
thermosphere/src/traps/hvisor_traps_hvc.cpp
Normal file
33
thermosphere/src/traps/hvisor_traps_hvc.cpp
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "hvisor_traps_hvc.hpp"
|
||||||
|
#include "../hvisor_exception_dispatcher.hpp"
|
||||||
|
|
||||||
|
namespace ams::hvisor::traps {
|
||||||
|
|
||||||
|
void HandleHypercall(ExceptionStackFrame *frame, cpu::ExceptionSyndromeRegister esr)
|
||||||
|
{
|
||||||
|
u32 id = esr.iss;
|
||||||
|
switch (id) {
|
||||||
|
default:
|
||||||
|
DEBUG("Unhandled hypercall: 0x%x.\n");
|
||||||
|
DumpStackFrame(frame, false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019 Atmosphère-NX
|
* Copyright (c) 2019-2020 Atmosphère-NX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
@ -15,6 +15,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "exceptions.h"
|
|
||||||
|
|
||||||
void handleHypercall(ExceptionStackFrame *frame, ExceptionSyndromeRegister esr);
|
#include "../hvisor_exception_stack_frame.hpp"
|
||||||
|
|
||||||
|
namespace ams::hvisor::traps {
|
||||||
|
|
||||||
|
void HandleHypercall(ExceptionStackFrame *frame, cpu::ExceptionSyndromeRegister esr);
|
||||||
|
|
||||||
|
}
|
87
thermosphere/src/traps/hvisor_traps_single_step.cpp
Normal file
87
thermosphere/src/traps/hvisor_traps_single_step.cpp
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "hvisor_traps_single_step.hpp"
|
||||||
|
|
||||||
|
#include "../hvisor_core_context.hpp"
|
||||||
|
#include "../cpu/hvisor_cpu_sysreg_general.hpp"
|
||||||
|
#include "../cpu/hvisor_cpu_instructions.hpp"
|
||||||
|
|
||||||
|
#include "../debug_manager.h"
|
||||||
|
|
||||||
|
namespace ams::hvisor::traps {
|
||||||
|
|
||||||
|
SingleStepState GetNextSingleStepState(ExceptionStackFrame *frame)
|
||||||
|
{
|
||||||
|
u64 mdscr = THERMOSPHERE_GET_SYSREG(mdscr_el1);
|
||||||
|
bool mdscrSS = (mdscr & cpu::MDSCR_SS) != 0;
|
||||||
|
bool pstateSS = (frame->spsr_el2 & cpu::PSR_SS) != 0;
|
||||||
|
|
||||||
|
if (!mdscrSS) {
|
||||||
|
return SingleStepState::Inactive;
|
||||||
|
} else {
|
||||||
|
return pstateSS ? SingleStepState::ActiveNotPending : SingleStepState::ActivePending;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetNextSingleStepState(ExceptionStackFrame *frame, SingleStepState state)
|
||||||
|
{
|
||||||
|
u64 mdscr = THERMOSPHERE_GET_SYSREG(mdscr_el1);
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case SingleStepState::Inactive:
|
||||||
|
// Unset mdscr_el1.ss
|
||||||
|
mdscr &= ~cpu::MDSCR_SS;
|
||||||
|
break;
|
||||||
|
case SingleStepState::ActiveNotPending:
|
||||||
|
// Set mdscr_el1.ss and pstate.ss
|
||||||
|
mdscr |= cpu::MDSCR_SS;
|
||||||
|
frame->spsr_el2 |= cpu::PSR_SS;
|
||||||
|
break;
|
||||||
|
case SingleStepState::ActivePending:
|
||||||
|
// We never use this because pstate.ss is 0 by default...
|
||||||
|
// Set mdscr_el1.ss and unset pstate.ss
|
||||||
|
mdscr |= cpu::MDSCR_SS;
|
||||||
|
frame->spsr_el2 &= cpu::PSR_SS;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
THERMOSPHERE_SET_SYSREG(mdscr_el1, mdscr);
|
||||||
|
cpu::isb(); // TRM-mandated
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleSingleStep(ExceptionStackFrame *frame, cpu::ExceptionSyndromeRegister esr)
|
||||||
|
{
|
||||||
|
uintptr_t addr = frame->elr_el2;
|
||||||
|
|
||||||
|
// Stepping range support;
|
||||||
|
auto [startAddr, endAddr] = currentCoreCtx->GetSteppingRange();
|
||||||
|
if (addr >= startAddr && addr < endAddr) {
|
||||||
|
// Reactivate single-step
|
||||||
|
SetNextSingleStepState(frame, SingleStepState::ActiveNotPending);
|
||||||
|
} else {
|
||||||
|
// Disable single-step
|
||||||
|
SetNextSingleStepState(frame, SingleStepState::Inactive);
|
||||||
|
debugManagerReportEvent(DBGEVENT_EXCEPTION);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG("Single-step exeception ELR = 0x%016llx, ISV = %u, EX = %u\n", frame->elr_el2, (esr.iss >> 24) & 1, (esr.iss >> 6) & 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
37
thermosphere/src/traps/hvisor_traps_single_step.hpp
Normal file
37
thermosphere/src/traps/hvisor_traps_single_step.hpp
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* 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 "../hvisor_exception_stack_frame.hpp"
|
||||||
|
|
||||||
|
namespace ams::hvisor::traps {
|
||||||
|
|
||||||
|
enum class SingleStepState {
|
||||||
|
Inactive = 0, /// Single step disabled OR in the debugger
|
||||||
|
ActiveNotPending = 1, /// Instruction not yet executed
|
||||||
|
ActivePending = 2, /// Instruction executed or return-from-trap, single-step exception is going to be generated soon
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Get the single-step state machine state (state after eret)
|
||||||
|
SingleStepState GetNextSingleStepState(ExceptionStackFrame *frame);
|
||||||
|
|
||||||
|
/// Set the single-step state machine state (state after eret). Frame can be nullptr iff new state is "inactive"
|
||||||
|
void SetNextSingleStepState(ExceptionStackFrame *frame, SingleStepState state);
|
||||||
|
|
||||||
|
void HandleSingleStep(ExceptionStackFrame *frame, cpu::ExceptionSyndromeRegister esr);
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue