Skip to content

Commit

Permalink
hvf: arm: Add support for GICv3
Browse files Browse the repository at this point in the history
We currently only support GICv2 emulation. To also support GICv3, we will
need to pass a few system registers into their respective handler functions.

This patch adds handling for all of the required system registers, so that
we can run with more than 8 vCPUs.

Signed-off-by: Alexander Graf <[email protected]>
Message-Id: <[email protected]>
  • Loading branch information
agraf authored and osy committed Dec 8, 2020
1 parent 5233199 commit 222130c
Showing 1 changed file with 141 additions and 0 deletions.
141 changes: 141 additions & 0 deletions target/arm/hvf/hvf.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

#include "exec/address-spaces.h"
#include "hw/irq.h"
#include "hw/intc/gicv3_internal.h"
#include "qemu/main-loop.h"
#include "sysemu/accel.h"
#include "sysemu/cpus.h"
Expand All @@ -46,6 +47,33 @@
#define SYSREG_CNTPCT_EL0 SYSREG(3, 3, 1, 14, 0)
#define SYSREG_PMCCNTR_EL0 SYSREG(3, 3, 0, 9, 13)

#define SYSREG_ICC_AP0R0_EL1 SYSREG(3, 0, 4, 12, 8)
#define SYSREG_ICC_AP0R1_EL1 SYSREG(3, 0, 5, 12, 8)
#define SYSREG_ICC_AP0R2_EL1 SYSREG(3, 0, 6, 12, 8)
#define SYSREG_ICC_AP0R3_EL1 SYSREG(3, 0, 7, 12, 8)
#define SYSREG_ICC_AP1R0_EL1 SYSREG(3, 0, 0, 12, 9)
#define SYSREG_ICC_AP1R1_EL1 SYSREG(3, 0, 1, 12, 9)
#define SYSREG_ICC_AP1R2_EL1 SYSREG(3, 0, 2, 12, 9)
#define SYSREG_ICC_AP1R3_EL1 SYSREG(3, 0, 3, 12, 9)
#define SYSREG_ICC_ASGI1R_EL1 SYSREG(3, 0, 6, 12, 11)
#define SYSREG_ICC_BPR0_EL1 SYSREG(3, 0, 3, 12, 8)
#define SYSREG_ICC_BPR1_EL1 SYSREG(3, 0, 3, 12, 12)
#define SYSREG_ICC_CTLR_EL1 SYSREG(3, 0, 4, 12, 12)
#define SYSREG_ICC_DIR_EL1 SYSREG(3, 0, 1, 12, 11)
#define SYSREG_ICC_EOIR0_EL1 SYSREG(3, 0, 1, 12, 8)
#define SYSREG_ICC_EOIR1_EL1 SYSREG(3, 0, 1, 12, 12)
#define SYSREG_ICC_HPPIR0_EL1 SYSREG(3, 0, 2, 12, 8)
#define SYSREG_ICC_HPPIR1_EL1 SYSREG(3, 0, 2, 12, 12)
#define SYSREG_ICC_IAR0_EL1 SYSREG(3, 0, 0, 12, 8)
#define SYSREG_ICC_IAR1_EL1 SYSREG(3, 0, 0, 12, 12)
#define SYSREG_ICC_IGRPEN0_EL1 SYSREG(3, 0, 6, 12, 12)
#define SYSREG_ICC_IGRPEN1_EL1 SYSREG(3, 0, 7, 12, 12)
#define SYSREG_ICC_PMR_EL1 SYSREG(3, 0, 0, 4, 6)
#define SYSREG_ICC_RPR_EL1 SYSREG(3, 0, 3, 12, 11)
#define SYSREG_ICC_SGI0R_EL1 SYSREG(3, 0, 7, 12, 11)
#define SYSREG_ICC_SGI1R_EL1 SYSREG(3, 0, 5, 12, 11)
#define SYSREG_ICC_SRE_EL1 SYSREG(3, 0, 5, 12, 12)

#define WFX_IS_WFE (1 << 0)

struct hvf_reg_match {
Expand Down Expand Up @@ -418,6 +446,38 @@ void hvf_kick_vcpu_thread(CPUState *cpu)
hv_vcpus_exit(&cpu->hvf->fd, 1);
}

static uint32_t hvf_reg2cp_reg(uint32_t reg)
{
return ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP,
(reg >> 10) & 0xf,
(reg >> 1) & 0xf,
(reg >> 20) & 0x3,
(reg >> 14) & 0x7,
(reg >> 17) & 0x7);
}

static uint64_t hvf_sysreg_read_cp(CPUState *cpu, uint32_t reg)
{
ARMCPU *arm_cpu = ARM_CPU(cpu);
CPUARMState *env = &arm_cpu->env;
const ARMCPRegInfo *ri;
uint64_t val = 0;

ri = get_arm_cp_reginfo(arm_cpu->cp_regs, hvf_reg2cp_reg(reg));
if (ri) {
if (ri->type & ARM_CP_CONST) {
val = ri->resetvalue;
} else if (ri->readfn) {
val = ri->readfn(env, ri);
} else {
val = CPREG_FIELD64(env, ri);
}
DPRINTF("vgic read from %s [val=%016llx]", ri->name, val);
}

return val;
}

