Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/stand/efi/boot1/proto.c
34859 views
1
/*-
2
* Copyright (c) 1998 Robert Nordier
3
* All rights reserved.
4
* Copyright (c) 2001 Robert Drehmel
5
* All rights reserved.
6
* Copyright (c) 2014 Nathan Whitehorn
7
* All rights reserved.
8
* Copyright (c) 2015 Eric McCorkle
9
* All rights reserved.
10
*
11
* Redistribution and use in source and binary forms are freely
12
* permitted provided that the above copyright notice and this
13
* paragraph and the following disclaimer are duplicated in all
14
* such forms.
15
*
16
* This software is provided "AS IS" and without any express or
17
* implied warranties, including, without limitation, the implied
18
* warranties of merchantability and fitness for a particular
19
* purpose.
20
*/
21
22
#include <sys/param.h>
23
#include <sys/stdarg.h>
24
25
#include <machine/elf.h>
26
27
#include <stand.h>
28
29
#include <efi.h>
30
#include <eficonsctl.h>
31
#include <efichar.h>
32
33
#include "boot_module.h"
34
#include "paths.h"
35
#include "proto.h"
36
37
static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL;
38
static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL;
39
40
#ifndef EFI_DEBUG
41
static const char *prio_str[] = {
42
"error",
43
"not supported",
44
"good",
45
"better"
46
};
47
#endif
48
49
/*
50
* probe_handle determines if the passed handle represents a logical partition
51
* if it does it uses each module in order to probe it and if successful it
52
* returns EFI_SUCCESS.
53
*/
54
static int
55
probe_handle(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath)
56
{
57
dev_info_t *devinfo;
58
EFI_BLOCK_IO *blkio;
59
EFI_DEVICE_PATH *devpath;
60
EFI_STATUS status;
61
UINTN i;
62
int preferred;
63
64
/* Figure out if we're dealing with an actual partition. */
65
status = OpenProtocolByHandle(h, &DevicePathGUID, (void **)&devpath);
66
if (status == EFI_UNSUPPORTED)
67
return (0);
68
69
if (status != EFI_SUCCESS) {
70
DPRINTF("\nFailed to query DevicePath (%lu)\n",
71
EFI_ERROR_CODE(status));
72
return (-1);
73
}
74
#ifdef EFI_DEBUG
75
{
76
CHAR16 *text = efi_devpath_name(devpath);
77
DPRINTF("probing: %S ", text);
78
efi_free_devpath_name(text);
79
}
80
#endif
81
status = OpenProtocolByHandle(h, &BlockIoProtocolGUID, (void **)&blkio);
82
if (status == EFI_UNSUPPORTED)
83
return (0);
84
85
if (status != EFI_SUCCESS) {
86
DPRINTF("\nFailed to query BlockIoProtocol (%lu)\n",
87
EFI_ERROR_CODE(status));
88
return (-1);
89
}
90
91
if (!blkio->Media->LogicalPartition)
92
return (0);
93
94
preferred = efi_devpath_same_disk(imgpath, devpath);
95
96
/* Run through each module, see if it can load this partition */
97
devinfo = malloc(sizeof(*devinfo));
98
if (devinfo == NULL) {
99
DPRINTF("\nFailed to allocate devinfo\n");
100
return (-1);
101
}
102
devinfo->dev = blkio;
103
devinfo->devpath = devpath;
104
devinfo->devhandle = h;
105
devinfo->preferred = preferred;
106
devinfo->next = NULL;
107
108
for (i = 0; i < num_boot_modules; i++) {
109
devinfo->devdata = NULL;
110
111
status = boot_modules[i]->probe(devinfo);
112
if (status == EFI_SUCCESS)
113
return (preferred + 1);
114
}
115
free(devinfo);
116
117
return (0);
118
}
119
120
/*
121
* load_loader attempts to load the loader image data.
122
*
123
* It tries each module and its respective devices, identified by mod->probe,
124
* in order until a successful load occurs at which point it returns EFI_SUCCESS
125
* and EFI_NOT_FOUND otherwise.
126
*
127
* Only devices which have preferred matching the preferred parameter are tried.
128
*/
129
static EFI_STATUS
130
load_loader(const boot_module_t **modp, dev_info_t **devinfop, void **bufp,
131
size_t *bufsize, int preferred)
132
{
133
UINTN i;
134
dev_info_t *dev;
135
const boot_module_t *mod;
136
137
for (i = 0; i < num_boot_modules; i++) {
138
mod = boot_modules[i];
139
for (dev = mod->devices(); dev != NULL; dev = dev->next) {
140
if (dev->preferred != preferred)
141
continue;
142
143
if (mod->load(PATH_LOADER_EFI, dev, bufp, bufsize) ==
144
EFI_SUCCESS) {
145
*devinfop = dev;
146
*modp = mod;
147
return (EFI_SUCCESS);
148
}
149
}
150
}
151
152
return (EFI_NOT_FOUND);
153
}
154
155
void
156
choice_protocol(EFI_HANDLE *handles, UINTN nhandles, EFI_DEVICE_PATH *imgpath)
157
{
158
UINT16 boot_current;
159
size_t sz;
160
UINT16 boot_order[100];
161
unsigned i;
162
int rv;
163
EFI_STATUS status;
164
const boot_module_t *mod;
165
dev_info_t *dev;
166
void *loaderbuf;
167
size_t loadersize;
168
169
/* Report UEFI Boot Manager Protocol details */
170
boot_current = 0;
171
sz = sizeof(boot_current);
172
if (efi_global_getenv("BootCurrent", &boot_current, &sz) == EFI_SUCCESS) {
173
printf(" BootCurrent: %04x\n", boot_current);
174
175
sz = sizeof(boot_order);
176
if (efi_global_getenv("BootOrder", &boot_order, &sz) == EFI_SUCCESS) {
177
printf(" BootOrder:");
178
for (i = 0; i < sz / sizeof(boot_order[0]); i++)
179
printf(" %04x%s", boot_order[i],
180
boot_order[i] == boot_current ? "[*]" : "");
181
printf("\n");
182
}
183
}
184
185
#ifdef TEST_FAILURE
186
/*
187
* For testing failover scenarios, it's nice to be able to fail fast.
188
* Define TEST_FAILURE to create a boot1.efi that always fails after
189
* reporting the boot manager protocol details.
190
*/
191
BS->Exit(IH, EFI_OUT_OF_RESOURCES, 0, NULL);
192
#endif
193
194
/* Scan all partitions, probing with all modules. */
195
printf(" Probing %zu block devices...", nhandles);
196
DPRINTF("\n");
197
for (i = 0; i < nhandles; i++) {
198
rv = probe_handle(handles[i], imgpath);
199
#ifdef EFI_DEBUG
200
printf("%c", "x.+*"[rv + 1]);
201
#else
202
printf("%s\n", prio_str[rv + 1]);
203
#endif
204
}
205
printf(" done\n");
206
207
208
/* Status summary. */
209
for (i = 0; i < num_boot_modules; i++) {
210
printf(" ");
211
boot_modules[i]->status();
212
}
213
214
status = load_loader(&mod, &dev, &loaderbuf, &loadersize, 1);
215
if (status != EFI_SUCCESS) {
216
status = load_loader(&mod, &dev, &loaderbuf, &loadersize, 0);
217
if (status != EFI_SUCCESS) {
218
printf("Failed to load '%s'\n", PATH_LOADER_EFI);
219
return;
220
}
221
}
222
223
try_boot(mod, dev, loaderbuf, loadersize);
224
}
225
226