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

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

unix.superglobalmegacorp.com

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