您的位置:首页 > 其它

【第四章复习】突破512字节,实现读扇区函数

2010-02-07 21:21 197 查看
经历了保护模式的复习后,我们再来继续我们的操作系统。我们之前只做了一个极其简陋的引导程序,现在来扩展它。

引导扇区太小,只有512字节,很可能不够用,那么我们把只要的功能交给LOADER来做,引导扇区BOOT的工作就是把LOADER加载进内存,并把控制权交给LOADER。

那么LOADER怎么放呢?在这里不妨把软盘做成FAT12格式,这样对于操作会方便得多。FAT12是一种使用普遍的文件系统,关于文件系统已经在操作系统教科书上有详述,这里不多说了。

要想软盘被DOS或者LINUX识别,则在软盘的引导扇区中写入一些数据才行,如下列代码:

Code:

jmp short LABEL_START ; Start to boot.

nop ; 这个 nop 不可少



; 下面是 FAT12 磁盘的头

BS_OEMName db 'MarcusX ' ; OEM String, 必须 8 个字节

BPB_BytsPerSec dw 512 ; 每扇区字节数

BPB_SecPerClus db 1 ; 每簇多少扇区

BPB_RsvdSecCnt dw 1 ; Boot 记录占用多少扇区

BPB_NumFATs db 2 ; 共有多少 FAT 表

BPB_RootEntCnt dw 224 ; 根目录文件数最大值

BPB_TotSec16 dw 2880 ; 逻辑扇区总数

BPB_Media db 0xF0 ; 媒体描述符

BPB_FATSz16 dw 9 ; 每FAT扇区数

BPB_SecPerTrk dw 18 ; 每磁道扇区数

BPB_NumHeads dw 2 ; 磁头数(面数)

BPB_HiddSec dd 0 ; 隐藏扇区数

BPB_TotSec32 dd 0 ; wTotalSectorCount为0时这个值记录扇区数

BS_DrvNum db 0 ; 中断 13 的驱动器号

BS_Reserved1 db 0 ; 未使用

BS_BootSig db 29h ; 扩展引导标记 (29h)

BS_VolID dd 0 ; 卷序列号

BS_VolLab dd 'MarcusOs0.2' ; 卷标, 必须 11 个字节

BS_FileSysType db 'FAT12 ' ; 文件系统类型, 必须 8个字节



LABEL_START:

操作系统就是根据这些信息来进行管理的。这样,我们把编译好的LOADER.BIN文件放到软盘上,引导的时候需要找到这个文件并加载,那么找文件就必须要读软盘上的目录区和FAT,那么现在就来实现这个功能,我们用到BIOS的13h号中断:

入口参数:ah=02h,al=要读的扇区数,ch=柱面(磁道)号,cl=起始扇区号,dh=磁头号,dl=驱动器号(0表示A盘),es:bx缓冲区地址

对于1.44M的软盘来说,一共有2880个扇区,所以0到2879是扇区的逻辑号,但是调用这个中断要把逻辑扇区号转换成磁头号(0或1),柱面号(0到79)和相对柱面的扇区号(1到18),公式如下:

相对扇区号/每磁道扇区号(18)的商Q,余数R,其中:

柱面号=Q>>1,磁头号=Q&1,相对起始扇区号=R+1

有了公式,那就很容易的翻译成代码了:

Code:

Read_Sector:

;C function proto(REAL MODE,SHORT CALL):

;void Read_Sector(byte16 first_sector_index,byte16 read_sector_number);

;attention:

;before call this function must let es:bx point to the buffer

push bp

mov bp,sp

push ax

push bx

push cx

push dx



push bx ; 暂存缓冲区偏移

mov ax,[bp + 6] ; 取得要读取的扇区数

push ax ; 暂时保存之

mov ax,[bp + 4] ; 取得要读的逻辑扇区号

mov bl,[BPB_SecPerTrk]

div bl ; 除以每柱面扇区数

mov ch,al

shr ch,1 ; ch<-柱面号

mov dh,al

and dh,1 ; dh<-磁头号

mov cl,ah

inc cl ; cl<-相对扇区号

mov dl,0 ; 读A盘

pop ax ; al<-要读的扇区数

