DOS中调用INT13中断操作磁盘 tc3.0

来源:互联网 发布:snmp开发java 编辑:程序博客网 时间:2024/06/06 03:52
通过调用中断操作磁盘,进行扇区操作。
/* disk.cpp * * Source file for implementation of CDisk, * * Authors: perry  * Date   : February 21, 2011 * class  : CDisk * * History: *   2011/02/21  perry       created. */CDisk::CDisk(uint16_t driver) :  m_int13ext_ver(0),  m_valid(false),  m_drive(0){  union REGS    regs;  struct SREGS    sregs;  // try multiple times, if error.  for ( int i = 0; i < CALL_INT_TRIES; i++ )  {    regs.h.ah = 0x41;    regs.x.bx = 0x55aa;    regs.h.dl = driver | 0x80;    // confirm ext int 13 can be support.    int86x(0x13, ®s, ®s, &sregs);    if ( regs.x.cflag || regs.x.bx != 0xaa55 )      continue;    // 01h = 1.x    // 20h = 2.0 / EDD-1.0    // 21h = 2.1 / EDD-1.1    // 30h = EDD-3.0    m_int13ext_ver = regs.h.ah;    break;  }  regs.h.ah = 0x08;  regs.h.dl = driver | 0x80;  int86x(0x13, ®s, ®s, &sregs);  if ( regs.h.dl <= driver )  {    fprintf(stderr, "%d: drive not found\n", driver);    return;  }  if ( regs.x.cflag )  {#ifdef _DEBUG    CException      * exp = NULL;    exp = new CExceptInt13(regs.h.ah);    exp->show();    exp->destroy();#endif    return;  }  m_drive = driver;  m_valid = true;  m_cylinder_count = ((((int)regs.h.cl << 2) & 0x300) | regs.h.ch) + 1;  m_head_count = regs.h.dh + 1;  m_sector_count = regs.h.cl & 0x3f;}bool CDisk::callBios_CHS(    uint16_t cmd,    uint16_t cylinder,    uint16_t head,    uint16_t sector,    uint16_t count,    CBufferT<uint8_t> _FAR & buff){  union REGS    regs;  struct SREGS    sregs;  if ( sector < 1 )    return false;  sector &= 0x3f;  if ( cylinder > 0xff )    sector |= (cylinder >> 0x02) & 0xc0;  segread(&sregs);  // set up packet.  regs.x.bx = FP_OFF((void _FAR *)buff);  sregs.es = FP_SEG((void _FAR *)buff);  // set up registers for INT 13h AH = 02/03h.  regs.h.ch = cylinder;       // low eight bits of cylinder number  regs.h.cl = sector;         // start sector and high two bits of cylinder  regs.h.dh = head;           // head  regs.h.dl = m_drive | 0x80; // drive number  // try multiple times, if error.  for ( int i = 0; i < CALL_INT_TRIES; i++ )  {    switch ( cmd )    {    case DISK_RESET:      regs.h.ah = 0x00;       // reset.      break;    case DISK_STATUS:      regs.h.ah = 0x01;       // status.      break;    case DISK_READ:      regs.h.ah = 0x02;       // read.      break;    case DISK_WRITE:      regs.h.ah = 0x03;       // write.      break;    case DISK_VERIFY:      regs.h.ah = 0x04;       // verify.      break;    default:#ifdef _DEBUG      fprintf(stderr, "%d, invalid command.\n", cmd);#endif      return false;    }    // set sector count.    regs.h.al = count;    // call BIOS interrup    int86x(0x13, ®s, ®s, &sregs);    // call succeed.    if ( !regs.x.cflag && !regs.h.ah )      return true;#ifdef _DEBUG    // CF set on error    CException      * exp = NULL;    exp = new CExceptInt13(regs.h.ah);    exp->show();    exp->destroy();#endif    // reset disk    regs.h.ah = 0;    // call BIOS interrup    int86x(0x13, ®s, ®s, &sregs);  }  return false;}bool CDisk::callBios_LBA(    uint16_t cmd,    uint64_t lba,    uint16_t count,    CBufferT<uint8_t> _FAR & buff){  union REGS    regs;  struct SREGS    sregs;  struct lba_addr_pkt    packet;  segread(&sregs);  // set up packet.  sregs.ds = FP_SEG(&packet);  regs.x.si = FP_OFF(&packet);  packet.pkt_len = sizeof(lba_addr_pkt);  packet.nsects = count;  packet.buf_off = FP_OFF((void _FAR *)buff);  packet.buf_seg = FP_SEG((void _FAR *)buff);  packet.lba = lba;  // set up registers for INT 13h AH = 02/03h.  regs.h.ah = 0x42;           // extended read.  regs.h.dl = m_drive | 0x80; // drive number  // try multiple times, if error.  for ( int i = 0; i < CALL_INT_TRIES; i++ )  {    switch ( cmd )    {    case DISK_RESET:      regs.h.ah = 0x00;       // reset.      break;    case DISK_STATUS:      regs.h.ah = 0x01;       // status.      break;    case DISK_READ:      regs.h.ah = 0x42;       // read.      regs.h.al = 0x00;       /* AL = write flags                                 ---v1.0,2.0---                                 bit 0: verify write                                 bits 7-1 reserved (0)                                 ---v2.1+ ---                                 00h,01h write without verify                                 02h write with verify                                */      break;    case DISK_WRITE:      regs.h.ah = 0x43;       // write.      break;    case DISK_VERIFY:      regs.h.ah = 0x04;       // verify.      break;    default:#ifdef _DEBUG      fprintf(stderr, "%d, invalid command.\n", cmd);#endif      return false;    }    // call BIOS interrup    int86x(0x13, ®s, ®s, &sregs);    // call succeed.    if ( !regs.x.cflag && !regs.h.ah )      return true;#ifdef _DEBUG    // CF set on error    CException      * exp = NULL;    exp = new CExceptInt13Ex(regs.h.ah);    exp->show();    exp->destroy();#endif    // reset disk    regs.h.ah = 0;    // call BIOS interrup    int86x(0x13, ®s, ®s, &sregs);  }  return false;}bool CDisk::readSectors(    uint32_t lba31_0,    uint32_t lba63_32,    uint16_t count,    CBufferT<uint8_t> _FAR & buff){  uint64_t    lba;  // using 64 bit address.  lba.dwords.dw1 = lba31_0;  lba.dwords.dw2 = lba63_32;  return readSectors(lba, count, buff);}bool CDisk::writeSectors(    uint32_t lba31_0,    uint32_t lba63_32,    uint16_t count,    CBufferT<uint8_t> _FAR & buff){  uint64_t    lba;  // using 64 bit address.  lba.dwords.dw1 = lba31_0;  lba.dwords.dw2 = lba63_32;  return writeSectors(lba, count, buff);}bool CDisk::readSectors(    uint64_t lba,    uint16_t count,    CBufferT<uint8_t> _FAR & buff){  if ( !isValid() )    return false;  // the number of sector must be greater than zero.  if ( count < 1 )  {#ifdef _DEBUG  fprintf(stderr, "number of sectors must be greater than 0; (%d).\n", count);#endif    return false;  }  // check size of buffer.  if ( buff.length() < (count * SECTOR_PER_BYTES) )  {#ifdef _DEBUG    fprintf(stderr, "size of buffer too small; %d < (%d * %d).\n", buff.length(), count, SECTOR_PER_BYTES);#endif    return false;  }  // clear buffer  buff.clear();  // if support ext int13. using LBA mode.  if ( m_int13ext_ver > 0 )  {#ifdef _DEBUG    fprintf(stdout, "DISK_READ LBA %04x.\n", m_int13ext_ver);#endif    if ( callBios_LBA(DISK_READ, lba, count, buff) )      return true;  }  // CHS params.  uint16_t    cylinder,    head,    sector;  // translate a LBA value to an CHS value.  if ( !LBA2CHS(lba, &cylinder, &head, §or) )    return false;#ifdef _DEBUG  fprintf(stdout, "DISK_READ CHS.\n");#endif  // using CHS mode to read sectors.  return callBios_CHS(DISK_READ, cylinder, head, sector, count, buff);}bool CDisk::writeSectors(    uint64_t lba,    uint16_t count,    CBufferT<uint8_t> _FAR & buff){  if ( !isValid() )    return false;  // the number of sector must be greater than zero.  if ( count < 1 )  {#ifdef _DEBUG    fprintf(stderr, "number of sectors must be greater than 0; (%d).\n", count);#endif    return false;  }  // check size of buffer.  if ( buff.length() < (count * SECTOR_PER_BYTES) )  {#ifdef _DEBUG    fprintf(stderr, "size of buffer too small; %d < (%d * %d).\n", buff.length(), count, SECTOR_PER_BYTES);#endif    return false;  }  // if support ext int13. using LBA mode.  if ( m_int13ext_ver > 0 )  {#ifdef _DEBUG    fprintf(stdout, "DISK_WRITE LBA %04x.\n", m_int13ext_ver);#endif    if ( callBios_LBA(DISK_WRITE, lba, count, buff) )      return true;  }  // CHS params.  uint16_t    cylinder,    head,    sector;#ifdef _DEBUG  fprintf(stdout, "DISK_WRITE CHS.\n");#endif  // translate a LBA value to an CHS value.  if ( !LBA2CHS(lba, &cylinder, &head, §or) )    return false;  // using CHS mode to read sectors.  return callBios_CHS(DISK_WRITE, cylinder, head, sector, count, buff);}bool CDisk::LBA2CHS(    uint64_t lba,    uint16_t _FAR * pCylinder,    uint16_t _FAR * pHead,    uint16_t _FAR * pSector){  uint32_t    temp1 = m_head_count * m_sector_count,    temp2;  if ( !temp1 )    return false;  temp2 = lba.dwords.dw1 % temp1;  *pCylinder = (uint16_t)((lba.dwords.dw1 - temp2) / temp1);  *pHead = (uint16_t)(temp2 / m_sector_count);  *pSector = (uint16_t)(temp2 % m_sector_count + 1);  return true;}bool CDisk::CHS2LBA(    uint16_t cylinder,    uint16_t head,    uint16_t sector,    uint64_t _FAR * plba){  if ( sector < 1 )    return false;  plba->dwords.dw1 = ((cylinder * m_head_count + head) * m_sector_count) + sector - 1;  plba->dwords.dw2 = 0;  return true;}bool CDisk::saveSectors(    uint32_t lba,    uint16_t num,    const CString _FAR & file){  if ( !isValid() )    return false;  CBufferT    buff(SECTOR_PER_BYTES);  bool    result = true;  CFile    ffout(file);  for ( int i = 0; i < num; i++ )  {    if ( !readSectors(lba + i, 0, 1, buff) )    {#ifdef _DEBUG      fprintf(stderr, "FAIL ==> readSectors\n");#endif      result = false;      break;    }    if ( ffout.write(buff) != SECTOR_PER_BYTES )    {#ifdef _DEBUG      fprintf(stderr, "FAIL ==> ffout.Write\n");#endif      result = false;      break;    }  }#ifdef _DEBUG  if ( !result )    fprintf(stdout, "FAIL ==> saveSectors\n");  else    fprintf(stdout, "PASS ==> saveSectors\n");#endif  return result;}bool CDisk::saveSectors(    uint32_t lba,    uint16_t num,    CBufferT _FAR & buff){  if ( !isValid() )    return false;  if ( buff.length() < (num * SECTOR_PER_BYTES) )    return false;  return readSectors(lba, 0, num, buff);}bool CDisk::fillSectors(    uint32_t lba,    uint16_t num,    const CString _FAR & file){  if ( !isValid() )    return false;  CBufferT    buff(SECTOR_PER_BYTES);  bool    result = true;  CFile    ffin(file, O_RDONLY | O_BINARY);  for ( int i = 0; i < num; i++ )  {    // zero buffer    buff.clear();    // read data from file.    if ( ffin.read(buff) != SECTOR_PER_BYTES )    {#ifdef _DEBUG      fprintf(stderr, "FAIL ==> ffin.Read\n");#endif      result = false;      break;    }    // write buffer to sector.    if ( !writeSectors(lba + i, 0, 1, buff) )    {#ifdef _DEBUG      fprintf(stderr, "FAIL ==> writeSectors\n");#endif      result = false;      break;    }  }#ifdef _DEBUG  if ( !result )    fprintf(stdout, "FAIL ==> fillSectors\n");  else    fprintf(stdout, "PASS ==> fillSectors\n");#endif  return result;}bool CDisk::fillSectors(    uint32_t lba,    uint16_t num,    uint8_t val){  if ( !isValid() )    return false;  CBufferT    buff(SECTOR_PER_BYTES);  bool    result = true;  // fill buffer  buff.clear();  for ( int i = 0; i < num; i++ )  {    if ( !writeSectors(lba + i, 0, 1, buff) )    {#ifdef _DEBUG      fprintf(stderr, "FAIL ==> writeSectors\n");#endif      result = false;      break;    }  }#ifdef _DEBUG  if ( !result )    fprintf(stdout, "FAIL ==> fillSectors\n");  else    fprintf(stdout, "PASS ==> fillSectors\n");#endif  return result;}const char* CDisk::toString(void){  return "CDisk";}