[U-Boot] [PATCH 5/6] ARM: extend non-secure switch to also go into HYP mode

Christoffer Dall cdall at cs.columbia.edu
Sat Jun 1 01:51:21 CEST 2013


On Fri, May 31, 2013 at 11:34:38AM +0200, Andre Przywara wrote:
> On 05/31/2013 07:43 AM, Christoffer Dall wrote:
> >On Mon, May 06, 2013 at 03:17:49PM +0200, Andre Przywara wrote:
> >>For the KVM and XEN hypervisors to be usable, we need to enter the
> >>kernel in HYP mode. Now that we already are in non-secure state,
> >>HYP mode switching is within short reach.
> >>
> >>While doing the non-secure switch, we have to enable the HVC
> >>instruction and setup the HYP mode HVBAR (while still secure).
> >>
> >>The actual switch is done by dropping back from a HYP mode handler
> >>without actually leaving HYP mode, so we introduce a new handler
> >>routine in the exception vector table.
> >>
> >>In the assembly switching routine - which we rename to hyp_gic_switch
> >>on the way - we save and restore the banked LR and SP registers
> >>around the hypercall to do the actual HYP mode switch.
> >>
> >>The C routine first checks whether we are in HYP mode already and
> >>also whether the virtualization extensions are available. It also
> >>checks whether the HYP mode switch was finally successful.
> >>The bootm command part only adds and adjusts some error reporting.
> >>
> >>Signed-off-by: Andre Przywara <andre.przywara at linaro.org>
> >>---
> >>  arch/arm/cpu/armv7/start.S   | 34 +++++++++++++++++++++++-----------
> >>  arch/arm/include/asm/armv7.h |  4 ++--
> >>  arch/arm/lib/bootm.c         | 12 +++++++++---
> >>  arch/arm/lib/virt-v7.c       | 22 +++++++++++++++-------
> >>  4 files changed, 49 insertions(+), 23 deletions(-)
> >>
> >>diff --git a/arch/arm/cpu/armv7/start.S b/arch/arm/cpu/armv7/start.S
> >>index 02234c7..921e9d9 100644
> >>--- a/arch/arm/cpu/armv7/start.S
> >>+++ b/arch/arm/cpu/armv7/start.S
> >>@@ -41,7 +41,7 @@ _start: b	reset
> >>  	ldr	pc, _software_interrupt
> >>  	ldr	pc, _prefetch_abort
> >>  	ldr	pc, _data_abort
> >>-	ldr	pc, _not_used
> >>+	ldr	pc, _hyp_trap
> >>  	ldr	pc, _irq
> >>  	ldr	pc, _fiq
> >>  #ifdef CONFIG_SPL_BUILD
> >>@@ -49,7 +49,7 @@ _undefined_instruction: .word _undefined_instruction
> >>  _software_interrupt:	.word _software_interrupt
> >>  _prefetch_abort:	.word _prefetch_abort
> >>  _data_abort:		.word _data_abort
> >>-_not_used:		.word _not_used
> >>+_hyp_trap:		.word _hyp_trap
> >>  _irq:			.word _irq
> >>  _fiq:			.word _fiq
> >>  _pad:			.word 0x12345678 /* now 16*4=64 */
> >>@@ -58,7 +58,7 @@ _undefined_instruction: .word undefined_instruction
> >>  _software_interrupt:	.word software_interrupt
> >>  _prefetch_abort:	.word prefetch_abort
> >>  _data_abort:		.word data_abort
> >>-_not_used:		.word not_used
> >>+_hyp_trap:		.word hyp_trap
> >>  _irq:			.word irq
> >>  _fiq:			.word fiq
> >>  _pad:			.word 0x12345678 /* now 16*4=64 */
> >>@@ -513,12 +513,18 @@ software_interrupt:
> >>  	mrc	p15, 0, r1, c1, c1, 0		@ read SCR
> >>  	bic	r1, r1, #0x07f
> >>  	orr	r1, r1, #0x31			@ enable NS, AW, FW
> >>+	mrc	p15, 0, r0, c0, c1, 1		@ check for Virt ext
> >>+	and	r0, r0, #0xf000
> >>+	cmp	r0, #0x1000
> >
> >you can just do ands r0, r0 ,#0xf000 and change the orreq below to orrne
> 
> Can I? But I want to make sure that Virt ext is of version 1 only,
> anything beyond that I cannot reliably support, right? Or is there a
> guarantee that this is backwards compatible?

