Chapter 6: Virtual Interrupt Handling and Prioritization
This chapter describes the fundamental aspects of GIC virtual interrupt handling and prioritization:
-
About GIC support for virtualization .
-
Operation overview .
-
Configuration and control of VMs .
-
Pseudocode .
6.1 About GIC support for virtualization
An operating system that is executing at EL1 under the control of a hypervisor executing at EL2 is sometimes referred as a virtual machine (VM). A VM can support multiprocessing, which means that multiple virtual PEs (vPEs), that are scheduled by the hypervisor are executing on one or more physical PEs. When a vPE is executing on a PE, that vPE of the VM is referred to as being scheduled on the physical PE.
In Armv8, when EL2 is implemented and enabled, the CPU interface provides mechanisms to minimize the hypervisor overhead of routing interrupts to a VM. For more information about vPEs, see Operation overview .
For more information about EL2 and virtual interrupts, see Arm[®] Architecture Reference Manual, Armv8, for Armv8-A architecture profile .
In GICv4, for the directly injected virtual LPIs, the scheduled vPE is determined by GICR_VPENDBASER. For more information, see Doorbell interrupts .
Note The GIC does not provide additional mechanisms for the virtualization of the GICD_, GICR_, and GITS_* registers. To virtualize VM accesses to these registers, the hypervisor must set stage 2 Data Aborts to those memory locations so that the hypervisor can emulate these effects. For more information about stage 2 Data Aborts, see Arm[®] Architecture Reference Manual, Armv8, for Armv8-A architecture profile .
When a GIC provides support for virtualization, the VM operates in an environment that has the following features:
-
The vPE can be configured to receive virtual Group 0 interrupts.
-
The vPE can be configured to receive virtual Group 1 interrupts.
-
Virtual Group 0 interrupts are signaled using the virtual FIQ signal to Non-secure EL1.
-
Virtual Group 1 interrupts are signaled using the virtual IRQ signal to Non-secure EL1.
-
Virtual interrupts can be handled by the vPE as if they were physical interrupts.
Note
This applies when affinity routing and System register access are enabled. For information about support for virtual interrupts in legacy operation, see Support for legacy operation of VMs .
EL2 controls the generation of virtual interrupts for a VM. This allows software executing at EL2 to:
-
Generate virtual Group 0 and Group 1 interrupts for the vPE.
-
Save and restore the interrupt state of the vPE.
-
Control the prioritization of the virtual interrupts.
-
Change the vPE that is scheduled.
GICv4 introduces the ability to present virtual LPIs from an ITS directly to a vPE, without hypervisor intervention.
Handling virtual interrupts in legacy operation requires a GICV_* memory-mapped interface. See Support for legacy operation of VMs for more information.
6.2 Operation overview
GICv3 supports the Armv8-A virtualization functionality. A hypervisor executing at EL2 uses the ICH_* System register interface to configure and control a virtual PE (vPE) executing at EL1. For information about the VM control interface, see Configuration and control of VMs . A vPE uses the ICC_*_EL1 System register interface to communicate with the GIC. The configuration of HCR_EL2.{IMO, FMO} determines whether the virtual or the physical interface registers are accessed.
Note This chapter describes the handling of virtual interrupts in the context of the AArch64 state with System register access enabled. The individual AArch64 System register descriptions that are cross-referenced in this chapter contain a reference to the AArch32 System register that provides the same functionality. For information about VMs in legacy operation, see Support for legacy operation of VMs .
Software executing at EL3 or EL2 configures the PE to route physical interrupts to EL2. The interrupt can be:
-
An interrupt targeting a vPE. The hypervisor sets the corresponding virtual INTID to the pending state on the target vPE and includes the information about the associated physical INTID. When the vPE is not scheduled on a PE, the hypervisor might choose to reschedule the vPE. Otherwise the interrupt is left pending on the vPE for scheduling by the hypervisor at a later time.
-
An interrupt targeting the hypervisor. This interrupt might:
-
Have been generated by the system.
-
Be a maintenance interrupt associated with a scheduled VM. See Maintenance interrupts for more details.
-
In GICv4, be a doorbell interrupt from an ITS. In GICv4, a virtual interrupt can be presented to a vPE without hypervisor involvement. A doorbell interrupt must be generated when a virtual interrupt is made pending for a vPE but the vPE is not scheduled on a PE.
-
The hypervisor handles physical interrupts according to the rules described in Chapter 4 Physical Interrupt Handling and Prioritization before they are virtualized. For information about the handling of physical interrupts and their virtualization during legacy operation, see Chapter 14 Legacy Operation and Asymmetric Configurations .
The GIC virtualization support includes a list of virtual interrupts for a vPE that is stored in hardware List registers, see Usage model for the List registers . Each entry in the list corresponds to either a pending or an active interrupt, and the entry describes the virtual interrupt number, the interrupt group, the interrupt state, and the virtual priority of the interrupt. A virtual interrupt described in the list entry can be configured to be associated with a physical SPI or PPI.
The GIC implementation selects the highest priority pending virtual interrupt from the list of interrupts held in the List registers and, if it is of sufficient virtual priority compared to the active virtual interrupts and virtual priority mask, presents it as either a virtual FIQ or a virtual IRQ, depending on the group of the interrupt. The virtual CPU interface controls apply to the virtual interrupt in the same way as the physical interrupt controls apply to the physical interrupt. Therefore, using the virtual CPU interface controls, software executing on the vPE can:
-
Set the virtual priority mask.
-
Control how the virtual priority is split between the group priority and the subpriority.
-
Acknowledge a virtual interrupt.
-
Perform a priority drop on the virtual interrupt.
-
Deactivate the virtual interrupt.
The virtual CPU interface supports both EOImodes, so that a virtual EOI can perform a priority drop alone, or a combined priority drop and deactivation.
When a virtual interrupt is acknowledged, then the state of the virtual interrupt changes from pending to active in the corresponding List register entry.
When a virtual interrupt is deactivated, then the state of the virtual interrupt changes from active to inactive, or from active and pending to pending, in the corresponding List register entry. If the virtual interrupt is associated with a physical interrupt, then the associated physical interrupt is deactivated. Virtual interrupts taken to EL1 are handled in a similar manner to physical interrupts that are handled in a system with a single Security state, that is where GICD_CTLR.DS is set to 1:
-
Group 0 interrupts are signaled using the virtual FIQ signal.
-
Group 1 interrupts are signaled using the virtual IRQ signal.
-
Group 0 and Group 1 interrupts share an interrupt prioritization and preemption scheme. A minimum of 32 and a maximum of 256 priority levels are supported, as determined by the values in ICH_VTR_EL2.
Note The priority value is not subject to the shift used for Non-secure physical interrupts. While virtualization supports up to 8 bits of priority, a minimum of 5 and a maximum of 8 bits must be implemented.
Note For information about the rules governing exception entry on an Armv8-A PE, see Arm[®] Architecture Reference Manual, Armv8, for Armv8-A architecture profile .
Accesses at EL1 to Group 0 registers are virtual when:
-
The current Security state is Non-secure and HCR_EL2.FMO == 1.
-
The current Security state is Secure, HCR_EL2.FMO == 1 and SCR_EL3.EEL2 == 1.
Virtual accesses to the following Group 0 ICC_* registers access the ICV_* equivalents:
-
Accesses to ICC_AP0R
_EL1 access ICV_AP0R _EL1. -
Accesses to ICC_BPR0_EL1 access ICV_BPR0_EL1.
-
Accesses to ICC_EOIR0_EL1 access ICV_EOIR0_EL1.
-
Accesses to ICC_HPPIR0_EL1 access ICV_HPPIR0_EL1.
-
Accesses to ICC_IAR0_EL1 access ICV_IAR0_EL1.
-
Accesses to ICC_IGRPEN0_EL1 access ICV_IGRPEN0_EL1.
Accesses at EL1 to Group 1 registers are virtual when:
-
The current Security state is Non-secure and HCR_EL2.IMO == 1.
-
The current Security state is Secure, HCR_EL2.IMO == 1 and SCR_EL3.EEL2 == 1.
Virtual accesses to the following Group 1 ICC_* registers access the ICV_* equivalents:
-
Accesses to ICC_AP1R
_EL1 access ICV_AP1R _EL1. -
Accesses to ICC_BPR1_EL1 access ICV_BPR1_EL1.
-
Accesses to ICC_EOIR1_EL1 access ICV_EOIR1_EL1.
-
Accesses to ICC_HPPIR1_EL1 access ICV_HPPIR1_EL1.
-
Accesses to ICC_IAR1_EL1 access ICV_IAR1_EL1.
-
Accesses to ICC_IGRPEN1_EL1 access ICV_IGRPEN1_EL1.
Accesses at EL1 to the common registers are virtual when:
-
The current Security state is Non-secure and (HCR_EL2.FMO == 1 || HCR_EL2.IMO == 1).
-
The current Security state is Secure, (HCR_EL2.FMO == 1 || HCR_EL2.IMO == 1) and SCR_EL3.EEL2 == 1.
Virtual accesses to the following Common ICC_* registers access the ICV_* equivalents:
-
Accesses to ICC_RPR_EL1 access ICV_RPR_EL1.
-
Accesses to ICC_CTLR_EL1 access ICV_CTLR_EL1.
-
Accesses to ICC_DIR_EL1 access ICV_DIR_EL1.
-
Accesses to ICC_PMR_EL1 access ICV_PMR_EL1.
A virtual write to ICC_SGI0R_EL1, ICC_SGI1R_EL1, or ICC_ASGI1R_EL1 traps to EL2.
Software executing at EL2 can access some ICV_* register state using ICH_VMCR_EL2 and ICH_VTR_EL2 as follows:
-
ICV_PMR_EL1.Priority aliases ICH_VMCR_EL2.VPMR.
-
ICV_BPR0_EL1.BinaryPoint aliases ICH_VMCR_EL2.VBPR0.
-
ICV_BPR1_EL1.BinaryPoint aliases ICH_VMCR_EL2.VBPR1.
-
ICV_CTLR_EL1.EOImode aliases ICH_VMCR_EL2.VEOIM.
-
ICV_CTLR_EL1.CBPR aliases ICH_VMCR_EL2.VCBPR.
-
ICV_IGRPEN0_EL1aliases ICH_VMCR_EL2.VENG0.
-
ICV_IGRPEN1_EL1. aliases ICH_VMCR_EL2.VENG1.
-
ICV_CTLR_EL1.PRIbits aliases ICH_VTR_EL2.PRIbits.
-
ICV_CTLR_EL1.IDbits aliases ICH_VTR_EL2.IDbits.
-
ICV_CTLR_EL1.SEIS aliases ICH_VTR_EL2.SEIS.
-
ICV_CTLR_EL1.A3V aliases ICH_VTR_EL2.A3V.
6.2.1 Usage model for the List registers
A fundamental function of an interrupt controller is to develop list of pending interrupts in priority order for each PE, and then to present the highest priority interrupt to the PE if the interrupt is of sufficient priority. For physical interrupts, this task is performed entirely in hardware by the GIC. However, in order to reduce the cost in hardware, the GIC handles virtual interrupts using both hardware and software.
For each physical interrupt received that is targeting a vPE, the hypervisor adds that interrupt to a prioritized list of pending virtual interrupts that is presented to the vPE. The GIC hardware also provides a set of List registers, ICH_LR
However, the total number of interrupts that are pending, active and pending, or active, can exceed the number of List registers available. In this case, the hypervisor can save one or more entries to memory, and later restore them to the List registers based on their priority. In this way, the List registers act as a cache for the list of pending, active, or active and pending interrupts that are controlled by software, for a vPE.
The List registers provide maintenance interrupts for:
-
The purpose of signaling when there are no pending interrupts in the List registers to allow the hypervisor to load more pending interrupts to the List registers.
-
The purpose of signaling when the List registers are empty or nearly empty to allow the hypervisor to refill the List registers with entries from the list in memory.
-
The purpose of signaling when an EOI has been received for an entry that is not in the List registers, which can occur if an active interrupt is held in memory.
-
The enabling and disabling of virtual interrupt groups, which might result in a requirement to change the content of the List registers.
For more details on maintenance interrupts, see Maintenance interrupts .
Note Although the List registers might include only active interrupts, with the hypervisor maintaining any pending interrupts in memory, a pending interrupt cannot be signaled to the vPE until the hypervisor adds it to the List registers. Therefore, to minimize interrupt latency and ensure the efficient operation of the vPE, Arm strongly recommends that the List registers contain at least one pending interrupt, if a List register is available for this interrupt.
The List registers form part of the context of the vPE. When there is switch from one vPE running on a PE to another vPE, the hypervisor switches the List registers accordingly.
The number of List registers is IMPLEMENTATION DEFINED, and can be discovered by reading ICH_VTR_EL2.
The following pseudocode indicates the number of List registers that are implemented.
// NumListRegs()
// =============
// The number of implemented List Registers. This value is IMPLEMENTATION DEFINED.
6.2.2 List register usage resulting in UNPREDICTABLE behavior
The following cases are considered software programming errors and result in UNPREDICTABLE behavior:
-
Having two or more interrupts with the same pINTID in the List registers for a single virtual CPU interface.
-
Having a List register entry with ICH_LR
_EL2.HW= 1, which is associated with a physical interrupt, in active state or in pending state in the List registers if the Distributor does not have the corresponding physical interrupt in either the active state or the active and pending state. -
If ICV_CTLR_EL1.EOImode ==0, then either:
-
Having an active interrupt in the List registers with a priority that is not set in the corresponding Active Priorities Register.
-
Having two interrupts in the List registers in the active state with the same preemption priority.
-
-
When GICv4 is supported, having a valid List register and an ITS mapping for a vPE that use the same vINTID.
-
When GICv4.1 is supported, having a valid List Register with vINTID set to an SGI and generating the same SGI for the vPE via the ITS.
6.3 Configuration and control of VMs
The virtual GIC works by holding a prioritized list of pending virtual interrupts for each PE. In GICv3 this list is compiled in software and a number of the top entries are held in List registers in hardware. For LPIs, this list can be compiled using tables for each vPE. These tables are controlled by the GICR_* registers.
A hypervisor uses a System register interface that is accessible at EL2 to switch context and to control multiple VMs. The context held in the ICH_* System registers is the context for the scheduled vPE. A vPE is scheduled when:
-
ICH_HCR_EL2.En == 1.
-
HCR_EL2.FMO == 1, when virtualizing Group 0 interrupts.
-
HCR_EL2.IMO == 1, when virtualizing Group 1 interrupts.
-
The PE is executing at EL1 and either:
-
SCR_EL3.NS == 1.
-
SCR_EL3.EEL2 == 1.
-
When a vPE is scheduled, the ICH_*_EL2 registers affect software executing at EL1.
The ICH_*_EL2 registers control and maintain a vPE as follows:
-
ICH_HCR_EL2 is used for the top-level configuration and control of virtual interrupts.
-
Information about the implementation, such as the size of the supported virtual INTIDs and the number of levels of prioritization is read from ICH_VTR_EL2.
-
A hypervisor can monitor and provide context for ICV_CTLR_EL1 using ICH_VMCR_EL2.
-
A set of List registers, ICH_LR
_EL2, are used by the hypervisor to forward a queue of pending interrupts to the PE, see Usage model for the List registers . The status of free locations in ICH_LR _EL2 is held in ICH_ELRSR_EL2. -
The end of interrupt status for the List registers is held in ICH_EISR_EL2.
-
The VM maintenance interrupt status is held in ICH_MISR_EL2.
-
The active priority status is held in:
-
ICH_AP0R
_EL2, where n = 0-3. -
ICH_AP1R
_EL2, where n = 0-3.
-
6.3.1 Association of virtual interrupts with physical interrupts
A virtual interrupt can become pending in response to a physical interrupt, where, for example, the physical interrupt is being used by a peripheral that is owned by a particular VM, or it can be generated for other reasons by the hypervisor where there is no corresponding physical interrupt. This second case can be used, for example, when the hypervisor emulates a virtual peripheral.
To support these two models, for SPIs and PPIs, the GIC List registers provide a mechanism to configure a virtual interrupt be associated with a physical interrupt. The physical interrupt and the virtual interrupt do not necessarily have the same INTID.
Usage model for associating a virtual interrupt with a physical interrupt
A virtual interrupt can be associated with a physical interrupt as follows:
-
The hypervisor configures ICC_CTLR_EL1.EOImode == 1, in this model.
-
On taking a physical PPI or a physical SPI that is targeting a vPE, the interrupt is taken to the hypervisor and is acknowledged by the hypervisor, making the physical interrupt active.
-
The hypervisor inserts a virtual interrupt to the list of pending interrupts for the targeted vPE. The hypervisor performs an EOI when it wants to do a priority drop for that interrupt. The hypervisor does not deactivate the interrupt.
-
When this virtual interrupt has a sufficiently high priority in the list of pending interrupts for that vPE, and that vPE is scheduled on the PE, the hypervisor writes this pending virtual interrupt into a List register, and ICH_LR
_EL2.HW is set to 1 to indicate that the virtual interrupt is associated with a physical interrupt. The INTID of the associated physical interrupt is held in the same List register. -
When the vPE is running, it will take the pending virtual interrupt, and acknowledge it in the same way as it would acknowledge a physical interrupt, using the virtual CPU interface. When the interrupt handler running on the vPE has completed its task, and the virtual interrupt is to be deactivated, then the hardware deactivates both the virtual interrupt and the associated physical interrupt. The virtual interrupt might be deactivated as the result of either an end of interrupt, if ICH_VMCR_EL2.VEOIM== 0, or as the result of a separate deactivation if ICH_VMCR_EL2.VEOIM == 1.
6.3.2 The Active Priorities registers
The active priority is held separately for virtual Group 0 and Group 1 interrupts, using ICH_AP0R
Table 6-1 Group bit count in the hypervisor Active Priorities Registers
| Bits | Register | Number of registers |
|---|---|---|
| 5 | ICH_AP0R | n = 0 |
| 6 | ICH_AP0R | n = 0-1 |
| 7 | ICH_AP0R | n = 0-3 |
If a bit is set to 1 in one of the ICH_AP0R
If a bit is set to 1 in one of the ICH_AP1R
ICH_AP0R
Note Writing to the Link registers does not have an effect on the Active Priorities Registers.
ICH_AP1R
Writing any value other than the last read value of the register, or 0x00000000, to these registers can cause:
-
Virtual interrupts that would otherwise preempt execution to not preempt execution.
-
Virtual interrupts that otherwise would not preempt execution to preempt execution at EL1 or EL0.
Note Arm does not expect these registers to be read and written by software for any purpose other than:
- Saving and restoring state, as part of software power management.
- Context switching between vPEs on the same PE.
Writing to the Active Priority Registers in any order other than the following order results in UNPREDICTABLE behavior:
-
ICH_AP0R
_EL2. -
ICH_AP1R
_EL2.
Note
An ISB is not required between the write to ICH_AP0R
6.3.3 Maintenance interrupts
Maintenance interrupts can signal key events in the operation of a GIC that implements virtualization. These events are processed by the hypervisor.
-
Note
-
Maintenance interrupts are generated only when the global enable bit for the virtual CPU interface, ICH_HCR_EL2.En, is set to 1.
-
Arm strongly recommends that maintenance interrupts are configured to use INTID 25. For more information, see Server Base System Architecture (SBSA) .
Maintenance interrupts are level-sensitive interrupts. Configuration bits in ICH_HCR_EL2 can be set to 1 to enable the generation of maintenance interrupts when:
-
Group 0 virtual interrupts are enabled.
-
Group 1 virtual interrupts are enabled.
-
Group 0 virtual interrupts are disabled.
-
Group 1 virtual interrupts are disabled.
-
There are no pending interrupts in the List registers.
-
At least one EOI request occurs with no valid List register entry for the corresponding interrupt.
-
There are no valid entries, or there is only one valid entry, in the List registers. This is an underflow condition.
-
At least one List register entry has received an EOI request.
See ICH_MISR_EL2, Interrupt Controller Maintenance Interrupt State Register for more information about the control and status reporting of maintenance interrupts.
6.4 Pseudocode
The following pseudocode indicates the number of virtual active priority bits.
// ActiveVirtualPRIBits()
// ======================
integer ActiveVirtualPRIBits()
if VirtualPRIBits() == 8 then
return 128;
else
return 2^(VirtualPREBits());
The following pseudocode indicates the highest active group virtual priority.
// GetHighestActiveVGroup()
// ========================
// Returns a value indicating the interrupt group of the highest priority
// bit set from two registers. Returns None if no bits are set.
IntGroup GetHighestActiveVGroup(bits(128) avp0, bits(128) avp1)
for rval = 0 to ActiveVirtualPRIBits() - 1
if avp0<rval> != '0' then
return IntGroup_G0;
elsif avp1<rval> != '0' then
return IntGroup_G1NS;
return IntGroup_None;
The following pseudocode indicates the highest active virtual priority.
// GetHighestActiveVPriority()
// ===========================
// Returns the index of the highest priority bit set from two registers.
// Returns 0xFF if no bits are set.
bits(8) GetHighestActiveVPriority(bits(128) avp0, bits(128) avp1)
for rval = 0 to ActiveVirtualPRIBits() - 1
if avp0<rval> != '0' || avp1<rval> != '0' then
return rval<7:0>;
return Ones();
The following pseudocode indicates whether any bits are set in the supplied Active Priorities registers.
// VPriorityBitsSet()
// ==================
// Returns TRUE if any bit is set in the supplied registers, FALSE otherwise
boolean VPriorityBitsSet(bits(128) avp0, bits(128) avp1)
for i = 0 to ActiveVirtualPRIBits() - 1
if avp0<i> != '0' || avp1<i> != '0' then
return TRUE;
return FALSE;
The following pseudocode clears the highest priority bit in the supplied virtual Active Priorities registers.
// VPriorityDrop()
// ===============
// Clears the highest priority bit set in the supplied registers.
VPriorityDrop[bits(128) &avp0, bits(128) &avp1] = bit v
assert IsZero(v);
for i = 0 to ActiveVirtualPRIBits() - 1
if avp0<i> != v then
avp0<i> = v;
The following pseudocode indicates the highest active group virtual priority.
// GetHighestActiveVGroup()
// ========================
// Returns TRUE if the value supplied has bits above the implemented range or
// if the value supplied exceeds the maximum configured size in the
// appropriate GITS_BASERn
boolean VCPUOutOfRange(bits(16) vcpu);
The following pseudocode indicates the highest active virtual priority.
// GetHighestActiveVPriority() // ===========================
// Returns the index of the highest priority bit set from two registers.
// Returns 0xFF if no bits are set.
bits(8) GetHighestActiveVPriority(bits(128) avp0,
bits(128) avp1) for rval = 0 to ActiveVirtualPRIBits() - 1
if avp0<rval> != '0' || avp1<rval> != '0'
then return rval<7:0>;
return Ones();
The following pseudocode indicates whether any bits are set in the supplied Active Priorities registers.
// VPriorityBitsSet()
// ==================
// Returns TRUE
if any bit is set in the supplied registers, FALSE otherwise
boolean VPriorityBitsSet(bits(128) avp0,
bits(128) avp1)
for i = 0 to ActiveVirtualPRIBits() - 1
if avp0<i> != '0' || avp1<i> != '0' then
return TRUE;
return FALSE;
The following pseudocode clears the highest priority bit in the supplied virtual Active Priorities registers.
// VPriorityDrop()
// ===============
// Clears the highest priority bit set in the supplied registers. VPriorityDrop[bits(128) &avp0,
bits(128) &avp1] = bit v
assert IsZero(v);
for i = 0 to ActiveVirtualPRIBits() - 1
if avp0<i> != v then avp0<i> = v;
return; elsif avp1<i> != v then avp1<i> = v; return;
return;
The following pseudocode determines which active bits are set.
// FindActiveVirtualInterrupt()
// ============================
// Find a matching List register. Returns -1 if there is no match.
integer FindActiveVirtualInterrupt(bits(INTID_SIZE) vID)
for i = 0 to NumListRegs() - 1
if ((ICH_LR_EL2[i].State IN {IntState_Active, IntState_ActivePending}) &&
ICH_LR_EL2[i].VirtualID<INTID_SIZE-1:0> == vID) then
return i;
return -1;
The following pseudocode indicates the virtual group priority based on the minimum Binary Point register.
// VPriorityGroup()
// ================
// Returns the priority group field for the minimum BPR value
bits(8) VPriorityGroup(bits(8) priority, integer group)
integer vpre_bits = VirtualPREBits();
mask = Ones(vpre_bits):Zeros(8 - vpre_bits);
return (priority AND mask);
The following pseudocode indicates the virtual group priority based on the appropriate Binary Point register.
// VGroupBits()
// ============
// Returns the priority group field for the current BPR value for the group
bits(8) VGroupBits(bits(8) priority, bit group)
if IsSecure() then
bpr = UInt(ICH_VMCR_EL2.VBPR1);
else
bpr = UInt(ICH_VMCR_EL2.VBPR1) -1;
if group == '0' || ICH_VMCR_EL2.VCBPR == '1' then
bpr = UInt(ICH_VMCR_EL2.VBPR0);
mask = Ones(7-bpr):Zeros(bpr+1);
return (priority AND mask);
The following pseudocode indicates the number of virtual ID bits.
// VIDBits()
// =========
integer VIDBits()
id_bits = ICH_VTR_EL2.IDbits;
case id_bits of
when '000' return 16;
when '001' return 24;
otherwise Unreachable();
The following pseudocode indicates the number of virtual preemption bits.
// VirtualPREBits()
// ================
integer VirtualPREBits()
The following pseudocode indicates the virtual group priority based on the minimum Binary Point register.
// VPriorityGroup()
// ================
// Returns the priority group field
for the minimum BPR value
bits(8) VPriorityGroup(bits(8) priority,
integer group)
integer vpre_bits = VirtualPREBits(); mask = Ones(vpre_bits):Zeros(8 - vpre_bits);
return (priority AND mask);
The following pseudocode indicates the virtual group priority based on the appropriate Binary Point register.
// VGroupBits()
// ============
// Returns the priority group field
for the current BPR value
for the group
bits(8) VGroupBits(bits(8) priority, bit group)
if IsSecure() then bpr = UInt(ICH_VMCR_EL2.VBPR1);
else bpr = UInt(ICH_VMCR_EL2.VBPR1) -1;
if group == '0' || ICH_VMCR_EL2.VCBPR == '1' then bpr = UInt(ICH_VMCR_EL2.VBPR0);
mask = Ones(7-bpr):Zeros(bpr+1); return (priority AND mask);
The following pseudocode indicates the number of virtual ID bits.
// VIDBits() // =========
integer VIDBits() id_bits = ICH_VTR_EL2.IDbits; case id_bits of when '000'
return 16; when '001'
return 24; otherwise Unreachable();
The following pseudocode indicates the number of virtual preemption bits.
// VirtualPREBits() // ================
integer VirtualPREBits()
return UInt(ICH_VTR_EL2.PREbits) + 1;
The following pseudocode indicates the number of virtual priority bits.
// VirtualPRIBits()
// ================
integer VirtualPRIBits()
return UInt(ICH_VTR_EL2.PRIbits) + 1;