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

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
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: 
                    230:     int scan_code = get_keystroke(CONFIG_BOOTMENU_WAIT);
                    231:     if (scan_code != 0x86)
                    232:         /* not F12 */
                    233:         return;
                    234: 
                    235:     while (get_keystroke(0) >= 0)
                    236:         ;
                    237: 
                    238:     printf("Select boot device:\n\n");
1.1.1.3 ! root      239:     wait_threads();
1.1       root      240: 
                    241:     int subcount[ARRAY_SIZE(IPL.bev)];
                    242:     int menupos = 1;
                    243:     int i;
                    244:     for (i = 0; i < IPL.bevcount; i++) {
                    245:         struct ipl_entry_s *ie = &IPL.bev[i];
                    246:         int sc;
                    247:         switch (ie->type) {
                    248:         case IPL_TYPE_FLOPPY:
                    249:             sc = menu_show_floppy(ie, menupos);
                    250:             break;
                    251:         case IPL_TYPE_HARDDISK:
                    252:             sc = menu_show_harddisk(ie, menupos);
                    253:             break;
                    254:         case IPL_TYPE_CDROM:
                    255:             sc = menu_show_cdrom(ie, menupos);
                    256:             break;
                    257:         case IPL_TYPE_CBFS:
                    258:             sc = menu_show_cbfs(ie, menupos);
                    259:             break;
                    260:         default:
                    261:             sc = menu_show_default(ie, menupos);
                    262:             break;
                    263:         }
                    264:         subcount[i] = sc;
                    265:         menupos += sc;
                    266:     }
                    267: 
                    268:     for (;;) {
                    269:         scan_code = get_keystroke(1000);
                    270:         if (scan_code == 0x01)
                    271:             // ESC
                    272:             break;
                    273:         if (scan_code < 1 || scan_code > menupos)
                    274:             continue;
                    275:         int choice = scan_code - 1;
                    276: 
                    277:         // Find out which IPL this was for.
                    278:         int bev = 0;
                    279:         while (choice > subcount[bev]) {
                    280:             choice -= subcount[bev];
                    281:             bev++;
                    282:         }
                    283:         IPL.bev[bev].subchoice = choice-1;
                    284: 
                    285:         // Add user choice to the boot order.
                    286:         IPL.bootorder = (IPL.bootorder << 4) | (bev+1);
                    287:         break;
                    288:     }
                    289:     printf("\n");
                    290: }
                    291: 
                    292: // Run the specified bcv.
                    293: static void
                    294: run_bcv(struct ipl_entry_s *ie)
                    295: {
                    296:     switch (ie->type) {
                    297:     case BCV_TYPE_INTERNAL:
                    298:         map_hd_drive((void*)ie->vector);
                    299:         break;
                    300:     case BCV_TYPE_EXTERNAL:
                    301:         call_bcv(ie->vector >> 16, ie->vector & 0xffff);
                    302:         break;
                    303:     }
                    304: }
                    305: 
                    306: // Prepare for boot - show menu and run bcvs.
                    307: void
