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 boot code for ARMv7A cores.
12 */
13#include <kernel.h>
14
15#include <barrelfish_kpi/arm_core_data.h>
16#include <boot_protocol.h>
17#include <cp15.h>
18#include <dev/cpuid_arm_dev.h>
19#include <getopt/getopt.h>
20#include <global.h>
21#include <kcb.h>
22#include <multiboot.h>
23#include <paging_kernel_arch.h>
24#include <serial.h>
25#include <stdio.h>
26
27#define MSG(format, ...) printk( LOG_NOTE, "ARMv7-A: "format, ## __VA_ARGS__ )
28
29void boot_bsp_core(void *pointer, void *cpu_driver_entry,
30                   void *cpu_driver_base);
31void boot_app_core(struct armv7_boot_record *bootrec);
32
33extern char boot_start;
34
35coreid_t my_core_id;
36
37extern union arm_l1_entry l1_low [ARM_L1_MAX_ENTRIES];
38extern union arm_l1_entry l1_high[ARM_L1_MAX_ENTRIES];
39
40/* This is the table of boot records on which core spin, waiting for a boot
41 * request.  Presently there's only one, but if we want to scale to more than
42 * a few cores, we'll probably want to hash into this based on MPID. */
43struct armv7_boot_record boot_records[1];
44
45/* There is only one copy of the global locks, which is allocated alongside
46 * the BSP kernel.  All kernels have their pointers set to the BSP copy. */
47static struct global bsp_global __attribute__((section(".boot")));
48struct global *global= &bsp_global;
49
50/* The BSP core's KCB is allocated here.  Application cores will have theirs
51 * allocated at user level. */
52struct kcb bsp_kcb __attribute__((section(".boot")));
53
54struct arm_core_data boot_core_data __attribute__((section(".boot")));
55
56/* Print a little information about the processor, and check that it supports
57 * the features we require. */
58static bool check_cpuid(void) __attribute__((noinline));
59static bool
60check_cpuid(void) {
61    uint32_t midr= cp15_read_midr();
62
63    /* XXX - Mackerel should give nice strings to print. */
64    MSG("This is an ");
65
66    if(cpuid_arm_midr_architecture_extract((uint8_t *)&midr) != 0xf) {
67        printf("unsupported ARMv6 or earlier core\n");
68        return false;
69    }
70
71    switch(cpuid_arm_midr_implementer_extract((uint8_t *)&midr)) {
72        case cpuid_arm_impl_arm:
73            printf("ARM ");
74            switch(cpuid_arm_midr_part_extract((uint8_t *)&midr)) {
75                case cpuid_arm_part_a5:
76                    printf("Cortex-A5 ");
77                    break;
78                case cpuid_arm_part_a7:
79                    printf("Cortex-A7 ");
80                    break;
81                case cpuid_arm_part_a8:
82                    printf("Cortex-A8 ");
83                    break;
84                case cpuid_arm_part_a9:
85                    printf("Cortex-A9 ");
86                    break;
87                case cpuid_arm_part_a15:
88                    printf("Cortex-A15 ");
89                    break;
90                case cpuid_arm_part_a17:
91                    printf("Cortex-A17 ");
92                    break;
93                case cpuid_arm_part_a53:
94                    printf("Cortex-A53 ");
95                    break;
96                case cpuid_arm_part_a57:
97                    printf("Cortex-A57 ");
98                    break;
99                case cpuid_arm_part_a72:
100                    printf("Cortex-A72 ");
101                    break;
102                case cpuid_arm_part_a73:
103                    printf("Cortex-A73 ");
104                    break;
105            }
106            printf("r%dp%d\n",
107                   cpuid_arm_midr_variant_extract((uint8_t *)&midr),
108                   cpuid_arm_midr_revision_extract((uint8_t *)&midr));
109            break;
110
111        case cpuid_arm_impl_dec:
112            printf("Unknown DEC core\n");
113            break;
114        case cpuid_arm_impl_motorola:
115            printf("Unknown Motorola core\n");
116            break;
117        case cpuid_arm_impl_qualcomm:
118            printf("Unknown Qualcomm core\n");
119            break;
120        case cpuid_arm_impl_marvell:
121            printf("Unknown Marvell core\n");
122            break;
123        case cpuid_arm_impl_intel:
124            printf("Unknown Intel core\n");
125            break;
126
127        default:
128            printf("Unknown manufacturer's core\n");
129            break;
130    }
131
132    uint32_t id_pfr1= cp15_read_id_pfr1();
133    if(cpuid_arm_id_pfr1_security_extract((uint8_t *)&id_pfr1) ==
134       cpuid_arm_sec_ni) {
135        MSG("  Security extensions required but not implemented\n");
136        return false;
137    }
138    else {
139        MSG("  Security extensions implemented\n");
140    }
141
142    MSG("  Virtualisation extensions ");
143    if(cpuid_arm_id_pfr1_virtualisation_extract((uint8_t *)&id_pfr1) ==
144       cpuid_arm_ftr_i) {
145        printf("implemented.\n");
146    }
147    else {
148        printf("not implemented.\n");
149    }
150
151    MSG("  Generic timer ");
152    if(cpuid_arm_id_pfr1_generic_timer_extract((uint8_t *)&id_pfr1) ==
153       cpuid_arm_ftr_i) {
154        printf("implemented.\n");
155    }
156    else {
157        printf("not implemented.\n");
158    }
159
160    return true;
161}
162
163extern char kernel_stack_top;
164
165/* On many platforms, we have no way to set the argument register values when
166 * starting the boot driver.  In that case, the static loader will place those
167 * values here, which we'll detect by seeing that the multiboot pointer isn't
168 * 0xdeadbeef. */
169struct boot_arguments {
170    void *pointer;
171    void *cpu_driver_entry;
172    void *cpu_driver_base;
173} boot_arguments= { (void *)0xdeadbeef, NULL, NULL };
174
175/* The boot driver needs the index of the console port, but nothing else.  The
176 * argument list is left untouched, for the CPU driver. */
177static struct cmdarg bootargs[] = {
178    { "consolePort", ArgType_UInt, { .uinteger = (void *)0 } },
179    { NULL, 0, { NULL } }
180};
181
182static void
183init_bootargs(void) {
184    bootargs[0].var.uinteger= &serial_console_port;
185}
186
187void switch_and_jump(void *cpu_driver_entry, lvaddr_t boot_pointer,
188                     lpaddr_t ttbr0, lpaddr_t ttbr1, lvaddr_t mailbox)
189    __attribute__((noreturn));
190
191__attribute__((noreturn))
192void boot_app_core(struct armv7_boot_record *bootrec) {
193    my_core_id = cp15_get_cpu_id();
194
195    MSG("APP core %"PRIu32" booting.\n", bootrec->target_mpid);
196
197    /* Get the core_data structure from the boot record. */
198    struct arm_core_data *app_core_data=
199        (struct arm_core_data *)mem_to_local_phys(bootrec->core_data);
200
201    MSG("CPU driver entry point is KV:%08"PRIx32"\n",
202            app_core_data->entry_point);
203
204    MSG("Page tables at P:%08"PRIx32" and P:%08"PRIx32".\n",
205            app_core_data->kernel_l1_low,
206            app_core_data->kernel_l1_high);
207
208    MSG("Switching page tables and jumping - see you in arch_init().\n");
209    switch_and_jump((void *)app_core_data->entry_point,
210                    bootrec->core_data,
211                    app_core_data->kernel_l1_low,
212                    app_core_data->kernel_l1_high,
213                    local_phys_to_mem((lpaddr_t)bootrec));
214}
215
216/**
217 * \brief Entry point called from boot.S for the BSP kernel.
218 *
219 * \param pointer address of \c multiboot_info on the BSP;
220 */
221__attribute__((noreturn))
222void boot_bsp_core(void *pointer, void *cpu_driver_entry,
223                   void *cpu_driver_base)
224{
225    my_core_id = cp15_get_cpu_id();
226
227    /* Place all AP cores in the WFE loop. */
228    plat_advance_aps();
229
230    /* If this pointer has been modified by the loader, it means we're got a
231     * statically-allocated multiboot info structure, as we're executing from
232     * ROM, in a simulator, or otherwise unable to use a full bootloader. */
233    if(boot_arguments.pointer != (void *)0xdeadbeef) {
234        pointer= boot_arguments.pointer;
235        cpu_driver_entry= boot_arguments.cpu_driver_entry;
236        cpu_driver_base= boot_arguments.cpu_driver_base;
237    }
238
239    /* Grab the multiboot header, so we can find our command line.  Note that
240     * we're still executing with physical addresses, to we need to convert
241     * the pointer back from the kernel-virtual address that the CPU driver
242     * will use. */
243    struct multiboot_info *mbi=
244        (struct multiboot_info *)mem_to_local_phys((lvaddr_t)pointer);
245
246    /* If there's no commandline passed, panic on port 0. */
247    if(!(mbi->flags & MULTIBOOT_INFO_FLAG_HAS_CMDLINE)) {
248        serial_early_init(0);
249        panic("No commandline arguments.\n");
250    }
251
252    /* Parse the commandline, to find which console port to connect to. */
253    init_bootargs();
254    const char *cmdline= (const char *)mbi->cmdline;
255    parse_commandline(cmdline, bootargs);
256
257    /* Initialise the serial port driver using the physical address of the
258     * port, so that we can start printing before we enable the MMU. */
259    serial_early_init(serial_console_port);
260
261    /* The spinlocks are in the BSS, and thus already zeroed, but it's polite
262     * to explicitly initialize them here... */
263    spinlock_init(&global->locks.print);
264
265    MSG("Boot driver invoked as: %s\n", cmdline);
266
267    /* These, likewise, use physical addresses directly. */
268    check_cpuid();
269    //platform_print_id();
270
271    /* Print kernel address for debugging with gdb. */
272    MSG("First byte of boot driver at 0x%"PRIxLVADDR"\n",
273            local_phys_to_mem((uint32_t)&boot_start));
274    MSG("First byte of CPU driver at %p\n", cpu_driver_base);
275
276    /* Get the memory map. */
277    if(!(mbi->flags & MULTIBOOT_INFO_FLAG_HAS_MMAP))
278        panic("No memory map.\n");
279    struct multiboot_mmap *mmap= (struct multiboot_mmap *)mbi->mmap_addr;
280    if(mbi->mmap_length == 0) panic("Memory map is empty.\n");
281
282    /* Find the first RAM region. */
283    size_t region;
284    for(region= 0;
285        region < mbi->mmap_length &&
286        mmap[region].type != MULTIBOOT_MEM_TYPE_RAM;
287        region++);
288    if(region == mbi->mmap_length) panic("No RAM regions.\n");
289
290    /* Make sure there's some RAM we can use. */
291    if(mmap[region].base_addr > (uint64_t)UINT32_MAX)
292        panic("First RAM region is >4GB - I can't address it.\n");
293    lpaddr_t ram_base= (uint32_t)mmap[region].base_addr;
294
295    /* Truncate the region if necessary. */
296    size_t ram_size;
297    if(mmap[region].base_addr + (mmap[region].length - 1) >
298       (uint64_t)UINT32_MAX) {
299        ram_size=
300            (uint32_t)((uint64_t)UINT32_MAX - mmap[region].base_addr + 1);
301        printf("Truncated first RAM region to fit in 4GB.\n");
302    }
303    else ram_size= (uint32_t)mmap[region].length;
304
305    if(ram_size > RAM_WINDOW_SIZE) {
306        panic("Reduce the first MMAP entry to <1GB, otherwise everything\n"
307              "breaks.  This is really dumb, and must be fixed.\n");
308    }
309
310    MSG("CPU driver entry point is %p\n", cpu_driver_entry);
311
312    /* Fill in the boot data structure for the CPU driver. */
313    /* We need to pass in anything we've allocated. */
314    boot_core_data.multiboot_header= local_phys_to_mem((lpaddr_t)mbi);
315    boot_core_data.global=           local_phys_to_mem((lpaddr_t)&bsp_global);
316    boot_core_data.kcb=              local_phys_to_mem((lpaddr_t)&bsp_kcb);
317    boot_core_data.target_bootrecs=  local_phys_to_mem((lpaddr_t)&boot_records);
318    /* We're starting the BSP core, so its commandline etc. is that given in
319     * the multiboot header. */
320    assert(mbi->mods_count > 0);
321    memcpy(&boot_core_data.kernel_module,
322           (void *)mbi->mods_addr,
323           sizeof(struct multiboot_modinfo));
324    boot_core_data.cmdline= local_phys_to_mem(mbi->cmdline);
325
326    /* Relocate the boot data pointer for the CPU driver. */
327    lvaddr_t boot_pointer= local_phys_to_mem((lpaddr_t)&boot_core_data);
328    MSG("Boot data structure at kernel VA %08x\n", boot_pointer);
329
330    /* Create the kernel page tables. */
331    MSG("Initialising kernel page tables.\n");
332    paging_init(ram_base, ram_size, &boot_core_data);
333
334    MSG("Switching page tables and jumping - see you in arch_init().\n");
335    switch_and_jump(cpu_driver_entry, boot_pointer, (lpaddr_t)l1_low,
336                    (lpaddr_t)l1_high, 0);
337}
338
339void
340switch_and_jump(void *cpu_driver_entry, lvaddr_t boot_pointer, lpaddr_t ttbr0,
341                lpaddr_t ttbr1, lvaddr_t bootrec) {
342    /* Switch the MMU on. */
343    enable_mmu(ttbr0, ttbr1);
344
345    /* We're now executing with the kernel window mapped.  If we're on a
346     * platform that doesn't have RAM at 0x80000000, then we're still using
347     * physical addresses through the uncached device mappings in TTBR0.
348     * Otherwise our physical addresses were mapped 1-1 by the kernel window.
349     *
350     * In either case, we can't safely use the UART, as there's no guarantee
351     * that its device registers weren't in what is now the kernel window
352     * (this is the case on the Zynq). */
353
354    /* This is important.  We need to clean and invalidate the data caches, to
355     * ensure that anything we've modified since enabling them is visible
356     * after we make the jump. */
357    invalidate_data_caches_pouu(true);
358
359    /* Long jump to the CPU driver entry point, passing the kernel-virtual
360     * address of the boot_core_data structure. */
361    __asm("mov r0, %[pointer]\n"
362          "mov r1, %[bootrec]\n"
363          "mov pc, %[jump_target]\n"
364          : /* No outputs */
365          : [jump_target] "r"(cpu_driver_entry),
366            [bootrec]     "r"(bootrec),
367            [pointer]     "r"(boot_pointer)
368          : "r0", "r1");
369
370    panic("Shut up GCC, I'm not returning.\n");
371}
372