1*58554311Spatrick /* $OpenBSD: efiboot.c,v 1.36 2021/10/26 14:10:02 patrick 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; 50f24071e5Spatrick 51fa854029Spatrick EFI_PHYSICAL_ADDRESS heap; 52fa854029Spatrick UINTN heapsiz = 1 * 1024 * 1024; 53f673f4ddSkettenis EFI_MEMORY_DESCRIPTOR *mmap; 54fa854029Spatrick UINTN mmap_key; 55fa854029Spatrick UINTN mmap_ndesc; 56fa854029Spatrick UINTN mmap_descsiz; 57f4dd1aebSkettenis UINT32 mmap_version; 58f24071e5Spatrick 59f24071e5Spatrick static EFI_GUID imgp_guid = LOADED_IMAGE_PROTOCOL; 60f24071e5Spatrick static EFI_GUID blkio_guid = BLOCK_IO_PROTOCOL; 61f24071e5Spatrick static EFI_GUID devp_guid = DEVICE_PATH_PROTOCOL; 621e44dc38Skettenis static EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; 63f24071e5Spatrick 6433e5575aSpatrick int efi_device_path_depth(EFI_DEVICE_PATH *dp, int); 6533e5575aSpatrick int efi_device_path_ncmp(EFI_DEVICE_PATH *, EFI_DEVICE_PATH *, int); 66fa854029Spatrick static void efi_heap_init(void); 67fa854029Spatrick static void efi_memprobe_internal(void); 68f24071e5Spatrick static void efi_timer_init(void); 69f24071e5Spatrick static void efi_timer_cleanup(void); 70f24071e5Spatrick static EFI_STATUS efi_memprobe_find(UINTN, UINTN, EFI_PHYSICAL_ADDRESS *); 71f24071e5Spatrick 72f24071e5Spatrick EFI_STATUS 73f24071e5Spatrick efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab) 74f24071e5Spatrick { 75f24071e5Spatrick extern char *progname; 76f24071e5Spatrick EFI_LOADED_IMAGE *imgp; 77f24071e5Spatrick EFI_DEVICE_PATH *dp = NULL; 78f24071e5Spatrick EFI_STATUS status; 79f24071e5Spatrick 80f24071e5Spatrick ST = systab; 81f24071e5Spatrick BS = ST->BootServices; 82496ffee0Spatrick RS = ST->RuntimeServices; 83f24071e5Spatrick IH = image; 84f24071e5Spatrick 85f0da534cSjsg /* disable reset by watchdog after 5 minutes */ 861f462730Skrw BS->SetWatchdogTimer(0, 0, 0, NULL); 87f0da534cSjsg 881f462730Skrw status = BS->HandleProtocol(image, &imgp_guid, 89f24071e5Spatrick (void **)&imgp); 90f24071e5Spatrick if (status == EFI_SUCCESS) 911f462730Skrw status = BS->HandleProtocol(imgp->DeviceHandle, &devp_guid, 921f462730Skrw (void **)&dp); 93f24071e5Spatrick if (status == EFI_SUCCESS) 94f24071e5Spatrick efi_bootdp = dp; 95f24071e5Spatrick 96f24071e5Spatrick progname = "BOOTAA64"; 97f24071e5Spatrick 98f24071e5Spatrick boot(0); 99f24071e5Spatrick 100f24071e5Spatrick return (EFI_SUCCESS); 101f24071e5Spatrick } 102f24071e5Spatrick 103f24071e5Spatrick static SIMPLE_TEXT_OUTPUT_INTERFACE *conout; 104f24071e5Spatrick static SIMPLE_INPUT_INTERFACE *conin; 105f24071e5Spatrick 1065cfe0970Skettenis /* 1075cfe0970Skettenis * The device majors for these don't match the ones used by the 1085cfe0970Skettenis * kernel. That's fine. They're just used as an index into the cdevs 1095cfe0970Skettenis * array and never passed on to the kernel. 1105cfe0970Skettenis */ 1115cfe0970Skettenis static dev_t serial = makedev(0, 0); 1125cfe0970Skettenis static dev_t framebuffer = makedev(1, 0); 1135cfe0970Skettenis 1145f7ab753Skettenis static char framebuffer_path[128]; 1155f7ab753Skettenis 116f24071e5Spatrick void 117f24071e5Spatrick efi_cons_probe(struct consdev *cn) 118f24071e5Spatrick { 119f24071e5Spatrick cn->cn_pri = CN_MIDPRI; 1205cfe0970Skettenis cn->cn_dev = serial; 121f24071e5Spatrick } 122f24071e5Spatrick 123f24071e5Spatrick void 124f24071e5Spatrick efi_cons_init(struct consdev *cp) 125f24071e5Spatrick { 126f24071e5Spatrick conin = ST->ConIn; 127f24071e5Spatrick conout = ST->ConOut; 128f24071e5Spatrick } 129f24071e5Spatrick 130f24071e5Spatrick int 131f24071e5Spatrick efi_cons_getc(dev_t dev) 132f24071e5Spatrick { 133f24071e5Spatrick EFI_INPUT_KEY key; 134f24071e5Spatrick EFI_STATUS status; 135f24071e5Spatrick #if 0 136f24071e5Spatrick UINTN dummy; 137f24071e5Spatrick #endif 138f24071e5Spatrick static int lastchar = 0; 139f24071e5Spatrick 140f24071e5Spatrick if (lastchar) { 141f24071e5Spatrick int r = lastchar; 142f24071e5Spatrick if ((dev & 0x80) == 0) 143f24071e5Spatrick lastchar = 0; 144f24071e5Spatrick return (r); 145f24071e5Spatrick } 146f24071e5Spatrick 147f24071e5Spatrick status = conin->ReadKeyStroke(conin, &key); 148678d37b9Syasuoka while (status == EFI_NOT_READY || key.UnicodeChar == 0) { 149f24071e5Spatrick if (dev & 0x80) 150f24071e5Spatrick return (0); 151f24071e5Spatrick /* 152f24071e5Spatrick * XXX The implementation of WaitForEvent() in U-boot 153f24071e5Spatrick * is broken and neverreturns. 154f24071e5Spatrick */ 155f24071e5Spatrick #if 0 156f24071e5Spatrick BS->WaitForEvent(1, &conin->WaitForKey, &dummy); 157f24071e5Spatrick #endif 158f24071e5Spatrick status = conin->ReadKeyStroke(conin, &key); 159f24071e5Spatrick } 160f24071e5Spatrick 161f24071e5Spatrick if (dev & 0x80) 162f24071e5Spatrick lastchar = key.UnicodeChar; 163f24071e5Spatrick 164f24071e5Spatrick return (key.UnicodeChar); 165f24071e5Spatrick } 166f24071e5Spatrick 167f24071e5Spatrick void 168f24071e5Spatrick efi_cons_putc(dev_t dev, int c) 169f24071e5Spatrick { 170f24071e5Spatrick CHAR16 buf[2]; 171f24071e5Spatrick 172f24071e5Spatrick if (c == '\n') 173f24071e5Spatrick efi_cons_putc(dev, '\r'); 174f24071e5Spatrick 175f24071e5Spatrick buf[0] = c; 176f24071e5Spatrick buf[1] = 0; 177f24071e5Spatrick 178f24071e5Spatrick conout->OutputString(conout, buf); 179f24071e5Spatrick } 180f24071e5Spatrick 1815cfe0970Skettenis void 1825cfe0970Skettenis efi_fb_probe(struct consdev *cn) 1835cfe0970Skettenis { 1845cfe0970Skettenis cn->cn_pri = CN_LOWPRI; 1855cfe0970Skettenis cn->cn_dev = framebuffer; 1865cfe0970Skettenis } 1875cfe0970Skettenis 1885cfe0970Skettenis void 1895cfe0970Skettenis efi_fb_init(struct consdev *cn) 1905cfe0970Skettenis { 1915cfe0970Skettenis conin = ST->ConIn; 1925cfe0970Skettenis conout = ST->ConOut; 1935cfe0970Skettenis } 1945cfe0970Skettenis 1955cfe0970Skettenis int 1965cfe0970Skettenis efi_fb_getc(dev_t dev) 1975cfe0970Skettenis { 1985cfe0970Skettenis return efi_cons_getc(dev); 1995cfe0970Skettenis } 2005cfe0970Skettenis 2015cfe0970Skettenis void 2025cfe0970Skettenis efi_fb_putc(dev_t dev, int c) 2035cfe0970Skettenis { 2045cfe0970Skettenis efi_cons_putc(dev, c); 2055cfe0970Skettenis } 2065cfe0970Skettenis 207f24071e5Spatrick static void 208f24071e5Spatrick efi_heap_init(void) 209f24071e5Spatrick { 210f24071e5Spatrick EFI_STATUS status; 211f24071e5Spatrick 2121f462730Skrw status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, 213f24071e5Spatrick EFI_SIZE_TO_PAGES(heapsiz), &heap); 214f24071e5Spatrick if (status != EFI_SUCCESS) 215f24071e5Spatrick panic("BS->AllocatePages()"); 216f24071e5Spatrick } 217f24071e5Spatrick 2185b351376Spatrick struct disklist_lh disklist; 2195b351376Spatrick struct diskinfo *bootdev_dip; 220f24071e5Spatrick 221f24071e5Spatrick void 222f24071e5Spatrick efi_diskprobe(void) 223f24071e5Spatrick { 2245b351376Spatrick int i, bootdev = 0, depth = -1; 225f24071e5Spatrick UINTN sz; 226f24071e5Spatrick EFI_STATUS status; 227f24071e5Spatrick EFI_HANDLE *handles = NULL; 228f24071e5Spatrick EFI_BLOCK_IO *blkio; 229f24071e5Spatrick EFI_BLOCK_IO_MEDIA *media; 2305b351376Spatrick struct diskinfo *di; 231c6d7d0adSpatrick EFI_DEVICE_PATH *dp; 232f24071e5Spatrick 2335b351376Spatrick TAILQ_INIT(&disklist); 2345b351376Spatrick 235f24071e5Spatrick sz = 0; 2361f462730Skrw status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz, 0); 237f24071e5Spatrick if (status == EFI_BUFFER_TOO_SMALL) { 238f24071e5Spatrick handles = alloc(sz); 2391f462730Skrw status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz, 2401f462730Skrw handles); 241f24071e5Spatrick } 242f24071e5Spatrick if (handles == NULL || EFI_ERROR(status)) 24333e5575aSpatrick return; 244f24071e5Spatrick 245c6d7d0adSpatrick if (efi_bootdp != NULL) 246c6d7d0adSpatrick depth = efi_device_path_depth(efi_bootdp, MEDIA_DEVICE_PATH); 247c6d7d0adSpatrick 248c94e7257Skettenis /* 249c94e7257Skettenis * U-Boot incorrectly represents devices with a single 250c94e7257Skettenis * MEDIA_DEVICE_PATH component. In that case include that 251c94e7257Skettenis * component into the matching, otherwise we'll blindly select 252c94e7257Skettenis * the first device. 253c94e7257Skettenis */ 254c94e7257Skettenis if (depth == 0) 255c94e7257Skettenis depth = 1; 256c94e7257Skettenis 257f24071e5Spatrick for (i = 0; i < sz / sizeof(EFI_HANDLE); i++) { 2581f462730Skrw status = BS->HandleProtocol(handles[i], &blkio_guid, 259f24071e5Spatrick (void **)&blkio); 260f24071e5Spatrick if (EFI_ERROR(status)) 261f24071e5Spatrick panic("BS->HandleProtocol() returns %d", status); 262f24071e5Spatrick 263f24071e5Spatrick media = blkio->Media; 264f24071e5Spatrick if (media->LogicalPartition || !media->MediaPresent) 265f24071e5Spatrick continue; 2665b351376Spatrick di = alloc(sizeof(struct diskinfo)); 2675b351376Spatrick efid_init(di, blkio); 268f24071e5Spatrick 2695b351376Spatrick if (efi_bootdp == NULL || depth == -1 || bootdev != 0) 2705b351376Spatrick goto next; 2711f462730Skrw status = BS->HandleProtocol(handles[i], &devp_guid, 272f24071e5Spatrick (void **)&dp); 273f24071e5Spatrick if (EFI_ERROR(status)) 2745b351376Spatrick goto next; 275c6d7d0adSpatrick if (efi_device_path_ncmp(efi_bootdp, dp, depth) == 0) { 2765b351376Spatrick TAILQ_INSERT_HEAD(&disklist, di, list); 2775b351376Spatrick bootdev_dip = di; 2785b351376Spatrick bootdev = 1; 2795b351376Spatrick continue; 280f24071e5Spatrick } 2815b351376Spatrick next: 2825b351376Spatrick TAILQ_INSERT_TAIL(&disklist, di, list); 283f24071e5Spatrick } 284f24071e5Spatrick 285f24071e5Spatrick free(handles, sz); 2865b351376Spatrick 2875b351376Spatrick /* Print available disks and probe for softraid. */ 2885b351376Spatrick i = 0; 2895b351376Spatrick printf("disks:"); 2905b351376Spatrick TAILQ_FOREACH(di, &disklist, list) { 2915b351376Spatrick printf(" sd%d%s", i, di == bootdev_dip ? "*" : ""); 2925b351376Spatrick i++; 2935b351376Spatrick } 2945b351376Spatrick srprobe(); 2955b351376Spatrick printf("\n"); 296f24071e5Spatrick } 297f24071e5Spatrick 298c94e7257Skettenis /* 299c94e7257Skettenis * Determine the number of nodes up to, but not including, the first 300c94e7257Skettenis * node of the specified type. 301c94e7257Skettenis */ 30233e5575aSpatrick int 303c6d7d0adSpatrick efi_device_path_depth(EFI_DEVICE_PATH *dp, int dptype) 304c6d7d0adSpatrick { 305c6d7d0adSpatrick int i; 306c6d7d0adSpatrick 307c6d7d0adSpatrick for (i = 0; !IsDevicePathEnd(dp); dp = NextDevicePathNode(dp), i++) { 308c6d7d0adSpatrick if (DevicePathType(dp) == dptype) 309c94e7257Skettenis return (i); 310c6d7d0adSpatrick } 311c6d7d0adSpatrick 312d64e7de5Skettenis return (i); 313c6d7d0adSpatrick } 314c6d7d0adSpatrick 31533e5575aSpatrick int 316c6d7d0adSpatrick efi_device_path_ncmp(EFI_DEVICE_PATH *dpa, EFI_DEVICE_PATH *dpb, int deptn) 317c6d7d0adSpatrick { 318c6d7d0adSpatrick int i, cmp; 319c6d7d0adSpatrick 320c6d7d0adSpatrick for (i = 0; i < deptn; i++) { 321c6d7d0adSpatrick if (IsDevicePathEnd(dpa) || IsDevicePathEnd(dpb)) 322c6d7d0adSpatrick return ((IsDevicePathEnd(dpa) && IsDevicePathEnd(dpb)) 323c6d7d0adSpatrick ? 0 : (IsDevicePathEnd(dpa))? -1 : 1); 324c6d7d0adSpatrick cmp = DevicePathNodeLength(dpa) - DevicePathNodeLength(dpb); 325c6d7d0adSpatrick if (cmp) 326c6d7d0adSpatrick return (cmp); 327c6d7d0adSpatrick cmp = memcmp(dpa, dpb, DevicePathNodeLength(dpa)); 328c6d7d0adSpatrick if (cmp) 329c6d7d0adSpatrick return (cmp); 330c6d7d0adSpatrick dpa = NextDevicePathNode(dpa); 331c6d7d0adSpatrick dpb = NextDevicePathNode(dpb); 332c6d7d0adSpatrick } 333c6d7d0adSpatrick 334c6d7d0adSpatrick return (0); 335c6d7d0adSpatrick } 336c6d7d0adSpatrick 3371e44dc38Skettenis void 3381e44dc38Skettenis efi_framebuffer(void) 3391e44dc38Skettenis { 3401e44dc38Skettenis EFI_GRAPHICS_OUTPUT *gop; 3411e44dc38Skettenis EFI_STATUS status; 3421e44dc38Skettenis void *node, *child; 3431e44dc38Skettenis uint32_t acells, scells; 3441e44dc38Skettenis uint64_t base, size; 3451e44dc38Skettenis uint32_t reg[4]; 3461e44dc38Skettenis uint32_t width, height, stride; 3471e44dc38Skettenis char *format; 3485cfe0970Skettenis char *prop; 3491e44dc38Skettenis 3501e44dc38Skettenis /* 3511e44dc38Skettenis * Don't create a "simple-framebuffer" node if we already have 3521e44dc38Skettenis * one. Besides "/chosen", we also check under "/" since that 3531e44dc38Skettenis * is where the Raspberry Pi firmware puts it. 3541e44dc38Skettenis */ 3551e44dc38Skettenis node = fdt_find_node("/chosen"); 3561e44dc38Skettenis for (child = fdt_child_node(node); child; 3571e44dc38Skettenis child = fdt_next_node(child)) { 3585cfe0970Skettenis if (!fdt_node_is_compatible(child, "simple-framebuffer")) 3595cfe0970Skettenis continue; 3605028e024Skettenis if (!fdt_node_property(child, "status", &prop) || 3615f7ab753Skettenis strcmp(prop, "okay") == 0) { 3625f7ab753Skettenis strlcpy(framebuffer_path, "/chosen/", 3635f7ab753Skettenis sizeof(framebuffer_path)); 3645f7ab753Skettenis strlcat(framebuffer_path, fdt_node_name(child), 3655f7ab753Skettenis sizeof(framebuffer_path)); 3661e44dc38Skettenis return; 3671e44dc38Skettenis } 3685f7ab753Skettenis } 3691e44dc38Skettenis node = fdt_find_node("/"); 3701e44dc38Skettenis for (child = fdt_child_node(node); child; 3711e44dc38Skettenis child = fdt_next_node(child)) { 3725cfe0970Skettenis if (!fdt_node_is_compatible(child, "simple-framebuffer")) 3735cfe0970Skettenis continue; 3745028e024Skettenis if (!fdt_node_property(child, "status", &prop) || 3755f7ab753Skettenis strcmp(prop, "okay") == 0) { 3765f7ab753Skettenis strlcpy(framebuffer_path, "/", 3775f7ab753Skettenis sizeof(framebuffer_path)); 3785f7ab753Skettenis strlcat(framebuffer_path, fdt_node_name(child), 3795f7ab753Skettenis sizeof(framebuffer_path)); 3801e44dc38Skettenis return; 3811e44dc38Skettenis } 3825f7ab753Skettenis } 3831e44dc38Skettenis 3841f462730Skrw status = BS->LocateProtocol(&gop_guid, NULL, (void **)&gop); 3851e44dc38Skettenis if (status != EFI_SUCCESS) 3861e44dc38Skettenis return; 3871e44dc38Skettenis 3881e44dc38Skettenis /* Paranoia! */ 3891e44dc38Skettenis if (gop == NULL || gop->Mode == NULL || gop->Mode->Info == NULL) 3901e44dc38Skettenis return; 3911e44dc38Skettenis 3921e44dc38Skettenis /* We only support 32-bit pixel modes for now. */ 3931e44dc38Skettenis switch (gop->Mode->Info->PixelFormat) { 3941e44dc38Skettenis case PixelRedGreenBlueReserved8BitPerColor: 395b870cd26Skettenis format = "x8b8g8r8"; 3961e44dc38Skettenis break; 3971e44dc38Skettenis case PixelBlueGreenRedReserved8BitPerColor: 398b870cd26Skettenis format = "x8r8g8b8"; 3991e44dc38Skettenis break; 4001e44dc38Skettenis default: 4011e44dc38Skettenis return; 4021e44dc38Skettenis } 4031e44dc38Skettenis 4041e44dc38Skettenis base = gop->Mode->FrameBufferBase; 4051e44dc38Skettenis size = gop->Mode->FrameBufferSize; 4061e44dc38Skettenis width = htobe32(gop->Mode->Info->HorizontalResolution); 4071e44dc38Skettenis height = htobe32(gop->Mode->Info->VerticalResolution); 4081e44dc38Skettenis stride = htobe32(gop->Mode->Info->PixelsPerScanLine * 4); 4091e44dc38Skettenis 4101e44dc38Skettenis node = fdt_find_node("/"); 4111e44dc38Skettenis if (fdt_node_property_int(node, "#address-cells", &acells) != 1) 4121e44dc38Skettenis acells = 1; 4131e44dc38Skettenis if (fdt_node_property_int(node, "#size-cells", &scells) != 1) 4141e44dc38Skettenis scells = 1; 4151e44dc38Skettenis if (acells > 2 || scells > 2) 4161e44dc38Skettenis return; 4171e44dc38Skettenis if (acells >= 1) 4181e44dc38Skettenis reg[0] = htobe32(base); 4191e44dc38Skettenis if (acells == 2) { 4201e44dc38Skettenis reg[1] = reg[0]; 4211e44dc38Skettenis reg[0] = htobe32(base >> 32); 4221e44dc38Skettenis } 4231e44dc38Skettenis if (scells >= 1) 4241e44dc38Skettenis reg[acells] = htobe32(size); 4251e44dc38Skettenis if (scells == 2) { 4261e44dc38Skettenis reg[acells + 1] = reg[acells]; 4271e44dc38Skettenis reg[acells] = htobe32(size >> 32); 4281e44dc38Skettenis } 4291e44dc38Skettenis 4301e44dc38Skettenis node = fdt_find_node("/chosen"); 4311e44dc38Skettenis fdt_node_add_node(node, "framebuffer", &child); 4321e44dc38Skettenis fdt_node_add_property(child, "status", "okay", strlen("okay") + 1); 4331e44dc38Skettenis fdt_node_add_property(child, "format", format, strlen(format) + 1); 4341e44dc38Skettenis fdt_node_add_property(child, "stride", &stride, 4); 4351e44dc38Skettenis fdt_node_add_property(child, "height", &height, 4); 4361e44dc38Skettenis fdt_node_add_property(child, "width", &width, 4); 4371e44dc38Skettenis fdt_node_add_property(child, "reg", reg, (acells + scells) * 4); 4381e44dc38Skettenis fdt_node_add_property(child, "compatible", 4391e44dc38Skettenis "simple-framebuffer", strlen("simple-framebuffer") + 1); 4405f7ab753Skettenis 4415f7ab753Skettenis strlcpy(framebuffer_path, "/chosen/framebuffer", 4425f7ab753Skettenis sizeof(framebuffer_path)); 4431e44dc38Skettenis } 4441e44dc38Skettenis 4455cfe0970Skettenis void 4465cfe0970Skettenis efi_console(void) 4475cfe0970Skettenis { 4485f7ab753Skettenis void *node; 4495cfe0970Skettenis 4505cfe0970Skettenis if (cn_tab->cn_dev != framebuffer) 4515cfe0970Skettenis return; 4525cfe0970Skettenis 4535f7ab753Skettenis if (strlen(framebuffer_path) == 0) 4545cfe0970Skettenis return; 4555cfe0970Skettenis 4565cfe0970Skettenis /* Point stdout-path at the framebuffer node. */ 4575f7ab753Skettenis node = fdt_find_node("/chosen"); 4585f7ab753Skettenis fdt_node_add_property(node, "stdout-path", 4595f7ab753Skettenis framebuffer_path, strlen(framebuffer_path) + 1); 4605cfe0970Skettenis } 4615cfe0970Skettenis 462a88d1494Skettenis uint64_t dma_constraint[2] = { 0, -1 }; 463a88d1494Skettenis 464a88d1494Skettenis void 465a88d1494Skettenis efi_dma_constraint(void) 466a88d1494Skettenis { 467a88d1494Skettenis void *node; 468cfb73cfeSpatrick char *prop; 469cfb73cfeSpatrick uint32_t *propint; 470cfb73cfeSpatrick uint64_t base, size; 471cfb73cfeSpatrick uint32_t pacells, pscells; 472cfb73cfeSpatrick uint32_t acells, scells; 473cfb73cfeSpatrick int len; 474cfb73cfeSpatrick 475cfb73cfeSpatrick node = fdt_find_node("/"); 476cfb73cfeSpatrick if (fdt_node_property_int(node, "#address-cells", &pacells) != 1) 477cfb73cfeSpatrick pacells = 1; 478cfb73cfeSpatrick if (fdt_node_property_int(node, "#size-cells", &pscells) != 1) 479cfb73cfeSpatrick pscells = 1; 480cfb73cfeSpatrick if (pacells > 2 || pscells > 2) 481cfb73cfeSpatrick return; 482cfb73cfeSpatrick 483cfb73cfeSpatrick node = fdt_find_node("/soc"); 484cfb73cfeSpatrick if (node != NULL) { 485cfb73cfeSpatrick if (fdt_node_property_int(node, "#address-cells", &acells) != 1) 486cfb73cfeSpatrick acells = pacells; 487cfb73cfeSpatrick if (fdt_node_property_int(node, "#size-cells", &scells) != 1) 488cfb73cfeSpatrick scells = pscells; 489cfb73cfeSpatrick if (acells > 2 || scells > 2) 490cfb73cfeSpatrick return; 491cfb73cfeSpatrick 492cfb73cfeSpatrick len = fdt_node_property(node, "dma-ranges", &prop); 493cfb73cfeSpatrick propint = (uint32_t *)prop; 494cfb73cfeSpatrick if (len == (acells + pacells + scells) * sizeof(uint32_t)) { 495cfb73cfeSpatrick base = betoh32(propint[acells]); 496cfb73cfeSpatrick if (pacells == 2) 497cfb73cfeSpatrick base = (base << 32) | 498cfb73cfeSpatrick betoh32(propint[acells + 1]); 499cfb73cfeSpatrick size = betoh32(propint[acells + pacells]); 500cfb73cfeSpatrick if (scells == 2) 501cfb73cfeSpatrick size = (size << 32) | 502cfb73cfeSpatrick betoh32(propint[acells + pacells + 1]); 503cfb73cfeSpatrick 504cfb73cfeSpatrick dma_constraint[0] = htobe64(base); 505cfb73cfeSpatrick dma_constraint[1] = htobe64(base + size - 1); 506cfb73cfeSpatrick } 507cfb73cfeSpatrick } 508a88d1494Skettenis 509a88d1494Skettenis /* Raspberry Pi 4 is "special". */ 510a88d1494Skettenis node = fdt_find_node("/"); 511a88d1494Skettenis if (fdt_node_is_compatible(node, "brcm,bcm2711")) 512a88d1494Skettenis dma_constraint[1] = htobe64(0x3bffffff); 513a88d1494Skettenis 514a88d1494Skettenis /* Pass DMA constraint. */ 515a88d1494Skettenis node = fdt_find_node("/chosen"); 516a88d1494Skettenis fdt_node_add_property(node, "openbsd,dma-constraint", 517a88d1494Skettenis dma_constraint, sizeof(dma_constraint)); 518a88d1494Skettenis } 519a88d1494Skettenis 520be07ee62Skettenis int acpi = 0; 5216f83097eSpatrick void *fdt = NULL; 5229ccb13abSnaddy char *bootmac = NULL; 523f24071e5Spatrick static EFI_GUID fdt_guid = FDT_TABLE_GUID; 524f24071e5Spatrick 525f24071e5Spatrick #define efi_guidcmp(_a, _b) memcmp((_a), (_b), sizeof(EFI_GUID)) 526f24071e5Spatrick 527f24071e5Spatrick void * 5289419d8aaSkettenis efi_makebootargs(char *bootargs, int howto) 529f24071e5Spatrick { 5305b351376Spatrick struct sr_boot_volume *bv; 531f4dd1aebSkettenis u_char bootduid[8]; 532f4dd1aebSkettenis u_char zero[8] = { 0 }; 533f4dd1aebSkettenis uint64_t uefi_system_table = htobe64((uintptr_t)ST); 5349419d8aaSkettenis uint32_t boothowto = htobe32(howto); 535*58554311Spatrick EFI_PHYSICAL_ADDRESS addr; 536f24071e5Spatrick void *node; 537f24071e5Spatrick size_t len; 538f24071e5Spatrick int i; 539f24071e5Spatrick 5406f83097eSpatrick if (fdt == NULL) { 541f24071e5Spatrick for (i = 0; i < ST->NumberOfTableEntries; i++) { 542f24071e5Spatrick if (efi_guidcmp(&fdt_guid, 543f24071e5Spatrick &ST->ConfigurationTable[i].VendorGuid) == 0) 544f24071e5Spatrick fdt = ST->ConfigurationTable[i].VendorTable; 545f24071e5Spatrick } 5466f83097eSpatrick } 547f24071e5Spatrick 548be07ee62Skettenis if (fdt == NULL || acpi) 5499a1480b1Skettenis fdt = efi_acpi(); 5509a1480b1Skettenis 551*58554311Spatrick if (!fdt_get_size(fdt)) 552*58554311Spatrick return NULL; 553*58554311Spatrick 554*58554311Spatrick len = roundup(fdt_get_size(fdt) + PAGE_SIZE, PAGE_SIZE); 555*58554311Spatrick if (BS->AllocatePages(AllocateAnyPages, EfiLoaderData, 556*58554311Spatrick EFI_SIZE_TO_PAGES(len), &addr) == EFI_SUCCESS) { 557*58554311Spatrick memcpy((void *)addr, fdt, fdt_get_size(fdt)); 558*58554311Spatrick fdt = (void *)addr; 559*58554311Spatrick } 560*58554311Spatrick 561f24071e5Spatrick if (!fdt_init(fdt)) 562f24071e5Spatrick return NULL; 563f24071e5Spatrick 564f24071e5Spatrick node = fdt_find_node("/chosen"); 565f24071e5Spatrick if (!node) 566f24071e5Spatrick return NULL; 567f24071e5Spatrick 568f24071e5Spatrick len = strlen(bootargs) + 1; 569f24071e5Spatrick fdt_node_add_property(node, "bootargs", bootargs, len); 5709419d8aaSkettenis fdt_node_add_property(node, "openbsd,boothowto", 5719419d8aaSkettenis &boothowto, sizeof(boothowto)); 572f24071e5Spatrick 573f24071e5Spatrick /* Pass DUID of the boot disk. */ 5745b351376Spatrick if (bootdev_dip) { 5755b351376Spatrick memcpy(&bootduid, bootdev_dip->disklabel.d_uid, 576f24071e5Spatrick sizeof(bootduid)); 5775b351376Spatrick if (memcmp(bootduid, zero, sizeof(bootduid)) != 0) { 5785b351376Spatrick fdt_node_add_property(node, "openbsd,bootduid", 5795b351376Spatrick bootduid, sizeof(bootduid)); 580f24071e5Spatrick } 581f24071e5Spatrick 5825b351376Spatrick if (bootdev_dip->sr_vol != NULL) { 5835b351376Spatrick bv = bootdev_dip->sr_vol; 5845b351376Spatrick fdt_node_add_property(node, "openbsd,sr-bootuuid", 5855b351376Spatrick &bv->sbv_uuid, sizeof(bv->sbv_uuid)); 5865b351376Spatrick if (bv->sbv_maskkey != NULL) 5875b351376Spatrick fdt_node_add_property(node, 5885b351376Spatrick "openbsd,sr-bootkey", bv->sbv_maskkey, 5895b351376Spatrick SR_CRYPTO_MAXKEYBYTES); 5905b351376Spatrick } 5915b351376Spatrick } 5925b351376Spatrick 5935b351376Spatrick sr_clear_keys(); 5945b351376Spatrick 5959ccb13abSnaddy /* Pass netboot interface address. */ 5969ccb13abSnaddy if (bootmac) 5979ccb13abSnaddy fdt_node_add_property(node, "openbsd,bootmac", bootmac, 6); 5989ccb13abSnaddy 599f4dd1aebSkettenis /* Pass EFI system table. */ 600f4dd1aebSkettenis fdt_node_add_property(node, "openbsd,uefi-system-table", 601f4dd1aebSkettenis &uefi_system_table, sizeof(uefi_system_table)); 602f4dd1aebSkettenis 603f4dd1aebSkettenis /* Placeholders for EFI memory map. */ 604f4dd1aebSkettenis fdt_node_add_property(node, "openbsd,uefi-mmap-start", zero, 8); 605f4dd1aebSkettenis fdt_node_add_property(node, "openbsd,uefi-mmap-size", zero, 4); 606f4dd1aebSkettenis fdt_node_add_property(node, "openbsd,uefi-mmap-desc-size", zero, 4); 607f4dd1aebSkettenis fdt_node_add_property(node, "openbsd,uefi-mmap-desc-ver", zero, 4); 608f4dd1aebSkettenis 6091e44dc38Skettenis efi_framebuffer(); 6105cfe0970Skettenis efi_console(); 611a88d1494Skettenis efi_dma_constraint(); 6121e44dc38Skettenis 613f24071e5Spatrick fdt_finalize(); 614f24071e5Spatrick 615f24071e5Spatrick return fdt; 616f24071e5Spatrick } 617f24071e5Spatrick 618f4dd1aebSkettenis void 619f4dd1aebSkettenis efi_updatefdt(void) 620f4dd1aebSkettenis { 621f4dd1aebSkettenis uint64_t uefi_mmap_start = htobe64((uintptr_t)mmap); 622f4dd1aebSkettenis uint32_t uefi_mmap_size = htobe32(mmap_ndesc * mmap_descsiz); 623f4dd1aebSkettenis uint32_t uefi_mmap_desc_size = htobe32(mmap_descsiz); 624f4dd1aebSkettenis uint32_t uefi_mmap_desc_ver = htobe32(mmap_version); 625f4dd1aebSkettenis void *node; 626f4dd1aebSkettenis 627f4dd1aebSkettenis node = fdt_find_node("/chosen"); 628f4dd1aebSkettenis if (!node) 629f4dd1aebSkettenis return; 630f4dd1aebSkettenis 631f4dd1aebSkettenis /* Pass EFI memory map. */ 632f4dd1aebSkettenis fdt_node_set_property(node, "openbsd,uefi-mmap-start", 633f4dd1aebSkettenis &uefi_mmap_start, sizeof(uefi_mmap_start)); 634f4dd1aebSkettenis fdt_node_set_property(node, "openbsd,uefi-mmap-size", 635f4dd1aebSkettenis &uefi_mmap_size, sizeof(uefi_mmap_size)); 636f4dd1aebSkettenis fdt_node_set_property(node, "openbsd,uefi-mmap-desc-size", 637f4dd1aebSkettenis &uefi_mmap_desc_size, sizeof(uefi_mmap_desc_size)); 638f4dd1aebSkettenis fdt_node_set_property(node, "openbsd,uefi-mmap-desc-ver", 639f4dd1aebSkettenis &uefi_mmap_desc_ver, sizeof(uefi_mmap_desc_ver)); 640f4dd1aebSkettenis 641f4dd1aebSkettenis fdt_finalize(); 642f4dd1aebSkettenis } 643f4dd1aebSkettenis 644f24071e5Spatrick u_long efi_loadaddr; 645f24071e5Spatrick 646f24071e5Spatrick void 647f24071e5Spatrick machdep(void) 648f24071e5Spatrick { 649f24071e5Spatrick EFI_PHYSICAL_ADDRESS addr; 650f24071e5Spatrick 651f24071e5Spatrick cninit(); 652f24071e5Spatrick efi_heap_init(); 653f24071e5Spatrick 654f24071e5Spatrick /* 6559a118d7eSpatrick * The kernel expects to be loaded into a block of memory aligned 6569a118d7eSpatrick * on a 2MB boundary. We allocate a block of 64MB of memory, which 6579a118d7eSpatrick * gives us plenty of room for growth. 658f24071e5Spatrick */ 6599a118d7eSpatrick if (efi_memprobe_find(EFI_SIZE_TO_PAGES(64 * 1024 * 1024), 6609a118d7eSpatrick 0x200000, &addr) != EFI_SUCCESS) 661f24071e5Spatrick printf("Can't allocate memory\n"); 662f24071e5Spatrick efi_loadaddr = addr; 663f24071e5Spatrick 664f24071e5Spatrick efi_timer_init(); 665f24071e5Spatrick efi_diskprobe(); 66633e5575aSpatrick efi_pxeprobe(); 667f24071e5Spatrick } 668f24071e5Spatrick 669f24071e5Spatrick void 670f24071e5Spatrick efi_cleanup(void) 671f24071e5Spatrick { 672fa854029Spatrick int retry; 673fa854029Spatrick EFI_STATUS status; 674fa854029Spatrick 675f24071e5Spatrick efi_timer_cleanup(); 676f24071e5Spatrick 677fa854029Spatrick /* retry once in case of failure */ 678fa854029Spatrick for (retry = 1; retry >= 0; retry--) { 679fa854029Spatrick efi_memprobe_internal(); /* sync the current map */ 680f4dd1aebSkettenis efi_updatefdt(); 6811f462730Skrw status = BS->ExitBootServices(IH, mmap_key); 682fa854029Spatrick if (status == EFI_SUCCESS) 683fa854029Spatrick break; 684fa854029Spatrick if (retry == 0) 685fa854029Spatrick panic("ExitBootServices failed (%d)", status); 686fa854029Spatrick } 687f24071e5Spatrick } 688f24071e5Spatrick 689f24071e5Spatrick void 690f24071e5Spatrick _rtt(void) 691f24071e5Spatrick { 692f24071e5Spatrick #ifdef EFI_DEBUG 693f24071e5Spatrick printf("Hit any key to reboot\n"); 694f24071e5Spatrick efi_cons_getc(0); 695f24071e5Spatrick #endif 696f24071e5Spatrick RS->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL); 697111d6387Skettenis for (;;) 698111d6387Skettenis continue; 699f24071e5Spatrick } 700f24071e5Spatrick 701f24071e5Spatrick /* 702f24071e5Spatrick * U-Boot only implements the GetTime() Runtime Service if it has been 703f24071e5Spatrick * configured with CONFIG_DM_RTC. Most board configurations don't 704f24071e5Spatrick * include that option, so we can't use it to implement our boot 705f24071e5Spatrick * prompt timeout. Instead we use timer events to simulate a clock 706f24071e5Spatrick * that ticks ever second. 707f24071e5Spatrick */ 708f24071e5Spatrick 709f24071e5Spatrick EFI_EVENT timer; 710f24071e5Spatrick int ticks; 711f24071e5Spatrick 712f24071e5Spatrick static VOID 713f24071e5Spatrick efi_timer(EFI_EVENT event, VOID *context) 714f24071e5Spatrick { 715f24071e5Spatrick ticks++; 716f24071e5Spatrick } 717f24071e5Spatrick 718f24071e5Spatrick static void 719f24071e5Spatrick efi_timer_init(void) 720f24071e5Spatrick { 721f24071e5Spatrick EFI_STATUS status; 722f24071e5Spatrick 723a4d88df4Sjsg status = BS->CreateEvent(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, 724f24071e5Spatrick efi_timer, NULL, &timer); 725f24071e5Spatrick if (status == EFI_SUCCESS) 726f24071e5Spatrick status = BS->SetTimer(timer, TimerPeriodic, 10000000); 727f24071e5Spatrick if (EFI_ERROR(status)) 728f24071e5Spatrick printf("Can't create timer\n"); 729f24071e5Spatrick } 730f24071e5Spatrick 731f24071e5Spatrick static void 732f24071e5Spatrick efi_timer_cleanup(void) 733f24071e5Spatrick { 734f24071e5Spatrick BS->CloseEvent(timer); 735f24071e5Spatrick } 736f24071e5Spatrick 737f24071e5Spatrick time_t 738f24071e5Spatrick getsecs(void) 739f24071e5Spatrick { 740f24071e5Spatrick return ticks; 741f24071e5Spatrick } 742f24071e5Spatrick 743f24071e5Spatrick /* 744f24071e5Spatrick * Various device-related bits. 745f24071e5Spatrick */ 746f24071e5Spatrick 747f24071e5Spatrick void 748f24071e5Spatrick devboot(dev_t dev, char *p) 749f24071e5Spatrick { 7505b351376Spatrick struct sr_boot_volume *bv; 7515b351376Spatrick struct sr_boot_chunk *bc; 7525b351376Spatrick struct diskinfo *dip; 7535b351376Spatrick int sd_boot_vol = 0; 7545b351376Spatrick int sr_boot_vol = -1; 7555b351376Spatrick int part_type = FS_UNUSED; 7565b351376Spatrick 7575b351376Spatrick if (bootdev_dip == NULL) { 75833e5575aSpatrick strlcpy(p, "tftp0a", 7); 7595b351376Spatrick return; 7605b351376Spatrick } 7615b351376Spatrick 7625b351376Spatrick TAILQ_FOREACH(dip, &disklist, list) { 7635b351376Spatrick if (bootdev_dip == dip) 7645b351376Spatrick break; 7655b351376Spatrick sd_boot_vol++; 7665b351376Spatrick } 7675b351376Spatrick 7685b351376Spatrick /* 7695b351376Spatrick * Determine the partition type for the 'a' partition of the 7705b351376Spatrick * boot device. 7715b351376Spatrick */ 7725b351376Spatrick if ((bootdev_dip->flags & DISKINFO_FLAG_GOODLABEL) != 0) 7735b351376Spatrick part_type = bootdev_dip->disklabel.d_partitions[0].p_fstype; 7745b351376Spatrick 7755b351376Spatrick /* 7765b351376Spatrick * See if we booted from a disk that is a member of a bootable 7775b351376Spatrick * softraid volume. 7785b351376Spatrick */ 7795b351376Spatrick SLIST_FOREACH(bv, &sr_volumes, sbv_link) { 7805b351376Spatrick SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link) 7815b351376Spatrick if (bc->sbc_diskinfo == bootdev_dip) 7825b351376Spatrick sr_boot_vol = bv->sbv_unit; 7835b351376Spatrick if (sr_boot_vol != -1) 7845b351376Spatrick break; 7855b351376Spatrick } 7865b351376Spatrick 7875b351376Spatrick if (sr_boot_vol != -1 && part_type != FS_BSDFFS) { 7885b351376Spatrick strlcpy(p, "sr0a", 5); 7895b351376Spatrick p[2] = '0' + sr_boot_vol; 7905b351376Spatrick return; 7915b351376Spatrick } 7925b351376Spatrick 7935b351376Spatrick strlcpy(p, "sd0a", 5); 7945b351376Spatrick p[2] = '0' + sd_boot_vol; 795f24071e5Spatrick } 796f24071e5Spatrick 7975cfe0970Skettenis const char cdevs[][4] = { "com", "fb" }; 7985cfe0970Skettenis const int ncdevs = nitems(cdevs); 7995cfe0970Skettenis 800f24071e5Spatrick int 801f24071e5Spatrick cnspeed(dev_t dev, int sp) 802f24071e5Spatrick { 803f24071e5Spatrick return 115200; 804f24071e5Spatrick } 805f24071e5Spatrick 8065cfe0970Skettenis char ttyname_buf[8]; 8075cfe0970Skettenis 808f24071e5Spatrick char * 809f24071e5Spatrick ttyname(int fd) 810f24071e5Spatrick { 8115cfe0970Skettenis snprintf(ttyname_buf, sizeof ttyname_buf, "%s%d", 8125cfe0970Skettenis cdevs[major(cn_tab->cn_dev)], minor(cn_tab->cn_dev)); 8135cfe0970Skettenis 8145cfe0970Skettenis return ttyname_buf; 815f24071e5Spatrick } 816f24071e5Spatrick 817f24071e5Spatrick dev_t 818f24071e5Spatrick ttydev(char *name) 819f24071e5Spatrick { 8205cfe0970Skettenis int i, unit = -1; 8215cfe0970Skettenis char *no = name + strlen(name) - 1; 8225cfe0970Skettenis 8235cfe0970Skettenis while (no >= name && *no >= '0' && *no <= '9') 8245cfe0970Skettenis unit = (unit < 0 ? 0 : (unit * 10)) + *no-- - '0'; 8255cfe0970Skettenis if (no < name || unit < 0) 8265cfe0970Skettenis return NODEV; 8275cfe0970Skettenis for (i = 0; i < ncdevs; i++) 8285cfe0970Skettenis if (strncmp(name, cdevs[i], no - name + 1) == 0) 8295cfe0970Skettenis return makedev(i, unit); 830f24071e5Spatrick return NODEV; 831f24071e5Spatrick } 832f24071e5Spatrick 833f24071e5Spatrick #define MAXDEVNAME 16 834f24071e5Spatrick 835f24071e5Spatrick /* 836f24071e5Spatrick * Parse a device spec. 837f24071e5Spatrick * 838f24071e5Spatrick * [A-Za-z]*[0-9]*[A-Za-z]:file 839f24071e5Spatrick * dev uint part 840f24071e5Spatrick */ 841f24071e5Spatrick int 842f24071e5Spatrick devparse(const char *fname, int *dev, int *unit, int *part, const char **file) 843f24071e5Spatrick { 844f24071e5Spatrick const char *s; 845f24071e5Spatrick 846f24071e5Spatrick *unit = 0; /* default to wd0a */ 847f24071e5Spatrick *part = 0; 848f24071e5Spatrick *dev = 0; 849f24071e5Spatrick 850f24071e5Spatrick s = strchr(fname, ':'); 851f24071e5Spatrick if (s != NULL) { 852f24071e5Spatrick int devlen; 853f24071e5Spatrick int i, u, p = 0; 854f24071e5Spatrick struct devsw *dp; 855f24071e5Spatrick char devname[MAXDEVNAME]; 856f24071e5Spatrick 857f24071e5Spatrick devlen = s - fname; 858f24071e5Spatrick if (devlen > MAXDEVNAME) 859f24071e5Spatrick return (EINVAL); 860f24071e5Spatrick 861f24071e5Spatrick /* extract device name */ 862f24071e5Spatrick for (i = 0; isalpha(fname[i]) && (i < devlen); i++) 863f24071e5Spatrick devname[i] = fname[i]; 864f24071e5Spatrick devname[i] = 0; 865f24071e5Spatrick 866f24071e5Spatrick if (!isdigit(fname[i])) 867f24071e5Spatrick return (EUNIT); 868f24071e5Spatrick 869f24071e5Spatrick /* device number */ 870f24071e5Spatrick for (u = 0; isdigit(fname[i]) && (i < devlen); i++) 871f24071e5Spatrick u = u * 10 + (fname[i] - '0'); 872f24071e5Spatrick 873f24071e5Spatrick if (!isalpha(fname[i])) 874f24071e5Spatrick return (EPART); 875f24071e5Spatrick 876f24071e5Spatrick /* partition number */ 877f24071e5Spatrick if (i < devlen) 878f24071e5Spatrick p = fname[i++] - 'a'; 879f24071e5Spatrick 880f24071e5Spatrick if (i != devlen) 881f24071e5Spatrick return (ENXIO); 882f24071e5Spatrick 883f24071e5Spatrick /* check device name */ 884f24071e5Spatrick for (dp = devsw, i = 0; i < ndevs; dp++, i++) { 885f24071e5Spatrick if (dp->dv_name && !strcmp(devname, dp->dv_name)) 886f24071e5Spatrick break; 887f24071e5Spatrick } 888f24071e5Spatrick 889f24071e5Spatrick if (i >= ndevs) 890f24071e5Spatrick return (ENXIO); 891f24071e5Spatrick 892f24071e5Spatrick *unit = u; 893f24071e5Spatrick *part = p; 894f24071e5Spatrick *dev = i; 895f24071e5Spatrick fname = ++s; 896f24071e5Spatrick } 897f24071e5Spatrick 898f24071e5Spatrick *file = fname; 899f24071e5Spatrick 900f24071e5Spatrick return (0); 901f24071e5Spatrick } 902f24071e5Spatrick 903f24071e5Spatrick int 904f24071e5Spatrick devopen(struct open_file *f, const char *fname, char **file) 905f24071e5Spatrick { 906f24071e5Spatrick struct devsw *dp; 907f24071e5Spatrick int dev, unit, part, error; 908f24071e5Spatrick 909f24071e5Spatrick error = devparse(fname, &dev, &unit, &part, (const char **)file); 910f24071e5Spatrick if (error) 911f24071e5Spatrick return (error); 912f24071e5Spatrick 91333e5575aSpatrick dp = &devsw[dev]; 914f24071e5Spatrick f->f_dev = dp; 915f24071e5Spatrick 916ad424d98Snaddy if (strcmp("tftp", dp->dv_name) != 0) { 917ad424d98Snaddy /* 918ad424d98Snaddy * Clear bootmac, to signal that we loaded this file from a 919ad424d98Snaddy * non-network device. 920ad424d98Snaddy */ 921ad424d98Snaddy bootmac = NULL; 922ad424d98Snaddy } 923ad424d98Snaddy 924f24071e5Spatrick return (*dp->dv_open)(f, unit, part); 925f24071e5Spatrick } 926f24071e5Spatrick 927fa854029Spatrick static void 928fa854029Spatrick efi_memprobe_internal(void) 929fa854029Spatrick { 930fa854029Spatrick EFI_STATUS status; 931fa854029Spatrick UINTN mapkey, mmsiz, siz; 932fa854029Spatrick UINT32 mmver; 933fa854029Spatrick EFI_MEMORY_DESCRIPTOR *mm; 934fa854029Spatrick int n; 935fa854029Spatrick 936fa854029Spatrick free(mmap, mmap_ndesc * mmap_descsiz); 937fa854029Spatrick 938fa854029Spatrick siz = 0; 9391f462730Skrw status = BS->GetMemoryMap(&siz, NULL, &mapkey, &mmsiz, &mmver); 940fa854029Spatrick if (status != EFI_BUFFER_TOO_SMALL) 941fa854029Spatrick panic("cannot get the size of memory map"); 942fa854029Spatrick mm = alloc(siz); 9431f462730Skrw status = BS->GetMemoryMap(&siz, mm, &mapkey, &mmsiz, &mmver); 944fa854029Spatrick if (status != EFI_SUCCESS) 945fa854029Spatrick panic("cannot get the memory map"); 946fa854029Spatrick n = siz / mmsiz; 947fa854029Spatrick mmap = mm; 948fa854029Spatrick mmap_key = mapkey; 949fa854029Spatrick mmap_ndesc = n; 950fa854029Spatrick mmap_descsiz = mmsiz; 951f4dd1aebSkettenis mmap_version = mmver; 952fa854029Spatrick } 953fa854029Spatrick 954f24071e5Spatrick /* 955f24071e5Spatrick * 64-bit ARMs can have a much wider memory mapping, as in somewhere 956f24071e5Spatrick * after the 32-bit region. To cope with our alignment requirement, 957f24071e5Spatrick * use the memory table to find a place where we can fit. 958f24071e5Spatrick */ 959f24071e5Spatrick static EFI_STATUS 960f24071e5Spatrick efi_memprobe_find(UINTN pages, UINTN align, EFI_PHYSICAL_ADDRESS *addr) 961f24071e5Spatrick { 962fa854029Spatrick EFI_MEMORY_DESCRIPTOR *mm; 963fa854029Spatrick int i, j; 964f24071e5Spatrick 965f24071e5Spatrick if (align < EFI_PAGE_SIZE) 966f24071e5Spatrick return EFI_INVALID_PARAMETER; 967f24071e5Spatrick 968fa854029Spatrick efi_memprobe_internal(); /* sync the current map */ 969f24071e5Spatrick 970fa854029Spatrick for (i = 0, mm = mmap; i < mmap_ndesc; 971fa854029Spatrick i++, mm = NextMemoryDescriptor(mm, mmap_descsiz)) { 972f24071e5Spatrick if (mm->Type != EfiConventionalMemory) 973f24071e5Spatrick continue; 974f24071e5Spatrick 975f24071e5Spatrick if (mm->NumberOfPages < pages) 976f24071e5Spatrick continue; 977f24071e5Spatrick 978f2c0e408Skettenis for (j = 0; j < mm->NumberOfPages; j++) { 979f24071e5Spatrick EFI_PHYSICAL_ADDRESS paddr; 980f24071e5Spatrick 981f24071e5Spatrick if (mm->NumberOfPages - j < pages) 982f24071e5Spatrick break; 983f24071e5Spatrick 984f24071e5Spatrick paddr = mm->PhysicalStart + (j * EFI_PAGE_SIZE); 98573dc1409Spatrick if (paddr & (align - 1)) 98673dc1409Spatrick continue; 98773dc1409Spatrick 9881f462730Skrw if (BS->AllocatePages(AllocateAddress, EfiLoaderData, 9891f462730Skrw pages, &paddr) == EFI_SUCCESS) { 990f24071e5Spatrick *addr = paddr; 991f24071e5Spatrick return EFI_SUCCESS; 992f24071e5Spatrick } 993f24071e5Spatrick } 994f24071e5Spatrick } 995f24071e5Spatrick return EFI_OUT_OF_RESOURCES; 996f24071e5Spatrick } 997111d6387Skettenis 998111d6387Skettenis /* 999111d6387Skettenis * Commands 1000111d6387Skettenis */ 1001111d6387Skettenis 1002be07ee62Skettenis int Xacpi_efi(void); 10036f83097eSpatrick int Xdtb_efi(void); 1004111d6387Skettenis int Xexit_efi(void); 1005111d6387Skettenis int Xpoweroff_efi(void); 1006111d6387Skettenis 1007111d6387Skettenis const struct cmd_table cmd_machine[] = { 1008be07ee62Skettenis { "acpi", CMDT_CMD, Xacpi_efi }, 10096f83097eSpatrick { "dtb", CMDT_CMD, Xdtb_efi }, 1010111d6387Skettenis { "exit", CMDT_CMD, Xexit_efi }, 1011111d6387Skettenis { "poweroff", CMDT_CMD, Xpoweroff_efi }, 1012111d6387Skettenis { NULL, 0 } 1013111d6387Skettenis }; 1014111d6387Skettenis 1015111d6387Skettenis int 1016be07ee62Skettenis Xacpi_efi(void) 1017be07ee62Skettenis { 1018be07ee62Skettenis acpi = 1; 1019be07ee62Skettenis return (0); 1020be07ee62Skettenis } 1021be07ee62Skettenis 1022be07ee62Skettenis int 10236f83097eSpatrick Xdtb_efi(void) 10246f83097eSpatrick { 10256f83097eSpatrick EFI_PHYSICAL_ADDRESS addr; 10266f83097eSpatrick char path[MAXPATHLEN]; 10276f83097eSpatrick struct stat sb; 10286f83097eSpatrick int fd; 10296f83097eSpatrick 1030fcf3d43cSkn if (cmd.argc != 2) { 1031fcf3d43cSkn printf("dtb file\n"); 1032fcf3d43cSkn return (0); 1033fcf3d43cSkn } 10346f83097eSpatrick 10356f83097eSpatrick snprintf(path, sizeof(path), "%s:%s", cmd.bootdev, cmd.argv[1]); 10366f83097eSpatrick 10376f83097eSpatrick fd = open(path, O_RDONLY); 10386f83097eSpatrick if (fd < 0 || fstat(fd, &sb) == -1) { 10396f83097eSpatrick printf("cannot open %s\n", path); 1040fcf3d43cSkn return (0); 10416f83097eSpatrick } 10426f83097eSpatrick if (efi_memprobe_find(EFI_SIZE_TO_PAGES(sb.st_size), 10436f83097eSpatrick 0x1000, &addr) != EFI_SUCCESS) { 10446f83097eSpatrick printf("cannot allocate memory for %s\n", path); 1045fcf3d43cSkn return (0); 10466f83097eSpatrick } 10476f83097eSpatrick if (read(fd, (void *)addr, sb.st_size) != sb.st_size) { 10486f83097eSpatrick printf("cannot read from %s\n", path); 1049fcf3d43cSkn return (0); 10506f83097eSpatrick } 10516f83097eSpatrick 10526f83097eSpatrick fdt = (void *)addr; 10536f83097eSpatrick return (0); 10546f83097eSpatrick } 10556f83097eSpatrick 10566f83097eSpatrick int 1057111d6387Skettenis Xexit_efi(void) 1058111d6387Skettenis { 10591f462730Skrw BS->Exit(IH, 0, 0, NULL); 1060111d6387Skettenis for (;;) 1061111d6387Skettenis continue; 1062111d6387Skettenis return (0); 1063111d6387Skettenis } 1064111d6387Skettenis 1065111d6387Skettenis int 1066111d6387Skettenis Xpoweroff_efi(void) 1067111d6387Skettenis { 10681f462730Skrw RS->ResetSystem(EfiResetShutdown, EFI_SUCCESS, 0, NULL); 1069111d6387Skettenis return (0); 1070111d6387Skettenis } 1071