|
|
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.