|
|
1.1 root 1: // Code to load disk image and start system boot.
2: //
1.1.1.4 ! root 3: // Copyright (C) 2008-2010 Kevin O'Connor <[email protected]>
1.1 root 4: // Copyright (C) 2002 MandrakeSoft S.A.
5: //
6: // This file may be distributed under the terms of the GNU LGPLv3 license.
7:
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
15: #include "paravirt.h"
16:
17: struct ipl_s IPL;
18:
19:
20: /****************************************************************
21: * IPL and BCV handlers
22: ****************************************************************/
23:
24: void
1.1.1.2 root 25: boot_setup(void)
1.1 root 26: {
27: if (! CONFIG_BOOT)
28: return;
29: dprintf(3, "init boot device ordering\n");
30:
31: memset(&IPL, 0, sizeof(IPL));
1.1.1.3 root 32: struct ipl_entry_s *ie = &IPL.bev[0];
1.1 root 33:
34: // Floppy drive
35: ie->type = IPL_TYPE_FLOPPY;
36: ie->description = "Floppy";
37: ie++;
38:
39: // First HDD
40: ie->type = IPL_TYPE_HARDDISK;
41: ie->description = "Hard Disk";
42: ie++;
43:
44: // CDROM
45: if (CONFIG_CDROM_BOOT) {
46: ie->type = IPL_TYPE_CDROM;
1.1.1.3 root 47: ie->description = "DVD/CD";
1.1 root 48: ie++;
49: }
50:
1.1.1.3 root 51: if (CONFIG_COREBOOT && CONFIG_COREBOOT_FLASH) {
1.1 root 52: ie->type = IPL_TYPE_CBFS;
53: ie->description = "CBFS";
54: ie++;
55: }
56:
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;
63: } else {
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;
69: }
70: }
71:
72: // Add a BEV vector for a given pnp compatible option rom.
73: void
74: add_bev(u16 seg, u16 bev, u16 desc)
75: {
76: if (! CONFIG_BOOT)
77: return;
78: if (IPL.bevcount >= ARRAY_SIZE(IPL.bev))
79: return;
80:
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";
85: if (desc)
86: d = MAKE_FLATPTR(seg, desc);
87: ie->description = d;
88: }
89:
90: // Add a bcv entry for an expansion card harddrive or legacy option rom
91: void
92: add_bcv(u16 seg, u16 ip, u16 desc)
93: {
94: if (! CONFIG_BOOT)
95: return;
96: if (IPL.bcvcount >= ARRAY_SIZE(IPL.bcv))
97: return;
98:
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";
103: if (desc)
104: d = MAKE_FLATPTR(seg, desc);
105: ie->description = d;
106: }
107:
108: // Add a bcv entry for an internal harddrive
109: void
110: add_bcv_internal(struct drive_s *drive_g)
111: {
112: if (! CONFIG_BOOT)
113: return;
114: if (IPL.bcvcount >= ARRAY_SIZE(IPL.bcv))
115: return;
116:
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;
121: for (;;) {
122: struct ipl_entry_s *prev = ie - 1;
123: if (prev < IPL.bcv || prev->type != BCV_TYPE_INTERNAL)
124: break;
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))
129: break;
130: ie--;
131: }
132: if (ie != end)
133: memmove(ie+1, ie, (void*)end-(void*)ie);
134: }
135: ie->type = BCV_TYPE_INTERNAL;
136: ie->vector = (u32)drive_g;
137: ie->description = "";
138: }
139:
140:
141: /****************************************************************
142: * Boot menu and BCV execution
143: ****************************************************************/
144:
145: // Show a generic menu item
146: static int
147: menu_show_default(struct ipl_entry_s *ie, int menupos)
148: {
149: char desc[33];
150: printf("%d. %s\n", menupos
151: , strtcpy(desc, ie->description, ARRAY_SIZE(desc)));
152: return 1;
153: }
154:
155: // Show floppy menu item - but only if there exists a floppy drive.
156: static int
157: menu_show_floppy(struct ipl_entry_s *ie, int menupos)
158: {
159: int i;
160: for (i = 0; i < Drives.floppycount; i++) {
161: struct drive_s *drive_g = getDrive(EXTTYPE_FLOPPY, i);
1.1.1.3 root 162: printf("%d. Floppy [%s]\n", menupos + i, drive_g->desc);
1.1 root 163: }
164: return Drives.floppycount;
165: }
166:
167: // Show menu items from BCV list.
168: static int
169: menu_show_harddisk(struct ipl_entry_s *ie, int menupos)
170: {
171: int i;
172: for (i = 0; i < IPL.bcvcount; i++) {
173: struct ipl_entry_s *ie = &IPL.bcv[i];
1.1.1.3 root 174: struct drive_s *drive_g = (void*)ie->vector;
1.1 root 175: switch (ie->type) {
176: case BCV_TYPE_INTERNAL:
1.1.1.3 root 177: printf("%d. %s\n", menupos + i, drive_g->desc);
1.1 root 178: break;
179: default:
180: menu_show_default(ie, menupos+i);
181: break;
182: }
183: }
184: return IPL.bcvcount;
185: }
186:
187: // Show cdrom menu item - but only if there exists a cdrom drive.
188: static int
189: menu_show_cdrom(struct ipl_entry_s *ie, int menupos)
190: {
191: int i;
192: for (i = 0; i < Drives.cdcount; i++) {
193: struct drive_s *drive_g = getDrive(EXTTYPE_CD, i);
1.1.1.3 root 194: printf("%d. DVD/CD [%s]\n", menupos + i, drive_g->desc);
1.1 root 195: }
196: return Drives.cdcount;
197: }
198:
199: // Show coreboot-fs menu item.
200: static int
201: menu_show_cbfs(struct ipl_entry_s *ie, int menupos)
202: {
203: int count = 0;
204: struct cbfs_file *file = NULL;
205: for (;;) {
206: file = cbfs_findprefix("img/", file);
207: if (!file)
208: break;
209: const char *filename = cbfs_filename(file);
210: printf("%d. Payload [%s]\n", menupos + count, &filename[4]);
211: count++;
212: if (count > 8)
213: break;
214: }
215: return count;
216: }
217:
218: // Show IPL option menu.
219: static void
1.1.1.2 root 220: interactive_bootmenu(void)
1.1 root 221: {
222: if (! CONFIG_BOOTMENU || ! qemu_cfg_show_boot_menu())
223: return;
224:
225: while (get_keystroke(0) >= 0)
226: ;
227:
228: printf("Press F12 for boot menu.\n\n");
229:
1.1.1.4 ! root 230: enable_bootsplash();
1.1 root 231: int scan_code = get_keystroke(CONFIG_BOOTMENU_WAIT);
1.1.1.4 ! root 232: disable_bootsplash();
1.1 root 233: if (scan_code != 0x86)
234: /* not F12 */
235: return;
236:
237: while (get_keystroke(0) >= 0)
238: ;
239:
240: printf("Select boot device:\n\n");
1.1.1.3 root 241: wait_threads();
1.1 root 242:
243: int subcount[ARRAY_SIZE(IPL.bev)];
244: int menupos = 1;
245: int i;
246: for (i = 0; i < IPL.bevcount; i++) {
247: struct ipl_entry_s *ie = &IPL.bev[i];
248: int sc;
249: switch (ie->type) {
250: case IPL_TYPE_FLOPPY:
251: sc = menu_show_floppy(ie, menupos);
252: break;
253: case IPL_TYPE_HARDDISK:
254: sc = menu_show_harddisk(ie, menupos);
255: break;
256: case IPL_TYPE_CDROM:
257: sc = menu_show_cdrom(ie, menupos);
258: break;
259: case IPL_TYPE_CBFS:
260: sc = menu_show_cbfs(ie, menupos);
261: break;
262: default:
263: sc = menu_show_default(ie, menupos);
264: break;
265: }
266: subcount[i] = sc;
267: menupos += sc;
268: }
269:
270: for (;;) {
271: scan_code = get_keystroke(1000);
272: if (scan_code == 0x01)
273: // ESC
274: break;
275: if (scan_code < 1 || scan_code > menupos)
276: continue;
277: int choice = scan_code - 1;
278:
279: // Find out which IPL this was for.
280: int bev = 0;
281: while (choice > subcount[bev]) {
282: choice -= subcount[bev];
283: bev++;
284: }
285: IPL.bev[bev].subchoice = choice-1;
286:
287: // Add user choice to the boot order.
288: IPL.bootorder = (IPL.bootorder << 4) | (bev+1);
289: break;
290: }
291: printf("\n");
292: }
293:
294: // Run the specified bcv.
295: static void
296: run_bcv(struct ipl_entry_s *ie)
297: {
298: switch (ie->type) {
299: case BCV_TYPE_INTERNAL:
300: map_hd_drive((void*)ie->vector);
301: break;
302: case BCV_TYPE_EXTERNAL:
303: call_bcv(ie->vector >> 16, ie->vector & 0xffff);
304: break;
305: }
306: }
307:
308: // Prepare for boot - show menu and run bcvs.
309: void
1.1.1.2 root 310: boot_prep(void)
1.1 root 311: {
1.1.1.3 root 312: if (! CONFIG_BOOT) {
313: wait_threads();
1.1 root 314: return;
1.1.1.3 root 315: }
1.1 root 316:
317: // XXX - show available drives?
318:
319: // Allow user to modify BCV/IPL order.
320: interactive_bootmenu();
1.1.1.3 root 321: wait_threads();
1.1 root 322:
323: // Setup floppy boot order
324: int override = IPL.bev[0].subchoice;
1.1.1.3 root 325: struct drive_s *tmp = Drives.idmap[EXTTYPE_FLOPPY][0];
1.1 root 326: Drives.idmap[EXTTYPE_FLOPPY][0] = Drives.idmap[EXTTYPE_FLOPPY][override];
327: Drives.idmap[EXTTYPE_FLOPPY][override] = tmp;
328:
329: // Run BCVs
330: override = IPL.bev[1].subchoice;
331: if (override < IPL.bcvcount)
332: run_bcv(&IPL.bcv[override]);
333: int i;
334: for (i=0; i<IPL.bcvcount; i++)
335: if (i != override)
336: run_bcv(&IPL.bcv[i]);
337: }
338:
339:
340: /****************************************************************
341: * Boot code (int 18/19)
342: ****************************************************************/
343:
344: // Jump to a bootup entry point.
345: static void
346: call_boot_entry(u16 bootseg, u16 bootip, u8 bootdrv)
347: {
348: dprintf(1, "Booting from %04x:%04x\n", bootseg, bootip);
349: struct bregs br;
350: memset(&br, 0, sizeof(br));
351: br.flags = F_IF;
352: br.code = SEGOFF(bootseg, bootip);
353: // Set the magic number in ax and the boot drive in dl.
354: br.dl = bootdrv;
355: br.ax = 0xaa55;
356: call16(&br);
357: }
358:
359: // Boot from a disk (either floppy or harddrive)
360: static void
361: boot_disk(u8 bootdrv, int checksig)
362: {
363: u16 bootseg = 0x07c0;
364:
365: // Read sector
366: struct bregs br;
367: memset(&br, 0, sizeof(br));
368: br.flags = F_IF;
369: br.dl = bootdrv;
370: br.es = bootseg;
371: br.ah = 2;
372: br.al = 1;
373: br.cl = 1;
374: call16_int(0x13, &br);
375:
376: if (br.flags & F_CF) {
377: printf("Boot failed: could not read the boot disk\n\n");
378: return;
379: }
380:
381: if (checksig) {
382: struct mbr_s *mbr = (void*)0;
383: if (GET_FARVAR(bootseg, mbr->signature) != MBR_SIGNATURE) {
384: printf("Boot failed: not a bootable disk\n\n");
385: return;
386: }
387: }
388:
389: /* Canonicalize bootseg:bootip */
390: u16 bootip = (bootseg & 0x0fff) << 4;
391: bootseg &= 0xf000;
392:
393: call_boot_entry(bootseg, bootip, bootdrv);
394: }
395:
396: // Boot from a CD-ROM
397: static void
398: boot_cdrom(struct ipl_entry_s *ie)
399: {
400: if (! CONFIG_CDROM_BOOT)
401: return;
402: int status = cdrom_boot(ie->subchoice);
403: if (status) {
404: printf("Boot failed: Could not read from CDROM (code %04x)\n", status);
405: return;
406: }
407:
408: u16 ebda_seg = get_ebda_seg();
409: u8 bootdrv = GET_EBDA2(ebda_seg, cdemu.emulated_extdrive);
410: u16 bootseg = GET_EBDA2(ebda_seg, cdemu.load_segment);
411: /* Canonicalize bootseg:bootip */
412: u16 bootip = (bootseg & 0x0fff) << 4;
413: bootseg &= 0xf000;
414:
415: call_boot_entry(bootseg, bootip, bootdrv);
416: }
417:
418: // Boot from a CBFS payload
419: static void
420: boot_cbfs(struct ipl_entry_s *ie)
421: {
1.1.1.3 root 422: if (!CONFIG_COREBOOT || !CONFIG_COREBOOT_FLASH)
1.1 root 423: return;
424: int count = ie->subchoice;
425: struct cbfs_file *file = NULL;
426: for (;;) {
427: file = cbfs_findprefix("img/", file);
428: if (!file)
429: return;
430: if (count--)
431: continue;
432: cbfs_run_payload(file);
433: }
434: }
435:
436: static void
437: do_boot(u16 seq_nr)
438: {
439: if (! CONFIG_BOOT)
440: panic("Boot support not compiled in.\n");
441:
442: u32 bootdev = IPL.bootorder;
443: bootdev >>= 4 * seq_nr;
444: bootdev &= 0xf;
445:
446: /* Translate bootdev to an IPL table offset by subtracting 1 */
447: bootdev -= 1;
448:
449: if (bootdev >= IPL.bevcount) {
450: printf("No bootable device.\n");
451: // Loop with irqs enabled - this allows ctrl+alt+delete to work.
452: for (;;)
1.1.1.3 root 453: wait_irq();
1.1 root 454: }
455:
456: /* Do the loading, and set up vector as a far pointer to the boot
457: * address, and bootdrv as the boot drive */
458: struct ipl_entry_s *ie = &IPL.bev[bootdev];
459: char desc[33];
460: printf("Booting from %s...\n"
461: , strtcpy(desc, ie->description, ARRAY_SIZE(desc)));
462:
1.1.1.4 ! root 463: switch (ie->type) {
1.1 root 464: case IPL_TYPE_FLOPPY:
465: boot_disk(0x00, IPL.checkfloppysig);
466: break;
467: case IPL_TYPE_HARDDISK:
468: boot_disk(0x80, 1);
469: break;
470: case IPL_TYPE_CDROM:
471: boot_cdrom(ie);
472: break;
473: case IPL_TYPE_CBFS:
474: boot_cbfs(ie);
475: break;
476: case IPL_TYPE_BEV:
477: call_boot_entry(ie->vector >> 16, ie->vector & 0xffff, 0);
478: break;
479: }
480:
481: // Boot failed: invoke the boot recovery function
482: struct bregs br;
483: memset(&br, 0, sizeof(br));
484: br.flags = F_IF;
485: call16_int(0x18, &br);
486: }
487:
488: // Boot Failure recovery: try the next device.
1.1.1.2 root 489: void VISIBLE32FLAT
490: handle_18(void)
1.1 root 491: {
492: debug_serial_setup();
493: debug_enter(NULL, DEBUG_HDL_18);
494: u16 ebda_seg = get_ebda_seg();
495: u16 seq = GET_EBDA2(ebda_seg, boot_sequence) + 1;
496: SET_EBDA2(ebda_seg, boot_sequence, seq);
497: do_boot(seq);
498: }
499:
500: // INT 19h Boot Load Service Entry Point
1.1.1.2 root 501: void VISIBLE32FLAT
502: handle_19(void)
1.1 root 503: {
504: debug_serial_setup();
505: debug_enter(NULL, DEBUG_HDL_19);
506: SET_EBDA(boot_sequence, 0);
507: do_boot(0);
508: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.