示例#1
0
void BIOSCALL int13_harddisk(disk_regs_t r)
{
    uint32_t            lba;
    uint16_t            cylinder, head, sector;
    uint16_t            nlc, nlh, nlspt;
    uint16_t            count;
    uint8_t             device, status;
    bio_dsk_t __far     *bios_dsk;

    BX_DEBUG_INT13_HD("%s: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", __func__, AX, BX, CX, DX, ES);

    bios_dsk = read_word(0x0040,0x000E) :> &EbdaData->bdisk;
    write_byte(0x0040, 0x008e, 0);  // clear completion flag
    
    // basic check : device has to be defined
    if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_STORAGE_DEVICES) ) {
        BX_DEBUG("%s: function %02x, ELDL out of range %02x\n", __func__, GET_AH(), GET_ELDL());
        goto int13_fail;
    }
    
    // Get the ata channel
    device = bios_dsk->hdidmap[GET_ELDL()-0x80];
    
    // basic check : device has to be valid
    if (device >= BX_MAX_STORAGE_DEVICES) {
        BX_DEBUG("%s: function %02x, unmapped device for ELDL=%02x\n", __func__, GET_AH(), GET_ELDL());
        goto int13_fail;
    }

    switch (GET_AH()) {

    case 0x00: /* disk controller reset */
#ifdef VBOX_WITH_SCSI
        /* SCSI controller does not need a reset. */
        if (!VBOX_IS_SCSI_DEVICE(device))
#endif
        ata_reset (device);
        goto int13_success;
        break;

    case 0x01: /* read disk status */
        status = read_byte(0x0040, 0x0074);
        SET_AH(status);
        SET_DISK_RET_STATUS(0);
        /* set CF if error status read */
        if (status) goto int13_fail_nostatus;
        else        goto int13_success_noah;
        break;

    case 0x02: // read disk sectors
    case 0x03: // write disk sectors
    case 0x04: // verify disk sectors

        count       = GET_AL();
        cylinder    = GET_CH();
        cylinder   |= ( ((uint16_t) GET_CL()) << 2) & 0x300;
        sector      = (GET_CL() & 0x3f);
        head        = GET_DH();
        
        /* Segment and offset are in ES:BX. */        
        if ( (count > 128) || (count == 0) ) {
            BX_INFO("%s: function %02x, count out of range!\n", __func__, GET_AH());
            goto int13_fail;
        }

        /* Get the logical CHS geometry. */
        nlc   = bios_dsk->devices[device].lchs.cylinders;
        nlh   = bios_dsk->devices[device].lchs.heads;
        nlspt = bios_dsk->devices[device].lchs.spt;

        /* Sanity check the geometry. */
        if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
            BX_INFO("%s: function %02x, disk %02x, parameters out of range %04x/%04x/%04x!\n", __func__, GET_AH(), GET_DL(), cylinder, head, sector);
            goto int13_fail;
        }
        
        // FIXME verify
        if ( GET_AH() == 0x04 )
            goto int13_success;

        /* If required, translate LCHS to LBA and execute command. */
        //@todo: The IS_SCSI_DEVICE check should be redundant...
        if (( (bios_dsk->devices[device].pchs.heads != nlh) || (bios_dsk->devices[device].pchs.spt != nlspt)) || VBOX_IS_SCSI_DEVICE(device)) {
            lba = ((((uint32_t)cylinder * (uint32_t)nlh) + (uint32_t)head) * (uint32_t)nlspt) + (uint32_t)sector - 1;
            sector = 0; // this forces the command to be lba
        }

        /* Clear the count of transferred sectors/bytes. */
        bios_dsk->drqp.trsfsectors = 0;
        bios_dsk->drqp.trsfbytes   = 0;

        /* Pass request information to low level disk code. */
        bios_dsk->drqp.lba      = lba;
        bios_dsk->drqp.buffer   = MK_FP(ES, BX);
        bios_dsk->drqp.nsect    = count;
        bios_dsk->drqp.sect_sz  = 512;  //@todo: device specific?
        bios_dsk->drqp.cylinder = cylinder;
        bios_dsk->drqp.head     = head;
        bios_dsk->drqp.sector   = sector;
        bios_dsk->drqp.dev_id   = device;

        status = dskacc[bios_dsk->devices[device].type].a[GET_AH() - 0x02](bios_dsk);

        // Set nb of sector transferred
        SET_AL(bios_dsk->drqp.trsfsectors);
        
        if (status != 0) {
            BX_INFO("%s: function %02x, error %02x !\n", __func__, GET_AH(), status);
            SET_AH(0x0c);
            goto int13_fail_noah;
        }
        
        goto int13_success;
        break;

    case 0x05: /* format disk track */
          BX_INFO("format disk track called\n");
          goto int13_success;
          return;
          break;

    case 0x08: /* read disk drive parameters */

        /* Get the logical geometry from internal table. */
        nlc   = bios_dsk->devices[device].lchs.cylinders;
        nlh   = bios_dsk->devices[device].lchs.heads;
        nlspt = bios_dsk->devices[device].lchs.spt;

        count = bios_dsk->hdcount;
        /* Maximum cylinder number is just one less than the number of cylinders. */
        nlc = nlc - 1; /* 0 based , last sector not used */
        SET_AL(0);
        SET_CH(nlc & 0xff);
        SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f));
        SET_DH(nlh - 1);
        SET_DL(count); /* FIXME returns 0, 1, or n hard drives */
        
        // FIXME should set ES & DI
        // @todo: Actually, the above comment is nonsense.
        
        goto int13_success;
        break;

    case 0x10: /* check drive ready */
        // should look at 40:8E also???

        // Read the status from controller
        status = inb(bios_dsk->channels[device/2].iobase1 + ATA_CB_STAT);
        if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) {
            goto int13_success;
        } else {
            SET_AH(0xAA);
            goto int13_fail_noah;
        }
        break;

    case 0x15: /* read disk drive size */

        /* Get the physical geometry from internal table. */
        cylinder = bios_dsk->devices[device].pchs.cylinders;
        head     = bios_dsk->devices[device].pchs.heads;
        sector   = bios_dsk->devices[device].pchs.spt;

        /* Calculate sector count seen by old style INT 13h. */
        lba = (uint32_t)cylinder * head * sector;
        CX = lba >> 16;
        DX = lba & 0xffff;
        
        SET_AH(3);  // hard disk accessible
        goto int13_success_noah;
        break;

    case 0x09: /* initialize drive parameters */
    case 0x0c: /* seek to specified cylinder */
    case 0x0d: /* alternate disk reset */
    case 0x11: /* recalibrate */
    case 0x14: /* controller internal diagnostic */
        BX_INFO("%s: function %02xh unimplemented, returns success\n", __func__, GET_AH());
        goto int13_success;
        break;

    case 0x0a: /* read disk sectors with ECC */
    case 0x0b: /* write disk sectors with ECC */
    case 0x18: // set media type for format
    default:
        BX_INFO("%s: function %02xh unsupported, returns fail\n", __func__, GET_AH());
        goto int13_fail;
        break;
    }

