示例#1
0
文件: aaa.c 项目: shuowen/OpenNT
GLOBAL VOID
AAA()
{
    if ( (GET_AL() & 0xf) > 9 || GET_AF() )
    {
        SET_AX(GET_AX() + 6);
        SET_AH(GET_AH() + 1);
        SET_CF(1);
        SET_AF(1);
    }
    else
    {
        SET_CF(0);
        SET_AF(0);
    }
    SET_AL(GET_AL() & 0xf);

    /* Set undefined flag(s) */
#ifdef SET_UNDEFINED_FLAG
    SET_OF(UNDEFINED_FLAG);
    SET_SF(UNDEFINED_FLAG);
    SET_ZF(UNDEFINED_FLAG);
    SET_PF(UNDEFINED_FLAG);
#endif
}
示例#2
0
文件: rcl.c 项目: chunhualiu/OpenNT
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
GLOBAL VOID
RCL
       	    	    	                    
IFN3(
	IU32 *, pop1,	/* pntr to dst/src operand */
	IU32, op2,	/* rotation count operand */
	IUM8, op_sz	/* 8, 16 or 32-bit */
    )


   {
   IU32 result;
   IU32 feedback;	/* Bit posn to feed into carry */
   ISM32 i;
   ISM32 new_of;

   /* only use lower five bits of count */
   if ( (op2 &= 0x1f) == 0 )
      return;

   /*
	    ====     =================
	 -- |CF| <-- | | | | | | | | | <--
	 |  ====     =================   |
	 ---------------------------------
    */
   feedback = SZ2MSB(op_sz);
   for ( result = *pop1, i = 0; i < op2; i++ )
      {
      if ( result & feedback )
	 {
	 result = result << 1 | GET_CF();
	 SET_CF(1);
	 }
      else
	 {
	 result = result << 1 | GET_CF();
	 SET_CF(0);
	 }
      }
   
   /* OF = CF ^ MSB of result */
   new_of = GET_CF() ^ (result & feedback) != 0;

   if ( op2 == 1 )
      {
      SET_OF(new_of);
      }
   else
      {
      do_multiple_shiftrot_of(new_of);
      }

   *pop1 = result;	/* Return answer */
   }
示例#3
0
文件: daa.c 项目: chunhualiu/OpenNT
GLOBAL VOID
DAA()
   {
   IU8 temp_al;

   temp_al = GET_AL();

   if ( (temp_al & 0xf) > 9 || GET_AF() )
      {
      temp_al += 6;
      SET_AF(1);
      }

   if ( GET_AL() > 0x99 || GET_CF() )
      {
      temp_al += 0x60;
      SET_CF(1);
      }

   SET_AL(temp_al);

   /* set ZF,SF,PF according to result */
   SET_ZF(temp_al == 0);
   SET_SF((temp_al & BIT7_MASK) != 0);
   SET_PF(pf_table[temp_al]);

   /* Set undefined flag(s) */
#ifdef SET_UNDEFINED_FLAG
   SET_OF(UNDEFINED_FLAG);
#endif
   }
示例#4
0
文件: btc.c 项目: chunhualiu/OpenNT
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
GLOBAL VOID
BTC
       	    	    	                    
IFN3(
	IU32 *, pop1,	/* pntr to lsrc/dst operand */
	IU32, op2,	/* rsrc (ie bit nr.) operand */
	IUM8, op_sz	/* 16 or 32-bit */
    )


   {
   IU32 bit_mask;

   op2 = op2 % op_sz;		/* take bit nr. modulo operand size */
   bit_mask = 1 << op2;			/* form mask for bit */
   SET_CF((*pop1 & bit_mask) != 0);	/* set CF to given bit */
   *pop1 = *pop1 ^ bit_mask;		/* Set Bit = !Bit */
   }
示例#5
0
文件: sbb.c 项目: chunhualiu/OpenNT
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
GLOBAL VOID
SBB
       	    	    	                    
IFN3(
	IU32 *, pop1,	/* pntr to dst/lsrc operand */
	IU32, op2,	/* rsrc operand */
	IUM8, op_sz	/* 8, 16 or 32-bit */
    )


   {
   IU32 result;
   IU32 carry;
   IU32 msb;
   IU32 op1_msb;
   IU32 op2_msb;
   IU32 res_msb;

   msb = SZ2MSB(op_sz);
   					/* Do operation */
   result = *pop1 - op2 - GET_CF() & SZ2MASK(op_sz);
   op1_msb = (*pop1  & msb) != 0;	/* Isolate all msb's */
   op2_msb = (op2    & msb) != 0;
   res_msb = (result & msb) != 0;
   carry = *pop1 ^ op2 ^ result;	/* Isolate carries */
					/* Determine flags */
   /*
      OF = (op1 == !op2) & (op1 ^ res)
      ie if operand signs differ and res sign different to original
      destination set OF.
    */
   SET_OF((op1_msb != op2_msb) & (op1_msb ^ res_msb));
   /*
      Formally:-     CF = !op1 & op2 | res & !op1 | res & op2
      Equivalently:- CF = OF ^ op1 ^ op2 ^ res
    */
   SET_CF(((carry & msb) != 0) ^ GET_OF());
   SET_PF(pf_table[result & BYTE_MASK]);
   SET_ZF(result == 0);
   SET_SF((result & msb) != 0);		/* SF = MSB */
   SET_AF((carry & BIT4_MASK) != 0);	/* AF = Bit 4 carry */
   *pop1 = result;			/* Return answer */
   }