static uint64_t hvf_sysreg_read(CPUState *cpu, uint32_t reg)
{
ARMCPU *arm_cpu = ARM_CPU(cpu);
Expand All @@ -431,6 +491,39 @@ static uint64_t hvf_sysreg_read(CPUState *cpu, uint32_t reg)
case SYSREG_PMCCNTR_EL0:
val = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
break;
case SYSREG_ICC_AP0R0_EL1:
case SYSREG_ICC_AP0R1_EL1:
case SYSREG_ICC_AP0R2_EL1:
case SYSREG_ICC_AP0R3_EL1:
case SYSREG_ICC_AP1R0_EL1:
case SYSREG_ICC_AP1R1_EL1:
case SYSREG_ICC_AP1R2_EL1:
case SYSREG_ICC_AP1R3_EL1:
case SYSREG_ICC_ASGI1R_EL1:
case SYSREG_ICC_BPR0_EL1:
case SYSREG_ICC_BPR1_EL1:
case SYSREG_ICC_DIR_EL1:
case SYSREG_ICC_EOIR0_EL1:
case SYSREG_ICC_EOIR1_EL1:
case SYSREG_ICC_HPPIR0_EL1:
case SYSREG_ICC_HPPIR1_EL1:
case SYSREG_ICC_IAR0_EL1:
case SYSREG_ICC_IAR1_EL1:
case SYSREG_ICC_IGRPEN0_EL1:
case SYSREG_ICC_IGRPEN1_EL1:
case SYSREG_ICC_PMR_EL1:
case SYSREG_ICC_SGI0R_EL1:
case SYSREG_ICC_SGI1R_EL1:
case SYSREG_ICC_SRE_EL1:
val = hvf_sysreg_read_cp(cpu, reg);
break;
case SYSREG_ICC_CTLR_EL1:
val = hvf_sysreg_read_cp(cpu, reg);

/* AP0R registers above 0 don't trap, expose less PRIs to fit */
val &= ~ICC_CTLR_EL1_PRIBITS_MASK;
val |= 4 << ICC_CTLR_EL1_PRIBITS_SHIFT;
break;
default:
DPRINTF("unhandled sysreg read %08x (op0=%d op1=%d op2=%d "
"crn=%d crm=%d)", reg, (reg >> 20) & 0x3,
Expand All @@ -442,13 +535,61 @@ static uint64_t hvf_sysreg_read(CPUState *cpu, uint32_t reg)
return val;
}

static void hvf_sysreg_write_cp(CPUState *cpu, uint32_t reg, uint64_t val)
{
ARMCPU *arm_cpu = ARM_CPU(cpu);
CPUARMState *env = &arm_cpu->env;
const ARMCPRegInfo *ri;

ri = get_arm_cp_reginfo(arm_cpu->cp_regs, hvf_reg2cp_reg(reg));

if (ri) {
if (ri->writefn) {
ri->writefn(env, ri, val);
} else {
CPREG_FIELD64(env, ri) = val;
}
DPRINTF("vgic write to %s [val=%016llx]", ri->name, val);
}
}

static void hvf_sysreg_write(CPUState *cpu, uint32_t reg, uint64_t val)
{
ARMCPU *arm_cpu = ARM_CPU(cpu);

switch (reg) {
case SYSREG_CNTPCT_EL0:
break;
case SYSREG_ICC_AP0R0_EL1:
case SYSREG_ICC_AP0R1_EL1:
case SYSREG_ICC_AP0R2_EL1:
case SYSREG_ICC_AP0R3_EL1:
case SYSREG_ICC_AP1R0_EL1:
case SYSREG_ICC_AP1R1_EL1:
case SYSREG_ICC_AP1R2_EL1:
case SYSREG_ICC_AP1R3_EL1:
case SYSREG_ICC_ASGI1R_EL1:
case SYSREG_ICC_BPR0_EL1:
case SYSREG_ICC_BPR1_EL1:
case SYSREG_ICC_CTLR_EL1:
case SYSREG_ICC_DIR_EL1:
case SYSREG_ICC_HPPIR0_EL1:
case SYSREG_ICC_HPPIR1_EL1:
case SYSREG_ICC_IAR0_EL1:
case SYSREG_ICC_IAR1_EL1:
case SYSREG_ICC_IGRPEN0_EL1:
case SYSREG_ICC_IGRPEN1_EL1:
case SYSREG_ICC_PMR_EL1:
case SYSREG_ICC_SGI0R_EL1:
case SYSREG_ICC_SGI1R_EL1:
case SYSREG_ICC_SRE_EL1:
hvf_sysreg_write_cp(cpu, reg, val);
break;
case SYSREG_ICC_EOIR0_EL1:
case SYSREG_ICC_EOIR1_EL1:
hvf_sysreg_write_cp(cpu, reg, val);
qemu_set_irq(arm_cpu->gt_timer_outputs[GTIMER_VIRT], 0);
hv_vcpu_set_vtimer_mask(cpu->hvf->fd, false);
default:
DPRINTF("unhandled sysreg write %08x", reg);
break;
Expand Down

0 comments on commit 222130c

Please sign in to comment.