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