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