xref: /freebsd/stand/kboot/kboot/arch/amd64/load_addr.c (revision d7e6ab7a9709c8fc986dedd4783d311d4fbb676e)
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