aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch/arm/arm32/mode_switch.S
diff options
context:
space:
mode:
Diffstat (limited to 'xen/arch/arm/arm32/mode_switch.S')
-rw-r--r--xen/arch/arm/arm32/mode_switch.S121
1 files changed, 121 insertions, 0 deletions
diff --git a/xen/arch/arm/arm32/mode_switch.S b/xen/arch/arm/arm32/mode_switch.S
new file mode 100644
index 0000000000..411eb924cb
--- /dev/null
+++ b/xen/arch/arm/arm32/mode_switch.S
@@ -0,0 +1,121 @@
+/*
+ * xen/arch/arm/mode_switch.S
+ *
+ * Start-of day code to take a CPU from Secure mode to Hyp mode.
+ *
+ * Tim Deegan <tim@xen.org>
+ * Copyright (c) 2011-2012 Citrix Systems.
+ *
+ * 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.
+ */
+
+#include <asm/config.h>
+#include <asm/page.h>
+#include <asm/platform_vexpress.h>
+#include <asm/asm_defns.h>
+#include <asm/gic.h>
+
+
+/* XXX: Versatile Express specific code */
+/* wake up secondary cpus */
+.globl kick_cpus
+kick_cpus:
+ /* write start paddr to v2m sysreg FLAGSSET register */
+ ldr r0, =(V2M_SYS_MMIO_BASE) /* base V2M sysreg MMIO address */
+ dsb
+ mov r2, #0xffffffff
+ str r2, [r0, #(V2M_SYS_FLAGSCLR)]
+ dsb
+ ldr r2, =start
+ add r2, r2, r10
+ str r2, [r0, #(V2M_SYS_FLAGSSET)]
+ dsb
+ /* send an interrupt */
+ ldr r0, =(GIC_BASE_ADDRESS + GIC_DR_OFFSET) /* base GICD MMIO address */
+ mov r2, #0x1
+ str r2, [r0, #(GICD_CTLR * 4)] /* enable distributor */
+ mov r2, #0xfe0000
+ str r2, [r0, #(GICD_SGIR * 4)] /* send IPI to everybody */
+ dsb
+ str r2, [r0, #(GICD_CTLR * 4)] /* disable distributor */
+ mov pc, lr
+
+
+/* Get up a CPU into Hyp mode. Clobbers r0-r3.
+ *
+ * Expects r12 == CPU number
+ *
+ * This code is specific to the VE model, and not intended to be used
+ * on production systems. As such it's a bit hackier than the main
+ * boot code in head.S. In future it will be replaced by better
+ * integration with the bootloader/firmware so that Xen always starts
+ * in Hyp mode. */
+
+.globl enter_hyp_mode
+enter_hyp_mode:
+ mov r3, lr /* Put return address in non-banked reg */
+ cpsid aif, #0x16 /* Enter Monitor mode */
+ mrc CP32(r0, SCR)
+ orr r0, r0, #0x100 /* Set HCE */
+ orr r0, r0, #0xb1 /* Set SCD, AW, FW and NS */
+ bic r0, r0, #0xe /* Clear EA, FIQ and IRQ */
+ mcr CP32(r0, SCR)
+ /* Ugly: the system timer's frequency register is only
+ * programmable in Secure state. Since we don't know where its
+ * memory-mapped control registers live, we can't find out the
+ * right frequency. Use the VE model's default frequency here. */
+ ldr r0, =0x5f5e100 /* 100 MHz */
+ mcr CP32(r0, CNTFRQ)
+ ldr r0, =0x40c00 /* SMP, c11, c10 in non-secure mode */
+ mcr CP32(r0, NSACR)
+ mov r0, #GIC_BASE_ADDRESS
+ add r0, r0, #GIC_DR_OFFSET
+ /* Disable the GIC distributor, on the boot CPU only */
+ mov r1, #0
+ teq r12, #0 /* Is this the boot CPU? */
+ streq r1, [r0]
+ /* Continuing ugliness: Set up the GIC so NS state owns interrupts,
+ * The first 32 interrupts (SGIs & PPIs) must be configured on all
+ * CPUs while the remainder are SPIs and only need to be done one, on
+ * the boot CPU. */
+ add r0, r0, #0x80 /* GICD_IGROUP0 */
+ mov r2, #0xffffffff /* All interrupts to group 1 */
+ teq r12, #0 /* Boot CPU? */
+ str r2, [r0] /* Interrupts 0-31 (SGI & PPI) */
+ streq r2, [r0, #4] /* Interrupts 32-63 (SPI) */
+ streq r2, [r0, #8] /* Interrupts 64-95 (SPI) */
+ /* Disable the GIC CPU interface on all processors */
+ mov r0, #GIC_BASE_ADDRESS
+ add r0, r0, #GIC_CR_OFFSET
+ mov r1, #0
+ str r1, [r0]
+ /* Must drop priority mask below 0x80 before entering NS state */
+ ldr r1, =0xff
+ str r1, [r0, #0x4] /* -> GICC_PMR */
+ /* Reset a few config registers */
+ mov r0, #0
+ mcr CP32(r0, FCSEIDR)
+ mcr CP32(r0, CONTEXTIDR)
+ /* Allow non-secure access to coprocessors, FIQs, VFP and NEON */
+ ldr r1, =0x3fff /* 14 CP bits set, all others clear */
+ mcr CP32(r1, NSACR)
+
+ mrs r0, cpsr /* Copy the CPSR */
+ add r0, r0, #0x4 /* 0x16 (Monitor) -> 0x1a (Hyp) */
+ msr spsr_cxsf, r0 /* into the SPSR */
+ movs pc, r3 /* Exception-return into Hyp mode */
+
+/*
+ * Local variables:
+ * mode: ASM
+ * indent-tabs-mode: nil
+ * End:
+ */