1.1.1.2   root      308: boot_prep(void)
1.1       root      309: {
1.1.1.3 ! root      310:     if (! CONFIG_BOOT) {
        !           311:         wait_threads();
1.1       root      312:         return;
1.1.1.3 ! root      313:     }
1.1       root      314: 
                    315:     // XXX - show available drives?
                    316: 
                    317:     // Allow user to modify BCV/IPL order.
                    318:     interactive_bootmenu();
1.1.1.3 ! root      319:     wait_threads();
1.1       root      320: 
                    321:     // Setup floppy boot order
                    322:     int override = IPL.bev[0].subchoice;
1.1.1.3 ! root      323:     struct drive_s *tmp = Drives.idmap[EXTTYPE_FLOPPY][0];
1.1       root      324:     Drives.idmap[EXTTYPE_FLOPPY][0] = Drives.idmap[EXTTYPE_FLOPPY][override];
                    325:     Drives.idmap[EXTTYPE_FLOPPY][override] = tmp;
                    326: 
                    327:     // Run BCVs
                    328:     override = IPL.bev[1].subchoice;
                    329:     if (override < IPL.bcvcount)
                    330:         run_bcv(&IPL.bcv[override]);
                    331:     int i;
                    332:     for (i=0; i<IPL.bcvcount; i++)
                    333:         if (i != override)
                    334:             run_bcv(&IPL.bcv[i]);
                    335: }
                    336: 
                    337: 
                    338: /****************************************************************
                    339:  * Boot code (int 18/19)
                    340:  ****************************************************************/
                    341: 
                    342: // Jump to a bootup entry point.
                    343: static void
                    344: call_boot_entry(u16 bootseg, u16 bootip, u8 bootdrv)
                    345: {
                    346:     dprintf(1, "Booting from %04x:%04x\n", bootseg, bootip);
                    347: 
1.1.1.3 ! root      348:     /* Go back to text, the OS might expect it... (Can't do this any later) */
        !           349:     disable_bootsplash();
        !           350: 
1.1       root      351:     struct bregs br;
                    352:     memset(&br, 0, sizeof(br));
                    353:     br.flags = F_IF;
                    354:     br.code = SEGOFF(bootseg, bootip);
                    355:     // Set the magic number in ax and the boot drive in dl.
                    356:     br.dl = bootdrv;
                    357:     br.ax = 0xaa55;
                    358:     call16(&br);
                    359: }
                    360: 
                    361: // Boot from a disk (either floppy or harddrive)
                    362: static void
                    363: boot_disk(u8 bootdrv, int checksig)
                    364: {
                    365:     u16 bootseg = 0x07c0;
                    366: 
                    367:     // Read sector
                    368:     struct bregs br;
                    369:     memset(&br, 0, sizeof(br));
                    370:     br.flags = F_IF;
                    371:     br.dl = bootdrv;
                    372:     br.es = bootseg;
                    373:     br.ah = 2;
                    374:     br.al = 1;
                    375:     br.cl = 1;
                    376:     call16_int(0x13, &br);
                    377: 
                    378:     if (br.flags & F_CF) {
                    379:         printf("Boot failed: could not read the boot disk\n\n");
                    380:         return;
                    381:     }
                    382: 
                    383:     if (checksig) {
                    384:         struct mbr_s *mbr = (void*)0;
                    385:         if (GET_FARVAR(bootseg, mbr->signature) != MBR_SIGNATURE) {
                    386:             printf("Boot failed: not a bootable disk\n\n");
                    387:             return;
                    388:         }
                    389:     }
                    390: 
                    391:     /* Canonicalize bootseg:bootip */
                    392:     u16 bootip = (bootseg & 0x0fff) << 4;
                    393:     bootseg &= 0xf000;
                    394: 
                    395:     call_boot_entry(bootseg, bootip, bootdrv);
                    396: }
                    397: 
                    398: // Boot from a CD-ROM
                    399: static void
                    400: boot_cdrom(struct ipl_entry_s *ie)
                    401: {
                    402:     if (! CONFIG_CDROM_BOOT)
                    403:         return;
                    404:     int status = cdrom_boot(ie->subchoice);
                    405:     if (status) {
                    406:         printf("Boot failed: Could not read from CDROM (code %04x)\n", status);
                    407:         return;
                    408:     }
                    409: 
                    410:     u16 ebda_seg = get_ebda_seg();
                    411:     u8 bootdrv = GET_EBDA2(ebda_seg, cdemu.emulated_extdrive);
                    412:     u16 bootseg = GET_EBDA2(ebda_seg, cdemu.load_segment);
                    413:     /* Canonicalize bootseg:bootip */
                    414:     u16 bootip = (bootseg & 0x0fff) << 4;
                    415:     bootseg &= 0xf000;
                    416: 
                    417:     call_boot_entry(bootseg, bootip, bootdrv);
                    418: }
                    419: 
                    420: // Boot from a CBFS payload
                    421: static void
                    422: boot_cbfs(struct ipl_entry_s *ie)
                    423: {
1.1.1.3 ! root      424:     if (!CONFIG_COREBOOT || !CONFIG_COREBOOT_FLASH)
1.1       root      425:         return;
                    426:     int count = ie->subchoice;
                    427:     struct cbfs_file *file = NULL;
                    428:     for (;;) {
                    429:         file = cbfs_findprefix("img/", file);
                    430:         if (!file)
                    431:             return;
                    432:         if (count--)
                    433:             continue;
                    434:         cbfs_run_payload(file);
                    435:     }
                    436: }
                    437: 
                    438: static void
                    439: do_boot(u16 seq_nr)
                    440: {
                    441:     if (! CONFIG_BOOT)
                    442:         panic("Boot support not compiled in.\n");
                    443: 
                    444:     u32 bootdev = IPL.bootorder;
                    445:     bootdev >>= 4 * seq_nr;
                    446:     bootdev &= 0xf;
                    447: 
                    448:     /* Translate bootdev to an IPL table offset by subtracting 1 */
                    449:     bootdev -= 1;
                    450: 
                    451:     if (bootdev >= IPL.bevcount) {
                    452:         printf("No bootable device.\n");
                    453:         // Loop with irqs enabled - this allows ctrl+alt+delete to work.
                    454:         for (;;)
1.1.1.3 ! root      455:             wait_irq();
1.1       root      456:     }
                    457: 
                    458:     /* Do the loading, and set up vector as a far pointer to the boot
                    459:      * address, and bootdrv as the boot drive */
                    460:     struct ipl_entry_s *ie = &IPL.bev[bootdev];
                    461:     char desc[33];
                    462:     printf("Booting from %s...\n"
                    463:            , strtcpy(desc, ie->description, ARRAY_SIZE(desc)));
                    464: 
                    465:     switch(ie->type) {
                    466:     case IPL_TYPE_FLOPPY:
                    467:         boot_disk(0x00, IPL.checkfloppysig);
                    468:         break;
                    469:     case IPL_TYPE_HARDDISK:
                    470:         boot_disk(0x80, 1);
                    471:         break;
                    472:     case IPL_TYPE_CDROM:
                    473:         boot_cdrom(ie);
                    474:         break;
                    475:     case IPL_TYPE_CBFS:
                    476:         boot_cbfs(ie);
                    477:         break;
                    478:     case IPL_TYPE_BEV:
                    479:         call_boot_entry(ie->vector >> 16, ie->vector & 0xffff, 0);
                    480:         break;
                    481:     }
                    482: 
                    483:     // Boot failed: invoke the boot recovery function
                    484:     struct bregs br;
                    485:     memset(&br, 0, sizeof(br));
                    486:     br.flags = F_IF;
                    487:     call16_int(0x18, &br);
                    488: }
                    489: 
                    490: // Boot Failure recovery: try the next device.
1.1.1.2   root      491: void VISIBLE32FLAT
                    492: handle_18(void)
1.1       root      493: {
                    494:     debug_serial_setup();
                    495:     debug_enter(NULL, DEBUG_HDL_18);
                    496:     u16 ebda_seg = get_ebda_seg();
                    497:     u16 seq = GET_EBDA2(ebda_seg, boot_sequence) + 1;
                    498:     SET_EBDA2(ebda_seg, boot_sequence, seq);
                    499:     do_boot(seq);
                    500: }
                    501: 
                    502: // INT 19h Boot Load Service Entry Point
1.1.1.2   root      503: void VISIBLE32FLAT
                    504: handle_19(void)
1.1       root      505: {
                    506:     debug_serial_setup();
                    507:     debug_enter(NULL, DEBUG_HDL_19);
                    508:     SET_EBDA(boot_sequence, 0);
                    509:     do_boot(0);
                    510: }

unix.superglobalmegacorp.com

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