From patchwork Tue Jul 9 23:54:18 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andre Przywara X-Patchwork-Id: 18297 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-wg0-f69.google.com (mail-wg0-f69.google.com [74.125.82.69]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id D0F8625E04 for ; Tue, 9 Jul 2013 23:55:26 +0000 (UTC) Received: by mail-wg0-f69.google.com with SMTP id e11sf6065227wgh.4 for ; Tue, 09 Jul 2013 16:55:25 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=mime-version:x-beenthere:x-forwarded-to:x-forwarded-for :delivered-to:from:to:cc:subject:date:message-id:x-mailer :in-reply-to:references:x-gm-message-state:x-original-sender :x-original-authentication-results:precedence:mailing-list:list-id :x-google-group-id:list-post:list-help:list-archive:list-unsubscribe; bh=FeOh1jtM2DPct+HPID+j/3X6TZBH4dWZ9iH1BJOKjmk=; b=YbIN3ChWwk3nOFuMYk4SEBCafbQpSk+uVYI6GUdH/L6/RJYdjIYITN8g2hw8i9e/JL wFzcDYCn4T5ebyqGLh/55TfjYD2qCE/XZG9/NfA+yfmhGJ08AKxzsQADaQLVh1BQQdMx xXqTVDtkNnmd1loKw7qF6SL2MSBbuub1wrzYJ3t+2DO9XOwFp4DYfZywwiyqYMEZrLbj /kAoLIUPiOAPdS4rZ7X+XViSlb8/+z2Klhq57kbzxEPEDdjRpkJJLT1GW9wRex+wK/1P u3QK2nGVkI0yHf+fVILnbGMmVKPXmxbobNhdCTaZzum/RdB6k7n5q9UoGWmXuQ/MSHyz JBCw== X-Received: by 10.180.187.229 with SMTP id fv5mr6587360wic.6.1373414125943; Tue, 09 Jul 2013 16:55:25 -0700 (PDT) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.180.78.167 with SMTP id c7ls2537803wix.39.canary; Tue, 09 Jul 2013 16:55:25 -0700 (PDT) X-Received: by 10.194.157.65 with SMTP id wk1mr16252245wjb.8.1373414125769; Tue, 09 Jul 2013 16:55:25 -0700 (PDT) Received: from mail-ve0-f182.google.com (mail-ve0-f182.google.com [209.85.128.182]) by mx.google.com with ESMTPS id ld6si9375147wjb.101.2013.07.09.16.55.25 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 09 Jul 2013 16:55:25 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.128.182 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.128.182; Received: by mail-ve0-f182.google.com with SMTP id ox1so5211340veb.13 for ; Tue, 09 Jul 2013 16:55:24 -0700 (PDT) X-Received: by 10.52.91.202 with SMTP id cg10mr14943061vdb.85.1373414124548; Tue, 09 Jul 2013 16:55:24 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patches@linaro.org Received: by 10.220.149.77 with SMTP id s13csp57410vcv; Tue, 9 Jul 2013 16:55:23 -0700 (PDT) X-Received: by 10.194.78.110 with SMTP id a14mr16511222wjx.84.1373414123424; Tue, 09 Jul 2013 16:55:23 -0700 (PDT) Received: from mail-wi0-f175.google.com (mail-wi0-f175.google.com [209.85.212.175]) by mx.google.com with ESMTPS id x12si16780464wib.49.2013.07.09.16.55.22 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 09 Jul 2013 16:55:23 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.212.175 is neither permitted nor denied by best guess record for domain of andre.przywara@linaro.org) client-ip=209.85.212.175; Received: by mail-wi0-f175.google.com with SMTP id m6so10788241wiv.14 for ; Tue, 09 Jul 2013 16:55:22 -0700 (PDT) X-Received: by 10.194.121.132 with SMTP id lk4mr16560503wjb.25.1373414122837; Tue, 09 Jul 2013 16:55:22 -0700 (PDT) Received: from localhost.localdomain ([193.120.41.118]) by mx.google.com with ESMTPSA id fs8sm64073738wib.0.2013.07.09.16.55.20 for (version=TLSv1.2 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 09 Jul 2013 16:55:22 -0700 (PDT) From: Andre Przywara To: trini@ti.com, albert.u.boot@aribaud.net, christoffer.dall@linaro.org Cc: u-boot@lists.denx.de, marc.zyngier@arm.com, peter.maydell@linaro.org, geoff.levand@linaro.org, agraf@suse.de, kvmarm@lists.cs.columbia.edu, yamada.m@jp.panasonic.com, nicknickolaev@gmail.com, patches@linaro.org Subject: [PATCH v3 6/7] ARM: extend non-secure switch to also go into HYP mode Date: Wed, 10 Jul 2013 01:54:18 +0200 Message-Id: <1373414059-22779-7-git-send-email-andre.przywara@linaro.org> X-Mailer: git-send-email 1.7.12.1 In-Reply-To: <1373414059-22779-1-git-send-email-andre.przywara@linaro.org> References: <1373414059-22779-1-git-send-email-andre.przywara@linaro.org> X-Gm-Message-State: ALoCoQmLgei68FKrQnnjgvWxvvmkoEsdjXdlNQVs/HYu8XuZNc5znmJUjiYtBgGwuNh53i4gUB7u X-Original-Sender: andre.przywara@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.128.182 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Precedence: list Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org List-ID: X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , 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 our new secure exception vector table. In the assembly switching routine 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/Makefile | 2 +- arch/arm/cpu/armv7/nonsec_virt.S | 43 +++++++++++++++++++++++++++++++++++----- arch/arm/cpu/armv7/virt-v7.c | 31 +++++++++++++++++++++++++++++ arch/arm/include/asm/armv7.h | 9 +++++++-- arch/arm/lib/bootm.c | 19 +++++++++++++++--- 5 files changed, 93 insertions(+), 11 deletions(-) diff --git a/arch/arm/cpu/armv7/Makefile b/arch/arm/cpu/armv7/Makefile index b59f59e..e5eaa56 100644 --- a/arch/arm/cpu/armv7/Makefile +++ b/arch/arm/cpu/armv7/Makefile @@ -36,7 +36,7 @@ ifneq ($(CONFIG_AM33XX)$(CONFIG_OMAP44XX)$(CONFIG_OMAP54XX)$(CONFIG_TEGRA)$(CONF SOBJS += lowlevel_init.o endif -ifneq ($(CONFIG_ARMV7_NONSEC),) +ifneq ($(CONFIG_ARMV7_NONSEC)$(CONFIG_ARMV7_VIRT),) SOBJS += nonsec_virt.o COBJS += virt-v7.o endif diff --git a/arch/arm/cpu/armv7/nonsec_virt.S b/arch/arm/cpu/armv7/nonsec_virt.S index f9b6b39..895c3b0 100644 --- a/arch/arm/cpu/armv7/nonsec_virt.S +++ b/arch/arm/cpu/armv7/nonsec_virt.S @@ -1,5 +1,5 @@ /* - * code for switching cores into non-secure state + * code for switching cores into non-secure state and into HYP mode * * Copyright (c) 2013 Andre Przywara * @@ -28,15 +28,16 @@ #include .arch_extension sec +.arch_extension virt -/* the vector table for secure state */ +/* the vector table for secure state and HYP mode */ _monitor_vectors: .word 0 /* reset */ .word 0 /* undef */ adr pc, _secure_monitor .word 0 .word 0 - .word 0 + adr pc, _hyp_trap .word 0 .word 0 .word 0 /* pad */ @@ -53,10 +54,27 @@ _secure_monitor: bic r1, r1, #0x4e @ clear IRQ, FIQ, EA, nET bits orr r1, r1, #0x31 @ enable NS, AW, FW bits +#ifdef CONFIG_ARMV7_VIRT + 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) + orreq r1, r1, #0x100 @ allow HVC instruction +#endif + mcr p15, 0, r1, c1, c1, 0 @ write SCR (with NS bit set) +#ifdef CONFIG_ARMV7_VIRT + mrceq p15, 0, r0, c12, c0, 1 @ get MVBAR value + mcreq p15, 4, r0, c12, c0, 0 @ write HVBAR +#endif + 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 + /* * 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 @@ -71,9 +89,13 @@ ENTRY(_smp_pen) mcr p15, 0, r1, c12, c0, 0 @ set VBAR bl _nonsec_init + mov r12, r0 @ save GICC address +#ifdef CONFIG_ARMV7_VIRT + bl _switch_to_hyp +#endif - ldr r1, [r0, #GICC_IAR] @ acknowledge IPI - str r1, [r0, #GICC_EOIR] @ signal end of interrupt + ldr r1, [r12, #GICC_IAR] @ acknowledge IPI + str r1, [r12, #GICC_EOIR] @ signal end of interrupt adr r1, _smp_pen waitloop: wfi @@ -164,3 +186,14 @@ ENTRY(_nonsec_init) bx lr ENDPROC(_nonsec_init) + +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) diff --git a/arch/arm/cpu/armv7/virt-v7.c b/arch/arm/cpu/armv7/virt-v7.c index a0d0b34..3645572 100644 --- a/arch/arm/cpu/armv7/virt-v7.c +++ b/arch/arm/cpu/armv7/virt-v7.c @@ -3,6 +3,7 @@ * Andre Przywara, Linaro * * Routines to transition 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 @@ -29,6 +30,14 @@ #include #include +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; @@ -92,6 +101,28 @@ static void kick_secondary_cpus(unsigned int gicdaddr) writel(1U << 24, gicdaddr + GICD_SGIR); } +enum nonsec_virt_errors armv7_switch_hyp(void) +{ + unsigned int reg; + + /* check whether we are in HYP mode already */ + if ((read_cpsr() & 0x1f) == 0x1a) + return VIRT_ALREADY_HYP_MODE; + + /* check whether the CPU supports the virtualization extensions */ + reg = read_id_pfr1(); + if ((reg & CPUID_ARM_VIRT_MASK) != 1 << CPUID_ARM_VIRT_SHIFT) + return VIRT_ERR_NO_VIRT_EXT; + + /* call the HYP switching code on this CPU also */ + _switch_to_hyp(); + + if ((read_cpsr() & 0x1F) != 0x1a) + return VIRT_ERR_NOT_HYP_MODE; + + return NONSEC_VIRT_SUCCESS; +} + enum nonsec_virt_errors armv7_switch_nonsec(void) { unsigned int reg, ret; diff --git a/arch/arm/include/asm/armv7.h b/arch/arm/include/asm/armv7.h index f6582a1..baa22fe 100644 --- a/arch/arm/include/asm/armv7.h +++ b/arch/arm/include/asm/armv7.h @@ -89,21 +89,26 @@ 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); -#ifdef CONFIG_ARMV7_NONSEC +#if defined(CONFIG_ARMV7_NONSEC) || defined(CONFIG_ARMV7_VIRT) enum nonsec_virt_errors { NONSEC_VIRT_SUCCESS, NONSEC_ERR_NO_SEC_EXT, NONSEC_ERR_NO_GIC_ADDRESS, NONSEC_ERR_GIC_ADDRESS_ABOVE_4GB, + VIRT_ALREADY_HYP_MODE, + VIRT_ERR_NO_VIRT_EXT, + VIRT_ERR_NOT_HYP_MODE }; enum nonsec_virt_errors armv7_switch_nonsec(void); +enum nonsec_virt_errors armv7_switch_hyp(void); /* defined in assembly file */ unsigned int _nonsec_init(void); void _smp_pen(void); -#endif /* CONFIG_ARMV7_NONSEC */ +void _switch_to_hyp(void); +#endif /* CONFIG_ARMV7_NONSEC || CONFIG_ARMV7_VIRT */ #endif /* ! __ASSEMBLY__ */ diff --git a/arch/arm/lib/bootm.c b/arch/arm/lib/bootm.c index 7b0619e..90875b3 100644 --- a/arch/arm/lib/bootm.c +++ b/arch/arm/lib/bootm.c @@ -34,7 +34,7 @@ #include #include -#ifdef CONFIG_ARMV7_NONSEC +#if defined(CONFIG_ARMV7_NONSEC) || defined(CONFIG_ARMV7_VIRT) #include #endif @@ -192,13 +192,17 @@ __weak void setup_board_tags(struct tag **in_params) {} static void do_nonsec_virt_switch(void) { -#ifdef CONFIG_ARMV7_NONSEC +#if defined(CONFIG_ARMV7_NONSEC) || defined(CONFIG_ARMV7_VIRT) int ret; ret = armv7_switch_nonsec(); +#ifdef CONFIG_ARMV7_VIRT + if (ret == NONSEC_VIRT_SUCCESS) + ret = armv7_switch_hyp(); +#endif switch (ret) { case NONSEC_VIRT_SUCCESS: - debug("entered non-secure state\n"); + debug("entered non-secure state or HYP mode\n"); break; case NONSEC_ERR_NO_SEC_EXT: printf("nonsec: Security extensions not implemented.\n"); @@ -209,6 +213,15 @@ static void do_nonsec_virt_switch(void) case NONSEC_ERR_GIC_ADDRESS_ABOVE_4GB: printf("nonsec: PERIPHBASE is above 4 GB, no access.\n"); break; + case VIRT_ERR_NO_VIRT_EXT: + printf("HYP mode: Virtualization extensions not implemented.\n"); + break; + case VIRT_ALREADY_HYP_MODE: + debug("CPU already in HYP mode\n"); + break; + case VIRT_ERR_NOT_HYP_MODE: + printf("HYP mode: switch not successful.\n"); + break; } #endif }