I am trying to bring up xen suing u-boot that has this patch. Unfortunately as 
soon as the code tries to call _nonsec_init through secure_ram_addr in 
arm7_init_nonsec function in virt-v7.c I get an undefined instruction 
exception. I suspect the CONFIG_ARMV7_SECURE_BASE needs to be defined to a 
particular value. What should that be defined to for omap5432?
Surya

On Saturday, February 15, 2014 at 5:36:30 AM UTC-8, Marc Zyngier wrote:
> The current non-sec switching code suffers from one major issue:
> it cannot run in secure RAM, as a large part of u-boot still needs
> to be run while we're switched to non-secure.
> 
> This patch reworks the whole HYP/non-secure strategy by:
> - making sure the secure code is the *last* thing u-boot executes
>   before entering the payload
> - performing an exception return from secure mode directly into
>   the payload
> - allowing the code to be dynamically relocated to secure RAM
>   before switching to non-secure.
> 
> This involves quite a bit of horrible code, specially as u-boot
> relocation is quite primitive.
> 
> Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
> ---
>  arch/arm/cpu/armv7/nonsec_virt.S | 161 
> +++++++++++++++++++--------------------
>  arch/arm/cpu/armv7/virt-v7.c     |  59 +++++---------
>  arch/arm/include/asm/armv7.h     |  10 ++-
>  arch/arm/include/asm/secure.h    |  26 +++++++
>  arch/arm/lib/bootm.c             |  22 +++---
>  5 files changed, 138 insertions(+), 140 deletions(-)
>  create mode 100644 arch/arm/include/asm/secure.h
> 
> diff --git a/arch/arm/cpu/armv7/nonsec_virt.S 
> b/arch/arm/cpu/armv7/nonsec_virt.S
> index b5c946f..2a43e3c 100644
> --- a/arch/arm/cpu/armv7/nonsec_virt.S
> +++ b/arch/arm/cpu/armv7/nonsec_virt.S
> @@ -10,10 +10,13 @@
>  #include <linux/linkage.h>
>  #include <asm/gic.h>
>  #include <asm/armv7.h>
> +#include <asm/proc-armv/ptrace.h>
>  
>  .arch_extension sec
>  .arch_extension virt
>  
> +     .pushsection ._secure.text, "ax"
> +
>       .align  5
>  /* the vector table for secure state and HYP mode */
>  _monitor_vectors:
> @@ -22,51 +25,86 @@ _monitor_vectors:
>       adr pc, _secure_monitor
>       .word 0
>       .word 0
> -     adr pc, _hyp_trap
> +     .word 0
>       .word 0
>       .word 0
>  
> +.macro is_cpu_virt_capable   tmp
> +     mrc     p15, 0, \tmp, c0, c1, 1         @ read ID_PFR1
> +     and     \tmp, \tmp, #CPUID_ARM_VIRT_MASK        @ mask virtualization 
> bits
> +     cmp     \tmp, #(1 << CPUID_ARM_VIRT_SHIFT)
> +.endm
> +
>  /*
>   * secure monitor handler
>   * U-boot calls this "software interrupt" in start.S
>   * This is executed on a "smc" instruction, we use a "smc #0" to switch
>   * to non-secure state.
> - * We use only r0 and r1 here, due to constraints in the caller.
> + * r0, r1, r2: passed to the callee
> + * ip: target PC
>   */
>  _secure_monitor:
> -     mrc     p15, 0, r1, c1, c1, 0           @ read SCR
> -     bic     r1, r1, #0x4e                   @ clear IRQ, FIQ, EA, nET bits
> -     orr     r1, r1, #0x31                   @ enable NS, AW, FW bits
> +     mrc     p15, 0, r5, c1, c1, 0           @ read SCR
> +     bic     r5, r5, #0x4e                   @ clear IRQ, FIQ, EA, nET bits
> +     orr     r5, r5, #0x31                   @ enable NS, AW, FW bits
>  
> -     mrc     p15, 0, r0, c0, c1, 1           @ read ID_PFR1
> -     and     r0, r0, #CPUID_ARM_VIRT_MASK    @ mask virtualization bits
> -     cmp     r0, #(1 << CPUID_ARM_VIRT_SHIFT)
> +     mov     r6, #SVC_MODE                   @ default mode is SVC
> +     is_cpu_virt_capable r4
>  #ifdef CONFIG_ARMV7_VIRT
> -     orreq   r1, r1, #0x100                  @ allow HVC instruction
> +     orreq   r5, r5, #0x100                  @ allow HVC instruction
> +     moveq   r6, #HYP_MODE                   @ Enter the kernel as HYP
>  #endif
>  
> -     mcr     p15, 0, r1, c1, c1, 0           @ write SCR (with NS bit set)
> +     mcr     p15, 0, r5, c1, c1, 0           @ write SCR (with NS bit set)
>       isb
>  
> -#ifdef CONFIG_ARMV7_VIRT
> -     mrceq   p15, 0, r0, c12, c0, 1          @ get MVBAR value
> -     mcreq   p15, 4, r0, c12, c0, 0          @ write HVBAR
> -#endif
>       bne     1f
>  
>       @ Reset CNTVOFF to 0 before leaving monitor mode
> -     mrc     p15, 0, r0, c0, c1, 1           @ read ID_PFR1
> -     ands    r0, r0, #CPUID_ARM_GENTIMER_MASK        @ test arch timer bits
> -     movne   r0, #0
> -     mcrrne  p15, 4, r0, r0, c14             @ Reset CNTVOFF to zero
> +     mrc     p15, 0, r4, c0, c1, 1           @ read ID_PFR1
> +     ands    r4, r4, #CPUID_ARM_GENTIMER_MASK        @ test arch timer bits
> +     movne   r4, #0
> +     mcrrne  p15, 4, r4, r4, c14             @ Reset CNTVOFF to zero
>  1:
> -     movs    pc, lr                          @ return to non-secure SVC
> -
> -_hyp_trap:
> -     mrs     lr, elr_hyp     @ for older asm: .byte 0x00, 0xe3, 0x0e, 0xe1
> -     mov pc, lr                              @ do no switch modes, but
> -                                             @ return to caller
> -
> +     mov     lr, ip
> +     mov     ip, #(F_BIT | I_BIT | A_BIT)    @ Set A, I and F
> +     tst     lr, #1                          @ Check for Thumb PC
> +     orrne   ip, ip, #T_BIT                  @ Set T if Thumb
> +     orr     ip, ip, r6                      @ Slot target mode in
> +     msr     spsr_cxfs, ip                   @ Set full SPSR
> +     movs    pc, lr                          @ ERET to non-secure
> +
> +ENTRY(_do_nonsec_entry)
> +     mov     ip, r0
> +     mov     r0, r1
> +     mov     r1, r2
> +     mov     r2, r3
> +     smc     #0
> +ENDPROC(_do_nonsec_entry)
> +
> +.macro get_cbar_addr addr
> +#ifdef CONFIG_ARM_GIC_BASE_ADDRESS
> +     ldr     \addr, =CONFIG_ARM_GIC_BASE_ADDRESS
> +#else
> +     mrc     p15, 4, \addr, c15, c0, 0       @ read CBAR
> +     bfc     \addr, #0, #15                  @ clear reserved bits
> +#endif
> +.endm
> +
> +.macro get_gicd_addr addr
> +     get_cbar_addr   \addr
> +     add     \addr, \addr, #GIC_DIST_OFFSET  @ GIC dist i/f offset
> +.endm
> +
> +.macro get_gicc_addr addr, tmp
> +     get_cbar_addr   \addr
> +     is_cpu_virt_capable \tmp
> +     movne   \tmp, #GIC_CPU_OFFSET_A9        @ GIC CPU offset for A9
> +     moveq   \tmp, #GIC_CPU_OFFSET_A15       @ GIC CPU offset for A15/A7
> +     add     \addr, \addr, \tmp
> +.endm
> +
> +#ifndef CONFIG_ARMV7_PSCI
>  /*
>   * Secondary CPUs start here and call the code for the core specific parts
>   * of the non-secure and HYP mode transition. The GIC distributor specific
> @@ -74,31 +112,21 @@ _hyp_trap:
>   * Then they go back to wfi and wait to be woken up by the kernel again.
>   */
>  ENTRY(_smp_pen)
> -     mrs     r0, cpsr
> -     orr     r0, r0, #0xc0
> -     msr     cpsr, r0                        @ disable interrupts
> -     ldr     r1, =_start
> -     mcr     p15, 0, r1, c12, c0, 0          @ set VBAR
> +     cpsid   i
> +     cpsid   f
>  
>       bl      _nonsec_init
> -     mov     r12, r0                         @ save GICC address
> -#ifdef CONFIG_ARMV7_VIRT
> -     bl      _switch_to_hyp
> -#endif
> -
> -     ldr     r1, [r12, #GICC_IAR]            @ acknowledge IPI
> -     str     r1, [r12, #GICC_EOIR]           @ signal end of interrupt
>  
>       adr     r0, _smp_pen                    @ do not use this address again
>       b       smp_waitloop                    @ wait for IPIs, board specific
>  ENDPROC(_smp_pen)
> +#endif
>  
>  /*
>   * Switch a core to non-secure state.
>   *
>   *  1. initialize the GIC per-core interface
>   *  2. allow coprocessor access in non-secure modes
> - *  3. switch the cpu mode (by calling "smc #0")
>   *
>   * Called from smp_pen by secondary cores and directly by the BSP.
>   * Do not assume that the stack is available and only use registers
> @@ -108,38 +136,23 @@ ENDPROC(_smp_pen)
>   * though, but we check this in C before calling this function.
>   */
>  ENTRY(_nonsec_init)
> -#ifdef CONFIG_ARM_GIC_BASE_ADDRESS
> -     ldr     r2, =CONFIG_ARM_GIC_BASE_ADDRESS
> -#else
> -     mrc     p15, 4, r2, c15, c0, 0          @ read CBAR
> -     bfc     r2, #0, #15                     @ clear reserved bits
> -#endif
> -     add     r3, r2, #GIC_DIST_OFFSET        @ GIC dist i/f offset
> +     get_gicd_addr   r3
> +
>       mvn     r1, #0                          @ all bits to 1
>       str     r1, [r3, #GICD_IGROUPRn]        @ allow private interrupts
>  
> -     mrc     p15, 0, r0, c0, c0, 0           @ read MIDR
> -     ldr     r1, =MIDR_PRIMARY_PART_MASK
> -     and     r0, r0, r1                      @ mask out variant and revision
> +     get_gicc_addr   r3, r1
>  
> -     ldr     r1, =MIDR_CORTEX_A7_R0P0 & MIDR_PRIMARY_PART_MASK
> -     cmp     r0, r1                          @ check for Cortex-A7
> -
> -     ldr     r1, =MIDR_CORTEX_A15_R0P0 & MIDR_PRIMARY_PART_MASK
> -     cmpne   r0, r1                          @ check for Cortex-A15
> -
> -     movne   r1, #GIC_CPU_OFFSET_A9          @ GIC CPU offset for A9
> -     moveq   r1, #GIC_CPU_OFFSET_A15         @ GIC CPU offset for A15/A7
> -     add     r3, r2, r1                      @ r3 = GIC CPU i/f addr
> -
> -     mov     r1, #1                          @ set GICC_CTLR[enable]
> +     mov     r1, #3                          @ Enable both groups
>       str     r1, [r3, #GICC_CTLR]            @ and clear all other bits
>       mov     r1, #0xff
>       str     r1, [r3, #GICC_PMR]             @ set priority mask register
>  
> +     mrc     p15, 0, r0, c1, c1, 2
>       movw    r1, #0x3fff
> -     movt    r1, #0x0006
> -     mcr     p15, 0, r1, c1, c1, 2           @ NSACR = all copros to non-sec
> +     movt    r1, #0x0004
> +     orr     r0, r0, r1
> +     mcr     p15, 0, r0, c1, c1, 2           @ NSACR = all copros to non-sec
>  
>  /* The CNTFRQ register of the generic timer needs to be
>   * programmed in secure state. Some primary bootloaders / firmware
> @@ -157,21 +170,9 @@ ENTRY(_nonsec_init)
>  
>       adr     r1, _monitor_vectors
>       mcr     p15, 0, r1, c12, c0, 1          @ set MVBAR to secure vectors
> -
> -     mrc     p15, 0, ip, c12, c0, 0          @ save secure copy of VBAR
> -
>       isb
> -     smc     #0                              @ call into MONITOR mode
> -
> -     mcr     p15, 0, ip, c12, c0, 0          @ write non-secure copy of VBAR
> -
> -     mov     r1, #1
> -     str     r1, [r3, #GICC_CTLR]            @ enable non-secure CPU i/f
> -     add     r2, r2, #GIC_DIST_OFFSET
> -     str     r1, [r2, #GICD_CTLR]            @ allow private interrupts
>  
>       mov     r0, r3                          @ return GICC address
> -
>       bx      lr
>  ENDPROC(_nonsec_init)
>  
> @@ -183,18 +184,10 @@ ENTRY(smp_waitloop)
>       ldr     r1, [r1]
>       cmp     r0, r1                  @ make sure we dont execute this code
>       beq     smp_waitloop            @ again (due to a spurious wakeup)
> -     mov     pc, r1
> +     mov     r0, r1
> +     b       _do_nonsec_entry
>  ENDPROC(smp_waitloop)
>  .weak smp_waitloop
>  #endif
>  
> -ENTRY(_switch_to_hyp)
> -     mov     r0, lr
> -     mov     r1, sp                          @ save SVC copy of LR and SP
> -     isb
> -     hvc #0                   @ for older asm: .byte 0x70, 0x00, 0x40, 0xe1
> -     mov     sp, r1
> -     mov     lr, r0                          @ restore SVC copy of LR and SP
> -
> -     bx      lr
> -ENDPROC(_switch_to_hyp)
> +     .popsection
> diff --git a/arch/arm/cpu/armv7/virt-v7.c b/arch/arm/cpu/armv7/virt-v7.c
> index 2cd604f..6500030 100644
> --- a/arch/arm/cpu/armv7/virt-v7.c
> +++ b/arch/arm/cpu/armv7/virt-v7.c
> @@ -13,17 +13,10 @@
>  #include <asm/armv7.h>
>  #include <asm/gic.h>
>  #include <asm/io.h>
> +#include <asm/secure.h>
>  
>  unsigned long gic_dist_addr;
>  
> -static unsigned int read_cpsr(void)
> -{
> -     unsigned int reg;
> -
> -     asm volatile ("mrs %0, cpsr\n" : "=r" (reg));
> -     return reg;
> -}
> -
>  static unsigned int read_id_pfr1(void)
>  {
>       unsigned int reg;
> @@ -72,6 +65,18 @@ static unsigned long get_gicd_base_address(void)
>  #endif
>  }
>  
> +static void relocate_secure_section(void)
> +{
> +#ifdef CONFIG_ARMV7_SECURE_BASE
> +     size_t sz = __secure_end - __secure_start;
> +
> +     memcpy((void *)CONFIG_ARMV7_SECURE_BASE, __secure_start, sz);
> +     flush_dcache_range(CONFIG_ARMV7_SECURE_BASE,
> +                        CONFIG_ARMV7_SECURE_BASE + sz + 1);
> +     invalidate_icache_all();
> +#endif
> +}
> +
>  static void kick_secondary_cpus_gic(unsigned long gicdaddr)
>  {
>       /* kick all CPUs (except this one) by writing to GICD_SGIR */
> @@ -83,35 +88,7 @@ void __weak smp_kick_all_cpus(void)
>       kick_secondary_cpus_gic(gic_dist_addr);
>  }
>  
> -int armv7_switch_hyp(void)
> -{
> -     unsigned int reg;
> -
> -     /* check whether we are in HYP mode already */
> -     if ((read_cpsr() & 0x1f) == 0x1a) {
> -             debug("CPU already in HYP mode\n");
> -             return 0;
> -     }
> -
> -     /* check whether the CPU supports the virtualization extensions */
> -     reg = read_id_pfr1();
> -     if ((reg & CPUID_ARM_VIRT_MASK) != 1 << CPUID_ARM_VIRT_SHIFT) {
> -             printf("HYP mode: Virtualization extensions not 
> implemented.\n");
> -             return -1;
> -     }
> -
> -     /* call the HYP switching code on this CPU also */
> -     _switch_to_hyp();
> -
> -     if ((read_cpsr() & 0x1F) != 0x1a) {
> -             printf("HYP mode: switch not successful.\n");
> -             return -1;
> -     }
> -
> -     return 0;
> -}
> -
> -int armv7_switch_nonsec(void)
> +int armv7_init_nonsec(void)
>  {
>       unsigned int reg;
>       unsigned itlinesnr, i;
> @@ -147,11 +124,13 @@ int armv7_switch_nonsec(void)
>       for (i = 1; i <= itlinesnr; i++)
>               writel((unsigned)-1, gic_dist_addr + GICD_IGROUPRn + 4 * i);
>  
> -     smp_set_core_boot_addr((unsigned long)_smp_pen, -1);
> +#ifndef CONFIG_ARMV7_PSCI
> +     smp_set_core_boot_addr((unsigned long)secure_ram_addr(_smp_pen), -1);
>       smp_kick_all_cpus();
> +#endif
>  
>       /* call the non-sec switching code on this CPU also */
> -     _nonsec_init();
> -
> +     relocate_secure_section();
> +     secure_ram_addr(_nonsec_init)();
>       return 0;
>  }
> diff --git a/arch/arm/include/asm/armv7.h b/arch/arm/include/asm/armv7.h
> index 395444e..11476dd 100644
> --- a/arch/arm/include/asm/armv7.h
> +++ b/arch/arm/include/asm/armv7.h
> @@ -78,13 +78,17 @@ void v7_outer_cache_inval_range(u32 start, u32 end);
>  
>  #if defined(CONFIG_ARMV7_NONSEC) || defined(CONFIG_ARMV7_VIRT)
>  
> -int armv7_switch_nonsec(void);
> -int armv7_switch_hyp(void);
> +int armv7_init_nonsec(void);
>  
>  /* defined in assembly file */
>  unsigned int _nonsec_init(void);
> +void _do_nonsec_entry(void *target_pc, unsigned long r0,
> +                   unsigned long r1, unsigned long r2);
>  void _smp_pen(void);
> -void _switch_to_hyp(void);
> +
> +extern char __secure_start[];
> +extern char __secure_end[];
> +
>  #endif /* CONFIG_ARMV7_NONSEC || CONFIG_ARMV7_VIRT */
>  
>  #endif /* ! __ASSEMBLY__ */
> diff --git a/arch/arm/include/asm/secure.h b/arch/arm/include/asm/secure.h
> new file mode 100644
> index 0000000..effdb18
> --- /dev/null
> +++ b/arch/arm/include/asm/secure.h
> @@ -0,0 +1,26 @@
> +#ifndef __ASM_SECURE_H
> +#define __ASM_SECURE_H
> +
> +#include <config.h>
> +
> +#ifdef CONFIG_ARMV7_SECURE_BASE
> +/*
> + * Warning, horror ahead.
> + *
> + * The target code lives in our "secure ram", but u-boot doesn't know
> + * that, and has blindly added reloc_off to every relocation
> + * entry. Gahh. Do the opposite conversion. This hack also prevents
> + * GCC from generating code veeners, which u-boot doesn't relocate at
> + * all...
> + */
> +#define secure_ram_addr(_fn) ({                                              
> \
> +                     DECLARE_GLOBAL_DATA_PTR;                        \
> +                     void *__fn = _fn;                               \
> +                     typeof(_fn) *__tmp = (__fn - gd->reloc_off);    \
> +                     __tmp;                                          \
> +             })
> +#else
> +#define secure_ram_addr(_fn) (_fn)
> +#endif
> +
> +#endif
> diff --git a/arch/arm/lib/bootm.c b/arch/arm/lib/bootm.c
> index 68554c8..ecc25f9 100644
> --- a/arch/arm/lib/bootm.c
> +++ b/arch/arm/lib/bootm.c
> @@ -20,6 +20,7 @@
>  #include <libfdt.h>
>  #include <fdt_support.h>
>  #include <asm/bootm.h>
> +#include <asm/secure.h>
>  #include <linux/compiler.h>
>  
>  #if defined(CONFIG_ARMV7_NONSEC) || defined(CONFIG_ARMV7_VIRT)
> @@ -185,26 +186,16 @@ static void setup_end_tag(bd_t *bd)
>  
>  __weak void setup_board_tags(struct tag **in_params) {}
>  
> +#ifdef CONFIG_ARM64
>  static void do_nonsec_virt_switch(void)
>  {
> -#if defined(CONFIG_ARMV7_NONSEC) || defined(CONFIG_ARMV7_VIRT)
> -     if (armv7_switch_nonsec() == 0)
> -#ifdef CONFIG_ARMV7_VIRT
> -             if (armv7_switch_hyp() == 0)
> -                     debug("entered HYP mode\n");
> -#else
> -             debug("entered non-secure state\n");
> -#endif
> -#endif
> -
> -#ifdef CONFIG_ARM64
>       smp_kick_all_cpus();
>       armv8_switch_to_el2();
>  #ifdef CONFIG_ARMV8_SWITCH_TO_EL1
>       armv8_switch_to_el1();
>  #endif
> -#endif
>  }
> +#endif
>  
>  /* Subcommand: PREP */
>  static void boot_prep_linux(bootm_headers_t *images)
> @@ -287,8 +278,13 @@ static void boot_jump_linux(bootm_headers_t *images, int 
> flag)
>               r2 = gd->bd->bi_boot_params;
>  
>       if (!fake) {
> -             do_nonsec_virt_switch();
> +#if defined(CONFIG_ARMV7_NONSEC) || defined(CONFIG_ARMV7_VIRT)
> +             armv7_init_nonsec();
> +             secure_ram_addr(_do_nonsec_entry)(kernel_entry,
> +                                               0, machid, r2);
> +#else
>               kernel_entry(0, machid, r2);
> +#endif
>       }
>  #endif
>  }
> -- 
> 1.8.5.1

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to