Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Guest reboot support #157

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/arch/armv8/aarch64/inc/arch/subarch/sysregs.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ SYSREG_GEN_ACCESSORS(icc_iar1_el1)
SYSREG_GEN_ACCESSORS(icc_eoir1_el1)
SYSREG_GEN_ACCESSORS(icc_dir_el1)
SYSREG_GEN_ACCESSORS(ich_vtr_el2)
SYSREG_GEN_ACCESSORS(ich_vmcr_el2)
SYSREG_GEN_ACCESSORS(icc_sre_el2)
SYSREG_GEN_ACCESSORS(icc_pmr_el1)
SYSREG_GEN_ACCESSORS(icc_bpr1_el1)
Expand Down
3 changes: 3 additions & 0 deletions src/arch/armv8/gic.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ void gic_init()
void gic_handle()
{
uint32_t ack = gicc_iar();
cpu()->is_handling_irq = true;
cpu()->arch.handling_irq_ack = ack;
irqid_t id = bit32_extract(ack, GICC_IAR_ID_OFF, GICC_IAR_ID_LEN);

if (id < GIC_FIRST_SPECIAL_INTID) {
Expand All @@ -101,6 +103,7 @@ void gic_handle()
gicc_dir(ack);
}
}
cpu()->is_handling_irq = false;
}

uint8_t gicd_get_prio(irqid_t int_id)
Expand Down
1 change: 1 addition & 0 deletions src/arch/armv8/inc/arch/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
struct cpu_arch {
struct cpu_arch_profile profile;
unsigned long mpidr;
unsigned long handling_irq_ack;
};

unsigned long cpu_id_to_mpidr(cpuid_t id);
Expand Down
10 changes: 10 additions & 0 deletions src/arch/armv8/inc/arch/gicv2.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,16 @@ static inline uint64_t gich_get_elrsr()
return elsr;
}

static inline uint32_t gich_get_vmcr()
{
return gich->VMCR;
}

static inline void gich_set_vmcr(uint32_t vmcr)
{
gich->VMCR = vmcr;
}

static inline uint32_t gicc_iar()
{
return gicc->IAR;
Expand Down
10 changes: 10 additions & 0 deletions src/arch/armv8/inc/arch/gicv3.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,16 @@ static inline uint64_t gich_get_elrsr()
return sysreg_ich_elrsr_el2_read();
}

static inline uint32_t gich_get_vmcr()
{
return (uint32_t)sysreg_ich_vmcr_el2_read();
}

static inline void gich_set_vmcr(uint32_t vmcr)
{
sysreg_ich_vmcr_el2_write(vmcr);
}

