/* * Compliant CPUs advertise their VHE-onlyness with * ID_AA64MMFR4_EL1.E2H0 < 0. On such CPUs HCR_EL2.E2H is RES1, but it * can reset into an UNKNOWN state and might not read as 1 until it has * been initialized explicitly. * * Fruity CPUs seem to have HCR_EL2.E2H set to RAO/WI, but * don't advertise it (they predate this relaxation). * * Initalize HCR_EL2.E2H so that later code can rely upon HCR_EL2.E2H * indicating whether the CPU is running in E2H mode.
*/
mrs_s x1, SYS_ID_AA64MMFR4_EL1
sbfx x1, x1, #ID_AA64MMFR4_EL1_E2H0_SHIFT, #ID_AA64MMFR4_EL1_E2H0_WIDTH
cmp x1, #0
b.ge .LnVHE_\@
/* Check if running in host at EL2 mode, i.e., (h)VHE. Jump to fail if not. */
.macro __check_hvhe fail, tmp
mrs \tmp, hcr_el2 and \tmp, \tmp, #HCR_E2H
cbz \tmp, \fail
.endm
/* * Allow Non-secure EL1 and EL0 to access physical timer and counter. * This is not necessary for VHE, since the host kernel runs in EL2, * and EL0 accesses are configured in the later stage of boot process. * Note that when HCR_EL2.E2H == 1, CNTHCTL_EL2 has the same bit layout * as CNTKCTL_EL1, and CNTKCTL_EL1 accessing instructions are redefined * to access CNTHCTL_EL2. This allows the kernel designed to run at EL1 * to transparently mess with the EL0 bits via CNTKCTL_EL1 access in * EL2.
*/
.macro __init_el2_timers
mov x0, #3// Enable EL1 physical timers
__check_hvhe .LnVHE_\@, x1
lsl x0, x0, #10
.LnVHE_\@:
msr cnthctl_el2, x0
msr cntvoff_el2, xzr // Clear virtual offset
.endm
.macro __init_el2_debug
mrs x1, id_aa64dfr0_el1
ubfx x0, x1, #ID_AA64DFR0_EL1_PMUVer_SHIFT, #4
cmp x0, #ID_AA64DFR0_EL1_PMUVer_NI
ccmp x0, #ID_AA64DFR0_EL1_PMUVer_IMP_DEF, #4, ne
b.eq .Lskip_pmu_\@ // Skip if no PMU present or IMP_DEF
mrs x0, pmcr_el0 // Disable debug access traps
ubfx x0, x0, #11, #5// to EL2 and allow access to
.Lskip_pmu_\@:
csel x2, xzr, x0, eq // all PMU counters from EL1
/* Statistical profiling */
ubfx x0, x1, #ID_AA64DFR0_EL1_PMSVer_SHIFT, #4
cbz x0, .Lskip_spe_\@ // Skip if SPE not present
mrs_s x0, SYS_PMBIDR_EL1 // If SPE available at EL2, and x0, x0, #(1 << PMBIDR_EL1_P_SHIFT)
cbnz x0, .Lskip_spe_el2_\@ // then permit sampling of physical
mov x0, #(1 << PMSCR_EL2_PCT_SHIFT | \
1 << PMSCR_EL2_PA_SHIFT)
msr_s SYS_PMSCR_EL2, x0 // addresses and physical counter
.Lskip_spe_el2_\@:
mov x0, #MDCR_EL2_E2PB_MASK
orr x2, x2, x0 // If we don't have VHE, then // use EL1&0 translation.
.Lskip_spe_\@: /* Trace buffer */
ubfx x0, x1, #ID_AA64DFR0_EL1_TraceBuffer_SHIFT, #4
cbz x0, .Lskip_trace_\@ // Skip if TraceBuffer is not present
mrs_s x0, SYS_TRBIDR_EL1 and x0, x0, TRBIDR_EL1_P
cbnz x0, .Lskip_trace_\@ // If TRBE is available at EL2
mov x0, #MDCR_EL2_E2TB_MASK
orr x2, x2, x0 // allow the EL1&0 translation // to own it.
/* * Configure BRBE to permit recording cycle counts and branch mispredicts. * * At any EL, to record cycle counts BRBE requires that both BRBCR_EL2.CC=1 and * BRBCR_EL1.CC=1. * * At any EL, to record branch mispredicts BRBE requires that both * BRBCR_EL2.MPRED=1 and BRBCR_EL1.MPRED=1. * * Set {CC,MPRED} in BRBCR_EL2 in case nVHE mode is used and we are * executing in EL1.
*/
.macro __init_el2_brbe
mrs x1, id_aa64dfr0_el1
ubfx x1, x1, #ID_AA64DFR0_EL1_BRBE_SHIFT, #4
cbz x1, .Lskip_brbe_\@
/* Disable trapping of POR_EL0 */
orr x0, x0, #HFGRTR_EL2_nPOR_EL0
.Lskip_poe_fgt_\@: /* GCS depends on PIE so we don't check it if PIE is absent */
mrs_s x1, SYS_ID_AA64PFR1_EL1
ubfx x1, x1, #ID_AA64PFR1_EL1_GCS_SHIFT, #4
cbz x1, .Lskip_gce_fgt_\@
/* Disable traps of access to GCS registers at EL0 and EL1 */
orr x0, x0, #HFGRTR_EL2_nGCS_EL1_MASK
orr x0, x0, #HFGRTR_EL2_nGCS_EL0_MASK
/** * Initialize EL2 registers to sane values. This should be called early on all * cores that were booted in EL2. Note that everything gets initialised as * if VHE was not available. The kernel context will be upgraded to VHE * if possible later on in the boot process * * Regs: x0, x1 and x2 are clobbered.
*/
.macro init_el2_state
__init_el2_sctlr
__init_el2_hcrx
__init_el2_timers
__init_el2_debug
__init_el2_brbe
__init_el2_lor
__init_el2_stage2
__init_el2_gicv3
__init_el2_gicv5
__init_el2_hstr
__init_el2_nvhe_idregs
__init_el2_cptr
__init_el2_fgt
__init_el2_fgt2
.endm
#ifndef __KVM_NVHE_HYPERVISOR__ // This will clobber tmp1 and tmp2, and expect tmp1 to contain // the id register value as read from the HW
.macro __check_override idreg, fld, width, pass, fail, tmp1, tmp2
ubfx \tmp1, \tmp1, #\fld, #\width
cbz \tmp1, \fail
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.