admin 管理员组

文章数量: 1184232

Cpu 启动时,如果在 bios 中设置了从软盘启动,则 bios 会自动把软盘的第一个扇区( 512 字节)搬移到 0x7c00 ,然后会从 0x7c00 开始运行,我们需要在这 512 字节的程序中实现把 boot 从软盘中搬移到内存中的功能。

此时 x86 系列的 cpu 还处在实模式中,可以利用 bios 提供的中断完成软盘读写,也就是著名的 int 13

1 软盘操作 1.1 软盘结构

1.44M 软盘为例,软盘有上、下两个盘面,每个盘面被划分为 80 track ,每个 track 被划分为 18 Sector ,每个 Sector 大小为 512 BYTES

2 × 80 × 18 × 512 1440 × 1024 1.44MB

如果是单纯的进行软盘读写操作,知道软盘的这些知识就够了。

1.2 软盘读写

中断号

寄存器

作用

13h

ah=00h      al= 驱动器号( 0 表示 A 盘)

复位软驱

ah=02h      al= 要读扇区数

ch= 磁道号 cl= 起始扇区号

dh= 磁头号 dl= 驱动器号

es:bx= 数据缓冲区

cl/ch/dh/dl 指向的扇区开始读取 al 个扇区的数据到 es:bx 指向的缓冲区

ah=03h      al= 要写扇区数

ch= 磁道号 cl= 起始扇区号

dh= 磁头号 dl= 驱动器号

es:bx= 数据缓冲区

es:bx 指向的缓冲区读取 al 个扇区的数据写入 cl/ch/dh/dl 指向的 al 个扇区

对于软盘来说, DL=0 0 表示 A 盘)

CL 的取值范围是: 1—18

CH 的取值范围是: 0—79

DH 的取值范围是: 0—1

如果软盘的 CL CH DH 取值超过了范围,中断调用出错。

使用 int13 时对应扇区数的计算方法如下:

1.3 软盘编程

用软盘存放操作系统时, bios 只会把前 512 个字节(即第一个扇区,引导区)读入内存的 0x7c00 处执行。程序的长度也被限制在了 512 字节大小,一个出入保护模式的程序就会超出。

为了突破 512 字节的限制,需要在这个扇区内放置一段引导程序,用于把后面的程序加载到内存中。这也是第一个扇区被称为引导区的原因。

下面的就是一段简单的加载程序, reset 软驱后从 LABEL_SECTOR2 开始读入 17 个扇区。加上 0 号扇区(引导区),一共是 18 个扇区,也就是第一个磁道。这是因为 13 号中断不能跨磁道读取,所以这里只读入第一个磁道剩下的 17 个扇区。

; reset floppy

xor ah, ah

xor dl,  dl

int 13h

; read sector 2 to memory

mov ah, 03h

mov al, 11h

mov ch, 00h

mov cl, 03h

mov dh, 00h

mov dl, 00h

mov bx, 0100h

int 13h

下面的程序用于保证除引导程序外的所有程序都在引导区之外,完成把磁盘内容拷贝入 memory 的操作后,就会跳入 LABEL_SECTOR2

jmp LABEL_SECTOR2

; fill boot sector

times 510 - ($ - $$) db 1

dw 0xaa55

; Sector 2

LABEL_SECTOR2:

下面是完整的程序代码

org 07c00h

jmp LABEL_BEGIN

LABEL_BEGIN:

mov ax, cs

mov ds, ax

mov ss, ax

mov es, ax

; reset floppy

xor ah, ah

xor dl,  dl

int 13h

; read sector 2

mov ah, 02h

mov al, 01h

mov ch, 00h

mov cl, 02h

mov dh, 00h

mov dl, 00h

mov bx, LABEL_SECTOR2

int 13h

jmp LABEL_SECTOR2

; fill boot sector

uutimes 510 - ($ - $$) db 0

dw 0xaa55

; Sector 2 jmp into loader

;      org 0100h

LABEL_SECTOR2 :

mov ax, cs

mov ds, ax

mov es, ax

call  DispStr                 ; 调用显示字符串例程

jmp  $                   ; 无限循环

DispStr:

mov ax, BootMessage

mov bp, ax                   ; ES:BP = 串地址

mov cx, 16                   ; CX = 串长度

mov ax, 01301h            ; AH = 13,  AL = 01h

mov bx, 000ch              ; 页号为 0(BH = 0) 黑底红字 (BL = 0Ch, 高亮 )

mov dl, 0

int   10h                ; 10h 号中断

ret

BootMessage:         db    "Hello, OS world!"

; fill floppy

times (2 * 18 * 80 * 512 - ($ - $$)) db 0

软盘 ,INT 13H IMG 文件

1: 软盘

