1/* 2 * Copyright (c) 2009-2016, ETH Zurich. All rights reserved. 3 * 4 * This file is distributed under the terms in the attached LICENSE file. If 5 * you do not find this file, copies can be found by writing to: ETH Zurich 6 * D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich, Attn: Systems Group. 7 */ 8 9/** 10 * \file 11 * \brief CPU driver init code for ARMv7A cores. 12 */ 13#include <kernel.h> 14 15#include <barrelfish_kpi/arm_core_data.h> 16#include <barrelfish_kpi/flags_arch.h> 17#include <bitmacros.h> 18#include <boot_protocol.h> 19#include <coreboot.h> 20#include <cp15.h> 21#include <dev/cpuid_arm_dev.h> 22#include <elf/elf.h> 23#include <exceptions.h> 24#include <getopt/getopt.h> 25#include <gic.h> 26#include <global.h> 27#include <init.h> 28#include <kcb.h> 29#include <kernel_multiboot.h> 30#include <offsets.h> 31#include <paging_kernel_arch.h> 32#include <platform.h> 33#include <serial.h> 34#include <startup_arch.h> 35#include <stdio.h> 36#include <string.h> 37 38/* 39 * Forward declarations 40 */ 41 42#if 0 43static void bsp_init( void *pointer ); 44static void nonbsp_init( void *pointer ); 45#endif 46 47#define MSG(format, ...) printk( LOG_NOTE, "ARMv7-A: "format, ## __VA_ARGS__ ) 48 49/* This is the kernel stack, allocated in the BSS. */ 50uintptr_t kernel_stack[KERNEL_STACK_SIZE/sizeof(uintptr_t)] 51 __attribute__((aligned(8))); 52 53static bool is_bsp = false; 54 55// 56// Kernel command line variables and binding options 57// 58 59uint32_t periphclk = 0; 60uint32_t periphbase = 0; 61uint32_t timerirq = 0; 62uint32_t cntfrq = 0; 63 64static struct cmdarg cmdargs[] = { 65 { "consolePort", ArgType_UInt, { .uinteger = (void *)0 } }, 66 { "debugPort", ArgType_UInt, { .uinteger = (void *)0 } }, 67 { "loglevel", ArgType_Int, { .integer = (void *)0 } }, 68 { "logmask", ArgType_Int, { .integer = (void *)0 } }, 69 { "timeslice", ArgType_UInt, { .uinteger = (void *)0 } }, 70 { "periphclk", ArgType_UInt, { .uinteger = (void *)0 } }, 71 { "periphbase", ArgType_UInt, { .uinteger = (void *)0 } }, 72 { "timerirq" , ArgType_UInt, { .uinteger = (void *)0 } }, 73 { "cntfrq" , ArgType_UInt, { .uinteger = (void *)0 } }, 74 { NULL, 0, { NULL } } 75}; 76 77static void 78init_cmdargs(void) { 79 cmdargs[0].var.uinteger= &serial_console_port; 80 cmdargs[1].var.uinteger= &serial_debug_port; 81 cmdargs[2].var.integer= &kernel_loglevel; 82 cmdargs[3].var.integer= &kernel_log_subsystem_mask; 83 cmdargs[4].var.uinteger= &config_timeslice; 84 cmdargs[5].var.uinteger= &periphclk; 85 cmdargs[6].var.uinteger= &periphbase; 86 cmdargs[7].var.uinteger= &timerirq; 87 cmdargs[8].var.uinteger= &cntfrq; 88} 89 90/** 91 * \brief Is this the BSP? 92 * \return True iff the current core is the bootstrap processor. 93 */ 94bool cpu_is_bsp(void) 95{ 96 return is_bsp; 97} 98 99bool arch_core_is_bsp(void) 100{ 101 return cpu_is_bsp(); 102} 103 104#define EXCEPTION_MODE_STACK_BYTES 256 105 106/* 107 * Exception mode stacks 108 * 109 * These are small stacks used to figure out where to spill registers. As 110 * these are banked functions are expected to leave them as found (ie. so they 111 * do not need to be reset next time around). 112 */ 113char abt_stack[EXCEPTION_MODE_STACK_BYTES] __attribute__((aligned(8))); 114char irq_stack[EXCEPTION_MODE_STACK_BYTES] __attribute__((aligned(8))); 115char fiq_stack[EXCEPTION_MODE_STACK_BYTES] __attribute__((aligned(8))); 116char undef_stack[EXCEPTION_MODE_STACK_BYTES] __attribute__((aligned(8))); 117char svc_stack[EXCEPTION_MODE_STACK_BYTES] __attribute__((aligned(8))); 118 119void set_stack_for_mode(uint8_t mode, void *sp_mode); 120 121/** 122 * Initialise the banked exception-mode stack registers. 123 * 124 * The kernel doesn't actually need separate stacks for different modes, as 125 * it's reentrant, but it's useful for debugging in-kernel faults. 126 */ 127static void 128exceptions_load_stacks(void) { 129 set_stack_for_mode(ARM_MODE_ABT, abt_stack + EXCEPTION_MODE_STACK_BYTES); 130 set_stack_for_mode(ARM_MODE_IRQ, irq_stack + EXCEPTION_MODE_STACK_BYTES); 131 set_stack_for_mode(ARM_MODE_FIQ, fiq_stack + EXCEPTION_MODE_STACK_BYTES); 132 set_stack_for_mode(ARM_MODE_UND, undef_stack + EXCEPTION_MODE_STACK_BYTES); 133 set_stack_for_mode(ARM_MODE_SVC, svc_stack + EXCEPTION_MODE_STACK_BYTES); 134} 135 136/** 137 * \brief Continue kernel initialization in kernel address space. 138 * 139 * This function sets up exception handling, initializes devices and enables 140 * interrupts. After that it calls arm_kernel_startup(), which should not 141 * return (if it does, this function halts the kernel). 142 */ 143void 144arch_init(struct arm_core_data *boot_core_data, 145 struct armv7_boot_record *bootrec) { 146 /* Now we're definitely executing inside the kernel window, with 147 * translation and caches available, and all pointers relocated to their 148 * correct virtual address. The low mappings are still enabled, but we 149 * shouldn't be accessing them any longer, no matter where RAM is located. 150 * */ 151 152 /* There's no boot record iff we're the first core to boot. */ 153 is_bsp= (bootrec == NULL); 154 155 /* Save our core data. */ 156 core_data= boot_core_data; 157 158 /* Let the paging code know where the kernel page tables are. Note that 159 * paging_map_device() won't work until this is called. */ 160 paging_load_pointers(core_data); 161 162 /* Reinitialise the serial port, as it may have moved, and we need to map 163 * it into high memory. */ 164 /* XXX - reread the args to update serial_console_port. */ 165 serial_console_init(is_bsp); 166 167 /* Load the global lock address. */ 168 global= (struct global *)core_data->global; 169 170 /* Select high vectors */ 171 uint32_t sctlr= cp15_read_sctlr(); 172 sctlr|= BIT(13); 173 cp15_write_sctlr(sctlr); 174 175 my_core_id = cp15_get_cpu_id(); 176 177 MSG("Barrelfish CPU driver starting on ARMv7\n"); 178 MSG("Core data at %p\n", core_data); 179 MSG("Global data at %p\n", global); 180 MSG("Boot record at %p\n", bootrec); 181 errval_t errval; 182 assert(core_data != NULL); 183 assert(paging_mmu_enabled()); 184 185 if(!is_bsp) { 186 MSG("APP core.\n"); 187 platform_notify_bsp(&bootrec->done); 188 } 189 190 /* Read the build ID, and store it. */ 191 const char *build_id_name= 192 ((const char *)&build_id_nhdr) + sizeof(struct Elf32_Nhdr); 193 194 if(build_id_nhdr.n_type != NT_GNU_BUILD_ID || 195 build_id_nhdr.n_namesz != 4 || 196 strncmp(build_id_name, "GNU", 4)) { 197 panic("Build ID missing or corrupted.\n"); 198 } 199 200 if(build_id_nhdr.n_descsz > MAX_BUILD_ID) { 201 panic("Build ID is more than %zu bytes.\n", MAX_BUILD_ID); 202 } 203 204 core_data->build_id.length= build_id_nhdr.n_descsz; 205 const char *build_id_data= build_id_name + build_id_nhdr.n_namesz; 206 memcpy(core_data->build_id.data, build_id_data, build_id_nhdr.n_descsz); 207 208 MSG("Build ID: "); 209 for(size_t i= 0; i < core_data->build_id.length; i++) 210 printf("%02x", build_id_data[i]); 211 printf("\n"); 212 213 struct multiboot_info *mb= 214 (struct multiboot_info *)core_data->multiboot_header; 215 216 /* On the BSP core, initialise our core_data command line. */ 217 if(is_bsp) { 218 const char *mb_cmdline= 219 (const char *)local_phys_to_mem((lpaddr_t)mb->cmdline); 220 memcpy(core_data->cmdline_buf, mb_cmdline, 221 min(MAXCMDLINE-1, strlen(mb_cmdline))); 222 core_data->cmdline_buf[MAXCMDLINE-1]= '\0'; 223 } 224 225 MSG("Multiboot info:\n"); 226 MSG(" info header at 0x%"PRIxLVADDR"\n", (lvaddr_t)mb); 227 MSG(" mods_addr is P:0x%"PRIxLPADDR"\n", (lpaddr_t)mb->mods_addr); 228 MSG(" mods_count is 0x%"PRIu32"\n", mb->mods_count); 229 MSG(" cmdline is at P:0x%"PRIxLPADDR"\n", (lpaddr_t)mb->cmdline); 230 MSG(" cmdline reads '%s'\n", local_phys_to_mem((lpaddr_t)mb->cmdline)); 231 MSG(" mmap_length is 0x%"PRIu32"\n", mb->mmap_length); 232 MSG(" mmap_addr is P:0x%"PRIxLPADDR"\n", (lpaddr_t)mb->mmap_addr); 233 MSG(" multiboot_flags is 0x%"PRIu32"\n", mb->flags); 234 235#if 0 236 if(cpu_is_bsp()) bsp_init( NULL ); 237 else nonbsp_init(NULL); 238#endif 239 240 MSG("Initializing exceptions.\n"); 241 242 if(is_bsp) { 243 /* Map the exception vectors. */ 244 paging_map_vectors(); 245 } 246 247 /* Initialise the exception stack pointers. */ 248 exceptions_load_stacks(); 249 250 /* Relocate the KCB into our new address space. */ 251 kcb_current= (struct kcb *)(lpaddr_t)core_data->kcb; 252 MSG("KCB at %p\n", kcb_current); 253 254 MSG("Parsing command line\n"); 255 init_cmdargs(); 256 parse_commandline((const char *)core_data->cmdline, cmdargs); 257 config_timeslice = min(max(config_timeslice, 1), 20); 258 259 errval = serial_debug_init(); 260 if (err_is_fail(errval)) { 261 MSG("Failed to initialize debug port: %d", serial_debug_port); 262 } 263 MSG("Debug port initialized.\n"); 264 265 MSG("Initializing the GIC\n"); 266 gic_init(); 267 MSG("gic_init done\n"); 268 269 if (cpu_is_bsp()) { 270 platform_revision_init(); 271 MSG("%"PRIu32" cores in system\n", platform_get_core_count()); 272 } 273 274 MSG("Enabling timers\n"); 275 timers_init(config_timeslice); 276 277 MSG("Enabling cycle counter user access\n"); 278 /* enable user-mode access to the performance counter */ 279 __asm volatile ("mcr p15, 0, %0, C9, C14, 0\n\t" :: "r"(1)); 280 /* disable counter overflow interrupts (just in case) */ 281 __asm volatile ("mcr p15, 0, %0, C9, C14, 2\n\t" :: "r"(0x8000000f)); 282 283 MSG("Enabling VFP\n"); 284 // full access to cp10 and cp11 285 __asm volatile ("ldr r0, =(0xf << 20)\n" 286 "mcr p15, 0, r0, c1, c0, 2\n"); 287 // enable floating-point extensions 288 __asm volatile ("mov r3, #0x40000000\n" 289 "vmsr fpexc, r3\n"); 290 291 // uint32_t mvfr0, mvfr1; 292 // __asm volatile ("vmrs %0, mvfr0\n" 293 // "vmrs %1, mvfr1\n" 294 // : "=r" (mvfr0), "=r" (mvfr1)); 295 // MSG("VFP: MVFR0=%08x MVFR1=%08x\n", mvfr0, mvfr1); 296 297 MSG("Setting coreboot spawn handler\n"); 298 coreboot_set_spawn_handler(CPU_ARM7, platform_boot_aps); 299 300 MSG("Calling arm_kernel_startup\n"); 301 302 arm_kernel_startup(); 303} 304 305#if 0 306/** 307 * \brief Initialization for the BSP (the first core to be booted). 308 * \param pointer address of \c multiboot_info 309 */ 310static void bsp_init( void *pointer ) 311{ 312 struct multiboot_info *mb = pointer; 313 314 MSG("We seem to be a BSP; multiboot info:\n"); 315 MSG(" mods_addr is 0x%"PRIxLVADDR"\n", (lvaddr_t)mb->mods_addr); 316 MSG(" mods_count is 0x%"PRIxLVADDR"\n", (lvaddr_t)mb->mods_count); 317 MSG(" cmdline is 0x%"PRIxLVADDR"\n", (lvaddr_t)mb->cmdline); 318 MSG(" cmdline reads '%s'\n", mb->cmdline); 319 MSG(" mmap_length is 0x%"PRIxLVADDR"\n", (lvaddr_t)mb->mmap_length); 320 MSG(" mmap_addr is 0x%"PRIxLVADDR"\n", (lvaddr_t)mb->mmap_addr); 321 MSG(" multiboot_flags is 0x%"PRIxLVADDR"\n", (lvaddr_t)mb->flags); 322} 323 324/** 325 * \brief Initialization on a non-BSP (second and successive cores). 326 * \param pointer address of the global structure set up by \c bsp_init 327 */ 328static void nonbsp_init( void *pointer ) 329{ 330 panic("Unimplemented.\n"); 331 332#if 0 333 MSG("We seem to be an AP.\n"); 334 // global = (struct global *)GLOBAL_VBASE; 335 336 // Our core data (struct arm_core_data) is placed one page before the 337 // first byte of the kernel image 338 core_data = (struct arm_core_data *) 339 ((lpaddr_t)&kernel_first_byte - BASE_PAGE_SIZE); 340 core_data->cmdline = (lpaddr_t)&core_data->kernel_cmdline; 341 kcb_current = (struct kcb*) (lpaddr_t)core_data->kcb; 342 my_core_id = core_data->dst_core_id; 343 344 // Tell the BSP that we are started up 345 platform_notify_bsp(); 346 347 // Print kernel address for debugging with gdb 348 MSG("Barrelfish non-BSP CPU driver starting at addr 0x%"PRIxLVADDR" on core %"PRIuCOREID"\n", 349 local_phys_to_mem((lpaddr_t)&kernel_first_byte), my_core_id); 350#endif 351} 352#endif 353