From patchwork Fri Apr 26 13:14:58 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andre Przywara X-Patchwork-Id: 239870 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 ABEA32C010B for ; Fri, 26 Apr 2013 23:17:22 +1000 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 633534A11D; Fri, 26 Apr 2013 15:17:04 +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 s+90Q+PYD4bP; Fri, 26 Apr 2013 15:17:04 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 0C4454A125; Fri, 26 Apr 2013 15:16:47 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 645C34A0F6 for ; Fri, 26 Apr 2013 15:16:39 +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 UljWBC96s98f for ; Fri, 26 Apr 2013 15:16:38 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail-ie0-f173.google.com (mail-ie0-f173.google.com [209.85.223.173]) by theia.denx.de (Postfix) with ESMTPS id 2ECC74A0F9 for ; Fri, 26 Apr 2013 15:16:23 +0200 (CEST) Received: by mail-ie0-f173.google.com with SMTP id k5so4896350iea.32 for ; Fri, 26 Apr 2013 06:16:21 -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=OynSp8a5MUw2NUW63KAGuGezlJCj9JZleZEeJj+Hemg=; b=cgXN7ungDfeOuYCboOr4VZyLnjBEHNUQNMIAcVraN3lwKHMH6MlFKU6ubOeRKNJeoI 26p/8544uxiqGUSCBwcM3dbceTUnU62MCK3uR0fOzRRcewSrVv3Hl1mg41S9rJH1UIjZ yuRhI4daKaT8EqdrQCVwhpDX2eHOuqsZHQXQZ8CgTOZUYhdqwtQ6VByWrHlxP2Yh+6s8 MlkQuKUllB+sufhajvHvXUQYX0/b4iKvPICIRITMdsE9wYKIjWl1gMldzXnhv9MkrAgQ f5foBV1gX7RvS6L3fTftJu33gRe8AFLkXxTrBQRUxCWxKj25u040K5qmACgbja3mQ9XQ qYLQ== X-Received: by 10.50.154.129 with SMTP id vo1mr1736790igb.93.1366982181883; Fri, 26 Apr 2013 06:16:21 -0700 (PDT) Received: from slackpad.drs.calxeda.com (f053081241.adsl.alicedsl.de. [78.53.81.241]) by mx.google.com with ESMTPSA id b6sm3105602igv.5.2013.04.26.06.16.19 for (version=TLSv1.2 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 26 Apr 2013 06:16:21 -0700 (PDT) From: Andre Przywara To: trini@ti.com, albert.u.boot@aribaud.net Date: Fri, 26 Apr 2013 15:14:58 +0200 Message-Id: <1366982099-22360-6-git-send-email-andre.przywara@linaro.org> X-Mailer: git-send-email 1.7.12.1 In-Reply-To: <1366982099-22360-1-git-send-email-andre.przywara@linaro.org> References: <1366982099-22360-1-git-send-email-andre.przywara@linaro.org> X-Gm-Message-State: ALoCoQmZ+TGL+7N7uA67eg9IKqOZCzOR4DvDX1lqdw+xj4ttd25psuy/dqJFDvePNHy7wmTpL/kC Cc: cdall@cs.columbia.edu, geoff.levand@linaro.org, marc.zyngier@arm.com, agraf@suse.de, u-boot@lists.denx.de, kvmarm@lists.cs.columbia.edu Subject: [U-Boot] [RFC 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 U-Boot command 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 | 2 +- arch/arm/lib/virt-v7.c | 24 ++++++++++++++++-------- common/cmd_virt.c | 20 +++++++++++++------- 4 files changed, 53 insertions(+), 27 deletions(-) diff --git a/arch/arm/cpu/armv7/start.S b/arch/arm/cpu/armv7/start.S index 2b47881..00890a3 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 */ @@ -502,12 +502,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 @@ -523,10 +529,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 @@ -562,21 +567,21 @@ fiq: #endif /* CONFIG_USE_IRQ */ #endif /* CONFIG_SPL_BUILD */ -/* 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 @@ -616,6 +621,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 3567692..6c6955b 100644 --- a/arch/arm/include/asm/armv7.h +++ b/arch/arm/include/asm/armv7.h @@ -74,6 +74,6 @@ void v7_outer_cache_inval_all(void); void v7_outer_cache_flush_range(u32 start, u32 end); void v7_outer_cache_inval_range(u32 start, u32 end); -int armv7_switch_nonsec(void); +int armv7_switch_hyp(void); #endif diff --git a/arch/arm/lib/virt-v7.c b/arch/arm/lib/virt-v7.c index 5ca093a..72481c6 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 @@ -28,7 +29,7 @@ #include /* the assembly routine doing the actual work in start.S */ -void _nonsec_gic_switch(void); +void _hyp_gic_switch(void); void _smp_pen(void); #define GICD_CTLR 0x000 @@ -47,16 +48,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 @@ -77,8 +82,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)); @@ -117,8 +122,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; } diff --git a/common/cmd_virt.c b/common/cmd_virt.c index 132b6b1..78b1aa1 100644 --- a/common/cmd_virt.c +++ b/common/cmd_virt.c @@ -2,8 +2,8 @@ * (C) Copyright 2013 * Andre Przywara, Linaro * - * command to switch an ARMv7 CPU with security extensions into - * non-secure state + * command to switch an ARMv7 CPU with virtualization extensions into + * HYP mode to allow hypervisors to install themselves * * See file CREDITS for list of people who contributed to this * project. @@ -29,17 +29,20 @@ #include -static int do_nonsec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +static int do_hyp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { unsigned int ret; - ret = armv7_switch_nonsec(); + ret = armv7_switch_hyp(); switch (ret) { case 0: break; + case 1: + printf("Already in HYP mode\n"); + break; case 2: - printf("Security extensions not implemented.\n"); + printf("Virtualization extensions not implemented.\n"); break; case 3: printf("CPU not supported, must be either Cortex-A15 or A7.\n"); @@ -47,13 +50,16 @@ static int do_nonsec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) case 4: printf("PERIPHBASE is above 4 GB, cannot access this.\n"); break; + case 5: + printf("HYP mode switch not successful.\n"); + break; } return ret; } U_BOOT_CMD( - hypmode, 1, 0, do_nonsec, - "switch ARM CPUs into non-secure state", + hypmode, 1, 0, do_hyp, + "switch ARM CPUs into HYP mode", "" );