tag 标签: int13

相关博文
  • 热度 18
    2015-4-23 16:44
    5418 次阅读|
    0 个评论
    DOS下BIOS中断INT13H、IO端口直接编程读取IDE、SATA硬盘的参数和TC语言程序 wxleasyland@sina.com 2015.4   一、    背景 华硕笔记本电脑A45VD,640GB SATA机械硬盘放在硬盘位,120GB SSD SATA硬盘放在光驱位。BIOS中设置SATA为 AHCI方式(不是IDE兼容方式)。 在WIN7看,SATA控制器是Intel 7 Series/C216 Chipset Family SATA AHCI Controller,硬件ID是VEN_8086DEV_1E03CC_010601,位置在PCI总线0,设备31,功能2。 640GB机械硬盘是在CHANNEL0(通道0,即安装在SATA控制器接口PORT0上)。 120GB SSD硬盘是在通道2(即安装在SATA控制器接口PORT2上)。 SSD设置成为启动盘。因为BIOS启动设置是SSD硬盘,故在DOS下,机械硬盘就排第2了,即磁盘号81H。   以下均是对640GB机械硬盘进行分析。   二、    INT 13H 传统中断,AH=08H (1)  读取驱动器参数 AH=08H 入口: DL=驱动器,00H~7FH:软盘;80H~0FFH:硬盘 返回: CF=1——操作失败,AH=状态代码 CF=0 成功 BL=01H — 360K =02H — 1.2M =03H — 720K =04H — 1.44M =05H   ?? =06H  2.88M =10H  ATAPI可移动介质 CH=最大柱面号的低8位   low eight bits of maximum cylinder number(柱面号从0开始算) CL的位7-6=最大柱面号的高2位 high two bits of maximum cylinder number CL的位5-0=最大扇区号 maximum sector number(扇区号从1开始算) DH=最大磁头号 maximum head number(磁头号从0开始算) DL=驱动器数 number of drives ES:DI=磁盘驱动器参数表地址(只软驱)   (2) 注意: 1. 得到的数值是“编号”、不是“总个数”! “总个数”是number of ... “编号”是xxx number 扇区号从1开始,故 扇区数=最大扇区号 磁头号从0开始,故 磁头数=最大磁头号+1   2. BIOS 保留最后1个柱用于测试目的,这个柱不报告出来,而且柱面号从0开始,所以   柱面总个数=最大柱面号+2! There is one "test cylinder", It is last cylinder on drive, which is always reserved for test purposes, and therefore not reported by BIOS to be.(这点说明在http://computer-programming-forum.com/46-asm/16321e22892a8381.htm)   这两点说明看似简单,但是是经过研究很久才知道的!!!   (3)实测 U盘软驱启动,98版DOS下DEBUG, INT13H ,AH=08H ,DL=81H硬盘: 得到AX=0,BX=0,CH=FE(1022,即0~1022+1柱号),CL=FF(63,即1~63扇号),DH=FE(254,即0~254头号),DL=2(即2个硬盘),ES:DI没有数据。 即1024柱×255头×63扇=16450560扇,合8.4G硬盘,总容量不一致。   可以看出,除柱面个数外,磁头数、扇区数与后面DISKMAN一致。   可以将柱面个数单独计算,柱面个数=实际LBA总扇区数÷头数÷每道扇区数,DISKMAN就是这么做的。     三、    INT 13H 扩展中断,AH=48H (1)获取磁盘参数 入口: AH=48H DL=驱动器号 DS:SI=指向缓冲区的指针(即返回的数据会保存在这个缓冲区中) 返回: 失败: AH=错误号 CF置位 成功: AH=0 CF=0 缓冲区中偏移量: 04H  双字   柱面总个数  ――注意:是“总个数” 08H  双字   物理磁头总个数 0CH  双字   物理每道扇区总个数 10H  4字     扇区总个数 18H  字      每扇区字节数   (2)实测 U盘软驱启动,98版DOS下DEBUG, INT13H扩展 ,AH=48H ,DL= 81H 硬盘,得到: 16383柱,16头,63扇,乘起来是16514064总扇区,即8.4G的硬盘,总容量不一致。 总扇区数是1250263728扇区,OK,总扇区数与AIDA,DISKMAN检测是一致的。   (3)分析 “INT13H扩展”返回的是16头,而“INT13传统”返回的是255头!! “INT13H扩展”返回的直接就是硬盘的ATA参数,即与直接访问硬盘端口得到的参数是一样的! 而“INT13传统”返回的数值是BIOS加工转换后的,与分区表中的格式相一致。 ATA参数一般是16头最多了,而分区表中参数会是255头。也就是说,硬盘的ATA参数格式,与分区表参数格式是不一样的,所以造成了早期硬盘的一些容量限制问题。     四、    DISKMAN 用USB软驱启动到DOS,运行DISKMAN(打开时提示分区不对,忽略之),显示是“第2硬盘”。   DISKMAN得到的参数说明下: DISKMAN的CMOS参数CHS,12289柱面,255磁头,63扇区,是按照“传统INT 13H” AH=08来得到的。 其中, 柱面数是反算的 ,去掉小数,转成16进制,因变量只有2字节,只能保存低2字节,即1250263728总扇÷255头÷63扇=77825.32柱→0x13001,只能保存2字节,故是0x3001→12289柱。 “总扇区数”1250263728,是按“INT 13H扩展”得到的。     五、    分区表与“传统INT13H”兼容 分区表中,主分区和扩展分区必须要从新柱面开始(扩展分区中的逻辑盘不用)。 通过研究640GB机械硬盘上分区表中的分区起始LBA地址,看能不能被头、扇整除。发现分区是按255头、63扇来分的,而不是16头。即与“传统INT13H”兼容。 即分区软件分区时,要以“传统INT13H”得到的参数(柱面数除外)去进行分区。     六、    BIOS 是支持SATA硬盘读写的 从前面可看出,BIOS是直接支持SATA硬盘的读写的,用“INT 13H扩展”访问即可!!因为主板厂家自己知道是用什么型号的SATA控制器,知道如何去控制它,并且它还要读取硬盘的MBR进行启动,所以BIOS必须支持SATA硬盘读写。所以DOS下直接用INT 13H即可读写SATA硬盘扇区,用GHOST软件克隆就不是问题了。 那为什么XP安装时,需要加载SATA驱动?因为WINDOWS不使用INT 13H去访问硬盘,而是自己要去底层访问SATA控制器,如果它不认识SATA控制器,就访问不了硬盘了。       七、    直接IO读取IDE硬盘 (1)ATA控制器、IDE硬盘 在电脑上,连接结构是这样的:   CPU――数据总线、地址总线、控制总线――PCI控制器――PCI总线――ATA控制器                                                                ∧         ∧                                                                |  硬盘线 |                                                                ∨         ∨                                                                 IDE接口硬盘   硬盘IDE接口的数据线、控制线、地址线是分开的,IDE硬盘线有40芯之多,数据口直接挂在PCI的总线上,所以CPU可以直接访问到它。 ATA控制器是把IO端口地址转换到IDE硬盘接口上,从而CPU可以IN、OUT这些IO端口,直接访问到硬盘! 因此,IDE硬盘的IO端口是固定的,一组为命令寄存器组(Task File Registers),I/O的端口地址为1F0H~1F7H,其作用是传送命令与命令参数。另一组为控制/诊断寄存器(Control/Diagnostic Registers),I/O的端口地址为3F6H~3F7H,其作用是控制硬盘驱动器。   可以直接用单片机直接控制IDE硬盘: 单片机――40芯硬盘线――IDE硬盘 这个比较容易就能实现,将IDE接口的数据线、控制线、地址线分别连线控制就可以,物理电气信号连接不复杂。   注:ATA应是指协议标准,IDE应是指接口 相关详细说明可参考《如何在MCS-51系统中使用IDE硬盘》、《IDE接口硬盘读写技术》、《基于单片机的IDE硬盘控制的研究与设计》等文章。     (2)访问方法 引用别人说的(有修改): ①向端口3F6H写入控制字节,建立相应的硬盘控制方式; ②检验硬盘控制器和驱动器的状态(检测端口的第7和第6两位),如果控制器空闲而且驱动器就绪,即可输入命令; ③完整的输入7个字节长度的命令块,一次写入端口1F1H-1F7H,不论是否需要,端口1F1H-1F6H对应的6个字节的参数必须给出,端口1F7H的输出命令码为“0ECH”; ④检测端口1F7H的第7和第3两位,如果控制器空闲且第3位置1,表示操作结束,即可读取结果; ⑤通过端口1F0H读取数据,读取256个WORD到缓冲区,注意这里的数据是WORD 16位(2字节)的; ⑥再次读取端口1F7H,判断第0位是否为0,如果为0,表示命令成功,否则表示命令失败;   读出的256字节信息的主要内容如下: 偏移量          内 容               长度(字节) 00-01H    2字节 02H-03H      柱面总个数             2字节             04-05H     2字节 06H-07H      磁头总个数             2字节             08H-09H      每磁道所含的字节数     2字节             0AH-0BH       每扇区所含的字节数     2字节             0CH-0DH       每磁道所含的扇区个数   2字节             0EH-13H   6字节 14H-27H      产品的序列号           20字节            28H-29H   2字节 2AH-2BH       硬盘缓冲区容量         2字节             2CH-2DH       ECC校验码的长度       2字节             2EH-35H      硬件软体版本号         8字节             36H-5DH      硬盘型号               40字节             (3)程序 引用别人的(有修改),wxlhd1.c:   #include #include #include #include #include   #define BASEADDR1F0 0x1F0 #define BASEADDR3F6 0x3F6   void hdinfor2()    {     unsigned int i,j;     unsigned char p;       j=0;     p=0;     while (p!=0x40)          /*  必须RDY,并且不忙。读1f7H状态寄存器  0100 0000  bit6=1表示RDY*/     {        j++;       if (j=255) { printf("error1! NOT RDY NOT BSY.   ERR REG=%02X", inportb(BASEADDR1F0+1));  exit(0);}        p=inportb(BASEADDR1F0+7);        printf("%02X ",p);        p=0xc0;       /*  1100 0000 bit6=1表示RDY,BIT7=1是忙*/     }     printf("ok1 \n");       outportb(BASEADDR3F6,0);   /* 写3F6H 设备控制寄存器   0000 0000 BIT1中断允许  BIT2非复位*/       for(i=0;i5;i++)  outportb(BASEADDR1F0+1+i,0);    /* 写 1F1H~1F5H */     outportb(BASEADDR1F0+6, 0xa0);         /*  驱动器/磁头寄存器 1010 0000  BIT6=0非LBA方式 */     outportb(BASEADDR1F0+7, 0xec);         /*  写命令寄存器 */       j=0;     p=0;     while(p!=0x8)              /*必须有中断请求产生,并且不忙*/     {        j++;       if (j=255) { printf("error2! NOT RDY NOT IRQ.   ERR REG=%02X", inportb(BASEADDR1F0+1));  exit(0);}         p=inportb(BASEADDR1F0+7);            printf("%02X ",p);        p=0x88;          /* 1000 1000 BIT3=1是有中断请求,BIT7=1是忙 */     }     printf("ok2 \n");     /* 读1F0H数据寄存器 */     p=0;     for(i=0; i256; i++)     {        j=inport(BASEADDR1F0);                /* 应该要一次读出2字节,而不是1字节! 所以用inport 。        硬盘中就是高字节在后, inport读出来就是高字节放在高字节上。        比如硬盘中是11 22,inport读出来就是0x2211        */        printf("%02X %02X ",(unsigned char) j, (unsigned char) (j8) );        p++;        if(p=8)        {            /*printf("\n");*/            p=0;        }            }       return; }     void main() {     hdinfor2(); }     (4)DOS下运行 在DOS下运行,肯定失败,因为这里是SATA AHCI控制器,没有传统的IDE端口。 在虚拟机下DOS运行,OK,成功。       八、    直接读取SATA硬盘之(一)、SATA AHCI控制器、SATA硬盘   在电脑上,连接结构是这样的:   CPU――数据总线、地址总线、控制总线――PCI控制器――PCI总线――AHCI控制器――串行硬盘线――SATA硬盘   SATA硬盘没有直接挂在PCI的总线上,所以CPU无法直接访问到它,CPU只能访问AHCI控制器。 AHCI控制器与SATA硬盘之间是通过SATA协议进行通讯的,这个可以不用管它,只需要考虑如何访问AHCI控制器即可。 也就是说,AHCI控制器把SATA接口封装掉了,内部完成与SATA硬盘之间的电气信号连接、协议通讯。我们只需要访问AHCI控制器,大大简化了操作。   PCI转SATA口的转换卡,也能接SATA硬盘,上面也是带了控制器,原理是一样的,不做研究。   如果用单片机直接控制SATA硬盘: 单片机――串行硬盘线――SATA硬盘 个人认为这几乎是不可能的事情,串行信号速率太高了,物理电气信号连接单片机很困难,更何况SATA通讯协议又很复杂。 所以要接一个控制器,让控制器来代劳。 单片机――控制器――串行硬盘线――SATA硬盘 控制器当然不限于AHCI控制器这么复杂的东东,可以是转成简单一些的,比如USB To SATA接口芯片、SATA转IDE的转换卡等等,都可以。(个人观点)   AHCI控制器是一个PCI设备,访问起来比较复杂。需要先得到它的“PCI配置空间”信息,从而得到控制器的“内存空间”地址,再对“内存空间”进行读写,达到访问AHCI控制器的目的。