Annotation of qemu/roms/seabios/src/boot.c, revision 1.1.1.4

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.