[PATCH v2 4/6] aarch64: Introduce EL2 boot code for Armv8-R AArch64
Luca Fancellu
Luca.Fancellu at arm.com
Mon Jul 29 08:27:37 PDT 2024
Hi Mark,
>> * - EL2 (Non-secure)
>> - * Entering at EL2 is partially supported.
>> + * Entering at EL2 is partially supported for Armv8-A.
>> + * Entering at EL2 is supported for Armv8-R.
>
> Nit: IIUC ARMv8-R is Secure-only, so this isn't quite right.
Ok I’ll drop this change
>
>> * PSCI is not supported when entered in this exception level.
>> */
>> ASM_FUNC(_start)
>> @@ -76,6 +77,39 @@ reset_at_el2:
>> msr sctlr_el2, x0
>> isb
>>
>> + /* Detect Armv8-R AArch64 */
>> + mrs x1, id_aa64mmfr0_el1
>> + /*
>> + * Check MSA, bits [51:48]:
>> + * 0xf means Armv8-R AArch64.
>> + * If not 0xf, proceed in Armv8-A EL2.
>> + */
>> + ubfx x0, x1, #48, #4 // MSA
>> + cmp x0, 0xf
>> + bne reset_no_el3
>> +
>> + /*
>> + * Armv8-R AArch64 is found, check if Linux can be booted.
>> + * Check MSA_frac, bits [55:52]:
>> + * 0x2 means EL1&0 translation regime also supports VMSAv8-64.
>> + */
>> + ubfx x0, x1, #52, #4 // MSA_frac
>> + cmp x0, 0x2
>> + /*
>> + * If not 0x2, no VMSA, so cannot boot Linux and dead loop.
>> + * Also, since the architecture guarantees that those CPUID
>> + * fields never lose features when the value in a field
>> + * increases, we use blt to cover it.
>> + */
>> + blt err_invalid_arch
>> +
>> + /* Start Armv8-R Linux at EL1 */
>> + mov w0, #SPSR_KERNEL_EL1
>> + ldr x1, =spsr_to_elx
>> + str w0, [x1]
>
> I'd prefer if we could do this in C code. I'll post a series shortly
> where we'll have consistent cpu_init_arch() hook that we can do this
> under.
Ok are you suggesting to base this serie on the one you’ll push?
>>
>>
>> +void cpu_init_armv8r_el2(void)
>> +{
>> + unsigned long hcr = mrs(hcr_el2);
>> +
>> + msr(vpidr_el2, mrs(midr_el1));
>> + msr(vmpidr_el2, mrs(mpidr_el1));
>> +
>> + /* VTCR_MSA: VMSAv8-64 support */
>> + msr(vtcr_el2, VTCR_EL2_MSA);
>
> I suspect we also need to initialize VSTCR_EL2?
Ok, I’ve booted Linux and it seems to work fine, is this considered at all when HCR_EL2.VM is off?
Anyway I’ll initialise it, I noticed it’s not done in TF-A.
>
> ... and don't we also need to initialize VSCTLR_EL2 to give all CPUs the
> same VMID? Otherwise barriers won't work at EL1 and below...
I can see TF-A is initialising it so I’ll do the same
>
>> +
>> + /*
>> + * HCR_EL2.ENSCXT is written unconditionally even if in some cases it's
>> + * RES0 (when FEAT_CSV2_2 or FEAT_CSV2_1p2 are not implemented) in order
>> + * to simplify the code, but it's safe in this case as the write would be
>> + * ignored when not implemented and would remove the trap otherwise.
>> + */
>> + hcr |= HCR_EL2_ENSCXT_NOTRAP;
>
> I'd prefer if we can do the necessary checks. IIUC we can do this with a
> helper, e.g.
>
> static bool cpu_has_scxt(void)
> {
> unsigned long csv2 = mrs_field(ID_AA64PFR0_EL1, CSV2);
> if (csv2 >= 2)
> return true;
> if (csv2 < 1)
> return false;
> return mrs_field(ID_AA64PFR1_EL1, CSV2_frac) >= 2;
> }
>
> ... then here we can have:
>
> if (cpu_has_scxt())
> hcr |= HCR_EL2_ENSCXT_NOTRAP;
Ok I’ll do
>
>> +
>> + if (mrs_field(ID_AA64PFR0_EL1, RAS) >= 2)
>> + hcr |= HCR_EL2_FIEN_NOTRAP;
>> +
>> + if (cpu_has_pauth())
>> + hcr |= HCR_EL2_APK_NOTRAP | HCR_EL2_API_NOTRAP;
>> +
>> + msr(hcr_el2, hcr);
>> + isb();
>> + msr(CNTFRQ_EL0, COUNTER_FREQ);
>> +}
>
> I believe we also need to initialize:
>
> * CNTVOFF_EL2 (for timers to work correctly)
> * CNTHCTL_EL2 (for timers to not trap)
> * CPTR_EL2 (for FP to not trap)
> * MDCR_EL2 (for PMU & debug to not trap)
Sure, I’ll reset them like in TF-A.
Thanks fo your review!
Cheers,
Luca
More information about the linux-arm-kernel
mailing list