[U-Boot] [PATCH v4 1/2] armv8: Support loading 32-bit OS in AArch32 execution state

Alexander Graf agraf at suse.de
Thu Jun 30 10:41:47 CEST 2016



On 30.06.16 09:16, Huan Wang wrote:
> Hi, Alex,
> 
>>> Am 15.06.2016 um 05:04 schrieb Huan Wang <alison.wang at nxp.com>:
>>>
>>> Hi, Alex,
>>>
>>>>> On 06/08/2016 07:14 AM, Alison Wang wrote:
>>>>> To support loading a 32-bit OS, the execution state will change from
>>>>> AArch64 to AArch32 when jumping to kernel.
>>>>>
>>>>> The architecture information will be got through checking FIT image,
>>>>> then U-Boot will load 32-bit OS or 64-bit OS automatically.
>>>>>
>>>>> Signed-off-by: Ebony Zhu <ebony.zhu at nxp.com>
>>>>> Signed-off-by: Alison Wang <alison.wang at nxp.com>
>>>>> Signed-off-by: Chenhui Zhao <chenhui.zhao at nxp.com>
>>>>> ---
>>>>> Changes in v4:
>>>>> - Correct config ARM64_SUPPORT_AARCH32.
>>>>> - Omit arch and ftaddr arguments.
>>>>> - Rename "xreg5" to "tmp".
>>>>> - Use xxx_RES1 to combine all RES1 fields in xxx register.
>>>>> - Use an immediate cmp directly.
>>>>> - Use #ifdef for CONFIG_ARM64_SUPPORT_AARCH32.
>>>>>
>>>>> Changes in v3:
>>>>> - Comments the functions and the arguments.
>>>>> - Rename the real parameters.
>>>>> - Use the macros instead of the magic values.
>>>>> - Remove the redundant codes.
>>>>> - Clean up all of the mess in boot_jump_linux().
>>>>> - Add CONFIG_ARM64_SUPPORT_AARCH32 to detect for some ARM64 system
>>>> doesn't support AArch32 state.
>>>>>
>>>>> Changes in v2:
>>>>> - armv8_switch_to_el2_aarch32() is removed. armv8_switch_to_el2_m is
>>>> used
>>>>>   to switch to AArch64 EL2 or AArch32 Hyp.
>>>>> - armv8_switch_to_el1_aarch32() is removed. armv8_switch_to_el1_m is
>>>> used
>>>>>   to switch to AArch64 EL1 or AArch32 SVC.
>>>>>
>>>>>  arch/arm/Kconfig                |   6 ++
>>>>>  arch/arm/cpu/armv8/start.S      |   1 +
>>>>>  arch/arm/cpu/armv8/transition.S |   8 +-
>>>>>  arch/arm/include/asm/macro.h    | 172
>>>> ++++++++++++++++++++++++++++++----------
>>>>>  arch/arm/include/asm/system.h   | 111 +++++++++++++++++++++++++-
>>>>>  arch/arm/lib/bootm.c            |  19 ++++-
>>>>>  common/image-fit.c              |  19 ++++-
>>>>>  7 files changed, 284 insertions(+), 52 deletions(-)
>>>>>
>>>>> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index
>>>>> 77eab66..9cf4acd 100644
>>>>> --- a/arch/arm/Kconfig
>>>>> +++ b/arch/arm/Kconfig
>>>>> @@ -91,6 +91,12 @@ config SYS_L2CACHE_OFF
>>>>>        If SoC does not support L2CACHE or one do not want to enable
>>>>>        L2CACHE, choose this option.
>>>>>
>>>>> +config ARM64_SUPPORT_AARCH32
>>>>> +    bool "ARM64 system support AArch32 execution state"
>>>>> +    default y if ARM64 && !TARGET_THUNDERX_88XX
>>>>> +    help
>>>>> +      This ARM64 system supports AArch32 execution state.
>>>>> +
>>>>>  choice
>>>>>      prompt "Target select"
>>>>>      default TARGET_HIKEY
>>>>> diff --git a/arch/arm/cpu/armv8/start.S b/arch/arm/cpu/armv8/start.S
>>>>> index e933021..dd69501 100644
>>>>> --- a/arch/arm/cpu/armv8/start.S
>>>>> +++ b/arch/arm/cpu/armv8/start.S
>>>>> @@ -234,6 +234,7 @@ WEAK(lowlevel_init)
>>>>>      /*
>>>>>       * All slaves will enter EL2 and optionally EL1.
>>>>>       */
>>>>> +    ldr    x3, =ES_TO_AARCH64
>>>>>      bl    armv8_switch_to_el2
>>>>>  #ifdef CONFIG_ARMV8_SWITCH_TO_EL1
>>>>>      bl    armv8_switch_to_el1
>>>>> diff --git a/arch/arm/cpu/armv8/transition.S
>>>> b/arch/arm/cpu/armv8/transition.S
>>>>> index 253a39b..e61b6ae 100644
>>>>> --- a/arch/arm/cpu/armv8/transition.S
>>>>> +++ b/arch/arm/cpu/armv8/transition.S
>>>>> @@ -11,13 +11,13 @@
>>>>>  #include <asm/macro.h>
>>>>>
>>>>>  ENTRY(armv8_switch_to_el2)
>>>>> -    switch_el x0, 1f, 0f, 0f
>>>>> +    switch_el x4, 1f, 0f, 0f
>>>>>  0:    ret
>>>>> -1:    armv8_switch_to_el2_m x0
>>>>> +1:    armv8_switch_to_el2_m x0, x3, x4
>>>>>  ENDPROC(armv8_switch_to_el2)
>>>>>
>>>>>  ENTRY(armv8_switch_to_el1)
>>>>> -    switch_el x0, 0f, 1f, 0f
>>>>> +    switch_el x4, 0f, 1f, 0f
>>>>>  0:    ret
>>>>> -1:    armv8_switch_to_el1_m x0, x1
>>>>> +1:    armv8_switch_to_el1_m x0, x3, x4
>>>>>  ENDPROC(armv8_switch_to_el1)
>>>>> diff --git a/arch/arm/include/asm/macro.h
>>>> b/arch/arm/include/asm/macro.h
>>>>> index 9bb0efa..109724f 100644
>>>>> --- a/arch/arm/include/asm/macro.h
>>>>> +++ b/arch/arm/include/asm/macro.h
>>>>> @@ -8,6 +8,9 @@
>>>>>
>>>>>  #ifndef __ASM_ARM_MACRO_H__
>>>>>  #define __ASM_ARM_MACRO_H__
>>>>> +
>>>>> +#include <asm/system.h>
>>>>> +
>>>>>  #ifdef __ASSEMBLY__
>>>>>
>>>>>  /*
>>>>> @@ -135,13 +138,20 @@ lr    .req    x30
>>>>>  #endif
>>>>>  .endm
>>>>>
>>>>> -.macro armv8_switch_to_el2_m, xreg1
>>>>> -    /* 64bit EL2 | HCE | SMD | RES1 (Bits[5:4]) | Non-secure
>> EL0/EL1
>>>> */
>>>>> -    mov    \xreg1, #0x5b1
>>>>> -    msr    scr_el3, \xreg1
>>>>> +/*
>>>>> + * Switch from EL3 to EL2 for ARMv8
>>>>> + * @ep:     kernel entry point
>>>>> + * @flag:   The execution state flag for lower exception
>>>>> + *          level, ES_TO_AARCH64 or ES_TO_AARCH32
>>>>> + * @tmp:    temporary register
>>>>> + *
>>>>> + * x1 is machine nr and x2 is ftaddr, they will be passed
>>>>> + * to the guest.
>>>>> + */
>>>>> +.macro armv8_switch_to_el2_m, ep, flag, tmp
>>>>>      msr    cptr_el3, xzr        /* Disable coprocessor traps to EL3
>>>> */
>>>>> -    mov    \xreg1, #0x33ff
>>>>> -    msr    cptr_el2, \xreg1    /* Disable coprocessor traps to EL2
>> */
>>>>> +    mov    \tmp, #CPTR_EL2_RES1
>>>>> +    msr    cptr_el2, \tmp        /* Disable coprocessor traps to
>> EL2
>>>> */
>>>>>
>>>>>      /* Initialize Generic Timers */
>>>>>      msr    cntvoff_el2, xzr
>>>>> @@ -152,45 +162,91 @@ lr    .req    x30
>>>>>       * and RES0 bits (31,30,27,26,24,21,20,17,15-13,10-6) +
>>>>>       * EE,WXN,I,SA,C,A,M to 0
>>>>>       */
>>>>> -    mov    \xreg1, #0x0830
>>>>> -    movk    \xreg1, #0x30C5, lsl #16
>>>>> -    msr    sctlr_el2, \xreg1
>>>>> +    ldr    \tmp, =(SCTLR_EL2_RES1 | SCTLR_EL2_EE_LE |\
>>>>> +            SCTLR_EL2_WXN_DIS | SCTLR_EL2_ICACHE_DIS |\
>>>>> +            SCTLR_EL2_SA_DIS | SCTLR_EL2_DCACHE_DIS |\
>>>>> +            SCTLR_EL2_ALIGN_DIS | SCTLR_EL2_MMU_DIS)
>>>>> +    msr    sctlr_el2, \tmp
>>>>> +
>>>>> +    mov    \tmp, sp
>>>>> +    msr    sp_el2, \tmp        /* Migrate SP */
>>>>> +    mrs    \tmp, vbar_el3
>>>>> +    msr    vbar_el2, \tmp        /* Migrate VBAR */
>>>>> +
>>>>> +    /* Check switch to AArch64 EL2 or AArch32 Hypervisor mode */
>>>>> +    cmp    \flag, #ES_TO_AARCH32
>>>>> +    b.eq    1f
>>>>> +
>>>>> +    /*
>>>>> +     * The next lower exception level is AArch64, 64bit EL2 | HCE |
>>>>> +     * SMD | RES1 (Bits[5:4]) | Non-secure EL0/EL1.
>>>>> +     */
>>>>> +    ldr    \tmp, =(SCR_EL3_RW_AARCH64 | SCR_EL3_HCE_EN |\
>>>>> +            SCR_EL3_SMD_DIS | SCR_EL3_RES1 |\
>>>>> +            SCR_EL3_NS_EN)
>>>>> +    msr    scr_el3, \tmp
>>>>>
>>>>>      /* Return to the EL2_SP2 mode from EL3 */
>>>>> -    mov    \xreg1, sp
>>>>> -    msr    sp_el2, \xreg1        /* Migrate SP */
>>>>> -    mrs    \xreg1, vbar_el3
>>>>> -    msr    vbar_el2, \xreg1    /* Migrate VBAR */
>>>>> -    mov    \xreg1, #0x3c9
>>>>> -    msr    spsr_el3, \xreg1    /* EL2_SP2 | D | A | I | F */
>>>>> +    ldr    \tmp, =(SPSR_EL_DEBUG_MASK | SPSR_EL_SERR_MASK |\
>>>>> +            SPSR_EL_IRQ_MASK | SPSR_EL_FIQ_MASK |\
>>>>> +            SPSR_EL_M_AARCH64 | SPSR_EL_M_EL2H)
>>>>> +    msr    spsr_el3, \tmp
>>>>>      msr    elr_el3, lr
>>>>
>>>> So if we switch into AArch64 mode, we return ...
>>>>
>>>>>      eret
>>>>> +
>>>>> +1:
>>>>> +    /*
>>>>> +     * The next lower exception level is AArch32, 32bit EL2 | HCE |
>>>>> +     * SMD | RES1 (Bits[5:4]) | Non-secure EL0/EL1.
>>>>> +     */
>>>>> +    ldr    \tmp, =(SCR_EL3_RW_AARCH32 | SCR_EL3_HCE_EN |\
>>>>> +            SCR_EL3_SMD_DIS | SCR_EL3_RES1 |\
>>>>> +            SCR_EL3_NS_EN)
>>>>> +    msr    scr_el3, \tmp
>>>>> +
>>>>> +    /* Return to AArch32 Hypervisor mode */
>>>>> +    ldr     \tmp, =(SPSR_EL_END_LE | SPSR_EL_ASYN_MASK |\
>>>>> +            SPSR_EL_IRQ_MASK | SPSR_EL_FIQ_MASK |\
>>>>> +            SPSR_EL_T_A32 | SPSR_EL_M_AARCH32 |\
>>>>> +            SPSR_EL_M_HYP)
>>>>> +    msr    spsr_el3, \tmp
>>>>> +    msr     elr_el3, \ep
>>>>> +
>>>>> +    mov    \ep, #0
>>>>
>>>> ... while if we switch to AArch32 mode we jump to ep.
>>>>
>>>> I think it would make a lot of sense if we could *always* jump to ep.
>>>> Just swizzle the argument order so that you get
>>>>
>>>>                if ((IH_ARCH_DEFAULT == IH_ARCH_ARM64) &&
>>>>                    (images->os.arch == IH_ARCH_ARM))
>>>>                        armv8_switch_to_el2(0, gd->bd->bi_arch_number,
>>>> (uintptr_t)images->ft_addr, (u64)images->ep, ES_TO_AARCH32);
>>>>                else
>>>> armv8_switch_to_el2((uintptr_t)images->ft_addr, 0 0, images->ep,
>>>> ES_TO_AARCH64);
>>> [Alison Wang] I don't agree it would make a lot of sense if we could
>>> *always* jump to ep.
>>> If we switch to EL2 AArch32 mode, it will happen at the last minute
>>> from U-Boot to kernel. The ep is the entry pointer for kernel.
>>> If we switch to EL2 AArch64 mode, it will happen earlier. For primary
>>> core, it will call kernel entry after the switch. For secondary cores,
>>> it will switch from EL3 AArch64 to EL2 AArch64 first, then it will
>>> wait until the spin-table is written by the kernel, later it will jump
>> to kernel.
>>
>> Then jump to a separate function that continues the execution stream. I
>> really think we should keep the interface between both flags as
>> identical as possible.
> [Alison Wang] I think you are right. I will change the code to *always*
> jump to ep in v5.
>>
>>>>
>>>> If you *really really really* are attached to booting into EL1, just
>>>> add a small function that calls armv8_switch_to_el1() for you and
>>>> pass the pointer to that as ep to the el2 switch. If I were you I'd
>>>> just remove the EL1 mess.
>>> [Alison Wang] I agreed with you to remove the EL1 mess.
>>
>> Awesome, thanks.
> [Alison Wang] When I tried to remove the EL1 mess, I found CONFIG_ARMV8_SWITCH_TO_EL1
> is enabled for Versatile Express Aemv8a. If that platform uses it, I have a concern
> about removing it.

Do you have access to the respective simulator? It's probably only
enabled because in the very very very early days of Linux bringup Linux
didn't know how to run in EL2 yet. So we can probably just drop it.

But let's CC people who might know :).


Alex


More information about the U-Boot mailing list