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

1.1       root        1: // 16bit code to access hard drives.
                      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 "disk.h" // floppy_13
                      9: #include "biosvar.h" // SET_BDA
                     10: #include "config.h" // CONFIG_*
                     11: #include "util.h" // debug_enter
                     12: #include "pic.h" // eoi_pic2
                     13: #include "bregs.h" // struct bregs
                     14: #include "pci.h" // pci_bdf_to_bus
                     15: #include "ata.h" // ATA_CB_DC
                     16: 
                     17: 
                     18: /****************************************************************
                     19:  * Helper functions
                     20:  ****************************************************************/
                     21: 
                     22: void
                     23: __disk_ret(struct bregs *regs, u32 linecode, const char *fname)
                     24: {
                     25:     u8 code = linecode;
                     26:     if (regs->dl < EXTSTART_HD)
                     27:         SET_BDA(floppy_last_status, code);
                     28:     else
                     29:         SET_BDA(disk_last_status, code);
                     30:     if (code)
                     31:         __set_code_invalid(regs, linecode, fname);
                     32:     else
                     33:         set_code_success(regs);
                     34: }
                     35: 
                     36: void
                     37: __disk_ret_unimplemented(struct bregs *regs, u32 linecode, const char *fname)
                     38: {
                     39:     u8 code = linecode;
                     40:     if (regs->dl < EXTSTART_HD)
                     41:         SET_BDA(floppy_last_status, code);
                     42:     else
                     43:         SET_BDA(disk_last_status, code);
                     44:     __set_code_unimplemented(regs, linecode, fname);
                     45: }
                     46: 
                     47: static void
                     48: __disk_stub(struct bregs *regs, int lineno, const char *fname)
                     49: {
                     50:     __warn_unimplemented(regs, lineno, fname);
                     51:     __disk_ret(regs, DISK_RET_SUCCESS | (lineno << 8), fname);
                     52: }
                     53: 
                     54: #define DISK_STUB(regs)                         \
                     55:     __disk_stub((regs), __LINE__, __func__)
                     56: 
                     57: static void
                     58: fillLCHS(struct drive_s *drive_g, u16 *nlc, u16 *nlh, u16 *nlspt)
                     59: {
                     60:     if (CONFIG_CDROM_EMU && drive_g == GET_GLOBAL(cdemu_drive)) {
                     61:         // Emulated drive - get info from ebda.  (It's not possible to
                     62:         // populate the geometry directly in the driveid because the
                     63:         // geometry is only known after the bios segment is made
                     64:         // read-only).
                     65:         u16 ebda_seg = get_ebda_seg();
                     66:         *nlc = GET_EBDA2(ebda_seg, cdemu.lchs.cylinders);
                     67:         *nlh = GET_EBDA2(ebda_seg, cdemu.lchs.heads);
                     68:         *nlspt = GET_EBDA2(ebda_seg, cdemu.lchs.spt);
                     69:         return;
                     70:     }
                     71:     *nlc = GET_GLOBAL(drive_g->lchs.cylinders);
                     72:     *nlh = GET_GLOBAL(drive_g->lchs.heads);
                     73:     *nlspt = GET_GLOBAL(drive_g->lchs.spt);
                     74: }
                     75: 
                     76: // Perform read/write/verify using old-style chs accesses
                     77: static void
                     78: basic_access(struct bregs *regs, struct drive_s *drive_g, u16 command)
                     79: {
                     80:     struct disk_op_s dop;
                     81:     dop.drive_g = drive_g;
                     82:     dop.command = command;
                     83: 
                     84:     u8 count = regs->al;
                     85:     u16 cylinder = regs->ch | ((((u16)regs->cl) << 2) & 0x300);
                     86:     u16 sector = regs->cl & 0x3f;
                     87:     u16 head = regs->dh;
                     88: 
                     89:     if (count > 128 || count == 0 || sector == 0) {
                     90:         dprintf(1, "int13_harddisk: function %02x, parameter out of range!\n"
                     91:                 , regs->ah);
                     92:         disk_ret(regs, DISK_RET_EPARAM);
                     93:         return;
                     94:     }
                     95:     dop.count = count;
                     96: 
                     97:     u16 nlc, nlh, nlspt;
                     98:     fillLCHS(drive_g, &nlc, &nlh, &nlspt);
                     99: 
                    100:     // sanity check on cyl heads, sec
                    101:     if (cylinder >= nlc || head >= nlh || sector > nlspt) {
                    102:         dprintf(1, "int13_harddisk: function %02x, parameters out of"
                    103:                 " range %04x/%04x/%04x!\n"
                    104:                 , regs->ah, cylinder, head, sector);
                    105:         disk_ret(regs, DISK_RET_EPARAM);
                    106:         return;
                    107:     }
                    108: 
                    109:     // translate lchs to lba
                    110:     dop.lba = (((((u32)cylinder * (u32)nlh) + (u32)head) * (u32)nlspt)
                    111:                + (u32)sector - 1);
                    112: 
                    113:     dop.buf_fl = MAKE_FLATPTR(regs->es, regs->bx);
                    114: 
                    115:     int status = send_disk_op(&dop);
                    116: 
                    117:     regs->al = dop.count;
                    118: 
                    119:     disk_ret(regs, status);
                    120: }
                    121: 
                    122: // Perform read/write/verify using new-style "int13ext" accesses.
                    123: static void
                    124: extended_access(struct bregs *regs, struct drive_s *drive_g, u16 command)
                    125: {
                    126:     struct disk_op_s dop;
                    127:     // Get lba and check.
                    128:     dop.lba = GET_INT13EXT(regs, lba);
                    129:     dop.command = command;
                    130:     dop.drive_g = drive_g;
                    131:     if (dop.lba >= GET_GLOBAL(drive_g->sectors)) {
                    132:         dprintf(1, "int13_harddisk: function %02x. LBA out of range\n"
                    133:                 , regs->ah);
                    134:         disk_ret(regs, DISK_RET_EPARAM);
                    135:         return;
                    136:     }
                    137: 
                    138:     dop.buf_fl = SEGOFF_TO_FLATPTR(GET_INT13EXT(regs, data));
                    139:     dop.count = GET_INT13EXT(regs, count);
                    140: 
                    141:     int status = send_disk_op(&dop);
                    142: 
                    143:     SET_INT13EXT(regs, count, dop.count);
                    144: 
                    145:     disk_ret(regs, status);
                    146: }
                    147: 
                    148: 
                    149: /****************************************************************
                    150:  * Hard Drive functions
                    151:  ****************************************************************/
                    152: 
                    153: // disk controller reset
                    154: static void
                    155: disk_1300(struct bregs *regs, struct drive_s *drive_g)
                    156: {
                    157:     struct disk_op_s dop;
                    158:     dop.drive_g = drive_g;
                    159:     dop.command = CMD_RESET;
                    160:     int status = send_disk_op(&dop);
                    161:     disk_ret(regs, status);
                    162: }
                    163: 
                    164: // read disk status
                    165: static void
                    166: disk_1301(struct bregs *regs, struct drive_s *drive_g)
                    167: {
                    168:     u8 v;
                    169:     if (regs->dl < EXTSTART_HD)
                    170:         // Floppy
                    171:         v = GET_BDA(floppy_last_status);
                    172:     else
                    173:         v = GET_BDA(disk_last_status);
                    174:     regs->ah = v;
                    175:     set_cf(regs, v);
                    176:     // XXX - clear disk_last_status?
                    177: }
                    178: 
                    179: // read disk sectors
                    180: static void
                    181: disk_1302(struct bregs *regs, struct drive_s *drive_g)
                    182: {
                    183:     basic_access(regs, drive_g, CMD_READ);
                    184: }
                    185: 
                    186: // write disk sectors
                    187: static void
                    188: disk_1303(struct bregs *regs, struct drive_s *drive_g)
                    189: {
                    190:     basic_access(regs, drive_g, CMD_WRITE);
                    191: }
                    192: 
                    193: // verify disk sectors
                    194: static void
                    195: disk_1304(struct bregs *regs, struct drive_s *drive_g)
                    196: {
                    197:     basic_access(regs, drive_g, CMD_VERIFY);
                    198: }
                    199: 
                    200: // format disk track
                    201: static void
                    202: disk_1305(struct bregs *regs, struct drive_s *drive_g)
                    203: {
                    204:     debug_stub(regs);
                    205: 
                    206:     u16 nlc, nlh, nlspt;
                    207:     fillLCHS(drive_g, &nlc, &nlh, &nlspt);
                    208: 
                    209:     u8 num_sectors = regs->al;
                    210:     u8 head        = regs->dh;
                    211: 
                    212:     if (head >= nlh || num_sectors == 0 || num_sectors > nlspt) {
                    213:         disk_ret(regs, DISK_RET_EPARAM);
                    214:         return;
                    215:     }
                    216: 
                    217:     struct disk_op_s dop;
                    218:     dop.drive_g = drive_g;
                    219:     dop.command = CMD_FORMAT;
                    220:     dop.lba = head;
                    221:     dop.count = num_sectors;
                    222:     dop.buf_fl = MAKE_FLATPTR(regs->es, regs->bx);
                    223:     int status = send_disk_op(&dop);
                    224:     disk_ret(regs, status);
                    225: }
                    226: 
                    227: // read disk drive parameters
                    228: static void
                    229: disk_1308(struct bregs *regs, struct drive_s *drive_g)
                    230: {
                    231:     u16 ebda_seg = get_ebda_seg();
                    232:     // Get logical geometry from table
                    233:     u16 nlc, nlh, nlspt;
                    234:     fillLCHS(drive_g, &nlc, &nlh, &nlspt);
                    235:     nlc--;
                    236:     nlh--;
                    237:     u8 count;
                    238:     if (regs->dl < EXTSTART_HD) {
                    239:         // Floppy
                    240:         count = GET_GLOBAL(Drives.floppycount);
                    241: 
                    242:         if (CONFIG_CDROM_EMU && drive_g == GET_GLOBAL(cdemu_drive))
                    243:             regs->bx = GET_EBDA2(ebda_seg, cdemu.media) * 2;
                    244:         else
                    245:             regs->bx = GET_GLOBAL(drive_g->floppy_type);
                    246: 
                    247:         // set es & di to point to 11 byte diskette param table in ROM
                    248:         regs->es = SEG_BIOS;
                    249:         regs->di = (u32)&diskette_param_table2;
                    250:     } else if (regs->dl < EXTSTART_CD) {
                    251:         // Hard drive
                    252:         count = GET_BDA(hdcount);
                    253:         nlc--;  // last sector reserved
                    254:     } else {
                    255:         // Not supported on CDROM
                    256:         disk_ret(regs, DISK_RET_EPARAM);
                    257:         return;
                    258:     }
                    259: 
                    260:     if (CONFIG_CDROM_EMU && GET_EBDA2(ebda_seg, cdemu.active)) {
                    261:         u8 emudrive = GET_EBDA2(ebda_seg, cdemu.emulated_extdrive);
                    262:         if (((emudrive ^ regs->dl) & 0x80) == 0)
                    263:             // Note extra drive due to emulation.
                    264:             count++;
                    265:         if (regs->dl < EXTSTART_HD && count > 2)
                    266:             // Max of two floppy drives.
                    267:             count = 2;
                    268:     }
                    269: 
                    270:     regs->al = 0;
                    271:     regs->ch = nlc & 0xff;
                    272:     regs->cl = ((nlc >> 2) & 0xc0) | (nlspt & 0x3f);
                    273:     regs->dh = nlh;
                    274: 
                    275:     disk_ret(regs, DISK_RET_SUCCESS);
                    276:     regs->dl = count;
                    277: }
                    278: 
                    279: // initialize drive parameters
                    280: static void
                    281: disk_1309(struct bregs *regs, struct drive_s *drive_g)
                    282: {
                    283:     DISK_STUB(regs);
                    284: }
                    285: 
                    286: // seek to specified cylinder
                    287: static void
                    288: disk_130c(struct bregs *regs, struct drive_s *drive_g)
                    289: {
                    290:     DISK_STUB(regs);
                    291: }
                    292: 
                    293: // alternate disk reset
                    294: static void
                    295: disk_130d(struct bregs *regs, struct drive_s *drive_g)
                    296: {
                    297:     DISK_STUB(regs);
                    298: }
                    299: 
                    300: // check drive ready
                    301: static void
                    302: disk_1310(struct bregs *regs, struct drive_s *drive_g)
                    303: {
                    304:     // should look at 40:8E also???
                    305: 
                    306:     struct disk_op_s dop;
                    307:     dop.drive_g = drive_g;
                    308:     dop.command = CMD_ISREADY;
                    309:     int status = send_disk_op(&dop);
                    310:     disk_ret(regs, status);
                    311: }
                    312: 
                    313: // recalibrate
                    314: static void
                    315: disk_1311(struct bregs *regs, struct drive_s *drive_g)
                    316: {
                    317:     DISK_STUB(regs);
                    318: }
                    319: 
                    320: // controller internal diagnostic
                    321: static void
                    322: disk_1314(struct bregs *regs, struct drive_s *drive_g)
                    323: {
                    324:     DISK_STUB(regs);
                    325: }
                    326: 
                    327: // read disk drive size
                    328: static void
                    329: disk_1315(struct bregs *regs, struct drive_s *drive_g)
                    330: {
                    331:     disk_ret(regs, DISK_RET_SUCCESS);
                    332:     if (regs->dl < EXTSTART_HD || regs->dl >= EXTSTART_CD) {
                    333:         // Floppy or cdrom
                    334:         regs->ah = 1;
                    335:         return;
                    336:     }
                    337:     // Hard drive
                    338: 
                    339:     // Get logical geometry from table
                    340:     u16 nlc, nlh, nlspt;
                    341:     fillLCHS(drive_g, &nlc, &nlh, &nlspt);
                    342: 
                    343:     // Compute sector count seen by int13
                    344:     u32 lba = (u32)(nlc - 1) * (u32)nlh * (u32)nlspt;
                    345:     regs->cx = lba >> 16;
                    346:     regs->dx = lba & 0xffff;
                    347:     regs->ah = 3; // hard disk accessible
                    348: }
                    349: 
                    350: static void
                    351: disk_1316(struct bregs *regs, struct drive_s *drive_g)
                    352: {
                    353:     if (regs->dl >= EXTSTART_HD) {
                    354:         // Hard drive
                    355:         disk_ret(regs, DISK_RET_EPARAM);
                    356:         return;
                    357:     }
                    358:     disk_ret(regs, DISK_RET_ECHANGED);
                    359: }
                    360: 
                    361: // IBM/MS installation check
                    362: static void
                    363: disk_1341(struct bregs *regs, struct drive_s *drive_g)
                    364: {
                    365:     regs->bx = 0xaa55;  // install check
                    366:     regs->cx = 0x0007;  // ext disk access and edd, removable supported
                    367:     disk_ret(regs, DISK_RET_SUCCESS);
                    368:     regs->ah = 0x30;    // EDD 3.0
                    369: }
                    370: 
                    371: // IBM/MS extended read
                    372: static void
                    373: disk_1342(struct bregs *regs, struct drive_s *drive_g)
                    374: {
                    375:     extended_access(regs, drive_g, CMD_READ);
                    376: }
                    377: 
                    378: // IBM/MS extended write
                    379: static void
                    380: disk_1343(struct bregs *regs, struct drive_s *drive_g)
                    381: {
                    382:     extended_access(regs, drive_g, CMD_WRITE);
                    383: }
                    384: 
                    385: // IBM/MS verify
                    386: static void
                    387: disk_1344(struct bregs *regs, struct drive_s *drive_g)
                    388: {
                    389:     extended_access(regs, drive_g, CMD_VERIFY);
                    390: }
                    391: 
                    392: // lock
                    393: static void
                    394: disk_134500(struct bregs *regs, struct drive_s *drive_g)
                    395: {
                    396:     u16 ebda_seg = get_ebda_seg();
                    397:     int cdid = regs->dl - EXTSTART_CD;
                    398:     u8 locks = GET_EBDA2(ebda_seg, cdrom_locks[cdid]);
                    399:     if (locks == 0xff) {
                    400:         regs->al = 1;
                    401:         disk_ret(regs, DISK_RET_ETOOMANYLOCKS);
                    402:         return;
                    403:     }
                    404:     SET_EBDA2(ebda_seg, cdrom_locks[cdid], locks + 1);
                    405:     regs->al = 1;
                    406:     disk_ret(regs, DISK_RET_SUCCESS);
                    407: }
                    408: 
                    409: // unlock
                    410: static void
                    411: disk_134501(struct bregs *regs, struct drive_s *drive_g)
                    412: {
                    413:     u16 ebda_seg = get_ebda_seg();
                    414:     int cdid = regs->dl - EXTSTART_CD;
                    415:     u8 locks = GET_EBDA2(ebda_seg, cdrom_locks[cdid]);
                    416:     if (locks == 0x00) {
                    417:         regs->al = 0;
                    418:         disk_ret(regs, DISK_RET_ENOTLOCKED);
                    419:         return;
                    420:     }
                    421:     locks--;
                    422:     SET_EBDA2(ebda_seg, cdrom_locks[cdid], locks);
                    423:     regs->al = (locks ? 1 : 0);
                    424:     disk_ret(regs, DISK_RET_SUCCESS);
                    425: }
                    426: 
                    427: // status
                    428: static void
                    429: disk_134502(struct bregs *regs, struct drive_s *drive_g)
                    430: {
                    431:     int cdid = regs->dl - EXTSTART_CD;
                    432:     u8 locks = GET_EBDA(cdrom_locks[cdid]);
                    433:     regs->al = (locks ? 1 : 0);
                    434:     disk_ret(regs, DISK_RET_SUCCESS);
                    435: }
                    436: 
                    437: static void
                    438: disk_1345XX(struct bregs *regs, struct drive_s *drive_g)
                    439: {
                    440:     disk_ret_unimplemented(regs, DISK_RET_EPARAM);
                    441: }
                    442: 
                    443: // IBM/MS lock/unlock drive
                    444: static void
                    445: disk_1345(struct bregs *regs, struct drive_s *drive_g)
                    446: {
                    447:     if (regs->dl < EXTSTART_CD) {
                    448:         // Always success for HD
                    449:         disk_ret(regs, DISK_RET_SUCCESS);
                    450:         return;
                    451:     }
                    452: 
                    453:     switch (regs->al) {
                    454:     case 0x00: disk_134500(regs, drive_g); break;
                    455:     case 0x01: disk_134501(regs, drive_g); break;
                    456:     case 0x02: disk_134502(regs, drive_g); break;
                    457:     default:   disk_1345XX(regs, drive_g); break;
                    458:     }
                    459: }
                    460: 
                    461: // IBM/MS eject media
                    462: static void
                    463: disk_1346(struct bregs *regs, struct drive_s *drive_g)
                    464: {
                    465:     if (regs->dl < EXTSTART_CD) {
                    466:         // Volume Not Removable
                    467:         disk_ret(regs, DISK_RET_ENOTREMOVABLE);
                    468:         return;
                    469:     }
                    470: 
                    471:     int cdid = regs->dl - EXTSTART_CD;
                    472:     u8 locks = GET_EBDA(cdrom_locks[cdid]);
                    473:     if (locks != 0) {
                    474:         disk_ret(regs, DISK_RET_ELOCKED);
                    475:         return;
                    476:     }
                    477: 
                    478:     // FIXME should handle 0x31 no media in device
                    479:     // FIXME should handle 0xb5 valid request failed
                    480: 
                    481:     // Call removable media eject
                    482:     struct bregs br;
                    483:     memset(&br, 0, sizeof(br));
                    484:     br.ah = 0x52;
                    485:     call16_int(0x15, &br);
                    486: 
                    487:     if (br.ah || br.flags & F_CF) {
                    488:         disk_ret(regs, DISK_RET_ELOCKED);
                    489:         return;
                    490:     }
                    491:     disk_ret(regs, DISK_RET_SUCCESS);
                    492: }
                    493: 
                    494: // IBM/MS extended seek
                    495: static void
                    496: disk_1347(struct bregs *regs, struct drive_s *drive_g)
                    497: {
                    498:     extended_access(regs, drive_g, CMD_SEEK);
                    499: }
                    500: 
                    501: // IBM/MS get drive parameters
                    502: static void
                    503: disk_1348(struct bregs *regs, struct drive_s *drive_g)
                    504: {
                    505:     u16 size = GET_INT13DPT(regs, size);
                    506: 
                    507:     // Buffer is too small
                    508:     if (size < 26) {
                    509:         disk_ret(regs, DISK_RET_EPARAM);
                    510:         return;
                    511:     }
                    512: 
                    513:     // EDD 1.x
                    514: 
                    515:     u8  type    = GET_GLOBAL(drive_g->type);
                    516:     u16 npc     = GET_GLOBAL(drive_g->pchs.cylinders);
                    517:     u16 nph     = GET_GLOBAL(drive_g->pchs.heads);
                    518:     u16 npspt   = GET_GLOBAL(drive_g->pchs.spt);
                    519:     u64 lba     = GET_GLOBAL(drive_g->sectors);
                    520:     u16 blksize = GET_GLOBAL(drive_g->blksize);
                    521: 
                    522:     dprintf(DEBUG_HDL_13, "disk_1348 size=%d t=%d chs=%d,%d,%d lba=%d bs=%d\n"
                    523:             , size, type, npc, nph, npspt, (u32)lba, blksize);
                    524: 
                    525:     SET_INT13DPT(regs, size, 26);
                    526:     if (type == DTYPE_ATAPI) {
                    527:         // 0x74 = removable, media change, lockable, max values
                    528:         SET_INT13DPT(regs, infos, 0x74);
                    529:         SET_INT13DPT(regs, cylinders, 0xffffffff);
                    530:         SET_INT13DPT(regs, heads, 0xffffffff);
                    531:         SET_INT13DPT(regs, spt, 0xffffffff);
                    532:         SET_INT13DPT(regs, sector_count, (u64)-1);
                    533:     } else {
                    534:         if (lba > (u64)npspt*nph*0x3fff) {
                    535:             SET_INT13DPT(regs, infos, 0x00); // geometry is invalid
                    536:             SET_INT13DPT(regs, cylinders, 0x3fff);
                    537:         } else {
                    538:             SET_INT13DPT(regs, infos, 0x02); // geometry is valid
                    539:             SET_INT13DPT(regs, cylinders, (u32)npc);
                    540:         }
                    541:         SET_INT13DPT(regs, heads, (u32)nph);
                    542:         SET_INT13DPT(regs, spt, (u32)npspt);
                    543:         SET_INT13DPT(regs, sector_count, lba);
                    544:     }
                    545:     SET_INT13DPT(regs, blksize, blksize);
                    546: 
                    547:     if (size < 30 || (type != DTYPE_ATA && type != DTYPE_ATAPI)) {
                    548:         disk_ret(regs, DISK_RET_SUCCESS);
                    549:         return;
                    550:     }
                    551: 
                    552:     // EDD 2.x
                    553: 
                    554:     u16 ebda_seg = get_ebda_seg();
                    555:     SET_INT13DPT(regs, size, 30);
                    556: 
                    557:     SET_INT13DPT(regs, dpte_segment, ebda_seg);
                    558:     SET_INT13DPT(regs, dpte_offset
                    559:                  , offsetof(struct extended_bios_data_area_s, dpte));
                    560: 
                    561:     // Fill in dpte
                    562:     u8 ataid = GET_GLOBAL(drive_g->cntl_id);
                    563:     u8 channel = ataid / 2;
                    564:     u8 slave = ataid % 2;
                    565:     u16 iobase1 = GET_GLOBAL(ATA_channels[channel].iobase1);
                    566:     u16 iobase2 = GET_GLOBAL(ATA_channels[channel].iobase2);
                    567:     u8 irq = GET_GLOBAL(ATA_channels[channel].irq);
                    568: 
                    569:     u16 options = 0;
                    570:     if (type == DTYPE_ATA) {
                    571:         u8 translation = GET_GLOBAL(drive_g->translation);
                    572:         if (translation != TRANSLATION_NONE) {
                    573:             options |= 1<<3; // CHS translation
                    574:             if (translation == TRANSLATION_LBA)
                    575:                 options |= 1<<9;
                    576:             if (translation == TRANSLATION_RECHS)
                    577:                 options |= 3<<9;
                    578:         }
                    579:     } else {
                    580:         // ATAPI
                    581:         options |= 1<<5; // removable device
                    582:         options |= 1<<6; // atapi device
                    583:     }
                    584:     options |= 1<<4; // lba translation
                    585:     if (CONFIG_ATA_PIO32)
                    586:         options |= 1<<7;
                    587: 
                    588:     SET_EBDA2(ebda_seg, dpte.iobase1, iobase1);
                    589:     SET_EBDA2(ebda_seg, dpte.iobase2, iobase2 + ATA_CB_DC);
                    590:     SET_EBDA2(ebda_seg, dpte.prefix, ((slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0)
                    591:                                       | ATA_CB_DH_LBA));
                    592:     SET_EBDA2(ebda_seg, dpte.unused, 0xcb);
                    593:     SET_EBDA2(ebda_seg, dpte.irq, irq);
                    594:     SET_EBDA2(ebda_seg, dpte.blkcount, 1);
                    595:     SET_EBDA2(ebda_seg, dpte.dma, 0);
                    596:     SET_EBDA2(ebda_seg, dpte.pio, 0);
                    597:     SET_EBDA2(ebda_seg, dpte.options, options);
                    598:     SET_EBDA2(ebda_seg, dpte.reserved, 0);
                    599:     SET_EBDA2(ebda_seg, dpte.revision, 0x11);
                    600: 
                    601:     u8 sum = checksum_far(
                    602:         ebda_seg, (void*)offsetof(struct extended_bios_data_area_s, dpte), 15);
                    603:     SET_EBDA2(ebda_seg, dpte.checksum, -sum);
                    604: 
                    605:     if (size < 66) {
                    606:         disk_ret(regs, DISK_RET_SUCCESS);
                    607:         return;
                    608:     }
                    609: 
                    610:     // EDD 3.x
                    611:     SET_INT13DPT(regs, key, 0xbedd);
                    612:     SET_INT13DPT(regs, dpi_length, 36);
                    613:     SET_INT13DPT(regs, reserved1, 0);
                    614:     SET_INT13DPT(regs, reserved2, 0);
                    615: 
                    616:     int bdf = GET_GLOBAL(ATA_channels[channel].pci_bdf);
                    617:     if (bdf != -1) {
                    618:         SET_INT13DPT(regs, host_bus[0], 'P');
                    619:         SET_INT13DPT(regs, host_bus[1], 'C');
                    620:         SET_INT13DPT(regs, host_bus[2], 'I');
                    621:         SET_INT13DPT(regs, host_bus[3], 0);
                    622: 
                    623:         u32 path = (pci_bdf_to_bus(bdf) | (pci_bdf_to_dev(bdf) << 8)
                    624:                     | (pci_bdf_to_fn(bdf) << 16));
                    625:         SET_INT13DPT(regs, iface_path, path);
                    626:     } else {
                    627:         // ISA
                    628:         SET_INT13DPT(regs, host_bus[0], 'I');
                    629:         SET_INT13DPT(regs, host_bus[1], 'S');
                    630:         SET_INT13DPT(regs, host_bus[2], 'A');
                    631:         SET_INT13DPT(regs, host_bus[3], 0);
                    632: 
                    633:         SET_INT13DPT(regs, iface_path, iobase1);
                    634:     }
                    635: 
                    636:     SET_INT13DPT(regs, iface_type[0], 'A');
                    637:     SET_INT13DPT(regs, iface_type[1], 'T');
                    638:     SET_INT13DPT(regs, iface_type[2], 'A');
                    639:     SET_INT13DPT(regs, iface_type[3], 0);
                    640:     SET_INT13DPT(regs, iface_type[4], 0);
                    641:     SET_INT13DPT(regs, iface_type[5], 0);
                    642:     SET_INT13DPT(regs, iface_type[6], 0);
                    643:     SET_INT13DPT(regs, iface_type[7], 0);
                    644: 
                    645:     SET_INT13DPT(regs, device_path, slave);
                    646: 
                    647:     SET_INT13DPT(regs, checksum
                    648:                  , -checksum_far(regs->ds, (void*)(regs->si+30), 35));
                    649: 
                    650:     disk_ret(regs, DISK_RET_SUCCESS);
                    651: }
                    652: 
                    653: // IBM/MS extended media change
                    654: static void
                    655: disk_1349(struct bregs *regs, struct drive_s *drive_g)
                    656: {
                    657:     if (regs->dl < EXTSTART_CD) {
                    658:         // Always success for HD
                    659:         disk_ret(regs, DISK_RET_SUCCESS);
                    660:         return;
                    661:     }
                    662:     set_invalid(regs);
                    663:     // always send changed ??
                    664:     regs->ah = DISK_RET_ECHANGED;
                    665: }
                    666: 
                    667: static void
                    668: disk_134e01(struct bregs *regs, struct drive_s *drive_g)
                    669: {
                    670:     disk_ret(regs, DISK_RET_SUCCESS);
                    671: }
                    672: 
                    673: static void
                    674: disk_134e03(struct bregs *regs, struct drive_s *drive_g)
                    675: {
                    676:     disk_ret(regs, DISK_RET_SUCCESS);
                    677: }
                    678: 
                    679: static void
                    680: disk_134e04(struct bregs *regs, struct drive_s *drive_g)
                    681: {
                    682:     disk_ret(regs, DISK_RET_SUCCESS);
                    683: }
                    684: 
                    685: static void
                    686: disk_134e06(struct bregs *regs, struct drive_s *drive_g)
                    687: {
                    688:     disk_ret(regs, DISK_RET_SUCCESS);
                    689: }
                    690: 
                    691: static void
                    692: disk_134eXX(struct bregs *regs, struct drive_s *drive_g)
                    693: {
                    694:     disk_ret(regs, DISK_RET_EPARAM);
                    695: }
                    696: 
                    697: // IBM/MS set hardware configuration
                    698: static void
                    699: disk_134e(struct bregs *regs, struct drive_s *drive_g)
                    700: {
                    701:     switch (regs->al) {
                    702:     case 0x01: disk_134e01(regs, drive_g); break;
                    703:     case 0x03: disk_134e03(regs, drive_g); break;
                    704:     case 0x04: disk_134e04(regs, drive_g); break;
                    705:     case 0x06: disk_134e06(regs, drive_g); break;
                    706:     default:   disk_134eXX(regs, drive_g); break;
                    707:     }
                    708: }
                    709: 
                    710: static void
                    711: disk_13XX(struct bregs *regs, struct drive_s *drive_g)
                    712: {
                    713:     disk_ret_unimplemented(regs, DISK_RET_EPARAM);
                    714: }
                    715: 
                    716: static void
                    717: disk_13(struct bregs *regs, struct drive_s *drive_g)
                    718: {
                    719:     //debug_stub(regs);
                    720: 
                    721:     // clear completion flag
                    722:     SET_BDA(disk_interrupt_flag, 0);
                    723: 
                    724:     switch (regs->ah) {
                    725:     case 0x00: disk_1300(regs, drive_g); break;
                    726:     case 0x01: disk_1301(regs, drive_g); break;
                    727:     case 0x02: disk_1302(regs, drive_g); break;
                    728:     case 0x03: disk_1303(regs, drive_g); break;
                    729:     case 0x04: disk_1304(regs, drive_g); break;
                    730:     case 0x05: disk_1305(regs, drive_g); break;
                    731:     case 0x08: disk_1308(regs, drive_g); break;
                    732:     case 0x09: disk_1309(regs, drive_g); break;
                    733:     case 0x0c: disk_130c(regs, drive_g); break;
                    734:     case 0x0d: disk_130d(regs, drive_g); break;
                    735:     case 0x10: disk_1310(regs, drive_g); break;
                    736:     case 0x11: disk_1311(regs, drive_g); break;
                    737:     case 0x14: disk_1314(regs, drive_g); break;
                    738:     case 0x15: disk_1315(regs, drive_g); break;
                    739:     case 0x16: disk_1316(regs, drive_g); break;
                    740:     case 0x41: disk_1341(regs, drive_g); break;
                    741:     case 0x42: disk_1342(regs, drive_g); break;
                    742:     case 0x43: disk_1343(regs, drive_g); break;
                    743:     case 0x44: disk_1344(regs, drive_g); break;
                    744:     case 0x45: disk_1345(regs, drive_g); break;
                    745:     case 0x46: disk_1346(regs, drive_g); break;
                    746:     case 0x47: disk_1347(regs, drive_g); break;
                    747:     case 0x48: disk_1348(regs, drive_g); break;
                    748:     case 0x49: disk_1349(regs, drive_g); break;
                    749:     case 0x4e: disk_134e(regs, drive_g); break;
                    750:     default:   disk_13XX(regs, drive_g); break;
                    751:     }
                    752: }
                    753: 
                    754: static void
                    755: floppy_13(struct bregs *regs, struct drive_s *drive_g)
                    756: {
                    757:     // Only limited commands are supported on floppies.
                    758:     switch (regs->ah) {
                    759:     case 0x00:
                    760:     case 0x01:
                    761:     case 0x02:
                    762:     case 0x03:
                    763:     case 0x04:
                    764:     case 0x05:
                    765:     case 0x08:
                    766:     case 0x15:
                    767:     case 0x16:
                    768:         disk_13(regs, drive_g);
                    769:         break;
                    770:     default:   disk_13XX(regs, drive_g); break;
                    771:     }
                    772: }
                    773: 
                    774: 
                    775: /****************************************************************
                    776:  * Entry points
                    777:  ****************************************************************/
                    778: 
                    779: static void
                    780: handle_legacy_disk(struct bregs *regs, u8 extdrive)
                    781: {
                    782:     if (! CONFIG_DRIVES) {
                    783:         // XXX - support handle_1301 anyway?
                    784:         disk_ret(regs, DISK_RET_EPARAM);
                    785:         return;
                    786:     }
                    787: 
                    788:     if (extdrive < EXTSTART_HD) {
                    789:         struct drive_s *drive_g = getDrive(EXTTYPE_FLOPPY, extdrive);
                    790:         if (!drive_g)
                    791:             goto fail;
                    792:         floppy_13(regs, drive_g);
                    793:         return;
                    794:     }
                    795: 
                    796:     struct drive_s *drive_g;
                    797:     if (extdrive >= EXTSTART_CD)
                    798:         drive_g = getDrive(EXTTYPE_CD, extdrive - EXTSTART_CD);
                    799:     else
                    800:         drive_g = getDrive(EXTTYPE_HD, extdrive - EXTSTART_HD);
                    801:     if (!drive_g)
                    802:         goto fail;
                    803:     disk_13(regs, drive_g);
                    804:     return;
                    805: 
                    806: fail:
                    807:     // XXX - support 1301/1308/1315 anyway?
                    808:     disk_ret(regs, DISK_RET_EPARAM);
                    809: }
                    810: 
                    811: void VISIBLE16
                    812: handle_40(struct bregs *regs)
                    813: {
                    814:     debug_enter(regs, DEBUG_HDL_40);
                    815:     handle_legacy_disk(regs, regs->dl);
                    816: }
                    817: 
                    818: // INT 13h Fixed Disk Services Entry Point
                    819: void VISIBLE16
                    820: handle_13(struct bregs *regs)
                    821: {
                    822:     debug_enter(regs, DEBUG_HDL_13);
                    823:     u8 extdrive = regs->dl;
                    824: 
                    825:     if (CONFIG_CDROM_EMU) {
                    826:         if (regs->ah == 0x4b) {
                    827:             cdemu_134b(regs);
                    828:             return;
                    829:         }
                    830:         u16 ebda_seg = get_ebda_seg();
                    831:         if (GET_EBDA2(ebda_seg, cdemu.active)) {
                    832:             u8 emudrive = GET_EBDA2(ebda_seg, cdemu.emulated_extdrive);
                    833:             if (extdrive == emudrive) {
                    834:                 // Access to an emulated drive.
                    835:                 struct drive_s *cdemu = GET_GLOBAL(cdemu_drive);
                    836:                 if (regs->ah > 0x16) {
                    837:                     // Only old-style commands supported.
                    838:                     disk_13XX(regs, cdemu);
                    839:                     return;
                    840:                 }
                    841:                 disk_13(regs, cdemu);
                    842:                 return;
                    843:             }
                    844:             if (extdrive < EXTSTART_CD && ((emudrive ^ extdrive) & 0x80) == 0)
                    845:                 // Adjust id to make room for emulated drive.
                    846:                 extdrive--;
                    847:         }
                    848:     }
                    849:     handle_legacy_disk(regs, extdrive);
                    850: }
                    851: 
                    852: // record completion in BIOS task complete flag
                    853: void VISIBLE16
                    854: handle_76()
                    855: {
                    856:     debug_isr(DEBUG_ISR_76);
                    857:     SET_BDA(disk_interrupt_flag, 0xff);
                    858:     eoi_pic2();
                    859: }
                    860: 
                    861: // Old Fixed Disk Parameter Table (newer tables are in the ebda).
                    862: struct fdpt_s OldFDPT VAR16FIXED(0xe401);

unix.superglobalmegacorp.com

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