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, Universitaetstrasse 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/armv8/arm_hal.h>
25#include <arch/armv8/init.h>
26#include <arch/armv8/exceptions.h>
27#include <arch/armv8/global.h>
28#include <arch/armv8/startup_arch.h>
29#include <efi.h>
30#include <sysreg.h>
31#include <arch/armv8/kernel_multiboot2.h>
32#include <arch/armv8/paging_kernel_arch.h>
33#include <arch/arm/platform.h>
34#include <systime.h>
35#include <coreboot.h>
36#include <dev/armv8_dev.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
48const char *kernel_command_line;
49
50#define MSG(format, ...) printk( LOG_NOTE, "ARMv8-A: "format, ## __VA_ARGS__ )
51
52/*
53 * parsing of command line arguments
54 */
55static struct cmdarg cmdargs[] = {
56    {"loglevel", ArgType_Int, { .integer = &kernel_loglevel }},
57    {"logmask", ArgType_Int, { .integer = &kernel_log_subsystem_mask }},
58    {"ticks", ArgType_Bool, { .boolean = &kernel_ticks_enabled }},
59    {"timeslice", ArgType_UInt, { .uinteger = &config_timeslice }},
60    {"serial", ArgType_ULong, { .ulonginteger = &platform_uart_base[0] }},
61    {NULL, 0, {NULL}}
62};
63
64static void mmap_find_memory(struct multiboot_tag_efi_mmap *mmap)
65{
66    lpaddr_t physical_mem = 0;
67
68    for (size_t i = 0; i < mmap->size; i += mmap->descr_size) {
69        efi_memory_descriptor *desc = (efi_memory_descriptor *)(mmap->efi_mmap + i);
70        if (desc->Type == EfiConventionalMemory && desc->NumberOfPages > ARMV8_CORE_DATA_PAGES) {
71            physical_mem = ROUND_UP(desc->PhysicalStart, BASE_PAGE_SIZE);
72            break;
73        }
74    }
75
76    if (!physical_mem) {
77        panic("No free memory found!\n");
78    }
79
80    armv8_glbl_core_data->start_kernel_ram = physical_mem;
81    armv8_glbl_core_data->start_free_ram = physical_mem;
82
83    global = (void*) local_phys_to_mem(armv8_glbl_core_data->start_free_ram);
84
85    // Construct the global structure
86    memset(&global->locks, 0, sizeof(global->locks));
87
88    armv8_glbl_core_data->start_free_ram += sizeof(*global);
89    armv8_glbl_core_data->start_free_ram = ROUND_UP(armv8_glbl_core_data->start_free_ram, BASE_PAGE_SIZE);
90
91}
92
93bool cpu_is_bsp(void)
94{
95    /* xxx: assumes the coreid to be set */
96    return (my_core_id == 0);
97}
98
99bool arch_core_is_bsp(void)
100{
101    return cpu_is_bsp();
102}
103
104/**
105 * @param Entry point to architecture specific initialization
106 *
107 * @param magic     Magic value to tell the kernel it was started by multiboot
108 * @param pointer   Pointer to the ARMv8 core data
109 *
110 * ASSUMPTIONS:
111 *   - the execution starts in HIGH addresses (e.g. > KERNEL_OFFSET)
112 *   - Pointers to stack and multiboot structures point to HIGH memory
113 *   - ARM exception level is EL1 (privileged)
114 */
115void
116arch_init(struct armv8_core_data *core_data) {
117    global = &global_temp;
118    memset(&global->locks, 0, sizeof(global->locks));
119
120    armv8_glbl_core_data = core_data;
121
122    my_core_id = armv8_glbl_core_data->dst_core_id;
123
124    /* parse the cmdline */
125    kernel_command_line = (const char *)armv8_glbl_core_data->cpu_driver_cmdline;
126    parse_commandline(kernel_command_line, cmdargs);
127
128    /* initialize the serial console */
129    serial_console_init(false);
130
131    /* store the stack pointers */
132    kernel_stack = local_phys_to_mem(core_data->cpu_driver_stack);
133    kernel_stack_top = local_phys_to_mem(core_data->cpu_driver_stack_limit);
134
135    uint8_t mpidr_aff0 = armv8_MPIDR_EL1_Aff0_rdf(NULL);
136    uint8_t mpidr_aff1 = armv8_MPIDR_EL1_Aff1_rdf(NULL);
137    uint8_t mpidr_aff2 = armv8_MPIDR_EL1_Aff2_rdf(NULL);
138    uint8_t mpidr_aff3 = armv8_MPIDR_EL1_Aff3_rdf(NULL);
139
140    switch (armv8_glbl_core_data->boot_magic) {
141        case ARMV8_BOOTMAGIC_BSP:
142            assert(my_core_id == 0);
143            printf("Barrelfish CPU driver starting on ARMv8 (BSP)\n");
144
145            struct multiboot_info *multiboot = (struct multiboot_info *)
146                local_phys_to_mem(armv8_glbl_core_data->multiboot_image.base);
147            struct multiboot_tag_efi_mmap *mmap = (struct multiboot_tag_efi_mmap *)
148                multiboot2_find_tag(multiboot->tags, multiboot->total_size - 8, MULTIBOOT_TAG_TYPE_EFI_MMAP);
149
150            mmap_find_memory(mmap);
151            break;
152        case ARMV8_BOOTMAGIC_PSCI :
153        case ARMV8_BOOTMAGIC_PARKING :
154            assert(my_core_id != 0);
155
156            global = (struct global *)core_data->cpu_driver_globals_pointer;
157
158            printf("Barrelfish CPU driver starting on ARMv8 (APP) "
159                    "mpid=%"PRIu8":%"PRIu8":%"PRIu8":%"PRIu8"\n",
160                    mpidr_aff3, mpidr_aff2, mpidr_aff1, mpidr_aff0);
161
162            break;
163        default: {
164            serial_console_putchar('x');
165            serial_console_putchar('x');
166            serial_console_putchar('\n');
167
168            panic("Implement AP booting!");
169            __asm volatile ("wfi":::);
170            break;
171        }
172    }
173
174    MSG("Global data at %p\n", global);
175
176    MSG("Kernel stack at 0x%016" PRIxPTR ".. 0x%016" PRIxPTR "\n",
177        kernel_stack_top, kernel_stack);
178    MSG("Kernel first byte at 0x%" PRIxPTR "\n", &kernel_first_byte);
179
180    MSG("Exception vectors (VBAR_EL1): %p\n", &vectors);
181    sysreg_write_vbar_el1((uint64_t)&vectors);
182
183    if (cpu_is_bsp()) {
184        platform_revision_init();
185	    MSG("%"PRIu32" cores in system\n", platform_get_core_count());
186        MSG("Initializing the interrupt controller\n");
187        platform_init_ic_bsp();
188    } else {
189        platform_init_ic_app();
190    }
191
192    MSG("Enabling timers\n");
193    platform_timer_init(config_timeslice);
194
195    MSG("Setting coreboot spawn handler\n");
196    coreboot_set_spawn_handler(CPU_ARM8, platform_boot_core);
197
198    MSG("Calling arm_kernel_startup\n");
199    arm_kernel_startup();
200    while (1) {
201        __asm volatile ("wfi":::);
202    }
203}
204