If you are smart enough, you will understand that I'm not a simple boy!

2009年8月29日星期六

LBA大硬盘读写方法

硬盘参数表是可以从BIOS内存区获取得到的。GRUB也会提供。
IDE应该没问题。
我上网本是SATA 160GB硬盘,貌似也能工作,可能与BIOS有关?哪位大牛帮忙解释一下。

//硬盘参数表
typedef struct HD_PARAMS{
 t_16 cyls; //柱面数
 t_8 heads; //磁头数
 t_16 null0; //
 t_16 WPC; //预补偿柱面号
 t_8 null1; //
 t_8 controlByte; //控制字节
 t_8 null2;
 t_8 null3;
 t_8 null4;
 t_16 lzone; //磁头登陆柱面号
 t_8 SPT; //每次道扇区数
 t_8 null5;
}__attribute__((packed)) HD_PARAMS;


//硬盘端口,状态码及分区表
#define HD_DATA  0x1f0
#define HD_CMD  0x3f6
#define HD_STATUS 0x1f7
#define HD_COMMAND HD_STATUS
//状态码
#define STAT_ERR 0x01
#define STAT_INDEX 0x02
#define STAT_ECC 0x04
#define STAT_DRQ 0x08
#define STAT_SEEK 0x10
#define STAT_WRERR 0x20
#define STAT_READY 0x40
#define STAT_BUSY 0x80

int lba_rw_sectors(t_8 dev, t_32 sec_start, t_32 sec_count, uchar *buf, int write)
{
// printf("rwhd %x, %x, %x, 0x%x, %d\n",
//  dev, sec_start, sec_count, buf, write);
 /*采用LBA方式读写*/
 int drive;
 if( dev<5 )
  drive=0;
 else
  drive=1;
 outbyte(HD_CMD, hd_param[drive].controlByte); /*输出控制字节*/
 outbyte(HD_DATA+2, sec_count);   /*设置扇区数*/
 outbyte(HD_DATA+3, sec_start);   /*lba低8位*/
 outbyte(HD_DATA+4, sec_start>>8);  /*lba次8位*/
 outbyte(HD_DATA+5, sec_start>>16);  /*lba中8位*/
 outbyte(HD_DATA+6,0xe0|(drive<<4)|(sec_start&0x0f000000)>>24); /*驱动器号,lba高4位*/
 if(write){ /*写硬盘*/
  outbyte(HD_STATUS, 0x30);
 }else{  /*读硬盘*/
  outbyte(HD_STATUS, 0x20);
 }
 while(sec_count){
  while( ( inbyte(HD_STATUS) & 0xf ) != STAT_DRQ )
   Thread::Sleep(1);
  if(write)
   WRITE_WORDS(HD_DATA, buf, 256); /*写端口数据*/
  else
   READ_WORDS(HD_DATA, buf, 256); /*读端口数据*/
  buf += 512;
  sec_count--;
 }
 return sec_count;
}

没有评论:

发表评论

关注者