1*d6abfaa7Skettenis /* $OpenBSD: efiboot.c,v 1.50 2024/02/23 21:52:12 kettenis Exp $ */
2f24071e5Spatrick
3f24071e5Spatrick /*
4f24071e5Spatrick * Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net>
5f24071e5Spatrick * Copyright (c) 2016 Mark Kettenis
6f24071e5Spatrick *
7f24071e5Spatrick * Permission to use, copy, modify, and distribute this software for any
8f24071e5Spatrick * purpose with or without fee is hereby granted, provided that the above
9f24071e5Spatrick * copyright notice and this permission notice appear in all copies.
10f24071e5Spatrick *
11f24071e5Spatrick * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12f24071e5Spatrick * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13f24071e5Spatrick * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14f24071e5Spatrick * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15f24071e5Spatrick * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16f24071e5Spatrick * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17f24071e5Spatrick * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18f24071e5Spatrick */
19f24071e5Spatrick
20f24071e5Spatrick #include <sys/param.h>
21f24071e5Spatrick #include <sys/queue.h>
226f83097eSpatrick #include <sys/stat.h>
23f24071e5Spatrick #include <dev/cons.h>
24f24071e5Spatrick #include <sys/disklabel.h>
25f24071e5Spatrick
26f24071e5Spatrick #include <efi.h>
27f24071e5Spatrick #include <efiapi.h>
28f24071e5Spatrick #include <efiprot.h>
29f24071e5Spatrick #include <eficonsctl.h>
30f24071e5Spatrick
315b351376Spatrick #include <dev/biovar.h>
325b351376Spatrick #include <dev/softraidvar.h>
335b351376Spatrick
34f24071e5Spatrick #include <lib/libkern/libkern.h>
355b351376Spatrick #include <lib/libsa/softraid.h>
36f24071e5Spatrick #include <stand/boot/cmd.h>
37f24071e5Spatrick
385b351376Spatrick #include "libsa.h"
39f24071e5Spatrick #include "disk.h"
405b351376Spatrick #include "softraid_arm64.h"
415b351376Spatrick
425b351376Spatrick #include "efidev.h"
4333e5575aSpatrick #include "efiboot.h"
44f24071e5Spatrick #include "fdt.h"
45f24071e5Spatrick
46f24071e5Spatrick EFI_SYSTEM_TABLE *ST;
47f24071e5Spatrick EFI_BOOT_SERVICES *BS;
48f24071e5Spatrick EFI_RUNTIME_SERVICES *RS;
49f673f4ddSkettenis EFI_HANDLE IH, efi_bootdp;
504befd8f0Spatrick void *fdt_sys = NULL;
514befd8f0Spatrick void *fdt_override = NULL;
524befd8f0Spatrick size_t fdt_override_size;
534befd8f0Spatrick void *smbios = NULL;
54f24071e5Spatrick
55fa854029Spatrick EFI_PHYSICAL_ADDRESS heap;
56fa854029Spatrick UINTN heapsiz = 1 * 1024 * 1024;
57f673f4ddSkettenis EFI_MEMORY_DESCRIPTOR *mmap;
58fa854029Spatrick UINTN mmap_key;
59fa854029Spatrick UINTN mmap_ndesc;
60fa854029Spatrick UINTN mmap_descsiz;
61f4dd1aebSkettenis UINT32 mmap_version;
62f24071e5Spatrick
63f24071e5Spatrick static EFI_GUID imgp_guid = LOADED_IMAGE_PROTOCOL;
64f24071e5Spatrick static EFI_GUID blkio_guid = BLOCK_IO_PROTOCOL;
65f24071e5Spatrick static EFI_GUID devp_guid = DEVICE_PATH_PROTOCOL;
661e44dc38Skettenis static EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
67f3468426Skettenis static EFI_GUID fdt_guid = FDT_TABLE_GUID;
684befd8f0Spatrick static EFI_GUID smbios_guid = SMBIOS_TABLE_GUID;
694befd8f0Spatrick static EFI_GUID smbios3_guid = SMBIOS3_TABLE_GUID;
70f3468426Skettenis
7149dff005Sderaadt #define efi_guidcmp(_a, _b) memcmp((_a), (_b), sizeof(EFI_GUID))
72f24071e5Spatrick
7333e5575aSpatrick int efi_device_path_depth(EFI_DEVICE_PATH *dp, int);
7433e5575aSpatrick int efi_device_path_ncmp(EFI_DEVICE_PATH *, EFI_DEVICE_PATH *, int);
75fa854029Spatrick static void efi_heap_init(void);
76fa854029Spatrick static void efi_memprobe_internal(void);
77f24071e5Spatrick static void efi_timer_init(void);
78f24071e5Spatrick static void efi_timer_cleanup(void);
792c32ef33Skettenis static EFI_STATUS efi_memprobe_find(UINTN, UINTN, EFI_MEMORY_TYPE,
802c32ef33Skettenis EFI_PHYSICAL_ADDRESS *);
814befd8f0Spatrick void *efi_fdt(void);
824befd8f0Spatrick int fdt_load_override(char *);
834befd8f0Spatrick extern void smbios_init(void *);
84f24071e5Spatrick
85f24071e5Spatrick EFI_STATUS
efi_main(EFI_HANDLE image,EFI_SYSTEM_TABLE * systab)86f24071e5Spatrick efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
87f24071e5Spatrick {
88f24071e5Spatrick extern char *progname;
89f24071e5Spatrick EFI_LOADED_IMAGE *imgp;
90f24071e5Spatrick EFI_DEVICE_PATH *dp = NULL;
91f24071e5Spatrick EFI_STATUS status;
92f3468426Skettenis int i;
93f24071e5Spatrick
94f24071e5Spatrick ST = systab;
95f24071e5Spatrick BS = ST->BootServices;
96496ffee0Spatrick RS = ST->RuntimeServices;
97f24071e5Spatrick IH = image;
98f24071e5Spatrick
99f0da534cSjsg /* disable reset by watchdog after 5 minutes */
1001f462730Skrw BS->SetWatchdogTimer(0, 0, 0, NULL);
101f0da534cSjsg
1021f462730Skrw status = BS->HandleProtocol(image, &imgp_guid,
103f24071e5Spatrick (void **)&imgp);
104f24071e5Spatrick if (status == EFI_SUCCESS)
1051f462730Skrw status = BS->HandleProtocol(imgp->DeviceHandle, &devp_guid,
1061f462730Skrw (void **)&dp);
107f24071e5Spatrick if (status == EFI_SUCCESS)
108f24071e5Spatrick efi_bootdp = dp;
109f24071e5Spatrick
110f3468426Skettenis for (i = 0; i < ST->NumberOfTableEntries; i++) {
111f3468426Skettenis if (efi_guidcmp(&fdt_guid,
112f3468426Skettenis &ST->ConfigurationTable[i].VendorGuid) == 0)
1134befd8f0Spatrick fdt_sys = ST->ConfigurationTable[i].VendorTable;
1144befd8f0Spatrick if (efi_guidcmp(&smbios_guid,
1154befd8f0Spatrick &ST->ConfigurationTable[i].VendorGuid) == 0)
1164befd8f0Spatrick smbios = ST->ConfigurationTable[i].VendorTable;
1174befd8f0Spatrick if (efi_guidcmp(&smbios3_guid,
1184befd8f0Spatrick &ST->ConfigurationTable[i].VendorGuid) == 0)
1194befd8f0Spatrick smbios = ST->ConfigurationTable[i].VendorTable;
120f3468426Skettenis }
1214befd8f0Spatrick fdt_init(fdt_sys);
122f3468426Skettenis
123f24071e5Spatrick progname = "BOOTAA64";
124f24071e5Spatrick
125f24071e5Spatrick boot(0);
126f24071e5Spatrick
127f24071e5Spatrick return (EFI_SUCCESS);
128f24071e5Spatrick }
129f24071e5Spatrick
130f24071e5Spatrick static SIMPLE_TEXT_OUTPUT_INTERFACE *conout;
131f24071e5Spatrick static SIMPLE_INPUT_INTERFACE *conin;
132f24071e5Spatrick
1335cfe0970Skettenis /*
1345cfe0970Skettenis * The device majors for these don't match the ones used by the
1355cfe0970Skettenis * kernel. That's fine. They're just used as an index into the cdevs
1365cfe0970Skettenis * array and never passed on to the kernel.
1375cfe0970Skettenis */
138c7045f51Skettenis static dev_t serial = makedev(1, 0);
139c7045f51Skettenis static dev_t framebuffer = makedev(2, 0);
1405cfe0970Skettenis
1415f7ab753Skettenis static char framebuffer_path[128];
1425f7ab753Skettenis
143f24071e5Spatrick void
efi_cons_probe(struct consdev * cn)144f24071e5Spatrick efi_cons_probe(struct consdev *cn)
145f24071e5Spatrick {
146f24071e5Spatrick cn->cn_pri = CN_MIDPRI;
147c7045f51Skettenis cn->cn_dev = makedev(0, 0);
148f24071e5Spatrick }
149f24071e5Spatrick
150f24071e5Spatrick void
efi_cons_init(struct consdev * cp)151f24071e5Spatrick efi_cons_init(struct consdev *cp)
152f24071e5Spatrick {
153f24071e5Spatrick conin = ST->ConIn;
154f24071e5Spatrick conout = ST->ConOut;
155f24071e5Spatrick }
156f24071e5Spatrick
157f24071e5Spatrick int
efi_cons_getc(dev_t dev)158f24071e5Spatrick efi_cons_getc(dev_t dev)
159f24071e5Spatrick {
160f24071e5Spatrick EFI_INPUT_KEY key;
161f24071e5Spatrick EFI_STATUS status;
162f24071e5Spatrick #if 0
163f24071e5Spatrick UINTN dummy;
164f24071e5Spatrick #endif
165f24071e5Spatrick static int lastchar = 0;
166f24071e5Spatrick
167f24071e5Spatrick if (lastchar) {
168f24071e5Spatrick int r = lastchar;
169f24071e5Spatrick if ((dev & 0x80) == 0)
170f24071e5Spatrick lastchar = 0;
171f24071e5Spatrick return (r);
172f24071e5Spatrick }
173f24071e5Spatrick
174f24071e5Spatrick status = conin->ReadKeyStroke(conin, &key);
175678d37b9Syasuoka while (status == EFI_NOT_READY || key.UnicodeChar == 0) {
176f24071e5Spatrick if (dev & 0x80)
177f24071e5Spatrick return (0);
178f24071e5Spatrick /*
179f24071e5Spatrick * XXX The implementation of WaitForEvent() in U-boot
180f24071e5Spatrick * is broken and neverreturns.
181f24071e5Spatrick */
182f24071e5Spatrick #if 0
183f24071e5Spatrick BS->WaitForEvent(1, &conin->WaitForKey, &dummy);
184f24071e5Spatrick #endif
185f24071e5Spatrick status = conin->ReadKeyStroke(conin, &key);
186f24071e5Spatrick }
187f24071e5Spatrick
188f24071e5Spatrick if (dev & 0x80)
189f24071e5Spatrick lastchar = key.UnicodeChar;
190f24071e5Spatrick
191f24071e5Spatrick return (key.UnicodeChar);
192f24071e5Spatrick }
193f24071e5Spatrick
194f24071e5Spatrick void
efi_cons_putc(dev_t dev,int c)195f24071e5Spatrick efi_cons_putc(dev_t dev, int c)
196f24071e5Spatrick {
197f24071e5Spatrick CHAR16 buf[2];
198f24071e5Spatrick
199f24071e5Spatrick if (c == '\n')
200f24071e5Spatrick efi_cons_putc(dev, '\r');
201f24071e5Spatrick
202f24071e5Spatrick buf[0] = c;
203f24071e5Spatrick buf[1] = 0;
204f24071e5Spatrick
205f24071e5Spatrick conout->OutputString(conout, buf);
206f24071e5Spatrick }
207f24071e5Spatrick
2085cfe0970Skettenis void
efi_com_probe(struct consdev * cn)209c7045f51Skettenis efi_com_probe(struct consdev *cn)
210c7045f51Skettenis {
211c7045f51Skettenis cn->cn_pri = CN_LOWPRI;
212c7045f51Skettenis cn->cn_dev = serial;
213c7045f51Skettenis }
214c7045f51Skettenis
215c7045f51Skettenis void
efi_com_init(struct consdev * cn)216c7045f51Skettenis efi_com_init(struct consdev *cn)
217c7045f51Skettenis {
218c7045f51Skettenis conin = ST->ConIn;
219c7045f51Skettenis conout = ST->ConOut;
220c7045f51Skettenis }
221c7045f51Skettenis
222c7045f51Skettenis int
efi_com_getc(dev_t dev)223c7045f51Skettenis efi_com_getc(dev_t dev)
224c7045f51Skettenis {
225c7045f51Skettenis return efi_cons_getc(dev);
226c7045f51Skettenis }
227c7045f51Skettenis
228c7045f51Skettenis void
efi_com_putc(dev_t dev,int c)229c7045f51Skettenis efi_com_putc(dev_t dev, int c)
230c7045f51Skettenis {
231c7045f51Skettenis efi_cons_putc(dev, c);
232c7045f51Skettenis }
233c7045f51Skettenis
234c7045f51Skettenis void
efi_fb_probe(struct consdev * cn)2355cfe0970Skettenis efi_fb_probe(struct consdev *cn)
2365cfe0970Skettenis {
2375cfe0970Skettenis cn->cn_pri = CN_LOWPRI;
2385cfe0970Skettenis cn->cn_dev = framebuffer;
2395cfe0970Skettenis }
2405cfe0970Skettenis
2415cfe0970Skettenis void
efi_fb_init(struct consdev * cn)2425cfe0970Skettenis efi_fb_init(struct consdev *cn)
2435cfe0970Skettenis {
2445cfe0970Skettenis conin = ST->ConIn;
2455cfe0970Skettenis conout = ST->ConOut;
2465cfe0970Skettenis }
2475cfe0970Skettenis
2485cfe0970Skettenis int
efi_fb_getc(dev_t dev)2495cfe0970Skettenis efi_fb_getc(dev_t dev)
2505cfe0970Skettenis {
2515cfe0970Skettenis return efi_cons_getc(dev);
2525cfe0970Skettenis }
2535cfe0970Skettenis
2545cfe0970Skettenis void
efi_fb_putc(dev_t dev,int c)2555cfe0970Skettenis efi_fb_putc(dev_t dev, int c)
2565cfe0970Skettenis {
2575cfe0970Skettenis efi_cons_putc(dev, c);
2585cfe0970Skettenis }
2595cfe0970Skettenis
260f24071e5Spatrick static void
efi_heap_init(void)261f24071e5Spatrick efi_heap_init(void)
262f24071e5Spatrick {
263f24071e5Spatrick EFI_STATUS status;
264f24071e5Spatrick
2651f462730Skrw status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData,
266f24071e5Spatrick EFI_SIZE_TO_PAGES(heapsiz), &heap);
267f24071e5Spatrick if (status != EFI_SUCCESS)
268f24071e5Spatrick panic("BS->AllocatePages()");
269f24071e5Spatrick }
270f24071e5Spatrick
2715b351376Spatrick struct disklist_lh disklist;
2725b351376Spatrick struct diskinfo *bootdev_dip;
273f24071e5Spatrick
274f24071e5Spatrick void
efi_diskprobe(void)275f24071e5Spatrick efi_diskprobe(void)
276f24071e5Spatrick {
2775b351376Spatrick int i, bootdev = 0, depth = -1;
278f24071e5Spatrick UINTN sz;
279f24071e5Spatrick EFI_STATUS status;
280f24071e5Spatrick EFI_HANDLE *handles = NULL;
281f24071e5Spatrick EFI_BLOCK_IO *blkio;
282f24071e5Spatrick EFI_BLOCK_IO_MEDIA *media;
2835b351376Spatrick struct diskinfo *di;
284c6d7d0adSpatrick EFI_DEVICE_PATH *dp;
285f24071e5Spatrick
2865b351376Spatrick TAILQ_INIT(&disklist);
2875b351376Spatrick
288f24071e5Spatrick sz = 0;
2891f462730Skrw status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz, 0);
290f24071e5Spatrick if (status == EFI_BUFFER_TOO_SMALL) {
291f24071e5Spatrick handles = alloc(sz);
2921f462730Skrw status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz,
2931f462730Skrw handles);
294f24071e5Spatrick }
295f24071e5Spatrick if (handles == NULL || EFI_ERROR(status))
29633e5575aSpatrick return;
297f24071e5Spatrick
298c6d7d0adSpatrick if (efi_bootdp != NULL)
299c6d7d0adSpatrick depth = efi_device_path_depth(efi_bootdp, MEDIA_DEVICE_PATH);
300c6d7d0adSpatrick
301c94e7257Skettenis /*
302c94e7257Skettenis * U-Boot incorrectly represents devices with a single
303c94e7257Skettenis * MEDIA_DEVICE_PATH component. In that case include that
304c94e7257Skettenis * component into the matching, otherwise we'll blindly select
305c94e7257Skettenis * the first device.
306c94e7257Skettenis */
307c94e7257Skettenis if (depth == 0)
308c94e7257Skettenis depth = 1;
309c94e7257Skettenis
310f24071e5Spatrick for (i = 0; i < sz / sizeof(EFI_HANDLE); i++) {
3111f462730Skrw status = BS->HandleProtocol(handles[i], &blkio_guid,
312f24071e5Spatrick (void **)&blkio);
313f24071e5Spatrick if (EFI_ERROR(status))
314f24071e5Spatrick panic("BS->HandleProtocol() returns %d", status);
315f24071e5Spatrick
316f24071e5Spatrick media = blkio->Media;
317f24071e5Spatrick if (media->LogicalPartition || !media->MediaPresent)
318f24071e5Spatrick continue;
3195b351376Spatrick di = alloc(sizeof(struct diskinfo));
3205b351376Spatrick efid_init(di, blkio);
321f24071e5Spatrick
3225b351376Spatrick if (efi_bootdp == NULL || depth == -1 || bootdev != 0)
3235b351376Spatrick goto next;
3241f462730Skrw status = BS->HandleProtocol(handles[i], &devp_guid,
325f24071e5Spatrick (void **)&dp);
326f24071e5Spatrick if (EFI_ERROR(status))
3275b351376Spatrick goto next;
328c6d7d0adSpatrick if (efi_device_path_ncmp(efi_bootdp, dp, depth) == 0) {
3295b351376Spatrick TAILQ_INSERT_HEAD(&disklist, di, list);
3305b351376Spatrick bootdev_dip = di;
3315b351376Spatrick bootdev = 1;
3325b351376Spatrick continue;
333f24071e5Spatrick }
3345b351376Spatrick next:
3355b351376Spatrick TAILQ_INSERT_TAIL(&disklist, di, list);
336f24071e5Spatrick }
337f24071e5Spatrick
338f24071e5Spatrick free(handles, sz);
3395b351376Spatrick
3405b351376Spatrick /* Print available disks and probe for softraid. */
3415b351376Spatrick i = 0;
3425b351376Spatrick printf("disks:");
3435b351376Spatrick TAILQ_FOREACH(di, &disklist, list) {
3445b351376Spatrick printf(" sd%d%s", i, di == bootdev_dip ? "*" : "");
3455b351376Spatrick i++;
3465b351376Spatrick }
3475b351376Spatrick srprobe();
3485b351376Spatrick printf("\n");
349f24071e5Spatrick }
350f24071e5Spatrick
351c94e7257Skettenis /*
352c94e7257Skettenis * Determine the number of nodes up to, but not including, the first
353c94e7257Skettenis * node of the specified type.
354c94e7257Skettenis */
35533e5575aSpatrick int
efi_device_path_depth(EFI_DEVICE_PATH * dp,int dptype)356c6d7d0adSpatrick efi_device_path_depth(EFI_DEVICE_PATH *dp, int dptype)
357c6d7d0adSpatrick {
358c6d7d0adSpatrick int i;
359c6d7d0adSpatrick
360c6d7d0adSpatrick for (i = 0; !IsDevicePathEnd(dp); dp = NextDevicePathNode(dp), i++) {
361c6d7d0adSpatrick if (DevicePathType(dp) == dptype)
362c94e7257Skettenis return (i);
363c6d7d0adSpatrick }
364c6d7d0adSpatrick
365d64e7de5Skettenis return (i);
366c6d7d0adSpatrick }
367c6d7d0adSpatrick
36833e5575aSpatrick int
efi_device_path_ncmp(EFI_DEVICE_PATH * dpa,EFI_DEVICE_PATH * dpb,int deptn)369c6d7d0adSpatrick efi_device_path_ncmp(EFI_DEVICE_PATH *dpa, EFI_DEVICE_PATH *dpb, int deptn)
370c6d7d0adSpatrick {
371c6d7d0adSpatrick int i, cmp;
372c6d7d0adSpatrick
373c6d7d0adSpatrick for (i = 0; i < deptn; i++) {
374c6d7d0adSpatrick if (IsDevicePathEnd(dpa) || IsDevicePathEnd(dpb))
375c6d7d0adSpatrick return ((IsDevicePathEnd(dpa) && IsDevicePathEnd(dpb))
376c6d7d0adSpatrick ? 0 : (IsDevicePathEnd(dpa))? -1 : 1);
377c6d7d0adSpatrick cmp = DevicePathNodeLength(dpa) - DevicePathNodeLength(dpb);
378c6d7d0adSpatrick if (cmp)
379c6d7d0adSpatrick return (cmp);
380c6d7d0adSpatrick cmp = memcmp(dpa, dpb, DevicePathNodeLength(dpa));
381c6d7d0adSpatrick if (cmp)
382c6d7d0adSpatrick return (cmp);
383c6d7d0adSpatrick dpa = NextDevicePathNode(dpa);
384c6d7d0adSpatrick dpb = NextDevicePathNode(dpb);
385c6d7d0adSpatrick }
386c6d7d0adSpatrick
387c6d7d0adSpatrick return (0);
388c6d7d0adSpatrick }
389c6d7d0adSpatrick
3901e44dc38Skettenis void
efi_framebuffer(void)3911e44dc38Skettenis efi_framebuffer(void)
3921e44dc38Skettenis {
3931e44dc38Skettenis EFI_GRAPHICS_OUTPUT *gop;
3941e44dc38Skettenis EFI_STATUS status;
3951e44dc38Skettenis void *node, *child;
3961e44dc38Skettenis uint32_t acells, scells;
3971e44dc38Skettenis uint64_t base, size;
3981e44dc38Skettenis uint32_t reg[4];
3991e44dc38Skettenis uint32_t width, height, stride;
4001e44dc38Skettenis char *format;
4015cfe0970Skettenis char *prop;
4021e44dc38Skettenis
4031e44dc38Skettenis /*
4041e44dc38Skettenis * Don't create a "simple-framebuffer" node if we already have
4051e44dc38Skettenis * one. Besides "/chosen", we also check under "/" since that
4061e44dc38Skettenis * is where the Raspberry Pi firmware puts it.
4071e44dc38Skettenis */
4081e44dc38Skettenis node = fdt_find_node("/chosen");
4091e44dc38Skettenis for (child = fdt_child_node(node); child;
4101e44dc38Skettenis child = fdt_next_node(child)) {
4115cfe0970Skettenis if (!fdt_node_is_compatible(child, "simple-framebuffer"))
4125cfe0970Skettenis continue;
4135028e024Skettenis if (!fdt_node_property(child, "status", &prop) ||
4145f7ab753Skettenis strcmp(prop, "okay") == 0) {
4155f7ab753Skettenis strlcpy(framebuffer_path, "/chosen/",
4165f7ab753Skettenis sizeof(framebuffer_path));
4175f7ab753Skettenis strlcat(framebuffer_path, fdt_node_name(child),
4185f7ab753Skettenis sizeof(framebuffer_path));
4191e44dc38Skettenis return;
4201e44dc38Skettenis }
4215f7ab753Skettenis }
4221e44dc38Skettenis node = fdt_find_node("/");
4231e44dc38Skettenis for (child = fdt_child_node(node); child;
4241e44dc38Skettenis child = fdt_next_node(child)) {
4255cfe0970Skettenis if (!fdt_node_is_compatible(child, "simple-framebuffer"))
4265cfe0970Skettenis continue;
4275028e024Skettenis if (!fdt_node_property(child, "status", &prop) ||
4285f7ab753Skettenis strcmp(prop, "okay") == 0) {
4295f7ab753Skettenis strlcpy(framebuffer_path, "/",
4305f7ab753Skettenis sizeof(framebuffer_path));
4315f7ab753Skettenis strlcat(framebuffer_path, fdt_node_name(child),
4325f7ab753Skettenis sizeof(framebuffer_path));
4331e44dc38Skettenis return;
4341e44dc38Skettenis }
4355f7ab753Skettenis }
4361e44dc38Skettenis
4371f462730Skrw status = BS->LocateProtocol(&gop_guid, NULL, (void **)&gop);
4381e44dc38Skettenis if (status != EFI_SUCCESS)
4391e44dc38Skettenis return;
4401e44dc38Skettenis
4411e44dc38Skettenis /* Paranoia! */
4421e44dc38Skettenis if (gop == NULL || gop->Mode == NULL || gop->Mode->Info == NULL)
4431e44dc38Skettenis return;
4441e44dc38Skettenis
4451e44dc38Skettenis /* We only support 32-bit pixel modes for now. */
4461e44dc38Skettenis switch (gop->Mode->Info->PixelFormat) {
4471e44dc38Skettenis case PixelRedGreenBlueReserved8BitPerColor:
448b870cd26Skettenis format = "x8b8g8r8";
4491e44dc38Skettenis break;
4501e44dc38Skettenis case PixelBlueGreenRedReserved8BitPerColor:
451b870cd26Skettenis format = "x8r8g8b8";
4521e44dc38Skettenis break;
4531e44dc38Skettenis default:
4541e44dc38Skettenis return;
4551e44dc38Skettenis }
4561e44dc38Skettenis
4571e44dc38Skettenis base = gop->Mode->FrameBufferBase;
4581e44dc38Skettenis size = gop->Mode->FrameBufferSize;
4591e44dc38Skettenis width = htobe32(gop->Mode->Info->HorizontalResolution);
4601e44dc38Skettenis height = htobe32(gop->Mode->Info->VerticalResolution);
4611e44dc38Skettenis stride = htobe32(gop->Mode->Info->PixelsPerScanLine * 4);
4621e44dc38Skettenis
4631e44dc38Skettenis node = fdt_find_node("/");
4641e44dc38Skettenis if (fdt_node_property_int(node, "#address-cells", &acells) != 1)
4651e44dc38Skettenis acells = 1;
4661e44dc38Skettenis if (fdt_node_property_int(node, "#size-cells", &scells) != 1)
4671e44dc38Skettenis scells = 1;
4681e44dc38Skettenis if (acells > 2 || scells > 2)
4691e44dc38Skettenis return;
4701e44dc38Skettenis if (acells >= 1)
4711e44dc38Skettenis reg[0] = htobe32(base);
4721e44dc38Skettenis if (acells == 2) {
4731e44dc38Skettenis reg[1] = reg[0];
4741e44dc38Skettenis reg[0] = htobe32(base >> 32);
4751e44dc38Skettenis }
4761e44dc38Skettenis if (scells >= 1)
4771e44dc38Skettenis reg[acells] = htobe32(size);
4781e44dc38Skettenis if (scells == 2) {
4791e44dc38Skettenis reg[acells + 1] = reg[acells];
4801e44dc38Skettenis reg[acells] = htobe32(size >> 32);
4811e44dc38Skettenis }
4821e44dc38Skettenis
4831e44dc38Skettenis node = fdt_find_node("/chosen");
4841e44dc38Skettenis fdt_node_add_node(node, "framebuffer", &child);
4851e44dc38Skettenis fdt_node_add_property(child, "status", "okay", strlen("okay") + 1);
4861e44dc38Skettenis fdt_node_add_property(child, "format", format, strlen(format) + 1);
4871e44dc38Skettenis fdt_node_add_property(child, "stride", &stride, 4);
4881e44dc38Skettenis fdt_node_add_property(child, "height", &height, 4);
4891e44dc38Skettenis fdt_node_add_property(child, "width", &width, 4);
4901e44dc38Skettenis fdt_node_add_property(child, "reg", reg, (acells + scells) * 4);
4911e44dc38Skettenis fdt_node_add_property(child, "compatible",
4921e44dc38Skettenis "simple-framebuffer", strlen("simple-framebuffer") + 1);
4935f7ab753Skettenis
4945f7ab753Skettenis strlcpy(framebuffer_path, "/chosen/framebuffer",
4955f7ab753Skettenis sizeof(framebuffer_path));
4961e44dc38Skettenis }
4971e44dc38Skettenis
4985cfe0970Skettenis void
efi_console(void)4995cfe0970Skettenis efi_console(void)
5005cfe0970Skettenis {
5015f7ab753Skettenis void *node;
5025cfe0970Skettenis
503c7045f51Skettenis if (major(cn_tab->cn_dev) == major(serial)) {
504c7045f51Skettenis char *serial_path;
505c7045f51Skettenis char alias[16];
506c7045f51Skettenis int len;
507c7045f51Skettenis
508c7045f51Skettenis /* Construct alias and resolve it. */
509c7045f51Skettenis snprintf(alias, sizeof(alias), "serial%d",
510c7045f51Skettenis minor(cn_tab->cn_dev));
511c7045f51Skettenis node = fdt_find_node("/aliases");
512c7045f51Skettenis len = fdt_node_property(node, alias, &serial_path);
513c7045f51Skettenis if (len <= 0)
5145cfe0970Skettenis return;
5155cfe0970Skettenis
516c7045f51Skettenis /* Point stdout-path at the serial node. */
517c7045f51Skettenis node = fdt_find_node("/chosen");
518c7045f51Skettenis fdt_node_add_property(node, "stdout-path",
519c7045f51Skettenis serial_path, strlen(serial_path) + 1);
520c7045f51Skettenis } else if (major(cn_tab->cn_dev) == major(framebuffer)) {
5215f7ab753Skettenis if (strlen(framebuffer_path) == 0)
5225cfe0970Skettenis return;
5235cfe0970Skettenis
5245cfe0970Skettenis /* Point stdout-path at the framebuffer node. */
5255f7ab753Skettenis node = fdt_find_node("/chosen");
5265f7ab753Skettenis fdt_node_add_property(node, "stdout-path",
5275f7ab753Skettenis framebuffer_path, strlen(framebuffer_path) + 1);
5285cfe0970Skettenis }
529c7045f51Skettenis }
5305cfe0970Skettenis
531a88d1494Skettenis uint64_t dma_constraint[2] = { 0, -1 };
532a88d1494Skettenis
533a88d1494Skettenis void
efi_dma_constraint(void)534a88d1494Skettenis efi_dma_constraint(void)
535a88d1494Skettenis {
536a88d1494Skettenis void *node;
537cfb73cfeSpatrick char *prop;
538cfb73cfeSpatrick uint32_t *propint;
539cfb73cfeSpatrick uint64_t base, size;
540cfb73cfeSpatrick uint32_t pacells, pscells;
541cfb73cfeSpatrick uint32_t acells, scells;
542cfb73cfeSpatrick int len;
543cfb73cfeSpatrick
544cfb73cfeSpatrick node = fdt_find_node("/");
545cfb73cfeSpatrick if (fdt_node_property_int(node, "#address-cells", &pacells) != 1)
546cfb73cfeSpatrick pacells = 1;
547cfb73cfeSpatrick if (fdt_node_property_int(node, "#size-cells", &pscells) != 1)
548cfb73cfeSpatrick pscells = 1;
549cfb73cfeSpatrick if (pacells > 2 || pscells > 2)
550cfb73cfeSpatrick return;
551cfb73cfeSpatrick
552cfb73cfeSpatrick node = fdt_find_node("/soc");
553cfb73cfeSpatrick if (node != NULL) {
554cfb73cfeSpatrick if (fdt_node_property_int(node, "#address-cells", &acells) != 1)
555cfb73cfeSpatrick acells = pacells;
556cfb73cfeSpatrick if (fdt_node_property_int(node, "#size-cells", &scells) != 1)
557cfb73cfeSpatrick scells = pscells;
558cfb73cfeSpatrick if (acells > 2 || scells > 2)
559cfb73cfeSpatrick return;
560cfb73cfeSpatrick
561cfb73cfeSpatrick len = fdt_node_property(node, "dma-ranges", &prop);
562cfb73cfeSpatrick propint = (uint32_t *)prop;
563cfb73cfeSpatrick if (len == (acells + pacells + scells) * sizeof(uint32_t)) {
564cfb73cfeSpatrick base = betoh32(propint[acells]);
565cfb73cfeSpatrick if (pacells == 2)
566cfb73cfeSpatrick base = (base << 32) |
567cfb73cfeSpatrick betoh32(propint[acells + 1]);
568cfb73cfeSpatrick size = betoh32(propint[acells + pacells]);
569cfb73cfeSpatrick if (scells == 2)
570cfb73cfeSpatrick size = (size << 32) |
571cfb73cfeSpatrick betoh32(propint[acells + pacells + 1]);
572cfb73cfeSpatrick
573cfb73cfeSpatrick dma_constraint[0] = htobe64(base);
574cfb73cfeSpatrick dma_constraint[1] = htobe64(base + size - 1);
575cfb73cfeSpatrick }
576cfb73cfeSpatrick }
577a88d1494Skettenis
5782bc3fe80Skettenis /*
5792bc3fe80Skettenis * Some SoC's have DMA constraints that aren't explicitly
5802bc3fe80Skettenis * advertised.
5812bc3fe80Skettenis */
582a88d1494Skettenis node = fdt_find_node("/");
583a88d1494Skettenis if (fdt_node_is_compatible(node, "brcm,bcm2711"))
584a88d1494Skettenis dma_constraint[1] = htobe64(0x3bffffff);
5852bc3fe80Skettenis if (fdt_node_is_compatible(node, "rockchip,rk3566") ||
5862bc3fe80Skettenis fdt_node_is_compatible(node, "rockchip,rk3568") ||
5872bc3fe80Skettenis fdt_node_is_compatible(node, "rockchip,rk3588") ||
5882bc3fe80Skettenis fdt_node_is_compatible(node, "rockchip,rk3588s"))
5892bc3fe80Skettenis dma_constraint[1] = htobe64(0xffffffff);
5902ae6c737Skettenis if (fdt_node_is_compatible(node, "lenovo,thinkpad-x13s"))
5912ae6c737Skettenis dma_constraint[1] = htobe64(0xffffffff);
592a88d1494Skettenis
593a88d1494Skettenis /* Pass DMA constraint. */
594a88d1494Skettenis node = fdt_find_node("/chosen");
595a88d1494Skettenis fdt_node_add_property(node, "openbsd,dma-constraint",
596a88d1494Skettenis dma_constraint, sizeof(dma_constraint));
597a88d1494Skettenis }
598a88d1494Skettenis
599be07ee62Skettenis int acpi = 0;
6009ccb13abSnaddy char *bootmac = NULL;
601f24071e5Spatrick
602f24071e5Spatrick void *
efi_makebootargs(char * bootargs,int howto)6039419d8aaSkettenis efi_makebootargs(char *bootargs, int howto)
604f24071e5Spatrick {
6055b351376Spatrick struct sr_boot_volume *bv;
606f4dd1aebSkettenis u_char bootduid[8];
607f4dd1aebSkettenis u_char zero[8] = { 0 };
608f4dd1aebSkettenis uint64_t uefi_system_table = htobe64((uintptr_t)ST);
6099419d8aaSkettenis uint32_t boothowto = htobe32(howto);
61058554311Spatrick EFI_PHYSICAL_ADDRESS addr;
6114befd8f0Spatrick void *node, *fdt;
612f24071e5Spatrick size_t len;
613f24071e5Spatrick
6144befd8f0Spatrick fdt = efi_fdt();
615be07ee62Skettenis if (fdt == NULL || acpi)
6169a1480b1Skettenis fdt = efi_acpi();
6179a1480b1Skettenis
61858554311Spatrick if (!fdt_get_size(fdt))
61958554311Spatrick return NULL;
62058554311Spatrick
62158554311Spatrick len = roundup(fdt_get_size(fdt) + PAGE_SIZE, PAGE_SIZE);
62258554311Spatrick if (BS->AllocatePages(AllocateAnyPages, EfiLoaderData,
62358554311Spatrick EFI_SIZE_TO_PAGES(len), &addr) == EFI_SUCCESS) {
62458554311Spatrick memcpy((void *)addr, fdt, fdt_get_size(fdt));
625259d2111Skettenis ((struct fdt_head *)addr)->fh_size = htobe32(len);
62658554311Spatrick fdt = (void *)addr;
62758554311Spatrick }
62858554311Spatrick
629f24071e5Spatrick if (!fdt_init(fdt))
630f24071e5Spatrick return NULL;
631f24071e5Spatrick
632bd928107Spatrick /* Create common nodes which might not exist when using mach dtb */
633bd928107Spatrick node = fdt_find_node("/aliases");
634bd928107Spatrick if (node == NULL)
635bd928107Spatrick fdt_node_add_node(fdt_find_node("/"), "aliases", &node);
636f24071e5Spatrick node = fdt_find_node("/chosen");
637bd928107Spatrick if (node == NULL)
638bd928107Spatrick fdt_node_add_node(fdt_find_node("/"), "chosen", &node);
639f24071e5Spatrick
640bd928107Spatrick node = fdt_find_node("/chosen");
641f24071e5Spatrick len = strlen(bootargs) + 1;
642f24071e5Spatrick fdt_node_add_property(node, "bootargs", bootargs, len);
6439419d8aaSkettenis fdt_node_add_property(node, "openbsd,boothowto",
6449419d8aaSkettenis &boothowto, sizeof(boothowto));
645f24071e5Spatrick
646f24071e5Spatrick /* Pass DUID of the boot disk. */
6475b351376Spatrick if (bootdev_dip) {
6485b351376Spatrick memcpy(&bootduid, bootdev_dip->disklabel.d_uid,
649f24071e5Spatrick sizeof(bootduid));
6505b351376Spatrick if (memcmp(bootduid, zero, sizeof(bootduid)) != 0) {
6515b351376Spatrick fdt_node_add_property(node, "openbsd,bootduid",
6525b351376Spatrick bootduid, sizeof(bootduid));
653f24071e5Spatrick }
654f24071e5Spatrick
6555b351376Spatrick if (bootdev_dip->sr_vol != NULL) {
6565b351376Spatrick bv = bootdev_dip->sr_vol;
6575b351376Spatrick fdt_node_add_property(node, "openbsd,sr-bootuuid",
6585b351376Spatrick &bv->sbv_uuid, sizeof(bv->sbv_uuid));
6595b351376Spatrick if (bv->sbv_maskkey != NULL)
6605b351376Spatrick fdt_node_add_property(node,
6615b351376Spatrick "openbsd,sr-bootkey", bv->sbv_maskkey,
6625b351376Spatrick SR_CRYPTO_MAXKEYBYTES);
6635b351376Spatrick }
6645b351376Spatrick }
6655b351376Spatrick
6665b351376Spatrick sr_clear_keys();
6675b351376Spatrick
6689ccb13abSnaddy /* Pass netboot interface address. */
6699ccb13abSnaddy if (bootmac)
6709ccb13abSnaddy fdt_node_add_property(node, "openbsd,bootmac", bootmac, 6);
6719ccb13abSnaddy
672f4dd1aebSkettenis /* Pass EFI system table. */
673f4dd1aebSkettenis fdt_node_add_property(node, "openbsd,uefi-system-table",
674f4dd1aebSkettenis &uefi_system_table, sizeof(uefi_system_table));
675f4dd1aebSkettenis
676f4dd1aebSkettenis /* Placeholders for EFI memory map. */
677f4dd1aebSkettenis fdt_node_add_property(node, "openbsd,uefi-mmap-start", zero, 8);
678f4dd1aebSkettenis fdt_node_add_property(node, "openbsd,uefi-mmap-size", zero, 4);
679f4dd1aebSkettenis fdt_node_add_property(node, "openbsd,uefi-mmap-desc-size", zero, 4);
680f4dd1aebSkettenis fdt_node_add_property(node, "openbsd,uefi-mmap-desc-ver", zero, 4);
681f4dd1aebSkettenis
6821e44dc38Skettenis efi_framebuffer();
6835cfe0970Skettenis efi_console();
684a88d1494Skettenis efi_dma_constraint();
6851e44dc38Skettenis
686f24071e5Spatrick fdt_finalize();
687f24071e5Spatrick
688f24071e5Spatrick return fdt;
689f24071e5Spatrick }
690f24071e5Spatrick
691f4dd1aebSkettenis void
efi_updatefdt(void)692f4dd1aebSkettenis efi_updatefdt(void)
693f4dd1aebSkettenis {
694f4dd1aebSkettenis uint64_t uefi_mmap_start = htobe64((uintptr_t)mmap);
695f4dd1aebSkettenis uint32_t uefi_mmap_size = htobe32(mmap_ndesc * mmap_descsiz);
696f4dd1aebSkettenis uint32_t uefi_mmap_desc_size = htobe32(mmap_descsiz);
697f4dd1aebSkettenis uint32_t uefi_mmap_desc_ver = htobe32(mmap_version);
698f4dd1aebSkettenis void *node;
699f4dd1aebSkettenis
700f4dd1aebSkettenis node = fdt_find_node("/chosen");
701f4dd1aebSkettenis if (!node)
702f4dd1aebSkettenis return;
703f4dd1aebSkettenis
704f4dd1aebSkettenis /* Pass EFI memory map. */
705f4dd1aebSkettenis fdt_node_set_property(node, "openbsd,uefi-mmap-start",
706f4dd1aebSkettenis &uefi_mmap_start, sizeof(uefi_mmap_start));
707f4dd1aebSkettenis fdt_node_set_property(node, "openbsd,uefi-mmap-size",
708f4dd1aebSkettenis &uefi_mmap_size, sizeof(uefi_mmap_size));
709f4dd1aebSkettenis fdt_node_set_property(node, "openbsd,uefi-mmap-desc-size",
710f4dd1aebSkettenis &uefi_mmap_desc_size, sizeof(uefi_mmap_desc_size));
711f4dd1aebSkettenis fdt_node_set_property(node, "openbsd,uefi-mmap-desc-ver",
712f4dd1aebSkettenis &uefi_mmap_desc_ver, sizeof(uefi_mmap_desc_ver));
713f4dd1aebSkettenis
714f4dd1aebSkettenis fdt_finalize();
715f4dd1aebSkettenis }
716f4dd1aebSkettenis
717f24071e5Spatrick u_long efi_loadaddr;
718f24071e5Spatrick
719f24071e5Spatrick void
machdep(void)720f24071e5Spatrick machdep(void)
721f24071e5Spatrick {
722f24071e5Spatrick EFI_PHYSICAL_ADDRESS addr;
723f24071e5Spatrick
724f24071e5Spatrick cninit();
725f24071e5Spatrick efi_heap_init();
7264befd8f0Spatrick smbios_init(smbios);
727f24071e5Spatrick
728f24071e5Spatrick /*
7299a118d7eSpatrick * The kernel expects to be loaded into a block of memory aligned
7309a118d7eSpatrick * on a 2MB boundary. We allocate a block of 64MB of memory, which
7319a118d7eSpatrick * gives us plenty of room for growth.
732f24071e5Spatrick */
7339a118d7eSpatrick if (efi_memprobe_find(EFI_SIZE_TO_PAGES(64 * 1024 * 1024),
7342c32ef33Skettenis 0x200000, EfiLoaderCode, &addr) != EFI_SUCCESS)
735f24071e5Spatrick printf("Can't allocate memory\n");
736f24071e5Spatrick efi_loadaddr = addr;
737f24071e5Spatrick
738f24071e5Spatrick efi_timer_init();
739f24071e5Spatrick efi_diskprobe();
74033e5575aSpatrick efi_pxeprobe();
741f24071e5Spatrick }
742f24071e5Spatrick
743f24071e5Spatrick void
efi_cleanup(void)744f24071e5Spatrick efi_cleanup(void)
745f24071e5Spatrick {
746fa854029Spatrick int retry;
747fa854029Spatrick EFI_STATUS status;
748fa854029Spatrick
749f24071e5Spatrick efi_timer_cleanup();
750f24071e5Spatrick
751fa854029Spatrick /* retry once in case of failure */
752fa854029Spatrick for (retry = 1; retry >= 0; retry--) {
753fa854029Spatrick efi_memprobe_internal(); /* sync the current map */
754f4dd1aebSkettenis efi_updatefdt();
7551f462730Skrw status = BS->ExitBootServices(IH, mmap_key);
756fa854029Spatrick if (status == EFI_SUCCESS)
757fa854029Spatrick break;
758fa854029Spatrick if (retry == 0)
759fa854029Spatrick panic("ExitBootServices failed (%d)", status);
760fa854029Spatrick }
761f24071e5Spatrick }
762f24071e5Spatrick
763f24071e5Spatrick void
_rtt(void)764f24071e5Spatrick _rtt(void)
765f24071e5Spatrick {
766f24071e5Spatrick #ifdef EFI_DEBUG
767f24071e5Spatrick printf("Hit any key to reboot\n");
768f24071e5Spatrick efi_cons_getc(0);
769f24071e5Spatrick #endif
770f24071e5Spatrick RS->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
771111d6387Skettenis for (;;)
772111d6387Skettenis continue;
773f24071e5Spatrick }
774f24071e5Spatrick
775f24071e5Spatrick /*
776f24071e5Spatrick * U-Boot only implements the GetTime() Runtime Service if it has been
777f24071e5Spatrick * configured with CONFIG_DM_RTC. Most board configurations don't
778f24071e5Spatrick * include that option, so we can't use it to implement our boot
779f24071e5Spatrick * prompt timeout. Instead we use timer events to simulate a clock
780f24071e5Spatrick * that ticks ever second.
781f24071e5Spatrick */
782f24071e5Spatrick
783f24071e5Spatrick EFI_EVENT timer;
784f24071e5Spatrick int ticks;
785f24071e5Spatrick
786f24071e5Spatrick static VOID
efi_timer(EFI_EVENT event,VOID * context)787f24071e5Spatrick efi_timer(EFI_EVENT event, VOID *context)
788f24071e5Spatrick {
789f24071e5Spatrick ticks++;
790f24071e5Spatrick }
791f24071e5Spatrick
792f24071e5Spatrick static void
efi_timer_init(void)793f24071e5Spatrick efi_timer_init(void)
794f24071e5Spatrick {
795f24071e5Spatrick EFI_STATUS status;
796f24071e5Spatrick
797a4d88df4Sjsg status = BS->CreateEvent(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
798f24071e5Spatrick efi_timer, NULL, &timer);
799f24071e5Spatrick if (status == EFI_SUCCESS)
800f24071e5Spatrick status = BS->SetTimer(timer, TimerPeriodic, 10000000);
801f24071e5Spatrick if (EFI_ERROR(status))
802f24071e5Spatrick printf("Can't create timer\n");
803f24071e5Spatrick }
804f24071e5Spatrick
805f24071e5Spatrick static void
efi_timer_cleanup(void)806f24071e5Spatrick efi_timer_cleanup(void)
807f24071e5Spatrick {
808f24071e5Spatrick BS->CloseEvent(timer);
809f24071e5Spatrick }
810f24071e5Spatrick
811f24071e5Spatrick time_t
getsecs(void)812f24071e5Spatrick getsecs(void)
813f24071e5Spatrick {
814f24071e5Spatrick return ticks;
815f24071e5Spatrick }
816f24071e5Spatrick
817f24071e5Spatrick /*
818f24071e5Spatrick * Various device-related bits.
819f24071e5Spatrick */
820f24071e5Spatrick
821f24071e5Spatrick void
devboot(dev_t dev,char * p)822f24071e5Spatrick devboot(dev_t dev, char *p)
823f24071e5Spatrick {
8245b351376Spatrick struct sr_boot_volume *bv;
8255b351376Spatrick struct sr_boot_chunk *bc;
8265b351376Spatrick struct diskinfo *dip;
8275b351376Spatrick int sd_boot_vol = 0;
8285b351376Spatrick int sr_boot_vol = -1;
8295b351376Spatrick int part_type = FS_UNUSED;
8305b351376Spatrick
8315b351376Spatrick if (bootdev_dip == NULL) {
83233e5575aSpatrick strlcpy(p, "tftp0a", 7);
8335b351376Spatrick return;
8345b351376Spatrick }
8355b351376Spatrick
8367db964dcSkettenis /*
8377db964dcSkettenis * If there is no BSD disklabel on the boot device, boot from
8387db964dcSkettenis * the ESP instead.
8397db964dcSkettenis */
8407db964dcSkettenis if ((bootdev_dip->flags & DISKINFO_FLAG_GOODLABEL) == 0) {
8417db964dcSkettenis strlcpy(p, "esp0a", 6);
8427db964dcSkettenis return;
8437db964dcSkettenis }
8447db964dcSkettenis
8455b351376Spatrick TAILQ_FOREACH(dip, &disklist, list) {
8465b351376Spatrick if (bootdev_dip == dip)
8475b351376Spatrick break;
8485b351376Spatrick sd_boot_vol++;
8495b351376Spatrick }
8505b351376Spatrick
8515b351376Spatrick /*
8525b351376Spatrick * Determine the partition type for the 'a' partition of the
8535b351376Spatrick * boot device.
8545b351376Spatrick */
8555b351376Spatrick part_type = bootdev_dip->disklabel.d_partitions[0].p_fstype;
8565b351376Spatrick
8575b351376Spatrick /*
8585b351376Spatrick * See if we booted from a disk that is a member of a bootable
8595b351376Spatrick * softraid volume.
8605b351376Spatrick */
8615b351376Spatrick SLIST_FOREACH(bv, &sr_volumes, sbv_link) {
8625b351376Spatrick SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link)
8635b351376Spatrick if (bc->sbc_diskinfo == bootdev_dip)
8645b351376Spatrick sr_boot_vol = bv->sbv_unit;
8655b351376Spatrick if (sr_boot_vol != -1)
8665b351376Spatrick break;
8675b351376Spatrick }
8685b351376Spatrick
8695b351376Spatrick if (sr_boot_vol != -1 && part_type != FS_BSDFFS) {
8705b351376Spatrick strlcpy(p, "sr0a", 5);
8715b351376Spatrick p[2] = '0' + sr_boot_vol;
8725b351376Spatrick return;
8735b351376Spatrick }
8745b351376Spatrick
8755b351376Spatrick strlcpy(p, "sd0a", 5);
8765b351376Spatrick p[2] = '0' + sd_boot_vol;
877f24071e5Spatrick }
878f24071e5Spatrick
879c7045f51Skettenis const char cdevs[][4] = { "cons", "com", "fb" };
8805cfe0970Skettenis const int ncdevs = nitems(cdevs);
8815cfe0970Skettenis
882f24071e5Spatrick int
cnspeed(dev_t dev,int sp)883f24071e5Spatrick cnspeed(dev_t dev, int sp)
884f24071e5Spatrick {
885f24071e5Spatrick return 115200;
886f24071e5Spatrick }
887f24071e5Spatrick
8885cfe0970Skettenis char ttyname_buf[8];
8895cfe0970Skettenis
890f24071e5Spatrick char *
ttyname(int fd)891f24071e5Spatrick ttyname(int fd)
892f24071e5Spatrick {
8935cfe0970Skettenis snprintf(ttyname_buf, sizeof ttyname_buf, "%s%d",
8945cfe0970Skettenis cdevs[major(cn_tab->cn_dev)], minor(cn_tab->cn_dev));
8955cfe0970Skettenis
8965cfe0970Skettenis return ttyname_buf;
897f24071e5Spatrick }
898f24071e5Spatrick
899f24071e5Spatrick dev_t
ttydev(char * name)900f24071e5Spatrick ttydev(char *name)
901f24071e5Spatrick {
9025cfe0970Skettenis int i, unit = -1;
9035cfe0970Skettenis char *no = name + strlen(name) - 1;
9045cfe0970Skettenis
9055cfe0970Skettenis while (no >= name && *no >= '0' && *no <= '9')
9065cfe0970Skettenis unit = (unit < 0 ? 0 : (unit * 10)) + *no-- - '0';
9075cfe0970Skettenis if (no < name || unit < 0)
9085cfe0970Skettenis return NODEV;
9095cfe0970Skettenis for (i = 0; i < ncdevs; i++)
9105cfe0970Skettenis if (strncmp(name, cdevs[i], no - name + 1) == 0)
9115cfe0970Skettenis return makedev(i, unit);
912f24071e5Spatrick return NODEV;
913f24071e5Spatrick }
914f24071e5Spatrick
915f24071e5Spatrick #define MAXDEVNAME 16
916f24071e5Spatrick
917f24071e5Spatrick /*
918f24071e5Spatrick * Parse a device spec.
919f24071e5Spatrick *
920f24071e5Spatrick * [A-Za-z]*[0-9]*[A-Za-z]:file
921f24071e5Spatrick * dev uint part
922f24071e5Spatrick */
923f24071e5Spatrick int
devparse(const char * fname,int * dev,int * unit,int * part,const char ** file)924f24071e5Spatrick devparse(const char *fname, int *dev, int *unit, int *part, const char **file)
925f24071e5Spatrick {
926f24071e5Spatrick const char *s;
927f24071e5Spatrick
928f24071e5Spatrick *unit = 0; /* default to wd0a */
929f24071e5Spatrick *part = 0;
930f24071e5Spatrick *dev = 0;
931f24071e5Spatrick
932f24071e5Spatrick s = strchr(fname, ':');
933f24071e5Spatrick if (s != NULL) {
934f24071e5Spatrick int devlen;
935f24071e5Spatrick int i, u, p = 0;
936f24071e5Spatrick struct devsw *dp;
937f24071e5Spatrick char devname[MAXDEVNAME];
938f24071e5Spatrick
939f24071e5Spatrick devlen = s - fname;
940f24071e5Spatrick if (devlen > MAXDEVNAME)
941f24071e5Spatrick return (EINVAL);
942f24071e5Spatrick
943f24071e5Spatrick /* extract device name */
944f24071e5Spatrick for (i = 0; isalpha(fname[i]) && (i < devlen); i++)
945f24071e5Spatrick devname[i] = fname[i];
946f24071e5Spatrick devname[i] = 0;
947f24071e5Spatrick
948f24071e5Spatrick if (!isdigit(fname[i]))
949f24071e5Spatrick return (EUNIT);
950f24071e5Spatrick
951f24071e5Spatrick /* device number */
952f24071e5Spatrick for (u = 0; isdigit(fname[i]) && (i < devlen); i++)
953f24071e5Spatrick u = u * 10 + (fname[i] - '0');
954f24071e5Spatrick
955f24071e5Spatrick if (!isalpha(fname[i]))
956f24071e5Spatrick return (EPART);
957f24071e5Spatrick
958f24071e5Spatrick /* partition number */
959f24071e5Spatrick if (i < devlen)
960f24071e5Spatrick p = fname[i++] - 'a';
961f24071e5Spatrick
962f24071e5Spatrick if (i != devlen)
963f24071e5Spatrick return (ENXIO);
964f24071e5Spatrick
965f24071e5Spatrick /* check device name */
966f24071e5Spatrick for (dp = devsw, i = 0; i < ndevs; dp++, i++) {
967f24071e5Spatrick if (dp->dv_name && !strcmp(devname, dp->dv_name))
968f24071e5Spatrick break;
969f24071e5Spatrick }
970f24071e5Spatrick
971f24071e5Spatrick if (i >= ndevs)
972f24071e5Spatrick return (ENXIO);
973f24071e5Spatrick
974f24071e5Spatrick *unit = u;
975f24071e5Spatrick *part = p;
976f24071e5Spatrick *dev = i;
977f24071e5Spatrick fname = ++s;
978f24071e5Spatrick }
979f24071e5Spatrick
980f24071e5Spatrick *file = fname;
981f24071e5Spatrick
982f24071e5Spatrick return (0);
983f24071e5Spatrick }
984f24071e5Spatrick
985f24071e5Spatrick int
devopen(struct open_file * f,const char * fname,char ** file)986f24071e5Spatrick devopen(struct open_file *f, const char *fname, char **file)
987f24071e5Spatrick {
988f24071e5Spatrick struct devsw *dp;
989f24071e5Spatrick int dev, unit, part, error;
990f24071e5Spatrick
991f24071e5Spatrick error = devparse(fname, &dev, &unit, &part, (const char **)file);
992f24071e5Spatrick if (error)
993f24071e5Spatrick return (error);
994f24071e5Spatrick
99533e5575aSpatrick dp = &devsw[dev];
996f24071e5Spatrick f->f_dev = dp;
997f24071e5Spatrick
998ad424d98Snaddy if (strcmp("tftp", dp->dv_name) != 0) {
999ad424d98Snaddy /*
1000ad424d98Snaddy * Clear bootmac, to signal that we loaded this file from a
1001ad424d98Snaddy * non-network device.
1002ad424d98Snaddy */
1003ad424d98Snaddy bootmac = NULL;
1004ad424d98Snaddy }
1005ad424d98Snaddy
1006f24071e5Spatrick return (*dp->dv_open)(f, unit, part);
1007f24071e5Spatrick }
1008f24071e5Spatrick
1009fa854029Spatrick static void
efi_memprobe_internal(void)1010fa854029Spatrick efi_memprobe_internal(void)
1011fa854029Spatrick {
1012fa854029Spatrick EFI_STATUS status;
1013fa854029Spatrick UINTN mapkey, mmsiz, siz;
1014fa854029Spatrick UINT32 mmver;
1015fa854029Spatrick EFI_MEMORY_DESCRIPTOR *mm;
1016fa854029Spatrick int n;
1017fa854029Spatrick
1018fa854029Spatrick free(mmap, mmap_ndesc * mmap_descsiz);
1019fa854029Spatrick
1020fa854029Spatrick siz = 0;
10211f462730Skrw status = BS->GetMemoryMap(&siz, NULL, &mapkey, &mmsiz, &mmver);
1022fa854029Spatrick if (status != EFI_BUFFER_TOO_SMALL)
1023fa854029Spatrick panic("cannot get the size of memory map");
1024fa854029Spatrick mm = alloc(siz);
10251f462730Skrw status = BS->GetMemoryMap(&siz, mm, &mapkey, &mmsiz, &mmver);
1026fa854029Spatrick if (status != EFI_SUCCESS)
1027fa854029Spatrick panic("cannot get the memory map");
1028fa854029Spatrick n = siz / mmsiz;
1029fa854029Spatrick mmap = mm;
1030fa854029Spatrick mmap_key = mapkey;
1031fa854029Spatrick mmap_ndesc = n;
1032fa854029Spatrick mmap_descsiz = mmsiz;
1033f4dd1aebSkettenis mmap_version = mmver;
1034fa854029Spatrick }
1035fa854029Spatrick
1036f24071e5Spatrick /*
1037f24071e5Spatrick * 64-bit ARMs can have a much wider memory mapping, as in somewhere
1038f24071e5Spatrick * after the 32-bit region. To cope with our alignment requirement,
1039f24071e5Spatrick * use the memory table to find a place where we can fit.
1040f24071e5Spatrick */
1041f24071e5Spatrick static EFI_STATUS
efi_memprobe_find(UINTN pages,UINTN align,EFI_MEMORY_TYPE type,EFI_PHYSICAL_ADDRESS * addr)10422c32ef33Skettenis efi_memprobe_find(UINTN pages, UINTN align, EFI_MEMORY_TYPE type,
10432c32ef33Skettenis EFI_PHYSICAL_ADDRESS *addr)
1044f24071e5Spatrick {
1045fa854029Spatrick EFI_MEMORY_DESCRIPTOR *mm;
1046fa854029Spatrick int i, j;
1047f24071e5Spatrick
1048f24071e5Spatrick if (align < EFI_PAGE_SIZE)
1049f24071e5Spatrick return EFI_INVALID_PARAMETER;
1050f24071e5Spatrick
1051fa854029Spatrick efi_memprobe_internal(); /* sync the current map */
1052f24071e5Spatrick
1053fa854029Spatrick for (i = 0, mm = mmap; i < mmap_ndesc;
1054fa854029Spatrick i++, mm = NextMemoryDescriptor(mm, mmap_descsiz)) {
1055f24071e5Spatrick if (mm->Type != EfiConventionalMemory)
1056f24071e5Spatrick continue;
1057f24071e5Spatrick
1058f24071e5Spatrick if (mm->NumberOfPages < pages)
1059f24071e5Spatrick continue;
1060f24071e5Spatrick
1061f2c0e408Skettenis for (j = 0; j < mm->NumberOfPages; j++) {
1062f24071e5Spatrick EFI_PHYSICAL_ADDRESS paddr;
1063f24071e5Spatrick
1064f24071e5Spatrick if (mm->NumberOfPages - j < pages)
1065f24071e5Spatrick break;
1066f24071e5Spatrick
1067f24071e5Spatrick paddr = mm->PhysicalStart + (j * EFI_PAGE_SIZE);
106873dc1409Spatrick if (paddr & (align - 1))
106973dc1409Spatrick continue;
107073dc1409Spatrick
10712c32ef33Skettenis if (BS->AllocatePages(AllocateAddress, type,
10721f462730Skrw pages, &paddr) == EFI_SUCCESS) {
1073f24071e5Spatrick *addr = paddr;
1074f24071e5Spatrick return EFI_SUCCESS;
1075f24071e5Spatrick }
1076f24071e5Spatrick }
1077f24071e5Spatrick }
1078f24071e5Spatrick return EFI_OUT_OF_RESOURCES;
1079f24071e5Spatrick }
1080111d6387Skettenis
1081f3468426Skettenis int
mdrandom(char * buf,size_t buflen)1082f3468426Skettenis mdrandom(char *buf, size_t buflen)
1083f3468426Skettenis {
1084f3468426Skettenis char *random;
1085f3468426Skettenis void *node;
1086f3468426Skettenis int i, len, ret = -1;
1087f3468426Skettenis
1088f3468426Skettenis node = fdt_find_node("/chosen");
1089f3468426Skettenis if (!node)
1090f3468426Skettenis return -1;
1091f3468426Skettenis
1092f3468426Skettenis len = fdt_node_property(node, "rng-seed", &random);
1093f3468426Skettenis if (len > 0) {
1094f3468426Skettenis for (i = 0; i < buflen; i++)
1095f3468426Skettenis buf[i] ^= random[i % len];
1096f3468426Skettenis ret = 0;
1097f3468426Skettenis }
1098f3468426Skettenis
1099f3468426Skettenis len = fdt_node_property(node, "kaslr-seed", &random);
1100f3468426Skettenis if (len > 0) {
1101f3468426Skettenis for (i = 0; i < buflen; i++)
1102f3468426Skettenis buf[i] ^= random[i % len];
1103f3468426Skettenis ret = 0;
1104f3468426Skettenis }
1105f3468426Skettenis
1106f3468426Skettenis return ret;
1107f3468426Skettenis }
1108f3468426Skettenis
11094befd8f0Spatrick #define FW_PATH "/etc/firmware/dtb/"
11104befd8f0Spatrick
11114befd8f0Spatrick void *
efi_fdt(void)11124befd8f0Spatrick efi_fdt(void)
11134befd8f0Spatrick {
11144befd8f0Spatrick extern char *hw_vendor, *hw_prod;
11154befd8f0Spatrick
11164befd8f0Spatrick /* 'mach dtb' has precedence */
11174befd8f0Spatrick if (fdt_override != NULL)
11184befd8f0Spatrick return fdt_override;
11194befd8f0Spatrick
11204befd8f0Spatrick /* Return system provided one */
11214befd8f0Spatrick if (hw_vendor == NULL || hw_prod == NULL)
11224befd8f0Spatrick return fdt_sys;
11234befd8f0Spatrick
1124*d6abfaa7Skettenis if (strcmp(hw_vendor, "LENOVO") == 0) {
1125*d6abfaa7Skettenis if (strncmp(hw_prod, "21BX", 4) == 0 ||
1126*d6abfaa7Skettenis strncmp(hw_prod, "21BY", 4) == 0) {
11274befd8f0Spatrick fdt_load_override(FW_PATH
11284befd8f0Spatrick "qcom/sc8280xp-lenovo-thinkpad-x13s.dtb");
1129a36d06b9Spatrick /* TODO: find a better mechanism */
1130a36d06b9Spatrick cnset(ttydev("fb0"));
1131a36d06b9Spatrick }
1132*d6abfaa7Skettenis }
11334befd8f0Spatrick
11344befd8f0Spatrick return fdt_override ? fdt_override : fdt_sys;
11354befd8f0Spatrick }
11364befd8f0Spatrick
11374befd8f0Spatrick int
fdt_load_override(char * file)11384befd8f0Spatrick fdt_load_override(char *file)
11394befd8f0Spatrick {
11404befd8f0Spatrick EFI_PHYSICAL_ADDRESS addr;
11414befd8f0Spatrick char path[MAXPATHLEN];
11424befd8f0Spatrick struct stat sb;
11434befd8f0Spatrick int fd;
11444befd8f0Spatrick
11454befd8f0Spatrick if (file == NULL && fdt_override) {
11464befd8f0Spatrick BS->FreePages((uint64_t)fdt_override,
11474befd8f0Spatrick EFI_SIZE_TO_PAGES(fdt_override_size));
11484befd8f0Spatrick fdt_override = NULL;
11494befd8f0Spatrick fdt_init(fdt_sys);
11504befd8f0Spatrick return 0;
11514befd8f0Spatrick }
11524befd8f0Spatrick
11534befd8f0Spatrick snprintf(path, sizeof(path), "%s:%s", cmd.bootdev, file);
11544befd8f0Spatrick
11554befd8f0Spatrick fd = open(path, O_RDONLY);
11564befd8f0Spatrick if (fd < 0 || fstat(fd, &sb) == -1) {
11574befd8f0Spatrick printf("cannot open %s\n", path);
11584befd8f0Spatrick return 0;
11594befd8f0Spatrick }
11604befd8f0Spatrick if (efi_memprobe_find(EFI_SIZE_TO_PAGES(sb.st_size),
11614befd8f0Spatrick PAGE_SIZE, EfiLoaderData, &addr) != EFI_SUCCESS) {
11624befd8f0Spatrick printf("cannot allocate memory for %s\n", path);
11634befd8f0Spatrick return 0;
11644befd8f0Spatrick }
11654befd8f0Spatrick if (read(fd, (void *)addr, sb.st_size) != sb.st_size) {
11664befd8f0Spatrick printf("cannot read from %s\n", path);
11674befd8f0Spatrick return 0;
11684befd8f0Spatrick }
11694befd8f0Spatrick
11704befd8f0Spatrick if (!fdt_init((void *)addr)) {
11714befd8f0Spatrick printf("invalid device tree\n");
11724befd8f0Spatrick BS->FreePages(addr, EFI_SIZE_TO_PAGES(sb.st_size));
11734befd8f0Spatrick return 0;
11744befd8f0Spatrick }
11754befd8f0Spatrick
11764befd8f0Spatrick if (fdt_override) {
11774befd8f0Spatrick BS->FreePages((uint64_t)fdt_override,
11784befd8f0Spatrick EFI_SIZE_TO_PAGES(fdt_override_size));
11794befd8f0Spatrick fdt_override = NULL;
11804befd8f0Spatrick }
11814befd8f0Spatrick
11824befd8f0Spatrick fdt_override = (void *)addr;
11834befd8f0Spatrick fdt_override_size = sb.st_size;
11844befd8f0Spatrick return 0;
11854befd8f0Spatrick }
11864befd8f0Spatrick
1187111d6387Skettenis /*
1188111d6387Skettenis * Commands
1189111d6387Skettenis */
1190111d6387Skettenis
1191be07ee62Skettenis int Xacpi_efi(void);
11926f83097eSpatrick int Xdtb_efi(void);
1193111d6387Skettenis int Xexit_efi(void);
1194111d6387Skettenis int Xpoweroff_efi(void);
1195111d6387Skettenis
1196111d6387Skettenis const struct cmd_table cmd_machine[] = {
1197be07ee62Skettenis { "acpi", CMDT_CMD, Xacpi_efi },
11986f83097eSpatrick { "dtb", CMDT_CMD, Xdtb_efi },
1199111d6387Skettenis { "exit", CMDT_CMD, Xexit_efi },
1200111d6387Skettenis { "poweroff", CMDT_CMD, Xpoweroff_efi },
1201111d6387Skettenis { NULL, 0 }
1202111d6387Skettenis };
1203111d6387Skettenis
1204111d6387Skettenis int
Xacpi_efi(void)1205be07ee62Skettenis Xacpi_efi(void)
1206be07ee62Skettenis {
1207be07ee62Skettenis acpi = 1;
1208be07ee62Skettenis return (0);
1209be07ee62Skettenis }
1210be07ee62Skettenis
1211be07ee62Skettenis int
Xdtb_efi(void)12126f83097eSpatrick Xdtb_efi(void)
12136f83097eSpatrick {
12144befd8f0Spatrick if (cmd.argc == 1) {
12154befd8f0Spatrick fdt_load_override(NULL);
12164befd8f0Spatrick return (0);
12174befd8f0Spatrick }
12186f83097eSpatrick
1219fcf3d43cSkn if (cmd.argc != 2) {
1220fcf3d43cSkn printf("dtb file\n");
1221fcf3d43cSkn return (0);
1222fcf3d43cSkn }
12236f83097eSpatrick
12244befd8f0Spatrick return fdt_load_override(cmd.argv[1]);
12256f83097eSpatrick }
12266f83097eSpatrick
12276f83097eSpatrick int
Xexit_efi(void)1228111d6387Skettenis Xexit_efi(void)
1229111d6387Skettenis {
12301f462730Skrw BS->Exit(IH, 0, 0, NULL);
1231111d6387Skettenis for (;;)
1232111d6387Skettenis continue;
1233111d6387Skettenis return (0);
1234111d6387Skettenis }
1235111d6387Skettenis
1236111d6387Skettenis int
Xpoweroff_efi(void)1237111d6387Skettenis Xpoweroff_efi(void)
1238111d6387Skettenis {
12391f462730Skrw RS->ResetSystem(EfiResetShutdown, EFI_SUCCESS, 0, NULL);
1240111d6387Skettenis return (0);
1241111d6387Skettenis }
1242