示例#6
0
文件: xor.c 项目: chunhualiu/OpenNT
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
GLOBAL VOID
XOR
       	    	    	                    
IFN3(
	IU32 *, pop1,	/* pntr to dst/lsrc operand */
	IU32, op2,	/* rsrc operand */
	IUM8, op_sz	/* 8, 16 or 32-bit */
    )


   {
   IU32 result;

   result = *pop1 ^ op2;		/* Do operation */
   SET_CF(0);				/* Determine flags */
   SET_OF(0);
   SET_AF(0);
   SET_PF(pf_table[result & BYTE_MASK]);
   SET_ZF(result == 0);
   SET_SF((result & SZ2MSB(op_sz)) != 0);	/* SF = MSB */
   *pop1 = result;			/* Return answer */
   }
示例#7
0
文件: ror.c 项目: chunhualiu/OpenNT
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
GLOBAL VOID
ROR
       	    	    	                    
IFN3(
	IU32 *, pop1,	/* pntr to dst/src operand */
	IU32, op2,	/* rotation count operand */
	IUM8, op_sz	/* 8, 16 or 32-bit */
    )


   {
   IU32 result;
   IU32 feedback;		/* Bit posn to feed Bit 0 back to */
   ISM32 i;
   ISM32 new_of;

   /* only use lower five bits of count */
   if ( (op2 &= 0x1f) == 0 )
      return;

   /*
	    =================         ====
	 -> | | | | | | | | | --- --> |CF|
	 |  =================   |     ====
	 ------------------------
    */
   feedback = SZ2MSB(op_sz);
   for ( result = *pop1, i = 0; i < op2; i++ )
      {
      if ( result & BIT0_MASK )
	 {
	 result = result >> 1 | feedback;
	 SET_CF(1);
	 }
      else
	 {
示例#8
0
void BIOSCALL apm_function(sys_regs_t r)
{
    BX_DEBUG_APM("APM: AX=%04X BX=%04X CX=%04X\n", AX, BX, CX);

    CLEAR_CF();         /* Boldly expect success. */
    switch (GET_AL()) {
    case APM_CHECK:
        AX = 0x0102;    /* Version 1.2 */
        BX = 0x504D;    /* 'PM' */
        CX = 3;         /* Bits 0/1: 16-bit/32-bit PM interface */
        break;
    case APM_RM_CONN:
        // @todo: validate device ID
        // @todo: validate current connection state
        // @todo: change connection state
        break;
    case APM_PM_CONN:
        // @todo: validate device ID
        // @todo: validate current connection state
        // @todo: change connection state
        AX = APM_BIOS_SEG;              /* 16-bit PM code segment (RM segment base). */
        BX = (uint16_t)apm_pm16_entry;  /* 16-bit PM entry point offset. */
        CX = APM_BIOS_SEG;              /* 16-bit data segment. */
        SI = APM_BIOS_SEG_LEN;          /* 16-bit PM code segment length. */
        DI = APM_BIOS_SEG_LEN;          /* Data segment length. */
        break;
    case APM_32_CONN:
        // @todo: validate device ID
        // @todo: validate current connection state
        // @todo: change connection state
        AX = APM_BIOS_SEG;              /* 32-bit PM code segment (RM segment base). */
        BX = (uint16_t)apm_pm32_entry;  /* 32-bit entry point offset. */
        CX = APM_BIOS_SEG;              /* 16-bit code segment. */
        DX = APM_BIOS_SEG;              /* 16-bit data segment. */
        SI = APM_BIOS_SEG_LEN;          /* 32-bit code segment length. */
        DI = APM_BIOS_SEG_LEN;          /* Data segment length. */
        set_ebx_hi(0);
        set_esi_hi(APM_BIOS_SEG_LEN);   /* 16-bit code segment length. */
        break;
    case APM_IDLE:
        int_enable();   /* Simply halt the CPU with interrupts enabled. */
        halt();
        break;
    case APM_SET_PWR:
        // @todo: validate device ID
        // @todo: validate current connection state
        switch (CX) {
        case APM_PS_STANDBY:
            apm_out_str("Standby", APM_PORT);
            break;
        case APM_PS_SUSPEND:
            apm_out_str("Suspend", APM_PORT);
            break;
        case APM_PS_OFF:
            apm_out_str("Shutdown", APM_PORT);  /* Should not return. */
            break;
        default:
            SET_AH(APM_ERR_INVAL_PARAM);
            SET_CF();
        }
        break;
    case APM_DRV_VER:
        AX = 0x0102;    // @todo: Not right - must take driver version into account!
        break;
    case APM_DISCONN:
        // @todo: actually perform a disconnect...
    case APM_BUSY:      /* Nothing to do as APM Idle doesn't slow CPU clock. */
        break;
    case APM_GET_EVT:
        // @todo: error should be different if interface not connected + engaged
        SET_AH(APM_ERR_NO_EVENTS);  /* PM events don't happen. */
        SET_CF();
        break;
    default:
        BX_INFO("APM: Unsupported function AX=%04X BX=%04X called\n", AX, BX);
        SET_AH(APM_ERR_UNSUPPORTED);
        SET_CF();
    }
}
示例#9
0
文件: clc.c 项目: chunhualiu/OpenNT
GLOBAL VOID
CLC()
   {
   SET_CF(0);
   }
示例#10
0
void BIOSCALL int13_cdrom(uint16_t EHBX, disk_regs_t r)
{
    uint16_t            ebda_seg = read_word(0x0040,0x000E);
    uint8_t             device, status, locks;
    cdb_atapi           atapicmd;
    uint32_t            lba;
    uint16_t            count, segment, offset, size;
    bio_dsk_t __far     *bios_dsk;
    int13ext_t __far    *i13x;
    dpt_t __far         *dpt;

    bios_dsk = ebda_seg :> &EbdaData->bdisk;

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

    SET_DISK_RET_STATUS(0x00);

    /* basic check : device should be 0xE0+ */
    if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0 + 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->cdidmap[GET_ELDL()-0xE0];

    /* 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()) {

    // all those functions return SUCCESS
    case 0x00: /* disk controller reset */
    case 0x09: /* initialize drive parameters */
    case 0x0c: /* seek to specified cylinder */
    case 0x0d: /* alternate disk reset */
    case 0x10: /* check drive ready */
    case 0x11: /* recalibrate */
    case 0x14: /* controller internal diagnostic */
    case 0x16: /* detect disk change */
        goto int13_success;
        break;

    // all those functions return disk write-protected
    case 0x03: /* write disk sectors */
    case 0x05: /* format disk track */
    case 0x43: // IBM/MS extended write
        SET_AH(0x03);
        goto int13_fail_noah;
        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 0x15: /* read disk drive size */
        SET_AH(0x02);
        goto int13_fail_noah;
        break;

    case 0x41: // IBM/MS installation check
        BX = 0xaa55;    // install check
        SET_AH(0x30);   // EDD 2.1
        CX = 0x0007;    // ext disk access, removable and edd
        goto int13_success_noah;
        break;

    case 0x42: // IBM/MS extended read
    case 0x44: // IBM/MS verify sectors
    case 0x47: // IBM/MS extended seek

        /* Load the I13X struct pointer. */
        i13x = MK_FP(DS, SI);

        count   = i13x->count;
        segment = i13x->segment;
        offset  = i13x->offset;

        // Can't use 64 bits lba
        lba = i13x->lba2;
        if (lba != 0L) {
            BX_PANIC("%s: function %02x. Can't use 64bits lba\n", __func__, GET_AH());
            goto int13_fail;
        }

        // Get 32 bits lba
        lba = i13x->lba1;

        // If verify or seek
        if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
            goto int13_success;

        BX_DEBUG_INT13_CD("%s: read %u sectors @ LBA %lu to %04X:%04X\n",
                          __func__, count, lba, segment, offset);

        _fmemset(&atapicmd, 0, sizeof(atapicmd));
        atapicmd.command = 0x28;    // READ 10 command
        atapicmd.lba     = swap_32(lba);
        atapicmd.nsect   = swap_16(count);

        bios_dsk->drqp.nsect   = count;
        bios_dsk->drqp.sect_sz = 2048;

        status = pktacc[bios_dsk->devices[device].type](device, 12, (char __far *)&atapicmd, 0, count*2048L, ATA_DATA_IN, MK_FP(segment,offset));

        count = (uint16_t)(bios_dsk->drqp.trsfbytes >> 11);
        i13x->count = count;

        if (status != 0) {
            BX_INFO("%s: function %02x, status %02x !\n", __func__, GET_AH(), status);
            SET_AH(0x0c);
            goto int13_fail_noah;
        }

        goto int13_success;
        break;

    case 0x45: // IBM/MS lock/unlock drive
        if (GET_AL() > 2)
            goto int13_fail;

        locks = bios_dsk->devices[device].lock;

        switch (GET_AL()) {
        case 0 :  // lock
            if (locks == 0xff) {
                SET_AH(0xb4);
                SET_AL(1);
                goto int13_fail_noah;
            }
            bios_dsk->devices[device].lock = ++locks;
            SET_AL(1);
            break;
        case 1 :  // unlock
            if (locks == 0x00) {
                SET_AH(0xb0);
                SET_AL(0);
                goto int13_fail_noah;
            }
            bios_dsk->devices[device].lock = --locks;
            SET_AL(locks==0?0:1);
            break;
        case 2 :  // status
            SET_AL(locks==0?0:1);
            break;
        }
        goto int13_success;
        break;

    case 0x46: // IBM/MS eject media
        locks = bios_dsk->devices[device].lock;

        if (locks != 0) {
            SET_AH(0xb1); // media locked
            goto int13_fail_noah;
        }
        // FIXME should handle 0x31 no media in device
        // FIXME should handle 0xb5 valid request failed

#if 0 //@todo: implement!
        // Call removable media eject
        ASM_START
        push bp
        mov  bp, sp

        mov ah, #0x52
        int #0x15
        mov _int13_cdrom.status + 2[bp], ah
        jnc int13_cdrom_rme_end
        mov _int13_cdrom.status, #1
int13_cdrom_rme_end:
        pop bp
        ASM_END
#endif

        if (status != 0) {
            SET_AH(0xb1); // media locked
            goto int13_fail_noah;
        }

        goto int13_success;
        break;

    //@todo: Part of this should be merged with analogous code in disk.c
    case 0x48: // IBM/MS get drive parameters
        dpt = DS :> (dpt_t *)SI;
        size = dpt->size;

        // Buffer is too small
        if (size < 0x1a)
            goto int13_fail;

        // EDD 1.x
        if (size >= 0x1a) {
            uint16_t   blksize;

            blksize = bios_dsk->devices[device].blksize;

            dpt->size      = 0x1a;
            dpt->infos     = 0x74;  /* Removable, media change, lockable, max values */
            dpt->cylinders = 0xffffffff;
            dpt->heads     = 0xffffffff;
            dpt->spt       = 0xffffffff;
            dpt->blksize   = blksize;
            dpt->sector_count1 = 0xffffffff;  // FIXME should be Bit64
            dpt->sector_count2 = 0xffffffff;
        }

        // EDD 2.x
        if(size >= 0x1e) {
            uint8_t     channel, irq, mode, checksum, i;
            uint16_t    iobase1, iobase2, options;

            dpt->size = 0x1e;
            dpt->dpte_segment = ebda_seg;
            dpt->dpte_offset  = (uint16_t)&EbdaData->bdisk.dpte;

            // Fill in dpte
            channel = device / 2;
            iobase1 = bios_dsk->channels[channel].iobase1;
            iobase2 = bios_dsk->channels[channel].iobase2;
            irq     = bios_dsk->channels[channel].irq;
            mode    = bios_dsk->devices[device].mode;

            // FIXME atapi device
            options  = (1<<4); // lba translation
            options |= (1<<5); // removable device
            options |= (1<<6); // atapi device
#if VBOX_BIOS_CPU >= 80386
            options |= (mode==ATA_MODE_PIO32?1:0<<7);
#endif

            bios_dsk->dpte.iobase1  = iobase1;
            bios_dsk->dpte.iobase2  = iobase2;
            bios_dsk->dpte.prefix   = (0xe | (device % 2))<<4;
            bios_dsk->dpte.unused   = 0xcb;
            bios_dsk->dpte.irq      = irq;
            bios_dsk->dpte.blkcount = 1 ;
            bios_dsk->dpte.dma      = 0;
            bios_dsk->dpte.pio      = 0;
            bios_dsk->dpte.options  = options;
            bios_dsk->dpte.reserved = 0;
            bios_dsk->dpte.revision = 0x11;

            checksum = 0;
            for (i = 0; i < 15; ++i)
                checksum += read_byte(ebda_seg, (uint16_t)&EbdaData->bdisk.dpte + i);
            checksum = -checksum;
            bios_dsk->dpte.checksum = checksum;
        }

        // EDD 3.x
        if(size >= 0x42) {
            uint8_t     channel, iface, checksum, i;
            uint16_t    iobase1;

            channel = device / 2;
            iface   = bios_dsk->channels[channel].iface;
            iobase1 = bios_dsk->channels[channel].iobase1;

            dpt->size       = 0x42;
            dpt->key        = 0xbedd;
            dpt->dpi_length = 0x24;
            dpt->reserved1  = 0;
            dpt->reserved2  = 0;

            if (iface == ATA_IFACE_ISA) {
                dpt->host_bus[0] = 'I';
                dpt->host_bus[1] = 'S';
                dpt->host_bus[2] = 'A';
                dpt->host_bus[3] = ' ';
            }
            else {
                // FIXME PCI
            }
            dpt->iface_type[0] = 'A';
            dpt->iface_type[1] = 'T';
            dpt->iface_type[2] = 'A';
            dpt->iface_type[3] = ' ';
            dpt->iface_type[4] = ' ';
            dpt->iface_type[5] = ' ';
            dpt->iface_type[6] = ' ';
            dpt->iface_type[7] = ' ';

            if (iface == ATA_IFACE_ISA) {
                ((uint16_t __far *)dpt->iface_path)[0] = iobase1;
                ((uint16_t __far *)dpt->iface_path)[1] = 0;
                ((uint32_t __far *)dpt->iface_path)[1] = 0;
            }
            else {
                // FIXME PCI
            }
            ((uint16_t __far *)dpt->device_path)[0] = device & 1;
            ((uint16_t __far *)dpt->device_path)[1] = 0;
            ((uint32_t __far *)dpt->device_path)[1] = 0;

            checksum = 0;
            for (i = 30; i < 64; ++i)
                checksum += ((uint8_t __far *)dpt)[i];
            checksum = -checksum;
            dpt->checksum = checksum;
        }

        goto int13_success;
        break;

    case 0x49: // IBM/MS extended media change
        // always send changed ??
        SET_AH(06);
        goto int13_fail_nostatus;
        break;

    case 0x4e: // // IBM/MS set hardware configuration
        // DMA, prefetch, PIO maximum not supported
        switch (GET_AL()) {
        case 0x01:
        case 0x03:
        case 0x04:
        case 0x06:
            goto int13_success;
            break;
        default :
            goto int13_fail;
        }
        break;

    // all those functions return unimplemented
    case 0x02: /* read sectors */
    case 0x04: /* verify sectors */
    case 0x08: /* read disk drive parameters */
    case 0x0a: /* read disk sectors with ECC */
    case 0x0b: /* write disk sectors with ECC */
    case 0x18: /* set media type for format */
    case 0x50: // ? - send packet command
    default:
        BX_INFO("%s: unsupported AH=%02x\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;
}
示例#11
0
void BIOSCALL int13_cdemu(disk_regs_t r)
{
    // @TODO: a macro or a function for getting the EBDA segment
    uint16_t            ebda_seg=read_word(0x0040,0x000E);
    uint8_t             device, status;
    uint16_t            vheads, vspt, vcylinders;
    uint16_t            head, sector, cylinder, nbsectors;
    uint32_t            vlba, ilba, slba, elba;
    uint16_t            before, segment, offset;
    cdb_atapi           atapicmd;
    cdemu_t __far       *cdemu;
    bio_dsk_t __far     *bios_dsk;

    cdemu    = ebda_seg :> &EbdaData->cdemu;
    bios_dsk = ebda_seg :> &EbdaData->bdisk;

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

    /* at this point, we are emulating a floppy/harddisk */

    // Recompute the device number
    device  = cdemu->controller_index * 2;
    device += cdemu->device_spec;

    SET_DISK_RET_STATUS(0x00);

    /* basic checks : emulation should be active, dl should equal the emulated drive */
    if (!cdemu->active || (cdemu->emulated_drive != GET_DL())) {
        BX_INFO("%s: function %02x, emulation not active for DL= %02x\n", __func__, GET_AH(), GET_DL());
        goto int13_fail;
    }

    switch (GET_AH()) {

    case 0x00: /* disk controller reset */
        if (pktacc[bios_dsk->devices[device].type])
        {
            status = softrst[bios_dsk->devices[device].type](device);
        }
        goto int13_success;
        break;
    // all those functions return SUCCESS
    case 0x09: /* initialize drive parameters */
    case 0x0c: /* seek to specified cylinder */
    case 0x0d: /* alternate disk reset */  // FIXME ElTorito Various. should really reset ?
    case 0x10: /* check drive ready */     // FIXME ElTorito Various. should check if ready ?
    case 0x11: /* recalibrate */
    case 0x14: /* controller internal diagnostic */
    case 0x16: /* detect disk change */
        goto int13_success;
        break;

    // all those functions return disk write-protected
    case 0x03: /* write disk sectors */
    case 0x05: /* format disk track */
        SET_AH(0x03);
        goto int13_fail_noah;
        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 0x04: // verify disk sectors
        vspt       = cdemu->vdevice.spt;
        vcylinders = cdemu->vdevice.cylinders;
        vheads     = cdemu->vdevice.heads;
        ilba       = cdemu->ilba;

        sector    = GET_CL() & 0x003f;
        cylinder  = (GET_CL() & 0x00c0) << 2 | GET_CH();
        head      = GET_DH();
        nbsectors = GET_AL();
        segment   = ES;
        offset    = BX;

        BX_DEBUG_INT13_ET("%s: read to %04x:%04x @ VCHS %u/%u/%u (%u sectors)\n", __func__,
                          ES, BX, cylinder, head, sector, nbsectors);

        // no sector to read ?
        if(nbsectors==0)
            goto int13_success;

        // sanity checks sco openserver needs this!
        if ((sector   >  vspt)
          || (cylinder >= vcylinders)
          || (head     >= vheads)) {
            goto int13_fail;
        }

        // After validating the input, verify does nothing
        if (GET_AH() == 0x04)
            goto int13_success;

        segment = ES+(BX / 16);
        offset  = BX % 16;

        // calculate the virtual lba inside the image
        vlba=((((uint32_t)cylinder*(uint32_t)vheads)+(uint32_t)head)*(uint32_t)vspt)+((uint32_t)(sector-1));

        // In advance so we don't lose the count
        SET_AL(nbsectors);

        // start lba on cd
        slba   = (uint32_t)vlba / 4;
        before = (uint32_t)vlba % 4;

        // end lba on cd
        elba = (uint32_t)(vlba + nbsectors - 1) / 4;

        _fmemset(&atapicmd, 0, sizeof(atapicmd));
        atapicmd.command = 0x28;    // READ 10 command
        atapicmd.lba     = swap_32(ilba + slba);
        atapicmd.nsect   = swap_16(elba - slba + 1);

        bios_dsk->drqp.nsect   = nbsectors;
        bios_dsk->drqp.sect_sz = 512;

        bios_dsk->drqp.skip_b = before * 512;
        bios_dsk->drqp.skip_a = ((4 - nbsectors % 4 - before) * 512) % 2048;

        status = pktacc[bios_dsk->devices[device].type](device, 12, (char __far *)&atapicmd, before*512, nbsectors*512L, ATA_DATA_IN, MK_FP(segment,offset));

        bios_dsk->drqp.skip_b = 0;
        bios_dsk->drqp.skip_a = 0;

        if (status != 0) {
            BX_INFO("%s: function %02x, error %02x !\n", __func__, GET_AH(), status);
            SET_AH(0x02);
            SET_AL(0);
            goto int13_fail_noah;
        }

        goto int13_success;
        break;

    case 0x08: /* read disk drive parameters */
        vspt       = cdemu->vdevice.spt;
        vcylinders = cdemu->vdevice.cylinders - 1;
        vheads     = cdemu->vdevice.heads - 1;

        SET_AL( 0x00 );
        SET_BL( 0x00 );
        SET_CH( vcylinders & 0xff );
        SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt  & 0x3f ));
        SET_DH( vheads );
        SET_DL( 0x02 );   // FIXME ElTorito Various. should send the real count of drives 1 or 2
                          // FIXME ElTorito Harddisk. should send the HD count

        switch (cdemu->media) {
        case 0x01: SET_BL( 0x02 ); break;   /* 1.2 MB  */
        case 0x02: SET_BL( 0x04 ); break;   /* 1.44 MB */
        case 0x03: SET_BL( 0x05 ); break;   /* 2.88 MB */
        }

        /* Only set the DPT pointer for emulated floppies. */
        if (cdemu->media < 4) {
            DI = (uint16_t)&diskette_param_table;   // @todo: should this depend on emulated medium?
            ES = 0xF000;                            // @todo: how to make this relocatable?
        }
        goto int13_success;
        break;

    case 0x15: /* read disk drive size */
        // FIXME ElTorito Harddisk. What geometry to send ?
        SET_AH(0x03);
        goto int13_success_noah;
        break;

    // all those functions return unimplemented
    case 0x0a: /* read disk sectors with ECC */
    case 0x0b: /* write disk sectors with ECC */
    case 0x18: /* set media type for format */
    case 0x41: // IBM/MS installation check
      // FIXME ElTorito Harddisk. Darwin would like to use EDD
    case 0x42: // IBM/MS extended read
    case 0x43: // IBM/MS extended write
    case 0x44: // IBM/MS verify sectors
    case 0x45: // IBM/MS lock/unlock drive
    case 0x46: // IBM/MS eject media
    case 0x47: // IBM/MS extended seek
    case 0x48: // IBM/MS get drive parameters
    case 0x49: // IBM/MS extended media change
    case 0x4e: // ? - set hardware configuration
    case 0x50: // ? - send packet command
    default:
        BX_INFO("%s: function AH=%02x 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;
}
示例#12
0
void BIOSCALL int13_eltorito(disk_regs_t r)
{
    // @TODO: a macro or a function for getting the EBDA segment
    uint16_t        ebda_seg=read_word(0x0040,0x000E);
    cdemu_t __far   *cdemu;

    cdemu = ebda_seg :> &EbdaData->cdemu;


    BX_DEBUG_INT13_ET("%s: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", __func__, AX, BX, CX, DX, ES);
    // BX_DEBUG_INT13_ET("%s: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n", __func__, get_SS(), DS, ES, DI, SI);

    switch (GET_AH()) {

    // FIXME ElTorito Various. Not implemented in many real BIOSes.
    case 0x4a: // ElTorito - Initiate disk emu
    case 0x4c: // ElTorito - Initiate disk emu and boot
    case 0x4d: // ElTorito - Return Boot catalog
        BX_INFO("%s: call with AX=%04x not implemented.\n", __func__, AX);
        goto int13_fail;
        break;

    case 0x4b: // ElTorito - Terminate disk emu
        // FIXME ElTorito Hardcoded
        //@todo: maybe our cdemu struct should match El Torito to allow memcpy()?
        write_byte(DS,SI+0x00,0x13);
        write_byte(DS,SI+0x01,cdemu->media);
        write_byte(DS,SI+0x02,cdemu->emulated_drive);
        write_byte(DS,SI+0x03,cdemu->controller_index);
        write_dword(DS,SI+0x04,cdemu->ilba);
        write_word(DS,SI+0x08,cdemu->device_spec);
        write_word(DS,SI+0x0a,cdemu->buffer_segment);
        write_word(DS,SI+0x0c,cdemu->load_segment);
        write_word(DS,SI+0x0e,cdemu->sector_count);
        write_byte(DS,SI+0x10,cdemu->vdevice.cylinders);
        write_byte(DS,SI+0x11,cdemu->vdevice.spt);
        write_byte(DS,SI+0x12,cdemu->vdevice.heads);

        // If we have to terminate emulation
        if(GET_AL() == 0x00) {
            // FIXME ElTorito Various. Should be handled accordingly to spec
            cdemu->active = 0;  // bye bye
        }

        goto int13_success;
        break;

    default:
          BX_INFO("%s: unsupported AH=%02x\n", __func__, GET_AH());
          goto int13_fail;
          break;
    }

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

int13_success:
    SET_AH(0x00); // no error
    SET_DISK_RET_STATUS(0x00);
    CLEAR_CF();   // no error
    return;
}
示例#13
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;
}
示例#14
0
void BIOSCALL int13_harddisk_ext(disk_regs_t r)
{
    uint32_t            lba;
    uint16_t            ebda_seg = read_word(0x0040,0x000E);
    uint16_t            segment, offset;
    uint16_t            npc, nph, npspt;
    uint16_t            size, count;
    uint8_t             device, status;
    uint8_t             type;
    bio_dsk_t __far     *bios_dsk;
    int13ext_t __far    *i13_ext;
    dpt_t __far         *dpt;

    bios_dsk = read_word(0x0040,0x000E) :> &EbdaData->bdisk;

    BX_DEBUG_INT13_HD("%s: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", __func__, AX, BX, CX, DX, ES);
    
    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 int13x_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 int13x_fail;
    }

    switch (GET_AH()) {
    case 0x41: // IBM/MS installation check
        BX=0xaa55;     // install check
        SET_AH(0x30);  // EDD 3.0
        CX=0x0007;     // ext disk access and edd, removable supported
        goto int13x_success_noah;
        break;

    case 0x42: // IBM/MS extended read
    case 0x43: // IBM/MS extended write
    case 0x44: // IBM/MS verify
    case 0x47: // IBM/MS extended seek

        /* Get a pointer to the extended structure. */
        i13_ext = DS :> (int13ext_t *)SI;

        count   = i13_ext->count;
        segment = i13_ext->segment;
        offset  = i13_ext->offset;

        BX_DEBUG_INT13_HD("%s: %d sectors from lba %u @ %04x:%04x\n", __func__, 
                          count, i13_ext->lba1, segment, offset);

        // Can't use 64 bits lba
        lba = i13_ext->lba2;
        if (lba != 0L) {
            BX_PANIC("%s: function %02x. Can't use 64bits lba\n", __func__, GET_AH());
            goto int13x_fail;
        }
        
        // Get 32 bits lba and check
        lba = i13_ext->lba1;

        type = bios_dsk->devices[device].type;
        if (lba >= bios_dsk->devices[device].sectors) {
              BX_INFO("%s: function %02x. LBA out of range\n", __func__, GET_AH());
              goto int13x_fail;
        }

        /* Don't bother with seek or verify. */
        if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
            goto int13x_success;

        /* 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(segment, offset);
        bios_dsk->drqp.nsect   = count;
        bios_dsk->drqp.sect_sz = 512;   //@todo: device specific?
        bios_dsk->drqp.sector  = 0;     /* Indicate LBA. */
        bios_dsk->drqp.dev_id  = device;
        
        /* Execute the read or write command. */
        status = dskacc[type].a[GET_AH() - 0x42](bios_dsk);
        count  = bios_dsk->drqp.trsfsectors;
        i13_ext->count = count;
        
        if (status != 0) {
            BX_INFO("%s: function %02x, error %02x !\n", __func__, GET_AH(), status);
            SET_AH(0x0c);
            goto int13x_fail_noah;
        }
        
        goto int13x_success;
        break;

    case 0x45: // IBM/MS lock/unlock drive
    case 0x49: // IBM/MS extended media change
        goto int13x_success;   // Always success for HD
        break;

    case 0x46: // IBM/MS eject media
        SET_AH(0xb2);          // Volume Not Removable
        goto int13x_fail_noah; // Always fail for HD
        break;

    case 0x48: // IBM/MS get drive parameters
        dpt = DS :> (dpt_t *)SI;
        size = dpt->size;

        /* Check if buffer is large enough. */
        if (size < 0x1a)
            goto int13x_fail;
        
        /* Fill in EDD 1.x table. */
        if (size >= 0x1a) {
            uint16_t   blksize;

            npc     = bios_dsk->devices[device].pchs.cylinders;
            nph     = bios_dsk->devices[device].pchs.heads;
            npspt   = bios_dsk->devices[device].pchs.spt;
            lba     = bios_dsk->devices[device].sectors;
            blksize = bios_dsk->devices[device].blksize;

            dpt->size      = 0x1a;
            dpt->infos     = 0x02;  // geometry is valid
            dpt->cylinders = npc;
            dpt->heads     = nph;
            dpt->spt       = npspt;
            dpt->blksize   = blksize;
            dpt->sector_count1 = lba;   // FIXME should be Bit64
            dpt->sector_count2 = 0;
        }

        /* Fill in EDD 2.x table. */
        if (size >= 0x1e) {
            uint8_t     channel, irq, mode, checksum, i, translation;
            uint16_t    iobase1, iobase2, options;
            
            dpt->size = 0x1e;
            dpt->dpte_segment = ebda_seg;
            dpt->dpte_offset  = (uint16_t)&EbdaData->bdisk.dpte;
            
            // Fill in dpte
            channel = device / 2;
            iobase1 = bios_dsk->channels[channel].iobase1;
            iobase2 = bios_dsk->channels[channel].iobase2;
            irq     = bios_dsk->channels[channel].irq;
            mode    = bios_dsk->devices[device].mode;
            translation = bios_dsk->devices[device].translation;
            
            options  = (translation == GEO_TRANSLATION_NONE ? 0 : 1 << 3);  // chs translation
            options |= (1 << 4);    // lba translation
            options |= (mode == ATA_MODE_PIO32 ? 1 : 0 << 7);
            options |= (translation == GEO_TRANSLATION_LBA ? 1 : 0 << 9);
            options |= (translation == GEO_TRANSLATION_RECHS ? 3 : 0 << 9);
            
            bios_dsk->dpte.iobase1  = iobase1;
            bios_dsk->dpte.iobase2  = iobase2;
            bios_dsk->dpte.prefix   = (0xe | (device % 2)) << 4;
            bios_dsk->dpte.unused   = 0xcb;
            bios_dsk->dpte.irq      = irq;
            bios_dsk->dpte.blkcount = 1;
            bios_dsk->dpte.dma      = 0;
            bios_dsk->dpte.pio      = 0;
            bios_dsk->dpte.options  = options;
            bios_dsk->dpte.reserved = 0;
            bios_dsk->dpte.revision = 0x11;
            
            checksum = 0;
            for (i = 0; i < 15; ++i)
                checksum += read_byte(ebda_seg, (uint16_t)&EbdaData->bdisk.dpte + i);
            checksum = -checksum;
            bios_dsk->dpte.checksum = checksum;
        }

        /* Fill in EDD 3.x table. */
        if(size >= 0x42) {
            uint8_t     channel, iface, checksum, i;
            uint16_t    iobase1;

            channel = device / 2;
            iface   = bios_dsk->channels[channel].iface;
            iobase1 = bios_dsk->channels[channel].iobase1;
            
            dpt->size       = 0x42;
            dpt->key        = 0xbedd;
            dpt->dpi_length = 0x24;
            dpt->reserved1  = 0;
            dpt->reserved2  = 0;
            
            if (iface == ATA_IFACE_ISA) {
                dpt->host_bus[0] = 'I';
                dpt->host_bus[1] = 'S';
                dpt->host_bus[2] = 'A';
                dpt->host_bus[3] = ' ';
            }
            else {
                // FIXME PCI
            }
            dpt->iface_type[0] = 'A';
            dpt->iface_type[1] = 'T';
            dpt->iface_type[2] = 'A';
            dpt->iface_type[3] = ' ';
            dpt->iface_type[4] = ' ';
            dpt->iface_type[5] = ' ';
            dpt->iface_type[6] = ' ';
            dpt->iface_type[7] = ' ';
            
            if (iface == ATA_IFACE_ISA) {
                ((uint16_t __far *)dpt->iface_path)[0] = iobase1;
                ((uint16_t __far *)dpt->iface_path)[1] = 0;
                ((uint32_t __far *)dpt->iface_path)[1] = 0;
            }
            else {
                // FIXME PCI
            }
            ((uint16_t __far *)dpt->device_path)[0] = device & 1; // device % 2; @todo: correct?
            ((uint16_t __far *)dpt->device_path)[1] = 0;
            ((uint32_t __far *)dpt->device_path)[1] = 0;
            
            checksum = 0;
            for (i = 30; i < 64; i++)
                checksum += read_byte(DS, SI + i);
            checksum = -checksum;
            dpt->checksum = checksum;
        }

        goto int13x_success;
        break;

    case 0x4e: // // IBM/MS set hardware configuration
        // DMA, prefetch, PIO maximum not supported
        switch (GET_AL()) {
        case 0x01:
        case 0x03:
        case 0x04:
        case 0x06:
            goto int13x_success;
            break;
        default :
            goto int13x_fail;
        }
        break;

    case 0x50: // IBM/MS send packet command
    default:
        BX_INFO("%s: function %02xh unsupported, returns fail\n", __func__, GET_AH());
        goto int13x_fail;
        break;
    }

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

int13x_success:
    SET_AH(0x00); // no error
int13x_success_noah:
    SET_DISK_RET_STATUS(0x00);
    CLEAR_CF();   // no error
    return;
}