Changeset View
Changeset View
Standalone View
Standalone View
head/stand/efi/loader/main.c
Show First 20 Lines • Show All 82 Lines • ▼ Show 20 Lines | |||||
*/ | */ | ||||
static int fail_timeout = 5; | static int fail_timeout = 5; | ||||
/* | /* | ||||
* Current boot variable | * Current boot variable | ||||
*/ | */ | ||||
UINT16 boot_current; | UINT16 boot_current; | ||||
/* | |||||
* Image that we booted from. | |||||
*/ | |||||
EFI_LOADED_IMAGE *boot_img; | |||||
static bool | static bool | ||||
has_keyboard(void) | has_keyboard(void) | ||||
{ | { | ||||
EFI_STATUS status; | EFI_STATUS status; | ||||
EFI_DEVICE_PATH *path; | EFI_DEVICE_PATH *path; | ||||
EFI_HANDLE *hin, *hin_end, *walker; | EFI_HANDLE *hin, *hin_end, *walker; | ||||
UINTN sz; | UINTN sz; | ||||
bool retval = false; | bool retval = false; | ||||
▲ Show 20 Lines • Show All 196 Lines • ▼ Show 20 Lines | while (*p) { | ||||
p++; | p++; | ||||
} | } | ||||
} | } | ||||
#define SIZE(dp, edp) (size_t)((intptr_t)(void *)edp - (intptr_t)(void *)dp) | #define SIZE(dp, edp) (size_t)((intptr_t)(void *)edp - (intptr_t)(void *)dp) | ||||
enum { BOOT_INFO_OK = 0, BAD_CHOICE = 1, NOT_SPECIFIC = 2 }; | enum { BOOT_INFO_OK = 0, BAD_CHOICE = 1, NOT_SPECIFIC = 2 }; | ||||
static int | static int | ||||
match_boot_info(EFI_LOADED_IMAGE *img __unused, char *boot_info, size_t bisz) | match_boot_info(char *boot_info, size_t bisz) | ||||
{ | { | ||||
uint32_t attr; | uint32_t attr; | ||||
uint16_t fplen; | uint16_t fplen; | ||||
size_t len; | size_t len; | ||||
char *walker, *ep; | char *walker, *ep; | ||||
EFI_DEVICE_PATH *dp, *edp, *first_dp, *last_dp; | EFI_DEVICE_PATH *dp, *edp, *first_dp, *last_dp; | ||||
pdinfo_t *pp; | pdinfo_t *pp; | ||||
CHAR16 *descr; | CHAR16 *descr; | ||||
▲ Show 20 Lines • Show All 131 Lines • ▼ Show 20 Lines | |||||
* | * | ||||
* We always fail if we can't find the right thing. However, as | * We always fail if we can't find the right thing. However, as | ||||
* a concession to buggy UEFI implementations, like u-boot, if | * a concession to buggy UEFI implementations, like u-boot, if | ||||
* we have determined that the host is violating the UEFI boot | * we have determined that the host is violating the UEFI boot | ||||
* manager protocol, we'll signal the rest of the program that | * manager protocol, we'll signal the rest of the program that | ||||
* a drop to the OK boot loader prompt is possible. | * a drop to the OK boot loader prompt is possible. | ||||
*/ | */ | ||||
static int | static int | ||||
find_currdev(EFI_LOADED_IMAGE *img, bool do_bootmgr, bool is_last, | find_currdev(bool do_bootmgr, bool is_last, | ||||
char *boot_info, size_t boot_info_sz) | char *boot_info, size_t boot_info_sz) | ||||
{ | { | ||||
pdinfo_t *dp, *pp; | pdinfo_t *dp, *pp; | ||||
EFI_DEVICE_PATH *devpath, *copy; | EFI_DEVICE_PATH *devpath, *copy; | ||||
EFI_HANDLE h; | EFI_HANDLE h; | ||||
CHAR16 *text; | CHAR16 *text; | ||||
struct devsw *dev; | struct devsw *dev; | ||||
int unit; | int unit; | ||||
Show All 16 Lines | find_currdev(bool do_bootmgr, bool is_last, | ||||
* Second choice: If we can find out image boot_info, and there's | * Second choice: If we can find out image boot_info, and there's | ||||
* a follow-on boot image in that boot_info, use that. In this | * a follow-on boot image in that boot_info, use that. In this | ||||
* case root will be the partition specified in that image and | * case root will be the partition specified in that image and | ||||
* we'll load the kernel specified by the file path. Should there | * we'll load the kernel specified by the file path. Should there | ||||
* not be a filepath, we use the default. This filepath overrides | * not be a filepath, we use the default. This filepath overrides | ||||
* loader.conf. | * loader.conf. | ||||
*/ | */ | ||||
if (do_bootmgr) { | if (do_bootmgr) { | ||||
rv = match_boot_info(img, boot_info, boot_info_sz); | rv = match_boot_info(boot_info, boot_info_sz); | ||||
switch (rv) { | switch (rv) { | ||||
case BOOT_INFO_OK: /* We found it */ | case BOOT_INFO_OK: /* We found it */ | ||||
return (0); | return (0); | ||||
case BAD_CHOICE: /* specified file not found -> error */ | case BAD_CHOICE: /* specified file not found -> error */ | ||||
/* XXX do we want to have an escape hatch for last in boot order? */ | /* XXX do we want to have an escape hatch for last in boot order? */ | ||||
return (ENOENT); | return (ENOENT); | ||||
} /* Nothing specified, try normal match */ | } /* Nothing specified, try normal match */ | ||||
} | } | ||||
Show All 16 Lines | #endif /* EFI_ZFS_BOOT */ | ||||
/* | /* | ||||
* Try to find the block device by its handle based on the | * Try to find the block device by its handle based on the | ||||
* image we're booting. If we can't find a sane partition, | * image we're booting. If we can't find a sane partition, | ||||
* search all the other partitions of the disk. We do not | * search all the other partitions of the disk. We do not | ||||
* search other disks because it's a violation of the UEFI | * search other disks because it's a violation of the UEFI | ||||
* boot protocol to do so. We fail and let UEFI go on to | * boot protocol to do so. We fail and let UEFI go on to | ||||
* the next candidate. | * the next candidate. | ||||
*/ | */ | ||||
dp = efiblk_get_pdinfo_by_handle(img->DeviceHandle); | dp = efiblk_get_pdinfo_by_handle(boot_img->DeviceHandle); | ||||
if (dp != NULL) { | if (dp != NULL) { | ||||
text = efi_devpath_name(dp->pd_devpath); | text = efi_devpath_name(dp->pd_devpath); | ||||
if (text != NULL) { | if (text != NULL) { | ||||
printf("Trying ESP: %S\n", text); | printf("Trying ESP: %S\n", text); | ||||
efi_free_devpath_name(text); | efi_free_devpath_name(text); | ||||
} | } | ||||
set_currdev_pdinfo(dp); | set_currdev_pdinfo(dp); | ||||
if (sanity_check_currdev()) | if (sanity_check_currdev()) | ||||
Show All 22 Lines | #endif /* EFI_ZFS_BOOT */ | ||||
} | } | ||||
/* | /* | ||||
* Try the device handle from our loaded image first. If that | * Try the device handle from our loaded image first. If that | ||||
* fails, use the device path from the loaded image and see if | * fails, use the device path from the loaded image and see if | ||||
* any of the nodes in that path match one of the enumerated | * any of the nodes in that path match one of the enumerated | ||||
* handles. Currently, this handle list is only for netboot. | * handles. Currently, this handle list is only for netboot. | ||||
*/ | */ | ||||
if (efi_handle_lookup(img->DeviceHandle, &dev, &unit, &extra) == 0) { | if (efi_handle_lookup(boot_img->DeviceHandle, &dev, &unit, &extra) == 0) { | ||||
set_currdev_devsw(dev, unit); | set_currdev_devsw(dev, unit); | ||||
if (sanity_check_currdev()) | if (sanity_check_currdev()) | ||||
return (0); | return (0); | ||||
} | } | ||||
copy = NULL; | copy = NULL; | ||||
devpath = efi_lookup_image_devpath(IH); | devpath = efi_lookup_image_devpath(IH); | ||||
while (devpath != NULL) { | while (devpath != NULL) { | ||||
▲ Show 20 Lines • Show All 181 Lines • ▼ Show 20 Lines | main(int argc, CHAR16 *argv[]) | ||||
bool has_kbd, is_last; | bool has_kbd, is_last; | ||||
char *s; | char *s; | ||||
EFI_DEVICE_PATH *imgpath; | EFI_DEVICE_PATH *imgpath; | ||||
CHAR16 *text; | CHAR16 *text; | ||||
EFI_STATUS rv; | EFI_STATUS rv; | ||||
size_t sz, bosz = 0, bisz = 0; | size_t sz, bosz = 0, bisz = 0; | ||||
UINT16 boot_order[100]; | UINT16 boot_order[100]; | ||||
char boot_info[4096]; | char boot_info[4096]; | ||||
EFI_LOADED_IMAGE *img; | |||||
char buf[32]; | char buf[32]; | ||||
bool uefi_boot_mgr; | bool uefi_boot_mgr; | ||||
archsw.arch_autoload = efi_autoload; | archsw.arch_autoload = efi_autoload; | ||||
archsw.arch_getdev = efi_getdev; | archsw.arch_getdev = efi_getdev; | ||||
archsw.arch_copyin = efi_copyin; | archsw.arch_copyin = efi_copyin; | ||||
archsw.arch_copyout = efi_copyout; | archsw.arch_copyout = efi_copyout; | ||||
archsw.arch_readin = efi_readin; | archsw.arch_readin = efi_readin; | ||||
archsw.arch_zfs_probe = efi_zfs_probe; | archsw.arch_zfs_probe = efi_zfs_probe; | ||||
/* Get our loaded image protocol interface structure. */ | /* Get our loaded image protocol interface structure. */ | ||||
BS->HandleProtocol(IH, &imgid, (VOID**)&img); | BS->HandleProtocol(IH, &imgid, (VOID**)&boot_img); | ||||
/* | /* | ||||
* Chicken-and-egg problem; we want to have console output early, but | * Chicken-and-egg problem; we want to have console output early, but | ||||
* some console attributes may depend on reading from eg. the boot | * some console attributes may depend on reading from eg. the boot | ||||
* device, which we can't do yet. We can use printf() etc. once this is | * device, which we can't do yet. We can use printf() etc. once this is | ||||
* done. So, we set it to the efi console, then call console init. This | * done. So, we set it to the efi console, then call console init. This | ||||
* gets us printf early, but also primes the pump for all future console | * gets us printf early, but also primes the pump for all future console | ||||
* changes to take effect, regardless of where they come from. | * changes to take effect, regardless of where they come from. | ||||
*/ | */ | ||||
setenv("console", "efi", 1); | setenv("console", "efi", 1); | ||||
cons_probe(); | cons_probe(); | ||||
/* Tell ZFS probe code where we booted from, if zfs configured */ | |||||
efizfs_set_preferred(img->DeviceHandle); | |||||
/* Init the time source */ | /* Init the time source */ | ||||
efi_time_init(); | efi_time_init(); | ||||
has_kbd = has_keyboard(); | has_kbd = has_keyboard(); | ||||
/* | /* | ||||
* Initialise the block cache. Set the upper limit. | * Initialise the block cache. Set the upper limit. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 85 Lines • ▼ Show 20 Lines | printf(" EFI version: %d.%02d\n", ST->Hdr.Revision >> 16, | ||||
ST->Hdr.Revision & 0xffff); | ST->Hdr.Revision & 0xffff); | ||||
printf(" EFI Firmware: %S (rev %d.%02d)\n", ST->FirmwareVendor, | printf(" EFI Firmware: %S (rev %d.%02d)\n", ST->FirmwareVendor, | ||||
ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff); | ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff); | ||||
printf(" Console: %s (%#x)\n", getenv("console"), howto); | printf(" Console: %s (%#x)\n", getenv("console"), howto); | ||||
/* Determine the devpath of our image so we can prefer it. */ | /* Determine the devpath of our image so we can prefer it. */ | ||||
text = efi_devpath_name(img->FilePath); | text = efi_devpath_name(boot_img->FilePath); | ||||
if (text != NULL) { | if (text != NULL) { | ||||
printf(" Load Path: %S\n", text); | printf(" Load Path: %S\n", text); | ||||
efi_setenv_freebsd_wcs("LoaderPath", text); | efi_setenv_freebsd_wcs("LoaderPath", text); | ||||
efi_free_devpath_name(text); | efi_free_devpath_name(text); | ||||
} | } | ||||
rv = BS->HandleProtocol(img->DeviceHandle, &devid, (void **)&imgpath); | rv = BS->HandleProtocol(boot_img->DeviceHandle, &devid, (void **)&imgpath); | ||||
if (rv == EFI_SUCCESS) { | if (rv == EFI_SUCCESS) { | ||||
text = efi_devpath_name(imgpath); | text = efi_devpath_name(imgpath); | ||||
if (text != NULL) { | if (text != NULL) { | ||||
printf(" Load Device: %S\n", text); | printf(" Load Device: %S\n", text); | ||||
efi_setenv_freebsd_wcs("LoaderDev", text); | efi_setenv_freebsd_wcs("LoaderDev", text); | ||||
efi_free_devpath_name(text); | efi_free_devpath_name(text); | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 70 Lines • ▼ Show 20 Lines | #endif | ||||
/* | /* | ||||
* Try and find a good currdev based on the image that was booted. | * Try and find a good currdev based on the image that was booted. | ||||
* It might be desirable here to have a short pause to allow falling | * It might be desirable here to have a short pause to allow falling | ||||
* through to the boot loader instead of returning instantly to follow | * through to the boot loader instead of returning instantly to follow | ||||
* the boot protocol and also allow an escape hatch for users wishing | * the boot protocol and also allow an escape hatch for users wishing | ||||
* to try something different. | * to try something different. | ||||
*/ | */ | ||||
if (find_currdev(img, uefi_boot_mgr, is_last, boot_info, bisz) != 0) | if (find_currdev(uefi_boot_mgr, is_last, boot_info, bisz) != 0) | ||||
if (!interactive_interrupt("Failed to find bootable partition")) | if (!interactive_interrupt("Failed to find bootable partition")) | ||||
return (EFI_NOT_FOUND); | return (EFI_NOT_FOUND); | ||||
efi_init_environment(); | efi_init_environment(); | ||||
#if !defined(__arm__) | #if !defined(__arm__) | ||||
for (k = 0; k < ST->NumberOfTableEntries; k++) { | for (k = 0; k < ST->NumberOfTableEntries; k++) { | ||||
guid = &ST->ConfigurationTable[k].VendorGuid; | guid = &ST->ConfigurationTable[k].VendorGuid; | ||||
▲ Show 20 Lines • Show All 434 Lines • Show Last 20 Lines |