From patchwork Fri Apr 26 13:14:56 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andre Przywara X-Patchwork-Id: 239867 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 854022C00D6 for ; Fri, 26 Apr 2013 23:16:48 +1000 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id E59F34A0C6; Fri, 26 Apr 2013 15:16:40 +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 JBO3RxisSKiR; Fri, 26 Apr 2013 15:16:40 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 9776D4A108; Fri, 26 Apr 2013 15:16:32 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 062B94A0BE for ; Fri, 26 Apr 2013 15:16:22 +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 O1ceRNApdDNW for ; Fri, 26 Apr 2013 15:16:20 +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-f174.google.com (mail-ie0-f174.google.com [209.85.223.174]) by theia.denx.de (Postfix) with ESMTPS id 3E0D04A0AB for ; Fri, 26 Apr 2013 15:16:18 +0200 (CEST) Received: by mail-ie0-f174.google.com with SMTP id 10so4911983ied.33 for ; Fri, 26 Apr 2013 06:16:16 -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=MZboJ4iL8C7pevVr2Y8RfLcz0nSGhgOOJZqhghpnYaY=; b=TDTrFCIyzrt3UtaCahAXgexM3MgBjJWCKidSjVT9j2XzpNIBVSaUf2URNnBLfMe2pf QCi0E95Ugcew34TQEPddybGWI7F+UzbMO4URB5w4XSUzrw/h/avdvbgC1dokHnUBF/rN DsaY3KujvOpLyrXQWGuOEN/rOXwEEYhNBBrovTGY02ypNEgkXtwHTDhlOMqb+J9ht6i1 cQyMxBcSJbhV52PFpIHrdrZE/YpbyqsggAaGUvanCv8bGVjtXwrAAGuIvdUFjW18ky7T DJuR2ZzL+dYlm3ANsYdSkxHtU0huMbTmBlueyvcwktRJOCeJE20SKQlj/sdwEsKFwTt9 vjKw== X-Received: by 10.50.3.67 with SMTP id a3mr1847651iga.88.1366982176073; Fri, 26 Apr 2013 06:16:16 -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.13 for (version=TLSv1.2 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 26 Apr 2013 06:16:15 -0700 (PDT) From: Andre Przywara To: trini@ti.com, albert.u.boot@aribaud.net Date: Fri, 26 Apr 2013 15:14:56 +0200 Message-Id: <1366982099-22360-4-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: ALoCoQlhYpAiOYlrwRezLwBqUnIF9Ww74es/fMLN2u+YO5dprCaooU6JZnmCiB20gEqJC9pb4/AM 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 3/6] ARM: add U-Boot command "hypmode" to switch to non-secure state 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 In preparation for the actual HYP mode switch, we introduce a new U-Boot command called "hypmode". For now we only do the non-secure switch here. Some part of the work is done in the assembly routine in start.S, introduced with the previous patch, but for the full glory we need to setup the GIC distributor interface once for the whole system, which is done in C here. The routine is placed in arch/arm/lib to allow easy access from different boards or CPUs. First we check for the availability of the security extensions. The generic timer base frequency register is only accessible from secure state, so we have to program it now. Actually this should be done from primary firmware before, but some boards seems to omit this, so if needed we do this here with a board specific value. Since we need a safe way to access the GIC, we use the PERIPHBASE registers on Cortex-A15 and A7 CPUs and do some sanity checks. Then we actually do the GIC enablement: a) enable the GIC distributor, both for non-secure and secure state (GICD_CTLR[1:0] = 11b) b) allow all interrupts to be handled from non-secure state (GICD_IGROUPRn = 0xFFFFFFFF) The core specific GIC setup is then done in the assembly routine. The actual U-Boot command is pretty small: calling the routine and doing some error reporting. A return value of 1 will be added later. To enable the whole code we introduce the CONFIG_CMD_VIRT variable. Signed-off-by: Andre Przywara --- arch/arm/include/asm/armv7.h | 2 + arch/arm/lib/Makefile | 2 + arch/arm/lib/virt-v7.c | 116 +++++++++++++++++++++++++++++++++++++++++++ common/Makefile | 1 + common/cmd_virt.c | 59 ++++++++++++++++++++++ 5 files changed, 180 insertions(+) create mode 100644 arch/arm/lib/virt-v7.c create mode 100644 common/cmd_virt.c diff --git a/arch/arm/include/asm/armv7.h b/arch/arm/include/asm/armv7.h index a73630b..3567692 100644 --- a/arch/arm/include/asm/armv7.h +++ b/arch/arm/include/asm/armv7.h @@ -74,4 +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); + #endif diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile index 6ae161a..c5b6b69 100644 --- a/arch/arm/lib/Makefile +++ b/arch/arm/lib/Makefile @@ -58,6 +58,8 @@ COBJS-y += reset.o COBJS-y += cache.o COBJS-y += cache-cp15.o +COBJS-y += virt-v7.o + SRCS := $(GLSOBJS:.o=.S) $(GLCOBJS:.o=.c) \ $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c) OBJS := $(addprefix $(obj),$(SOBJS-y) $(COBJS-y)) diff --git a/arch/arm/lib/virt-v7.c b/arch/arm/lib/virt-v7.c new file mode 100644 index 0000000..416ca29 --- /dev/null +++ b/arch/arm/lib/virt-v7.c @@ -0,0 +1,116 @@ +/* + * (C) Copyright 2013 + * Andre Przywara, Linaro + * + * routines to push ARMv7 processors from secure into non-secure state + * needed to enable ARMv7 virtualization for current hypervisors + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include + +/* the assembly routine doing the actual work in start.S */ +void _nonsec_gic_switch(void); + +#define GICD_CTLR 0x000 +#define GICD_TYPER 0x004 +#define GICD_IGROUPR0 0x080 +#define GICD_SGIR 0xf00 + +#define CPU_ARM_CORTEX_A15 0x4100c0f0 +#define CPU_ARM_CORTEX_A7 0x4100c070 + +static inline unsigned int read_cpsr(void) +{ + unsigned int reg; + + asm volatile ("mrs %0, cpsr\n" : "=r" (reg)); + return reg; +} + +int armv7_switch_nonsec(void) +{ + unsigned int reg; + volatile unsigned int *gicdptr; + unsigned itlinesnr, i; + + /* check whether the CPU supports the security extensions */ + asm("mrc p15, 0, %0, c0, c1, 1\n" : "=r"(reg)); + if ((reg & 0xF0) == 0) + return 2; + + /* the timer frequency for the generic timer needs to be + * programmed still in secure state, should be done by firmware. + * check whether we have the generic timer first + */ +#ifdef CONFIG_SYS_CLK_FREQ + asm("mrc p15, 0, %0, c0, c1, 1\n" : "=r"(reg)); + if ((reg & 0xF0000) == 0x10000) + asm("mcr p15, 0, %0, c14, c0, 0\n" + : : "r"(CONFIG_SYS_CLK_FREQ)); +#endif + + /* the SCR register will be set directly in the monitor mode handler, + * according to the spec one should not tinker with it in secure state + * in SVC mode. Do not try to read it once in non-secure state, + * any access to it will trap. + */ + + /* 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, + * which we know only for sure for those two CPUs. + */ + asm("mrc p15, 0, %0, c0, c0, 0\n" : "=r"(reg)); + if (((reg & 0xFF00FFF0) != 0x4100C0F0) && + ((reg & 0xFF00FFF0) != 0x4100C070)) + return 3; + + /* get the GIC base address from the A15 PERIPHBASE register */ + asm("mrc p15, 4, %0, c15, c0, 0\n" : "=r" (reg)); + + /* the PERIPHBASE can be mapped above 4 GB (lower 8 bits used to + * encode this). Bail out here since we cannot access this without + * enabling paging. + */ + if ((reg & 0xff) != 0) + return 4; + + /* GIC distributor registers start at offset 0x1000 */ + gicdptr = (unsigned *)(reg + 0x1000); + + /* enable the GIC distributor */ + gicdptr[GICD_CTLR / 4] |= 0x03; + + /* TYPER[4:0] contains an encoded number of all interrupts */ + itlinesnr = gicdptr[GICD_TYPER / 4] & 0x1f; + + /* set all bits in the GIC group registers to one to allow access + * from non-secure state + */ + for (i = 0; i <= itlinesnr; i++) + gicdptr[GICD_IGROUPR0 / 4 + i] = (unsigned)-1; + + /* call the non-sec switching code on this CPU */ + _nonsec_gic_switch(); + + return 0; +} diff --git a/common/Makefile b/common/Makefile index 0e0fff1..d9ba5ab 100644 --- a/common/Makefile +++ b/common/Makefile @@ -129,6 +129,7 @@ COBJS-y += cmd_load.o COBJS-$(CONFIG_LOGBUFFER) += cmd_log.o COBJS-$(CONFIG_ID_EEPROM) += cmd_mac.o COBJS-$(CONFIG_CMD_MD5SUM) += cmd_md5sum.o +COBJS-$(CONFIG_CMD_VIRT) += cmd_virt.o COBJS-$(CONFIG_CMD_MEMORY) += cmd_mem.o COBJS-$(CONFIG_CMD_IO) += cmd_io.o COBJS-$(CONFIG_CMD_MFSL) += cmd_mfsl.o diff --git a/common/cmd_virt.c b/common/cmd_virt.c new file mode 100644 index 0000000..132b6b1 --- /dev/null +++ b/common/cmd_virt.c @@ -0,0 +1,59 @@ +/* + * (C) Copyright 2013 + * Andre Przywara, Linaro + * + * command to switch an ARMv7 CPU with security extensions into + * non-secure state + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include + +#include + +static int do_nonsec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + unsigned int ret; + + ret = armv7_switch_nonsec(); + + switch (ret) { + case 0: + break; + case 2: + printf("Security extensions not implemented.\n"); + break; + case 3: + printf("CPU not supported, must be either Cortex-A15 or A7.\n"); + break; + case 4: + printf("PERIPHBASE is above 4 GB, cannot access this.\n"); + break; + } + + return ret; +} + +U_BOOT_CMD( + hypmode, 1, 0, do_nonsec, + "switch ARM CPUs into non-secure state", + "" +);