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

Collapse All | Expand All

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

Return to bug 207940