1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Bootmethod for EFI boot manager 4 * 5 * Copyright 2021 Google LLC 6 * Written by Simon Glass <sjg@chromium.org> 7 */ 8 9#define LOG_CATEGORY UCLASS_BOOTSTD 10 11#include <common.h> 12#include <bootdev.h> 13#include <bootflow.h> 14#include <bootmeth.h> 15#include <command.h> 16#include <dm.h> 17#include <efi_loader.h> 18#include <efi_variable.h> 19#include <malloc.h> 20 21/** 22 * struct efi_mgr_priv - private info for the efi-mgr driver 23 * 24 * @fake_bootflow: Fake a valid bootflow for testing 25 */ 26struct efi_mgr_priv { 27 bool fake_dev; 28}; 29 30void sandbox_set_fake_efi_mgr_dev(struct udevice *dev, bool fake_dev) 31{ 32 struct efi_mgr_priv *priv = dev_get_priv(dev); 33 34 priv->fake_dev = fake_dev; 35} 36 37static int efi_mgr_check(struct udevice *dev, struct bootflow_iter *iter) 38{ 39 int ret; 40 41 /* Must be an bootstd device */ 42 ret = bootflow_iter_check_system(iter); 43 if (ret) 44 return log_msg_ret("net", ret); 45 46 return 0; 47} 48 49static int efi_mgr_read_bootflow(struct udevice *dev, struct bootflow *bflow) 50{ 51 struct efi_mgr_priv *priv = dev_get_priv(dev); 52 efi_status_t ret; 53 efi_uintn_t size; 54 u16 *bootorder; 55 56 if (priv->fake_dev) { 57 bflow->state = BOOTFLOWST_READY; 58 return 0; 59 } 60 61 ret = efi_init_obj_list(); 62 if (ret) 63 return log_msg_ret("init", ret); 64 65 /* Enable this method if the "BootOrder" UEFI exists. */ 66 bootorder = efi_get_var(u"BootOrder", &efi_global_variable_guid, 67 &size); 68 if (bootorder) { 69 free(bootorder); 70 bflow->state = BOOTFLOWST_READY; 71 return 0; 72 } 73 74 return -EINVAL; 75} 76 77static int efi_mgr_read_file(struct udevice *dev, struct bootflow *bflow, 78 const char *file_path, ulong addr, ulong *sizep) 79{ 80 /* Files are loaded by the 'bootefi bootmgr' command */ 81 82 return -ENOSYS; 83} 84 85static int efi_mgr_boot(struct udevice *dev, struct bootflow *bflow) 86{ 87 int ret; 88 89 /* Booting is handled by the 'bootefi bootmgr' command */ 90 ret = efi_bootmgr_run(EFI_FDT_USE_INTERNAL); 91 92 return 0; 93} 94 95static int bootmeth_efi_mgr_bind(struct udevice *dev) 96{ 97 struct bootmeth_uc_plat *plat = dev_get_uclass_plat(dev); 98 99 plat->desc = "EFI bootmgr flow"; 100 plat->flags = BOOTMETHF_GLOBAL; 101 102 return 0; 103} 104 105static struct bootmeth_ops efi_mgr_bootmeth_ops = { 106 .check = efi_mgr_check, 107 .read_bootflow = efi_mgr_read_bootflow, 108 .read_file = efi_mgr_read_file, 109 .boot = efi_mgr_boot, 110}; 111 112static const struct udevice_id efi_mgr_bootmeth_ids[] = { 113 { .compatible = "u-boot,efi-bootmgr" }, 114 { } 115}; 116 117U_BOOT_DRIVER(bootmeth_3efi_mgr) = { 118 .name = "bootmeth_efi_mgr", 119 .id = UCLASS_BOOTMETH, 120 .of_match = efi_mgr_bootmeth_ids, 121 .ops = &efi_mgr_bootmeth_ops, 122 .bind = bootmeth_efi_mgr_bind, 123 .priv_auto = sizeof(struct efi_mgr_priv), 124}; 125