mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-11-15 00:16:48 +00:00
vgic: fix multiple bugs
This commit is contained in:
parent
f3ad62d1b8
commit
fe0662a75d
2 changed files with 40 additions and 6 deletions
|
@ -99,7 +99,7 @@ typedef struct ArmGicV2MaintenanceIntStatRegister {
|
||||||
} ArmGicV2MaintenanceIntStatRegister;
|
} ArmGicV2MaintenanceIntStatRegister;
|
||||||
|
|
||||||
typedef struct ArmGicV2ListRegister {
|
typedef struct ArmGicV2ListRegister {
|
||||||
u32 virtualId : 9;
|
u32 virtualId : 10;
|
||||||
u32 physicalId : 10; // note: different encoding if hw = 0 (can't represent it in struct)
|
u32 physicalId : 10; // note: different encoding if hw = 0 (can't represent it in struct)
|
||||||
u32 sbz2 : 3;
|
u32 sbz2 : 3;
|
||||||
u32 priority : 5;
|
u32 priority : 5;
|
||||||
|
|
|
@ -735,7 +735,7 @@ static inline volatile ArmGicV2ListRegister *vgicGetFreeListRegister(void)
|
||||||
|
|
||||||
static void vgicPushListRegisters(VirqState *chosen[], size_t num)
|
static void vgicPushListRegisters(VirqState *chosen[], size_t num)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < num; num++) {
|
for (size_t i = 0; i < num; i++) {
|
||||||
VirqState *state = chosen[i];
|
VirqState *state = chosen[i];
|
||||||
u16 irqId = vgicGetVirqStateInterruptId(state);
|
u16 irqId = vgicGetVirqStateInterruptId(state);
|
||||||
|
|
||||||
|
@ -820,19 +820,29 @@ void vgicUpdateState(void)
|
||||||
|
|
||||||
// Choose interrupts...
|
// Choose interrupts...
|
||||||
newHiPrio = vgicChoosePendingInterrupts(&numChosen, chosen, numFreeLr);
|
newHiPrio = vgicChoosePendingInterrupts(&numChosen, chosen, numFreeLr);
|
||||||
|
(void)newHiPrio;
|
||||||
|
|
||||||
// ...and push them
|
// ...and push them
|
||||||
for (size_t i = 0; i < numChosen; i++) {
|
for (size_t i = 0; i < numChosen; i++) {
|
||||||
vgicPushListRegisters(chosen, numChosen);
|
vgicPushListRegisters(chosen, numChosen);
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
// Raise vIRQ when applicable. We only need to check for the highest priority
|
// Raise vIRQ when applicable. We only need to check for the highest priority
|
||||||
// TRM: "The GIC always masks an interrupt that has the largest supported priority field value.
|
// TRM: "The GIC always masks an interrupt that has the largest supported priority field value.
|
||||||
// This provides an additional means of preventing an interrupt being signaled to any processor"
|
// This provides an additional means of preventing an interrupt being signaled to any processor"
|
||||||
if (newHiPrio < 0x1F && vgicIsInterruptRaisable(newHiPrio)) {
|
if (false && newHiPrio < 0x1F && vgicIsInterruptRaisable(newHiPrio)) {
|
||||||
|
DEBUG("enablegrp0 %d\n", (int)gich->vmcr.enableGrp0);
|
||||||
|
DEBUG("enablegrp1 %d\n", (int)gich->vmcr.enableGrp1);
|
||||||
|
gich->hcr.npie = true;
|
||||||
u32 hcr = GET_SYSREG(hcr_el2);
|
u32 hcr = GET_SYSREG(hcr_el2);
|
||||||
SET_SYSREG(hcr_el2, hcr | HCR_VI);
|
SET_SYSREG(hcr_el2, hcr | HCR_VI);
|
||||||
|
} else {
|
||||||
|
//DEBUG("unraising\n");
|
||||||
|
gich->hcr.npie = false;
|
||||||
|
u32 hcr = GET_SYSREG(hcr_el2);
|
||||||
|
SET_SYSREG(hcr_el2, hcr & ~HCR_VI);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// Enable underflow interrupt when appropriate to do so
|
// Enable underflow interrupt when appropriate to do so
|
||||||
if (vgicGetNumberOfFreeListRegisters() != g_irqManager.numListRegisters) {
|
if (vgicGetNumberOfFreeListRegisters() != g_irqManager.numListRegisters) {
|
||||||
|
@ -844,13 +854,28 @@ void vgicUpdateState(void)
|
||||||
|
|
||||||
void vgicMaintenanceInterruptHandler(void)
|
void vgicMaintenanceInterruptHandler(void)
|
||||||
{
|
{
|
||||||
ArmGicV2MaintenanceIntStatRegister misr = g_irqManager.gic.gich->misr;
|
volatile ArmGicV2VirtualInterfaceController *gich = g_irqManager.gic.gich;
|
||||||
|
|
||||||
|
ArmGicV2MaintenanceIntStatRegister misr = g_irqManager.gic.gich->misr;
|
||||||
|
DEBUG("maintenance\n");
|
||||||
// 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
|
||||||
|
// Ensure we aren't spammed by maintenance interrupts, either.
|
||||||
if (misr.vgrp0e || misr.vgrp0d || misr.vgrp1e || misr.vgrp1d) {
|
if (misr.vgrp0e || misr.vgrp0d || misr.vgrp1e || misr.vgrp1d) {
|
||||||
g_irqManager.gic.gicv->ctlr &= BIT(9) | BIT(0);
|
g_irqManager.gic.gicv->ctlr &= BIT(9) | BIT(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (misr.vgrp0e) {
|
||||||
|
gich->hcr.vgrp0eie = false;
|
||||||
|
gich->hcr.vgrp0die = true;
|
||||||
|
} else if (misr.vgrp0d) {
|
||||||
|
gich->hcr.vgrp0eie = true;
|
||||||
|
gich->hcr.vgrp0die = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (misr.vgrp1e) {
|
||||||
|
// Nothing to do since we unset the bit asap
|
||||||
|
}
|
||||||
|
|
||||||
if (misr.lrenp) {
|
if (misr.lrenp) {
|
||||||
DEBUG("VGIC: List Register Entry Not Present maintenance interrupt!");
|
DEBUG("VGIC: List Register Entry Not Present maintenance interrupt!");
|
||||||
panic();
|
panic();
|
||||||
|
@ -858,6 +883,7 @@ void vgicMaintenanceInterruptHandler(void)
|
||||||
|
|
||||||
// The rest should be handled by the main loop...
|
// The rest should be handled by the main loop...
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleVgicdMmio(ExceptionStackFrame *frame, DataAbortIss dabtIss, size_t offset)
|
void handleVgicdMmio(ExceptionStackFrame *frame, DataAbortIss dabtIss, size_t offset)
|
||||||
{
|
{
|
||||||
size_t sz = BITL(dabtIss.sas);
|
size_t sz = BITL(dabtIss.sas);
|
||||||
|
@ -918,5 +944,13 @@ void vgicInit(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
g_irqManager.gic.gich->hcr.en = true;
|
// Deassert vIRQ line, just in case
|
||||||
|
// Enable a few maintenance interrupts
|
||||||
|
ArmGicV2HypervisorControlRegister hcr = {
|
||||||
|
.vgrp1eie = true,
|
||||||
|
.vgrp0eie = true,
|
||||||
|
.lrenpie = true,
|
||||||
|
.en = true,
|
||||||
|
};
|
||||||
|
g_irqManager.gic.gich->hcr = hcr;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue