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