软盘是以扇区为基本单位来进行操作的,每扇区 512 字节,共 2880 个扇区,空间大小为 1.44M.

2880 个扇区又可以用(磁头、磁道、扇区)这三个参数来描述。我们简单记(磁头、磁道、扇区)为( x,y,z ),那么

X 的取值范围是: 0—1

Y 的取值范围是: 0--79

Z 的取值范围是: 1—18

也就是说软盘有 2 磁头、每磁头有 80 磁道、每磁道有 18 扇区 , 2880 个扇区( 2880=2*80*18 )。

如果把 2880 个扇区从 0 开始编号,一直到 2879 结束,那么

编号为 i 的扇区和( X,Y,Z )的换算公式为: i=80*18*x+18*y+z-1

2:INT 13H

INT13H 是磁盘的 BOIS 中断 , 对于读写扇区操作,中断的完整调用参数如下 :

AL= 扇区数

AH= 中断子功能号 ;2= 读扇区, 3= 写扇区

CL 6 7 ,CH = 磁道号 ; 每磁头最多可以有 2^10=1024 个磁道

CL 的低 6 = 扇区号 ; 每磁道最多可以有 2^6=64 个扇区

DH = 磁头号 ; 最多可以有 256 个磁头

DL = 驱动器号 ;0= 软盘, 80H= 硬盘

ES:BX= 数据缓冲区的地址

其他:

1).

对于软盘来说,实际的 INT 13H DL=0 ,而 CL CH DH 的取值范围也不可能取到上面的数值,根据 1: 中的数据,有

CL 的取值范围是: 1--18

CH 的取值范围是: 0-79

DH 的取值范围是: 0—1

如果软盘的 CL CH DH 取值超过了范围,中断调用出错。

AL 的取值也不是任意的,一次调用 INT13H 进行读写扇区的只可以在一个磁道内的扇区进行。如果超出了一个磁道,必须要更新 INT13H 的中寄存器,重复调用 INT13H

对于软盘来说 AL 必须要小于 19-CL

下面是一个从软盘的 (x,y,z) 扇区中连续读出 n 个扇区的内容到缓冲区 BUFFER 中的代码片段 ( 代码使用了一些 80386 的指令和 MASM6.0 才支持的伪指令 )

MOV  AX,DS

MOV  ES,AX

MOV  BX,OFFSET

MOV   BP,  n

MOV CL z

MOV CH y

MOV DL 0

MOV DH x

.WHILE  BP  ;bp 记录的是还没有进行读操作的扇区数量

;WHILE 伪指令,和高级语言的 WHILE 一样理解就可以了,下面的。 IF 也一样

; AL 的取值进行计算

MOV AL,19

SUB AL,CL ; 最多可以读 19-CL 个扇区

XOR AH,AH

.IF AX>BP

MOV AX,BP

XOR BP,BP

.ELSE

SUB BP,AX ;更新 BP

.ENDIF

MOV AH,2

INT 13H   ; 读扇区

; 更新 CL CH DH

MOV CL,1

.IF  CH==79

INC DH

XOR CH,CH

.ELSE

INC CH

.ENDIF

XOR AH,AH

SHL AL,9 ;AX=AL*512 ,等于已经处理的字节数

;SHL AL,9 SHL AX 4 都是 80386+ 才支持的指令

SHR AX,4   ;AX=AX/16

ADD ES,AX  ; 更新 ES BX ,这里是更新了 ES ,也可以更新 BX

.endw

2).

INT13H 只理论上最多处理 2^24 个扇区 *512 字节 / 扇区 =8G 的磁盘空间,这对现在的硬盘来说,是远远不够的,于是后来对 INT13H 进行了扩展,用 AH=42H AH=43H 分别对大硬盘进行操作,这里就不详细讨论了。

3:IMG 文件

IMG 文件是软盘的镜像文件,文件大小也是 1.44M ,它和软盘是一种线性的对应关系。

软盘上一个编号为 (x,y,z) 512 字节的扇区,对应 IMG 文件中的以 2400H*x+4800H*y+(z-1)*512 为基址的 512 个字节(注意 ,2400H,4800H 16 进制数)。

IMG 文件的字节和软盘的扇区对应关系也可以如下图所示 ( 注意那些是十进制,那些是 16 进制 )

对于扩展 INT 13 中断,参数如下:

中断号 功能 调用寄存器 返回寄存器 备注

INT 13

AH=41H 检测扩展中断功能是否安装 AH = 41h

BX=55AAh

DL = 驱动器号 (80h FFH)

失败: AH=1

CF 置位

成功: AH= 版本号

CF=0 BX=AA55H

INT 13

AH=42H 磁盘扩展读操作 AH = 42H

DL = 驱动器号

DS:SI= 指向 LBA 地址包的指针 失败: AH= 错误号

