From patchwork Thu Jun 13 11:07:42 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andre Przywara X-Patchwork-Id: 17907 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-gh0-f199.google.com (mail-gh0-f199.google.com [209.85.160.199]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 4C63B25DF1 for ; Thu, 13 Jun 2013 11:08:33 +0000 (UTC) Received: by mail-gh0-f199.google.com with SMTP id g14sf5739959ghb.6 for ; Thu, 13 Jun 2013 04:08:33 -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: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=nBpgbrZ69Zel44WcXkoU8Hgvpy+WSaoigrBI42QNbkk=; b=N5OatLZATw4T10V++lMeQ8LTLWLBhWnPvBz4GFtbiog0B9B7H7Skwz8dVuAZZECcVd YsVhK79ngR1kjpyI1uTxY8zpSwemIav4pRv8NBTuwtCxr9eL9uVo9aKPNCfuCqif33Tw K+7AJkU0OZzzHHH4acpkVdY86jKLK3UcMeZck/BfC3ZTCvMTgp5YytmKSV6IqdWNUwOx m/RRiHHlcm/vOxYAepsn/W/+bJAhsICSibhAbaUCU7NmpBg+1iUn9P3J0eD15Udigsiw 7Xmav6D/1H/Hz3m5a2W2E5UU61YLaEP4jQITXvfCi1yqXkjHH7W1W3Nv9deXoJ368v1Q aR4g== X-Received: by 10.236.161.234 with SMTP id w70mr136234yhk.22.1371121713007; Thu, 13 Jun 2013 04:08:33 -0700 (PDT) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.49.58.146 with SMTP id r18ls498770qeq.23.gmail; Thu, 13 Jun 2013 04:08:32 -0700 (PDT) X-Received: by 10.52.114.135 with SMTP id jg7mr91819vdb.78.1371121712819; Thu, 13 Jun 2013 04:08:32 -0700 (PDT) Received: from mail-vc0-f178.google.com (mail-vc0-f178.google.com [209.85.220.178]) by mx.google.com with ESMTPS id bj6si10217827vcb.7.2013.06.13.04.08.32 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 13 Jun 2013 04:08:32 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.220.178 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.220.178; Received: by mail-vc0-f178.google.com with SMTP id m17so2912893vca.37 for ; Thu, 13 Jun 2013 04:08:32 -0700 (PDT) X-Received: by 10.52.155.67 with SMTP id vu3mr84491vdb.94.1371121712681; Thu, 13 Jun 2013 04:08:32 -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.58.191.99 with SMTP id gx3csp17027vec; Thu, 13 Jun 2013 04:08:32 -0700 (PDT) X-Received: by 10.60.141.2 with SMTP id rk2mr266856oeb.69.1371121712064; Thu, 13 Jun 2013 04:08:32 -0700 (PDT) Received: from mail-ob0-x234.google.com (mail-ob0-x234.google.com [2607:f8b0:4003:c01::234]) by mx.google.com with ESMTPS id xs6si19610083obc.51.2013.06.13.04.08.31 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 13 Jun 2013 04:08:32 -0700 (PDT) Received-SPF: neutral (google.com: 2607:f8b0:4003:c01::234 is neither permitted nor denied by best guess record for domain of andre.przywara@linaro.org) client-ip=2607:f8b0:4003:c01::234; Received: by mail-ob0-f180.google.com with SMTP id eh20so14315630obb.25 for ; Thu, 13 Jun 2013 04:08:31 -0700 (PDT) X-Received: by 10.182.46.230 with SMTP id y6mr233029obm.79.1371121711679; Thu, 13 Jun 2013 04:08:31 -0700 (PDT) Received: from slackpad.drs.calxeda.com (g224198135.adsl.alicedsl.de. [92.224.198.135]) by mx.google.com with ESMTPSA id eq4sm38120532obb.5.2013.06.13.04.08.30 for (version=TLSv1.2 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 13 Jun 2013 04:08:31 -0700 (PDT) From: Andre Przywara To: patches@linaro.org Subject: [PATCH v2 6/7] ARM: extend non-secure switch to also go into HYP mode Date: Thu, 13 Jun 2013 13:07:42 +0200 Message-Id: <1371121663-18810-7-git-send-email-andre.przywara@linaro.org> X-Mailer: git-send-email 1.7.12.1 In-Reply-To: <1371121663-18810-1-git-send-email-andre.przywara@linaro.org> References: <1371121663-18810-1-git-send-email-andre.przywara@linaro.org> X-Gm-Message-State: ALoCoQmVZjD4MQumUPZ+6kkJsIsb7YQwUFtoetgQ4geh5GqmrlAkrPVGwbqW2UrApoxpGWLEbp8b X-Original-Sender: andre.przywara@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.220.178 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/nonsec_virt.S | 31 ++++++++++++++++++++++++++++--- arch/arm/include/asm/armv7.h | 7 +++++-- arch/arm/lib/bootm.c | 14 ++++++++++---- arch/arm/lib/virt-v7.c | 27 ++++++++++++++++++++++----- 4 files changed, 65 insertions(+), 14 deletions(-) diff --git a/arch/arm/cpu/armv7/nonsec_virt.S b/arch/arm/cpu/armv7/nonsec_virt.S index 919f6e9..950da6f 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 * @@ -26,14 +26,14 @@ #include #include -/* the vector table for secure state */ +/* the vector table for secure state and HYP mode */ _secure_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 */ @@ -50,10 +50,23 @@ _secure_monitor: bic r1, r1, #0x4e @ clear IRQ, FIQ, EA, nET bits orr r1, r1, #0x31 @ enable NS, AW, FW bits + 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 + mcr p15, 0, r1, c1, c1, 0 @ write SCR (with NS bit set) + mrceq p15, 0, r0, c12, c0, 1 @ get MVBAR value + mcreq p15, 4, r0, c12, c0, 0 @ write HVBAR + movs pc, lr @ return to non-secure SVC +_hyp_trap: + .byte 0x00, 0xe3, 0x0e, 0xe1 @ mrs lr, elr_hyp + 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 @@ -69,6 +82,7 @@ _smp_pen: mcr p15, 0, r1, c12, c0, 0 @ set VBAR bl _nonsec_init + bl _hyp_init ldr r1, [r3, #0x0c] @ read GICD acknowledge str r1, [r3, #0x10] @ write GICD EOI @@ -145,3 +159,14 @@ _nonsec_init: str r1, [r2] @ allow private interrupts bx lr + +.globl _hyp_init +_hyp_init: + mov r2, lr + mov r3, sp @ save SVC copy of LR and SP + isb + .byte 0x70, 0x00, 0x40, 0xe1 @ hvc #0 + mov sp, r3 + mov lr, r2 @ fix HYP mode banked LR and SP + + bx lr diff --git a/arch/arm/include/asm/armv7.h b/arch/arm/include/asm/armv7.h index 04545b9..8c3a85e 100644 --- a/arch/arm/include/asm/armv7.h +++ b/arch/arm/include/asm/armv7.h @@ -89,15 +89,18 @@ void v7_outer_cache_inval_range(u32 start, u32 end); #ifdef CONFIG_ARMV7_VIRT -#define HYP_ERR_NO_SEC_EXT 2 +#define HYP_ERR_ALREADY_HYP_MODE 1 +#define HYP_ERR_NO_VIRT_EXT 2 #define HYP_ERR_NO_GIC_ADDRESS 3 #define HYP_ERR_GIC_ADDRESS_ABOVE_4GB 4 +#define HYP_ERR_NOT_HYP_MODE 5 -int armv7_switch_nonsec(void); +int armv7_switch_hyp(void); /* defined in cpu/armv7/nonsec_virt.S */ void _nonsec_init(void); void _smp_pen(void); +void _hyp_init(void); #endif /* CONFIG_ARMV7_VIRT */ #endif /* ! __ASSEMBLY__ */ diff --git a/arch/arm/lib/bootm.c b/arch/arm/lib/bootm.c index 8251a89..7edd84d 100644 --- a/arch/arm/lib/bootm.c +++ b/arch/arm/lib/bootm.c @@ -227,12 +227,15 @@ static void boot_prep_linux(bootm_headers_t *images) hang(); } #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 HYP_ERR_NO_SEC_EXT: - printf("HYP mode: Security extensions not implemented.\n"); + case HYP_ERR_ALREADY_HYP_MODE: + debug("CPU already in HYP mode\n"); + break; + case HYP_ERR_NO_VIRT_EXT: + printf("HYP mode: Virtualization extensions not implemented.\n"); break; case HYP_ERR_NO_GIC_ADDRESS: printf("HYP mode: could not determine GIC address.\n"); @@ -240,6 +243,9 @@ static void boot_prep_linux(bootm_headers_t *images) case HYP_ERR_GIC_ADDRESS_ABOVE_4GB: printf("HYP mode: PERIPHBASE is above 4 GB, cannot access this.\n"); break; + case HYP_ERR_NOT_HYP_MODE: + 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 6946e4d..1e206b9 100644 --- a/arch/arm/lib/virt-v7.c +++ b/arch/arm/lib/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; @@ -110,16 +119,20 @@ static void kick_secondary_cpus(char *gicdptr) writel(1U << 24, &gicdptr[GICD_SGIR]); } -int armv7_switch_nonsec(void) +int armv7_switch_hyp(void) { unsigned int reg, ret; char *gicdptr; unsigned itlinesnr, i; - /* check whether the CPU supports the security extensions */ + /* check whether we are in HYP mode already */ + if ((read_cpsr() & 0x1f) == 0x1a) + return HYP_ERR_ALREADY_HYP_MODE; + + /* check whether the CPU supports the virtualization extensions */ reg = read_id_pfr1(); - if ((reg & 0xF0) == 0) - return HYP_ERR_NO_SEC_EXT; + if ((reg & CPUID_ARM_VIRT_MASK) != 1 << CPUID_ARM_VIRT_SHIFT) + return HYP_ERR_NO_VIRT_EXT; set_generic_timer_frequency(); @@ -147,8 +160,12 @@ int armv7_switch_nonsec(void) kick_secondary_cpus(gicdptr); - /* call the non-sec switching code on this CPU also */ + /* call the HYP switching code on this CPU also */ _nonsec_init(); + _hyp_init(); + + if ((read_cpsr() & 0x1F) != 0x1a) + return HYP_ERR_NOT_HYP_MODE; return 0; }