Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 80c59daf authored by Dave Martin's avatar Dave Martin Committed by Marc Zyngier
Browse files

ARM: virt: allow the kernel to be entered in HYP mode



This patch does two things:

  * Ensure that asynchronous aborts are masked at kernel entry.
    The bootloader should be masking these anyway, but this reduces
    the damage window just in case it doesn't.

  * Enter svc mode via exception return to ensure that CPU state is
    properly serialised.  This does not matter when switching from
    an ordinary privileged mode ("PL1" modes in ARMv7-AR rev C
    parlance), but it potentially does matter when switching from a
    another privileged mode such as hyp mode.

This should allow the kernel to boot safely either from svc mode or
hyp mode, even if no support for use of the ARM Virtualization
Extensions is built into the kernel.

Signed-off-by: default avatarDave Martin <dave.martin@linaro.org>
Signed-off-by: default avatarMarc Zyngier <marc.zyngier@arm.com>
parent b9a348cb
Loading
Loading
Loading
Loading
+28 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@

#include <asm/ptrace.h>
#include <asm/domain.h>
#include <asm/opcodes-virt.h>

#define IOMEM(x)	(x)

@@ -239,6 +240,33 @@
	.endm
#endif

/*
 * Helper macro to enter SVC mode cleanly and mask interrupts. reg is
 * a scratch register for the macro to overwrite.
 *
 * This macro is intended for forcing the CPU into SVC mode at boot time.
 * you cannot return to the original mode.
 *
 * Beware, it also clobers LR.
 */
.macro safe_svcmode_maskall reg:req
	mrs	\reg , cpsr
	mov	lr , \reg
	and	lr , lr , #MODE_MASK
	cmp	lr , #HYP_MODE
	orr	\reg , \reg , #PSR_A_BIT | PSR_I_BIT | PSR_F_BIT
	bic	\reg , \reg , #MODE_MASK
	orr	\reg , \reg , #SVC_MODE
THUMB(	orr	\reg , \reg , #PSR_T_BIT	)
	msr	spsr_cxsf, \reg
	adr	lr, BSYM(2f)
	bne	1f
	__MSR_ELR_HYP(14)
	__ERET
1:	movs	pc, lr
2:
.endm

/*
 * STRT/LDRT access macros with ARM and Thumb-2 variants
 */
+1 −0
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@
#define IRQ_MODE	0x00000012
#define SVC_MODE	0x00000013
#define ABT_MODE	0x00000017
#define HYP_MODE	0x0000001a
#define UND_MODE	0x0000001b
#define SYSTEM_MODE	0x0000001f
#define MODE32_BIT	0x00000010
+52 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2012 Linaro Limited.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#ifndef VIRT_H
#define VIRT_H

#include <asm/ptrace.h>

/*
 * Flag indicating that the kernel was not entered in the same mode on every
 * CPU.  The zImage loader stashes this value in an SPSR, so we need an
 * architecturally defined flag bit here (the N flag, as it happens)
 */
#define BOOT_CPU_MODE_MISMATCH (1<<31)

#ifndef __ASSEMBLY__

#ifdef CONFIG_ARM_VIRT_EXT
/*
 * __boot_cpu_mode records what mode the primary CPU was booted in.
 * A correctly-implemented bootloader must start all CPUs in the same mode:
 * if it fails to do this, the flag BOOT_CPU_MODE_MISMATCH is set to indicate
 * that some CPU(s) were booted in a different mode.
 *
 * This allows the kernel to flag an error when the secondaries have come up.
 */
extern int __boot_cpu_mode;

void __hyp_set_vectors(unsigned long phys_vector_base);
unsigned long __hyp_get_vectors(void);
#else
#define __boot_cpu_mode	(SVC_MODE)
#endif

#endif /* __ASSEMBLY__ */

#endif /* ! VIRT_H */
+2 −0
Original line number Diff line number Diff line
@@ -82,4 +82,6 @@ head-y := head$(MMUEXT).o
obj-$(CONFIG_DEBUG_LL)	+= debug.o
obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o

obj-$(CONFIG_ARM_VIRT_EXT)	+= hyp-stub.o

extra-y := $(head-y) vmlinux.lds
+11 −3
Original line number Diff line number Diff line
@@ -83,8 +83,12 @@ ENTRY(stext)
 THUMB(	.thumb			)	@ switch to Thumb now.
 THUMB(1:			)

	setmode	PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode
						@ and irqs disabled
#ifdef CONFIG_ARM_VIRT_EXT
	bl	__hyp_stub_install
#endif
	@ ensure svc mode and all interrupts masked
	safe_svcmode_maskall r9

	mrc	p15, 0, r9, c0, c0		@ get processor id
	bl	__lookup_processor_type		@ r5=procinfo r9=cpuid
	movs	r10, r5				@ invalid processor (r5=0)?
@@ -326,7 +330,11 @@ ENTRY(secondary_startup)
	 * the processor type - there is no need to check the machine type
	 * as it has already been validated by the primary processor.
	 */
	setmode	PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9
#ifdef CONFIG_ARM_VIRT_EXT
	bl	__hyp_stub_install
#endif
	safe_svcmode_maskall r9

	mrc	p15, 0, r9, c0, c0		@ get processor id
	bl	__lookup_processor_type
	movs	r10, r5				@ invalid processor?
Loading