1/*
2 * Copyright (c) 2016, ETH Zurich.
3 * Copyright (c) 2016, Hewlett Packard Enterprise Development LP.
4 *
5 * This file is distributed under the terms in the attached LICENSE file.
6 * If you do not find this file, copies can be found by writing to:
7 * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
8 */
9
10#include <kernel.h>
11#include <serial.h>
12#include <offsets.h>
13#include <stdio.h>
14#include <stddef.h>
15#include <errno.h>
16
17#include <multiboot2.h>
18
19// parsing commandline arguments
20#include <getopt/getopt.h>
21
22#include <barrelfish_kpi/arm_core_data.h>
23
24#include <arch/arm/gic.h>
25#include <arch/armv8/arm_hal.h>
26#include <arch/armv8/init.h>
27#include <arch/armv8/exceptions.h>
28#include <arch/armv8/global.h>
29#include <arch/armv8/startup_arch.h>
30#include <efi.h>
31#include <sysreg.h>
32#include <arch/armv8/kernel_multiboot2.h>
33#include <arch/armv8/paging_kernel_arch.h>
34#include <arch/armv8/platform.h>
35#include <systime.h>
36#include <coreboot.h>
37
38static struct global global_temp;
39
40/*
41 * Need to be initialized during kernel loading.
42 */
43struct armv8_core_data *armv8_glbl_core_data = NULL;
44
45lpaddr_t kernel_stack = 0;
46lpaddr_t kernel_stack_top = 0;
47
48#define MSG(format, ...) printk( LOG_NOTE, "ARMv8-A: "format, ## __VA_ARGS__ )
49
50/*
51 * parsing of command line arguments
52 */
53static struct cmdarg cmdargs[] = {
54    {"loglevel", ArgType_Int, { .integer = &kernel_loglevel }},
55    {"logmask", ArgType_Int, { .integer = &kernel_log_subsystem_mask }},
56    {"ticks", ArgType_Bool, { .boolean = &kernel_ticks_enabled }},
57    {"timeslice", ArgType_UInt, { .uinteger = &config_timeslice }},
58    {"serial", ArgType_ULong, { .ulonginteger = &uart_base[0] }},
59    {"gic", ArgType_ULong, { .ulonginteger = &platform_gic_cpu_base }},
60    {"gicdist", ArgType_ULong, { .ulonginteger = &platform_gic_dist_base }},
61    {"gicredist", ArgType_ULong, { .ulonginteger = &platform_gic_redist_base }},
62    {NULL, 0, {NULL}}
63};
64
65static void mmap_find_memory(struct multiboot_tag_efi_mmap *mmap)
66{
67    lpaddr_t physical_mem = 0;
68    uint64_t pages = ARMV8_CORE_DATA_PAGES;
69
70    for (size_t i = 0; i < mmap->size; i += mmap->descr_size) {
71        efi_memory_descriptor *desc = (efi_memory_descriptor *)(mmap->efi_mmap + i);
72        if (desc->Type == EfiConventionalMemory && desc->NumberOfPages > pages) {
73            physical_mem = ROUND_UP(desc->PhysicalStart, BASE_PAGE_SIZE);
74            pages = desc->NumberOfPages;
75        }
76    }
77
78    if (!physical_mem) {
79        panic("No free memory found!\n");
80    }
81
82    armv8_glbl_core_data = (void*) local_phys_to_mem(physical_mem);
83    armv8_glbl_core_data->start_kernel_ram = physical_mem;
84    armv8_glbl_core_data->start_free_ram = physical_mem + sizeof(*armv8_glbl_core_data);
85
86    global = (void*) local_phys_to_mem(armv8_glbl_core_data->start_free_ram);
87
88    // Construct the global structure
89    memset(&global->locks, 0, sizeof(global->locks));
90
91    armv8_glbl_core_data->start_free_ram += sizeof(*global);
92    armv8_glbl_core_data->start_free_ram = ROUND_UP(armv8_glbl_core_data->start_free_ram, BASE_PAGE_SIZE);
93
94}
95
96bool cpu_is_bsp(void)
97{
98    /* xxx: assumes the coreid to be set */
99    return (my_core_id == 0);
100}
101
102bool arch_core_is_bsp(void)
103{
104    return cpu_is_bsp();
105}
106
107/**
108 * @param Entry point to architecture specific initialization
109 *
110 * @param magic     Magic value to tell the kernel it was started by multiboot
111 * @param pointer   Pointer to the multiboot structure
112 * @param stack     Pointer to the stack
113 *
114 * ASSUMPTIONS:
115 *   - the execution starts in HIGH addresses (e.g. > KERNEL_OFFSET)
116 *   - Pointers to stack and multiboot structures point to HIGH memory
117 *   - ARM exception level is EL1 (privileged)
118 */
119void
120arch_init(uint32_t magic, void *pointer, uintptr_t stack) {
121    global = &global_temp;
122    memset(&global->locks, 0, sizeof(global->locks));
123
124    switch (magic) {
125    case MULTIBOOT2_BOOTLOADER_MAGIC:
126        {
127        my_core_id = 0;
128
129        struct multiboot_header *mbhdr = pointer;
130        uint32_t size = mbhdr->header_length;
131
132        // sanity checks
133        assert(mbhdr->architecture == MULTIBOOT_ARCHITECTURE_AARCH64);
134        assert((mbhdr->architecture + mbhdr->checksum + mbhdr->header_length
135                 + mbhdr->magic) == 0);
136
137        struct multiboot_header_tag *mb;
138        struct multiboot_tag_string *kernel_cmd;
139
140        // get the first header tag
141        mb = (struct multiboot_header_tag *)(mbhdr + 1);
142
143        // get the kernel cmdline. this may contain address which UART/GIC to use
144        kernel_cmd = multiboot2_find_cmdline(mb, size);
145        if (kernel_cmd == NULL) {
146            panic("Multiboot did not contain an kernel CMD line\n");
147        }
148
149        // parse the cmdline
150        parse_commandline(kernel_cmd->string, cmdargs);
151
152        // initialize the serial console.
153        serial_init(serial_console_port, false);
154//        serial_console_init(false);
155
156        struct multiboot_tag_efi_mmap *mmap = (struct multiboot_tag_efi_mmap *)
157                multiboot2_find_header(mb, size, MULTIBOOT_TAG_TYPE_EFI_MMAP);
158        if (!mmap) {
159            panic("Multiboot image does not have EFI mmap!");
160        } else {
161            printf("Found EFI mmap: %p\n", mmap);
162        }
163
164        mmap_find_memory(mmap);
165
166        armv8_glbl_core_data->multiboot_image.base  = mem_to_local_phys((lvaddr_t) mb);
167        armv8_glbl_core_data->multiboot_image.length = size;
168        armv8_glbl_core_data->efi_mmap = mem_to_local_phys((lvaddr_t) mmap);
169
170        armv8_glbl_core_data->cpu_driver_stack = stack;
171
172        kernel_stack = stack;
173        kernel_stack_top = stack + 16 - KERNEL_STACK_SIZE;
174        break;
175    }
176    case ARMV8_BOOTMAGIC_PSCI :
177        //serial_init(serial_console_port, false);
178
179        serial_init(serial_console_port, false);
180
181        struct armv8_core_data *core_data = (struct armv8_core_data*)pointer;
182        armv8_glbl_core_data = core_data;
183        global = (struct global *)core_data->cpu_driver_globals_pointer;
184
185        kernel_stack = stack;
186        kernel_stack_top = local_phys_to_mem(core_data->cpu_driver_stack_limit);
187
188        my_core_id = core_data->dst_core_id;
189
190        MSG("ARMv8 Core magic...\n");
191
192        break;
193    default: {
194        serial_init(serial_console_port, false);
195
196        serial_console_putchar('x');
197        serial_console_putchar('x');
198        serial_console_putchar('\n');
199
200        panic("Implement AP booting!");
201        __asm volatile ("wfi":::);
202        break;
203    }
204    }
205
206
207    MSG("Barrelfish CPU driver starting on ARMv8\n");
208    MSG("Global data at %p\n", global);
209    MSG("Multiboot record at %p\n", pointer);
210    MSG("Kernel stack at 0x%016" PRIxPTR ".. 0x%016" PRIxPTR "\n",
211        kernel_stack_top, kernel_stack);
212    MSG("Kernel first byte at 0x%" PRIxPTR "\n", &kernel_first_byte);
213
214    MSG("Exception vectors (VBAR_EL1): %p\n", &vectors);
215    sysreg_write_vbar_el1((uint64_t)&vectors);
216
217    MSG("Setting coreboot spawn handler\n");
218    coreboot_set_spawn_handler(CPU_ARM8, platform_boot_core);
219
220    arm_kernel_startup(pointer);
221    while (1) {
222        __asm volatile ("wfi":::);
223    }
224}
225