|
|
1.1 root 1: // Code to load disk image and start system boot.
2: //
3: // Copyright (C) 2008 Kevin O'Connor <[email protected]>
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
25: boot_setup()
26: {
27: if (! CONFIG_BOOT)
28: return;
29: dprintf(3, "init boot device ordering\n");
30:
31: memset(&IPL, 0, sizeof(IPL));
32:
33: // Floppy drive
34: struct ipl_entry_s *ie = &IPL.bev[0];
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;
47: ie->description = "CD-Rom";
48: ie++;
49: }
50:
51: if (CONFIG_COREBOOT_FLASH) {
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);
162: printf("%d. Floppy [", menupos + i);
163: describe_drive(drive_g);
164: printf("]\n");
165: }
166: return Drives.floppycount;
167: }
168:
169: // Show menu items from BCV list.
170: static int
171: menu_show_harddisk(struct ipl_entry_s *ie, int menupos)
172: {
173: int i;
174: for (i = 0; i < IPL.bcvcount; i++) {
175: struct ipl_entry_s *ie = &IPL.bcv[i];
176: switch (ie->type) {
177: case BCV_TYPE_INTERNAL:
178: printf("%d. ", menupos + i);
179: describe_drive((void*)ie->vector);
180: printf("\n");
181: break;
182: default:
183: menu_show_default(ie, menupos+i);
184: break;
185: }
186: }
187: return IPL.bcvcount;
188: }
189:
190: // Show cdrom menu item - but only if there exists a cdrom drive.
191: static int
192: menu_show_cdrom(struct ipl_entry_s *ie, int menupos)
193: {
194: int i;
195: for (i = 0; i < Drives.cdcount; i++) {
196: struct drive_s *drive_g = getDrive(EXTTYPE_CD, i);
197: printf("%d. CD-Rom [", menupos + i);
198: describe_drive(drive_g);
199: printf("]\n");
200: }
201: return Drives.cdcount;
202: }
203:
204: // Show coreboot-fs menu item.
205: static int
206: menu_show_cbfs(struct ipl_entry_s *ie, int menupos)
207: {
208: int count = 0;
209: struct cbfs_file *file = NULL;
210: for (;;) {
211: file = cbfs_findprefix("img/", file);
212: if (!file)
213: break;
214: const char *filename = cbfs_filename(file);
215: printf("%d. Payload [%s]\n", menupos + count, &filename[4]);
216: count++;
217: if (count > 8)
218: break;
219: }
220: return count;
221: }
222:
223: // Show IPL option menu.
224: static void
225: interactive_bootmenu()
226: {
227: if (! CONFIG_BOOTMENU || ! qemu_cfg_show_boot_menu())
228: return;
229:
230: while (get_keystroke(0) >= 0)
231: ;
232:
233: printf("Press F12 for boot menu.\n\n");
234:
235: int scan_code = get_keystroke(CONFIG_BOOTMENU_WAIT);
236: if (scan_code != 0x86)
237: /* not F12 */
238: return;
239:
240: while (get_keystroke(0) >= 0)
241: ;
242:
243: printf("Select boot device:\n\n");
244:
245: int subcount[ARRAY_SIZE(IPL.bev)];
246: int menupos = 1;
247: int i;
248: for (i = 0; i < IPL.bevcount; i++) {
249: struct ipl_entry_s *ie = &IPL.bev[i];
250: int sc;
251: switch (ie->type) {
252: case IPL_TYPE_FLOPPY:
253: sc = menu_show_floppy(ie, menupos);
254: break;
255: case IPL_TYPE_HARDDISK:
256: sc = menu_show_harddisk(ie, menupos);
257: break;
258: case IPL_TYPE_CDROM:
259: sc = menu_show_cdrom(ie, menupos);
260: break;
261: case IPL_TYPE_CBFS:
262: sc = menu_show_cbfs(ie, menupos);
263: break;
264: default:
265: sc = menu_show_default(ie, menupos);
266: break;
267: }
268: subcount[i] = sc;
269: menupos += sc;
270: }
271:
272: for (;;) {
273: scan_code = get_keystroke(1000);
274: if (scan_code == 0x01)
275: // ESC
276: break;
277: if (scan_code < 1 || scan_code > menupos)
278: continue;
279: int choice = scan_code - 1;
280:
281: // Find out which IPL this was for.
282: int bev = 0;
283: while (choice > subcount[bev]) {
284: choice -= subcount[bev];
285: bev++;
286: }
287: IPL.bev[bev].subchoice = choice-1;
288:
289: // Add user choice to the boot order.
290: IPL.bootorder = (IPL.bootorder << 4) | (bev+1);
291: break;
292: }
293: printf("\n");
294: }
295:
296: // Run the specified bcv.
297: static void
298: run_bcv(struct ipl_entry_s *ie)
299: {
300: switch (ie->type) {
301: case BCV_TYPE_INTERNAL:
302: map_hd_drive((void*)ie->vector);
303: break;
304: case BCV_TYPE_EXTERNAL:
305: call_bcv(ie->vector >> 16, ie->vector & 0xffff);
306: break;
307: }
308: }
309:
310: // Prepare for boot - show menu and run bcvs.
311: void
312: boot_prep()
313: {
314: if (! CONFIG_BOOT)
315: return;
316:
317: // XXX - show available drives?
318:
319: // Allow user to modify BCV/IPL order.
320: interactive_bootmenu();
321:
322: // Setup floppy boot order
323: int override = IPL.bev[0].subchoice;
324: int tmp = Drives.idmap[EXTTYPE_FLOPPY][0];
325: Drives.idmap[EXTTYPE_FLOPPY][0] = Drives.idmap[EXTTYPE_FLOPPY][override];
326: Drives.idmap[EXTTYPE_FLOPPY][override] = tmp;
327:
328: // Run BCVs
329: override = IPL.bev[1].subchoice;
330: if (override < IPL.bcvcount)
331: run_bcv(&IPL.bcv[override]);
332: int i;
333: for (i=0; i<IPL.bcvcount; i++)
334: if (i != override)
335: run_bcv(&IPL.bcv[i]);
336: }
337:
338:
339: /****************************************************************
340: * Boot code (int 18/19)
341: ****************************************************************/
342:
343: // Jump to a bootup entry point.
344: static void
345: call_boot_entry(u16 bootseg, u16 bootip, u8 bootdrv)
346: {
347: dprintf(1, "Booting from %04x:%04x\n", bootseg, bootip);
348:
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: {
422: if (! CONFIG_COREBOOT_FLASH)
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 (;;)
453: biosusleep(1000000);
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:
463: switch(ie->type) {
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.
489: void VISIBLE32
490: handle_18()
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
501: void VISIBLE32
502: handle_19()
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.