Changeset View
Changeset View
Standalone View
Standalone View
sys/boot/efi/loader/main.c
Show All 22 Lines | |||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
*/ | */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include <sys/param.h> | |||||
#include <stand.h> | #include <stand.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <setjmp.h> | #include <setjmp.h> | ||||
#include <efi.h> | #include <efi.h> | ||||
#include <efilib.h> | #include <efilib.h> | ||||
#include <bootstrap.h> | #include <bootstrap.h> | ||||
#include <smbios.h> | #include <smbios.h> | ||||
#ifdef EFI_ZFS_BOOT | |||||
#include <libzfs.h> | |||||
#endif | |||||
#include "loader_efi.h" | #include "loader_efi.h" | ||||
extern char bootprog_name[]; | extern char bootprog_name[]; | ||||
extern char bootprog_rev[]; | extern char bootprog_rev[]; | ||||
extern char bootprog_date[]; | extern char bootprog_date[]; | ||||
extern char bootprog_maker[]; | extern char bootprog_maker[]; | ||||
struct devdesc currdev; /* our current device */ | |||||
struct arch_switch archsw; /* MI/MD interface boundary */ | struct arch_switch archsw; /* MI/MD interface boundary */ | ||||
EFI_GUID acpi = ACPI_TABLE_GUID; | EFI_GUID acpi = ACPI_TABLE_GUID; | ||||
EFI_GUID acpi20 = ACPI_20_TABLE_GUID; | EFI_GUID acpi20 = ACPI_20_TABLE_GUID; | ||||
EFI_GUID devid = DEVICE_PATH_PROTOCOL; | EFI_GUID devid = DEVICE_PATH_PROTOCOL; | ||||
EFI_GUID imgid = LOADED_IMAGE_PROTOCOL; | EFI_GUID imgid = LOADED_IMAGE_PROTOCOL; | ||||
EFI_GUID mps = MPS_TABLE_GUID; | EFI_GUID mps = MPS_TABLE_GUID; | ||||
EFI_GUID netid = EFI_SIMPLE_NETWORK_PROTOCOL; | EFI_GUID netid = EFI_SIMPLE_NETWORK_PROTOCOL; | ||||
EFI_GUID smbios = SMBIOS_TABLE_GUID; | EFI_GUID smbios = SMBIOS_TABLE_GUID; | ||||
EFI_GUID dxe = DXE_SERVICES_TABLE_GUID; | EFI_GUID dxe = DXE_SERVICES_TABLE_GUID; | ||||
EFI_GUID hoblist = HOB_LIST_TABLE_GUID; | EFI_GUID hoblist = HOB_LIST_TABLE_GUID; | ||||
EFI_GUID memtype = MEMORY_TYPE_INFORMATION_TABLE_GUID; | EFI_GUID memtype = MEMORY_TYPE_INFORMATION_TABLE_GUID; | ||||
EFI_GUID debugimg = DEBUG_IMAGE_INFO_TABLE_GUID; | EFI_GUID debugimg = DEBUG_IMAGE_INFO_TABLE_GUID; | ||||
EFI_GUID fdtdtb = FDT_TABLE_GUID; | EFI_GUID fdtdtb = FDT_TABLE_GUID; | ||||
#ifdef EFI_ZFS_BOOT | |||||
static void efi_zfs_probe(void); | |||||
#endif | |||||
/* | |||||
* Need this because EFI uses UTF-16 unicode string constants, but we | |||||
* use UTF-8. We can't use printf due to the possiblity of \0 and we | |||||
* don't support support wide characters either. | |||||
*/ | |||||
static void | |||||
print_str16(const CHAR16 *str) | |||||
{ | |||||
int i; | |||||
for (i = 0; str[i]; i++) | |||||
printf("%c", (char)str[i]); | |||||
} | |||||
EFI_STATUS | EFI_STATUS | ||||
main(int argc, CHAR16 *argv[]) | main(int argc, CHAR16 *argv[]) | ||||
{ | { | ||||
char var[128]; | char var[128]; | ||||
EFI_LOADED_IMAGE *img; | EFI_LOADED_IMAGE *img; | ||||
EFI_GUID *guid; | EFI_GUID *guid; | ||||
int i, j, vargood; | int i, j, vargood, unit; | ||||
struct devsw *dev; | |||||
uint64_t pool_guid; | |||||
archsw.arch_autoload = efi_autoload; | |||||
archsw.arch_getdev = efi_getdev; | |||||
archsw.arch_copyin = efi_copyin; | |||||
archsw.arch_copyout = efi_copyout; | |||||
archsw.arch_readin = efi_readin; | |||||
#ifdef EFI_ZFS_BOOT | |||||
/* Note this needs to be set before ZFS init. */ | |||||
archsw.arch_zfs_probe = efi_zfs_probe; | |||||
#endif | |||||
/* | /* | ||||
* XXX Chicken-and-egg problem; we want to have console output | * XXX Chicken-and-egg problem; we want to have console output | ||||
* early, but some console attributes may depend on reading from | * early, but some console attributes may depend on reading from | ||||
* eg. the boot device, which we can't do yet. We can use | * eg. the boot device, which we can't do yet. We can use | ||||
* printf() etc. once this is done. | * printf() etc. once this is done. | ||||
*/ | */ | ||||
cons_probe(); | cons_probe(); | ||||
Show All 30 Lines | #endif | ||||
*/ | */ | ||||
for (i = 0; devsw[i] != NULL; i++) | for (i = 0; devsw[i] != NULL; i++) | ||||
if (devsw[i]->dv_init != NULL) | if (devsw[i]->dv_init != NULL) | ||||
(devsw[i]->dv_init)(); | (devsw[i]->dv_init)(); | ||||
/* 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**)&img); | ||||
printf("Command line arguments:"); | |||||
for (i = 0; i < argc; i++) { | |||||
printf(" "); | |||||
print_str16(argv[i]); | |||||
} | |||||
printf("\n"); | |||||
printf("Image base: 0x%lx\n", (u_long)img->ImageBase); | printf("Image base: 0x%lx\n", (u_long)img->ImageBase); | ||||
printf("EFI version: %d.%02d\n", ST->Hdr.Revision >> 16, | printf("EFI version: %d.%02d\n", ST->Hdr.Revision >> 16, | ||||
ST->Hdr.Revision & 0xffff); | ST->Hdr.Revision & 0xffff); | ||||
printf("EFI Firmware: "); | printf("EFI Firmware: "); | ||||
/* printf doesn't understand EFI Unicode */ | /* printf doesn't understand EFI Unicode */ | ||||
ST->ConOut->OutputString(ST->ConOut, ST->FirmwareVendor); | ST->ConOut->OutputString(ST->ConOut, ST->FirmwareVendor); | ||||
printf(" (rev %d.%02d)\n", ST->FirmwareRevision >> 16, | printf(" (rev %d.%02d)\n", ST->FirmwareRevision >> 16, | ||||
ST->FirmwareRevision & 0xffff); | ST->FirmwareRevision & 0xffff); | ||||
printf("\n"); | printf("\n"); | ||||
printf("%s, Revision %s\n", bootprog_name, bootprog_rev); | printf("%s, Revision %s\n", bootprog_name, bootprog_rev); | ||||
printf("(%s, %s)\n", bootprog_maker, bootprog_date); | printf("(%s, %s)\n", bootprog_maker, bootprog_date); | ||||
efi_handle_lookup(img->DeviceHandle, &currdev.d_dev, &currdev.d_unit); | |||||
currdev.d_type = currdev.d_dev->dv_type; | |||||
/* | /* | ||||
* Disable the watchdog timer. By default the boot manager sets | * Disable the watchdog timer. By default the boot manager sets | ||||
* the timer to 5 minutes before invoking a boot option. If we | * the timer to 5 minutes before invoking a boot option. If we | ||||
* want to return to the boot manager, we have to disable the | * want to return to the boot manager, we have to disable the | ||||
* watchdog timer and since we're an interactive program, we don't | * watchdog timer and since we're an interactive program, we don't | ||||
* want to wait until the user types "quit". The timer may have | * want to wait until the user types "quit". The timer may have | ||||
* fired by then. We don't care if this fails. It does not prevent | * fired by then. We don't care if this fails. It does not prevent | ||||
* normal functioning in any way... | * normal functioning in any way... | ||||
*/ | */ | ||||
BS->SetWatchdogTimer(0, 0, 0, NULL); | BS->SetWatchdogTimer(0, 0, 0, NULL); | ||||
if (efi_handle_lookup(img->DeviceHandle, &dev, &unit, &pool_guid) != 0) | |||||
return (EFI_NOT_FOUND); | |||||
switch (dev->dv_type) { | |||||
#ifdef EFI_ZFS_BOOT | |||||
case DEVT_ZFS: { | |||||
struct zfs_devdesc currdev; | |||||
currdev.d_dev = dev; | |||||
currdev.d_unit = unit; | |||||
currdev.d_type = currdev.d_dev->dv_type; | |||||
currdev.d_opendata = NULL; | |||||
currdev.pool_guid = pool_guid; | |||||
currdev.root_guid = 0; | |||||
env_setenv("currdev", EV_VOLATILE, efi_fmtdev(&currdev), | env_setenv("currdev", EV_VOLATILE, efi_fmtdev(&currdev), | ||||
efi_setcurrdev, env_nounset); | efi_setcurrdev, env_nounset); | ||||
env_setenv("loaddev", EV_VOLATILE, efi_fmtdev(&currdev), env_noset, | env_setenv("loaddev", EV_VOLATILE, efi_fmtdev(&currdev), env_noset, | ||||
env_nounset); | env_nounset); | ||||
break; | |||||
} | |||||
#endif | |||||
default: { | |||||
struct devdesc currdev; | |||||
currdev.d_dev = dev; | |||||
currdev.d_unit = unit; | |||||
currdev.d_opendata = NULL; | |||||
currdev.d_type = currdev.d_dev->dv_type; | |||||
env_setenv("currdev", EV_VOLATILE, efi_fmtdev(&currdev), | |||||
efi_setcurrdev, env_nounset); | |||||
env_setenv("loaddev", EV_VOLATILE, efi_fmtdev(&currdev), env_noset, | |||||
env_nounset); | |||||
break; | |||||
} | |||||
} | |||||
setenv("LINES", "24", 1); /* optional */ | setenv("LINES", "24", 1); /* optional */ | ||||
archsw.arch_autoload = efi_autoload; | |||||
archsw.arch_getdev = efi_getdev; | |||||
archsw.arch_copyin = efi_copyin; | |||||
archsw.arch_copyout = efi_copyout; | |||||
archsw.arch_readin = efi_readin; | |||||
for (i = 0; i < ST->NumberOfTableEntries; i++) { | for (i = 0; i < ST->NumberOfTableEntries; i++) { | ||||
guid = &ST->ConfigurationTable[i].VendorGuid; | guid = &ST->ConfigurationTable[i].VendorGuid; | ||||
if (!memcmp(guid, &smbios, sizeof(EFI_GUID))) { | if (!memcmp(guid, &smbios, sizeof(EFI_GUID))) { | ||||
smbios_detect(ST->ConfigurationTable[i].VendorTable); | smbios_detect(ST->ConfigurationTable[i].VendorTable); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 250 Lines • ▼ Show 20 Lines | for (; status != EFI_NOT_FOUND; ) { | ||||
/* XXX */ | /* XXX */ | ||||
pager_output("\n"); | pager_output("\n"); | ||||
free(data); | free(data); | ||||
} | } | ||||
return (CMD_OK); | return (CMD_OK); | ||||
} | } | ||||
#ifdef EFI_ZFS_BOOT | |||||
COMMAND_SET(lszfs, "lszfs", "list child datasets of a zfs dataset", | |||||
command_lszfs); | |||||
static int | |||||
command_lszfs(int argc, char *argv[]) | |||||
{ | |||||
int err; | |||||
if (argc != 2) { | |||||
command_errmsg = "wrong number of arguments"; | |||||
return (CMD_ERROR); | |||||
} | |||||
err = zfs_list(argv[1]); | |||||
if (err != 0) { | |||||
command_errmsg = strerror(err); | |||||
return (CMD_ERROR); | |||||
} | |||||
return (CMD_OK); | |||||
} | |||||
#endif | |||||
#ifdef LOADER_FDT_SUPPORT | #ifdef LOADER_FDT_SUPPORT | ||||
extern int command_fdt_internal(int argc, char *argv[]); | extern int command_fdt_internal(int argc, char *argv[]); | ||||
/* | /* | ||||
* Since proper fdt command handling function is defined in fdt_loader_cmd.c, | * Since proper fdt command handling function is defined in fdt_loader_cmd.c, | ||||
* and declaring it as extern is in contradiction with COMMAND_SET() macro | * and declaring it as extern is in contradiction with COMMAND_SET() macro | ||||
* (which uses static pointer), we're defining wrapper function, which | * (which uses static pointer), we're defining wrapper function, which | ||||
* calls the proper fdt handling routine. | * calls the proper fdt handling routine. | ||||
*/ | */ | ||||
static int | static int | ||||
command_fdt(int argc, char *argv[]) | command_fdt(int argc, char *argv[]) | ||||
{ | { | ||||
return (command_fdt_internal(argc, argv)); | return (command_fdt_internal(argc, argv)); | ||||
} | } | ||||
COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt); | COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt); | ||||
#endif | |||||
#ifdef EFI_ZFS_BOOT | |||||
static void | |||||
efi_zfs_probe(void) | |||||
{ | |||||
EFI_HANDLE h; | |||||
u_int unit; | |||||
int i; | |||||
char dname[SPECNAMELEN + 1]; | |||||
uint64_t guid; | |||||
unit = 0; | |||||
h = efi_find_handle(&efipart_dev, 0); | |||||
for (i = 0; h != NULL; h = efi_find_handle(&efipart_dev, ++i)) { | |||||
snprintf(dname, sizeof(dname), "%s%d:", efipart_dev.dv_name, i); | |||||
if (zfs_probe_dev(dname, &guid) == 0) | |||||
(void)efi_handle_update_dev(h, &zfs_dev, unit++, guid); | |||||
} | |||||
} | |||||
#endif | #endif |