View | Details | Raw Unified | Return to bug 207940 | Differences between
and this patch

Collapse All | Expand All

(-)stand/efi/boot1/proto.c (-6 / +393 lines)
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);

Return to bug 207940