Annotation of qemu/roms/seabios/src/cdrom.c, revision 1.1.1.1

1.1       root        1: // Support for booting from cdroms (the "El Torito" spec).
                      2: //
                      3: // Copyright (C) 2008,2009  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 "disk.h" // cdrom_13
                      9: #include "util.h" // memset
                     10: #include "bregs.h" // struct bregs
                     11: #include "biosvar.h" // GET_EBDA
                     12: #include "ata.h" // ATA_CMD_REQUEST_SENSE
                     13: 
                     14: 
                     15: /****************************************************************
                     16:  * CD emulation
                     17:  ****************************************************************/
                     18: 
                     19: static int
                     20: cdemu_read(struct disk_op_s *op)
                     21: {
                     22:     u16 ebda_seg = get_ebda_seg();
                     23:     struct drive_s *drive_g = GET_EBDA2(ebda_seg, cdemu.emulated_drive);
                     24:     struct disk_op_s dop;
                     25:     dop.drive_g = drive_g;
                     26:     dop.command = op->command;
                     27:     dop.lba = GET_EBDA2(ebda_seg, cdemu.ilba) + op->lba / 4;
                     28: 
                     29:     int count = op->count;
                     30:     op->count = 0;
                     31:     u8 *cdbuf_far = (void*)offsetof(struct extended_bios_data_area_s, cdemu_buf);
                     32: 
                     33:     if (op->lba & 3) {
                     34:         // Partial read of first block.
                     35:         dop.count = 1;
                     36:         dop.buf_fl = MAKE_FLATPTR(ebda_seg, cdbuf_far);
                     37:         int ret = process_op(&dop);
                     38:         if (ret)
                     39:             return ret;
                     40:         u8 thiscount = 4 - (op->lba & 3);
                     41:         if (thiscount > count)
                     42:             thiscount = count;
                     43:         count -= thiscount;
                     44:         memcpy_far(FLATPTR_TO_SEG(op->buf_fl)
                     45:                    , (void*)FLATPTR_TO_OFFSET(op->buf_fl)
                     46:                    , ebda_seg, cdbuf_far + (op->lba & 3) * 512
                     47:                    , thiscount * 512);
                     48:         op->buf_fl += thiscount * 512;
                     49:         op->count += thiscount;
                     50:         dop.lba++;
                     51:     }
                     52: 
                     53:     if (count > 3) {
                     54:         // Read n number of regular blocks.
                     55:         dop.count = count / 4;
                     56:         dop.buf_fl = op->buf_fl;
                     57:         int ret = process_op(&dop);
                     58:         op->count += dop.count * 4;
                     59:         if (ret)
                     60:             return ret;
                     61:         u8 thiscount = count & ~3;
                     62:         count &= 3;
                     63:         op->buf_fl += thiscount * 512;
                     64:         dop.lba += thiscount / 4;
                     65:     }
                     66: 
                     67:     if (count) {
                     68:         // Partial read on last block.
                     69:         dop.count = 1;
                     70:         dop.buf_fl = MAKE_FLATPTR(ebda_seg, cdbuf_far);
                     71:         int ret = process_op(&dop);
                     72:         if (ret)
                     73:             return ret;
                     74:         u8 thiscount = count;
                     75:         memcpy_far(FLATPTR_TO_SEG(op->buf_fl)
                     76:                    , (void*)FLATPTR_TO_OFFSET(op->buf_fl)
                     77:                    , ebda_seg, cdbuf_far, thiscount * 512);
                     78:         op->count += thiscount;
                     79:     }
                     80: 
                     81:     return DISK_RET_SUCCESS;
                     82: }
                     83: 
                     84: int
                     85: process_cdemu_op(struct disk_op_s *op)
                     86: {
                     87:     if (!CONFIG_CDROM_EMU)
                     88:         return 0;
                     89: 
                     90:     switch (op->command) {
                     91:     case CMD_READ:
                     92:         return cdemu_read(op);
                     93:     case CMD_WRITE:
                     94:     case CMD_FORMAT:
                     95:         return DISK_RET_EWRITEPROTECT;
                     96:     case CMD_VERIFY:
                     97:     case CMD_RESET:
                     98:     case CMD_SEEK:
                     99:     case CMD_ISREADY:
                    100:         return DISK_RET_SUCCESS;
                    101:     default:
                    102:         op->count = 0;
                    103:         return DISK_RET_EPARAM;
                    104:     }
                    105: }
                    106: 
                    107: struct drive_s *cdemu_drive VAR16VISIBLE;
                    108: 
                    109: void
                    110: cdemu_setup()
                    111: {
                    112:     if (!CONFIG_CDROM_EMU)
                    113:         return;
                    114: 
                    115:     struct drive_s *drive_g = allocDrive();
                    116:     if (!drive_g) {
                    117:         cdemu_drive = NULL;
                    118:         return;
                    119:     }
                    120:     cdemu_drive = ADJUST_GLOBAL_PTR(drive_g);
                    121:     drive_g->type = DTYPE_CDEMU;
                    122:     drive_g->blksize = DISK_SECTOR_SIZE;
                    123:     drive_g->sectors = (u64)-1;
                    124: }
                    125: 
                    126: struct eltorito_s {
                    127:     u8 size;
                    128:     u8 media;
                    129:     u8 emulated_drive;
                    130:     u8 controller_index;
                    131:     u32 ilba;
                    132:     u16 device_spec;
                    133:     u16 buffer_segment;
                    134:     u16 load_segment;
                    135:     u16 sector_count;
                    136:     u8 cylinders;
                    137:     u8 sectors;
                    138:     u8 heads;
                    139: };
                    140: 
                    141: #define SET_INT13ET(regs,var,val)                                      \
                    142:     SET_FARVAR((regs)->ds, ((struct eltorito_s*)((regs)->si+0))->var, (val))
                    143: 
                    144: // ElTorito - Terminate disk emu
                    145: void
                    146: cdemu_134b(struct bregs *regs)
                    147: {
                    148:     // FIXME ElTorito Hardcoded
                    149:     u16 ebda_seg = get_ebda_seg();
                    150:     SET_INT13ET(regs, size, 0x13);
                    151:     SET_INT13ET(regs, media, GET_EBDA2(ebda_seg, cdemu.media));
                    152:     SET_INT13ET(regs, emulated_drive
                    153:                 , GET_EBDA2(ebda_seg, cdemu.emulated_extdrive));
                    154:     struct drive_s *drive_g = GET_EBDA2(ebda_seg, cdemu.emulated_drive);
                    155:     u8 cntl_id = GET_GLOBAL(drive_g->cntl_id);
                    156:     SET_INT13ET(regs, controller_index, cntl_id / 2);
                    157:     SET_INT13ET(regs, device_spec, cntl_id % 2);
                    158:     SET_INT13ET(regs, ilba, GET_EBDA2(ebda_seg, cdemu.ilba));
                    159:     SET_INT13ET(regs, buffer_segment, GET_EBDA2(ebda_seg, cdemu.buffer_segment));
                    160:     SET_INT13ET(regs, load_segment, GET_EBDA2(ebda_seg, cdemu.load_segment));
                    161:     SET_INT13ET(regs, sector_count, GET_EBDA2(ebda_seg, cdemu.sector_count));
                    162:     SET_INT13ET(regs, cylinders, GET_EBDA2(ebda_seg, cdemu.lchs.cylinders));
                    163:     SET_INT13ET(regs, sectors, GET_EBDA2(ebda_seg, cdemu.lchs.spt));
                    164:     SET_INT13ET(regs, heads, GET_EBDA2(ebda_seg, cdemu.lchs.heads));
                    165: 
                    166:     // If we have to terminate emulation
                    167:     if (regs->al == 0x00) {
                    168:         // FIXME ElTorito Various. Should be handled accordingly to spec
                    169:         SET_EBDA2(ebda_seg, cdemu.active, 0x00); // bye bye
                    170:     }
                    171: 
                    172:     disk_ret(regs, DISK_RET_SUCCESS);
                    173: }
                    174: 
                    175: 
                    176: /****************************************************************
                    177:  * CD booting
                    178:  ****************************************************************/
                    179: 
                    180: // Request SENSE
                    181: static int
                    182: atapi_get_sense(struct drive_s *drive_g, u8 *asc, u8 *ascq)
                    183: {
                    184:     u8 atacmd[12], buffer[18];
                    185:     memset(atacmd, 0, sizeof(atacmd));
                    186:     atacmd[0] = ATA_CMD_REQUEST_SENSE;
                    187:     atacmd[4] = sizeof(buffer);
                    188:     int ret = ata_cmd_packet(drive_g, atacmd, sizeof(atacmd), sizeof(buffer)
                    189:                              , MAKE_FLATPTR(GET_SEG(SS), buffer));
                    190:     if (ret)
                    191:         return ret;
                    192: 
                    193:     *asc = buffer[12];
                    194:     *ascq = buffer[13];
                    195: 
                    196:     return 0;
                    197: }
                    198: 
                    199: // Request capacity
                    200: static int
                    201: atapi_read_capacity(struct drive_s *drive_g, u32 *blksize, u32 *sectors)
                    202: {
                    203:     u8 packet[12], buf[8];
                    204:     memset(packet, 0, sizeof(packet));
                    205:     packet[0] = 0x25; /* READ CAPACITY */
                    206:     int ret = ata_cmd_packet(drive_g, packet, sizeof(packet), sizeof(buf)
                    207:                              , MAKE_FLATPTR(GET_SEG(SS), buf));
                    208:     if (ret)
                    209:         return ret;
                    210: 
                    211:     *blksize = (((u32)buf[4] << 24) | ((u32)buf[5] << 16)
                    212:                 | ((u32)buf[6] << 8) | ((u32)buf[7] << 0));
                    213:     *sectors = (((u32)buf[0] << 24) | ((u32)buf[1] << 16)
                    214:                 | ((u32)buf[2] << 8) | ((u32)buf[3] << 0));
                    215: 
                    216:     return 0;
                    217: }
                    218: 
                    219: static int
                    220: atapi_is_ready(struct drive_s *drive_g)
                    221: {
                    222:     dprintf(6, "atapi_is_ready (drive=%p)\n", drive_g);
                    223: 
                    224:     /* Retry READ CAPACITY for 5 seconds unless MEDIUM NOT PRESENT is
                    225:      * reported by the device.  If the device reports "IN PROGRESS",
                    226:      * 30 seconds is added. */
                    227:     u32 blksize, sectors;
                    228:     int in_progress = 0;
                    229:     u64 end = calc_future_tsc(5000);
                    230:     for (;;) {
                    231:         if (check_time(end)) {
                    232:             dprintf(1, "read capacity failed\n");
                    233:             return -1;
                    234:         }
                    235: 
                    236:         int ret = atapi_read_capacity(drive_g, &blksize, &sectors);
                    237:         if (!ret)
                    238:             // Success
                    239:             break;
                    240: 
                    241:         u8 asc, ascq;
                    242:         ret = atapi_get_sense(drive_g, &asc, &ascq);
                    243:         if (ret)
                    244:             // Error - retry.
                    245:             continue;
                    246: 
                    247:         // Sense succeeded.
                    248:         if (asc == 0x3a) { /* MEDIUM NOT PRESENT */
                    249:             dprintf(1, "Device reports MEDIUM NOT PRESENT\n");
                    250:             return -1;
                    251:         }
                    252: 
                    253:         if (asc == 0x04 && ascq == 0x01 && !in_progress) {
                    254:             /* IN PROGRESS OF BECOMING READY */
                    255:             printf("Waiting for device to detect medium... ");
                    256:             /* Allow 30 seconds more */
                    257:             end = calc_future_tsc(30000);
                    258:             in_progress = 1;
                    259:         }
                    260:     }
                    261: 
                    262:     if (blksize != GET_GLOBAL(drive_g->blksize)) {
                    263:         printf("Unsupported sector size %u\n", blksize);
                    264:         return -1;
                    265:     }
                    266: 
                    267:     dprintf(6, "sectors=%u\n", sectors);
                    268:     printf("%dMB medium detected\n", sectors>>(20-11));
                    269:     return 0;
                    270: }
                    271: 
                    272: int
                    273: cdrom_boot(int cdid)
                    274: {
                    275:     struct drive_s *drive_g = getDrive(EXTTYPE_CD, cdid);
                    276:     if (!drive_g)
                    277:         return 1;
                    278: 
                    279:     int ret = atapi_is_ready(drive_g);
                    280:     if (ret)
                    281:         dprintf(1, "atapi_is_ready returned %d\n", ret);
                    282: 
                    283:     // Read the Boot Record Volume Descriptor
                    284:     u8 buffer[2048];
                    285:     struct disk_op_s dop;
                    286:     memset(&dop, 0, sizeof(dop));
                    287:     dop.drive_g = drive_g;
                    288:     dop.lba = 0x11;
                    289:     dop.count = 1;
                    290:     dop.buf_fl = MAKE_FLATPTR(GET_SEG(SS), buffer);
                    291:     ret = cdrom_read(&dop);
                    292:     if (ret)
                    293:         return 3;
                    294: 
                    295:     // Validity checks
                    296:     if (buffer[0])
                    297:         return 4;
                    298:     if (strcmp((char*)&buffer[1], "CD001\001EL TORITO SPECIFICATION") != 0)
                    299:         return 5;
                    300: 
                    301:     // ok, now we calculate the Boot catalog address
                    302:     u32 lba = *(u32*)&buffer[0x47];
                    303: 
                    304:     // And we read the Boot Catalog
                    305:     dop.lba = lba;
                    306:     ret = cdrom_read(&dop);
                    307:     if (ret)
                    308:         return 7;
                    309: 
                    310:     // Validation entry
                    311:     if (buffer[0x00] != 0x01)
                    312:         return 8;   // Header
                    313:     if (buffer[0x01] != 0x00)
                    314:         return 9;   // Platform
                    315:     if (buffer[0x1E] != 0x55)
                    316:         return 10;  // key 1
                    317:     if (buffer[0x1F] != 0xAA)
                    318:         return 10;  // key 2
                    319: 
                    320:     // Initial/Default Entry
                    321:     if (buffer[0x20] != 0x88)
                    322:         return 11; // Bootable
                    323: 
                    324:     u16 ebda_seg = get_ebda_seg();
                    325:     u8 media = buffer[0x21];
                    326:     SET_EBDA2(ebda_seg, cdemu.media, media);
                    327: 
                    328:     SET_EBDA2(ebda_seg, cdemu.emulated_drive, ADJUST_GLOBAL_PTR(drive_g));
                    329: 
                    330:     u16 boot_segment = *(u16*)&buffer[0x22];
                    331:     if (!boot_segment)
                    332:         boot_segment = 0x07C0;
                    333:     SET_EBDA2(ebda_seg, cdemu.load_segment, boot_segment);
                    334:     SET_EBDA2(ebda_seg, cdemu.buffer_segment, 0x0000);
                    335: 
                    336:     u16 nbsectors = *(u16*)&buffer[0x26];
                    337:     SET_EBDA2(ebda_seg, cdemu.sector_count, nbsectors);
                    338: 
                    339:     lba = *(u32*)&buffer[0x28];
                    340:     SET_EBDA2(ebda_seg, cdemu.ilba, lba);
                    341: 
                    342:     // And we read the image in memory
                    343:     dop.lba = lba;
                    344:     dop.count = DIV_ROUND_UP(nbsectors, 4);
                    345:     dop.buf_fl = MAKE_FLATPTR(boot_segment, 0);
                    346:     ret = cdrom_read(&dop);
                    347:     if (ret)
                    348:         return 12;
                    349: 
                    350:     if (media == 0) {
                    351:         // No emulation requested - return success.
                    352:         SET_EBDA2(ebda_seg, cdemu.emulated_extdrive, EXTSTART_CD + cdid);
                    353:         return 0;
                    354:     }
                    355: 
                    356:     // Emulation of a floppy/harddisk requested
                    357:     if (! CONFIG_CDROM_EMU || !cdemu_drive)
                    358:         return 13;
                    359: 
                    360:     // Set emulated drive id and increase bios installed hardware
                    361:     // number of devices
                    362:     if (media < 4) {
                    363:         // Floppy emulation
                    364:         SET_EBDA2(ebda_seg, cdemu.emulated_extdrive, 0x00);
                    365:         SETBITS_BDA(equipment_list_flags, 0x41);
                    366: 
                    367:         switch (media) {
                    368:         case 0x01:  // 1.2M floppy
                    369:             SET_EBDA2(ebda_seg, cdemu.lchs.spt, 15);
                    370:             SET_EBDA2(ebda_seg, cdemu.lchs.cylinders, 80);
                    371:             SET_EBDA2(ebda_seg, cdemu.lchs.heads, 2);
                    372:             break;
                    373:         case 0x02:  // 1.44M floppy
                    374:             SET_EBDA2(ebda_seg, cdemu.lchs.spt, 18);
                    375:             SET_EBDA2(ebda_seg, cdemu.lchs.cylinders, 80);
                    376:             SET_EBDA2(ebda_seg, cdemu.lchs.heads, 2);
                    377:             break;
                    378:         case 0x03:  // 2.88M floppy
                    379:             SET_EBDA2(ebda_seg, cdemu.lchs.spt, 36);
                    380:             SET_EBDA2(ebda_seg, cdemu.lchs.cylinders, 80);
                    381:             SET_EBDA2(ebda_seg, cdemu.lchs.heads, 2);
                    382:             break;
                    383:         }
                    384:     } else {
                    385:         // Harddrive emulation
                    386:         SET_EBDA2(ebda_seg, cdemu.emulated_extdrive, 0x80);
                    387:         SET_BDA(hdcount, GET_BDA(hdcount) + 1);
                    388: 
                    389:         // Peak at partition table to get chs.
                    390:         struct mbr_s *mbr = (void*)0;
                    391:         u8 sptcyl = GET_FARVAR(boot_segment, mbr->partitions[0].last.sptcyl);
                    392:         u8 cyllow = GET_FARVAR(boot_segment, mbr->partitions[0].last.cyllow);
                    393:         u8 heads = GET_FARVAR(boot_segment, mbr->partitions[0].last.heads);
                    394: 
                    395:         SET_EBDA2(ebda_seg, cdemu.lchs.spt, sptcyl & 0x3f);
                    396:         SET_EBDA2(ebda_seg, cdemu.lchs.cylinders
                    397:                   , ((sptcyl<<2)&0x300) + cyllow + 1);
                    398:         SET_EBDA2(ebda_seg, cdemu.lchs.heads, heads + 1);
                    399:     }
                    400: 
                    401:     // everything is ok, so from now on, the emulation is active
                    402:     SET_EBDA2(ebda_seg, cdemu.active, 0x01);
                    403:     dprintf(6, "cdemu media=%d\n", media);
                    404: 
                    405:     return 0;
                    406: }

unix.superglobalmegacorp.com

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