1/* 2 * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 * 4 * SPDX-License-Identifier: GPL-2.0-only 5 */ 6 7#include <autoconf.h> 8#include <elfloader/gen_config.h> 9#include <elfloader.h> 10#include <printf.h> 11 12/* TODO: get rid of this, make GIC initialisation part of a driver. */ 13#define TK1_GICD_PADDR 0x50041000 14#define TK1_GICC_PADDR 0x50042000 15 16extern void flush_dcache(void); 17extern void invalidate_icache(void); 18 19/* non-secure bit: 0 secure; 1 nonsecure */ 20#define SCR_NS (0) 21 22/* controls which mode takes IRQ exceptions: 0 IRQ mode; 1 monitor mode */ 23#define SCR_IRQ (1) 24 25/* FIQ mode control */ 26#define SCR_FIQ (2) 27 28/* external abort handler. 0 abort mode; 1 monitor mode */ 29#define SCR_EA (3) 30 31/* CPSR.F can be modified in nonsecure mode */ 32#define SCR_FW (4) 33 34/* CPSR.A can be modified in nonsecure mode */ 35#define SCR_AW (5) 36 37/* not early terminination. not implmented */ 38#define SCR_NET (6) 39 40/* secure monitor call disabled: 0 smc executes in nonsecure state; 41 * 1 undefined instruction in nonsecure state 42 */ 43#define SCR_SCD (7) 44 45/* hyp call enable: 0 hvc instruction is undefined in nonsecure pl1 mode 46 * and unpredictable in hyp mode 47 * 1 hvc is enabled in nonsecure pl1. 48 */ 49#define SCR_HCE (8) 50 51/* secure instruction fetch. when in secure state, the bit disables 52 * instruction fetches from non-secure memory */ 53#define SCR_SIF (9) 54 55#define MONITOR_MODE (0x16) 56#define SUPERVISOR_MODE (0x13) 57#define HYPERVISOR_MODE (0x1a) 58 59/* if seL4 is used a hypervior, we should enable both HCe and SCE bits. 60 * the secure monitor exception handler does very limited things, so 61 * we let the seL4 handle interrupts/exceptions. 62 */ 63 64#define MONITOR_MODE (0x16) 65#define SUPERVISOR_MODE (0x13) 66#define HYPERVISOR_MODE (0x1a) 67 68void arm_halt(void) 69{ 70 while (1) { 71 asm volatile("wfe"); 72 } 73} 74 75/* steal the last 1 MiB physical memory for monitor mode */ 76 77#define MON_PA_START (0x80000000 + 0x27f00000) 78#define MON_PA_SIZE (1 << 20) 79#define MON_PA_END (MON_PA_START + MON_PA_SIZE) 80#define MON_PA_STACK (MON_PA_END - 0x10) 81#define MON_VECTOR_START (MON_PA_START) 82#define MON_HANDLER_START (MON_PA_START + 0x10000) 83#define LOADED_OFFSET 0x90000000 84 85#if defined(CONFIG_ARM_MONITOR_HOOK) || defined(CONFIG_ARM_NS_SUPERVISOR_MODE) \ 86 || defined(CONFIG_ARM_HYPERVISOR_MODE) || defined(CONFIG_ARM_MONITOR_MODE) 87static int mon_init_done = 0; 88 89static void switch_to_mon_mode(void) 90{ 91 if (mon_init_done == 0) { 92 /* first need to make sure that we are in secure world */ 93 uint32_t scr = 0; 94 95 /* read the secure configuration register, note if we are 96 * in nonsecure world, the instruction fails. 97 */ 98 99 asm volatile("mrc p15, 0, %0, c1, c1, 0":"=r"(scr)); 100 101 if (scr & BIT(SCR_NS)) { 102 printf("In nonsecure world, you should never see this!\n"); 103 arm_halt(); 104 } 105 106 /* enable hyper call */ 107 scr = BIT(SCR_HCE); 108 109 asm volatile("mcr p15, 0, %0, c1, c1, 0"::"r"(scr)); 110 111 /* now switch to secure monitor mode. restoring our stack and link register in the process 112 * as these two registers are banked. */ 113 uint32_t sp_temp = 0; 114 uint32_t lr_temp = 0; 115 asm volatile("mov %[SP_TEMP], sp\n" 116 "mov %[LR_TEMP], lr\n" 117 "cps %[MON_MODE]\n\t" 118 "isb\n" 119 "mov sp, %[SP_TEMP]\n" 120 "mov lr, %[LR_TEMP]\n" 121 : [SP_TEMP]"+r"(sp_temp), 122 [LR_TEMP]"+r"(lr_temp) 123 : [MON_MODE]"I"(MONITOR_MODE)); 124 mon_init_done = 1; 125 printf("ELF loader: monitor mode init done\n"); 126 } 127} 128 129#endif 130 131#ifdef CONFIG_ARM_MONITOR_HOOK 132 133extern void arm_monitor_vector(void); 134extern void arm_monitor_vector_end(void); 135extern void *memcpy(void *dest, void *src, size_t n); 136extern char _bootstack_top[1]; 137 138static void install_monitor_hook(void) 139{ 140 uint32_t size = arm_monitor_vector_end - arm_monitor_vector; 141 /* switch monitor mode if not already */ 142 switch_to_mon_mode(); 143 printf("Copy monitor mode vector from %x to %x size %x\n", (arm_monitor_vector), MON_VECTOR_START, size); 144 memcpy((void *)MON_VECTOR_START, (void *)(arm_monitor_vector), size); 145 146 asm volatile("mcr p15, 0, %0, c12, c0, 1"::"r"(MON_VECTOR_START)); 147} 148 149#endif 150 151#ifdef CONFIG_ARM_HYPERVISOR_MODE 152static void switch_to_hyp_mode(void) 153{ 154 uint32_t scr = 0; 155 156 /* 157 * Need to make sure anything in the write buffer is 158 * in RAM, and nothing in the cache that we want to access is tagged 159 * 'secure' because we're about to switch to non-secure mode. 160 * Note: flush_dcache() does a flush-and-invalidate. 161 */ 162 flush_dcache(); 163 invalidate_icache(); 164 165 asm volatile("mrc p15, 0, %0, c1, c1, 0":"=r"(scr)); 166 scr |= BIT(SCR_HCE); 167 scr &= ~BIT(SCR_SCD); 168 scr |= BIT(SCR_NS); 169 scr &= ~BIT(SCR_SIF); 170 asm volatile("mcr p15, 0, %0, c1, c1, 0"::"r"(scr)); 171 /* now switch to hypervisor mode. restoring our stack and link register in the process 172 * as these two registers are banked. */ 173 uint32_t sp_temp = 0; 174 uint32_t lr_temp = 0; 175 asm volatile("mov %[SP_TEMP], sp\n" 176 "mov %[LR_TEMP], lr\n" 177 "cps %[HYP_MODE]\n\t" 178 "isb\n" 179 "mov sp, %[SP_TEMP]\n" 180 "mov lr, %[LR_TEMP]\n" 181 : [SP_TEMP]"+r"(sp_temp), 182 [LR_TEMP]"+r"(lr_temp) 183 : [HYP_MODE]"I"(HYPERVISOR_MODE)); 184 185 asm volatile("mrs %0, cpsr":"=r"(scr)); 186 printf("Load seL4 in nonsecure HYP mode %x", scr); 187} 188#endif 189 190#ifdef CONFIG_ARM_NS_SUPERVISOR_MODE 191static void switch_to_ns_svc_mode(void) 192{ 193 uint32_t scr = 0; 194 195 asm volatile("cps %0\n\t" 196 "isb\n" 197 ::"I"(SUPERVISOR_MODE)); 198 199 asm volatile("mov r0, sp"); 200 asm volatile("mrc p15, 0, %0, c1, c1, 0":"=r"(scr)); 201 scr |= BIT(SCR_NS); 202 203 asm volatile("mcr p15, 0, %0, c1, c1, 0"::"r"(scr)); 204 asm volatile("mov sp, r0"); 205 206 printf("Load seL4 in nonsecure SVC mode\n"); 207} 208#endif 209 210extern void arm_monitor_vector(void); 211 212#if defined(CONFIG_ARM_HYPERVISOR_MODE) || defined(CONFIG_ARM_NS_SUPERVISOR_MODE) 213/* tk1 uses GIC v2 */ 214struct gicd_map { 215 uint32_t enable; 216 uint32_t ic_type; 217 uint32_t dist_ident; 218 uint32_t res1[29]; 219 uint32_t security[32]; 220 uint32_t enable_set[32]; 221 uint32_t enable_clr[32]; 222 uint32_t pending_set[32]; 223 uint32_t pending_clr[32]; 224 uint32_t active[32]; 225 uint32_t res2[32]; 226 uint32_t priority[255]; 227}; 228 229struct gicc_map { 230 uint32_t ctrl; 231 uint32_t pri_mask; 232 uint32_t pb_c; 233 uint32_t int_ack; 234 uint32_t eoi; 235}; 236 237volatile struct gicd_map *gicd = (volatile struct gicd_map *)(TK1_GICD_PADDR); 238volatile struct gicc_map *gicc = (volatile struct gicc_map *)(TK1_GICC_PADDR); 239 240static void route_irqs_to_nonsecure(void) 241{ 242 int i = 0; 243 int nirqs = 32 * ((gicd->ic_type & 0x1f) + 1); 244 printf("Number of IRQs: %d\n", nirqs); 245 gicd->enable = 0; 246 247 /* note: the security and priority initialisations in 248 * non-secure mode will not work, but use the values 249 * set by secure mode. 250 */ 251 252 /* set all irqs to group 1 - nonsecure */ 253 for (i = 0; i < nirqs; i += 32) { 254 gicd->security[i >> 5] = 0xffffffff; 255 } 256 257 /* assign the irqs in a single priority group: no preemptions */ 258 for (i = 0; i < nirqs; i += 4) { 259 gicd->priority[i >> 2] = 0x80808080; 260 } 261 262 gicc->ctrl = 0; 263 264 /* writing 255 always set the largest (lowest) priority value. 265 * missing this hurts health */ 266 gicc->pri_mask = 0xff; 267} 268#endif 269 270static void enable_ns_access_cp(void) 271{ 272 uint32_t nsacr = 0; 273 asm volatile("mrc p15, 0, %0, c1, c1, 2":"=r"(nsacr)); 274 275 /* enable cp10, cp11 */ 276 nsacr |= BIT(10) | BIT(11); 277 asm volatile("mcr p15, 0, %0, c1, c1, 2"::"r"(nsacr)); 278 279 asm volatile("isb"); 280} 281 282void platform_init(void) 283{ 284#if defined(CONFIG_ARM_MONITOR_HOOK) || defined(CONFIG_ARM_NS_SUPERVISOR_MODE) \ 285 || defined(CONFIG_ARM_HYPERVISOR_MODE) || defined(CONFIG_ARM_MONITOR_MODE) 286 /* mon_init_done needs to explicitly initialised when booting a binary image */ 287 mon_init_done = 0; 288#endif 289#ifdef CONFIG_ARM_MONITOR_HOOK 290 install_monitor_hook(); 291#endif 292 293 enable_ns_access_cp(); 294 295#ifdef CONFIG_ARM_NS_SUPERVISOR_MODE 296 switch_to_mon_mode(); 297 route_irqs_to_nonsecure(); 298 switch_to_ns_svc_mode(); 299#endif 300 301#ifdef CONFIG_ARM_HYPERVISOR_MODE 302 switch_to_mon_mode(); 303 route_irqs_to_nonsecure(); 304 switch_to_hyp_mode(); 305#endif 306 307#ifdef CONFIG_ARM_MONITOR_MODE 308 switch_to_mon_mode(); 309#endif 310 311} 312