In the ARMv7 specifications it mentions either 1 or 0 as the possible
values of this field, and doesn't say anything about reserved values
iirc, but maybe that shouldn't be taken that literally.  Just keep the
code as it is then.

> 
> >>+	orreq	r1, r1, #0x100			@ allow HVC instruction
> >>
> >>  	mrc	p15, 0, r0, c12, c0, 0		@ save secure copy of VBAR
> >>  	mcr	p15, 0, r1, c1, c1, 0		@ write SCR, switch to non-sec
> >>  	isb
> >>  	mcr	p15, 0, r0, c12, c0, 0		@ write non-secure copy of VBAR
> >>
> >>+	mcreq	p15, 4, r0, c12, c0, 0		@ write HYP mode HVBAR
> >>+
> >
> >nit: s/HYP mode//
> >
> >>  	movs	pc, lr
> >>
> >>  	.align	5
> >>@@ -534,10 +540,9 @@ data_abort:
> >>  	bl	do_data_abort
> >>
> >>  	.align	5
> >>-not_used:
> >>-	get_bad_stack
> >>-	bad_save_user_regs
> >>-	bl	do_not_used
> >>+hyp_trap:
> >>+	.byte 0x00, 0xe3, 0x0e, 0xe1		@ mrs lr, elr_hyp
> >
> >do we really need to support this on assemblers that old?
> 
> What do you mean with old? I can check again, but I think it didn't
> work with my self-compiled binutils 2.23. Or do I need a directive
> to enable this?
> 

You need a directive, see the Makefile in arch/arm/kvm/Makefile and the
corresponding source files in the kernel.

> >>+	mov pc, lr
> >>
> >>  #ifdef CONFIG_USE_IRQ
> >>
> >>@@ -574,21 +579,21 @@ fiq:
> >>  #endif /* CONFIG_SPL_BUILD */
> >>
> >>  #ifdef CONFIG_ARMV7_VIRT
> >>-/* Routine to initialize GIC CPU interface and switch to nonsecure state.
> >>- * Will be executed directly by secondary CPUs after coming out of
> >>+/* Routine to initialize GIC CPU interface, switch to nonsecure and to HYP
> >>+ * mode. Will be executed directly by secondary CPUs after coming out of
> >
> >So now this routine does three different things in different context at
> >once, why?
> 
> Not three. At most two. But actually it does only one thing: switch
> a single core to HYP mode. Only the entry and exit points are
> different.
> I just see that I could make the smp_pen a separate function,
> calling the switch function. This would also solve this "LR abuse"
> thing.
> Will try this.
> 

1: smp_pen
2: switch from secure to non-secure
3: switch from non-secure svc to hyp

but yes, I think we understand each other at this point.

> >>   * WFI, or can be called directly by C code for CPU 0.
> >>   * Those two paths mandate to not use any stack and to only use registers
> >>   * r0-r3 to comply with both the C ABI and the requirement of SMP startup
> >>   * code.
> >>   */
> >>-.globl _nonsec_gic_switch
> >>+.globl _hyp_gic_switch
> >>  .globl _smp_pen
> >>  _smp_pen:
> >>  	mrs	r0, cpsr
> >>  	orr	r0, r0, #0xc0
> >>  	msr	cpsr, r0			@ disable interrupts
> >>  	mov	lr, #0				@ clear LR to mark secondary
> >>-_nonsec_gic_switch:
> >>+_hyp_gic_switch:
> >>  	mrc	p15, 4, r2, c15, c0, 0		@ r2 = PERIPHBASE
> >>  	add	r3, r2, #0x1000			@ GIC dist i/f offset
> >>  	mvn	r1, #0
> >>@@ -628,6 +633,13 @@ _nonsec_gic_switch:
> >>  	add	r2, r2, #0x1000			@ GIC dist i/f offset
> >>  	str	r1, [r2]			@ allow private interrupts
> >>
> >>+	mov	r2, lr
> >>+	mov	r1, sp
> >>+	.byte 0x70, 0x00, 0x40, 0xe1		@ hvc #0
> >>+	isb
> >
> >again, I'm doubtful this isb is necessary when you just did an exception
> >return.
> 
> Good point. Exception returns should do this automatically, right?
> Is this an official fact or just a feeling?