static inline uint32_t gicc_iar()
{
return (uint32_t)sysreg_icc_iar1_el1_read();
Expand Down
1 change: 1 addition & 0 deletions src/arch/armv8/inc/arch/psci.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#define PSCI_AFFINITY_INFO_SMC64 (0xc4000004)
#define PSCI_FEATURES (0x8400000A)
#define PSCI_MIG_INFO_TYPE (0x84000006)
#define PSCI_SYSTEM_RESET (0x84000009)

#ifdef AARCH32
#define PSCI_CPU_SUSPEND PSCI_CPU_SUSPEND_SMC32
Expand Down
3 changes: 3 additions & 0 deletions src/arch/armv8/inc/arch/vgic.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,4 +126,7 @@ bool vgic_int_has_other_target(struct vcpu* vcpu, struct vgic_int* interrupt);
uint8_t vgic_int_ptarget_mask(struct vcpu* vcpu, struct vgic_int* interrupt);
void vgic_inject_sgi(struct vcpu* vcpu, struct vgic_int* interrupt, vcpuid_t source);

void vgic_reset(struct vm* vm);
void vgic_cpu_reset(struct vcpu* vcpu);

#endif /* __VGIC_H__ */
20 changes: 16 additions & 4 deletions src/arch/armv8/interrupts.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@
#include <cpu.h>
#include <platform.h>
#include <arch/gic.h>
#if (GIC_VERSION == GICV2)
#include <arch/gicv2.h>
#elif (GIC_VERSION == GICV3)
#include <arch/gicv3.h>
#else
#error "unknown GIV version " GIC_VERSION
#endif
#include <mem.h>
#include <arch/sysregs.h>
#include <vm.h>

#ifndef GIC_VERSION
#error "GIC_VERSION not defined for this platform"
#endif

void interrupts_arch_init()
{
gic_init();
Expand Down Expand Up @@ -61,3 +64,12 @@ void interrupts_arch_vm_assign(struct vm* vm, irqid_t id)
{
vgic_set_hw(vm, id);
}

void interrupts_arch_finish()
{
if (cpu()->is_handling_irq) {
gicc_eoir((uint32_t)cpu()->arch.handling_irq_ack);
gicc_dir((uint32_t)cpu()->arch.handling_irq_ack);
cpu()->is_handling_irq = false;
}
}
19 changes: 19 additions & 0 deletions src/arch/armv8/psci.c
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ static int32_t psci_features_handler(uint32_t feature_id)
case PSCI_AFFINITY_INFO_SMC32:
case PSCI_AFFINITY_INFO_SMC64:
case PSCI_FEATURES:
case PSCI_SYSTEM_RESET:
ret = PSCI_E_SUCCESS;
break;
default:
Expand All @@ -187,6 +188,21 @@ static int32_t psci_features_handler(uint32_t feature_id)
return ret;
}

static int32_t psci_reset()
{
// Although the spec mandates this call cannot fail, this might actually happen if Bao did
// not keep a copy of the original guest image around
bool res = PSCI_E_DENIED;

if (vm_reset(cpu()->vcpu->vm)) {
// Note that, if successful, this PSCI call does not actually return. We still "return"
// success to keep the compiler happy.
res = PSCI_E_SUCCESS;
}

return res;
}

int32_t psci_smc_handler(uint32_t smc_fid, unsigned long x1, unsigned long x2, unsigned long x3)
{
int32_t ret = PSCI_E_NOT_SUPPORTED;
Expand Down Expand Up @@ -223,6 +239,9 @@ int32_t psci_smc_handler(uint32_t smc_fid, unsigned long x1, unsigned long x2, u
ret = PSCI_TOS_NOT_PRESENT_MP;
break;

case PSCI_SYSTEM_RESET:
ret = psci_reset();
break;
default:
INFO("unkown psci smc_fid 0x%lx", smc_fid);
}
Expand Down
88 changes: 68 additions & 20 deletions src/arch/armv8/vgicv2.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#include <arch/vgic.h>
#include <arch/vgicv2.h>

#include <arch/gicv2.h>

#include <bit.h>
#include <spinlock.h>
#include <cpu.h>
Expand Down Expand Up @@ -140,6 +142,69 @@ void vgic_inject_sgi(struct vcpu* vcpu, struct vgic_int* interrupt, vcpuid_t sou
spin_unlock(&interrupt->lock);
}

void vgic_cpu_reset(struct vcpu* vcpu)
{
for (irqid_t i = 0; i < GIC_CPU_PRIV; i++) {
vcpu->arch.vgic_priv.interrupts[i].owner = vcpu;
vcpu->arch.vgic_priv.interrupts[i].lock = SPINLOCK_INITVAL;
vcpu->arch.vgic_priv.interrupts[i].state = INV;
vcpu->arch.vgic_priv.interrupts[i].prio = GIC_LOWEST_PRIO;
vcpu->arch.vgic_priv.interrupts[i].cfg = 0;
vcpu->arch.vgic_priv.interrupts[i].sgi.act = 0;
vcpu->arch.vgic_priv.interrupts[i].sgi.pend = 0;
vcpu->arch.vgic_priv.interrupts[i].in_lr = false;
vcpu->arch.vgic_priv.interrupts[i].enabled = false;

if (vcpu->arch.vgic_priv.interrupts[i].hw) {
gic_set_enable(i, false);
gic_set_prio(i, GIC_LOWEST_PRIO);
gic_set_act(i, false);
gic_set_pend(i, false);
}
}

for (irqid_t i = 0; i < GIC_MAX_SGIS; i++) {
vcpu->arch.vgic_priv.interrupts[i].enabled = true;
}

for (size_t i = 0; i < gich_num_lrs(); i++) {
gich_write_lr(i, 0);
}

// gich_set_hcr(0);
gich_set_vmcr(0);
// TODO: reset gich apr registers

list_init(&vcpu->arch.vgic_spilled);
}

void vgic_reset(struct vm* vm)
{
for (irqid_t i = 0; i < vm->arch.vgicd.int_num; i++) {
vm->arch.vgicd.interrupts[i].owner = NULL;
vm->arch.vgicd.interrupts[i].lock = SPINLOCK_INITVAL;
vm->arch.vgicd.interrupts[i].state = INV;
vm->arch.vgicd.interrupts[i].prio = GIC_LOWEST_PRIO;
vm->arch.vgicd.interrupts[i].cfg = 0;
vm->arch.vgicd.interrupts[i].targets = 0;
vm->arch.vgicd.interrupts[i].in_lr = false;
vm->arch.vgicd.interrupts[i].enabled = false;

if (vm->arch.vgicd.interrupts[i].hw) {
irqid_t id = vm->arch.vgicd.interrupts[i].id;
gic_set_enable(id, false);
gic_set_prio(id, GIC_LOWEST_PRIO);
gic_set_act(id, false);
gic_set_pend(id, false);
}
}

vm->arch.vgicd.CTLR = 0;

list_init(&vm->arch.vgic_spilled);
vm->arch.vgic_spilled_lock = SPINLOCK_INITVAL;
}

void vgic_init(struct vm* vm, const struct vgic_dscrp* vgic_dscrp)
{
vm->arch.vgicd.CTLR = 0;
Expand All @@ -160,46 +225,29 @@ void vgic_init(struct vm* vm, const struct vgic_dscrp* vgic_dscrp)
}

for (irqid_t i = 0; i < vm->arch.vgicd.int_num; i++) {
vm->arch.vgicd.interrupts[i].owner = NULL;
vm->arch.vgicd.interrupts[i].lock = SPINLOCK_INITVAL;
vm->arch.vgicd.interrupts[i].id = i + GIC_CPU_PRIV;
vm->arch.vgicd.interrupts[i].state = INV;
vm->arch.vgicd.interrupts[i].prio = GIC_LOWEST_PRIO;
vm->arch.vgicd.interrupts[i].cfg = 0;
vm->arch.vgicd.interrupts[i].targets = 0;
vm->arch.vgicd.interrupts[i].hw = false;
vm->arch.vgicd.interrupts[i].in_lr = false;
vm->arch.vgicd.interrupts[i].enabled = false;
}

vm->arch.vgicd_emul = (struct emul_mem){ .va_base = vgic_dscrp->gicd_addr,
.size = ALIGN(sizeof(struct gicd_hw), PAGE_SIZE),
.handler = vgicd_emul_handler };
vm_emul_add_mem(vm, &vm->arch.vgicd_emul);

list_init(&vm->arch.vgic_spilled);
vm->arch.vgic_spilled_lock = SPINLOCK_INITVAL;
vgic_reset(vm);
}

void vgic_cpu_init(struct vcpu* vcpu)
{
for (irqid_t i = 0; i < GIC_CPU_PRIV; i++) {
vcpu->arch.vgic_priv.interrupts[i].owner = vcpu;
vcpu->arch.vgic_priv.interrupts[i].lock = SPINLOCK_INITVAL;
vcpu->arch.vgic_priv.interrupts[i].id = i;
vcpu->arch.vgic_priv.interrupts[i].state = INV;
vcpu->arch.vgic_priv.interrupts[i].prio = GIC_LOWEST_PRIO;
vcpu->arch.vgic_priv.interrupts[i].cfg = 0;
vcpu->arch.vgic_priv.interrupts[i].sgi.act = 0;
vcpu->arch.vgic_priv.interrupts[i].sgi.pend = 0;
vcpu->arch.vgic_priv.interrupts[i].hw = false;
vcpu->arch.vgic_priv.interrupts[i].in_lr = false;
vcpu->arch.vgic_priv.interrupts[i].enabled = false;
vcpu->arch.vgic_priv.interrupts[i].targets = (uint8_t)(1UL << cpu()->id);
}

for (size_t i = 0; i < GIC_MAX_SGIS; i++) {
vcpu->arch.vgic_priv.interrupts[i].enabled = true;
}

list_init(&vcpu->arch.vgic_spilled);
vgic_cpu_reset(vcpu);
}
Loading
Loading