添加硬盘驱动-读identify


硬盘的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)