1/*
2 * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
7#include <autoconf.h>
8#include <elfloader/gen_config.h>
9
10#include <drivers.h>
11#include <drivers/uart.h>
12#include <printf.h>
13#include <types.h>
14#include <abort.h>
15#include <strops.h>
16#include <cpuid.h>
17
18#include <binaries/efi/efi.h>
19#include <elfloader.h>
20
21/* 0xd00dfeed in big endian */
22#define DTB_MAGIC (0xedfe0dd0)
23
24/* Maximum alignment we need to preserve when relocating (64K) */
25#define MAX_ALIGN_BITS (14)
26
27ALIGN(BIT(PAGE_BITS)) VISIBLE
28char core_stack_alloc[CONFIG_MAX_NUM_NODES][BIT(PAGE_BITS)];
29
30struct image_info kernel_info;
31struct image_info user_info;
32void *dtb;
33uint32_t dtb_size;
34
35extern void finish_relocation(int offset, void *_dynamic, unsigned int total_offset);
36void continue_boot(int was_relocated);
37
38/*
39 * Make sure the ELF loader is below the kernel's first virtual address
40 * so that when we enable the MMU we can keep executing.
41 */
42extern char _DYNAMIC[];
43void relocate_below_kernel(void)
44{
45    /*
46     * These are the ELF loader's physical addresses,
47     * since we are either running with MMU off or
48     * identity-mapped.
49     */
50    uintptr_t UNUSED start = (uintptr_t)_text;
51    uintptr_t end = (uintptr_t)_end;
52
53    if (end <= kernel_info.virt_region_start) {
54        /*
55         * If the ELF loader is already below the kernel,
56         * skip relocation.
57         */
58        continue_boot(0);
59        return;
60    }
61
62#ifdef CONFIG_IMAGE_EFI
63    /*
64     * Note: we make the (potentially incorrect) assumption
65     * that there is enough physical RAM below the kernel's first vaddr
66     * to fit the ELF loader.
67     * FIXME: do we need to make sure we don't accidentally wipe out the DTB too?
68     */
69    uintptr_t size = end - start;
70
71    /*
72     * we ROUND_UP size in this calculation so that all aligned things
73     * (interrupt vectors, stack, etc.) end up in similarly aligned locations.
74     * The strictes alignment requirement we have is the 64K-aligned AArch32
75     * page tables, so we use that to calculate the new base of the elfloader.
76     */
77    uintptr_t new_base = kernel_info.virt_region_start - (ROUND_UP(size, MAX_ALIGN_BITS));
78    uint32_t offset = start - new_base;
79    printf("relocating from %p-%p to %p-%p... size=0x%x (padded size = 0x%x)\n", start, end, new_base, new_base + size,
80           size, ROUND_UP(size, MAX_ALIGN_BITS));
81
82    memmove((void *)new_base, (void *)start, size);
83
84    /* call into assembly to do the finishing touches */
85    finish_relocation(offset, _DYNAMIC, new_base);
86#else
87    printf("The ELF loader does not support relocating itself. You probably need to move the kernel window higher, or the load address lower.\n");
88    abort();
89#endif
90}
91
92/*
93 * Entry point.
94 *
95 * Unpack images, setup the MMU, jump to the kernel.
96 */
97void main(UNUSED void *arg)
98{
99    int num_apps;
100
101    void *bootloader_dtb = NULL;
102
103    initialise_devices();
104
105#ifdef CONFIG_IMAGE_UIMAGE
106    if (arg) {
107        uint32_t magic = *(uint32_t *)arg;
108        /*
109         * This might happen on ancient bootloaders which
110         * still think Linux wants atags instead of a
111         * device tree.
112         */
113        if (magic != DTB_MAGIC) {
114            printf("Bootloader did not supply a valid device tree!\n");
115            arg = NULL;
116        }
117    }
118    bootloader_dtb = arg;
119#else
120    bootloader_dtb = NULL;
121#endif
122
123#ifdef CONFIG_IMAGE_EFI
124    if (efi_exit_boot_services() != EFI_SUCCESS) {
125        printf("Unable to exit UEFI boot services!\n");
126        abort();
127    }
128
129    bootloader_dtb = efi_get_fdt();
130#endif
131
132    /* Print welcome message. */
133    platform_init();
134    printf("\nELF-loader started on ");
135    print_cpuid();
136
137    printf("  paddr=[%p..%p]\n", _text, _end - 1);
138
139    /*
140     * U-Boot will either pass us a DTB, or (if we're being booted via bootelf)
141     * pass '0' in argc.
142     */
143    if (bootloader_dtb) {
144        printf("  dtb=%p\n", dtb);
145    } else {
146        printf("No DTB passed in from boot loader.\n");
147    }
148
149    /* Unpack ELF images into memory. */
150    load_images(&kernel_info, &user_info, 1, &num_apps, bootloader_dtb, &dtb, &dtb_size);
151    if (num_apps != 1) {
152        printf("No user images loaded!\n");
153        abort();
154    }
155
156    /*
157     * We don't really know where we've been loaded.
158     * It's possible that EFI loaded us in a place
159     * that will become part of the 'kernel window'
160     * once we switch to the boot page tables.
161     * Make sure this is not the case.
162     */
163    relocate_below_kernel();
164    printf("Relocation failed, aborting.\n");
165    abort();
166}
167
168void continue_boot(int was_relocated)
169{
170    if (was_relocated) {
171        printf("ELF loader relocated, continuing boot...\n");
172    }
173
174    /*
175     * If we were relocated, we need to re-initialise the
176     * driver model so all its pointers are set up properly.
177     */
178    if (was_relocated) {
179        initialise_devices();
180    }
181
182#if (defined(CONFIG_ARCH_ARM_V7A) || defined(CONFIG_ARCH_ARM_V8A)) && !defined(CONFIG_ARM_HYPERVISOR_SUPPORT)
183    if (is_hyp_mode()) {
184        extern void leave_hyp(void);
185        leave_hyp();
186    }
187#endif
188    /* Setup MMU. */
189    if (is_hyp_mode()) {
190#ifdef CONFIG_ARCH_AARCH64
191        extern void disable_caches_hyp();
192        disable_caches_hyp();
193#endif
194        init_hyp_boot_vspace(&kernel_info);
195    } else {
196        /* If we are not in HYP mode, we enable the SV MMU and paging
197         * just in case the kernel does not support hyp mode. */
198        init_boot_vspace(&kernel_info);
199    }
200
201#if CONFIG_MAX_NUM_NODES > 1
202    smp_boot();
203#endif /* CONFIG_MAX_NUM_NODES */
204
205    if (is_hyp_mode()) {
206        printf("Enabling hypervisor MMU and paging\n");
207        arm_enable_hyp_mmu();
208    } else {
209        printf("Enabling MMU and paging\n");
210        arm_enable_mmu();
211    }
212
213    /* Enter kernel. */
214    if ((uintptr_t)uart_get_mmio() < kernel_info.virt_region_start) {
215        printf("Jumping to kernel-image entry point...\n\n");
216    } else {
217        /* Our serial port is no longer accessible */
218    }
219
220    ((init_arm_kernel_t)kernel_info.virt_entry)(user_info.phys_region_start,
221                                                user_info.phys_region_end, user_info.phys_virt_offset,
222                                                user_info.virt_entry, (paddr_t)dtb, dtb_size);
223
224    /* We should never get here. */
225    printf("Kernel returned back to the elf-loader.\n");
226    abort();
227}
228