@ -42,6 +42,132 @@ static inline int icv_min_vbpr(GICv3CPUState *cs)
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 )
{
/* Calculate the current running priority based on the set bits
@ -1334,6 +1460,306 @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = {
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 )
{
GICv3CPUState * cs = opaque ;
@ -1362,6 +1788,57 @@ void gicv3_init_cpuif(GICv3State *s)
* to need to register anyway .
*/
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 ) ;
}
}