bootmeth: use efi_loader interfaces instead of bootefi command
[pandora-u-boot.git] / boot / bootmeth_efi_mgr.c
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  */
26 struct efi_mgr_priv {
27         bool fake_dev;
28 };
29
30 void 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
37 static 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
49 static 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
77 static 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
85 static 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
95 static 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
105 static 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
112 static const struct udevice_id efi_mgr_bootmeth_ids[] = {
113         { .compatible = "u-boot,efi-bootmgr" },
114         { }
115 };
116
117 U_BOOT_DRIVER(bootmeth_efi_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 };