From patchwork Mon May 6 13:17:49 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andre Przywara X-Patchwork-Id: 241652 X-Patchwork-Delegate: albert.aribaud@free.fr Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id EAFD12C00AC for ; Mon, 6 May 2013 23:20:14 +1000 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 2D3FE4A302; Mon, 6 May 2013 15:19:58 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id OoX-QjNPfDfM; Mon, 6 May 2013 15:19:57 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 96B424A307; Mon, 6 May 2013 15:19:43 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 50DF84A302 for ; Mon, 6 May 2013 15:19:41 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id Yzlo5ct-1YAl for ; Mon, 6 May 2013 15:19:36 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 BL_NJABL=ERR(-1.5) (only DNSBL check requested) Received: from mail-oa0-f49.google.com (mail-oa0-f49.google.com [209.85.219.49]) by theia.denx.de (Postfix) with ESMTPS id 800EA4A2B4 for ; Mon, 6 May 2013 15:19:05 +0200 (CEST) Received: by mail-oa0-f49.google.com with SMTP id l20so3407908oag.22 for ; Mon, 06 May 2013 06:19:04 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-received:from:to:cc:subject:date:message-id:x-mailer:in-reply-to :references:x-gm-message-state; bh=ztDQ04+5PAkHAUYMtA0yfGAQmBmcumw+M1na454z9RM=; b=hjZULpV7Dp9I4Dd7kWwbm6GA/IJ1S7Mruoa7qrrMUDZ16784AoIwKacgCNM/gZzrRS rVSXSAMfMoBgy1+ERgFEfTWvLbh8LAoxMzAZ/+RQc71YbRlQ6msKfhKr3921Uu73MU/M W6V6+MC3XD0kv+sEQx7SwO3KaEhLIZZYowafJ1qwjoFxliAWWQTTkagp1kk94GpfQC9l LSYwvJ7hcntiFE6/3ec6aApxfCstpfHbdsO7Ar2xteTS2x+MXt0Q9IKNkdG3uBEPNw+I aRVkyfHdA5QpFhtclqjd2tkf33K2WJ5cYC7LTaY4lCCmp05+QKwQcJsfzABcVocEPgLi UPVw== X-Received: by 10.60.132.238 with SMTP id ox14mr5368660oeb.102.1367846344736; Mon, 06 May 2013 06:19:04 -0700 (PDT) Received: from slackpad.drs.calxeda.com (f053080141.adsl.alicedsl.de. [78.53.80.141]) by mx.google.com with ESMTPSA id x10sm5081475oes.6.2013.05.06.06.19.01 for (version=TLSv1.2 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Mon, 06 May 2013 06:19:04 -0700 (PDT) From: Andre Przywara To: trini@ti.com, albert.u.boot@aribaud.net Date: Mon, 6 May 2013 15:17:49 +0200 Message-Id: <1367846270-1827-6-git-send-email-andre.przywara@linaro.org> X-Mailer: git-send-email 1.7.12.1 In-Reply-To: <1367846270-1827-1-git-send-email-andre.przywara@linaro.org> References: <1367846270-1827-1-git-send-email-andre.przywara@linaro.org> X-Gm-Message-State: ALoCoQnqUUtJruoauU3vhYr/9N7AJAopWc27NKIHKHdK44XUkamszLjS0gk9XgeOKTcFkJEPB9XF Cc: peter.maydell@linaro.org, geoff.levand@linaro.org, cdall@cs.columbia.edu, marc.zyngier@arm.com, agraf@suse.de, u-boot@lists.denx.de, kvmarm@lists.cs.columbia.edu Subject: [U-Boot] [PATCH 5/6] ARM: extend non-secure switch to also go into HYP mode X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.11 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de 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 --- 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 + 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 + 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 + 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 * 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 + mov sp, r1 + mov lr, r2 + cmp lr, #0 movne pc, lr @ CPU 0 to return @ all others: go to sleep diff --git a/arch/arm/include/asm/armv7.h b/arch/arm/include/asm/armv7.h index 296dc92..17bb497 100644 --- a/arch/arm/include/asm/armv7.h +++ b/arch/arm/include/asm/armv7.h @@ -75,11 +75,11 @@ void v7_outer_cache_flush_range(u32 start, u32 end); void v7_outer_cache_inval_range(u32 start, u32 end); #ifdef CONFIG_ARMV7_VIRT -int armv7_switch_nonsec(void); +int armv7_switch_hyp(void); /* defined in cpu/armv7/start.S */ void _smp_pen(void); -void _nonsec_gic_switch(void); +void _hyp_gic_switch(void); #endif /* CONFIG_ARMV7_VIRT */ #endif diff --git a/arch/arm/lib/bootm.c b/arch/arm/lib/bootm.c index a3d3aae..552ba59 100644 --- a/arch/arm/lib/bootm.c +++ b/arch/arm/lib/bootm.c @@ -324,12 +324,15 @@ static void boot_prep_linux(bootm_headers_t *images) #endif /* all tags */ } #ifdef CONFIG_ARMV7_VIRT - switch (armv7_switch_nonsec()) { + switch (armv7_switch_hyp()) { case 0: - debug("entered non-secure state\n"); + debug("entered HYP mode\n"); + break; + case 1: + debug("CPU already in HYP mode\n"); break; case 2: - printf("HYP mode: Security extensions not implemented.\n"); + printf("HYP mode: Virtualization extensions not implemented.\n"); break; case 3: printf("HYP mode: CPU not supported (must be Cortex-A15 or A7).\n"); @@ -337,6 +340,9 @@ static void boot_prep_linux(bootm_headers_t *images) case 4: printf("HYP mode: PERIPHBASE is above 4 GB, cannot access this.\n"); break; + case 5: + printf("HYP mode: switch not successful.\n"); + break; } #endif } 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; return 0; }