CF 置位

成功: AH=0

CF=0

地址包定义:

偏移 大小 描述

00H 字节 地址包大小

01H 字节 保留(为 0

02H 传输包个数

04H 双字 指向数据指针

08H 4 起始地址

其中 LBA=(( 柱面 * 磁头 / 柱面 + 磁头 )* 扇区 / 柱面 )+ 扇区 -1

INT 13

AH=43H 磁盘扩展写操作 AH=43H

AL= 写标志

DL = 驱动器号

DS:SI= 指向 LBA 地址包的指针 失败: AH= 错误号

CF 置位

成功: AH=0

CF =0 同上

INT 13

AH=48H 获取磁盘参数 AH=48H

DL= 驱动器号

DS:SI= 指向保存参数缓冲区的指针

失败: AH= 错误号

CF 置位

成功: AH=0

CF=0

参数缓冲区定义:

偏移 大小 描述

00H 缓冲区大小

02H 信息标志位

04H 双字 物理柱面数

08H 双字 物理磁头数

0CH 双字 物理每柱扇区数

10H 4 扇区总数

18H 每扇区字节数


1.1 保护模式下实现软盘编程

要发挥 x86芯片的功能,必须要进入保护模式。

系统启动时所加载的 512字节的MBR区为bootloader区,用于加载真正的boot程序。在bootloader区中,cpu还运行于实模式,因此bootloader通过bios中断加载boot。进入boot区后,一般来说已经完成了切换入保护模式的动作。

在保护模式下,不能使用 bios中断,需要通过读写软盘控制器芯片8237来完成。

1.1.1 软盘控制器

I/O address

Read or Write

Register

0x3f2

Write

DOR: Digital Output Register

0x3f4

Read

FDC Status: Floppy Disk Status Register

0x3f5

Read/Write

FDC Data: Floppy Disk Data Register

0x3f7

Read

DIR: Digital Input Register

Write

DCR: Disk Control Register

注: FDC为软盘控制器

1.1.1.1 DOR数字输出寄存器

DOR是一个8为寄存器,他控制驱动器马达的开启、驱动器选择、启动/复位FDC以及允许/禁止DMA请求

Name

Description

7

MOT_EN3

Driver D motor:1-start;0-stop

6

MOT_EN2

Driver C motor:1-start;0-stop

5

MOT_EN1

Driver B motor:1-start;0-stop

4

MOT_EN0

Driver A motor:1-start;0-stop

3

DMA_INT

DMA interrupt; 1 enable; 0-disable

2

RESET

FDC Reset

1

DRV_SEL1

Select driver

0

DRV_SEL0

1.1.1.2 FDC Status:FDC状态寄存器

FDC status用于反映软盘驱动器FDC的基本状态。通常,在CPU想FDC发送命令或从FDC获取结果前,都要读取FDC的状态为,以判断当前的FDC data寄存器是否就需,以及确定数据传输方向。

Name

Description

7

RQM

Data ready: FDD ready

6

DIO

Direction: 1 - FDD to CPU; 0 – CPU to FDD

5

NDM

DMA set: 1-not DMA; 0-DMA

4

CB

Controller busy

3

DDB

Driver D busy

2

DCB

Driver C busy

1

DBB

Driver B busy

0

DAB

Driver A busy

1.1.1.3 FDC Data:FDC数据寄存器

FDC Data寄存器用于向FDC发送控制命令或从FDC读取状态,实现数据读写等。FDC的使用比较复杂,可支持多种命令。每个命令都通过一个命令序列实现:命令阶段、执行阶段和结果阶段。

1) 重新校正命令( FD_RECALIBRATE)

软盘启动时调用

阶段

D7

D6

D5

D4

D3

D2

D1

D0

说明

cmd

0

0

0

0

0

0

1

1

1

0x07

1

0

0

0

0

0

0

US1

US2

Drive no.

执行

磁头移动到 track0

结果

2) 磁头寻道命令( FD_SEEK)

把磁头定位到制定位置,在读写前执行

阶段

D7

D6

D5

D4

D3

D2

D1

D0

说明

cmd

0

0

0

0

0

0

1

1

1

0x0F

1

0

0

0

0

0

HD

US1

US2

磁头号、驱动器号

2

C

磁道号

执行

磁头移动到制定磁道

结果

3) 读扇区数据命令( FD_READ)

阶段

D7

D6

D5

D4

D3

D2

D1

D0

说明

cmd

0

MT

MF

SK

0

0

1

1

0

0xE6(MT=MF=SK=1)

1

0

0

0

0

0

0

US1

US2

驱动器号

2

C

磁道号 track

3

H

磁头号 head

4

R

起始扇区号 start sector

5

N

扇区字节数

6

EOT

