经过一段时间的学习,把前四章都消化得差不多了,对进度和学习效果还是挺满意的。代码自己全部敲了几遍,没思路了再看看光盘上的代码,就这样下来掌握了最关键的思路。多亏了上学期学了汇编,感觉掌握得不错,呵呵,汇编非常有用,就是可读性太差。感觉底层很注重细节,稍微了哪里不对了全部死掉,用DEBUG查半天才查得到,呵呵。继续努力,至少在放寒假前看完上篇吧。争取把这个细菌操作系统当作毕业设计,哈哈。看完第四章只是迈了第一步,也是毕设的第一步吧。
贴不了汇编代码,直接复制过来,这是晚上临时写的DOS测试,以后还要对细节修正。
;不在DOS中调试时,必须注释掉下面这行----------------------------------
%define _DEBUG_BOOT_
;---------------------------------------------------------------------
%ifdef _DEBUG_BOOT_
org 0100h
%else
org 7c00h
%endif
;---------------------------------------------------------------------
;---------------------------------------------------------------------
%ifdef _DEBUG_BOOT_
Base_Of_Stack equ 100h ;在DOS下调式时的栈基址
%else
Base_Of_Stack equ 7c00h ;在裸机上执行时的栈基址
%endif
;---------------------------------------------------------------------
jmp short LABEL_BEGIN
nop
%include "include/FAT12hdc.inc"
Base_Of_Loader equ 9000h ;LOADER缓冲区的段地址(实模式)
Offset_Of_Loader equ 0100h ;LOADER缓冲区的偏移地址(实模式)
LOADER_NAME equ 11 ;LOADER文件名的长度
;一堆变量
_w_Current_Root_Sector: dw Root_Dir_Sector_Index ;控制根目录当前读取的扇区号
_w_Root_Sector_For_Loop: dw Root_Dir_Sector_Number ;控制读取根目录的扇区数
_b_Odd: db 0 ;控制加载的文件在FAT中的相对偏移字节的奇偶
_sz_Loader_Name: db "LOADER BIN" ;LOADER文件名,用于比较
_w_Load_Offset: dw 0 ;控制131行的LOADER缓冲区的偏移
;显示的字符串
String_Len equ 9
_sz_Booting: db 'Booting '
Booting_Message_Index equ 0
_sz_Ready: db 'Ready '
Ready_Message_Index equ 1
_sz_No_Loader: db 'No Loader'
No_Loader_Message_Index equ 2
LABEL_BEGIN:
mov ax,cs
mov ds,ax
mov es,ax
mov ss,ax
mov sp,Base_Of_Stack
;显示BOOTING字符串
mov dh,Booting_Message_Index
call Disp_Str_In_Real_Mode
;编程思路:找到根目录下的LOADER.BIN
;根目录的范围是总扇区编号19到32,共占14个扇区
;分别读取每个根目录扇区,共14次
;每个扇区读16次
;每个扇区可以容纳512/32=16个文件信息
LABEL_SEARCH_LOADER_BEGIN:
cmp word [_w_Root_Sector_For_Loop],0 ;比较要读取的根目录扇区数
je LABEL_LOADER_NOT_FOUND ;如果为0表示没有找到
dec word [_w_Root_Sector_For_Loop]
mov ax,1 ;读取当前扇区至es:bx处
push ax
mov ax,[_w_Current_Root_Sector]
push ax
mov ax,Offset_Of_Loader
push ax
mov ax,Base_Of_Loader
push ax
call Read_Sector
add sp,8
mov dx,File_Number_Per_Sector ;初始化dx控制一个扇区循环次数为16次
mov si,_sz_Loader_Name ;ds:si指向LOADER的名字字符串
mov ax,Base_Of_Loader ;es:di指向缓冲区
mov es,ax
mov di,Offset_Of_Loader
LABEL_NEXT_FILE:
cmp dx,0
je LABEL_READ_NEXT_SECTOR ;如果为0表示当前扇区比较结束,读下一个扇区
dec dx
LABEL_CMP_BEGIN:
mov cx,11 ;初始化cx控制比较次数为最多为11次
LABEL_CMP_GO_ON:
cmp cx,0 ;如果cx为0,表示找到LOADER
je LABEL_LOADER_FOUND
dec cx
lodsb ;读取一个LOADER名字字符串到al
cmp al,byte [es:di] ;比较之
jne LABEL_DIFF ;有不同的直接进行下一个文件的比较
jmp LABEL_NEXT_CMP ;相同则进行下一个字符的比较
LABEL_DIFF:
mov si,_sz_Loader_Name ;恢复si,使ds:si重新指向字符串
and di,0ffe0h
add di,File_Item_Byte_Number ;恢复di,使es:di指向下个根目录
jmp LABEL_NEXT_FILE
LABEL_NEXT_CMP:
inc di
jmp LABEL_CMP_GO_ON
LABEL_READ_NEXT_SECTOR: ;做读下一个扇区的准备工作
inc word [_w_Current_Root_Sector]
jmp LABEL_SEARCH_LOADER_BEGIN
LABEL_LOADER_NOT_FOUND:
;显示一些信息
mov dh,No_Loader_Message_Index
call Disp_Str_In_Real_Mode
jmp LABEL_EXIT
LABEL_LOADER_FOUND:
; 显示一些信息
mov dh,Ready_Message_Index
call Disp_Str_In_Real_Mode
and di,0ffe0h ;此时找到LOADER,恢复di指向名字字段的首字节
add di,FAT_Offset_In_File_Item ;此时di指向此文件在FAT的序号,记录序号的段占两字节
mov ax,[es:di] ;取出准备调用Get_FAT_Entry
push ax ;临时保存之,等待日后调用函数时使用
add ax,Root_Dir_Sector_Index
add ax,Root_Dir_Sector_Number
sub ax,2 ;此时ax为LOADER的相应扇区在DATA区的总偏移
LABEL_READ_AGAIN:
mov bx,1 ;把LOADER的相应一个扇区读到指定的位置
push bx
push ax
mov ax,Offset_Of_Loader
add ax,[_w_Load_Offset]
push ax
mov ax,Base_Of_Loader
push ax
call Read_Sector
add sp,8
pop ax
push ax
call Get_FAT_Entry
add sp,2
cmp ax,0fffh ;不等于0FFFH的话说明已是最后一个扇区了
je LABEL_LOADED_COMPLETE
push ax
add ax,Root_Dir_Sector_Index
add ax,Root_Dir_Sector_Number
sub ax,2
add word [_w_Load_Offset],Byte_Number_Per_Sector
jmp LABEL_READ_AGAIN
LABEL_LOADED_COMPLETE:
jmp Base_Of_Loader:Offset_Of_Loader ;把控制权交给LOADER
LABEL_EXIT:
%ifdef _BOOT_DEBUG_
mov ax,4c00h
int 21h
%else
jmp $
%endif
;Read_Sector----------------------------------------------------------
;压栈顺序 1:欲读取的扇区个数
; 2:欲读取的扇区总号
; 3:读取的扇区的缓冲区的偏移地址
; 4:读取的扇区的缓冲区的段地址
;---------------------------------------------------------------------
;入口参数
; ah=02h
; al:扇区数
; ch:柱面
; cl:扇区
; dh:磁头
; dl:驱动器,00H~7FH:软盘;80H~0FFH:硬盘
; es:bx=缓冲区的地址
;出口参数
; cf=0——操作成功,ah=00H,al=传输的扇区数,否则,ah=状态代码,参见功能号01H中的说明
;----------------------------------------------------------------------
;求解磁头号,柱面号,相对扇区数的算法如下
; 设扇区号为 x
; ┌ 柱面号 = y >> 1
; x ┌ 商 y ┤
; -------------- => ┤ └ 磁头号 = y & 1
; 每磁道扇区数 │
; └ 余 z => 起始扇区号 = z + 1
Read_Sector:
push bp
mov bp,sp
push ax
push bx
push cx
push dx
push es
mov ax,[bp + 8] ;扇区总数送ax
mov bl,18 ;除数是18,一个柱面有18个扇区
div bl ;商送al,余数送ah
mov ch,al
shr ch,1 ;求得柱面
mov dh,al
and dh,1 ;求得磁头
mov cl,ah
inc cl ;求得相对扇区偏移
mov dl,0 ;读取A盘
mov ax,[bp + 4]
mov es,ax ;设置缓冲区段地址
mov bx,[bp + 6] ;设置缓冲区偏移地址
LABEL_RETRY:
mov ax,[bp + 10] ;设置读取扇区的个数
mov ah,2 ;设置功能号
int 13h ;中断调用
jc LABEL_RETRY ;如果读取不成功,再继续读取
pop es
pop dx
pop cx
pop bx
pop ax
pop bp
ret
;end of Read_Sector---------------------------------------------------
;Get_FAT_Entry--------------------------------------------------------
;压栈顺序 1:一个文件在FAT中的序号
;返回值:在此FAT中序号的值,保留在ax中
Get_FAT_Entry:
push bp
mov bp,sp
push bx
push dx
push di
push es
mov ax,[bp + 4] ;求出在FAT中偏移的字节数,乘以1.5倍
mov bx,3
mul bx
mov bx,2
div bx
mov byte [_b_Odd],0
cmp dx,0
je LABEL_EVEN ;余数等于0的话,就为偶字节
mov byte [_b_Odd],1 ;余数等于1的话,就为奇字节
LABEL_EVEN:
xor dx,dx
mov bx,Byte_Number_Per_Sector ;字节数除以512,得到在FAT中的偏移扇区
div bx
inc ax ;得到总的扇区偏移,用来调用Read_Sector
;dx中保存相对扇区偏移的字节数
mov bx,2 ;读两个扇区,以免出现跨扇区的情况
push bx
push ax
mov ax,Offset_Of_Loader
push ax
mov ax,Base_Of_Loader - 100h ;换个地儿存放缓冲区
push ax
call Read_Sector
add sp,8
mov ax,Base_Of_Loader - 100h ;es:di指向要读取的FAT的首字节
mov es,ax
mov di,Offset_Of_Loader
add di,dx
mov ax,[es:di]
cmp byte [_b_Odd],0
je LABEL_EVEN2
shr ax,4 ;奇数的策略
LABEL_EVEN2:
and ax,0fffh ;偶数的策略
pop es
pop di
pop dx
pop bx
pop bp
ret
;end of Get_FAT_Entry-------------------------------------------------
;Disp_Str_In_Real_Mode------------------------------------------------
Disp_Str_In_Real_Mode:
push es
push bx
push cx
push dx
push bp
mov ax,String_Len
mul dh
add ax,_sz_Booting
mov bp,ax
mov ax,ds
mov es,ax
mov cx,String_Len
mov ax, 01301h ; AH = 13, AL = 01h
mov bx, 0007h ; 页号为0(BH = 0) 黑底白字(BL = 07h)
mov dl, 0
int 10h ; int 10h
pop bp
pop dx
pop cx
pop bx
pop es
ret
;end of Disp_Str_In_Real_Mode-----------------------------------------
times 510 - ($ - $$) db 0
dw 0xaa55
本文分享了一个在DOS环境下自制的引导程序代码,通过读取磁盘根目录下的特定文件来实现系统的引导过程。文章详细展示了如何在实模式下进行磁盘操作,包括查找指定文件、读取扇区等步骤。
1980

被折叠的 条评论
为什么被折叠?



