boot.asm
和setup.asm
编译后生成对应的boot.o
和setup.o
文件,boot.o
由dd
命令写入硬盘的0磁道0柱面1扇区
,由BIOS例程
自动读入内存的0x7c00
处;setup.o
通过dd
命令写入硬盘的0磁道0柱面2扇区
,并且写两个扇区,然后由boot
读入内存。
总结:
bios
+mbr
、uefi
+gpt
文件系统、OS如何操作硬盘,如下图:
除了
0x1F0
为两个字节外,其余的都为一个字节,其中0x1F3 ~ 0x1F5
分别为lab28
低八位、中八位以及高八位,再加上0x1F6
的低四位,总共28位。
0x1F3 ~ 0x1F6
四个寄存器拼起来的;boot.asm
;0磁道0柱面1扇区
[ORG 0x7c00]
[SECTION .data]
BOOT_MAIN_ADDR equ 0x500
[SECTION .text]
[BITS 16]
global _start
_start:
;设置屏幕输出文本模式,清除屏幕
mov ax, 3
int 0x10
;跳过去
mov si, jmp_to_setup
call print
jmp $
;如何调用
;mov si, msg ;1.传入字符串
;call print ;2 调用
print:
mov ah, 0x0e
mov bh, 0
mov bl, 0x10
.loop:
mov al, [si]
cmp al, 0
jz .done
int 0x10
inc si
jmp .loop
.done:
ret
jmp_to_setup:
db "jump to setup...", 10, 13, 0
times 510 - ($ - $$) db 0
db 0x55, 0xaa
2)增加汇编代码实现对硬件的同步读
列出0x1F7寄存器图:
下图分析是对的
在基本框架基础上增加寄存器操作实现boot.asm:
;0磁道0柱面1扇区
[ORG 0x7c00]
[SECTION .data]
BOOT_MAIN_ADDR equ 0x500 ;BOOT_MAIN_ADDR值为0x500
[SECTION .text]
[BITS 16]
global _start
_start:
;设置屏幕输出文本模式,清除屏幕
mov ax, 3
int 0x10
mov ecx, 2 ; 从硬盘哪个扇区开始读
mov bl, 2 ;读取扇区的数量
; 0x1f2 8bit 指定读取或写入的扇区数
mov dx, 0x1f2
mov al, bl
out dx, al ;out指令仅能与累加寄存器使用al、ax、eax
; 0x1f3 8bit iba地址的第八位 0-7
inc dx ;增加DX寄存器的值(指向下一个端口0x1f3)
mov al, cl
out dx, al
; 0x1f4 8bit iba地址的中八位 8-15
inc dx
mov al, ch
out dx, al
; 0x1f5 8bit iba地址的高八位 16-23
inc dx
shr ecx, 16
mov al, cl
out dx, al
; 0x1f6 8bit
; 0-3 位iba地址的24-27
; 4 0表示主盘 1表示从盘
; 5、7位固定为1
; 6 0表示CHS模式,1表示LAB模式
inc dx
mov al, ch
and al, 0b1110_1111
out dx, al
; 0x1f7 8bit 命令或状态端口
inc dx
mov al, 0x20 ;读
out dx, al
; 验证状态
; 3 0表示硬盘未准备好与主机交换数据 1表示准备好了
; 7 0表示硬盘不忙 1表示硬盘忙
; 0 0表示前一条指令正常执行 1表示执行出错 出错信息通过0x1f1端口获得
.read_check:
mov dx, 0x1f7
in al,dx
and al, 0b1000_0100 ; 取硬盘状态的第3、7位
cmp al, 0b0000_0100 ;硬盘数据准备好了且不忙了
jnz .read_check
;读数据
mov dx, 0x1f0
mov cx, 256 ;loop次数
mov edi, BOOT_MAIN_ADDR ;将EDI寄存器设置为0x500
.read_data:
in ax, dx
mov [edi], ax ;把ax的值给edi所指向的内存地址
add edi, 2
loop .read_data
;跳过去
mov si, jmp_to_setup
call print
jmp BOOT_MAIN_ADDR
;如何调用
;mov si, msg ;1.传入字符串
;call print ;2 调用
print:
mov ah, 0x0e
mov bh, 0
mov bl, 0x10
.loop:
mov al, [si]
cmp al, 0
jz .done
int 0x10
inc si
jmp .loop
.done:
ret
jmp_to_setup:
db "jump to setup...", 10, 13, 0
times 510 - ($ - $$) db 0
db 0x55, 0xaa
setup.asm实现:
; 0柱面0磁道2扇區
[ORG 0x500]
[SECTION .text]
[BITS 16]
global _start
_start:
;寄存器初始化操作
mov ax, 0
mov ss, ax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov si, ax
mov si, msg
call print
jmp $
; 如何调用
; mov si, msg ; 1 传入字符串
; call print ; 2 调用
print:
mov ah, 0x0e
mov bh, 0
mov bl, 0x01
.loop:
mov al, [si]
cmp al, 0
jz .done
int 0x10
inc si
jmp .loop
.done:
ret
msg:
db "hello", 10, 13, 0
3)运行成功效果图
运行完boot
后打印输出jump to setup...
,打印结束后通过jmp BOOT_MAIN_ADDR
跳到setup
执行。