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 |
/* |
175 |
* mediapath_str is convenience method which returns the text description of |
176 |
* mediapath using a static buffer, so it isn't thread safe! |
177 |
*/ |
178 |
static char * |
179 |
mediapath_str(EFI_DEVICE_PATH *devpath) |
180 |
{ |
181 |
static char buf[256]; |
182 |
|
183 |
mediapath_node_str(buf, sizeof(buf), devpath); |
184 |
|
185 |
return buf; |
186 |
} |
187 |
|
188 |
static int |
189 |
list_devices(void) |
190 |
{ |
191 |
UINTN i, j; |
192 |
dev_info_t *dev; |
193 |
const boot_module_t *mod; |
194 |
|
195 |
j = 0; |
196 |
for (i = 0; i < num_boot_modules; i++) { |
197 |
if (boot_modules[i] == NULL) |
198 |
continue; |
199 |
mod = boot_modules[i]; |
200 |
for (dev = mod->devices(); dev != NULL; dev = dev->next) { |
201 |
dev_list[j].devinfop = dev; |
202 |
dev_list[j].modp = mod; |
203 |
j++; |
204 |
if (j >= NUM_DEV_LIST) |
205 |
break; |
206 |
} |
207 |
} |
208 |
|
209 |
return (j); |
210 |
} |
211 |
|
212 |
|
213 |
static int |
214 |
get_sel(int ndevs,int time_left) |
215 |
{ |
216 |
int i; |
217 |
int c, n; |
218 |
EFI_STATUS status; |
219 |
EFI_EVENT timer; |
220 |
EFI_EVENT events[2]; |
221 |
EFI_DEVICE_PATH *mediapath; |
222 |
UINTN idx; |
223 |
|
224 |
status = BS->CreateEvent(EVT_TIMER, 0, 0, NULL, &timer); |
225 |
if (status != EFI_SUCCESS) { |
226 |
printf("Can't allocate timer event.\n"); |
227 |
return (-1); |
228 |
} |
229 |
printf(" 0: AutoSelected Partition (Default): 0\n"); |
230 |
for (i = 0; i < ndevs; i++) { |
231 |
if (dev_list[i].devinfop->preferred == TRUE) |
232 |
c = '*'; |
233 |
else |
234 |
c = ' '; |
235 |
mediapath = efi_devpath_to_media_path( |
236 |
dev_list[i].devinfop->devpath); |
237 |
printf(" %c%c: %s: %s: %c\n", c, idx2char(i+1), |
238 |
dev_list[i].modp->name, |
239 |
mediapath_str(mediapath), |
240 |
idx2char(i+1)); |
241 |
} |
242 |
/* One alpha-num selection only. Is this big enough ?? */ |
243 |
BS->SetTimer(timer, TimerPeriodic, 10000000); |
244 |
events[0] = timer; |
245 |
events[1] = ST->ConIn->WaitForKey; |
246 |
|
247 |
while (1) { |
248 |
if (time_left > 0) { |
249 |
printf("Select from 0 to %c. Timeout in %2d seconds," |
250 |
" [Space] to pause : ", |
251 |
idx2char(ndevs), time_left); |
252 |
} |
253 |
status = BS->WaitForEvent(2, events, &idx); |
254 |
if (status != EFI_SUCCESS) { |
255 |
BS->CloseEvent(timer); |
256 |
return (-1); |
257 |
} |
258 |
if (idx == 0) { |
259 |
time_left--; |
260 |
if (time_left <=0) { |
261 |
printf("\nTimeout. " |
262 |
"Partition is AutoSelected.\n"); |
263 |
n = 0; |
264 |
break; |
265 |
} else { |
266 |
move_to_tol(); |
267 |
} |
268 |
} |
269 |
if (idx == 1) { |
270 |
c = getchar(); |
271 |
if ((c == '\n') || (c == '\r')) { |
272 |
putchar('\n'); |
273 |
n = 0; |
274 |
break; |
275 |
} else if ((time_left > 0) && (c == ' ')) { |
276 |
BS->SetTimer(timer, TimerCancel, 0); |
277 |
time_left = -1; |
278 |
printf("\nTimer stopeed.\n Please Key in: "); |
279 |
} |
280 |
n = char2idx(c); |
281 |
if ((n >= 0) && (n <= ndevs)) { |
282 |
BS->SetTimer(timer, TimerCancel, 0); |
283 |
time_left = -1; |
284 |
printf("\n %c is selected.\n", c); |
285 |
break; |
286 |
} else { |
287 |
/* Invalid charecter. */ |
288 |
move_to_tol(); |
289 |
} |
290 |
} |
291 |
}; |
292 |
BS->CloseEvent(timer); |
293 |
return (n); |
294 |
} |
295 |
|
296 |
static EFI_STATUS |
297 |
select_loader(const boot_module_t **modp, dev_info_t **devinfop, |
298 |
void **bufp, size_t *bufsize) |
299 |
{ |
300 |
int n; |
301 |
int time_left; |
302 |
EFI_STATUS status; |
303 |
dev_info_t *dev; |
304 |
const boot_module_t *mod; |
305 |
int ndevs; |
306 |
|
307 |
ndevs = list_devices(); |
308 |
if ((ndevs <= 0) || (ndevs >= NUM_DEV_LIST)) { |
309 |
return (EFI_NOT_FOUND); |
310 |
} else if (ndevs == 1) { |
311 |
/* Only one condidate. */ |
312 |
*modp = mod = dev_list[0].modp; |
313 |
*devinfop = dev = dev_list[0].devinfop; |
314 |
return (mod->load(PATH_LOADER_EFI, dev,bufp, bufsize)); |
315 |
} |
316 |
|
317 |
/* Two or more candidate exist. */ |
318 |
|
319 |
/* Reset the console input. */ |
320 |
ST->ConIn->Reset(ST->ConIn, TRUE); |
321 |
|
322 |
time_left = SELECT_TIMEOUT; |
323 |
while (1) { |
324 |
n = get_sel(ndevs, time_left); |
325 |
if (n < 0) { |
326 |
return (EFI_NOT_FOUND); |
327 |
} else if (n == 0) { /* AutoSelect */ |
328 |
break; |
329 |
} else { |
330 |
mod = dev_list[n-1].modp; |
331 |
dev = dev_list[n-1].devinfop; |
332 |
status = mod->load(PATH_LOADER_EFI,dev, bufp, bufsize); |
333 |
if (status == EFI_SUCCESS) { |
334 |
break; |
335 |
} |
336 |
printf("Failed to load '%s'\n", PATH_LOADER_EFI); |
337 |
printf("Please select again: "); |
338 |
time_left = -1; |
339 |
} |
340 |
} |
341 |
if (n == 0) { /* AutoSelect */ |
342 |
status = load_loader(modp, devinfop, bufp, bufsize, TRUE); |
343 |
if (status != EFI_SUCCESS) { |
344 |
status = load_loader(modp, devinfop, bufp, bufsize, FALSE); |
345 |
} |
346 |
} else { |
347 |
*modp = dev_list[n-1].modp; |
348 |
*devinfop = dev_list[n-1].devinfop; |
349 |
status = EFI_SUCCESS; |
350 |
} |
351 |
return (status); |
352 |
} |
353 |
|
354 |
/* |
49 |
* probe_handle determines if the passed handle represents a logical partition |
355 |
* 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 |
356 |
* if it does it uses each module in order to probe it and if successful it |
51 |
* returns EFI_SUCCESS. |
357 |
* returns EFI_SUCCESS. |
Lines 210-222
Link Here
|
210 |
boot_modules[i]->status(); |
516 |
boot_modules[i]->status(); |
211 |
} |
517 |
} |
212 |
|
518 |
|
213 |
status = load_loader(&mod, &dev, &loaderbuf, &loadersize, 1); |
519 |
status = select_loader(&mod, &dev, &loaderbuf, &loadersize); |
214 |
if (status != EFI_SUCCESS) { |
520 |
if (status != EFI_SUCCESS) { |
215 |
status = load_loader(&mod, &dev, &loaderbuf, &loadersize, 0); |
521 |
printf("Failed to load '%s'\n", PATH_LOADER_EFI); |
216 |
if (status != EFI_SUCCESS) { |
522 |
return; |
217 |
printf("Failed to load '%s'\n", PATH_LOADER_EFI); |
|
|
218 |
return; |
219 |
} |
220 |
} |
523 |
} |
221 |
|
524 |
|
222 |
try_boot(mod, dev, loaderbuf, loadersize); |
525 |
try_boot(mod, dev, loaderbuf, loadersize); |