admin管理员组文章数量:1654277
硬盘的chs模式是指chs(Cylinder/Head/Sector)模式, 既磁头数(Heads), 柱面数(Cylinders), 扇区数(Sectors per track),以及相应的寻址方式. 刚一开始硬盘的容量还非常小, 人们采用与软盘类似的结构生产硬盘. 也就是硬盘盘片的每一条磁道都具有相同的扇区数。
其中:
磁头数(Heads) 表示硬盘总共有几个磁头,也就是有几面盘片, 最大为 256 (用 8 个二进制位存储), 取值范围为: 0 到 Heads-1;
柱面数(Cylinders) 表示硬盘每一面盘片上有几条磁道, 最大为 1024(用 10 个二进制位存储),取值范围为: 0 到 Cylinders-1;
扇区数(Sectors per track) 表示每一条磁道上有几个扇区, 最大为63 (用 6 个二进制位存储),取值范围为: 1 到 Sectors per track (注意是从 1 开始), 每个扇区一般是 512个字节.
所以磁盘最大容量为: 256 * 1024 * 63 * 512 / 1048576 = 8064 MB ( 1M = 1048576 Bytes)
有以下几种尺寸单位:扇区 (Sector) = 512 字节 (一般情况下)磁道 (Track) = (Sectors per track) 扇区
柱面 (Cylinder)= (Sectors per track) * Heads 扇区
这种方式会浪费很多磁盘空间 (与软盘一样). 为了解决这一问题, 进一步提高硬盘容量, 人们改用等密度结构生产硬盘. 也就是说, 外圈磁道的扇区比内圈磁道多. 采用这种结构后, 硬盘不再具有实际的3D参数, 寻址方式也改为线性寻址, 即以扇区为单位进行寻址.为了与使用3D寻址的老软件兼容 (如使用BIOS Int13H接口的软件), 在硬盘控制器内部安装了一个地址翻译器, 由它负责将老式3D参数翻译成新的线性参数. 这也是为什么现在硬盘的3D参数可以有多种选择的原因 (不同的工作模式, 对应不同的3D参数,如 LBA, LARGE, NORMAL). CHS模式只能识别大硬盘的前面8G.lba使用的线性寻址,突破了1024柱面的限制,能访问8G以外的空间了。
LBA寻址模式是直接以扇区为单位进行寻址的,将硬盘划分成一个一个扇区,寻址是从0扇区开始到最后一个扇区。把硬盘所有的物理扇区的C/H/S编号通过一定的规则转变为一线性的编号,不再用磁头/柱面/扇区三种单位来进行寻址,将CHS这种三维寻址方式转变为一维的线性寻址,它提高了效率简化了操作。
主要:CHS寻址是从1扇区开始,LBA寻址是从0扇区开始.实际编程时一定要注意这一点。
端口 | LBA | CHS | ||
| 读 | 写 | 读 | 写 |
1f0h | 数据寄存器 | |||
1f1h | 错误寄存器 | 特征寄存器 | 错误寄存器 | 写前预补偿寄存器 |
1f2h | 扇区数寄存器 | |||
1f3h | LBA块地址(0~7位) | 扇区号寄存器 | ||
1f4h | LBA块地址(8~15位) | 柱面号寄存器(高地址) | ||
1f5h | LBA块地址(16~23位) | 柱面号寄存器(低地址) | ||
1f6h | 驱动器号+LBA块地址(24~27位) | 驱动器号/磁头号 | ||
1f7h | 状态寄存器 | 命令寄存器 | 状态寄存器 | 命令寄存器 |
36f | 交换状态寄存器 | 硬盘控制寄存器 | 无 | 硬盘控制寄存器 |
1f6寄存器
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
1 | L | 1 | DRV | HS3 | HS2 | HS1 | HS0 |
L:0,使用CHS模式;1,使用LBA模式
DRV:0,主盘;1,从盘
HS0~HS3:LBA模式下是LBA块地址的24~27位。CHS模式下是磁头号的低四位
添加头文件
#ifndef HDREG_H
#define HDREG_H
#define HD_DATA 0x1f0
#define HD_ERROR 0x1f1
#define HD_STATUS 0x1f7
#define HD_PRECOMP HD_ERROR
#define HD_COMMAND HD_STATUS
#define HD_CMD 0x3f6
#endif
kernel目录下添加blk_drv目录,blk_drv目录下添加hd.c和Makefile,hd_out的主要作用就是向寄存器中填充数据,以完成相应的读写等操作。
blk_drv目录下的hd.c
#include <linux/head.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/hdreg.h>
#include <asm/system.h>
#include <asm/io.h>
extern void hd_interrupt(void);
#define port_read(port,buf,nr) \
__asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr):)
#define port_write(port,buf,nr) \
__asm__("cld;rep;outsw"::"d" (port),"S" (buf),"c" (nr):)
static int controller_ready(void)
{
int retries=10000;
while (--retries && (inb_p(HD_STATUS)&0x80));
return (retries);
}
#define LBA
#ifdef LBA
/*
*drive-硬盘号(0或1)
*nsect-要读写的扇区数
*lba -起始扇区
*cmd -命令码
*/
static void hd_out(unsigned int drive,unsigned int nsect,unsigned int lba,unsigned int cmd)
{
register int port asm("dx");
if (drive>1)
printk("Trying to write bad sector");
if (!controller_ready())
printk("HD controller not ready");
outb_p(0,HD_CMD);
port=HD_DATA;
outb_p(0,++port);
outb_p(nsect,++port);
outb_p(lba&0xff,++port);
outb_p((lba>>8)&0xff,++port);
outb_p((lba>>16)&0xff,++port);
outb_p(0xE0|(drive<<4)|((lba>>24)&0xf),++port);
outb(cmd,++port);
}
#else
/*
*drive-硬盘号(0或1)
*nsect-要读写的扇区数
*sect -起始扇区
*head -磁头号
*cyl -柱面号
*cmd -命令码
*/
static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
unsigned int head,unsigned int cyl,unsigned int cmd)
{
register int port asm("dx");
if (drive>1 || head>15)
printk("Trying to write bad sector");
if (!controller_ready())
printk("HD controller not ready");
outb_p(0,HD_CMD);
port=HD_DATA;
outb_p(0,++port);
outb_p(nsect,++port);
outb_p(sect,++port);
outb_p(cyl,++port);
outb_p(cyl>>8,++port);
outb_p(0xA0|(drive<<4)|head,++port);
outb(cmd,++port);
}
#endif
void hd_init(void)
{
set_intr_gate(0x2E,&hd_interrupt);
outb_p(inb_p(0x21)&0xfb,0x21);
outb(inb_p(0xA1)&0xbf,0xA1);
}
void print_identify_info(u16* hdinfo)
{
//看手册77页这张表
printk("Number of logical cylinders:%x\n",hdinfo[1]);
printk("Number of logical heads:%x\n",hdinfo[3]);
printk("sectors per track:%x\n",hdinfo[6]);
hdinfo[20]='\0';
printk("Serial number:%s\n",&hdinfo[10]);
printk("obsolete:%x\n",hdinfo[22]);
}
#define SECTOR_SIZE 512
u8 hdbuf[SECTOR_SIZE * 2];
void hd_identify(int drive)//读identify
{
#ifdef LBA
hd_out(0,0,0,0xEC);
#else
hd_out(0,0,0,0,0,0xEC);
#endif
delay(12);
port_read(HD_DATA, hdbuf, SECTOR_SIZE);
print_identify_info((u16*)hdbuf);
}
在main.c中添加测试程序
hd_init();//初始化
hd_identify(0);//读identity
move_to_user_mode();
blk_drv目录下的Makefile
AR =ar
AS =as
LD =ld
LDFLAGS = --oformat binary -N -e start -Ttext 0x0
CC =gcc
CFLAGS = -I../../include -fno-stack-protector
.c.s:
$(CC) $(CFLAGS) \
-S -o $*.s $<
.s.o:
$(AS) -c -o $*.o $<
.c.o:
$(CC) $(CFLAGS) \
-c -o $*.o $<
OBJS = hd.o
lib.a: $(OBJS)
$(AR) rcs blk_drv.a $(OBJS)
sync
clean:
rm -f *.o *.s *.a
System_call.S文件中添加硬盘中断处理函数hd_interrupt:
hd_interrupt:
movb $0x20,%al
outb %al,$0xA0
outb %al,$0x20
iret
先修改chr_drv下的Makefile,将其编译成一个库chr_drv.a,并相应修改kernel下的Makefile,最后修改顶层目录的Makefile
DRIVERS =kernel/blk_drv/blk_drv.a kernel/chr_drv/chr_drv.a
kernel/blk_drv/blk_drv.a:
(cd kernel/blk_drv; make)
kernel/chr_drv/chr_drv.a:
(cd kernel/chr_drv; make)
system: boot/head.o init/main.o kernel/kernel.o fs/fs.o $(LIBS) $(DRIVERS)
$(LD) $(LDFLAGS) -o system boot/head.o kernel/kernel.o init/main.o fs/fs.o $(LIBS) $(DRIVERS)
版权声明:本文标题:添加硬盘驱动-读identify 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://m.elefans.com/xitong/1729650232a1208951.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论