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

Collapse All | Expand All

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

Return to bug 207940