xref: /freebsd/stand/kboot/kboot/arch/aarch64/load_addr.c (revision 92ad79ec33fb5caf9a79c0bd8b33697b34c8e26d)
1 /*-
2  * Copyright (c) 2022 Netflix, Inc
3  *
4  * SPDX-License-Identifier: BSD-2-Clause
5  */
6 
7 #include <sys/param.h>
8 #include <machine/metadata.h>
9 #include <sys/linker.h>
10 #include <fdt_platform.h>
11 #include <libfdt.h>
12 
13 #include "kboot.h"
14 #include "efi.h"
15 
16 static bool
do_memory_from_fdt(int fd)17 do_memory_from_fdt(int fd)
18 {
19 	struct stat sb;
20 	char *buf = NULL;
21 	int len, offset;
22 	uint32_t sz, ver, esz;
23 	uint64_t mmap_pa;
24 	const uint32_t *u32p;
25 	const uint64_t *u64p;
26 
27 	if (fstat(fd, &sb) < 0)
28 		return false;
29 	buf = malloc(sb.st_size);
30 	if (buf == NULL)
31 		return false;
32 	len = read(fd, buf, sb.st_size);
33 	/* NB: we're reading this from sysfs, so mismatch OK */
34 	if (len <= 0)
35 		goto errout;
36 
37 	/*
38 	 * Look for /chosen to find these values:
39 	 * linux,uefi-system-table	PA of the UEFI System Table.
40 	 * linux,uefi-mmap-start	PA of the UEFI memory map
41 	 * linux,uefi-mmap-size		Size of mmap
42 	 * linux,uefi-mmap-desc-size	Size of each entry of mmap
43 	 * linux,uefi-mmap-desc-ver	Format version, should be 1
44 	 */
45 	offset = fdt_path_offset(buf, "/chosen");
46 	if (offset <= 0)
47 		goto errout;
48 	u64p = fdt_getprop(buf, offset, "linux,uefi-system-table", &len);
49 	if (u64p == NULL)
50 		goto errout;
51 	efi_set_systbl(fdt64_to_cpu(*u64p));
52 	u32p = fdt_getprop(buf, offset, "linux,uefi-mmap-desc-ver", &len);
53 	if (u32p == NULL)
54 		goto errout;
55 	ver = fdt32_to_cpu(*u32p);
56 	u32p = fdt_getprop(buf, offset, "linux,uefi-mmap-desc-size", &len);
57 	if (u32p == NULL)
58 		goto errout;
59 	esz = fdt32_to_cpu(*u32p);
60 	u32p = fdt_getprop(buf, offset, "linux,uefi-mmap-size", &len);
61 	if (u32p == NULL)
62 		goto errout;
63 	sz = fdt32_to_cpu(*u32p);
64 	u64p = fdt_getprop(buf, offset, "linux,uefi-mmap-start", &len);
65 	if (u64p == NULL)
66 		goto errout;
67 	mmap_pa = fdt64_to_cpu(*u64p);
68 	free(buf);
69 
70 	printf("UEFI MMAP: Ver %d Ent Size %d Tot Size %d PA %#lx\n",
71 	    ver, esz, sz, mmap_pa);
72 
73 	efi_read_from_pa(mmap_pa, sz, esz, ver);
74 	return true;
75 
76 errout:
77 	free(buf);
78 	return false;
79 }
80 
81 bool
enumerate_memory_arch(void)82 enumerate_memory_arch(void)
83 {
84 	int fd = -1;
85 	bool rv = false;
86 
87 	/*
88 	 * FDT publishes the parameters for the memory table in a series of
89 	 * nodes in the DTB.  One of them is the physical address for the memory
90 	 * table. Try to open the fdt nblob to find this information if we can
91 	 * and try to grab things from memory. If we return rv == TRUE then
92 	 * we found it. The global efi_map_phys_src is set != 0 when we know
93 	 * the PA but can't read it.
94 	 */
95 	fd = open("host:/sys/firmware/fdt", O_RDONLY);
96 	if (fd != -1) {
97 		rv = do_memory_from_fdt(fd);
98 		close(fd);
99 	}
100 
101 	/*
102 	 * One would think that one could use the raw EFI map to find memory
103 	 * that's free to boot the kernel with. However, Linux reserves some
104 	 * areas that it needs to properly. I'm not sure if the printf should be
105 	 * a panic, but for now, so I can debug (maybe at the loader prompt),
106 	 * I'm printing and carrying on.
107 	 */
108 	if (!rv) {
109 		printf("Could not obtain UEFI memory tables, expect failure\n");
110 	}
111 
112 	populate_avail_from_iomem();
113 	print_avail();
114 
115 	return true;
116 }
117 
118 uint64_t
kboot_get_phys_load_segment(void)119 kboot_get_phys_load_segment(void)
120 {
121 #define HOLE_SIZE	(64ul << 20)
122 #define KERN_ALIGN	(2ul << 20)
123 	static uint64_t	s = 0;
124 
125 	if (s != 0)
126 		return (s);
127 
128 	print_avail();
129 	s = first_avail(KERN_ALIGN, HOLE_SIZE, SYSTEM_RAM);
130 	printf("KBOOT GET PHYS Using %#llx\n", (long long)s);
131 	if (s != 0)
132 		return (s);
133 	s = 0x40000000 | 0x4200000;	/* should never get here */
134 	/* XXX PANIC? XXX */
135 	printf("Falling back to the crazy address %#lx which works in qemu\n", s);
136 	return (s);
137 }
138 
139 void
bi_loadsmap(struct preloaded_file * kfp)140 bi_loadsmap(struct preloaded_file *kfp)
141 {
142 	efi_bi_loadsmap(kfp);
143 }
144