1*73dc1409Spatrick /* $OpenBSD: efiboot.c,v 1.3 2017/02/03 08:48:40 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> 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; 41f24071e5Spatrick EFI_HANDLE IH; 42f24071e5Spatrick 43f24071e5Spatrick EFI_HANDLE efi_bootdp; 44f24071e5Spatrick 45f24071e5Spatrick static EFI_GUID imgp_guid = LOADED_IMAGE_PROTOCOL; 46f24071e5Spatrick static EFI_GUID blkio_guid = BLOCK_IO_PROTOCOL; 47f24071e5Spatrick static EFI_GUID devp_guid = DEVICE_PATH_PROTOCOL; 48f24071e5Spatrick 49f24071e5Spatrick static void efi_timer_init(void); 50f24071e5Spatrick static void efi_timer_cleanup(void); 51f24071e5Spatrick static EFI_STATUS efi_memprobe_find(UINTN, UINTN, EFI_PHYSICAL_ADDRESS *); 52f24071e5Spatrick 53f24071e5Spatrick EFI_STATUS 54f24071e5Spatrick efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab) 55f24071e5Spatrick { 56f24071e5Spatrick extern char *progname; 57f24071e5Spatrick EFI_LOADED_IMAGE *imgp; 58f24071e5Spatrick EFI_DEVICE_PATH *dp = NULL; 59f24071e5Spatrick EFI_STATUS status; 60f24071e5Spatrick 61f24071e5Spatrick ST = systab; 62f24071e5Spatrick BS = ST->BootServices; 63f24071e5Spatrick IH = image; 64f24071e5Spatrick 65f24071e5Spatrick status = EFI_CALL(BS->HandleProtocol, image, &imgp_guid, 66f24071e5Spatrick (void **)&imgp); 67f24071e5Spatrick if (status == EFI_SUCCESS) 68f24071e5Spatrick status = EFI_CALL(BS->HandleProtocol, imgp->DeviceHandle, 69f24071e5Spatrick &devp_guid, (void **)&dp); 70f24071e5Spatrick if (status == EFI_SUCCESS) 71f24071e5Spatrick efi_bootdp = dp; 72f24071e5Spatrick 73f24071e5Spatrick progname = "BOOTAA64"; 74f24071e5Spatrick 75f24071e5Spatrick boot(0); 76f24071e5Spatrick 77f24071e5Spatrick return (EFI_SUCCESS); 78f24071e5Spatrick } 79f24071e5Spatrick 80f24071e5Spatrick static SIMPLE_TEXT_OUTPUT_INTERFACE *conout; 81f24071e5Spatrick static SIMPLE_INPUT_INTERFACE *conin; 82f24071e5Spatrick 83f24071e5Spatrick void 84f24071e5Spatrick efi_cons_probe(struct consdev *cn) 85f24071e5Spatrick { 86f24071e5Spatrick cn->cn_pri = CN_MIDPRI; 87f24071e5Spatrick cn->cn_dev = makedev(12, 0); 88f24071e5Spatrick } 89f24071e5Spatrick 90f24071e5Spatrick void 91f24071e5Spatrick efi_cons_init(struct consdev *cp) 92f24071e5Spatrick { 93f24071e5Spatrick conin = ST->ConIn; 94f24071e5Spatrick conout = ST->ConOut; 95f24071e5Spatrick } 96f24071e5Spatrick 97f24071e5Spatrick int 98f24071e5Spatrick efi_cons_getc(dev_t dev) 99f24071e5Spatrick { 100f24071e5Spatrick EFI_INPUT_KEY key; 101f24071e5Spatrick EFI_STATUS status; 102f24071e5Spatrick #if 0 103f24071e5Spatrick UINTN dummy; 104f24071e5Spatrick #endif 105f24071e5Spatrick static int lastchar = 0; 106f24071e5Spatrick 107f24071e5Spatrick if (lastchar) { 108f24071e5Spatrick int r = lastchar; 109f24071e5Spatrick if ((dev & 0x80) == 0) 110f24071e5Spatrick lastchar = 0; 111f24071e5Spatrick return (r); 112f24071e5Spatrick } 113f24071e5Spatrick 114f24071e5Spatrick status = conin->ReadKeyStroke(conin, &key); 115f24071e5Spatrick while (status == EFI_NOT_READY) { 116f24071e5Spatrick if (dev & 0x80) 117f24071e5Spatrick return (0); 118f24071e5Spatrick /* 119f24071e5Spatrick * XXX The implementation of WaitForEvent() in U-boot 120f24071e5Spatrick * is broken and neverreturns. 121f24071e5Spatrick */ 122f24071e5Spatrick #if 0 123f24071e5Spatrick BS->WaitForEvent(1, &conin->WaitForKey, &dummy); 124f24071e5Spatrick #endif 125f24071e5Spatrick status = conin->ReadKeyStroke(conin, &key); 126f24071e5Spatrick } 127f24071e5Spatrick 128f24071e5Spatrick if (dev & 0x80) 129f24071e5Spatrick lastchar = key.UnicodeChar; 130f24071e5Spatrick 131f24071e5Spatrick return (key.UnicodeChar); 132f24071e5Spatrick } 133f24071e5Spatrick 134f24071e5Spatrick void 135f24071e5Spatrick efi_cons_putc(dev_t dev, int c) 136f24071e5Spatrick { 137f24071e5Spatrick CHAR16 buf[2]; 138f24071e5Spatrick 139f24071e5Spatrick if (c == '\n') 140f24071e5Spatrick efi_cons_putc(dev, '\r'); 141f24071e5Spatrick 142f24071e5Spatrick buf[0] = c; 143f24071e5Spatrick buf[1] = 0; 144f24071e5Spatrick 145f24071e5Spatrick conout->OutputString(conout, buf); 146f24071e5Spatrick } 147f24071e5Spatrick 148f24071e5Spatrick EFI_PHYSICAL_ADDRESS heap; 149f24071e5Spatrick UINTN heapsiz = 1 * 1024 * 1024; 150f24071e5Spatrick 151f24071e5Spatrick static void 152f24071e5Spatrick efi_heap_init(void) 153f24071e5Spatrick { 154f24071e5Spatrick EFI_STATUS status; 155f24071e5Spatrick 156f24071e5Spatrick status = EFI_CALL(BS->AllocatePages, AllocateAnyPages, EfiLoaderData, 157f24071e5Spatrick EFI_SIZE_TO_PAGES(heapsiz), &heap); 158f24071e5Spatrick if (status != EFI_SUCCESS) 159f24071e5Spatrick panic("BS->AllocatePages()"); 160f24071e5Spatrick } 161f24071e5Spatrick 162f24071e5Spatrick EFI_BLOCK_IO *disk; 163f24071e5Spatrick 164f24071e5Spatrick void 165f24071e5Spatrick efi_diskprobe(void) 166f24071e5Spatrick { 167f24071e5Spatrick int i, bootdev; 168f24071e5Spatrick UINTN sz; 169f24071e5Spatrick EFI_STATUS status; 170f24071e5Spatrick EFI_HANDLE *handles = NULL; 171f24071e5Spatrick EFI_BLOCK_IO *blkio; 172f24071e5Spatrick EFI_BLOCK_IO_MEDIA *media; 173f24071e5Spatrick EFI_DEVICE_PATH *dp, *bp; 174f24071e5Spatrick 175f24071e5Spatrick sz = 0; 176f24071e5Spatrick status = EFI_CALL(BS->LocateHandle, ByProtocol, &blkio_guid, 0, &sz, 0); 177f24071e5Spatrick if (status == EFI_BUFFER_TOO_SMALL) { 178f24071e5Spatrick handles = alloc(sz); 179f24071e5Spatrick status = EFI_CALL(BS->LocateHandle, ByProtocol, &blkio_guid, 180f24071e5Spatrick 0, &sz, handles); 181f24071e5Spatrick } 182f24071e5Spatrick if (handles == NULL || EFI_ERROR(status)) 183f24071e5Spatrick panic("BS->LocateHandle() returns %d", status); 184f24071e5Spatrick 185f24071e5Spatrick for (i = 0; i < sz / sizeof(EFI_HANDLE); i++) { 186f24071e5Spatrick bootdev = 0; 187f24071e5Spatrick status = EFI_CALL(BS->HandleProtocol, handles[i], &blkio_guid, 188f24071e5Spatrick (void **)&blkio); 189f24071e5Spatrick if (EFI_ERROR(status)) 190f24071e5Spatrick panic("BS->HandleProtocol() returns %d", status); 191f24071e5Spatrick 192f24071e5Spatrick media = blkio->Media; 193f24071e5Spatrick if (media->LogicalPartition || !media->MediaPresent) 194f24071e5Spatrick continue; 195f24071e5Spatrick 196f24071e5Spatrick if (efi_bootdp == NULL) 197f24071e5Spatrick goto next; 198f24071e5Spatrick status = EFI_CALL(BS->HandleProtocol, handles[i], &devp_guid, 199f24071e5Spatrick (void **)&dp); 200f24071e5Spatrick if (EFI_ERROR(status)) 201f24071e5Spatrick goto next; 202f24071e5Spatrick bp = efi_bootdp; 203f24071e5Spatrick while (1) { 204f24071e5Spatrick if (IsDevicePathEnd(dp)) { 205f24071e5Spatrick bootdev = 1; 206f24071e5Spatrick break; 207f24071e5Spatrick } 208f24071e5Spatrick if (memcmp(dp, bp, sizeof(EFI_DEVICE_PATH)) != 0 || 209f24071e5Spatrick memcmp(dp, bp, DevicePathNodeLength(dp)) != 0) 210f24071e5Spatrick break; 211f24071e5Spatrick dp = NextDevicePathNode(dp); 212f24071e5Spatrick bp = NextDevicePathNode(bp); 213f24071e5Spatrick } 214f24071e5Spatrick next: 215f24071e5Spatrick if (bootdev) { 216f24071e5Spatrick disk = blkio; 217f24071e5Spatrick break; 218f24071e5Spatrick } 219f24071e5Spatrick } 220f24071e5Spatrick 221f24071e5Spatrick free(handles, sz); 222f24071e5Spatrick } 223f24071e5Spatrick 224f24071e5Spatrick static EFI_GUID fdt_guid = FDT_TABLE_GUID; 225f24071e5Spatrick 226f24071e5Spatrick #define efi_guidcmp(_a, _b) memcmp((_a), (_b), sizeof(EFI_GUID)) 227f24071e5Spatrick 228f24071e5Spatrick void * 229f24071e5Spatrick efi_makebootargs(char *bootargs) 230f24071e5Spatrick { 231f24071e5Spatrick void *fdt = NULL; 232f24071e5Spatrick char bootduid[8]; 233f24071e5Spatrick u_char zero[8]; 234f24071e5Spatrick void *node; 235f24071e5Spatrick size_t len; 236f24071e5Spatrick int i; 237f24071e5Spatrick 238f24071e5Spatrick for (i = 0; i < ST->NumberOfTableEntries; i++) { 239f24071e5Spatrick if (efi_guidcmp(&fdt_guid, 240f24071e5Spatrick &ST->ConfigurationTable[i].VendorGuid) == 0) 241f24071e5Spatrick fdt = ST->ConfigurationTable[i].VendorTable; 242f24071e5Spatrick } 243f24071e5Spatrick 244f24071e5Spatrick if (!fdt_init(fdt)) 245f24071e5Spatrick return NULL; 246f24071e5Spatrick 247f24071e5Spatrick node = fdt_find_node("/chosen"); 248f24071e5Spatrick if (!node) 249f24071e5Spatrick return NULL; 250f24071e5Spatrick 251f24071e5Spatrick len = strlen(bootargs) + 1; 252f24071e5Spatrick fdt_node_add_property(node, "bootargs", bootargs, len); 253f24071e5Spatrick 254f24071e5Spatrick /* Pass DUID of the boot disk. */ 255f24071e5Spatrick memset(&zero, 0, sizeof(zero)); 256f24071e5Spatrick memcpy(&bootduid, diskinfo.disklabel.d_uid, sizeof(bootduid)); 257f24071e5Spatrick if (memcmp(bootduid, zero, sizeof(bootduid)) != 0) { 258f24071e5Spatrick fdt_node_add_property(node, "openbsd,bootduid", bootduid, 259f24071e5Spatrick sizeof(bootduid)); 260f24071e5Spatrick } 261f24071e5Spatrick 262f24071e5Spatrick fdt_finalize(); 263f24071e5Spatrick 264f24071e5Spatrick return fdt; 265f24071e5Spatrick } 266f24071e5Spatrick 267f24071e5Spatrick u_long efi_loadaddr; 268f24071e5Spatrick 269f24071e5Spatrick void 270f24071e5Spatrick machdep(void) 271f24071e5Spatrick { 272f24071e5Spatrick EFI_PHYSICAL_ADDRESS addr; 273f24071e5Spatrick 274f24071e5Spatrick cninit(); 275f24071e5Spatrick efi_heap_init(); 276f24071e5Spatrick 277f24071e5Spatrick /* 278f24071e5Spatrick * The kernel expects to be loaded at offset 0x00200000 into a 279f24071e5Spatrick * block of memory aligned on a 256MB boundary. We allocate a 280f24071e5Spatrick * block of 32MB of memory, which gives us plenty of room for 281f24071e5Spatrick * growth. 282f24071e5Spatrick */ 283f24071e5Spatrick if (efi_memprobe_find(EFI_SIZE_TO_PAGES(32 * 1024 * 1024), 284f24071e5Spatrick 0x10000000, &addr) != EFI_SUCCESS) 285f24071e5Spatrick printf("Can't allocate memory\n"); 286f24071e5Spatrick efi_loadaddr = addr; 287f24071e5Spatrick 288f24071e5Spatrick efi_timer_init(); 289f24071e5Spatrick efi_diskprobe(); 290f24071e5Spatrick } 291f24071e5Spatrick 292f24071e5Spatrick void 293f24071e5Spatrick efi_cleanup(void) 294f24071e5Spatrick { 295f24071e5Spatrick efi_timer_cleanup(); 296f24071e5Spatrick 297f24071e5Spatrick BS->ExitBootServices(NULL, 0); 298f24071e5Spatrick } 299f24071e5Spatrick 300f24071e5Spatrick void 301f24071e5Spatrick _rtt(void) 302f24071e5Spatrick { 303f24071e5Spatrick #ifdef EFI_DEBUG 304f24071e5Spatrick printf("Hit any key to reboot\n"); 305f24071e5Spatrick efi_cons_getc(0); 306f24071e5Spatrick #endif 307f24071e5Spatrick /* 308f24071e5Spatrick * XXX ResetSystem doesn't seem to work on U-Boot 2016.05 on 309f24071e5Spatrick * the CuBox-i. So trigger an unimplemented instruction trap 310f24071e5Spatrick * instead. 311f24071e5Spatrick */ 312f24071e5Spatrick #if 1 313f24071e5Spatrick asm volatile(".word 0xa000f7f0\n"); 314f24071e5Spatrick #else 315f24071e5Spatrick RS->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL); 316f24071e5Spatrick #endif 317f24071e5Spatrick while (1) { } 318f24071e5Spatrick } 319f24071e5Spatrick 320f24071e5Spatrick /* 321f24071e5Spatrick * U-Boot only implements the GetTime() Runtime Service if it has been 322f24071e5Spatrick * configured with CONFIG_DM_RTC. Most board configurations don't 323f24071e5Spatrick * include that option, so we can't use it to implement our boot 324f24071e5Spatrick * prompt timeout. Instead we use timer events to simulate a clock 325f24071e5Spatrick * that ticks ever second. 326f24071e5Spatrick */ 327f24071e5Spatrick 328f24071e5Spatrick EFI_EVENT timer; 329f24071e5Spatrick int ticks; 330f24071e5Spatrick 331f24071e5Spatrick static VOID 332f24071e5Spatrick efi_timer(EFI_EVENT event, VOID *context) 333f24071e5Spatrick { 334f24071e5Spatrick ticks++; 335f24071e5Spatrick } 336f24071e5Spatrick 337f24071e5Spatrick static void 338f24071e5Spatrick efi_timer_init(void) 339f24071e5Spatrick { 340f24071e5Spatrick EFI_STATUS status; 341f24071e5Spatrick 342f24071e5Spatrick status = BS->CreateEvent(EVT_TIMER, TPL_CALLBACK, 343f24071e5Spatrick efi_timer, NULL, &timer); 344f24071e5Spatrick if (status == EFI_SUCCESS) 345f24071e5Spatrick status = BS->SetTimer(timer, TimerPeriodic, 10000000); 346f24071e5Spatrick if (EFI_ERROR(status)) 347f24071e5Spatrick printf("Can't create timer\n"); 348f24071e5Spatrick } 349f24071e5Spatrick 350f24071e5Spatrick static void 351f24071e5Spatrick efi_timer_cleanup(void) 352f24071e5Spatrick { 353f24071e5Spatrick BS->CloseEvent(timer); 354f24071e5Spatrick } 355f24071e5Spatrick 356f24071e5Spatrick time_t 357f24071e5Spatrick getsecs(void) 358f24071e5Spatrick { 359f24071e5Spatrick return ticks; 360f24071e5Spatrick } 361f24071e5Spatrick 362f24071e5Spatrick /* 363f24071e5Spatrick * Various device-related bits. 364f24071e5Spatrick */ 365f24071e5Spatrick 366f24071e5Spatrick void 367f24071e5Spatrick devboot(dev_t dev, char *p) 368f24071e5Spatrick { 369f24071e5Spatrick strlcpy(p, "sd0a", 5); 370f24071e5Spatrick } 371f24071e5Spatrick 372f24071e5Spatrick int 373f24071e5Spatrick cnspeed(dev_t dev, int sp) 374f24071e5Spatrick { 375f24071e5Spatrick return 115200; 376f24071e5Spatrick } 377f24071e5Spatrick 378f24071e5Spatrick char * 379f24071e5Spatrick ttyname(int fd) 380f24071e5Spatrick { 381f24071e5Spatrick return "com0"; 382f24071e5Spatrick } 383f24071e5Spatrick 384f24071e5Spatrick dev_t 385f24071e5Spatrick ttydev(char *name) 386f24071e5Spatrick { 387f24071e5Spatrick return NODEV; 388f24071e5Spatrick } 389f24071e5Spatrick 390f24071e5Spatrick #define MAXDEVNAME 16 391f24071e5Spatrick 392f24071e5Spatrick /* 393f24071e5Spatrick * Parse a device spec. 394f24071e5Spatrick * 395f24071e5Spatrick * [A-Za-z]*[0-9]*[A-Za-z]:file 396f24071e5Spatrick * dev uint part 397f24071e5Spatrick */ 398f24071e5Spatrick int 399f24071e5Spatrick devparse(const char *fname, int *dev, int *unit, int *part, const char **file) 400f24071e5Spatrick { 401f24071e5Spatrick const char *s; 402f24071e5Spatrick 403f24071e5Spatrick *unit = 0; /* default to wd0a */ 404f24071e5Spatrick *part = 0; 405f24071e5Spatrick *dev = 0; 406f24071e5Spatrick 407f24071e5Spatrick s = strchr(fname, ':'); 408f24071e5Spatrick if (s != NULL) { 409f24071e5Spatrick int devlen; 410f24071e5Spatrick int i, u, p = 0; 411f24071e5Spatrick struct devsw *dp; 412f24071e5Spatrick char devname[MAXDEVNAME]; 413f24071e5Spatrick 414f24071e5Spatrick devlen = s - fname; 415f24071e5Spatrick if (devlen > MAXDEVNAME) 416f24071e5Spatrick return (EINVAL); 417f24071e5Spatrick 418f24071e5Spatrick /* extract device name */ 419f24071e5Spatrick for (i = 0; isalpha(fname[i]) && (i < devlen); i++) 420f24071e5Spatrick devname[i] = fname[i]; 421f24071e5Spatrick devname[i] = 0; 422f24071e5Spatrick 423f24071e5Spatrick if (!isdigit(fname[i])) 424f24071e5Spatrick return (EUNIT); 425f24071e5Spatrick 426f24071e5Spatrick /* device number */ 427f24071e5Spatrick for (u = 0; isdigit(fname[i]) && (i < devlen); i++) 428f24071e5Spatrick u = u * 10 + (fname[i] - '0'); 429f24071e5Spatrick 430f24071e5Spatrick if (!isalpha(fname[i])) 431f24071e5Spatrick return (EPART); 432f24071e5Spatrick 433f24071e5Spatrick /* partition number */ 434f24071e5Spatrick if (i < devlen) 435f24071e5Spatrick p = fname[i++] - 'a'; 436f24071e5Spatrick 437f24071e5Spatrick if (i != devlen) 438f24071e5Spatrick return (ENXIO); 439f24071e5Spatrick 440f24071e5Spatrick /* check device name */ 441f24071e5Spatrick for (dp = devsw, i = 0; i < ndevs; dp++, i++) { 442f24071e5Spatrick if (dp->dv_name && !strcmp(devname, dp->dv_name)) 443f24071e5Spatrick break; 444f24071e5Spatrick } 445f24071e5Spatrick 446f24071e5Spatrick if (i >= ndevs) 447f24071e5Spatrick return (ENXIO); 448f24071e5Spatrick 449f24071e5Spatrick *unit = u; 450f24071e5Spatrick *part = p; 451f24071e5Spatrick *dev = i; 452f24071e5Spatrick fname = ++s; 453f24071e5Spatrick } 454f24071e5Spatrick 455f24071e5Spatrick *file = fname; 456f24071e5Spatrick 457f24071e5Spatrick return (0); 458f24071e5Spatrick } 459f24071e5Spatrick 460f24071e5Spatrick int 461f24071e5Spatrick devopen(struct open_file *f, const char *fname, char **file) 462f24071e5Spatrick { 463f24071e5Spatrick struct devsw *dp; 464f24071e5Spatrick int dev, unit, part, error; 465f24071e5Spatrick 466f24071e5Spatrick error = devparse(fname, &dev, &unit, &part, (const char **)file); 467f24071e5Spatrick if (error) 468f24071e5Spatrick return (error); 469f24071e5Spatrick 470f24071e5Spatrick dp = &devsw[0]; 471f24071e5Spatrick f->f_dev = dp; 472f24071e5Spatrick 473f24071e5Spatrick return (*dp->dv_open)(f, unit, part); 474f24071e5Spatrick } 475f24071e5Spatrick 476f24071e5Spatrick /* 477f24071e5Spatrick * 64-bit ARMs can have a much wider memory mapping, as in somewhere 478f24071e5Spatrick * after the 32-bit region. To cope with our alignment requirement, 479f24071e5Spatrick * use the memory table to find a place where we can fit. 480f24071e5Spatrick */ 481f24071e5Spatrick static EFI_STATUS 482f24071e5Spatrick efi_memprobe_find(UINTN pages, UINTN align, EFI_PHYSICAL_ADDRESS *addr) 483f24071e5Spatrick { 484f24071e5Spatrick EFI_STATUS status; 485f24071e5Spatrick UINTN mapkey, mmsiz, siz; 486f24071e5Spatrick UINT32 mmver; 487f24071e5Spatrick EFI_MEMORY_DESCRIPTOR *mm0, *mm; 488f24071e5Spatrick int i, j, n; 489f24071e5Spatrick 490f24071e5Spatrick if (align < EFI_PAGE_SIZE) 491f24071e5Spatrick return EFI_INVALID_PARAMETER; 492f24071e5Spatrick 493f24071e5Spatrick siz = 0; 494f24071e5Spatrick status = EFI_CALL(BS->GetMemoryMap, &siz, NULL, &mapkey, &mmsiz, 495f24071e5Spatrick &mmver); 496f24071e5Spatrick if (status != EFI_BUFFER_TOO_SMALL) 497f24071e5Spatrick panic("cannot get the size of memory map"); 498f24071e5Spatrick mm0 = alloc(siz); 499f24071e5Spatrick status = EFI_CALL(BS->GetMemoryMap, &siz, mm0, &mapkey, &mmsiz, &mmver); 500f24071e5Spatrick if (status != EFI_SUCCESS) 501f24071e5Spatrick panic("cannot get the memory map"); 502f24071e5Spatrick n = siz / mmsiz; 503f24071e5Spatrick 504f24071e5Spatrick for (i = 0, mm = mm0; i < n; i++, mm = NextMemoryDescriptor(mm, mmsiz)) { 505f24071e5Spatrick if (mm->Type != EfiConventionalMemory) 506f24071e5Spatrick continue; 507f24071e5Spatrick 508f24071e5Spatrick if (mm->NumberOfPages < pages) 509f24071e5Spatrick continue; 510f24071e5Spatrick 511f2c0e408Skettenis for (j = 0; j < mm->NumberOfPages; j++) { 512f24071e5Spatrick EFI_PHYSICAL_ADDRESS paddr; 513f24071e5Spatrick 514f24071e5Spatrick if (mm->NumberOfPages - j < pages) 515f24071e5Spatrick break; 516f24071e5Spatrick 517f24071e5Spatrick paddr = mm->PhysicalStart + (j * EFI_PAGE_SIZE); 518*73dc1409Spatrick if (paddr & (align - 1)) 519*73dc1409Spatrick continue; 520*73dc1409Spatrick 521*73dc1409Spatrick if (EFI_CALL(BS->AllocatePages, AllocateAddress, 522*73dc1409Spatrick EfiLoaderData, pages, &paddr) == EFI_SUCCESS) { 523f24071e5Spatrick *addr = paddr; 524f24071e5Spatrick free(mm0, siz); 525f24071e5Spatrick return EFI_SUCCESS; 526f24071e5Spatrick } 527f24071e5Spatrick } 528f24071e5Spatrick } 529f24071e5Spatrick free(mm0, siz); 530f24071e5Spatrick return EFI_OUT_OF_RESOURCES; 531f24071e5Spatrick } 532