int13_fail:
    SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
int13_fail_noah:
    SET_DISK_RET_STATUS(GET_AH());
int13_fail_nostatus:
    SET_CF();     // error occurred
    return;

int13_success:
    SET_AH(0x00); // no error
int13_success_noah:
    SET_DISK_RET_STATUS(0x00);
    CLEAR_CF();   // no error
    return;
}
示例#2
0
void print_detected_harddisks(void)
{
    uint16_t    ebda_seg=read_word(0x0040,0x000E);
    uint8_t     hd_count;
    uint8_t     hd_curr = 0;
    uint8_t     ide_ctrl_printed = 0;
    uint8_t     sata_ctrl_printed = 0;
    uint8_t     scsi_ctrl_printed = 0;
    uint8_t     device;

    hd_count = read_byte(ebda_seg, (uint16_t)&EbdaData->bdisk.hdcount);

    for (hd_curr = 0; hd_curr < hd_count; hd_curr++)
    {
        device = read_byte(ebda_seg, (uint16_t)&EbdaData->bdisk.hdidmap[hd_curr]);

#ifdef VBOX_WITH_AHCI
        if (VBOX_IS_AHCI_DEVICE(device))
        {
            if (sata_ctrl_printed == 0)
            {
                printf("\n\nAHCI controller:\n");
                sata_ctrl_printed = 1;
            }

            printf("\n    %d) Hard disk", hd_curr+1);

        }
        else
#endif
#ifdef VBOX_WITH_SCSI
        if (VBOX_IS_SCSI_DEVICE(device))
        {
            if (scsi_ctrl_printed == 0)
            {
                printf("\n\nSCSI controller:\n");
                scsi_ctrl_printed = 1;
            }

            printf("\n    %d) Hard disk", hd_curr+1);

        }
        else
#endif
        {

            if ((device < 4) && (ide_ctrl_printed == 0))
            {
                printf("IDE controller:\n");
                ide_ctrl_printed = 1;
            }
            else if ((device >= 4) && (sata_ctrl_printed == 0))
            {
                printf("\n\nAHCI controller:\n");
                sata_ctrl_printed = 1;
            }

            printf("\n    %d) ", hd_curr+1);

            /*
             * If actual_device is bigger than or equal 4
             * this is the next controller and
             * the positions start at the beginning.
             */
            if (device >= 4)
                device -= 4;

            if (device / 2)
                printf("Secondary ");
            else
                printf("Primary ");

            if (device % 2)
                printf("Slave");
            else
                printf("Master");
        }
    }

    if (   (ide_ctrl_printed == 0)
        && (sata_ctrl_printed == 0)
        && (scsi_ctrl_printed == 0))
        printf("No hard disks found");

    printf("\n");
}