Lines 30-35
Link Here
|
30 |
#include <efi.h> |
30 |
#include <efi.h> |
31 |
#include <eficonsctl.h> |
31 |
#include <eficonsctl.h> |
32 |
#include <efichar.h> |
32 |
#include <efichar.h> |
|
|
33 |
#include <uuid.h> |
33 |
|
34 |
|
34 |
#include "boot_module.h" |
35 |
#include "boot_module.h" |
35 |
#include "paths.h" |
36 |
#include "paths.h" |
Lines 46-53
Link Here
|
46 |
"better" |
47 |
"better" |
47 |
}; |
48 |
}; |
48 |
#endif |
49 |
#endif |
49 |
|
50 |
|
|
|
51 |
/* quick and dirty work for boot partition menu */ |
52 |
|
53 |
#define NUM_DEV_LIST 35 |
54 |
#define SELECT_TIMEOUT 10 |
55 |
|
56 |
typedef struct { |
57 |
const boot_module_t *modp; |
58 |
dev_info_t *devinfop; |
59 |
} moddev_t; |
60 |
|
61 |
static moddev_t dev_list[NUM_DEV_LIST]; |
62 |
|
63 |
static EFI_STATUS |
64 |
load_loader(const boot_module_t **modp, dev_info_t **devinfop, void **bufp, |
65 |
size_t *bufsize, int preferred); |
66 |
|
67 |
static char * |
68 |
humanize_number_kmgt(UINT64 size) { |
69 |
static char buf2[6]; |
70 |
UINT64 size0; |
71 |
|
72 |
if (size < 1024) |
73 |
sprintf(buf2, "%luB", size); |
74 |
else if (size0 = (size*10+512)/1024, size0 < 100) |
75 |
sprintf(buf2, "%lu.%luK", size0 / 10, size0 % 10); |
76 |
else if (size0 = (size+512)/1024, size0 < 1024) |
77 |
sprintf(buf2, "%luK", size0); |
78 |
else if (size0 = (size*10/1024+512)/1024, size0 < 100) |
79 |
sprintf(buf2, "%lu.%luM", size0 / 10, size0 % 10); |
80 |
else if (size0 = (size/1024+512)/1024, size0 < 1024) |
81 |
sprintf(buf2, "%luM", size0); |
82 |
else if (size0 = (size*10/1024/1024+512)/1024, size0 < 100) |
83 |
sprintf(buf2, "%lu.%luG", size0 / 10, size0 % 10); |
84 |
else if (size0 = (size/1024/1024+512)/1024, size0 < 1024) |
85 |
sprintf(buf2, "%luG", size0); |
86 |
else if (size0 = (size*10/1024/1024/1024+512)/1024, size0 < 100) |
87 |
sprintf(buf2, "%lu.%luT", size0 / 10, size0 % 10); |
88 |
else |
89 |
sprintf(buf2, "%luT", (size/1024/1024/1024+512)/1024); |
90 |
return(buf2); |
91 |
} |
92 |
|
93 |
static char |
94 |
idx2char(int i) |
95 |
{ |
96 |
return (i<10 ? '0'+i : 'a'+i-10); |
97 |
} |
98 |
|
99 |
static int |
100 |
char2idx(char c) |
101 |
{ |
102 |
return ((c >= '0' && c <= '9') ? c - '0' : |
103 |
(c >= 'A' && c <= 'Z') ? c - 'A' + 10 : |
104 |
(c >= 'a' && c <= 'z') ? c - 'a' + 10 : |
105 |
-1 ); |
106 |
} |
107 |
|
108 |
static void |
109 |
move_to_tol() |
110 |
{ |
111 |
SIMPLE_TEXT_OUTPUT_INTERFACE *conout; |
112 |
int x,y; |
113 |
|
114 |
conout = ST->ConOut; |
115 |
x = conout->Mode->CursorColumn; |
116 |
y = conout->Mode->CursorRow; |
117 |
conout->SetCursorPosition(conout, 0, y); |
118 |
} |
119 |
|
120 |
int |
121 |
mygetchar(void) |
122 |
{ |
123 |
EFI_INPUT_KEY key; |
124 |
EFI_STATUS status; |
125 |
UINTN junk; |
126 |
|
127 |
/* Try to read a key stroke. We wait for one if none is pending. */ |
128 |
status = ST->ConIn->ReadKeyStroke(ST->ConIn, &key); |
129 |
if (status == EFI_NOT_READY) { |
130 |
BS->WaitForEvent(1, &ST->ConIn->WaitForKey, &junk); |
131 |
status = ST->ConIn->ReadKeyStroke(ST->ConIn, &key); |
132 |
} |
133 |
switch (key.ScanCode) { |
134 |
case 0x17: /* ESC */ |
135 |
return (0x1b); /* esc */ |
136 |
} |
137 |
|
138 |
/* this can return */ |
139 |
return (key.UnicodeChar); |
140 |
} |
141 |
|
50 |
/* |
142 |
/* |
|
|
143 |
* Output of EFI_DEVICE_PATH_TO_TEXT_PROTOCOL is not easy to read. |
144 |
" I hope this looks better. |
145 |
*/ |
146 |
static int |
147 |
mediapath_node_str(char *buf, size_t size, EFI_DEVICE_PATH *devpath) |
148 |
{ |
149 |
switch (devpath->Type) { |
150 |
case MEDIA_DEVICE_PATH: |
151 |
switch (devpath->SubType) { |
152 |
case MEDIA_CDROM_DP: { |
153 |
CDROM_DEVICE_PATH *cdrom; |
154 |
|
155 |
cdrom = (CDROM_DEVICE_PATH *)(void *)devpath; |
156 |
return snprintf(buf, size, "cdrom(%x)", |
157 |
cdrom->BootEntry); |
158 |
} |
159 |
case MEDIA_HARDDRIVE_DP: { |
160 |
HARDDRIVE_DEVICE_PATH *hd; |
161 |
|
162 |
hd = (HARDDRIVE_DEVICE_PATH *)(void *)devpath; |
163 |
return snprintf(buf, size, "hd(p%d) (%s)", |
164 |
hd->PartitionNumber, |
165 |
humanize_number_kmgt(hd->PartitionSize * 512)); |
166 |
} |
167 |
default: |
168 |
return snprintf(buf, size, "media(0x%02x)", |
169 |
devpath->SubType); |
170 |
} |
171 |
} |
172 |
|
173 |
return snprintf(buf, size, "type(0x%02x, 0x%02x)", devpath->Type, |
174 |
devpath->SubType); |
175 |
} |
176 |
|
177 |
static int |
178 |
messagingpath_node_str(char *buf, size_t size, EFI_DEVICE_PATH *devpath) |
179 |
{ |
180 |
size_t pos = 0; |
181 |
|
182 |
if (IsDevicePathEnd(devpath)) |
183 |
return (-1); |
184 |
while (!IsDevicePathEnd(NextDevicePathNode(devpath))) { |
185 |
if (pos >= size) |
186 |
break; |
187 |
switch (devpath->Type) { |
188 |
case MESSAGING_DEVICE_PATH: { |
189 |
switch (devpath->SubType) { |
190 |
case MSG_ATAPI_DP: { |
191 |
ATAPI_DEVICE_PATH *pata; |
192 |
char prisec[4], masslv[4]; |
193 |
|
194 |
pata = (ATAPI_DEVICE_PATH *)(void *)devpath; |
195 |
if (0 == pata->PrimarySecondary) |
196 |
snprintf(prisec, 4, "Pri"); |
197 |
else |
198 |
snprintf(prisec, 4, "Sec"); |
199 |
if (0 == pata->SlaveMaster) |
200 |
snprintf(masslv, 4, "Mas"); |
201 |
else |
202 |
snprintf(masslv, 4, "Slv"); |
203 |
pos += (size_t)snprintf(buf + pos, size - pos, |
204 |
"PATA(%s%s)", |
205 |
prisec, |
206 |
masslv); |
207 |
break; |
208 |
} |
209 |
case MSG_SCSI_DP: { |
210 |
SCSI_DEVICE_PATH *scsi; |
211 |
|
212 |
scsi = (SCSI_DEVICE_PATH *)(void *)devpath; |
213 |
pos += (size_t)snprintf(buf + pos, size - pos, |
214 |
"SCSI(%2d) ", |
215 |
scsi->Pun); |
216 |
break; |
217 |
} |
218 |
case MSG_SATA_DP: { |
219 |
SATA_DEVICE_PATH *sata; |
220 |
|
221 |
sata = (SATA_DEVICE_PATH *)(void *)devpath; |
222 |
pos += (size_t)snprintf(buf + pos, size - pos, |
223 |
"SATA(%d) ", |
224 |
sata->HBAPortNumber); |
225 |
break; |
226 |
} |
227 |
case MSG_USB_DP: { |
228 |
USB_DEVICE_PATH *usb; |
229 |
|
230 |
usb = (USB_DEVICE_PATH *)(void *)devpath; |
231 |
pos += (size_t)snprintf(buf + pos, size - pos, |
232 |
"USB(P%02xI%02x) ", |
233 |
usb->ParentPortNumber, |
234 |
usb->InterfaceNumber); |
235 |
break; |
236 |
} |
237 |
default: |
238 |
pos += (size_t)snprintf(buf + pos, size - pos, |
239 |
"drive(%02x) ", |
240 |
devpath->SubType); |
241 |
} |
242 |
} |
243 |
} |
244 |
devpath = NextDevicePathNode(devpath); |
245 |
} |
246 |
if (pos > size) return (size); else return (pos); |
247 |
} |
248 |
|
249 |
/* |
250 |
* mediapath_str is convenience method which returns the text description of |
251 |
* mediapath using a static buffer, so it isn't thread safe! |
252 |
*/ |
253 |
static char * |
254 |
mediapath_str(EFI_DEVICE_PATH *devpath) |
255 |
{ |
256 |
static char buf[256]; |
257 |
|
258 |
mediapath_node_str(buf, sizeof(buf), devpath); |
259 |
|
260 |
return buf; |
261 |
} |
262 |
|
263 |
static char * |
264 |
messagingpath_str(EFI_DEVICE_PATH *devpath) |
265 |
{ |
266 |
static char buf[256]; |
267 |
|
268 |
messagingpath_node_str(buf, sizeof(buf), devpath); |
269 |
|
270 |
return buf; |
271 |
} |
272 |
|
273 |
static int |
274 |
list_devices(void) |
275 |
{ |
276 |
UINTN i, j; |
277 |
dev_info_t *dev; |
278 |
const boot_module_t *mod; |
279 |
|
280 |
j = 0; |
281 |
for (i = 0; i < num_boot_modules; i++) { |
282 |
if (boot_modules[i] == NULL) |
283 |
continue; |
284 |
mod = boot_modules[i]; |
285 |
for (dev = mod->devices(); dev != NULL; dev = dev->next) { |
286 |
dev_list[j].devinfop = dev; |
287 |
dev_list[j].modp = mod; |
288 |
j++; |
289 |
if (j >= NUM_DEV_LIST) |
290 |
break; |
291 |
} |
292 |
} |
293 |
|
294 |
return (j); |
295 |
} |
296 |
|
297 |
|
298 |
static int |
299 |
get_sel(int ndevs,int time_left) |
300 |
{ |
301 |
int i; |
302 |
int c, n; |
303 |
EFI_STATUS status; |
304 |
EFI_EVENT timer; |
305 |
EFI_EVENT events[2]; |
306 |
EFI_DEVICE_PATH *mediapath; |
307 |
UINTN idx; |
308 |
|
309 |
status = BS->CreateEvent(EVT_TIMER, 0, 0, NULL, &timer); |
310 |
if (status != EFI_SUCCESS) { |
311 |
printf("Can't allocate timer event.\n"); |
312 |
return (-1); |
313 |
} |
314 |
printf(" 0: AutoSelected Partition (Default): 0\n"); |
315 |
for (i = 0; i < ndevs; i++) { |
316 |
if (dev_list[i].devinfop->preferred == TRUE) |
317 |
c = '*'; |
318 |
else |
319 |
c = ' '; |
320 |
mediapath = efi_devpath_to_media_path( |
321 |
dev_list[i].devinfop->devpath); |
322 |
printf(" %c%c: %s: %s: %s: %c\n", c, idx2char(i+1), |
323 |
dev_list[i].modp->name, |
324 |
messagingpath_str(dev_list[i].devinfop->devpath), |
325 |
mediapath_str(mediapath), |
326 |
idx2char(i+1)); |
327 |
} |
328 |
/* One alpha-num selection only. Is this big enough ?? */ |
329 |
BS->SetTimer(timer, TimerPeriodic, 10000000); |
330 |
events[0] = timer; |
331 |
events[1] = ST->ConIn->WaitForKey; |
332 |
|
333 |
while (1) { |
334 |
if (time_left > 0) { |
335 |
printf("Select from 0 to %c. Timeout in %2d seconds," |
336 |
" [Space] to pause : ", |
337 |
idx2char(ndevs), time_left); |
338 |
} |
339 |
status = BS->WaitForEvent(2, events, &idx); |
340 |
if (status != EFI_SUCCESS) { |
341 |
BS->CloseEvent(timer); |
342 |
return (-1); |
343 |
} |
344 |
if (idx == 0) { |
345 |
time_left--; |
346 |
if (time_left <=0) { |
347 |
printf("\nTimeout. " |
348 |
"Partition is AutoSelected.\n"); |
349 |
n = 0; |
350 |
break; |
351 |
} else { |
352 |
move_to_tol(); |
353 |
} |
354 |
} |
355 |
if (idx == 1) { |
356 |
c = mygetchar(); |
357 |
if ((c == '\n') || (c == '\r')) { |
358 |
putchar('\n'); |
359 |
n = 0; |
360 |
break; |
361 |
} else if ((time_left > 0) && (c == ' ')) { |
362 |
BS->SetTimer(timer, TimerCancel, 0); |
363 |
time_left = -1; |
364 |
printf("\nTimer stopeed.\n Please Key in: "); |
365 |
} |
366 |
n = char2idx(c); |
367 |
if ((n >= 0) && (n <= ndevs)) { |
368 |
BS->SetTimer(timer, TimerCancel, 0); |
369 |
time_left = -1; |
370 |
printf("\n %c is selected.\n", c); |
371 |
break; |
372 |
} else { |
373 |
/* Invalid charecter. */ |
374 |
move_to_tol(); |
375 |
} |
376 |
} |
377 |
}; |
378 |
BS->CloseEvent(timer); |
379 |
return (n); |
380 |
} |
381 |
|
382 |
static EFI_STATUS |
383 |
select_loader(const boot_module_t **modp, dev_info_t **devinfop, |
384 |
void **bufp, size_t *bufsize) |
385 |
{ |
386 |
int n; |
387 |
int time_left; |
388 |
EFI_STATUS status; |
389 |
dev_info_t *dev; |
390 |
const boot_module_t *mod; |
391 |
int ndevs; |
392 |
|
393 |
ndevs = list_devices(); |
394 |
if ((ndevs <= 0) || (ndevs >= NUM_DEV_LIST)) { |
395 |
return (EFI_NOT_FOUND); |
396 |
} else if (ndevs == 1) { |
397 |
/* Only one condidate. */ |
398 |
*modp = mod = dev_list[0].modp; |
399 |
*devinfop = dev = dev_list[0].devinfop; |
400 |
return (mod->load(PATH_LOADER_EFI, dev,bufp, bufsize)); |
401 |
} |
402 |
|
403 |
/* Two or more candidate exist. */ |
404 |
|
405 |
/* Reset the console input. */ |
406 |
ST->ConIn->Reset(ST->ConIn, TRUE); |
407 |
|
408 |
time_left = SELECT_TIMEOUT; |
409 |
while (1) { |
410 |
n = get_sel(ndevs, time_left); |
411 |
if (n < 0) { |
412 |
return (EFI_NOT_FOUND); |
413 |
} else if (n == 0) { /* AutoSelect */ |
414 |
break; |
415 |
} else { |
416 |
mod = dev_list[n-1].modp; |
417 |
dev = dev_list[n-1].devinfop; |
418 |
status = mod->load(PATH_LOADER_EFI,dev, bufp, bufsize); |
419 |
if (status == EFI_SUCCESS) { |
420 |
break; |
421 |
} |
422 |
printf("Failed to load '%s'\n", PATH_LOADER_EFI); |
423 |
printf("Please select again: "); |
424 |
time_left = -1; |
425 |
} |
426 |
} |
427 |
if (n == 0) { /* AutoSelect */ |
428 |
status = load_loader(modp, devinfop, bufp, bufsize, TRUE); |
429 |
if (status != EFI_SUCCESS) { |
430 |
status = load_loader(modp, devinfop, bufp, bufsize, FALSE); |
431 |
} |
432 |
} else { |
433 |
*modp = dev_list[n-1].modp; |
434 |
*devinfop = dev_list[n-1].devinfop; |
435 |
status = EFI_SUCCESS; |
436 |
} |
437 |
return (status); |
438 |
} |
439 |
|
440 |
/* |
51 |
* probe_handle determines if the passed handle represents a logical partition |
441 |
* probe_handle determines if the passed handle represents a logical partition |
52 |
* if it does it uses each module in order to probe it and if successful it |
442 |
* if it does it uses each module in order to probe it and if successful it |
53 |
* returns EFI_SUCCESS. |
443 |
* returns EFI_SUCCESS. |
Lines 212-224
Link Here
|
212 |
boot_modules[i]->status(); |
602 |
boot_modules[i]->status(); |
213 |
} |
603 |
} |
214 |
|
604 |
|
215 |
status = load_loader(&mod, &dev, &loaderbuf, &loadersize, 1); |
605 |
status = select_loader(&mod, &dev, &loaderbuf, &loadersize); |
216 |
if (status != EFI_SUCCESS) { |
606 |
if (status != EFI_SUCCESS) { |
217 |
status = load_loader(&mod, &dev, &loaderbuf, &loadersize, 0); |
607 |
printf("Failed to load '%s'\n", PATH_LOADER_EFI); |
218 |
if (status != EFI_SUCCESS) { |
608 |
return; |
219 |
printf("Failed to load '%s'\n", PATH_LOADER_EFI); |
|
|
220 |
return; |
221 |
} |
222 |
} |
609 |
} |
223 |
|
610 |
|
224 |
try_boot(mod, dev, loaderbuf, loadersize); |
611 |
try_boot(mod, dev, loaderbuf, loadersize); |