|
|
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
1.1.1.5 root 13: #include "boot.h" // func defs
1.1 root 14: #include "cmos.h" // inb_cmos
1.1.1.5 root 15: #include "paravirt.h" // romfile_loadfile
16: #include "pci.h" //pci_bdf_to_*
1.1 root 17:
18:
19: /****************************************************************
1.1.1.5 root 20: * Boot priority ordering
1.1 root 21: ****************************************************************/
22:
1.1.1.5 root 23: static char **Bootorder;
24: static int BootorderCount;
25:
26: static void
27: loadBootOrder(void)
1.1 root 28: {
1.1.1.6 ! root 29: if (!CONFIG_BOOTORDER)
! 30: return;
! 31:
1.1.1.5 root 32: char *f = romfile_loadfile("bootorder", NULL);
33: if (!f)
1.1 root 34: return;
35:
1.1.1.5 root 36: int i = 0;
37: BootorderCount = 1;
38: while (f[i]) {
39: if (f[i] == '\n')
40: BootorderCount++;
41: i++;
42: }
43: Bootorder = malloc_tmphigh(BootorderCount*sizeof(char*));
44: if (!Bootorder) {
45: warn_noalloc();
46: free(f);
47: BootorderCount = 0;
48: return;
1.1 root 49: }
50:
1.1.1.5 root 51: dprintf(3, "boot order:\n");
52: i = 0;
53: do {
54: Bootorder[i] = f;
55: f = strchr(f, '\n');
56: if (f)
57: *(f++) = '\0';
58: nullTrailingSpace(Bootorder[i]);
59: dprintf(3, "%d: %s\n", i+1, Bootorder[i]);
60: i++;
61: } while (f);
62: }
63:
64: // See if 'str' starts with 'glob' - if glob contains an '*' character
65: // it will match any number of characters in str that aren't a '/' or
66: // the next glob character.
67: static char *
68: glob_prefix(const char *glob, const char *str)
69: {
70: for (;;) {
71: if (!*glob && (!*str || *str == '/'))
72: return (char*)str;
73: if (*glob == '*') {
74: if (!*str || *str == '/' || *str == glob[1])
75: glob++;
76: else
77: str++;
78: continue;
79: }
80: if (*glob != *str)
81: return NULL;
82: glob++;
83: str++;
1.1 root 84: }
1.1.1.5 root 85: }
1.1 root 86:
1.1.1.5 root 87: // Search the bootorder list for the given glob pattern.
88: static int
89: find_prio(const char *glob)
90: {
91: dprintf(1, "Searching bootorder for: %s\n", glob);
92: int i;
93: for (i = 0; i < BootorderCount; i++)
94: if (glob_prefix(glob, Bootorder[i]))
95: return i+1;
96: return -1;
97: }
98:
99: #define FW_PCI_DOMAIN "/pci@i0cf8"
100:
101: static char *
1.1.1.6 ! root 102: build_pci_path(char *buf, int max, const char *devname, struct pci_device *pci)
1.1.1.5 root 103: {
104: // Build the string path of a bdf - for example: /pci@i0cf8/isa@1,2
105: char *p = buf;
1.1.1.6 ! root 106: if (pci->parent) {
! 107: p = build_pci_path(p, max, "pci-bridge", pci->parent);
1.1 root 108: } else {
1.1.1.6 ! root 109: if (pci->rootbus)
! 110: p += snprintf(p, max, "/pci-root@%x", pci->rootbus);
1.1.1.5 root 111: p += snprintf(p, buf+max-p, "%s", FW_PCI_DOMAIN);
1.1 root 112: }
1.1.1.5 root 113:
1.1.1.6 ! root 114: int dev = pci_bdf_to_dev(pci->bdf), fn = pci_bdf_to_fn(pci->bdf);
1.1.1.5 root 115: p += snprintf(p, buf+max-p, "/%s@%x", devname, dev);
116: if (fn)
117: p += snprintf(p, buf+max-p, ",%x", fn);
118: return p;
1.1 root 119: }
120:
1.1.1.6 ! root 121: int bootprio_find_pci_device(struct pci_device *pci)
1.1 root 122: {
1.1.1.6 ! root 123: if (!CONFIG_BOOTORDER)
! 124: return -1;
1.1.1.5 root 125: // Find pci device - for example: /pci@i0cf8/ethernet@5
126: char desc[256];
1.1.1.6 ! root 127: build_pci_path(desc, sizeof(desc), "*", pci);
1.1.1.5 root 128: return find_prio(desc);
129: }
1.1 root 130:
1.1.1.6 ! root 131: int bootprio_find_ata_device(struct pci_device *pci, int chanid, int slave)
1.1.1.5 root 132: {
1.1.1.6 ! root 133: if (!CONFIG_BOOTORDER)
! 134: return -1;
! 135: if (!pci)
1.1.1.5 root 136: // support only pci machine for now
137: return -1;
138: // Find ata drive - for example: /pci@i0cf8/ide@1,1/drive@1/disk@0
139: char desc[256], *p;
1.1.1.6 ! root 140: p = build_pci_path(desc, sizeof(desc), "*", pci);
1.1.1.5 root 141: snprintf(p, desc+sizeof(desc)-p, "/drive@%x/disk@%x", chanid, slave);
142: return find_prio(desc);
1.1 root 143: }
144:
1.1.1.6 ! root 145: int bootprio_find_fdc_device(struct pci_device *pci, int port, int fdid)
1.1 root 146: {
1.1.1.6 ! root 147: if (!CONFIG_BOOTORDER)
! 148: return -1;
! 149: if (!pci)
1.1.1.5 root 150: // support only pci machine for now
151: return -1;
152: // Find floppy - for example: /pci@i0cf8/isa@1/fdc@03f1/floppy@0
153: char desc[256], *p;
1.1.1.6 ! root 154: p = build_pci_path(desc, sizeof(desc), "isa", pci);
1.1.1.5 root 155: snprintf(p, desc+sizeof(desc)-p, "/fdc@%04x/floppy@%x", port, fdid);
156: return find_prio(desc);
157: }
158:
1.1.1.6 ! root 159: int bootprio_find_pci_rom(struct pci_device *pci, int instance)
1.1.1.5 root 160: {
1.1.1.6 ! root 161: if (!CONFIG_BOOTORDER)
! 162: return -1;
1.1.1.5 root 163: // Find pci rom - for example: /pci@i0cf8/scsi@3:rom2
164: char desc[256], *p;
1.1.1.6 ! root 165: p = build_pci_path(desc, sizeof(desc), "*", pci);
1.1.1.5 root 166: if (instance)
167: snprintf(p, desc+sizeof(desc)-p, ":rom%d", instance);
168: return find_prio(desc);
169: }
170:
171: int bootprio_find_named_rom(const char *name, int instance)
172: {
1.1.1.6 ! root 173: if (!CONFIG_BOOTORDER)
! 174: return -1;
1.1.1.5 root 175: // Find named rom - for example: /rom@genroms/linuxboot.bin
176: char desc[256], *p;
177: p = desc + snprintf(desc, sizeof(desc), "/rom@%s", name);
178: if (instance)
179: snprintf(p, desc+sizeof(desc)-p, ":rom%d", instance);
180: return find_prio(desc);
181: }
1.1 root 182:
1.1.1.6 ! root 183: int bootprio_find_usb(struct pci_device *pci, u64 path)
1.1.1.5 root 184: {
1.1.1.6 ! root 185: if (!CONFIG_BOOTORDER)
! 186: return -1;
1.1.1.5 root 187: // Find usb - for example: /pci@i0cf8/usb@1,2/hub@1/network@0/ethernet@0
188: int i;
189: char desc[256], *p;
1.1.1.6 ! root 190: p = build_pci_path(desc, sizeof(desc), "usb", pci);
1.1.1.5 root 191: for (i=56; i>0; i-=8) {
192: int port = (path >> i) & 0xff;
193: if (port != 0xff)
194: p += snprintf(p, desc+sizeof(desc)-p, "/hub@%x", port);
195: }
196: snprintf(p, desc+sizeof(desc)-p, "/*@%x", (u32)(path & 0xff));
197: return find_prio(desc);
1.1 root 198: }
199:
1.1.1.5 root 200:
201: /****************************************************************
202: * Boot setup
203: ****************************************************************/
204:
205: static int CheckFloppySig = 1;
206:
207: #define DEFAULT_PRIO 9999
208:
209: static int DefaultFloppyPrio = 101;
210: static int DefaultCDPrio = 102;
211: static int DefaultHDPrio = 103;
212: static int DefaultBEVPrio = 104;
213:
1.1 root 214: void
1.1.1.5 root 215: boot_setup(void)
1.1 root 216: {
217: if (! CONFIG_BOOT)
218: return;
219:
1.1.1.5 root 220: SET_EBDA(boot_sequence, 0xffff);
221:
222: if (!CONFIG_COREBOOT) {
223: // On emulators, get boot order from nvram.
224: if (inb_cmos(CMOS_BIOS_BOOTFLAG1) & 1)
225: CheckFloppySig = 0;
226: u32 bootorder = (inb_cmos(CMOS_BIOS_BOOTFLAG2)
227: | ((inb_cmos(CMOS_BIOS_BOOTFLAG1) & 0xf0) << 4));
228: DefaultFloppyPrio = DefaultCDPrio = DefaultHDPrio
229: = DefaultBEVPrio = DEFAULT_PRIO;
230: int i;
231: for (i=101; i<104; i++) {
232: u32 val = bootorder & 0x0f;
233: bootorder >>= 4;
234: switch (val) {
235: case 1: DefaultFloppyPrio = i; break;
236: case 2: DefaultHDPrio = i; break;
237: case 3: DefaultCDPrio = i; break;
238: case 4: DefaultBEVPrio = i; break;
239: }
1.1 root 240: }
241: }
1.1.1.5 root 242:
243: loadBootOrder();
1.1 root 244: }
245:
246:
247: /****************************************************************
1.1.1.5 root 248: * BootList handling
1.1 root 249: ****************************************************************/
250:
1.1.1.5 root 251: struct bootentry_s {
252: int type;
253: union {
254: u32 data;
255: struct segoff_s vector;
256: struct drive_s *drive;
257: };
258: int priority;
259: const char *description;
260: struct bootentry_s *next;
261: };
262: static struct bootentry_s *BootList;
263:
264: #define IPL_TYPE_FLOPPY 0x01
265: #define IPL_TYPE_HARDDISK 0x02
266: #define IPL_TYPE_CDROM 0x03
267: #define IPL_TYPE_CBFS 0x20
268: #define IPL_TYPE_BEV 0x80
269: #define IPL_TYPE_BCV 0x81
270:
271: static void
272: bootentry_add(int type, int prio, u32 data, const char *desc)
1.1 root 273: {
1.1.1.5 root 274: if (! CONFIG_BOOT)
275: return;
276: struct bootentry_s *be = malloc_tmp(sizeof(*be));
277: if (!be) {
278: warn_noalloc();
279: return;
280: }
281: be->type = type;
282: be->priority = prio;
283: be->data = data;
284: be->description = desc ?: "?";
285: dprintf(3, "Registering bootable: %s (type:%d prio:%d data:%x)\n"
286: , be->description, type, prio, data);
287:
288: // Add entry in sorted order.
289: struct bootentry_s **pprev;
290: for (pprev = &BootList; *pprev; pprev = &(*pprev)->next) {
291: struct bootentry_s *pos = *pprev;
292: if (be->priority < pos->priority)
293: break;
294: if (be->priority > pos->priority)
295: continue;
296: if (be->type < pos->type)
297: break;
298: if (be->type > pos->type)
299: continue;
300: if (be->type <= IPL_TYPE_CDROM
301: && (be->drive->type < pos->drive->type
302: || (be->drive->type == pos->drive->type
303: && be->drive->cntl_id < pos->drive->cntl_id)))
304: break;
305: }
306: be->next = *pprev;
307: *pprev = be;
1.1 root 308: }
309:
1.1.1.5 root 310: // Return the given priority if it's set - defaultprio otherwise.
311: static inline int defPrio(int priority, int defaultprio) {
312: return (priority < 0) ? defaultprio : priority;
313: }
314:
315: // Add a BEV vector for a given pnp compatible option rom.
316: void
317: boot_add_bev(u16 seg, u16 bev, u16 desc, int prio)
1.1 root 318: {
1.1.1.5 root 319: bootentry_add(IPL_TYPE_BEV, defPrio(prio, DefaultBEVPrio)
320: , SEGOFF(seg, bev).segoff
321: , desc ? MAKE_FLATPTR(seg, desc) : "Unknown");
322: DefaultBEVPrio = DEFAULT_PRIO;
1.1 root 323: }
324:
1.1.1.5 root 325: // Add a bcv entry for an expansion card harddrive or legacy option rom
326: void
327: boot_add_bcv(u16 seg, u16 ip, u16 desc, int prio)
1.1 root 328: {
1.1.1.5 root 329: bootentry_add(IPL_TYPE_BCV, defPrio(prio, DEFAULT_PRIO)
330: , SEGOFF(seg, ip).segoff
331: , desc ? MAKE_FLATPTR(seg, desc) : "Legacy option rom");
1.1 root 332: }
333:
1.1.1.5 root 334: void
335: boot_add_floppy(struct drive_s *drive_g, const char *desc, int prio)
1.1 root 336: {
1.1.1.5 root 337: bootentry_add(IPL_TYPE_FLOPPY, defPrio(prio, DefaultFloppyPrio)
338: , (u32)drive_g, desc);
1.1 root 339: }
340:
1.1.1.5 root 341: void
342: boot_add_hd(struct drive_s *drive_g, const char *desc, int prio)
1.1 root 343: {
1.1.1.5 root 344: bootentry_add(IPL_TYPE_HARDDISK, defPrio(prio, DefaultHDPrio)
345: , (u32)drive_g, desc);
346: }
347:
348: void
349: boot_add_cd(struct drive_s *drive_g, const char *desc, int prio)
350: {
351: bootentry_add(IPL_TYPE_CDROM, defPrio(prio, DefaultCDPrio)
352: , (u32)drive_g, desc);
1.1 root 353: }
354:
1.1.1.5 root 355: // Add a CBFS payload entry
356: void
357: boot_add_cbfs(void *data, const char *desc, int prio)
358: {
359: bootentry_add(IPL_TYPE_CBFS, defPrio(prio, DEFAULT_PRIO), (u32)data, desc);
360: }
361:
362:
363: /****************************************************************
364: * Boot menu and BCV execution
365: ****************************************************************/
366:
1.1.1.6 ! root 367: #define DEFAULT_BOOTMENU_WAIT 2500
! 368:
1.1 root 369: // Show IPL option menu.
370: static void
1.1.1.2 root 371: interactive_bootmenu(void)
1.1 root 372: {
373: if (! CONFIG_BOOTMENU || ! qemu_cfg_show_boot_menu())
374: return;
375:
376: while (get_keystroke(0) >= 0)
377: ;
378:
379: printf("Press F12 for boot menu.\n\n");
380:
1.1.1.6 ! root 381: u32 menutime = romfile_loadint("etc/boot-menu-wait", DEFAULT_BOOTMENU_WAIT);
1.1.1.4 root 382: enable_bootsplash();
1.1.1.6 ! root 383: int scan_code = get_keystroke(menutime);
1.1.1.4 root 384: disable_bootsplash();
1.1 root 385: if (scan_code != 0x86)
386: /* not F12 */
387: return;
388:
389: while (get_keystroke(0) >= 0)
390: ;
391:
392: printf("Select boot device:\n\n");
1.1.1.3 root 393: wait_threads();
1.1 root 394:
1.1.1.5 root 395: // Show menu items
396: struct bootentry_s *pos = BootList;
397: int maxmenu = 0;
398: while (pos) {
399: char desc[60];
400: maxmenu++;
401: printf("%d. %s\n", maxmenu
402: , strtcpy(desc, pos->description, ARRAY_SIZE(desc)));
403: pos = pos->next;
1.1 root 404: }
405:
1.1.1.5 root 406: // Get key press
1.1 root 407: for (;;) {
408: scan_code = get_keystroke(1000);
1.1.1.5 root 409: if (scan_code >= 1 && scan_code <= maxmenu+1)
1.1 root 410: break;
411: }
412: printf("\n");
1.1.1.5 root 413: if (scan_code == 0x01)
414: // ESC
415: return;
416:
417: // Find entry and make top priority.
418: int choice = scan_code - 1;
419: struct bootentry_s **pprev = &BootList;
420: while (--choice)
421: pprev = &(*pprev)->next;
422: pos = *pprev;
423: *pprev = pos->next;
424: pos->next = BootList;
425: BootList = pos;
426: pos->priority = 0;
427: }
428:
429: // BEV (Boot Execution Vector) list
430: struct bev_s {
431: int type;
432: u32 vector;
433: };
434: static struct bev_s BEV[20];
435: static int BEVCount;
436: static int HaveHDBoot, HaveFDBoot;
1.1 root 437:
438: static void
1.1.1.5 root 439: add_bev(int type, u32 vector)
1.1 root 440: {
1.1.1.5 root 441: if (type == IPL_TYPE_HARDDISK && HaveHDBoot++)
442: return;
443: if (type == IPL_TYPE_FLOPPY && HaveFDBoot++)
444: return;
445: if (BEVCount >= ARRAY_SIZE(BEV))
446: return;
447: struct bev_s *bev = &BEV[BEVCount++];
448: bev->type = type;
449: bev->vector = vector;
1.1 root 450: }
451:
452: // Prepare for boot - show menu and run bcvs.
453: void
1.1.1.2 root 454: boot_prep(void)
1.1 root 455: {
1.1.1.3 root 456: if (! CONFIG_BOOT) {
457: wait_threads();
1.1 root 458: return;
1.1.1.3 root 459: }
1.1 root 460:
461: // XXX - show available drives?
462:
463: // Allow user to modify BCV/IPL order.
464: interactive_bootmenu();
1.1.1.3 root 465: wait_threads();
1.1 root 466:
1.1.1.5 root 467: // Map drives and populate BEV list
468: struct bootentry_s *pos = BootList;
469: while (pos) {
470: switch (pos->type) {
471: case IPL_TYPE_BCV:
472: call_bcv(pos->vector.seg, pos->vector.offset);
473: add_bev(IPL_TYPE_HARDDISK, 0);
474: break;
475: case IPL_TYPE_FLOPPY:
476: map_floppy_drive(pos->drive);
477: add_bev(IPL_TYPE_FLOPPY, 0);
478: break;
479: case IPL_TYPE_HARDDISK:
480: map_hd_drive(pos->drive);
481: add_bev(IPL_TYPE_HARDDISK, 0);
482: break;
483: case IPL_TYPE_CDROM:
484: map_cd_drive(pos->drive);
485: // NO BREAK
486: default:
487: add_bev(pos->type, pos->data);
488: break;
489: }
490: pos = pos->next;
491: }
492:
493: // If nothing added a floppy/hd boot - add it manually.
494: add_bev(IPL_TYPE_FLOPPY, 0);
495: add_bev(IPL_TYPE_HARDDISK, 0);
1.1 root 496: }
497:
498:
499: /****************************************************************
500: * Boot code (int 18/19)
501: ****************************************************************/
502:
503: // Jump to a bootup entry point.
504: static void
1.1.1.5 root 505: call_boot_entry(struct segoff_s bootsegip, u8 bootdrv)
1.1 root 506: {
1.1.1.5 root 507: dprintf(1, "Booting from %04x:%04x\n", bootsegip.seg, bootsegip.offset);
1.1 root 508: struct bregs br;
509: memset(&br, 0, sizeof(br));
510: br.flags = F_IF;
1.1.1.5 root 511: br.code = bootsegip;
1.1 root 512: // Set the magic number in ax and the boot drive in dl.
513: br.dl = bootdrv;
514: br.ax = 0xaa55;
515: call16(&br);
516: }
517:
518: // Boot from a disk (either floppy or harddrive)
519: static void
520: boot_disk(u8 bootdrv, int checksig)
521: {
522: u16 bootseg = 0x07c0;
523:
524: // Read sector
525: struct bregs br;
526: memset(&br, 0, sizeof(br));
527: br.flags = F_IF;
528: br.dl = bootdrv;
529: br.es = bootseg;
530: br.ah = 2;
531: br.al = 1;
532: br.cl = 1;
533: call16_int(0x13, &br);
534:
535: if (br.flags & F_CF) {
536: printf("Boot failed: could not read the boot disk\n\n");
537: return;
538: }
539:
540: if (checksig) {
541: struct mbr_s *mbr = (void*)0;
542: if (GET_FARVAR(bootseg, mbr->signature) != MBR_SIGNATURE) {
543: printf("Boot failed: not a bootable disk\n\n");
544: return;
545: }
546: }
547:
548: /* Canonicalize bootseg:bootip */
549: u16 bootip = (bootseg & 0x0fff) << 4;
550: bootseg &= 0xf000;
551:
1.1.1.5 root 552: call_boot_entry(SEGOFF(bootseg, bootip), bootdrv);
1.1 root 553: }
554:
555: // Boot from a CD-ROM
556: static void
1.1.1.5 root 557: boot_cdrom(struct drive_s *drive_g)
1.1 root 558: {
559: if (! CONFIG_CDROM_BOOT)
560: return;
1.1.1.5 root 561: printf("Booting from DVD/CD...\n");
562:
563: int status = cdrom_boot(drive_g);
1.1 root 564: if (status) {
565: printf("Boot failed: Could not read from CDROM (code %04x)\n", status);
566: return;
567: }
568:
569: u16 ebda_seg = get_ebda_seg();
570: u8 bootdrv = GET_EBDA2(ebda_seg, cdemu.emulated_extdrive);
571: u16 bootseg = GET_EBDA2(ebda_seg, cdemu.load_segment);
572: /* Canonicalize bootseg:bootip */
573: u16 bootip = (bootseg & 0x0fff) << 4;
574: bootseg &= 0xf000;
575:
1.1.1.5 root 576: call_boot_entry(SEGOFF(bootseg, bootip), bootdrv);
1.1 root 577: }
578:
579: // Boot from a CBFS payload
580: static void
1.1.1.5 root 581: boot_cbfs(struct cbfs_file *file)
1.1 root 582: {
1.1.1.3 root 583: if (!CONFIG_COREBOOT || !CONFIG_COREBOOT_FLASH)
1.1 root 584: return;
1.1.1.5 root 585: printf("Booting from CBFS...\n");
586: cbfs_run_payload(file);
1.1 root 587: }
588:
1.1.1.5 root 589: // Boot from a BEV entry on an optionrom.
590: static void
591: boot_rom(u32 vector)
592: {
593: printf("Booting from ROM...\n");
594: struct segoff_s so;
595: so.segoff = vector;
596: call_boot_entry(so, 0);
597: }
598:
599: // Determine next boot method and attempt a boot using it.
1.1 root 600: static void
601: do_boot(u16 seq_nr)
602: {
603: if (! CONFIG_BOOT)
604: panic("Boot support not compiled in.\n");
605:
1.1.1.5 root 606: if (seq_nr >= BEVCount) {
1.1 root 607: printf("No bootable device.\n");
608: // Loop with irqs enabled - this allows ctrl+alt+delete to work.
609: for (;;)
1.1.1.3 root 610: wait_irq();
1.1 root 611: }
612:
1.1.1.5 root 613: // Boot the given BEV type.
614: struct bev_s *ie = &BEV[seq_nr];
1.1.1.4 root 615: switch (ie->type) {
1.1 root 616: case IPL_TYPE_FLOPPY:
1.1.1.5 root 617: printf("Booting from Floppy...\n");
618: boot_disk(0x00, CheckFloppySig);
1.1 root 619: break;
620: case IPL_TYPE_HARDDISK:
1.1.1.5 root 621: printf("Booting from Hard Disk...\n");
1.1 root 622: boot_disk(0x80, 1);
623: break;
624: case IPL_TYPE_CDROM:
1.1.1.5 root 625: boot_cdrom((void*)ie->vector);
1.1 root 626: break;
627: case IPL_TYPE_CBFS:
1.1.1.5 root 628: boot_cbfs((void*)ie->vector);
1.1 root 629: break;
630: case IPL_TYPE_BEV:
1.1.1.5 root 631: boot_rom(ie->vector);
1.1 root 632: break;
633: }
634:
635: // Boot failed: invoke the boot recovery function
636: struct bregs br;
637: memset(&br, 0, sizeof(br));
638: br.flags = F_IF;
639: call16_int(0x18, &br);
640: }
641:
642: // Boot Failure recovery: try the next device.
1.1.1.2 root 643: void VISIBLE32FLAT
644: handle_18(void)
1.1 root 645: {
646: debug_serial_setup();
647: debug_enter(NULL, DEBUG_HDL_18);
648: u16 ebda_seg = get_ebda_seg();
649: u16 seq = GET_EBDA2(ebda_seg, boot_sequence) + 1;
650: SET_EBDA2(ebda_seg, boot_sequence, seq);
651: do_boot(seq);
652: }
653:
654: // INT 19h Boot Load Service Entry Point
1.1.1.2 root 655: void VISIBLE32FLAT
656: handle_19(void)
1.1 root 657: {
658: debug_serial_setup();
659: debug_enter(NULL, DEBUG_HDL_19);
660: SET_EBDA(boot_sequence, 0);
661: do_boot(0);
662: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.