pop bx ; 恢复缓冲区偏移



.Go_On_Reading:

mov ah,2 ; ah<-功能号

int 13h

jc .Go_On_Reading ; 如果cf=1,继续读



pop dx

pop cx

pop bx

pop ax



pop bp

ret

为了验证这个函数的正确性,下面来测试一下,准备一个空白的软盘映像,在第1个扇区的第267个字节写入A的ASCII码,也就是逻辑地址30ah,如图所示:



下面是完整代码,把第3个扇区读进1个512字节的缓冲,然后把A显示出来,另外还加了预处理宏,方便在DOS下调试或直接引导:

Code:

%define _BOOT_DEBUG_ ; 做 Boot Sector 时一定将此行注释掉!将此行打开后用 nasm Boot.asm -o Boot.com 做成一个.COM文件易于调试



%ifdef _BOOT_DEBUG_

org 0100h ; 调试状态, 做成 .COM 文件, 可调试

%else

org 07c00h ; Boot 状态, Bios 将把 Boot Sector 加载到 0:7C00 处并开始执行

%endif



jmp short LABEL_START ; Start to boot.

nop ; 这个 nop 不可少



; 下面是 FAT12 磁盘的头

BS_OEMName db 'MarcusX ' ; OEM String, 必须 8 个字节

BPB_BytsPerSec dw 512 ; 每扇区字节数

BPB_SecPerClus db 1 ; 每簇多少扇区

BPB_RsvdSecCnt dw 1 ; Boot 记录占用多少扇区

BPB_NumFATs db 2 ; 共有多少 FAT 表

BPB_RootEntCnt dw 224 ; 根目录文件数最大值

BPB_TotSec16 dw 2880 ; 逻辑扇区总数

BPB_Media db 0xF0 ; 媒体描述符

BPB_FATSz16 dw 9 ; 每FAT扇区数

BPB_SecPerTrk dw 18 ; 每磁道扇区数

BPB_NumHeads dw 2 ; 磁头数(面数)

BPB_HiddSec dd 0 ; 隐藏扇区数

BPB_TotSec32 dd 0 ; wTotalSectorCount为0时这个值记录扇区数

BS_DrvNum db 0 ; 中断 13 的驱动器号

BS_Reserved1 db 0 ; 未使用

BS_BootSig db 29h ; 扩展引导标记 (29h)

BS_VolID dd 0 ; 卷序列号

BS_VolLab dd 'MarcusOs0.2' ; 卷标, 必须 11 个字节

BS_FileSysType db 'FAT12 ' ; 文件系统类型, 必须 8个字节



LABEL_START:

mov ax,cs

mov ds,ax

mov es,ax

mov ss,ax

mov sp,7c00h



mov bx,LABEL_BUFFER

push 1

push 1

call Read_Sector

add sp,4



mov ax,0b800h

mov gs,ax

mov ah,0ch

mov al,[LABEL_BUFFER + 266]

mov [gs:140],ax



mov ax,4c00h

int 21h



LABEL_BUFFER:

times 512 db 0



Read_Sector:

;C function proto(REAL MODE,SHORT CALL):

;void Read_Sector(byte16 first_sector_index,byte16 read_sector_number);

;attention:

;before call this function must let es:bx point to the buffer

push bp

mov bp,sp

push ax

push bx

push cx

push dx



push bx ; 暂存缓冲区偏移

mov ax,[bp + 6] ; 取得要读取的扇区数

push ax ; 暂时保存之

mov ax,[bp + 4] ; 取得要读的逻辑扇区号

mov bl,[BPB_SecPerTrk]

div bl ; 除以每柱面扇区数

mov ch,al

shr ch,1 ; ch<-柱面号

mov dh,al

and dh,1 ; dh<-磁头号

mov cl,ah

inc cl ; cl<-相对扇区号

mov dl,0 ; 读A盘

pop ax ; al<-要读的扇区数

pop bx ; 恢复缓冲区偏移



.Go_On_Reading:

mov ah,2 ; ah<-功能号

int 13h

jc .Go_On_Reading ; 如果cf=1,继续读



pop dx

pop cx

pop bx

pop ax



pop bp

ret

运行结果如图:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