1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #pragma once
6 
7 #include <stdalign.h>
8 #include <stdbool.h>
9 #include <stdint.h>
10 #include <stdnoreturn.h>
11 #include <zircon/boot/image.h>
12 #include <zircon/boot/multiboot.h>
13 #include <zircon/compiler.h>
14 
15 // x86-64 code for: `memcpy(rdi, rsi, rcx * 8); (*rax)(rsi=rbx);`
16 #define TRAMPOLINE_CODE {                                               \
17     0xf3, 0x48, 0xa5,                        /* rep movsq */            \
18     0x48, 0x89, 0xde,                        /* mov %rbx, %rsi */       \
19     0xff, 0xe0,                              /* jmp *%rax */            \
20 }
21 
22 // Initializers for GDT entries as uint64_t.
23 #define GDT_ENTRIES {                                                   \
24     0, /* Null entry for selector 0. */                                 \
25     /* 64-bit code segment with base zero, the only one we need. */     \
26     0xffffull |               /* limit 15:00 */                         \
27     (0b10011010ull << 40) |   /* P(1) DPL(00) S(1) 1 C(0) R(1) A(0) */  \
28     (0b10101111ull << 48),    /* G(1) D(0) L(1) AVL(0) limit 19:16 */   \
29 }
30 
31 // This is stored in some "safe" memory that won't be overwritten by
32 // the kernel immediately.  It contains everything needed to copy the
33 // kernel into place and run it in 64-bit mode.  Copying it into place
34 // will overwrite the code in this file, so nothing here can run after
35 // jumping to the trampoline code.
36 struct trampoline {
37     uint8_t code[sizeof((const uint8_t[])TRAMPOLINE_CODE)];
38     alignas(8) uint64_t gdt[
39         sizeof((const uint64_t[])GDT_ENTRIES) / sizeof(uint64_t)];
40     struct {
41         void* eip;
42         uint16_t cs;
43         uint16_t pad;
44     } ljmp;
45 };
46 
47 // This is defined by the linker script.
48 extern uint8_t PHYS_LOAD_ADDRESS[];
49 
50 noreturn void boot_zbi(const zbi_header_t* zbi,
51                        const zbi_header_t* kernel_item,
52                        struct trampoline* trampoline);
53 
54 // This is the entry point called from multiboot-start.S.  It's in the
55 // environment required by the Multiboot spec, but given a small stack
56 // and the C (regparm) calling convention.
57 noreturn void multiboot_main(uint32_t magic, multiboot_info_t* info);
58 
59 void enable_64bit_paging(uintptr_t start, uintptr_t end);
60 
panic(const char * msg,...)61 __PRINTFLIKE(1, 2) static inline noreturn void panic(const char* msg, ...) {
62     while (true) {
63         __builtin_trap();
64     }
65 }
66