磁道最大扇区号

7

GPL

扇区建间隔长度( 3)

8

DTL

N=0时,制定扇区字节书

执行

从软盘读取扇区

结果

1

ST0

状态字节 0

2

ST1

状态字节 1

3

ST2

状态字节 2

4

C

磁道号 track

5

H

磁头号 head

6

R

起始扇区号

7

N

扇区字节数

注:

MT:多磁道操作。MT=1表示允许多磁道操作

MF:记录方式。MF=1表示选用MFM记录方式,否则是FM记录方式d

SK:是否跳过有删除标志的扇区。SK=1表示跳过。

返回的返回的状态 ST0、ST1和ST2的含义如下:

ST0:

名称

说明

7

ST0_INTR

中断原因。 00-正常结束;01-异常结束;10-命令无效;11-软盘驱动器状态改变

6

5

ST0_SE

寻道操作或重新校正操作结束( seek end)

4

ST0_ECE

设备检查错误( 0磁道校正错误)(Equip. Check Error)

3

ST0_NR

软盘未就绪( Not Ready)

2

ST0_HA

磁头地址。中断时磁头地址( Head Address)

1

ST0_DS

驱动器号( Driver Select)

0

ST1:

名称

说明

7

ST1_EOC

范文超过磁道最大扇区号( End of Cylinder)

6

Reserve

5

ST1_CRC

CRC校验出错

4

ST1_OR

数据传输超时( Over Run)

3

Reserve

2

ST1_ND

未找到制定扇区( No Data)

1

ST1_WP

写保护( Write Protect)

0

ST1_MAM

未找到扇区地址标志 ID(Miss Address Mask)

ST2:

名称

说明

7

Reserve

6

ST2_CM

SK=0时,读数据遇到删除标志(Control Mark)

5

ST2_CRC

CRC校验出错

4

ST2_WC

扇区 ID信息的磁道号C不不符(Wrong Cylinder)

3

ST2_SEH

检索条件满足( Scan Equal Hit)

2

ST2_SNS

检索条件不满足( Scan Not Satisfied)

1

ST2_BC

磁道坏( Bad Cylinder)

0

ST2_MAM

未找到扇区地址标志 ID(Miss Address Mask)

4) 写扇区数据命令( FD_WRITE)

阶段

D7

D6

D5

D4

D3

D2

D1

D0

说明

cmd

0

MT

MF

0

0

0

1

0

1

0xC5(MT=MF=1)

1

0

0

0

0

0

0

US1

US2

磁头号、驱动器号

2

C

磁道号 track

3

H

磁头号 head

4

R

起始扇区号 start sector

5

N

扇区字节数

6

EOT

磁道最大扇区号

7

GPL

扇区建间隔长度( 3)

8

DTL

N=0时,制定扇区字节书

执行

向软盘写入扇区

结果

1

ST0

状态字节 0

2

ST1

状态字节 1

3

ST2

状态字节 2

5) 检测中断状态命令( FD_SENSEI)

阶段

D7

D6

D5

D4

D3

D2

D1

D0

说明

cmd

0

0

0

0

0

0

1

1

1

0x08

执行

结果

1

ST0

状态字节 0

2

磁头所在磁道号

6) 设定驱动器参数命令( FD_SPECIFY)

阶段

D7

D6

D5

D4

D3

D2

D1

D0

说明

cmd

0

0

0

0

0

0

1

1

1

0x03

1

SRT(单位2ms)

HUT(单位32ms)

马达速度、磁头卸载时间

2

HLT(单位4ms)

ND

磁头加载时间,非 DMA模式

执行

设置控制器

结果

1.1.1.4 DIR:数字输入寄存器

DIR寄存器只有D7位有效,用于表示软盘更换状态,其余用于硬盘控制器。

1.1.1.5 DCR:磁盘控制寄存器

DCR仅是用户D0与D1位,用于表示数据传输率。

00-500kpbs, 01-300kpbs, 10-250kpbs。

1.1.2 保护模式下代码实现 1.1.2.1 初始化

1) Reset

1) 设置磁盘数据传输速度

outb(FD_DCR, 0); // 500kpbs

2) Output_byte函数

用于 FDC命令的输出,FDC的每条命令需要确保上条命令已经完成

3) 设置驱动器参数

1.1.2.2 读扇区

程序很清楚,不再多说,写命令于此类似。

唯一不清楚的是 SetDMA函数。

我们在设置 DOR时设置的DMA工作方式为enable,也就是说数据会通过DMA方式传送,因此必须设置DMA控制器。

1.1.2.3 DMA传输

该函数由 linux0.11移植而来,可参照DMA控制器手册进行设置。不看也可以,注释写得很清楚,拿过来用就是了





本文标签: 系统 编程 驱动器号