hw/intc/arm_gicv3: Add accessors for ICH_ system registers
The GICv3 virtualization interface includes system registers accessible only to the hypervisor which form the control interface for interrupt virtualization. Implement these registers. The function gicv3_cpuif_virt_update() which determines whether it needs to signal vIRQ, vFIQ or a maintenance interrupt is introduced here as a stub function -- its implementation will be added in a subsequent commit. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 1483977924-14522-9-git-send-email-peter.maydell@linaro.org
This commit is contained in:
parent
4eb833b5df
commit
83f036fe3d
@ -42,6 +42,132 @@ static inline int icv_min_vbpr(GICv3CPUState *cs)
|
|||||||
return 7 - cs->vprebits;
|
return 7 - cs->vprebits;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Simple accessor functions for LR fields */
|
||||||
|
static int ich_lr_state(uint64_t lr)
|
||||||
|
{
|
||||||
|
return extract64(lr, ICH_LR_EL2_STATE_SHIFT, ICH_LR_EL2_STATE_LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int read_vbpr(GICv3CPUState *cs, int grp)
|
||||||
|
{
|
||||||
|
/* Read VBPR value out of the VMCR field (caller must handle
|
||||||
|
* VCBPR effects if required)
|
||||||
|
*/
|
||||||
|
if (grp == GICV3_G0) {
|
||||||
|
return extract64(cs->ich_vmcr_el2, ICH_VMCR_EL2_VBPR0_SHIFT,
|
||||||
|
ICH_VMCR_EL2_VBPR0_LENGTH);
|
||||||
|
} else {
|
||||||
|
return extract64(cs->ich_vmcr_el2, ICH_VMCR_EL2_VBPR1_SHIFT,
|
||||||
|
ICH_VMCR_EL2_VBPR1_LENGTH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write_vbpr(GICv3CPUState *cs, int grp, int value)
|
||||||
|
{
|
||||||
|
/* Write new VBPR1 value, handling the "writing a value less than
|
||||||
|
* the minimum sets it to the minimum" semantics.
|
||||||
|
*/
|
||||||
|
int min = icv_min_vbpr(cs);
|
||||||
|
|
||||||
|
if (grp != GICV3_G0) {
|
||||||
|
min++;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = MAX(value, min);
|
||||||
|
|
||||||
|
if (grp == GICV3_G0) {
|
||||||
|
cs->ich_vmcr_el2 = deposit64(cs->ich_vmcr_el2, ICH_VMCR_EL2_VBPR0_SHIFT,
|
||||||
|
ICH_VMCR_EL2_VBPR0_LENGTH, value);
|
||||||
|
} else {
|
||||||
|
cs->ich_vmcr_el2 = deposit64(cs->ich_vmcr_el2, ICH_VMCR_EL2_VBPR1_SHIFT,
|
||||||
|
ICH_VMCR_EL2_VBPR1_LENGTH, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t eoi_maintenance_interrupt_state(GICv3CPUState *cs,
|
||||||
|
uint32_t *misr)
|
||||||
|
{
|
||||||
|
/* Return a set of bits indicating the EOI maintenance interrupt status
|
||||||
|
* for each list register. The EOI maintenance interrupt status is
|
||||||
|
* 1 if LR.State == 0 && LR.HW == 0 && LR.EOI == 1
|
||||||
|
* (see the GICv3 spec for the ICH_EISR_EL2 register).
|
||||||
|
* If misr is not NULL then we should also collect the information
|
||||||
|
* about the MISR.EOI, MISR.NP and MISR.U bits.
|
||||||
|
*/
|
||||||
|
uint32_t value = 0;
|
||||||
|
int validcount = 0;
|
||||||
|
bool seenpending = false;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < cs->num_list_regs; i++) {
|
||||||
|
uint64_t lr = cs->ich_lr_el2[i];
|
||||||
|
|
||||||
|
if ((lr & (ICH_LR_EL2_STATE_MASK | ICH_LR_EL2_HW | ICH_LR_EL2_EOI))
|
||||||
|
== ICH_LR_EL2_EOI) {
|
||||||
|
value |= (1 << i);
|
||||||
|
}
|
||||||
|
if ((lr & ICH_LR_EL2_STATE_MASK)) {
|
||||||
|
validcount++;
|
||||||
|
}
|
||||||
|
if (ich_lr_state(lr) == ICH_LR_EL2_STATE_PENDING) {
|
||||||
|
seenpending = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (misr) {
|
||||||
|
if (validcount < 2 && (cs->ich_hcr_el2 & ICH_HCR_EL2_UIE)) {
|
||||||
|
*misr |= ICH_MISR_EL2_U;
|
||||||
|
}
|
||||||
|
if (!seenpending && (cs->ich_hcr_el2 & ICH_HCR_EL2_NPIE)) {
|
||||||
|
*misr |= ICH_MISR_EL2_NP;
|
||||||
|
}
|
||||||
|
if (value) {
|
||||||
|
*misr |= ICH_MISR_EL2_EOI;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t maintenance_interrupt_state(GICv3CPUState *cs)
|
||||||
|
{
|
||||||
|
/* Return a set of bits indicating the maintenance interrupt status
|
||||||
|
* (as seen in the ICH_MISR_EL2 register).
|
||||||
|
*/
|
||||||
|
uint32_t value = 0;
|
||||||
|
|
||||||
|
/* Scan list registers and fill in the U, NP and EOI bits */
|
||||||
|
eoi_maintenance_interrupt_state(cs, &value);
|
||||||
|
|
||||||
|
if (cs->ich_hcr_el2 & (ICH_HCR_EL2_LRENPIE | ICH_HCR_EL2_EOICOUNT_MASK)) {
|
||||||
|
value |= ICH_MISR_EL2_LRENP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((cs->ich_hcr_el2 & ICH_HCR_EL2_VGRP0EIE) &&
|
||||||
|
(cs->ich_vmcr_el2 & ICH_VMCR_EL2_VENG0)) {
|
||||||
|
value |= ICH_MISR_EL2_VGRP0E;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((cs->ich_hcr_el2 & ICH_HCR_EL2_VGRP0DIE) &&
|
||||||
|
!(cs->ich_vmcr_el2 & ICH_VMCR_EL2_VENG1)) {
|
||||||
|
value |= ICH_MISR_EL2_VGRP0D;
|
||||||
|
}
|
||||||
|
if ((cs->ich_hcr_el2 & ICH_HCR_EL2_VGRP1EIE) &&
|
||||||
|
(cs->ich_vmcr_el2 & ICH_VMCR_EL2_VENG1)) {
|
||||||
|
value |= ICH_MISR_EL2_VGRP1E;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((cs->ich_hcr_el2 & ICH_HCR_EL2_VGRP1DIE) &&
|
||||||
|
!(cs->ich_vmcr_el2 & ICH_VMCR_EL2_VENG1)) {
|
||||||
|
value |= ICH_MISR_EL2_VGRP1D;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gicv3_cpuif_virt_update(GICv3CPUState *cs)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
static int icc_highest_active_prio(GICv3CPUState *cs)
|
static int icc_highest_active_prio(GICv3CPUState *cs)
|
||||||
{
|
{
|
||||||
/* Calculate the current running priority based on the set bits
|
/* Calculate the current running priority based on the set bits
|
||||||
@ -1334,6 +1460,306 @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = {
|
|||||||
REGINFO_SENTINEL
|
REGINFO_SENTINEL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static uint64_t ich_ap_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||||
|
{
|
||||||
|
GICv3CPUState *cs = icc_cs_from_env(env);
|
||||||
|
int regno = ri->opc2 & 3;
|
||||||
|
int grp = ri->crm & 1 ? GICV3_G0 : GICV3_G1NS;
|
||||||
|
uint64_t value;
|
||||||
|
|
||||||
|
value = cs->ich_apr[grp][regno];
|
||||||
|
trace_gicv3_ich_ap_read(ri->crm & 1, regno, gicv3_redist_affid(cs), value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ich_ap_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
|
uint64_t value)
|
||||||
|
{
|
||||||
|
GICv3CPUState *cs = icc_cs_from_env(env);
|
||||||
|
int regno = ri->opc2 & 3;
|
||||||
|
int grp = ri->crm & 1 ? GICV3_G0 : GICV3_G1NS;
|
||||||
|
|
||||||
|
trace_gicv3_ich_ap_write(ri->crm & 1, regno, gicv3_redist_affid(cs), value);
|
||||||
|
|
||||||
|
cs->ich_apr[grp][regno] = value & 0xFFFFFFFFU;
|
||||||
|
gicv3_cpuif_virt_update(cs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t ich_hcr_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||||
|
{
|
||||||
|
GICv3CPUState *cs = icc_cs_from_env(env);
|
||||||
|
uint64_t value = cs->ich_hcr_el2;
|
||||||
|
|
||||||
|
trace_gicv3_ich_hcr_read(gicv3_redist_affid(cs), value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ich_hcr_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
|
uint64_t value)
|
||||||
|
{
|
||||||
|
GICv3CPUState *cs = icc_cs_from_env(env);
|
||||||
|
|
||||||
|
trace_gicv3_ich_hcr_write(gicv3_redist_affid(cs), value);
|
||||||
|
|
||||||
|
value &= ICH_HCR_EL2_EN | ICH_HCR_EL2_UIE | ICH_HCR_EL2_LRENPIE |
|
||||||
|
ICH_HCR_EL2_NPIE | ICH_HCR_EL2_VGRP0EIE | ICH_HCR_EL2_VGRP0DIE |
|
||||||
|
ICH_HCR_EL2_VGRP1EIE | ICH_HCR_EL2_VGRP1DIE | ICH_HCR_EL2_TC |
|
||||||
|
ICH_HCR_EL2_TALL0 | ICH_HCR_EL2_TALL1 | ICH_HCR_EL2_TSEI |
|
||||||
|
ICH_HCR_EL2_TDIR | ICH_HCR_EL2_EOICOUNT_MASK;
|
||||||
|
|
||||||
|
cs->ich_hcr_el2 = value;
|
||||||
|
gicv3_cpuif_virt_update(cs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t ich_vmcr_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||||
|
{
|
||||||
|
GICv3CPUState *cs = icc_cs_from_env(env);
|
||||||
|
uint64_t value = cs->ich_vmcr_el2;
|
||||||
|
|
||||||
|
trace_gicv3_ich_vmcr_read(gicv3_redist_affid(cs), value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ich_vmcr_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
|
uint64_t value)
|
||||||
|
{
|
||||||
|
GICv3CPUState *cs = icc_cs_from_env(env);
|
||||||
|
|
||||||
|
trace_gicv3_ich_vmcr_write(gicv3_redist_affid(cs), value);
|
||||||
|
|
||||||
|
value &= ICH_VMCR_EL2_VENG0 | ICH_VMCR_EL2_VENG1 | ICH_VMCR_EL2_VCBPR |
|
||||||
|
ICH_VMCR_EL2_VEOIM | ICH_VMCR_EL2_VBPR1_MASK |
|
||||||
|
ICH_VMCR_EL2_VBPR0_MASK | ICH_VMCR_EL2_VPMR_MASK;
|
||||||
|
value |= ICH_VMCR_EL2_VFIQEN;
|
||||||
|
|
||||||
|
cs->ich_vmcr_el2 = value;
|
||||||
|
/* Enforce "writing BPRs to less than minimum sets them to the minimum"
|
||||||
|
* by reading and writing back the fields.
|
||||||
|
*/
|
||||||
|
write_vbpr(cs, GICV3_G1, read_vbpr(cs, GICV3_G0));
|
||||||
|
write_vbpr(cs, GICV3_G1, read_vbpr(cs, GICV3_G1));
|
||||||
|
|
||||||
|
gicv3_cpuif_virt_update(cs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t ich_lr_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||||
|
{
|
||||||
|
GICv3CPUState *cs = icc_cs_from_env(env);
|
||||||
|
int regno = ri->opc2 | ((ri->crm & 1) << 3);
|
||||||
|
uint64_t value;
|
||||||
|
|
||||||
|
/* This read function handles all of:
|
||||||
|
* 64-bit reads of the whole LR
|
||||||
|
* 32-bit reads of the low half of the LR
|
||||||
|
* 32-bit reads of the high half of the LR
|
||||||
|
*/
|
||||||
|
if (ri->state == ARM_CP_STATE_AA32) {
|
||||||
|
if (ri->crm >= 14) {
|
||||||
|
value = extract64(cs->ich_lr_el2[regno], 32, 32);
|
||||||
|
trace_gicv3_ich_lrc_read(regno, gicv3_redist_affid(cs), value);
|
||||||
|
} else {
|
||||||
|
value = extract64(cs->ich_lr_el2[regno], 0, 32);
|
||||||
|
trace_gicv3_ich_lr32_read(regno, gicv3_redist_affid(cs), value);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
value = cs->ich_lr_el2[regno];
|
||||||
|
trace_gicv3_ich_lr_read(regno, gicv3_redist_affid(cs), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ich_lr_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
|
uint64_t value)
|
||||||
|
{
|
||||||
|
GICv3CPUState *cs = icc_cs_from_env(env);
|
||||||
|
int regno = ri->opc2 | ((ri->crm & 1) << 3);
|
||||||
|
|
||||||
|
/* This write function handles all of:
|
||||||
|
* 64-bit writes to the whole LR
|
||||||
|
* 32-bit writes to the low half of the LR
|
||||||
|
* 32-bit writes to the high half of the LR
|
||||||
|
*/
|
||||||
|
if (ri->state == ARM_CP_STATE_AA32) {
|
||||||
|
if (ri->crm >= 14) {
|
||||||
|
trace_gicv3_ich_lrc_write(regno, gicv3_redist_affid(cs), value);
|
||||||
|
value = deposit64(cs->ich_lr_el2[regno], 32, 32, value);
|
||||||
|
} else {
|
||||||
|
trace_gicv3_ich_lr32_write(regno, gicv3_redist_affid(cs), value);
|
||||||
|
value = deposit64(cs->ich_lr_el2[regno], 0, 32, value);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
trace_gicv3_ich_lr_write(regno, gicv3_redist_affid(cs), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enforce RES0 bits in priority field */
|
||||||
|
if (cs->vpribits < 8) {
|
||||||
|
value = deposit64(value, ICH_LR_EL2_PRIORITY_SHIFT,
|
||||||
|
8 - cs->vpribits, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
cs->ich_lr_el2[regno] = value;
|
||||||
|
gicv3_cpuif_virt_update(cs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t ich_vtr_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||||
|
{
|
||||||
|
GICv3CPUState *cs = icc_cs_from_env(env);
|
||||||
|
uint64_t value;
|
||||||
|
|
||||||
|
value = ((cs->num_list_regs - 1) << ICH_VTR_EL2_LISTREGS_SHIFT)
|
||||||
|
| ICH_VTR_EL2_TDS | ICH_VTR_EL2_NV4 | ICH_VTR_EL2_A3V
|
||||||
|
| (1 << ICH_VTR_EL2_IDBITS_SHIFT)
|
||||||
|
| ((cs->vprebits - 1) << ICH_VTR_EL2_PREBITS_SHIFT)
|
||||||
|
| ((cs->vpribits - 1) << ICH_VTR_EL2_PRIBITS_SHIFT);
|
||||||
|
|
||||||
|
trace_gicv3_ich_vtr_read(gicv3_redist_affid(cs), value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t ich_misr_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||||
|
{
|
||||||
|
GICv3CPUState *cs = icc_cs_from_env(env);
|
||||||
|
uint64_t value = maintenance_interrupt_state(cs);
|
||||||
|
|
||||||
|
trace_gicv3_ich_misr_read(gicv3_redist_affid(cs), value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t ich_eisr_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||||
|
{
|
||||||
|
GICv3CPUState *cs = icc_cs_from_env(env);
|
||||||
|
uint64_t value = eoi_maintenance_interrupt_state(cs, NULL);
|
||||||
|
|
||||||
|
trace_gicv3_ich_eisr_read(gicv3_redist_affid(cs), value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t ich_elrsr_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||||
|
{
|
||||||
|
GICv3CPUState *cs = icc_cs_from_env(env);
|
||||||
|
uint64_t value = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < cs->num_list_regs; i++) {
|
||||||
|
uint64_t lr = cs->ich_lr_el2[i];
|
||||||
|
|
||||||
|
if ((lr & ICH_LR_EL2_STATE_MASK) == 0 &&
|
||||||
|
((lr & ICH_LR_EL2_HW) == 1 || (lr & ICH_LR_EL2_EOI) == 0)) {
|
||||||
|
value |= (1 << i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trace_gicv3_ich_elrsr_read(gicv3_redist_affid(cs), value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const ARMCPRegInfo gicv3_cpuif_hcr_reginfo[] = {
|
||||||
|
{ .name = "ICH_AP0R0_EL2", .state = ARM_CP_STATE_BOTH,
|
||||||
|
.opc0 = 3, .opc1 = 4, .crn = 12, .crm = 8, .opc2 = 0,
|
||||||
|
.type = ARM_CP_IO | ARM_CP_NO_RAW,
|
||||||
|
.access = PL2_RW,
|
||||||
|
.readfn = ich_ap_read,
|
||||||
|
.writefn = ich_ap_write,
|
||||||
|
},
|
||||||
|
{ .name = "ICH_AP1R0_EL2", .state = ARM_CP_STATE_BOTH,
|
||||||
|
.opc0 = 3, .opc1 = 4, .crn = 12, .crm = 9, .opc2 = 0,
|
||||||
|
.type = ARM_CP_IO | ARM_CP_NO_RAW,
|
||||||
|
.access = PL2_RW,
|
||||||
|
.readfn = ich_ap_read,
|
||||||
|
.writefn = ich_ap_write,
|
||||||
|
},
|
||||||
|
{ .name = "ICH_HCR_EL2", .state = ARM_CP_STATE_BOTH,
|
||||||
|
.opc0 = 3, .opc1 = 4, .crn = 12, .crm = 11, .opc2 = 0,
|
||||||
|
.type = ARM_CP_IO | ARM_CP_NO_RAW,
|
||||||
|
.access = PL2_RW,
|
||||||
|
.readfn = ich_hcr_read,
|
||||||
|
.writefn = ich_hcr_write,
|
||||||
|
},
|
||||||
|
{ .name = "ICH_VTR_EL2", .state = ARM_CP_STATE_BOTH,
|
||||||
|
.opc0 = 3, .opc1 = 4, .crn = 12, .crm = 11, .opc2 = 1,
|
||||||
|
.type = ARM_CP_IO | ARM_CP_NO_RAW,
|
||||||
|
.access = PL2_R,
|
||||||
|
.readfn = ich_vtr_read,
|
||||||
|
},
|
||||||
|
{ .name = "ICH_MISR_EL2", .state = ARM_CP_STATE_BOTH,
|
||||||
|
.opc0 = 3, .opc1 = 4, .crn = 12, .crm = 11, .opc2 = 2,
|
||||||
|
.type = ARM_CP_IO | ARM_CP_NO_RAW,
|
||||||
|
.access = PL2_R,
|
||||||
|
.readfn = ich_misr_read,
|
||||||
|
},
|
||||||
|
{ .name = "ICH_EISR_EL2", .state = ARM_CP_STATE_BOTH,
|
||||||
|
.opc0 = 3, .opc1 = 4, .crn = 12, .crm = 11, .opc2 = 3,
|
||||||
|
.type = ARM_CP_IO | ARM_CP_NO_RAW,
|
||||||
|
.access = PL2_R,
|
||||||
|
.readfn = ich_eisr_read,
|
||||||
|
},
|
||||||
|
{ .name = "ICH_ELRSR_EL2", .state = ARM_CP_STATE_BOTH,
|
||||||
|
.opc0 = 3, .opc1 = 4, .crn = 12, .crm = 11, .opc2 = 5,
|
||||||
|
.type = ARM_CP_IO | ARM_CP_NO_RAW,
|
||||||
|
.access = PL2_R,
|
||||||
|
.readfn = ich_elrsr_read,
|
||||||
|
},
|
||||||
|
{ .name = "ICH_VMCR_EL2", .state = ARM_CP_STATE_BOTH,
|
||||||
|
.opc0 = 3, .opc1 = 4, .crn = 12, .crm = 11, .opc2 = 7,
|
||||||
|
.type = ARM_CP_IO | ARM_CP_NO_RAW,
|
||||||
|
.access = PL2_RW,
|
||||||
|
.readfn = ich_vmcr_read,
|
||||||
|
.writefn = ich_vmcr_write,
|
||||||
|
},
|
||||||
|
REGINFO_SENTINEL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const ARMCPRegInfo gicv3_cpuif_ich_apxr1_reginfo[] = {
|
||||||
|
{ .name = "ICH_AP0R1_EL2", .state = ARM_CP_STATE_BOTH,
|
||||||
|
.opc0 = 3, .opc1 = 4, .crn = 12, .crm = 8, .opc2 = 1,
|
||||||
|
.type = ARM_CP_IO | ARM_CP_NO_RAW,
|
||||||
|
.access = PL2_RW,
|
||||||
|
.readfn = ich_ap_read,
|
||||||
|
.writefn = ich_ap_write,
|
||||||
|
},
|
||||||
|
{ .name = "ICH_AP1R1_EL2", .state = ARM_CP_STATE_BOTH,
|
||||||
|
.opc0 = 3, .opc1 = 4, .crn = 12, .crm = 9, .opc2 = 1,
|
||||||
|
.type = ARM_CP_IO | ARM_CP_NO_RAW,
|
||||||
|
.access = PL2_RW,
|
||||||
|
.readfn = ich_ap_read,
|
||||||
|
.writefn = ich_ap_write,
|
||||||
|
},
|
||||||
|
REGINFO_SENTINEL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const ARMCPRegInfo gicv3_cpuif_ich_apxr23_reginfo[] = {
|
||||||
|
{ .name = "ICH_AP0R2_EL2", .state = ARM_CP_STATE_BOTH,
|
||||||
|
.opc0 = 3, .opc1 = 4, .crn = 12, .crm = 8, .opc2 = 2,
|
||||||
|
.type = ARM_CP_IO | ARM_CP_NO_RAW,
|
||||||
|
.access = PL2_RW,
|
||||||
|
.readfn = ich_ap_read,
|
||||||
|
.writefn = ich_ap_write,
|
||||||
|
},
|
||||||
|
{ .name = "ICH_AP0R3_EL2", .state = ARM_CP_STATE_BOTH,
|
||||||
|
.opc0 = 3, .opc1 = 4, .crn = 12, .crm = 8, .opc2 = 3,
|
||||||
|
.type = ARM_CP_IO | ARM_CP_NO_RAW,
|
||||||
|
.access = PL2_RW,
|
||||||
|
.readfn = ich_ap_read,
|
||||||
|
.writefn = ich_ap_write,
|
||||||
|
},
|
||||||
|
{ .name = "ICH_AP1R2_EL2", .state = ARM_CP_STATE_BOTH,
|
||||||
|
.opc0 = 3, .opc1 = 4, .crn = 12, .crm = 9, .opc2 = 2,
|
||||||
|
.type = ARM_CP_IO | ARM_CP_NO_RAW,
|
||||||
|
.access = PL2_RW,
|
||||||
|
.readfn = ich_ap_read,
|
||||||
|
.writefn = ich_ap_write,
|
||||||
|
},
|
||||||
|
{ .name = "ICH_AP1R3_EL2", .state = ARM_CP_STATE_BOTH,
|
||||||
|
.opc0 = 3, .opc1 = 4, .crn = 12, .crm = 9, .opc2 = 3,
|
||||||
|
.type = ARM_CP_IO | ARM_CP_NO_RAW,
|
||||||
|
.access = PL2_RW,
|
||||||
|
.readfn = ich_ap_read,
|
||||||
|
.writefn = ich_ap_write,
|
||||||
|
},
|
||||||
|
REGINFO_SENTINEL
|
||||||
|
};
|
||||||
|
|
||||||
static void gicv3_cpuif_el_change_hook(ARMCPU *cpu, void *opaque)
|
static void gicv3_cpuif_el_change_hook(ARMCPU *cpu, void *opaque)
|
||||||
{
|
{
|
||||||
GICv3CPUState *cs = opaque;
|
GICv3CPUState *cs = opaque;
|
||||||
@ -1362,6 +1788,57 @@ void gicv3_init_cpuif(GICv3State *s)
|
|||||||
* to need to register anyway.
|
* to need to register anyway.
|
||||||
*/
|
*/
|
||||||
define_arm_cp_regs(cpu, gicv3_cpuif_reginfo);
|
define_arm_cp_regs(cpu, gicv3_cpuif_reginfo);
|
||||||
|
if (arm_feature(&cpu->env, ARM_FEATURE_EL2)
|
||||||
|
&& cpu->gic_num_lrs) {
|
||||||
|
int j;
|
||||||
|
|
||||||
|
cs->num_list_regs = cpu->gic_num_lrs;
|
||||||
|
cs->vpribits = cpu->gic_vpribits;
|
||||||
|
cs->vprebits = cpu->gic_vprebits;
|
||||||
|
|
||||||
|
/* Check against architectural constraints: getting these
|
||||||
|
* wrong would be a bug in the CPU code defining these,
|
||||||
|
* and the implementation relies on them holding.
|
||||||
|
*/
|
||||||
|
g_assert(cs->vprebits <= cs->vpribits);
|
||||||
|
g_assert(cs->vprebits >= 5 && cs->vprebits <= 7);
|
||||||
|
g_assert(cs->vpribits >= 5 && cs->vpribits <= 8);
|
||||||
|
|
||||||
|
define_arm_cp_regs(cpu, gicv3_cpuif_hcr_reginfo);
|
||||||
|
|
||||||
|
for (j = 0; j < cs->num_list_regs; j++) {
|
||||||
|
/* Note that the AArch64 LRs are 64-bit; the AArch32 LRs
|
||||||
|
* are split into two cp15 regs, LR (the low part, with the
|
||||||
|
* same encoding as the AArch64 LR) and LRC (the high part).
|
||||||
|
*/
|
||||||
|
ARMCPRegInfo lr_regset[] = {
|
||||||
|
{ .name = "ICH_LRn_EL2", .state = ARM_CP_STATE_BOTH,
|
||||||
|
.opc0 = 3, .opc1 = 4, .crn = 12,
|
||||||
|
.crm = 12 + (j >> 3), .opc2 = j & 7,
|
||||||
|
.type = ARM_CP_IO | ARM_CP_NO_RAW,
|
||||||
|
.access = PL2_RW,
|
||||||
|
.readfn = ich_lr_read,
|
||||||
|
.writefn = ich_lr_write,
|
||||||
|
},
|
||||||
|
{ .name = "ICH_LRCn_EL2", .state = ARM_CP_STATE_AA32,
|
||||||
|
.cp = 15, .opc1 = 4, .crn = 12,
|
||||||
|
.crm = 14 + (j >> 3), .opc2 = j & 7,
|
||||||
|
.type = ARM_CP_IO | ARM_CP_NO_RAW,
|
||||||
|
.access = PL2_RW,
|
||||||
|
.readfn = ich_lr_read,
|
||||||
|
.writefn = ich_lr_write,
|
||||||
|
},
|
||||||
|
REGINFO_SENTINEL
|
||||||
|
};
|
||||||
|
define_arm_cp_regs(cpu, lr_regset);
|
||||||
|
}
|
||||||
|
if (cs->vprebits >= 6) {
|
||||||
|
define_arm_cp_regs(cpu, gicv3_cpuif_ich_apxr1_reginfo);
|
||||||
|
}
|
||||||
|
if (cs->vprebits == 7) {
|
||||||
|
define_arm_cp_regs(cpu, gicv3_cpuif_ich_apxr23_reginfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
arm_register_el_change_hook(cpu, gicv3_cpuif_el_change_hook, cs);
|
arm_register_el_change_hook(cpu, gicv3_cpuif_el_change_hook, cs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,6 +107,22 @@ gicv3_icc_hppir0_read(uint32_t cpu, uint64_t val) "GICv3 ICC_HPPIR0 read cpu %x
|
|||||||
gicv3_icc_hppir1_read(uint32_t cpu, uint64_t val) "GICv3 ICC_HPPIR1 read cpu %x value 0x%" PRIx64
|
gicv3_icc_hppir1_read(uint32_t cpu, uint64_t val) "GICv3 ICC_HPPIR1 read cpu %x value 0x%" PRIx64
|
||||||
gicv3_icc_dir_write(uint32_t cpu, uint64_t val) "GICv3 ICC_DIR write cpu %x value 0x%" PRIx64
|
gicv3_icc_dir_write(uint32_t cpu, uint64_t val) "GICv3 ICC_DIR write cpu %x value 0x%" PRIx64
|
||||||
gicv3_icc_rpr_read(uint32_t cpu, uint64_t val) "GICv3 ICC_RPR read cpu %x value 0x%" PRIx64
|
gicv3_icc_rpr_read(uint32_t cpu, uint64_t val) "GICv3 ICC_RPR read cpu %x value 0x%" PRIx64
|
||||||
|
gicv3_ich_ap_read(int grp, int regno, uint32_t cpu, uint64_t val) "GICv3 ICH_AP%dR%d read cpu %x value 0x%" PRIx64
|
||||||
|
gicv3_ich_ap_write(int grp, int regno, uint32_t cpu, uint64_t val) "GICv3 ICH_AP%dR%d write cpu %x value 0x%" PRIx64
|
||||||
|
gicv3_ich_hcr_read(uint32_t cpu, uint64_t val) "GICv3 ICH_HCR_EL2 read cpu %x value 0x%" PRIx64
|
||||||
|
gicv3_ich_hcr_write(uint32_t cpu, uint64_t val) "GICv3 ICH_HCR_EL2 write cpu %x value 0x%" PRIx64
|
||||||
|
gicv3_ich_vmcr_read(uint32_t cpu, uint64_t val) "GICv3 ICH_VMCR_EL2 read cpu %x value 0x%" PRIx64
|
||||||
|
gicv3_ich_vmcr_write(uint32_t cpu, uint64_t val) "GICv3 ICH_VMCR_EL2 write cpu %x value 0x%" PRIx64
|
||||||
|
gicv3_ich_lr_read(int regno, uint32_t cpu, uint64_t val) "GICv3 ICH_LR%d_EL2 read cpu %x value 0x%" PRIx64
|
||||||
|
gicv3_ich_lr32_read(int regno, uint32_t cpu, uint32_t val) "GICv3 ICH_LR%d read cpu %x value 0x%" PRIx32
|
||||||
|
gicv3_ich_lrc_read(int regno, uint32_t cpu, uint32_t val) "GICv3 ICH_LRC%d read cpu %x value 0x%" PRIx32
|
||||||
|
gicv3_ich_lr_write(int regno, uint32_t cpu, uint64_t val) "GICv3 ICH_LR%d_EL2 write cpu %x value 0x%" PRIx64
|
||||||
|
gicv3_ich_lr32_write(int regno, uint32_t cpu, uint32_t val) "GICv3 ICH_LR%d write cpu %x value 0x%" PRIx32
|
||||||
|
gicv3_ich_lrc_write(int regno, uint32_t cpu, uint32_t val) "GICv3 ICH_LRC%d write cpu %x value 0x%" PRIx32
|
||||||
|
gicv3_ich_vtr_read(uint32_t cpu, uint64_t val) "GICv3 ICH_VTR read cpu %x value 0x%" PRIx64
|
||||||
|
gicv3_ich_misr_read(uint32_t cpu, uint64_t val) "GICv3 ICH_MISR read cpu %x value 0x%" PRIx64
|
||||||
|
gicv3_ich_eisr_read(uint32_t cpu, uint64_t val) "GICv3 ICH_EISR read cpu %x value 0x%" PRIx64
|
||||||
|
gicv3_ich_elrsr_read(uint32_t cpu, uint64_t val) "GICv3 ICH_ELRSR read cpu %x value 0x%" PRIx64
|
||||||
|
|
||||||
# hw/intc/arm_gicv3_dist.c
|
# hw/intc/arm_gicv3_dist.c
|
||||||
gicv3_dist_read(uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 distributor read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d"
|
gicv3_dist_read(uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 distributor read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d"
|
||||||
|
Loading…
Reference in New Issue
Block a user