1 /*-
2 * Copyright (c) 2022 Netflix, Inc
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26 #include <sys/param.h>
27 #include <machine/pc/bios.h>
28 #include <machine/metadata.h>
29
30 #include "stand.h"
31 #include "host_syscall.h"
32 #include "efi.h"
33 #include "kboot.h"
34 #include "bootstrap.h"
35
36 /*
37 * Abbreviated x86 Linux struct boot_param for the so-called zero-page.
38 * We have to use this to get systab and memmap since neither of those
39 * are exposed in a sane way. We only define what we need and pad for
40 * everything else to minimize cross-coupling.
41 *
42 * Transcribed in FreeBSD-ese from Linux's asm/bootparam.h for x86 as of
43 * 6.15, but these details haven't changed in a long time.
44 */
45
46 struct linux_efi_info {
47 uint32_t efi_loader_signature; /* 0x00 */
48 uint32_t efi_systab; /* 0x04 */
49 uint32_t efi_memdesc_size; /* 0x08 */
50 uint32_t efi_memdesc_version; /* 0x0c */
51 uint32_t efi_memmap; /* 0x10 */
52 uint32_t efi_memmap_size; /* 0x14 */
53 uint32_t efi_systab_hi; /* 0x18 */
54 uint32_t efi_memmap_hi; /* 0x1c */
55 } __packed;
56
57 struct linux_boot_params {
58 uint8_t _pad1[0x1c0]; /* 0x000 */
59 struct linux_efi_info efi_info; /* 0x1c0 */
60 uint8_t _pad2[0x1000 - 0x1c0 - sizeof(struct linux_efi_info)]; /* 0x1e0 */
61 } __packed; /* Total size 4k, the page size on x86 */
62
63 bool
enumerate_memory_arch(void)64 enumerate_memory_arch(void)
65 {
66 struct linux_boot_params bp;
67
68 /*
69 * Sadly, there's no properly exported data for the EFI memory map nor
70 * the system table. systab is passed in from the original boot loader.
71 * memmap is obtained from boot time services (which are long gone) and
72 * then modified and passed to SetVirtualAddressMap. Even though the
73 * latter is in runtime services, it can only be called once and Linux
74 * has already called it. So unless we can dig all this out from the
75 * Linux kernel, there's no other wy to get it. A proper way would be to
76 * publish these in /sys/firmware/efi, but that's not done yet. We can
77 * only get the runtime subset and can't get systbl at all from today's
78 * (6.15) Linux kernel. Linux's pandora boot loader will copy this same
79 * information when it calls the new kernel, but since we don't use the
80 * bzImage kexec vector, we have to harvest it here.
81 */
82 if (data_from_kernel("boot_params", &bp, sizeof(bp))) {
83 uint64_t systbl, memmap;
84
85 systbl = (uint64_t)bp.efi_info.efi_systab_hi << 32 |
86 bp.efi_info.efi_systab;
87 memmap = (uint64_t)bp.efi_info.efi_memmap_hi << 32 |
88 bp.efi_info.efi_memmap;
89
90 efi_set_systbl(systbl);
91 efi_read_from_pa(memmap, bp.efi_info.efi_memmap_size,
92 bp.efi_info.efi_memdesc_size, bp.efi_info.efi_memdesc_version);
93 printf("UEFI SYSTAB PA: %#lx\n", systbl);
94 printf("UEFI MMAP: Ver %d Ent Size %d Tot Size %d PA %#lx\n",
95 bp.efi_info.efi_memdesc_version, bp.efi_info.efi_memdesc_size,
96 bp.efi_info.efi_memmap_size, memmap);
97 }
98 /*
99 * So, we can't use the EFI map for this, so we have to fall back to
100 * the proc iomem stuff to at least get started...
101 */
102 if (!populate_avail_from_iomem()) {
103 printf("Populate from avail also failed.\n");
104 return (false);
105 } else {
106 printf("Populate worked...\n");
107 }
108 print_avail();
109 return (true);
110 }
111
112 /* XXX refactor with aarch64 */
113 uint64_t
kboot_get_phys_load_segment(void)114 kboot_get_phys_load_segment(void)
115 {
116 #define HOLE_SIZE (64ul << 20)
117 #define KERN_ALIGN (2ul << 20)
118 static uint64_t s = 0;
119
120 if (s != 0)
121 return (s);
122
123 print_avail();
124 s = first_avail(KERN_ALIGN, HOLE_SIZE, SYSTEM_RAM);
125 printf("KBOOT GET PHYS Using %#llx\n", (long long)s);
126 if (s != 0)
127 return (s);
128 s = 0x40000000 | 0x4200000; /* should never get here */
129 /* XXX PANIC? XXX */
130 printf("Falling back to the crazy address %#lx which works in qemu\n", s);
131 return (s);
132 }
133
134 void
bi_loadsmap(struct preloaded_file * kfp)135 bi_loadsmap(struct preloaded_file *kfp)
136 {
137 efi_bi_loadsmap(kfp);
138 }
139