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

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));
                     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
1.1.1.2 ! root      225: interactive_bootmenu(void)
1.1       root      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
1.1.1.2 ! root      312: boot_prep(void)
1.1       root      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.
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.