armv7: enabling VFP
[barrelfish] / kernel / arch / armv7 / init.c
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
43 static void bsp_init( void *pointer );
44 static 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. */
50 uintptr_t kernel_stack[KERNEL_STACK_SIZE/sizeof(uintptr_t)]
51     __attribute__((aligned(8)));
52
53 static bool is_bsp = false;
54
55 //
56 // Kernel command line variables and binding options
57 //
58
59 uint32_t periphclk = 0;
60 uint32_t periphbase = 0;
61 uint32_t timerirq = 0;
62 uint32_t cntfrq = 0;
63
64 static 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
77 static void
78 init_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  */
94 bool cpu_is_bsp(void)
95 {
96     return is_bsp;
97 }
98
99 bool 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  */
113 char abt_stack[EXCEPTION_MODE_STACK_BYTES] __attribute__((aligned(8)));
114 char irq_stack[EXCEPTION_MODE_STACK_BYTES] __attribute__((aligned(8)));
115 char fiq_stack[EXCEPTION_MODE_STACK_BYTES] __attribute__((aligned(8)));
116 char undef_stack[EXCEPTION_MODE_STACK_BYTES] __attribute__((aligned(8)));
117 char svc_stack[EXCEPTION_MODE_STACK_BYTES] __attribute__((aligned(8)));
118
119 void 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  */
127 static void
128 exceptions_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  */
143 void
144 arch_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     MSG("Setting coreboot spawn handler\n");
292     coreboot_set_spawn_handler(CPU_ARM7, platform_boot_aps);
293
294     MSG("Calling arm_kernel_startup\n");
295
296     arm_kernel_startup();
297 }
298
299 #if 0
300 /**
301  * \brief Initialization for the BSP (the first core to be booted).
302  * \param pointer address of \c multiboot_info
303  */
304 static void bsp_init( void *pointer )
305 {
306     struct multiboot_info *mb = pointer;
307
308     MSG("We seem to be a BSP; multiboot info:\n");
309     MSG(" mods_addr is 0x%"PRIxLVADDR"\n",       (lvaddr_t)mb->mods_addr);
310     MSG(" mods_count is 0x%"PRIxLVADDR"\n",      (lvaddr_t)mb->mods_count);
311     MSG(" cmdline is 0x%"PRIxLVADDR"\n",         (lvaddr_t)mb->cmdline);
312     MSG(" cmdline reads '%s'\n",                 mb->cmdline);
313     MSG(" mmap_length is 0x%"PRIxLVADDR"\n",     (lvaddr_t)mb->mmap_length);
314     MSG(" mmap_addr is 0x%"PRIxLVADDR"\n",       (lvaddr_t)mb->mmap_addr);
315     MSG(" multiboot_flags is 0x%"PRIxLVADDR"\n", (lvaddr_t)mb->flags);
316 }
317
318 /**
319  * \brief Initialization on a non-BSP (second and successive cores).
320  * \param pointer address of the global structure set up by \c bsp_init
321  */
322 static void nonbsp_init( void *pointer )
323 {
324     panic("Unimplemented.\n");
325
326 #if 0
327     MSG("We seem to be an AP.\n");
328     // global = (struct global *)GLOBAL_VBASE;
329
330     // Our core data (struct arm_core_data) is placed one page before the
331     // first byte of the kernel image
332     core_data = (struct arm_core_data *)
333         ((lpaddr_t)&kernel_first_byte - BASE_PAGE_SIZE);
334     core_data->cmdline = (lpaddr_t)&core_data->kernel_cmdline;
335     kcb_current = (struct kcb*) (lpaddr_t)core_data->kcb;
336     my_core_id = core_data->dst_core_id;
337
338     // Tell the BSP that we are started up
339     platform_notify_bsp();
340
341     // Print kernel address for debugging with gdb
342     MSG("Barrelfish non-BSP CPU driver starting at addr 0x%"PRIxLVADDR" on core %"PRIuCOREID"\n",
343            local_phys_to_mem((lpaddr_t)&kernel_first_byte), my_core_id);
344 #endif
345 }
346 #endif