It's official, and I've been reminded numerous times by the ARM people
reviewing my KVM code :)  It's somewhere in the ARM ARM.

> 
> ...
> 
> >>diff --git a/arch/arm/lib/virt-v7.c b/arch/arm/lib/virt-v7.c
> >>index 0248010..3883463 100644
> >>--- a/arch/arm/lib/virt-v7.c
> >>+++ b/arch/arm/lib/virt-v7.c
> >>@@ -3,6 +3,7 @@
> >>   * Andre Przywara, Linaro
> >>   *
> >>   * routines to push ARMv7 processors from secure into non-secure state
> >>+ * and from non-secure SVC into HYP mode
> >>   * needed to enable ARMv7 virtualization for current hypervisors
> >>   *
> >>   * See file CREDITS for list of people who contributed to this
> >>@@ -43,16 +44,20 @@ static inline unsigned int read_cpsr(void)
> >>  	return reg;
> >>  }
> >>
> >>-int armv7_switch_nonsec(void)
> >>+int armv7_switch_hyp(void)
> >>  {
> >>  	unsigned int reg;
> >>  	volatile unsigned int *gicdptr;
> >>  	unsigned itlinesnr, i;
> >>  	unsigned int *sysflags;
> >>
> >>-	/* check whether the CPU supports the security extensions */
> >>+	/* check whether we are in HYP mode already */
> >>+	if ((read_cpsr() & 0x1F) == 0x1a)
> >>+		return 1;
> >>+
> >>+	/* check whether the CPU supports the virtualization extensions */
> >>  	asm("mrc p15, 0, %0, c0, c1, 1\n" : "=r"(reg));
> >>-	if ((reg & 0xF0) == 0)
> >>+	if ((reg & 0xF000) != 0x1000)
> >>  		return 2;
> >>
> >>  	/* the timer frequency for the generic timer needs to be
> >>@@ -73,8 +78,8 @@ int armv7_switch_nonsec(void)
> >>  	 */
> >>
> >>  	/* check whether we are an Cortex-A15 or A7.
> >>-	 * The actual non-secure switch should work with all CPUs supporting
> >>-	 * the security extension, but we need the GIC address,
> >>+	 * The actual HYP switch should work with all CPUs supporting
> >>+	 * the virtualization extension, but we need the GIC address,
> >>  	 * which we know only for sure for those two CPUs.
> >>  	 */
> >>  	asm("mrc p15, 0, %0, c0, c0, 0\n" : "=r"(reg));
> >>@@ -113,8 +118,11 @@ int armv7_switch_nonsec(void)
> >>  	sysflags[0] = (uintptr_t)_smp_pen;
> >>  	gicdptr[GICD_SGIR / 4] = 1U << 24;
> >>
> >>-	/* call the non-sec switching code on this CPU also */
> >>-	_nonsec_gic_switch();
> >>+	/* call the HYP switching code on this CPU also */
> >>+	_hyp_gic_switch();
> >>+
> >>+	if ((read_cpsr() & 0x1F) != 0x1a)
> >>+		return 5;
> >
> >this is really a fatal crash right? We probably don't want to try and
> >proceed with boot at this point.
> 
> Well not really. If we reach this point without being in HYP mode,
> that just hasn't worked - for various reasons. Since this new bootm
> functionality is unconditional, I felt we should better not crash.
> Actually Linux will run fine, just without KVM (for certains
> meanings of "fine" that is - as a KVM developer ;-)
> 
Really, but we checked all the prerequisites before calling
_hyp_gic_switch, so we really expect it to work.  If it didn't, it means
that something fatally bad happened as far as I can tell.

As for the integration with the bootm command, you already can't enable
CONFIG_ARMV7_VIRT on a board that's not booted in the secure world, and
you probably can never support determinig that at run-time.  Perhaps
things should look like this:

#ifdef CONFIG_ARMV7_SECURE_BOOT
... do all the non-secure boot stuff
#endif

#ifdef CONFIG_ARMV7_CHANGE_TO_HYP
... call board-specific go-to-hyp-function
... if no board-specific function, exists, tell the user
#endif

But it's just a suggestion, the U-boot guys would know how they want
this I suppose.

Thanks,
-Christoffer


More information about the U-Boot mailing list