199767f8919635c4928607450d9e0abb932109ceToomas Soome * Copyright (c) 1998 Robert Nordier
199767f8919635c4928607450d9e0abb932109ceToomas Soome * All rights reserved.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Copyright (c) 2001 Robert Drehmel
199767f8919635c4928607450d9e0abb932109ceToomas Soome * All rights reserved.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Copyright (c) 2014 Nathan Whitehorn
199767f8919635c4928607450d9e0abb932109ceToomas Soome * All rights reserved.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Copyright (c) 2015 Eric McCorkle
199767f8919635c4928607450d9e0abb932109ceToomas Soome * All rights reserved.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Redistribution and use in source and binary forms are freely
199767f8919635c4928607450d9e0abb932109ceToomas Soome * permitted provided that the above copyright notice and this
199767f8919635c4928607450d9e0abb932109ceToomas Soome * paragraph and the following disclaimer are duplicated in all
199767f8919635c4928607450d9e0abb932109ceToomas Soome * such forms.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * This software is provided "AS IS" and without any express or
199767f8919635c4928607450d9e0abb932109ceToomas Soome * implied warranties, including, without limitation, the implied
199767f8919635c4928607450d9e0abb932109ceToomas Soome * warranties of merchantability and fitness for a particular
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define NUM_BOOT_MODULES (sizeof(boot_modules) / sizeof(boot_module_t*))
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* The initial number of handles used to query EFI for partitions. */
199767f8919635c4928607450d9e0abb932109ceToomas SoomeEFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL;
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL;
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL;
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID;
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Provide Malloc / Free backed by EFIs AllocatePool / FreePool which ensures
199767f8919635c4928607450d9e0abb932109ceToomas Soome * memory is correctly aligned avoiding EFI_INVALID_PARAMETER returns from
199767f8919635c4928607450d9e0abb932109ceToomas Soome * EFI methods.
199767f8919635c4928607450d9e0abb932109ceToomas SoomeMalloc(size_t len, const char *file __unused, int line __unused)
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (bs->AllocatePool(EfiLoaderData, len, &out) == EFI_SUCCESS)
199767f8919635c4928607450d9e0abb932109ceToomas SoomeFree(void *buf, const char *file __unused, int line __unused)
199767f8919635c4928607450d9e0abb932109ceToomas Soome * nodes_match returns TRUE if the imgpath isn't NULL and the nodes match,
199767f8919635c4928607450d9e0abb932109ceToomas Soome * FALSE otherwise.
199767f8919635c4928607450d9e0abb932109ceToomas Soomenodes_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath)
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (imgpath == NULL || imgpath->Type != devpath->Type ||
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (memcmp(imgpath, devpath, (size_t)len) == 0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome * device_paths_match returns TRUE if the imgpath isn't NULL and all nodes
199767f8919635c4928607450d9e0abb932109ceToomas Soome * in imgpath and devpath match up to their respect occurances of a media
199767f8919635c4928607450d9e0abb932109ceToomas Soome * node, FALSE otherwise.
199767f8919635c4928607450d9e0abb932109ceToomas Soomedevice_paths_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath)
199767f8919635c4928607450d9e0abb932109ceToomas Soome while (!IsDevicePathEnd(imgpath) && !IsDevicePathEnd(devpath)) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (IsDevicePathType(imgpath, MEDIA_DEVICE_PATH) &&
199767f8919635c4928607450d9e0abb932109ceToomas Soome * devpath_last returns the last non-path end node in devpath.
199767f8919635c4928607450d9e0abb932109ceToomas Soome while (!IsDevicePathEnd(NextDevicePathNode(devpath)))
199767f8919635c4928607450d9e0abb932109ceToomas Soome * devpath_node_str is a basic output method for a devpath node which
199767f8919635c4928607450d9e0abb932109ceToomas Soome * only understands a subset of the available sub types.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * If we switch to UEFI 2.x then we should update it to use:
199767f8919635c4928607450d9e0abb932109ceToomas Soome * EFI_DEVICE_PATH_TO_TEXT_PROTOCOL.
199767f8919635c4928607450d9e0abb932109ceToomas Soomedevpath_node_str(char *buf, size_t size, EFI_DEVICE_PATH *devpath)
199767f8919635c4928607450d9e0abb932109ceToomas Soome (atapi->PrimarySecondary == 1) ? "Sec" : "Pri",
199767f8919635c4928607450d9e0abb932109ceToomas Soome (atapi->SlaveMaster == 1) ? "Slave" : "Master",
199767f8919635c4928607450d9e0abb932109ceToomas Soome return snprintf(buf, size, "usb(0x%02x,0x%02x)",
199767f8919635c4928607450d9e0abb932109ceToomas Soome return snprintf(buf, size, "scsi(0x%02x,0x%02x)",
199767f8919635c4928607450d9e0abb932109ceToomas Soome return snprintf(buf, size, "sata(0x%x,0x%x,0x%x)",
199767f8919635c4928607450d9e0abb932109ceToomas Soome sata->HBAPortNumber, sata->PortMultiplierPortNumber,
199767f8919635c4928607450d9e0abb932109ceToomas Soome return snprintf(buf, size, "pci(0x%02x,0x%02x)",
199767f8919635c4928607450d9e0abb932109ceToomas Soome acpi = (ACPI_HID_DEVICE_PATH *)(void *)devpath;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if ((acpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome case 0x0a03:
199767f8919635c4928607450d9e0abb932109ceToomas Soome case 0x0a08:
199767f8919635c4928607450d9e0abb932109ceToomas Soome case 0x0604:
199767f8919635c4928607450d9e0abb932109ceToomas Soome case 0x0301:
199767f8919635c4928607450d9e0abb932109ceToomas Soome case 0x0501:
199767f8919635c4928607450d9e0abb932109ceToomas Soome case 0x0401:
199767f8919635c4928607450d9e0abb932109ceToomas Soome return snprintf(buf, size, "parallelport(0x%x)",
199767f8919635c4928607450d9e0abb932109ceToomas Soome return snprintf(buf, size, "acpi(pnp%04x,0x%x)",
199767f8919635c4928607450d9e0abb932109ceToomas Soome return snprintf(buf, size, "acpi(0x%08x,0x%x)", acpi->HID,
199767f8919635c4928607450d9e0abb932109ceToomas Soome return snprintf(buf, size, "bbs(0x%02x)", devpath->SubType);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return snprintf(buf, size, "type(0x%02x, 0x%02x)", devpath->Type,
199767f8919635c4928607450d9e0abb932109ceToomas Soome * devpath_strlcat appends a text description of devpath to buf but not more
199767f8919635c4928607450d9e0abb932109ceToomas Soome * than size - 1 characters followed by NUL-terminator.
199767f8919635c4928607450d9e0abb932109ceToomas Soomedevpath_strlcat(char *buf, size_t size, EFI_DEVICE_PATH *devpath)
199767f8919635c4928607450d9e0abb932109ceToomas Soome len = devpath_node_str(buf, size - used, devpath);
199767f8919635c4928607450d9e0abb932109ceToomas Soome * devpath_str is convenience method which returns the text description of
199767f8919635c4928607450d9e0abb932109ceToomas Soome * devpath using a static buffer, so it isn't thread safe!
199767f8919635c4928607450d9e0abb932109ceToomas Soome * load_loader attempts to load the loader image data.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * It tries each module and its respective devices, identified by mod->probe,
199767f8919635c4928607450d9e0abb932109ceToomas Soome * in order until a successful load occurs at which point it returns EFI_SUCCESS
199767f8919635c4928607450d9e0abb932109ceToomas Soome * and EFI_NOT_FOUND otherwise.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Only devices which have preferred matching the preferred parameter are tried.
199767f8919635c4928607450d9e0abb932109ceToomas Soomeload_loader(const boot_module_t **modp, dev_info_t **devinfop, void **bufp,
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (i = 0; i < NUM_BOOT_MODULES; i++) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (dev = mod->devices(); dev != NULL; dev = dev->next) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (mod->load(PATH_LOADER_EFI, dev, bufp, bufsize) ==
199767f8919635c4928607450d9e0abb932109ceToomas Soome * try_boot only returns if it fails to load the loader. If it succeeds
199767f8919635c4928607450d9e0abb932109ceToomas Soome * it simply boots, otherwise it returns the status of last EFI call.
199767f8919635c4928607450d9e0abb932109ceToomas Soome status = load_loader(&mod, &dev, &loaderbuf, &loadersize, TRUE);
199767f8919635c4928607450d9e0abb932109ceToomas Soome status = load_loader(&mod, &dev, &loaderbuf, &loadersize,
199767f8919635c4928607450d9e0abb932109ceToomas Soome printf("Failed to load '%s'\n", PATH_LOADER_EFI);
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Read in and parse the command line from /boot.config or /boot/config,
199767f8919635c4928607450d9e0abb932109ceToomas Soome * if present. We'll pass it the next stage via a simple ASCII
199767f8919635c4928607450d9e0abb932109ceToomas Soome * string. loader.efi has a hack for ASCII strings, so we'll use that to
199767f8919635c4928607450d9e0abb932109ceToomas Soome * keep the size down here. We only try to read the alternate file if
199767f8919635c4928607450d9e0abb932109ceToomas Soome * we get EFI_NOT_FOUND because all other errors mean that the boot_module
199767f8919635c4928607450d9e0abb932109ceToomas Soome * had troubles with the filesystem. We could return early, but we'll let
199767f8919635c4928607450d9e0abb932109ceToomas Soome * loading the actual kernel sort all that out. Since these files are
199767f8919635c4928607450d9e0abb932109ceToomas Soome * optional, we don't report errors in trying to read them.
199767f8919635c4928607450d9e0abb932109ceToomas Soome status = mod->load(PATH_DOTCONFIG, dev, &buf, &bufsize);
199767f8919635c4928607450d9e0abb932109ceToomas Soome status = mod->load(PATH_CONFIG, dev, &buf, &bufsize);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if ((status = bs->LoadImage(TRUE, image, devpath_last(dev->devpath),
199767f8919635c4928607450d9e0abb932109ceToomas Soome loaderbuf, loadersize, &loaderhandle)) != EFI_SUCCESS) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome printf("Failed to load image provided by %s, size: %zu, (%lu)\n",
f4fb84c03b3f4c46dab36872e953dd3c27317c3aToomas Soome mod->name, loadersize, EFI_ERROR_CODE(status));
199767f8919635c4928607450d9e0abb932109ceToomas Soome if ((status = bs->HandleProtocol(loaderhandle, &LoadedImageGUID,
199767f8919635c4928607450d9e0abb932109ceToomas Soome printf("Failed to query LoadedImage provided by %s (%lu)\n",
199767f8919635c4928607450d9e0abb932109ceToomas Soome DPRINTF("Starting '%s' in 5 seconds...", PATH_LOADER_EFI);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if ((status = bs->StartImage(loaderhandle, NULL, NULL)) !=
199767f8919635c4928607450d9e0abb932109ceToomas Soome printf("Failed to start image provided by %s (%lu)\n",
199767f8919635c4928607450d9e0abb932109ceToomas Soome * probe_handle determines if the passed handle represents a logical partition
199767f8919635c4928607450d9e0abb932109ceToomas Soome * if it does it uses each module in order to probe it and if successful it
199767f8919635c4928607450d9e0abb932109ceToomas Soome * returns EFI_SUCCESS.
199767f8919635c4928607450d9e0abb932109ceToomas Soomeprobe_handle(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath, BOOLEAN *preferred)
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Figure out if we're dealing with an actual partition. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome status = bs->HandleProtocol(h, &DevicePathGUID, (void **)&devpath);
199767f8919635c4928607450d9e0abb932109ceToomas Soome DPRINTF("\nFailed to query DevicePath (%lu)\n",
199767f8919635c4928607450d9e0abb932109ceToomas Soome DPRINTF("probing: %s\n", devpath_str(devpath));
199767f8919635c4928607450d9e0abb932109ceToomas Soome status = bs->HandleProtocol(h, &BlockIoProtocolGUID, (void **)&blkio);
199767f8919635c4928607450d9e0abb932109ceToomas Soome DPRINTF("\nFailed to query BlockIoProtocol (%lu)\n",
199767f8919635c4928607450d9e0abb932109ceToomas Soome *preferred = device_paths_match(imgpath, devpath);
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Run through each module, see if it can load this partition */
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (i = 0; i < NUM_BOOT_MODULES; i++) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome DPRINTF("\nFailed to allocate devinfo (%lu)\n",
199767f8919635c4928607450d9e0abb932109ceToomas Soome * probe_handle_status calls probe_handle and outputs the returned status
199767f8919635c4928607450d9e0abb932109ceToomas Soome * of the call.
199767f8919635c4928607450d9e0abb932109ceToomas Soomeprobe_handle_status(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath)
199767f8919635c4928607450d9e0abb932109ceToomas Soome DPRINTF(" error (%lu)\n", EFI_ERROR_CODE(status));
199767f8919635c4928607450d9e0abb932109ceToomas Soomeefi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab)
199767f8919635c4928607450d9e0abb932109ceToomas Soome EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome UINTN i, max_dim, best_mode, cols, rows, hsize, nhandles;
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Basic initialization*/
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Set up the console, so printf works. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome status = bs->LocateProtocol(&ConsoleControlGUID, NULL,
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Reset the console and find the best text mode.
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (i = 0; ; i++) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome status = conout->QueryMode(conout, i, &cols, &rows);
199767f8919635c4928607450d9e0abb932109ceToomas Soome printf(" Loader path: %s\n\n", PATH_LOADER_EFI);
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (i = 0; i < NUM_BOOT_MODULES; i++) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Get all the device handles */
199767f8919635c4928607450d9e0abb932109ceToomas Soome hsize = (UINTN)NUM_HANDLES_INIT * sizeof(EFI_HANDLE);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if ((status = bs->AllocatePool(EfiLoaderData, hsize, (void **)&handles))
199767f8919635c4928607450d9e0abb932109ceToomas Soome panic("Failed to allocate %d handles (%lu)", NUM_HANDLES_INIT,
199767f8919635c4928607450d9e0abb932109ceToomas Soome status = bs->LocateHandle(ByProtocol, &BlockIoProtocolGUID, NULL,
199767f8919635c4928607450d9e0abb932109ceToomas Soome if ((status = bs->AllocatePool(EfiLoaderData, hsize,
199767f8919635c4928607450d9e0abb932109ceToomas Soome panic("Failed to allocate %zu handles (%lu)", hsize /
199767f8919635c4928607450d9e0abb932109ceToomas Soome status = bs->LocateHandle(ByProtocol, &BlockIoProtocolGUID,
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Scan all partitions, probing with all modules. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome printf(" Probing %zu block devices...", nhandles);
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Determine the devpath of our image so we can prefer it. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome status = bs->HandleProtocol(image, &LoadedImageGUID, (VOID**)&img);
199767f8919635c4928607450d9e0abb932109ceToomas Soome status = bs->HandleProtocol(img->DeviceHandle, &DevicePathGUID,
199767f8919635c4928607450d9e0abb932109ceToomas Soome DPRINTF("Failed to get image DevicePath (%lu)\n",
199767f8919635c4928607450d9e0abb932109ceToomas Soome DPRINTF("boot1 imagepath: %s\n", devpath_str(imgpath));
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (i = 0; i < nhandles; i++)
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Status summary. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (i = 0; i < NUM_BOOT_MODULES; i++) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* If we get here, we're out of luck... */
199767f8919635c4928607450d9e0abb932109ceToomas Soome * add_device adds a device to the passed devinfo list.
199767f8919635c4928607450d9e0abb932109ceToomas Soomeadd_device(dev_info_t **devinfop, dev_info_t *devinfo)
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (dev = *devinfop; dev->next != NULL; dev = dev->next)
199767f8919635c4928607450d9e0abb932109ceToomas Soome while (1) {}
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (c == '\n') {
199767f8919635c4928607450d9e0abb932109ceToomas Soome systab->ConOut->OutputString(systab->ConOut, buf);
199767f8919635c4928607450d9e0abb932109ceToomas Soome systab->ConOut->OutputString(systab->ConOut, buf);
199767f8919635c4928607450d9e0abb932109ceToomas Soome status = systab->ConIn->ReadKeyStroke(systab->ConIn, &key);
199767f8919635c4928607450d9e0abb932109ceToomas Soome bs->WaitForEvent(1, &systab->ConIn->WaitForKey, &junk);