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

Collapse All | Expand All

(-)stand/efi/boot1/boot1.c (-45 / +324 lines)
Lines 36-41 Link Here
36
36
37
static void efi_panic(EFI_STATUS s, const char *fmt, ...) __dead2 __printflike(2, 3);
37
static void efi_panic(EFI_STATUS s, const char *fmt, ...) __dead2 __printflike(2, 3);
38
38
39
static EFI_STATUS try_boot(const boot_module_t *mod, dev_info_t *dev, void *loaderbuf, size_t loadersize);
40
39
static const boot_module_t *boot_modules[] =
41
static const boot_module_t *boot_modules[] =
40
{
42
{
41
#ifdef EFI_ZFS_BOOT
43
#ifdef EFI_ZFS_BOOT
Lines 79-104 Link Here
79
}
81
}
80
82
81
/*
83
/*
82
 * nodes_match returns TRUE if the imgpath isn't NULL and the nodes match,
83
 * FALSE otherwise.
84
 */
85
static BOOLEAN
86
nodes_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath)
87
{
88
	size_t len;
89
90
	if (imgpath == NULL || imgpath->Type != devpath->Type ||
91
	    imgpath->SubType != devpath->SubType)
92
		return (FALSE);
93
94
	len = DevicePathNodeLength(imgpath);
95
	if (len != DevicePathNodeLength(devpath))
96
		return (FALSE);
97
98
	return (memcmp(imgpath, devpath, (size_t)len) == 0);
99
}
100
101
/*
102
 * device_paths_match returns TRUE if the imgpath isn't NULL and all nodes
84
 * device_paths_match returns TRUE if the imgpath isn't NULL and all nodes
103
 * in imgpath and devpath match up to their respective occurrences of a
85
 * in imgpath and devpath match up to their respective occurrences of a
104
 * media node, FALSE otherwise.
86
 * media node, FALSE otherwise.
Lines 115-121 Link Here
115
		    IsDevicePathType(devpath, MEDIA_DEVICE_PATH))
97
		    IsDevicePathType(devpath, MEDIA_DEVICE_PATH))
116
			return (TRUE);
98
			return (TRUE);
117
99
118
		if (!nodes_match(imgpath, devpath))
100
		if (!efi_devpath_match_node(imgpath, devpath))
119
			return (FALSE);
101
			return (FALSE);
120
102
121
		imgpath = NextDevicePathNode(imgpath);
103
		imgpath = NextDevicePathNode(imgpath);
Lines 125-144 Link Here
125
	return (FALSE);
107
	return (FALSE);
126
}
108
}
127
109
110
/* quick and dirty work for boot partition menu */
111
112
#define	NUM_DEV_LIST	35
113
#define	SELECT_TIMEOUT	10
114
115
typedef struct {
116
	const boot_module_t	*modp;
117
	dev_info_t		*devinfop;
118
} moddev_t;
119
120
static moddev_t dev_list[NUM_DEV_LIST];
121
122
static char *
123
humanize_number_kmgt(UINT64 size) {
124
	static char buf2[6];
125
	UINT64 size0;
126
127
	if (size < 1024)
128
		sprintf(buf2, "%luB", size);
129
	else if (size0 = (size*10+512)/1024, size0 < 100)
130
		sprintf(buf2, "%lu.%luK", size0 / 10, size0 % 10);
131
	else if (size0 = (size+512)/1024, size0 < 1024)
132
		sprintf(buf2, "%luK", size0);
133
	else if (size0 = (size*10/1024+512)/1024, size0 < 100)
134
		sprintf(buf2, "%lu.%luM", size0 / 10, size0 % 10);
135
	else if (size0 = (size/1024+512)/1024, size0 < 1024)
136
		sprintf(buf2, "%luM", size0);
137
	else if (size0 = (size*10/1024/1024+512)/1024, size0 < 100)
138
		sprintf(buf2, "%lu.%luG", size0 / 10, size0 % 10);
139
	else if (size0 = (size/1024/1024+512)/1024, size0 < 1024)
140
		sprintf(buf2, "%luG", size0);
141
	else if (size0 = (size*10/1024/1024/1024+512)/1024, size0 < 100)
142
		sprintf(buf2, "%lu.%luT", size0 / 10, size0 % 10);
143
	else
144
		sprintf(buf2, "%luT", (size/1024/1024/1024+512)/1024);
145
	return(buf2);
146
}
147
148
static char
149
idx2char(int i)
150
{
151
	return (i<10 ? '0'+i : 'a'+i-10);
152
}
153
154
static int
155
char2idx(char c)
156
{
157
	return ((c >= '0' && c <= '9') ? c - '0' :
158
	    (c >= 'A' && c <= 'Z') ? c - 'A' + 10 :
159
	    (c >= 'a' && c <= 'z') ? c - 'a' + 10 :
160
	    -1 );
161
}
162
163
static void
164
move_to_tol()
165
{
166
	SIMPLE_TEXT_OUTPUT_INTERFACE *conout;
167
	int x,y;
168
169
	conout = ST->ConOut;
170
	x = conout->Mode->CursorColumn;
171
	y = conout->Mode->CursorRow;
172
	conout->SetCursorPosition(conout, 0, y);
173
}
174
175
int
176
getchar(void)
177
{
178
	EFI_INPUT_KEY key;
179
	EFI_STATUS status;
180
	UINTN junk;
181
182
	/* Try to read a key stroke. We wait for one if none is pending. */
183
	status = ST->ConIn->ReadKeyStroke(ST->ConIn, &key);
184
	if (status == EFI_NOT_READY) {
185
		BS->WaitForEvent(1, &ST->ConIn->WaitForKey, &junk);
186
		status = ST->ConIn->ReadKeyStroke(ST->ConIn, &key);
187
	}
188
	switch (key.ScanCode) {
189
	case 0x17: /* ESC */
190
		return (0x1b);  /* esc */
191
	}
192
193
	/* this can return  */
194
	return (key.UnicodeChar);
195
}
196
128
/*
197
/*
129
 * devpath_last returns the last non-path end node in devpath.
198
 * Output of EFI_DEVICE_PATH_TO_TEXT_PROTOCOL is not easy to read.
199
 " I hope this looks better.
130
 */
