1*111d6387Skettenis /* $OpenBSD: efiboot.c,v 1.11 2017/08/07 19:34:53 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> 22f24071e5Spatrick #include <dev/cons.h> 23f24071e5Spatrick #include <sys/disklabel.h> 24f24071e5Spatrick 25f24071e5Spatrick #include <efi.h> 26f24071e5Spatrick #include <efiapi.h> 27f24071e5Spatrick #include <efiprot.h> 28f24071e5Spatrick #include <eficonsctl.h> 29f24071e5Spatrick 30f24071e5Spatrick #include <lib/libkern/libkern.h> 31f24071e5Spatrick #include <stand/boot/cmd.h> 32f24071e5Spatrick 33f24071e5Spatrick #include "disk.h" 34f24071e5Spatrick #include "eficall.h" 35f24071e5Spatrick #include "fdt.h" 36f24071e5Spatrick #include "libsa.h" 37f24071e5Spatrick 38f24071e5Spatrick EFI_SYSTEM_TABLE *ST; 39f24071e5Spatrick EFI_BOOT_SERVICES *BS; 40f24071e5Spatrick EFI_RUNTIME_SERVICES *RS; 41fa854029Spatrick EFI_HANDLE IH, efi_bootdp = NULL; 42f24071e5Spatrick 43fa854029Spatrick EFI_PHYSICAL_ADDRESS heap; 44fa854029Spatrick UINTN heapsiz = 1 * 1024 * 1024; 45fa854029Spatrick EFI_MEMORY_DESCRIPTOR *mmap = NULL; 46fa854029Spatrick UINTN mmap_key; 47fa854029Spatrick UINTN mmap_ndesc; 48fa854029Spatrick UINTN mmap_descsiz; 49f4dd1aebSkettenis UINT32 mmap_version; 50f24071e5Spatrick 51f24071e5Spatrick static EFI_GUID imgp_guid = LOADED_IMAGE_PROTOCOL; 52f24071e5Spatrick static EFI_GUID blkio_guid = BLOCK_IO_PROTOCOL; 53f24071e5Spatrick static EFI_GUID devp_guid = DEVICE_PATH_PROTOCOL; 54f24071e5Spatrick 55c6d7d0adSpatrick static int efi_device_path_depth(EFI_DEVICE_PATH *dp, int); 56c6d7d0adSpatrick static int efi_device_path_ncmp(EFI_DEVICE_PATH *, EFI_DEVICE_PATH *, int); 57fa854029Spatrick static void efi_heap_init(void); 58fa854029Spatrick static void efi_memprobe_internal(void); 59f24071e5Spatrick static void efi_timer_init(void); 60f24071e5Spatrick static void efi_timer_cleanup(void); 61f24071e5Spatrick static EFI_STATUS efi_memprobe_find(UINTN, UINTN, EFI_PHYSICAL_ADDRESS *); 62f24071e5Spatrick 63f24071e5Spatrick EFI_STATUS 64f24071e5Spatrick efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab) 65f24071e5Spatrick { 66f24071e5Spatrick extern char *progname; 67f24071e5Spatrick EFI_LOADED_IMAGE *imgp; 68f24071e5Spatrick EFI_DEVICE_PATH *dp = NULL; 69f24071e5Spatrick EFI_STATUS status; 70f24071e5Spatrick 71f24071e5Spatrick ST = systab; 72f24071e5Spatrick BS = ST->BootServices; 73f24071e5Spatrick IH = image; 74f24071e5Spatrick 75f24071e5Spatrick status = EFI_CALL(BS->HandleProtocol, image, &imgp_guid, 76f24071e5Spatrick (void **)&imgp); 77f24071e5Spatrick if (status == EFI_SUCCESS) 78f24071e5Spatrick status = EFI_CALL(BS->HandleProtocol, imgp->DeviceHandle, 79f24071e5Spatrick &devp_guid, (void **)&dp); 80f24071e5Spatrick if (status == EFI_SUCCESS) 81f24071e5Spatrick efi_bootdp = dp; 82f24071e5Spatrick 83f24071e5Spatrick progname = "BOOTAA64"; 84f24071e5Spatrick 85f24071e5Spatrick boot(0); 86f24071e5Spatrick 87f24071e5Spatrick return (EFI_SUCCESS); 88f24071e5Spatrick } 89f24071e5Spatrick 90f24071e5Spatrick static SIMPLE_TEXT_OUTPUT_INTERFACE *conout; 91f24071e5Spatrick static SIMPLE_INPUT_INTERFACE *conin; 92f24071e5Spatrick 93f24071e5Spatrick void 94f24071e5Spatrick efi_cons_probe(struct consdev *cn) 95f24071e5Spatrick { 96f24071e5Spatrick cn->cn_pri = CN_MIDPRI; 97f24071e5Spatrick cn->cn_dev = makedev(12, 0); 98f24071e5Spatrick } 99f24071e5Spatrick 100f24071e5Spatrick void 101f24071e5Spatrick efi_cons_init(struct consdev *cp) 102f24071e5Spatrick { 103f24071e5Spatrick conin = ST->ConIn; 104f24071e5Spatrick conout = ST->ConOut; 105f24071e5Spatrick } 106f24071e5Spatrick 107f24071e5Spatrick int 108f24071e5Spatrick efi_cons_getc(dev_t dev) 109f24071e5Spatrick { 110f24071e5Spatrick EFI_INPUT_KEY key; 111f24071e5Spatrick EFI_STATUS status; 112f24071e5Spatrick #if 0 113f24071e5Spatrick UINTN dummy; 114f24071e5Spatrick #endif 115f24071e5Spatrick static int lastchar = 0; 116f24071e5Spatrick 117f24071e5Spatrick if (lastchar) { 118f24071e5Spatrick int r = lastchar; 119f24071e5Spatrick if ((dev & 0x80) == 0) 120f24071e5Spatrick lastchar = 0; 121f24071e5Spatrick return (r); 122f24071e5Spatrick } 123f24071e5Spatrick 124f24071e5Spatrick status = conin->ReadKeyStroke(conin, &key); 125f24071e5Spatrick while (status == EFI_NOT_READY) { 126f24071e5Spatrick if (dev & 0x80) 127f24071e5Spatrick return (0); 128f24071e5Spatrick /* 129f24071e5Spatrick * XXX The implementation of WaitForEvent() in U-boot 130f24071e5Spatrick * is broken and neverreturns. 131f24071e5Spatrick */ 132f24071e5Spatrick #if 0 133f24071e5Spatrick BS->WaitForEvent(1, &conin->WaitForKey, &dummy); 134f24071e5Spatrick #endif 135f24071e5Spatrick status = conin->ReadKeyStroke(conin, &key); 136f24071e5Spatrick } 137f24071e5Spatrick 138f24071e5Spatrick if (dev & 0x80) 139f24071e5Spatrick lastchar = key.UnicodeChar; 140f24071e5Spatrick 141f24071e5Spatrick return (key.UnicodeChar); 142f24071e5Spatrick } 143f24071e5Spatrick 144f24071e5Spatrick void 145f24071e5Spatrick efi_cons_putc(dev_t dev, int c) 146f24071e5Spatrick { 147f24071e5Spatrick CHAR16 buf[2]; 148f24071e5Spatrick 149f24071e5Spatrick if (c == '\n') 150f24071e5Spatrick efi_cons_putc(dev, '\r'); 151f24071e5Spatrick 152f24071e5Spatrick buf[0] = c; 153f24071e5Spatrick buf[1] = 0; 154f24071e5Spatrick 155f24071e5Spatrick conout->OutputString(conout, buf); 156f24071e5Spatrick } 157f24071e5Spatrick 158f24071e5Spatrick static void 159f24071e5Spatrick efi_heap_init(void) 160f24071e5Spatrick { 161f24071e5Spatrick EFI_STATUS status; 162f24071e5Spatrick 163f24071e5Spatrick status = EFI_CALL(BS->AllocatePages, AllocateAnyPages, EfiLoaderData, 164f24071e5Spatrick EFI_SIZE_TO_PAGES(heapsiz), &heap); 165f24071e5Spatrick if (status != EFI_SUCCESS) 166f24071e5Spatrick panic("BS->AllocatePages()"); 167f24071e5Spatrick } 168f24071e5Spatrick 169f24071e5Spatrick EFI_BLOCK_IO *disk; 170f24071e5Spatrick 171f24071e5Spatrick void 172f24071e5Spatrick efi_diskprobe(void) 173f24071e5Spatrick { 174c6d7d0adSpatrick int i, depth = -1; 175f24071e5Spatrick UINTN sz; 176f24071e5Spatrick EFI_STATUS status; 177f24071e5Spatrick EFI_HANDLE *handles = NULL; 178f24071e5Spatrick EFI_BLOCK_IO *blkio; 179f24071e5Spatrick EFI_BLOCK_IO_MEDIA *media; 180c6d7d0adSpatrick EFI_DEVICE_PATH *dp; 181f24071e5Spatrick 182f24071e5Spatrick sz = 0; 183f24071e5Spatrick status = EFI_CALL(BS->LocateHandle, ByProtocol, &blkio_guid, 0, &sz, 0); 184f24071e5Spatrick if (status == EFI_BUFFER_TOO_SMALL) { 185f24071e5Spatrick handles = alloc(sz); 186f24071e5Spatrick status = EFI_CALL(BS->LocateHandle, ByProtocol, &blkio_guid, 187f24071e5Spatrick 0, &sz, handles); 188f24071e5Spatrick } 189f24071e5Spatrick if (handles == NULL || EFI_ERROR(status)) 190f24071e5Spatrick panic("BS->LocateHandle() returns %d", status); 191f24071e5Spatrick 192c6d7d0adSpatrick if (efi_bootdp != NULL) 193c6d7d0adSpatrick depth = efi_device_path_depth(efi_bootdp, MEDIA_DEVICE_PATH); 194c6d7d0adSpatrick 195c94e7257Skettenis /* 196c94e7257Skettenis * U-Boot incorrectly represents devices with a single 197c94e7257Skettenis * MEDIA_DEVICE_PATH component. In that case include that 198c94e7257Skettenis * component into the matching, otherwise we'll blindly select 199c94e7257Skettenis * the first device. 200c94e7257Skettenis */ 201c94e7257Skettenis if (depth == 0) 202c94e7257Skettenis depth = 1; 203c94e7257Skettenis 204f24071e5Spatrick for (i = 0; i < sz / sizeof(EFI_HANDLE); i++) { 205f24071e5Spatrick status = EFI_CALL(BS->HandleProtocol, handles[i], &blkio_guid, 206f24071e5Spatrick (void **)&blkio); 207f24071e5Spatrick if (EFI_ERROR(status)) 208f24071e5Spatrick panic("BS->HandleProtocol() returns %d", status); 209f24071e5Spatrick 210f24071e5Spatrick media = blkio->Media; 211f24071e5Spatrick if (media->LogicalPartition || !media->MediaPresent) 212f24071e5Spatrick continue; 213f24071e5Spatrick 214c6d7d0adSpatrick if (efi_bootdp == NULL || depth == -1) 215c6d7d0adSpatrick continue; 216f24071e5Spatrick status = EFI_CALL(BS->HandleProtocol, handles[i], &devp_guid, 217f24071e5Spatrick (void **)&dp); 218f24071e5Spatrick if (EFI_ERROR(status)) 219c6d7d0adSpatrick continue; 220c6d7d0adSpatrick if (efi_device_path_ncmp(efi_bootdp, dp, depth) == 0) { 221f24071e5Spatrick disk = blkio; 222f24071e5Spatrick break; 223f24071e5Spatrick } 224f24071e5Spatrick } 225f24071e5Spatrick 226f24071e5Spatrick free(handles, sz); 227f24071e5Spatrick } 228f24071e5Spatrick 229c94e7257Skettenis /* 230c94e7257Skettenis * Determine the number of nodes up to, but not including, the first 231c94e7257Skettenis * node of the specified type. 232c94e7257Skettenis */ 233c6d7d0adSpatrick static int 234c6d7d0adSpatrick efi_device_path_depth(EFI_DEVICE_PATH *dp, int dptype) 235c6d7d0adSpatrick { 236c6d7d0adSpatrick int i; 237c6d7d0adSpatrick 238c6d7d0adSpatrick for (i = 0; !IsDevicePathEnd(dp); dp = NextDevicePathNode(dp), i++) { 239c6d7d0adSpatrick if (DevicePathType(dp) == dptype) 240c94e7257Skettenis return (i); 241c6d7d0adSpatrick } 242c6d7d0adSpatrick 243c6d7d0adSpatrick return (-1); 244c6d7d0adSpatrick } 245c6d7d0adSpatrick 246c6d7d0adSpatrick static int 247c6d7d0adSpatrick efi_device_path_ncmp(EFI_DEVICE_PATH *dpa, EFI_DEVICE_PATH *dpb, int deptn) 248c6d7d0adSpatrick { 249c6d7d0adSpatrick int i, cmp; 250c6d7d0adSpatrick 251c6d7d0adSpatrick for (i = 0; i < deptn; i++) { 252c6d7d0adSpatrick if (IsDevicePathEnd(dpa) || IsDevicePathEnd(dpb)) 253c6d7d0adSpatrick return ((IsDevicePathEnd(dpa) && IsDevicePathEnd(dpb)) 254c6d7d0adSpatrick ? 0 : (IsDevicePathEnd(dpa))? -1 : 1); 255c6d7d0adSpatrick cmp = DevicePathNodeLength(dpa) - DevicePathNodeLength(dpb); 256c6d7d0adSpatrick if (cmp) 257c6d7d0adSpatrick return (cmp); 258c6d7d0adSpatrick cmp = memcmp(dpa, dpb, DevicePathNodeLength(dpa)); 259c6d7d0adSpatrick if (cmp) 260c6d7d0adSpatrick return (cmp); 261c6d7d0adSpatrick dpa = NextDevicePathNode(dpa); 262c6d7d0adSpatrick dpb = NextDevicePathNode(dpb); 263c6d7d0adSpatrick } 264c6d7d0adSpatrick 265c6d7d0adSpatrick return (0); 266c6d7d0adSpatrick } 267c6d7d0adSpatrick 268f24071e5Spatrick static EFI_GUID fdt_guid = FDT_TABLE_GUID; 269f24071e5Spatrick 270f24071e5Spatrick #define efi_guidcmp(_a, _b) memcmp((_a), (_b), sizeof(EFI_GUID)) 271f24071e5Spatrick 272f24071e5Spatrick void * 273f24071e5Spatrick efi_makebootargs(char *bootargs) 274f24071e5Spatrick { 275f24071e5Spatrick void *fdt = NULL; 276f4dd1aebSkettenis u_char bootduid[8]; 277f4dd1aebSkettenis u_char zero[8] = { 0 }; 278f4dd1aebSkettenis uint64_t uefi_system_table = htobe64((uintptr_t)ST); 279f24071e5Spatrick void *node; 280f24071e5Spatrick size_t len; 281f24071e5Spatrick int i; 282f24071e5Spatrick 283f24071e5Spatrick for (i = 0; i < ST->NumberOfTableEntries; i++) { 284f24071e5Spatrick if (efi_guidcmp(&fdt_guid, 285f24071e5Spatrick &ST->ConfigurationTable[i].VendorGuid) == 0) 286f24071e5Spatrick fdt = ST->ConfigurationTable[i].VendorTable; 287f24071e5Spatrick } 288f24071e5Spatrick 289f24071e5Spatrick if (!fdt_init(fdt)) 290f24071e5Spatrick return NULL; 291f24071e5Spatrick 292f24071e5Spatrick node = fdt_find_node("/chosen"); 293f24071e5Spatrick if (!node) 294f24071e5Spatrick return NULL; 295f24071e5Spatrick 296f24071e5Spatrick len = strlen(bootargs) + 1; 297f24071e5Spatrick fdt_node_add_property(node, "bootargs", bootargs, len); 298f24071e5Spatrick 299f24071e5Spatrick /* Pass DUID of the boot disk. */ 300f24071e5Spatrick memcpy(&bootduid, diskinfo.disklabel.d_uid, sizeof(bootduid)); 301f24071e5Spatrick if (memcmp(bootduid, zero, sizeof(bootduid)) != 0) { 302f24071e5Spatrick fdt_node_add_property(node, "openbsd,bootduid", bootduid, 303f24071e5Spatrick sizeof(bootduid)); 304f24071e5Spatrick } 305f24071e5Spatrick 306f4dd1aebSkettenis /* Pass EFI system table. */ 307f4dd1aebSkettenis fdt_node_add_property(node, "openbsd,uefi-system-table", 308f4dd1aebSkettenis &uefi_system_table, sizeof(uefi_system_table)); 309f4dd1aebSkettenis 310f4dd1aebSkettenis /* Placeholders for EFI memory map. */ 311f4dd1aebSkettenis fdt_node_add_property(node, "openbsd,uefi-mmap-start", zero, 8); 312f4dd1aebSkettenis fdt_node_add_property(node, "openbsd,uefi-mmap-size", zero, 4); 313f4dd1aebSkettenis fdt_node_add_property(node, "openbsd,uefi-mmap-desc-size", zero, 4); 314f4dd1aebSkettenis fdt_node_add_property(node, "openbsd,uefi-mmap-desc-ver", zero, 4); 315f4dd1aebSkettenis 316f24071e5Spatrick fdt_finalize(); 317f24071e5Spatrick 318f24071e5Spatrick return fdt; 319f24071e5Spatrick } 320f24071e5Spatrick 321f4dd1aebSkettenis void 322f4dd1aebSkettenis efi_updatefdt(void) 323f4dd1aebSkettenis { 324f4dd1aebSkettenis uint64_t uefi_mmap_start = htobe64((uintptr_t)mmap); 325f4dd1aebSkettenis uint32_t uefi_mmap_size = htobe32(mmap_ndesc * mmap_descsiz); 326f4dd1aebSkettenis uint32_t uefi_mmap_desc_size = htobe32(mmap_descsiz); 327f4dd1aebSkettenis uint32_t uefi_mmap_desc_ver = htobe32(mmap_version); 328f4dd1aebSkettenis void *node; 329f4dd1aebSkettenis 330f4dd1aebSkettenis node = fdt_find_node("/chosen"); 331f4dd1aebSkettenis if (!node) 332f4dd1aebSkettenis return; 333f4dd1aebSkettenis 334f4dd1aebSkettenis /* Pass EFI memory map. */ 335f4dd1aebSkettenis fdt_node_set_property(node, "openbsd,uefi-mmap-start", 336f4dd1aebSkettenis &uefi_mmap_start, sizeof(uefi_mmap_start)); 337f4dd1aebSkettenis fdt_node_set_property(node, "openbsd,uefi-mmap-size", 338f4dd1aebSkettenis &uefi_mmap_size, sizeof(uefi_mmap_size)); 339f4dd1aebSkettenis fdt_node_set_property(node, "openbsd,uefi-mmap-desc-size", 340f4dd1aebSkettenis &uefi_mmap_desc_size, sizeof(uefi_mmap_desc_size)); 341f4dd1aebSkettenis fdt_node_set_property(node, "openbsd,uefi-mmap-desc-ver", 342f4dd1aebSkettenis &uefi_mmap_desc_ver, sizeof(uefi_mmap_desc_ver)); 343f4dd1aebSkettenis 344f4dd1aebSkettenis fdt_finalize(); 345f4dd1aebSkettenis } 346f4dd1aebSkettenis 347f24071e5Spatrick u_long efi_loadaddr; 348f24071e5Spatrick 349f24071e5Spatrick void 350f24071e5Spatrick machdep(void) 351f24071e5Spatrick { 352f24071e5Spatrick EFI_PHYSICAL_ADDRESS addr; 353f24071e5Spatrick 354f24071e5Spatrick cninit(); 355f24071e5Spatrick efi_heap_init(); 356f24071e5Spatrick 357f24071e5Spatrick /* 3589a118d7eSpatrick * The kernel expects to be loaded into a block of memory aligned 3599a118d7eSpatrick * on a 2MB boundary. We allocate a block of 64MB of memory, which 3609a118d7eSpatrick * gives us plenty of room for growth. 361f24071e5Spatrick */ 3629a118d7eSpatrick if (efi_memprobe_find(EFI_SIZE_TO_PAGES(64 * 1024 * 1024), 3639a118d7eSpatrick 0x200000, &addr) != EFI_SUCCESS) 364f24071e5Spatrick printf("Can't allocate memory\n"); 365f24071e5Spatrick efi_loadaddr = addr; 366f24071e5Spatrick 367f24071e5Spatrick efi_timer_init(); 368f24071e5Spatrick efi_diskprobe(); 369f24071e5Spatrick } 370f24071e5Spatrick 371f24071e5Spatrick void 372f24071e5Spatrick efi_cleanup(void) 373f24071e5Spatrick { 374fa854029Spatrick int retry; 375fa854029Spatrick EFI_STATUS status; 376fa854029Spatrick 377f24071e5Spatrick efi_timer_cleanup(); 378f24071e5Spatrick 379fa854029Spatrick /* retry once in case of failure */ 380fa854029Spatrick for (retry = 1; retry >= 0; retry--) { 381fa854029Spatrick efi_memprobe_internal(); /* sync the current map */ 382f4dd1aebSkettenis efi_updatefdt(); 383fa854029Spatrick status = EFI_CALL(BS->ExitBootServices, IH, mmap_key); 384fa854029Spatrick if (status == EFI_SUCCESS) 385fa854029Spatrick break; 386fa854029Spatrick if (retry == 0) 387fa854029Spatrick panic("ExitBootServices failed (%d)", status); 388fa854029Spatrick } 389f24071e5Spatrick } 390f24071e5Spatrick 391f24071e5Spatrick void 392f24071e5Spatrick _rtt(void) 393f24071e5Spatrick { 394f24071e5Spatrick #ifdef EFI_DEBUG 395f24071e5Spatrick printf("Hit any key to reboot\n"); 396f24071e5Spatrick efi_cons_getc(0); 397f24071e5Spatrick #endif 398f24071e5Spatrick RS->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL); 399*111d6387Skettenis for (;;) 400*111d6387Skettenis continue; 401f24071e5Spatrick } 402f24071e5Spatrick 403f24071e5Spatrick /* 404f24071e5Spatrick * U-Boot only implements the GetTime() Runtime Service if it has been 405f24071e5Spatrick * configured with CONFIG_DM_RTC. Most board configurations don't 406f24071e5Spatrick * include that option, so we can't use it to implement our boot 407f24071e5Spatrick * prompt timeout. Instead we use timer events to simulate a clock 408f24071e5Spatrick * that ticks ever second. 409f24071e5Spatrick */ 410f24071e5Spatrick 411f24071e5Spatrick EFI_EVENT timer; 412f24071e5Spatrick int ticks; 413f24071e5Spatrick 414f24071e5Spatrick static VOID 415f24071e5Spatrick efi_timer(EFI_EVENT event, VOID *context) 416f24071e5Spatrick { 417f24071e5Spatrick ticks++; 418f24071e5Spatrick } 419f24071e5Spatrick 420f24071e5Spatrick static void 421f24071e5Spatrick efi_timer_init(void) 422f24071e5Spatrick { 423f24071e5Spatrick EFI_STATUS status; 424f24071e5Spatrick 425a4d88df4Sjsg status = BS->CreateEvent(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, 426f24071e5Spatrick efi_timer, NULL, &timer); 427f24071e5Spatrick if (status == EFI_SUCCESS) 428f24071e5Spatrick status = BS->SetTimer(timer, TimerPeriodic, 10000000); 429f24071e5Spatrick if (EFI_ERROR(status)) 430f24071e5Spatrick printf("Can't create timer\n"); 431f24071e5Spatrick } 432f24071e5Spatrick 433f24071e5Spatrick static void 434f24071e5Spatrick efi_timer_cleanup(void) 435f24071e5Spatrick { 436f24071e5Spatrick BS->CloseEvent(timer); 437f24071e5Spatrick } 438f24071e5Spatrick 439f24071e5Spatrick time_t 440f24071e5Spatrick getsecs(void) 441f24071e5Spatrick { 442f24071e5Spatrick return ticks; 443f24071e5Spatrick } 444f24071e5Spatrick 445f24071e5Spatrick /* 446f24071e5Spatrick * Various device-related bits. 447f24071e5Spatrick */ 448f24071e5Spatrick 449f24071e5Spatrick void 450f24071e5Spatrick devboot(dev_t dev, char *p) 451f24071e5Spatrick { 452f24071e5Spatrick strlcpy(p, "sd0a", 5); 453f24071e5Spatrick } 454f24071e5Spatrick 455f24071e5Spatrick int 456f24071e5Spatrick cnspeed(dev_t dev, int sp) 457f24071e5Spatrick { 458f24071e5Spatrick return 115200; 459f24071e5Spatrick } 460f24071e5Spatrick 461f24071e5Spatrick char * 462f24071e5Spatrick ttyname(int fd) 463f24071e5Spatrick { 464f24071e5Spatrick return "com0"; 465f24071e5Spatrick } 466f24071e5Spatrick 467f24071e5Spatrick dev_t 468f24071e5Spatrick ttydev(char *name) 469f24071e5Spatrick { 470f24071e5Spatrick return NODEV; 471f24071e5Spatrick } 472f24071e5Spatrick 473f24071e5Spatrick #define MAXDEVNAME 16 474f24071e5Spatrick 475f24071e5Spatrick /* 476f24071e5Spatrick * Parse a device spec. 477f24071e5Spatrick * 478f24071e5Spatrick * [A-Za-z]*[0-9]*[A-Za-z]:file 479f24071e5Spatrick * dev uint part 480f24071e5Spatrick */ 481f24071e5Spatrick int 482f24071e5Spatrick devparse(const char *fname, int *dev, int *unit, int *part, const char **file) 483f24071e5Spatrick { 484f24071e5Spatrick const char *s; 485f24071e5Spatrick 486f24071e5Spatrick *unit = 0; /* default to wd0a */ 487f24071e5Spatrick *part = 0; 488f24071e5Spatrick *dev = 0; 489f24071e5Spatrick 490f24071e5Spatrick s = strchr(fname, ':'); 491f24071e5Spatrick if (s != NULL) { 492f24071e5Spatrick int devlen; 493f24071e5Spatrick int i, u, p = 0; 494f24071e5Spatrick struct devsw *dp; 495f24071e5Spatrick char devname[MAXDEVNAME]; 496f24071e5Spatrick 497f24071e5Spatrick devlen = s - fname; 498f24071e5Spatrick if (devlen > MAXDEVNAME) 499f24071e5Spatrick return (EINVAL); 500f24071e5Spatrick 501f24071e5Spatrick /* extract device name */ 502f24071e5Spatrick for (i = 0; isalpha(fname[i]) && (i < devlen); i++) 503f24071e5Spatrick devname[i] = fname[i]; 504f24071e5Spatrick devname[i] = 0; 505f24071e5Spatrick 506f24071e5Spatrick if (!isdigit(fname[i])) 507f24071e5Spatrick return (EUNIT); 508f24071e5Spatrick 509f24071e5Spatrick /* device number */ 510f24071e5Spatrick for (u = 0; isdigit(fname[i]) && (i < devlen); i++) 511f24071e5Spatrick u = u * 10 + (fname[i] - '0'); 512f24071e5Spatrick 513f24071e5Spatrick if (!isalpha(fname[i])) 514f24071e5Spatrick return (EPART); 515f24071e5Spatrick 516f24071e5Spatrick /* partition number */ 517f24071e5Spatrick if (i < devlen) 518f24071e5Spatrick p = fname[i++] - 'a'; 519f24071e5Spatrick 520f24071e5Spatrick if (i != devlen) 521f24071e5Spatrick return (ENXIO); 522f24071e5Spatrick 523f24071e5Spatrick /* check device name */ 524f24071e5Spatrick for (dp = devsw, i = 0; i < ndevs; dp++, i++) { 525f24071e5Spatrick if (dp->dv_name && !strcmp(devname, dp->dv_name)) 526f24071e5Spatrick break; 527f24071e5Spatrick } 528f24071e5Spatrick 529f24071e5Spatrick if (i >= ndevs) 530f24071e5Spatrick return (ENXIO); 531f24071e5Spatrick 532f24071e5Spatrick *unit = u; 533f24071e5Spatrick *part = p; 534f24071e5Spatrick *dev = i; 535f24071e5Spatrick fname = ++s; 536f24071e5Spatrick } 537f24071e5Spatrick 538f24071e5Spatrick *file = fname; 539f24071e5Spatrick 540f24071e5Spatrick return (0); 541f24071e5Spatrick } 542f24071e5Spatrick 543f24071e5Spatrick int 544f24071e5Spatrick devopen(struct open_file *f, const char *fname, char **file) 545f24071e5Spatrick { 546f24071e5Spatrick struct devsw *dp; 547f24071e5Spatrick int dev, unit, part, error; 548f24071e5Spatrick 549f24071e5Spatrick error = devparse(fname, &dev, &unit, &part, (const char **)file); 550f24071e5Spatrick if (error) 551f24071e5Spatrick return (error); 552f24071e5Spatrick 553f24071e5Spatrick dp = &devsw[0]; 554f24071e5Spatrick f->f_dev = dp; 555f24071e5Spatrick 556f24071e5Spatrick return (*dp->dv_open)(f, unit, part); 557f24071e5Spatrick } 558f24071e5Spatrick 559fa854029Spatrick static void 560fa854029Spatrick efi_memprobe_internal(void) 561fa854029Spatrick { 562fa854029Spatrick EFI_STATUS status; 563fa854029Spatrick UINTN mapkey, mmsiz, siz; 564fa854029Spatrick UINT32 mmver; 565fa854029Spatrick EFI_MEMORY_DESCRIPTOR *mm; 566fa854029Spatrick int n; 567fa854029Spatrick 568fa854029Spatrick free(mmap, mmap_ndesc * mmap_descsiz); 569fa854029Spatrick 570fa854029Spatrick siz = 0; 571fa854029Spatrick status = EFI_CALL(BS->GetMemoryMap, &siz, NULL, &mapkey, &mmsiz, 572fa854029Spatrick &mmver); 573fa854029Spatrick if (status != EFI_BUFFER_TOO_SMALL) 574fa854029Spatrick panic("cannot get the size of memory map"); 575fa854029Spatrick mm = alloc(siz); 576fa854029Spatrick status = EFI_CALL(BS->GetMemoryMap, &siz, mm, &mapkey, &mmsiz, &mmver); 577fa854029Spatrick if (status != EFI_SUCCESS) 578fa854029Spatrick panic("cannot get the memory map"); 579fa854029Spatrick n = siz / mmsiz; 580fa854029Spatrick mmap = mm; 581fa854029Spatrick mmap_key = mapkey; 582fa854029Spatrick mmap_ndesc = n; 583fa854029Spatrick mmap_descsiz = mmsiz; 584f4dd1aebSkettenis mmap_version = mmver; 585fa854029Spatrick } 586fa854029Spatrick 587f24071e5Spatrick /* 588f24071e5Spatrick * 64-bit ARMs can have a much wider memory mapping, as in somewhere 589f24071e5Spatrick * after the 32-bit region. To cope with our alignment requirement, 590f24071e5Spatrick * use the memory table to find a place where we can fit. 591f24071e5Spatrick */ 592f24071e5Spatrick static EFI_STATUS 593f24071e5Spatrick efi_memprobe_find(UINTN pages, UINTN align, EFI_PHYSICAL_ADDRESS *addr) 594f24071e5Spatrick { 595fa854029Spatrick EFI_MEMORY_DESCRIPTOR *mm; 596fa854029Spatrick int i, j; 597f24071e5Spatrick 598f24071e5Spatrick if (align < EFI_PAGE_SIZE) 599f24071e5Spatrick return EFI_INVALID_PARAMETER; 600f24071e5Spatrick 601fa854029Spatrick efi_memprobe_internal(); /* sync the current map */ 602f24071e5Spatrick 603fa854029Spatrick for (i = 0, mm = mmap; i < mmap_ndesc; 604fa854029Spatrick i++, mm = NextMemoryDescriptor(mm, mmap_descsiz)) { 605f24071e5Spatrick if (mm->Type != EfiConventionalMemory) 606f24071e5Spatrick continue; 607f24071e5Spatrick 608f24071e5Spatrick if (mm->NumberOfPages < pages) 609f24071e5Spatrick continue; 610f24071e5Spatrick 611f2c0e408Skettenis for (j = 0; j < mm->NumberOfPages; j++) { 612f24071e5Spatrick EFI_PHYSICAL_ADDRESS paddr; 613f24071e5Spatrick 614f24071e5Spatrick if (mm->NumberOfPages - j < pages) 615f24071e5Spatrick break; 616f24071e5Spatrick 617f24071e5Spatrick paddr = mm->PhysicalStart + (j * EFI_PAGE_SIZE); 61873dc1409Spatrick if (paddr & (align - 1)) 61973dc1409Spatrick continue; 62073dc1409Spatrick 62173dc1409Spatrick if (EFI_CALL(BS->AllocatePages, AllocateAddress, 62273dc1409Spatrick EfiLoaderData, pages, &paddr) == EFI_SUCCESS) { 623f24071e5Spatrick *addr = paddr; 624f24071e5Spatrick return EFI_SUCCESS; 625f24071e5Spatrick } 626f24071e5Spatrick } 627f24071e5Spatrick } 628f24071e5Spatrick return EFI_OUT_OF_RESOURCES; 629f24071e5Spatrick } 630*111d6387Skettenis 631*111d6387Skettenis /* 632*111d6387Skettenis * Commands 633*111d6387Skettenis */ 634*111d6387Skettenis 635*111d6387Skettenis int Xexit_efi(void); 636*111d6387Skettenis int Xpoweroff_efi(void); 637*111d6387Skettenis 638*111d6387Skettenis const struct cmd_table cmd_machine[] = { 639*111d6387Skettenis { "exit", CMDT_CMD, Xexit_efi }, 640*111d6387Skettenis { "poweroff", CMDT_CMD, Xpoweroff_efi }, 641*111d6387Skettenis { NULL, 0 } 642*111d6387Skettenis }; 643*111d6387Skettenis 644*111d6387Skettenis int 645*111d6387Skettenis Xexit_efi(void) 646*111d6387Skettenis { 647*111d6387Skettenis EFI_CALL(BS->Exit, IH, 0, 0, NULL); 648*111d6387Skettenis for (;;) 649*111d6387Skettenis continue; 650*111d6387Skettenis return (0); 651*111d6387Skettenis } 652*111d6387Skettenis 653*111d6387Skettenis int 654*111d6387Skettenis Xpoweroff_efi(void) 655*111d6387Skettenis { 656*111d6387Skettenis EFI_CALL(RS->ResetSystem, EfiResetShutdown, EFI_SUCCESS, 0, NULL); 657*111d6387Skettenis return (0); 658*111d6387Skettenis } 659