1*2ae6c737Skettenis /* $OpenBSD: efiboot.c,v 1.49 2024/02/04 18:44:23 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 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 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 151f24071e5Spatrick efi_cons_init(struct consdev *cp) 152f24071e5Spatrick { 153f24071e5Spatrick conin = ST->ConIn; 154f24071e5Spatrick conout = ST->ConOut; 155f24071e5Spatrick } 156f24071e5Spatrick 157f24071e5Spatrick int 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 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 209c7045f51Skettenis efi_com_probe(struct consdev *cn) 210c7045f51Skettenis { 211c7045f51Skettenis cn->cn_pri = CN_LOWPRI; 212c7045f51Skettenis cn->cn_dev = serial; 213c7045f51Skettenis } 214c7045f51Skettenis 215c7045f51Skettenis void 216c7045f51Skettenis efi_com_init(struct consdev *cn) 217c7045f51Skettenis { 218c7045f51Skettenis conin = ST->ConIn; 219c7045f51Skettenis conout = ST->ConOut; 220c7045f51Skettenis } 221c7045f51Skettenis 222c7045f51Skettenis int 223c7045f51Skettenis efi_com_getc(dev_t dev) 224c7045f51Skettenis { 225c7045f51Skettenis return efi_cons_getc(dev); 226c7045f51Skettenis } 227c7045f51Skettenis 228c7045f51Skettenis void 229c7045f51Skettenis efi_com_putc(dev_t dev, int c) 230c7045f51Skettenis { 231c7045f51Skettenis efi_cons_putc(dev, c); 232c7045f51Skettenis } 233c7045f51Skettenis 234c7045f51Skettenis void 2355cfe0970Skettenis efi_fb_probe(struct consdev *cn) 2365cfe0970Skettenis { 2375cfe0970Skettenis cn->cn_pri = CN_LOWPRI; 2385cfe0970Skettenis cn->cn_dev = framebuffer; 2395cfe0970Skettenis } 2405cfe0970Skettenis 2415cfe0970Skettenis void 2425cfe0970Skettenis efi_fb_init(struct consdev *cn) 2435cfe0970Skettenis { 2445cfe0970Skettenis conin = ST->ConIn; 2455cfe0970Skettenis conout = ST->ConOut; 2465cfe0970Skettenis } 2475cfe0970Skettenis 2485cfe0970Skettenis int 2495cfe0970Skettenis efi_fb_getc(dev_t dev) 2505cfe0970Skettenis { 2515cfe0970Skettenis return efi_cons_getc(dev); 2525cfe0970Skettenis } 2535cfe0970Skettenis 2545cfe0970Skettenis void 2555cfe0970Skettenis efi_fb_putc(dev_t dev, int c) 2565cfe0970Skettenis { 2575cfe0970Skettenis efi_cons_putc(dev, c); 2585cfe0970Skettenis } 2595cfe0970Skettenis 260f24071e5Spatrick static 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 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 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 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 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 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 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); 590*2ae6c737Skettenis if (fdt_node_is_compatible(node, "lenovo,thinkpad-x13s")) 591*2ae6c737Skettenis 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 * 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 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 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 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 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 787f24071e5Spatrick efi_timer(EFI_EVENT event, VOID *context) 788f24071e5Spatrick { 789f24071e5Spatrick ticks++; 790f24071e5Spatrick } 791f24071e5Spatrick 792f24071e5Spatrick static 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 806f24071e5Spatrick efi_timer_cleanup(void) 807f24071e5Spatrick { 808f24071e5Spatrick BS->CloseEvent(timer); 809f24071e5Spatrick } 810f24071e5Spatrick 811f24071e5Spatrick time_t 812f24071e5Spatrick getsecs(void) 813f24071e5Spatrick { 814f24071e5Spatrick return ticks; 815f24071e5Spatrick } 816f24071e5Spatrick 817f24071e5Spatrick /* 818f24071e5Spatrick * Various device-related bits. 819f24071e5Spatrick */ 820f24071e5Spatrick 821f24071e5Spatrick void 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 883f24071e5Spatrick cnspeed(dev_t dev, int sp) 884f24071e5Spatrick { 885f24071e5Spatrick return 115200; 886f24071e5Spatrick } 887f24071e5Spatrick 8885cfe0970Skettenis char ttyname_buf[8]; 8895cfe0970Skettenis 890f24071e5Spatrick char * 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 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 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 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 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 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 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 * 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 11244befd8f0Spatrick if (strcmp(hw_vendor, "LENOVO") == 0 && 1125a36d06b9Spatrick strncmp(hw_prod, "21BX", 4) == 0) { 11264befd8f0Spatrick fdt_load_override(FW_PATH 11274befd8f0Spatrick "qcom/sc8280xp-lenovo-thinkpad-x13s.dtb"); 1128a36d06b9Spatrick /* TODO: find a better mechanism */ 1129a36d06b9Spatrick cnset(ttydev("fb0")); 1130a36d06b9Spatrick } 11314befd8f0Spatrick 11324befd8f0Spatrick return fdt_override ? fdt_override : fdt_sys; 11334befd8f0Spatrick } 11344befd8f0Spatrick 11354befd8f0Spatrick int 11364befd8f0Spatrick fdt_load_override(char *file) 11374befd8f0Spatrick { 11384befd8f0Spatrick EFI_PHYSICAL_ADDRESS addr; 11394befd8f0Spatrick char path[MAXPATHLEN]; 11404befd8f0Spatrick struct stat sb; 11414befd8f0Spatrick int fd; 11424befd8f0Spatrick 11434befd8f0Spatrick if (file == NULL && fdt_override) { 11444befd8f0Spatrick BS->FreePages((uint64_t)fdt_override, 11454befd8f0Spatrick EFI_SIZE_TO_PAGES(fdt_override_size)); 11464befd8f0Spatrick fdt_override = NULL; 11474befd8f0Spatrick fdt_init(fdt_sys); 11484befd8f0Spatrick return 0; 11494befd8f0Spatrick } 11504befd8f0Spatrick 11514befd8f0Spatrick snprintf(path, sizeof(path), "%s:%s", cmd.bootdev, file); 11524befd8f0Spatrick 11534befd8f0Spatrick fd = open(path, O_RDONLY); 11544befd8f0Spatrick if (fd < 0 || fstat(fd, &sb) == -1) { 11554befd8f0Spatrick printf("cannot open %s\n", path); 11564befd8f0Spatrick return 0; 11574befd8f0Spatrick } 11584befd8f0Spatrick if (efi_memprobe_find(EFI_SIZE_TO_PAGES(sb.st_size), 11594befd8f0Spatrick PAGE_SIZE, EfiLoaderData, &addr) != EFI_SUCCESS) { 11604befd8f0Spatrick printf("cannot allocate memory for %s\n", path); 11614befd8f0Spatrick return 0; 11624befd8f0Spatrick } 11634befd8f0Spatrick if (read(fd, (void *)addr, sb.st_size) != sb.st_size) { 11644befd8f0Spatrick printf("cannot read from %s\n", path); 11654befd8f0Spatrick return 0; 11664befd8f0Spatrick } 11674befd8f0Spatrick 11684befd8f0Spatrick if (!fdt_init((void *)addr)) { 11694befd8f0Spatrick printf("invalid device tree\n"); 11704befd8f0Spatrick BS->FreePages(addr, EFI_SIZE_TO_PAGES(sb.st_size)); 11714befd8f0Spatrick return 0; 11724befd8f0Spatrick } 11734befd8f0Spatrick 11744befd8f0Spatrick if (fdt_override) { 11754befd8f0Spatrick BS->FreePages((uint64_t)fdt_override, 11764befd8f0Spatrick EFI_SIZE_TO_PAGES(fdt_override_size)); 11774befd8f0Spatrick fdt_override = NULL; 11784befd8f0Spatrick } 11794befd8f0Spatrick 11804befd8f0Spatrick fdt_override = (void *)addr; 11814befd8f0Spatrick fdt_override_size = sb.st_size; 11824befd8f0Spatrick return 0; 11834befd8f0Spatrick } 11844befd8f0Spatrick 1185111d6387Skettenis /* 1186111d6387Skettenis * Commands 1187111d6387Skettenis */ 1188111d6387Skettenis 1189be07ee62Skettenis int Xacpi_efi(void); 11906f83097eSpatrick int Xdtb_efi(void); 1191111d6387Skettenis int Xexit_efi(void); 1192111d6387Skettenis int Xpoweroff_efi(void); 1193111d6387Skettenis 1194111d6387Skettenis const struct cmd_table cmd_machine[] = { 1195be07ee62Skettenis { "acpi", CMDT_CMD, Xacpi_efi }, 11966f83097eSpatrick { "dtb", CMDT_CMD, Xdtb_efi }, 1197111d6387Skettenis { "exit", CMDT_CMD, Xexit_efi }, 1198111d6387Skettenis { "poweroff", CMDT_CMD, Xpoweroff_efi }, 1199111d6387Skettenis { NULL, 0 } 1200111d6387Skettenis }; 1201111d6387Skettenis 1202111d6387Skettenis int 1203be07ee62Skettenis Xacpi_efi(void) 1204be07ee62Skettenis { 1205be07ee62Skettenis acpi = 1; 1206be07ee62Skettenis return (0); 1207be07ee62Skettenis } 1208be07ee62Skettenis 1209be07ee62Skettenis int 12106f83097eSpatrick Xdtb_efi(void) 12116f83097eSpatrick { 12124befd8f0Spatrick if (cmd.argc == 1) { 12134befd8f0Spatrick fdt_load_override(NULL); 12144befd8f0Spatrick return (0); 12154befd8f0Spatrick } 12166f83097eSpatrick 1217fcf3d43cSkn if (cmd.argc != 2) { 1218fcf3d43cSkn printf("dtb file\n"); 1219fcf3d43cSkn return (0); 1220fcf3d43cSkn } 12216f83097eSpatrick 12224befd8f0Spatrick return fdt_load_override(cmd.argv[1]); 12236f83097eSpatrick } 12246f83097eSpatrick 12256f83097eSpatrick int 1226111d6387Skettenis Xexit_efi(void) 1227111d6387Skettenis { 12281f462730Skrw BS->Exit(IH, 0, 0, NULL); 1229111d6387Skettenis for (;;) 1230111d6387Skettenis continue; 1231111d6387Skettenis return (0); 1232111d6387Skettenis } 1233111d6387Skettenis 1234111d6387Skettenis int 1235111d6387Skettenis Xpoweroff_efi(void) 1236111d6387Skettenis { 12371f462730Skrw RS->ResetSystem(EfiResetShutdown, EFI_SUCCESS, 0, NULL); 1238111d6387Skettenis return (0); 1239111d6387Skettenis } 1240