200
 */
131
static EFI_DEVICE_PATH *
201
static int
132
devpath_last(EFI_DEVICE_PATH *devpath)
202
mediapath_node_str(char *buf, size_t size, EFI_DEVICE_PATH *devpath)
133
{
203
{
204
	switch (devpath->Type) {
205
	case MEDIA_DEVICE_PATH:
206
		switch (devpath->SubType) {
207
		case MEDIA_CDROM_DP: {
208
			CDROM_DEVICE_PATH *cdrom;
134
209
135
	while (!IsDevicePathEnd(NextDevicePathNode(devpath)))
210
			cdrom = (CDROM_DEVICE_PATH *)(void *)devpath;
136
		devpath = NextDevicePathNode(devpath);
211
			return snprintf(buf, size, "cdrom(%x)",
212
			    cdrom->BootEntry);
213
		}
214
		case MEDIA_HARDDRIVE_DP: {
215
			HARDDRIVE_DEVICE_PATH *hd;
137
216
138
	return (devpath);
217
			hd = (HARDDRIVE_DEVICE_PATH *)(void *)devpath;
218
			return snprintf(buf, size, "hd(p%d) (%s)",
219
			    hd->PartitionNumber,
220
			    humanize_number_kmgt(hd->PartitionSize * 512));
221
		}
222
		default:
223
			return snprintf(buf, size, "media(0x%02x)",
224
			    devpath->SubType);
225
		}
226
	}
227
228
	return snprintf(buf, size, "type(0x%02x, 0x%02x)", devpath->Type,
229
	    devpath->SubType);
139
}
230
}
140
231
141
/*
232
/*
233
 * mediapath_str is convenience method which returns the text description of
234
 * mediapath using a static buffer, so it isn't thread safe!
235
 */
236
char *
237
mediapath_str(EFI_DEVICE_PATH *devpath)
238
{
239
	static char buf[256];
240
241
	mediapath_node_str(buf, sizeof(buf), devpath);
242
243
	return buf;
244
}
245
246
static int
247
list_devices(void)
248
{
249
	UINTN i, j;
250
	dev_info_t *dev;
251
	const boot_module_t *mod;
252
253
	j = 0;
254
	for (i = 0; i < NUM_BOOT_MODULES; i++) {
255
		if (boot_modules[i] == NULL)
256
			continue;
257
		mod = boot_modules[i];
258
		for (dev = mod->devices(); dev != NULL; dev = dev->next) {
259
			dev_list[j].devinfop = dev;
260
			dev_list[j].modp = mod;
261
			j++;
262
			if (j >= NUM_DEV_LIST)
263
			    break;
264
		}
265
	}
266
267
	return (j);
268
}
269
270
271
static int
272
get_sel(int ndevs,int time_left)
273
{
274
	int i;
275
	int c, n;
276
	EFI_STATUS status;
277
	EFI_EVENT timer;
278
	EFI_EVENT events[2];
279
	EFI_DEVICE_PATH *mediapath;
280
	UINTN idx;
281
	dev_info_t *dev;
282
	CHAR16 *text;
283
284
	status = BS->CreateEvent(EVT_TIMER, 0, 0, NULL, &timer);
285
	if (status != EFI_SUCCESS) {
286
		printf("Can't allocate timer event.\n");
287
		return (-1);
288
	}
289
	printf("  0: AutoSelected Partition (Default): 0\n"); 
290
	for (i = 0; i < ndevs; i++) {
291
		if (dev_list[i].devinfop->preferred == TRUE)
292
			c = '*';
293
		else
294
			c = ' ';
295
		mediapath = efi_devpath_to_media_path(
296
		    dev_list[i].devinfop->devpath);
297
		printf(" %c%c: %s: %s: %c\n", c, idx2char(i+1),
298
		    dev_list[i].modp->name,
299
		    mediapath_str(mediapath),
300
		    idx2char(i+1));
301
	}
302
	/* One alpha-num selection only. Is this big enough ?? */
303
	BS->SetTimer(timer, TimerPeriodic, 10000000); 
304
	events[0] = timer;
305
	events[1] = ST->ConIn->WaitForKey;
306
307
	while (1) {
308
		if (time_left > 0) {
309
			printf("Select from 0 to %c. Timeout in %2d seconds,"
310
			       " [Space] to pause : ",
311
			       idx2char(ndevs), time_left);
312
		}
313
		status = BS->WaitForEvent(2, events, &idx);
314
		if (status != EFI_SUCCESS) {
315
			BS->CloseEvent(timer);
316
			return (-1);
317
		}
318
		if (idx == 0) {
319
			time_left--;
320
			if (time_left <=0) {
321
				printf("\nTimeout. "
322
				       "Partition is AutoSelected.\n");
323
				n = 0;
324
				break;
325
			} else {
326
				move_to_tol();
327
			}
328
		}
329
		if (idx == 1) {
330
			c = getchar();
331
			if ((c == '\n') || (c == '\r')) {
332
				putchar('\n');
333
				n = 0;
334
				break;
335
			} else if ((time_left > 0) && (c == ' ')) {
336
				BS->SetTimer(timer, TimerCancel, 0); 
337
				time_left = -1;
338
				printf("\nTimer stopeed.\n Please Key in: ");
339
			}
340
			n = char2idx(c);
341
			if ((n >= 0) && (n <= ndevs)) {
342
				BS->SetTimer(timer, TimerCancel, 0); 
343
				time_left = -1;
344
				printf("\n %c is selected.\n", c);
345
				break;
346
			} else {
347
				/* Invalid charecter. */
348
				move_to_tol();
349
			}
350
		}
351
	};
352
	BS->CloseEvent(timer);
353
	return (n);
354
}
355
356
/*
142
 * load_loader attempts to load the loader image data.
357
 * load_loader attempts to load the loader image data.
143
 *
358
 *
144
 * It tries each module and its respective devices, identified by mod->probe,
359
 * It tries each module and its respective devices, identified by mod->probe,
Lines 173-204 Link Here
173
	return (EFI_NOT_FOUND);
388
	return (EFI_NOT_FOUND);
174
}
389
}
175
390
391
static EFI_STATUS
392
select_loader(const boot_module_t **modp, dev_info_t **devinfop,
393
    void **bufp, size_t *bufsize)
394
{
395
	int n;
396
	int time_left;
397
	EFI_STATUS status;
398
	dev_info_t *dev;
399
	const boot_module_t *mod;
400
	int ndevs;
401
402
	ndevs = list_devices();
403
	if ((ndevs <= 0) || (ndevs >= NUM_DEV_LIST)) {
404
		return (EFI_NOT_FOUND);
405
	} else if (ndevs == 1) {
406
		/* Only one condidate. */
407
		*modp = mod = dev_list[0].modp;
408
		*devinfop = dev = dev_list[0].devinfop;
409
		return (mod->load(PATH_LOADER_EFI, dev,bufp, bufsize));
410
	}
411
412
	/* Two or more candidate exist. */
413
414
	/* Reset the console input. */
415
	ST->ConIn->Reset(ST->ConIn, TRUE);
416
417
	time_left = SELECT_TIMEOUT;
418
	while (1) {
419
		n = get_sel(ndevs, time_left);
420
		if (n < 0) {
421
			return (EFI_NOT_FOUND);
422
		} else if (n == 0) { /* AutoSelect */
423
			break;
424
		} else {
425
			mod = dev_list[n-1].modp;
426
			dev = dev_list[n-1].devinfop;
427
			status = mod->load(PATH_LOADER_EFI,dev, bufp, bufsize);
428
			if (status == EFI_SUCCESS) {
429
				break;
430
			}
431
			printf("Failed to load '%s'\n", PATH_LOADER_EFI);
432
			printf("Please select again: ");
433
			time_left = -1;
434
		}
435
	}
436
	if (n == 0) { /* AutoSelect */
437
		status = load_loader(modp, devinfop, bufp, bufsize, TRUE);
438
		if (status != EFI_SUCCESS) {
439
			status = load_loader(modp, devinfop, bufp, bufsize, FALSE);
440
		}
441
	} else {
442
		*modp = dev_list[n-1].modp;
443
		*devinfop = dev_list[n-1].devinfop;
444
		status = EFI_SUCCESS;
445
	}
446
	return (status);
447
}
448
449
void
450
sel_boot(void)
451
{
452
	size_t loadersize;
453
	void *loaderbuf = NULL;
454
	dev_info_t *dev;
455
	const boot_module_t *mod;
456
	EFI_STATUS status;
457
458
	status = select_loader(&mod, &dev, &loaderbuf, &loadersize);	
459
	if (status != EFI_SUCCESS) {
460
		printf("Failed to load '%s'\n", PATH_LOADER_EFI);
461
		return;
462
	}
463
464
	try_boot(mod, dev, loaderbuf, loadersize);
465
}
466
176
/*
467
/*
177
 * try_boot only returns if it fails to load the loader. If it succeeds
468
 * try_boot only returns if it fails to load the loader. If it succeeds
178
 * it simply boots, otherwise it returns the status of last EFI call.
469
 * it simply boots, otherwise it returns the status of last EFI call.
179
 */
470
 */
180
static EFI_STATUS
471
EFI_STATUS
181
try_boot(void)
472
try_boot(const boot_module_t *mod, dev_info_t *dev, void *loaderbuf, size_t loadersize)
182
{
473
{
183
	size_t bufsize, loadersize, cmdsize;
474
	size_t bufsize, cmdsize;
184
	void *buf, *loaderbuf;
475
	void *buf;
185
	char *cmd;
476
	char *cmd;
186
	dev_info_t *dev;
187
	const boot_module_t *mod;
188
	EFI_HANDLE loaderhandle;
477
	EFI_HANDLE loaderhandle;
189
	EFI_LOADED_IMAGE *loaded_image;
478
	EFI_LOADED_IMAGE *loaded_image;
190
	EFI_STATUS status;
479
	EFI_STATUS status;
191
480
192
	status = load_loader(&mod, &dev, &loaderbuf, &loadersize, TRUE);
193
	if (status != EFI_SUCCESS) {
194
		status = load_loader(&mod, &dev, &loaderbuf, &loadersize,
195
		    FALSE);
196
		if (status != EFI_SUCCESS) {
197
			printf("Failed to load '%s'\n", PATH_LOADER_EFI);
198
			return (status);
199
		}
200
	}
201
202
	/*
481
	/*
203
	 * Read in and parse the command line from /boot.config or /boot/config,
482
	 * Read in and parse the command line from /boot.config or /boot/config,
204
	 * if present. We'll pass it the next stage via a simple ASCII
483
	 * if present. We'll pass it the next stage via a simple ASCII
Lines 225-231 Link Here
225
		buf = NULL;
504
		buf = NULL;
226
	}
505
	}
227
506
228
	if ((status = BS->LoadImage(TRUE, IH, devpath_last(dev->devpath),
507
	if ((status = BS->LoadImage(TRUE, IH, efi_devpath_last_node(dev->devpath),
229
	    loaderbuf, loadersize, &loaderhandle)) != EFI_SUCCESS) {
508
	    loaderbuf, loadersize, &loaderhandle)) != EFI_SUCCESS) {
230
		printf("Failed to load image provided by %s, size: %zu, (%lu)\n",
509
		printf("Failed to load image provided by %s, size: %zu, (%lu)\n",
231
		     mod->name, loadersize, EFI_ERROR_CODE(status));
510
		     mod->name, loadersize, EFI_ERROR_CODE(status));
Lines 522-528 Link Here
522
		boot_modules[i]->status();
801
		boot_modules[i]->status();
523
	}
802
	}
524
803
525
	try_boot();
804
	sel_boot();
526
805
527
	/* If we get here, we're out of luck... */
806
	/* If we get here, we're out of luck... */
528
	efi_panic(EFI_LOAD_ERROR, "No bootable partitions found!");
807
	efi_panic(EFI_LOAD_ERROR, "No bootable partitions found!");

Return to bug 207940