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

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