前段时间参考《自己动手写操作系统》来写操作系统,对操作系统有了更加深刻的认识。现在打算研读linux 0.11的源代码(参考书目:《Linux内核完全注释(修正版v1.9.5)》,《Linux_内核设计的艺术》)。由于linux 0.11源代码的汇编部分,有类似于intel的汇编还有AT&T汇编,本人对nasm比较熟悉,所以打算把汇编部分全部改为nasm汇编来实现。
现在给出linux0.11的bootsect部分的源代码
bootsect.asm 的源代码。 至于代码的具体意思请参考《Linux内核完全注释》
;;nasm -o bootsect.bin bootsect.asm
;fat12 文件头
jmp short start ; Start to boot.
nop ;
BS_OEMName DB 'ForrestY' ; 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 DB 'linux0.11 '; 卷标, 必须 11 个字节
BS_FileSysType DB 'FAT12 ' ; 文件系统类型, 必须 8个字节
;------------------------------------------------------------------------
[section .data]
SYSSIZE equ 0x3000
SETUPLEN equ 4
BOOTSEG equ 0x07c0
INITSEG equ 0x9000
SETUPSEG equ 0x9020
SYSSEG equ 0x1000
ENDSEG equ SYSSEG + SYSSIZE
ROOT_DEV equ 0x306 ;根设备号
[section .text]
start:
mov ax,BOOTSEG ;将bootsect从0x07c00复制到0x90000
mov ds,ax
mov ax,INITSEG
mov es,ax
mov cx,256
sub si,si
sub di,di
rep
movsw
jmp INITSEG:go
go:
mov ax,cs
mov ds,ax
mov es,ax
mov ss,ax
mov sp,0xFF00
load_setup: ;把setup.bin从软盘读到内存的0x90200处
mov dx,0x0000
mov cx,0x0002
mov bx,0x0200
mov ax,0x0200 +SETUPLEN
int 0x13
jnc ok_load_setup
mov dx,0x0000
mov ax,0x0000
int 0x13
jmp load_setup
ok_load_setup:
mov dl,0x00
mov ah,0x08
int 0x13
mov ch,0x00
mov [sectors],cx ;保存扇区数
mov ax,INITSEG
mov es,ax
mov ax,0x03 ;读光标位置
xor bh,bh
int 0x10
mov cx,24 ;显示字符
mov bx,0x0007
mov bp,msg1
mov ax,0x1300
int 0x10
mov ax,SYSSEG ;把system.bin从软盘加载到内存的0x1000处
mov es,ax
call read_it
call kill_motor
mov ax,[root_dev]
cmp ax,0
jne root_defined
mov bx,[sectors]
mov ax,0x0208
cmp bx,15
je root_defined
mov ax,0x021c
cmp bx,18
je root_defined
undef_root:
jmp undef_root
root_defined:
mov [root_dev],ax
jmp SETUPSEG:0
sread: dw 1+SETUPLEN
head: dw 0
track: dw 0
read_it:
mov ax,es
test ax,0x0fff
die:
jne die
xor bx,bx
rp_read:
mov ax,es
cmp ax,ENDSEG
jb ok1_read
ret
ok1_read:
mov ax,[sectors]
sub ax,[sread]
mov cx,ax
shl cx,9
add cx,bx
jnc ok2_read
je ok2_read
xor ax,ax
sub ax,bx
shr ax,9
ok2_read:
call read_track
mov cx,ax
add ax,[sread]
cmp ax,[sectors]
jne ok3_read
mov ax,1
sub ax,[head]
jne ok4_read
inc word [track]
ok4_read:
mov [head],ax
xor ax,ax
ok3_read:
mov [sread],ax
shl cx,9
add bx,cx
jnc rp_read
mov ax,es
add ax,0x1000
mov es,ax
xor bx,bx
jmp rp_read
read_track:
push ax
push bx
push cx
push dx
mov dx,[track]
mov cx,[sread]
inc cx
mov ch,dl
mov dx,[head]
mov dh,dl
mov dl,0
and dx,0x0100
mov ah,2
int 0x13
jc bad_rt
pop dx
pop cx
pop bx
pop ax
ret
bad_rt:
mov ax,0
mov dx,0
int 0x13
pop dx
pop cx
pop bx
pop ax
jmp read_track
kill_motor:
push dx
mov dx,0x3f2
mov al,0
out dx,al
pop dx
ret
sectors: dw 0
msg1:
db 13,0
db "loading system ..."
db 13,10,13,10
times 508-($-$$) db 0
root_dev:
dw ROOT_DEV
boot_flag:
dw 0xaa55
setup.asm 用于测试bootsect的代码(即看bootsect是否将setup加载到内存)。
[section .data]
INITSEG equ 0x9000
SYSSEG equ 0x1000
[section .text]
mov ax,INITSEG
mov ds,ax
mov ax,cs
mov es,ax
mov dx,0x0200;在第3行显示
mov cx,13 ;显示字符串“this is setup”
mov bx,0x0007
mov bp,msg2
mov ax,0x1300
int 0x10
jmp SYSSEG:0
msg2:
db "this is setup"
system.asm 用于测试bootsect的代码(即看bootsect是否将system加载到内存)。
[section .text]
mov ax,cs
mov es,ax
mov dx,0x0300
mov cx,14 ;显示字符串“this is system”
mov bx,0x0007
mov bp,msg3
mov ax,0x1300
int 0x10
jmp $
msg3:
db "this is system"
bootsect的主要作用是把setup(4个扇区的大小)加载到内存0x90200处,把system(240个扇区的大小)加载到内存0x10000处。
bootsect.bin,setup.bin,system.bin都是放在软盘(这里用的是1.44M的)上的。bootsect.bin放在磁头0,柱面0,扇区1,setup.bin放在磁头0,柱面0,扇区2-5,system.bin放在磁头0,柱面0,扇区6到后面的共240个扇区。1.44M软盘的结构:2面、80道/面、18扇区/道、512字节/扇区。
由于要将bootsect.bin,setup.bin,system.bin这些文件写到指定的扇区,所以要用到相应的工具,请到网上下载。http://download.csdn.net/detail/liuqizealot/1019735
执行步骤:
1.先将bootsect.asm,setup.asm,system.asm编译成.bin文件
2.准备一个虚拟软盘
3.将bootsect.bin,setup.bin,system.bin写到软盘的相应扇区。
4.用虚拟机启动虚拟软盘
结果图: