1
// Code to load disk image and start system boot.
3
// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
4
// Copyright (C) 2002 MandrakeSoft S.A.
6
// This file may be distributed under the terms of the GNU LGPLv3 license.
8
#include "util.h" // dprintf
9
#include "biosvar.h" // GET_EBDA
10
#include "config.h" // CONFIG_*
11
#include "disk.h" // cdrom_boot
12
#include "bregs.h" // struct bregs
13
#include "boot.h" // struct ipl_s
14
#include "cmos.h" // inb_cmos
20
/****************************************************************
21
* IPL and BCV handlers
22
****************************************************************/
29
dprintf(3, "init boot device ordering\n");
31
memset(&IPL, 0, sizeof(IPL));
34
struct ipl_entry_s *ie = &IPL.bev[0];
35
ie->type = IPL_TYPE_FLOPPY;
36
ie->description = "Floppy";
40
ie->type = IPL_TYPE_HARDDISK;
41
ie->description = "Hard Disk";
45
if (CONFIG_CDROM_BOOT) {
46
ie->type = IPL_TYPE_CDROM;
47
ie->description = "CD-Rom";
51
if (CONFIG_COREBOOT && CONFIG_COREBOOT_FLASH) {
52
ie->type = IPL_TYPE_CBFS;
53
ie->description = "CBFS";
57
IPL.bevcount = ie - IPL.bev;
58
SET_EBDA(boot_sequence, 0xffff);
59
if (CONFIG_COREBOOT) {
60
// XXX - hardcode defaults for coreboot.
61
IPL.bootorder = 0x87654231;
62
IPL.checkfloppysig = 1;
64
// On emulators, get boot order from nvram.
65
IPL.bootorder = (inb_cmos(CMOS_BIOS_BOOTFLAG2)
66
| ((inb_cmos(CMOS_BIOS_BOOTFLAG1) & 0xf0) << 4));
67
if (!(inb_cmos(CMOS_BIOS_BOOTFLAG1) & 1))
68
IPL.checkfloppysig = 1;
72
// Add a BEV vector for a given pnp compatible option rom.
74
add_bev(u16 seg, u16 bev, u16 desc)
78
if (IPL.bevcount >= ARRAY_SIZE(IPL.bev))
81
struct ipl_entry_s *ie = &IPL.bev[IPL.bevcount++];
82
ie->type = IPL_TYPE_BEV;
83
ie->vector = (seg << 16) | bev;
84
const char *d = "Unknown";
86
d = MAKE_FLATPTR(seg, desc);
90
// Add a bcv entry for an expansion card harddrive or legacy option rom
92
add_bcv(u16 seg, u16 ip, u16 desc)
96
if (IPL.bcvcount >= ARRAY_SIZE(IPL.bcv))
99
struct ipl_entry_s *ie = &IPL.bcv[IPL.bcvcount++];
100
ie->type = BCV_TYPE_EXTERNAL;
101
ie->vector = (seg << 16) | ip;
102
const char *d = "Legacy option rom";
104
d = MAKE_FLATPTR(seg, desc);
108
// Add a bcv entry for an internal harddrive
110
add_bcv_internal(struct drive_s *drive_g)
114
if (IPL.bcvcount >= ARRAY_SIZE(IPL.bcv))
117
struct ipl_entry_s *ie = &IPL.bcv[IPL.bcvcount++];
118
if (CONFIG_THREADS) {
119
// Add to bcv list with assured drive order.
120
struct ipl_entry_s *end = ie;
122
struct ipl_entry_s *prev = ie - 1;
123
if (prev < IPL.bcv || prev->type != BCV_TYPE_INTERNAL)
125
struct drive_s *prevdrive = (void*)prev->vector;
126
if (prevdrive->type < drive_g->type
127
|| (prevdrive->type == drive_g->type
128
&& prevdrive->cntl_id < drive_g->cntl_id))
133
memmove(ie+1, ie, (void*)end-(void*)ie);
135
ie->type = BCV_TYPE_INTERNAL;
136
ie->vector = (u32)drive_g;
137
ie->description = "";
141
/****************************************************************
142
* Boot menu and BCV execution
143
****************************************************************/
145
// Show a generic menu item
147
menu_show_default(struct ipl_entry_s *ie, int menupos)
150
printf("%d. %s\n", menupos
151
, strtcpy(desc, ie->description, ARRAY_SIZE(desc)));
155
// Show floppy menu item - but only if there exists a floppy drive.
157
menu_show_floppy(struct ipl_entry_s *ie, int menupos)
160
for (i = 0; i < Drives.floppycount; i++) {
161
struct drive_s *drive_g = getDrive(EXTTYPE_FLOPPY, i);
162
printf("%d. Floppy [%s]\n", menupos + i, drive_g->desc);
164
return Drives.floppycount;
167
// Show menu items from BCV list.
169
menu_show_harddisk(struct ipl_entry_s *ie, int menupos)
172
for (i = 0; i < IPL.bcvcount; i++) {
173
struct ipl_entry_s *ie = &IPL.bcv[i];
174
struct drive_s *drive_g = (void*)ie->vector;
176
case BCV_TYPE_INTERNAL:
177
printf("%d. %s\n", menupos + i, drive_g->desc);
180
menu_show_default(ie, menupos+i);
187
// Show cdrom menu item - but only if there exists a cdrom drive.
189
menu_show_cdrom(struct ipl_entry_s *ie, int menupos)
192
for (i = 0; i < Drives.cdcount; i++) {
193
struct drive_s *drive_g = getDrive(EXTTYPE_CD, i);
194
printf("%d. CD-Rom [%s]\n", menupos + i, drive_g->desc);
196
return Drives.cdcount;
199
// Show coreboot-fs menu item.
201
menu_show_cbfs(struct ipl_entry_s *ie, int menupos)
204
struct cbfs_file *file = NULL;
206
file = cbfs_findprefix("img/", file);
209
const char *filename = cbfs_filename(file);
210
printf("%d. Payload [%s]\n", menupos + count, &filename[4]);
218
// Show IPL option menu.
220
interactive_bootmenu(void)
222
if (! CONFIG_BOOTMENU || ! qemu_cfg_show_boot_menu())
225
while (get_keystroke(0) >= 0)
228
printf("Press F12 for boot menu.\n\n");
230
int scan_code = get_keystroke(CONFIG_BOOTMENU_WAIT);
231
if (scan_code != 0x86)
235
while (get_keystroke(0) >= 0)
238
printf("Select boot device:\n\n");
241
int subcount[ARRAY_SIZE(IPL.bev)];
244
for (i = 0; i < IPL.bevcount; i++) {
245
struct ipl_entry_s *ie = &IPL.bev[i];
248
case IPL_TYPE_FLOPPY:
249
sc = menu_show_floppy(ie, menupos);
251
case IPL_TYPE_HARDDISK:
252
sc = menu_show_harddisk(ie, menupos);
255
sc = menu_show_cdrom(ie, menupos);
258
sc = menu_show_cbfs(ie, menupos);
261
sc = menu_show_default(ie, menupos);
269
scan_code = get_keystroke(1000);
270
if (scan_code == 0x01)
273
if (scan_code < 1 || scan_code > menupos)
275
int choice = scan_code - 1;
277
// Find out which IPL this was for.
279
while (choice > subcount[bev]) {
280
choice -= subcount[bev];
283
IPL.bev[bev].subchoice = choice-1;
285
// Add user choice to the boot order.
286
IPL.bootorder = (IPL.bootorder << 4) | (bev+1);
292
// Run the specified bcv.
294
run_bcv(struct ipl_entry_s *ie)
297
case BCV_TYPE_INTERNAL:
298
map_hd_drive((void*)ie->vector);
300
case BCV_TYPE_EXTERNAL:
301
call_bcv(ie->vector >> 16, ie->vector & 0xffff);
306
// Prepare for boot - show menu and run bcvs.
315
// XXX - show available drives?
317
// Allow user to modify BCV/IPL order.
318
interactive_bootmenu();
321
// Setup floppy boot order
322
int override = IPL.bev[0].subchoice;
323
struct drive_s *tmp = Drives.idmap[EXTTYPE_FLOPPY][0];
324
Drives.idmap[EXTTYPE_FLOPPY][0] = Drives.idmap[EXTTYPE_FLOPPY][override];
325
Drives.idmap[EXTTYPE_FLOPPY][override] = tmp;
328
override = IPL.bev[1].subchoice;
329
if (override < IPL.bcvcount)
330
run_bcv(&IPL.bcv[override]);
332
for (i=0; i<IPL.bcvcount; i++)
334
run_bcv(&IPL.bcv[i]);
338
/****************************************************************
339
* Boot code (int 18/19)
340
****************************************************************/
342
// Jump to a bootup entry point.
344
call_boot_entry(u16 bootseg, u16 bootip, u8 bootdrv)
346
dprintf(1, "Booting from %04x:%04x\n", bootseg, bootip);
349
memset(&br, 0, sizeof(br));
351
br.code = SEGOFF(bootseg, bootip);
352
// Set the magic number in ax and the boot drive in dl.
358
// Boot from a disk (either floppy or harddrive)
360
boot_disk(u8 bootdrv, int checksig)
362
u16 bootseg = 0x07c0;
366
memset(&br, 0, sizeof(br));
373
call16_int(0x13, &br);
375
if (br.flags & F_CF) {
376
printf("Boot failed: could not read the boot disk\n\n");
381
struct mbr_s *mbr = (void*)0;
382
if (GET_FARVAR(bootseg, mbr->signature) != MBR_SIGNATURE) {
383
printf("Boot failed: not a bootable disk\n\n");
388
/* Canonicalize bootseg:bootip */
389
u16 bootip = (bootseg & 0x0fff) << 4;
392
call_boot_entry(bootseg, bootip, bootdrv);
395
// Boot from a CD-ROM
397
boot_cdrom(struct ipl_entry_s *ie)
399
if (! CONFIG_CDROM_BOOT)
401
int status = cdrom_boot(ie->subchoice);
403
printf("Boot failed: Could not read from CDROM (code %04x)\n", status);
407
u16 ebda_seg = get_ebda_seg();
408
u8 bootdrv = GET_EBDA2(ebda_seg, cdemu.emulated_extdrive);
409
u16 bootseg = GET_EBDA2(ebda_seg, cdemu.load_segment);
410
/* Canonicalize bootseg:bootip */
411
u16 bootip = (bootseg & 0x0fff) << 4;
414
call_boot_entry(bootseg, bootip, bootdrv);
417
// Boot from a CBFS payload
419
boot_cbfs(struct ipl_entry_s *ie)
421
if (!CONFIG_COREBOOT || !CONFIG_COREBOOT_FLASH)
423
int count = ie->subchoice;
424
struct cbfs_file *file = NULL;
426
file = cbfs_findprefix("img/", file);
431
cbfs_run_payload(file);
439
panic("Boot support not compiled in.\n");
441
u32 bootdev = IPL.bootorder;
442
bootdev >>= 4 * seq_nr;
445
/* Translate bootdev to an IPL table offset by subtracting 1 */
448
if (bootdev >= IPL.bevcount) {
449
printf("No bootable device.\n");
450
// Loop with irqs enabled - this allows ctrl+alt+delete to work.
455
/* Do the loading, and set up vector as a far pointer to the boot
456
* address, and bootdrv as the boot drive */
457
struct ipl_entry_s *ie = &IPL.bev[bootdev];
459
printf("Booting from %s...\n"
460
, strtcpy(desc, ie->description, ARRAY_SIZE(desc)));
463
case IPL_TYPE_FLOPPY:
464
boot_disk(0x00, IPL.checkfloppysig);
466
case IPL_TYPE_HARDDISK:
476
call_boot_entry(ie->vector >> 16, ie->vector & 0xffff, 0);
480
// Boot failed: invoke the boot recovery function
482
memset(&br, 0, sizeof(br));
484
call16_int(0x18, &br);
487
// Boot Failure recovery: try the next device.
491
debug_serial_setup();
492
debug_enter(NULL, DEBUG_HDL_18);
493
u16 ebda_seg = get_ebda_seg();
494
u16 seq = GET_EBDA2(ebda_seg, boot_sequence) + 1;
495
SET_EBDA2(ebda_seg, boot_sequence, seq);
499
// INT 19h Boot Load Service Entry Point
503
debug_serial_setup();
504
debug_enter(NULL, DEBUG_HDL_19);
505
SET_EBDA(boot_sequence, 0);