我们的操作系统启动流程:
boot.asm -> loader.asm -> kernel.asm -> shell.asm
直接上代码
Boot.asm
; Plain Kernel
; boot.asm
org 0x07C00
StackBase equ 0x07C00 ; 栈基址
LoaderBase equ 0x09000 ; Loader基址
OffsetLoader equ 0x0100 ; Loader偏移
RootDirSectors equ 14 ; 根目录大小
SectorNoRootDirectory equ 19 ; 根目录起始扇区
SectorNoFAT1 equ 1 ; 第一个FAT表开始扇区
DeltaSectorNo equ 17
jmp short start
nop
; 下面的...咱也不知道,咱也不敢问,厂家说啥就是啥
BS_OEMName db 'Plain ' ; 8个字节
BPB_BytsPerSec dw 512 ; 每扇区512个字节
BPB_SecPerClus db 1 ; 每簇固定1个扇区
BPB_RsvdSecCnt dw 1 ; MBR固定占用1个扇区
BPB_NumFATs db 2 ; FAT12文件系统固定2个FAT表
BPB_RootEntCnt dw 224 ; FAT12文件系统中根目录最大224个文件
BPB_TotSec16 dw 2880 ; 1.44MB磁盘固定2880个扇区
BPB_Media db 0xF0 ; 介质描述符,固定为0xF0
BPB_FATSz16 dw 9 ; 一个FAT表所占的扇区数FAT12文件系统固定为9个扇区
BPB_SecPerTrk dw 18 ; 每磁道扇区数,固定为18
BPB_NumHeads dw 2 ; 磁头数
BPB_HiddSec dd 0 ; 隐藏扇区数,没有
BPB_TotSec32 dd 0 ; 直接置0即可
BS_DrvNum db 0 ; int 13h 调用时所读取的驱动器号,由于只有一个软盘所以是0
BS_Reserved1 db 0 ; 未使用,预留
BS_BootSig db 0x29 ; 扩展引导标记,固定为0x29
BS_VolID dd 0 ; 卷序列号,由于只挂载一个软盘所以为0
BS_VolLab db 'Plain - OS ' ; 卷标,11个字节
BS_FileSysType db 'FAT12 ' ; 由于是 FAT12 文件系统,所以写入 FAT12 后补齐8个字节
start:
mov ax, 0x0600
mov bx, 0x0700
mov cx, 0
mov dx, 0x184F
int 0x10
mov ah, 0x02
xor bh, bh
mov dh, 0
mov dl, 0
int 0x10
xor ax, ax ; 相当于 mov ax, 0
mov ds, ax
mov es, ax
mov ss, ax
mov sp, StackBase
mov dh, 0
mov si, msg
call print_string
read_main:
mov word [wSectorNo], SectorNoRootDirectory
cmp word [wRootDirLoopSize], 0
jz no_loader
dec word [wRootDirLoopSize] ; 减一个扇区
mov ax, StackBase
mov es, ax
mov bx, OffsetLoader
mov ax, [wSectorNo] ; now
mov cl, 1
call read_sector
mov si, LoaderFileName
mov di, OffsetLoader
cld
mov dx, 0x10
loader_search:
cmp dx, 0
jz next_sector
dec dx
mov cx, 11
cmp_name:
cmp cx, 0
jz loader_found
dec cx
lodsb
cmp al, byte [es:di]
jz next_str
jmp different
next_str:
inc di
jmp cmp_name
different:
and di, 0xFFE0
add di, 0x20
mov si, LoaderFileName
jmp loader_search
next_sector:
add word [wSectorNo], 1
jmp read_main
no_loader:
mov si, Message2
call print_string
jmp $
loader_found:
mov ax, RootDirSectors
and di, 0xFFE0
add di, 0x1A
mov cx, word [es:di]
push cx
add cx,ax
add cx, DeltaSectorNo
mov ax, LoaderBase
mov es, ax
mov bx, OffsetLoader
mov ax, cx
load_file:
mov cl, 1
call read_sector
pop ax
call FAT_entry
cmp ax, 0x0FFF
jz loader_file
push ax
mov dx, RootDirSectors
add ax, dx
add ax, DeltaSectorNo
add bx, [BPB_BytsPerSec]
jmp load_file
loader_file:
mov dh, 1
mov si, Message1
call print_string
jmp LoaderBase:OffsetLoader ; Loader!
print_string:
lodsb
or al, al ; 检查是否为0
jz .done
mov ah, 0x0E
mov bx, 0x0007
int 0x10
jmp print_string
.done:
ret
read_sector:
push bp
mov bp, sp
sub esp, 2
mov byte [bp-2], cl
push bx
mov bl, [BPB_SecPerTrk]
div bl
inc ah
mov cl, ah
mov dh, al
shr al, 1
mov ch, al
and dh, 1 ; 磁头
pop bx
mov dl, [BS_DrvNum]
.read_start:
mov ah, 2
mov al, byte [bp-2]
int 0x13
jc .read_start
add esp, 2
pop bp
ret
FAT_entry:
push es
push bx
push ax
mov ax, LoaderBase
sub ax, 0x0100
mov es, ax ; 缓冲区的基址
pop ax
mov byte [bOdd], 0
mov bx, 3
mul bx
mov bx, 2
div bx
cmp dx, 0
jz FAT_next
mov byte [bOdd], 1
FAT_next:
xor dx, dx
mov bx, [BPB_BytsPerSec]
div bx
push dx
xor bx, bx
add ax, SectorNoFAT1
mov cl, 2
call read_sector
pop dx
add bx, dx
mov ax, [es:bx]
cmp byte [bOdd], 1
jnz FAT_next2
shr ax, 4
FAT_next2:
and ax, 0x0FFF
all_OK:
pop bx
pop es
ret
msg db "Loading Loader...", 0
wRootDirLoopSize dw RootDirSectors
wSectorNo dw 0 ; 当前扇区数
bOdd db 0
LoaderFileName db "LOADER BIN", 0 ; loader的文件名
Message1 db "OK!", 0x0A, 0x0D, 0
Message2 db "Loader Not Find", 0
times 510-($-$$) db 0
db 0x55, 0xAA
Loader.asm
org 0100h
BaseOfStack equ 0100h
jmp LABEL_START
%include "load.inc"
LABEL_GDT: Descriptor 0, 0, 0
LABEL_DESC_FLAT_C: Descriptor 0, 0fffffh, DA_C|DA_32|DA_LIMIT_4K
LABEL_DESC_FLAT_RW: Descriptor 0, 0fffffh, DA_DRW|DA_32|DA_LIMIT_4K
LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW|DA_DPL3
GdtLen equ $ - LABEL_GDT
GdtPtr dw GdtLen - 1
dd BaseOfLoaderPhyAddr + LABEL_GDT
SelectorFlatC equ LABEL_DESC_FLAT_C - LABEL_GDT
SelectorFlatRW equ LABEL_DESC_FLAT_RW - LABEL_GDT
SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT + SA_RPL3
LABEL_START:
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
mov sp, BaseOfStack
mov si, msg
call print_string
mov word [wSectorNo], SectorNoOfRootDirectory
xor ah, ah
xor dl, dl
int 13h
SearchRootDir:
cmp word [wRootDirSizeForLoop], 0
jz NoKernelFound
dec word [wRootDirSizeForLoop]
mov ax, BaseOfKernelFile
mov es, ax
mov bx, OffsetOfKernelFile
mov ax, [wSectorNo]
mov cl, 1
call ReadSector
mov si, KernelFileName
mov di, OffsetOfKernelFile
cld
mov dx, 10h
SearchFile:
cmp dx, 0
jz NextSector
dec dx
mov cx, 11
CmpFilename:
cmp cx, 0
jz FileFound
dec cx
lodsb
cmp al, byte [es:di]
jz NextChar
jmp DifferentFile
NextChar:
inc di
jmp CmpFilename
DifferentFile:
and di, 0FFE0h
add di, 20h
mov si, KernelFileName
jmp SearchFile
NextSector:
add word [wSectorNo], 1
jmp SearchRootDir
NoKernelFound:
mov si, Message2
call print_string
jmp $
FileFound:
mov ax, RootDirSectors
and di, 0FFF0h
push eax
mov eax, [es:di + 01Ch]
mov dword [dwKernelSize], eax
pop eax
add di, 01Ah
mov cx, word [es:di]
push cx
add cx, ax
add cx, DeltaSectorNo
mov ax, BaseOfKernelFile
mov es, ax
mov bx, OffsetOfKernelFile
mov ax, cx
LoadFile:
mov cl, 1
call ReadSector
pop ax
call GetFATEntry
cmp ax, 0FFFh
jz FileLoaded
push ax
mov dx, RootDirSectors
add ax, dx
add ax, DeltaSectorNo
add bx, [BPB_BytsPerSec]
jmp LoadFile
FileLoaded:
call KillMotor
mov si, Message1
call print_string
lgdt [GdtPtr]
cli
in al, 92h
or al, 00000010b
out 92h, al
mov eax, cr0
or eax, 1
mov cr0, eax
jmp dword SelectorFlatC:(BaseOfLoaderPhyAddr+LABEL_PM_START)
print_string:
lodsb
or al, al
jz .done
mov ah, 0x0E
mov bx, 0x0007
int 0x10
jmp print_string
.done:
ret
ReadSector:
push bp
mov bp, sp
sub esp, 2
mov byte [bp-2], cl
push bx
mov bl, [BPB_SecPerTrk]
div bl
inc ah
mov cl, ah
mov dh, al
shr al, 1
mov ch, al
and dh, 1
pop bx
mov dl, [BS_DrvNum]
ReadLoop:
mov ah, 2
mov al, byte [bp-2]
int 13h
jc ReadLoop
add esp, 2
pop bp
ret
GetFATEntry:
push es
push bx
push ax
mov ax, BaseOfKernelFile
sub ax, 0100h
mov es, ax
pop ax
mov byte [bOdd], 0
mov bx, 3
mul bx
mov bx, 2
div bx
cmp dx, 0
jz EvenEntry
mov byte [bOdd], 1
EvenEntry:
xor dx, dx
mov bx, [BPB_BytsPerSec]
div bx
push dx
mov bx, 0
add ax, SectorNoOfFAT1
mov cl, 2
call ReadSector
pop dx
add bx, dx
mov ax, [es:bx]
cmp byte [bOdd], 1
jnz EvenEntry2
shr ax, 4
EvenEntry2:
and ax, 0FFFh
pop bx
pop es
ret
KillMotor:
push dx
mov dx, 03F2h
mov al, 0
out dx, al
pop dx
ret
[section .s32]
align 32
[bits 32]
LABEL_PM_START:
mov ax, SelectorVideo
mov gs, ax
mov ax, SelectorFlatRW
mov ds, ax
mov es, ax
mov fs, ax
mov ss, ax
mov esp, TopOfStack
call InitKernel
jmp SelectorFlatC:KernelEntryPointPhyAddr
MemCpy:
push ebp
mov ebp, esp
push esi
push edi
push ecx
mov edi, [ebp + 8]
mov esi, [ebp + 12]
mov ecx, [ebp + 16]
CopyLoop:
cmp ecx, 0
jz CopyDone
mov al, [ds:esi]
inc esi
mov byte [es:edi], al
inc edi
dec ecx
jmp CopyLoop
CopyDone:
mov eax, [ebp + 8]
pop ecx
pop edi
pop esi
mov esp, ebp
pop ebp
ret
InitKernel:
xor esi, esi
mov cx, word [BaseOfKernelFilePhyAddr + 2Ch]
movzx ecx, cx
mov esi, [BaseOfKernelFilePhyAddr + 1Ch]
add esi, BaseOfKernelFilePhyAddr
ProcessHeader:
mov eax, [esi]
cmp eax, 0
jz NextHeader
push dword [esi + 010h]
mov eax, [esi + 04h]
add eax, BaseOfKernelFilePhyAddr
push eax
push dword [esi + 08h]
call MemCpy
add esp, 12
NextHeader:
add esi, 020h
dec ecx
jnz ProcessHeader
ret
[section .data1]
StackSpace: times 1024 db 0
TopOfStack equ $ - StackSpace
dwKernelSize dd 0
wRootDirSizeForLoop dw RootDirSectors
wSectorNo dw 0
bOdd db 0
KernelFileName db "KERNEL BIN", 0
msg db "Loading Kernel...", 0
Message1 db "OK!", 0x0A, 0x0D, 0
Message2 db "Kernel Not Find", 0
loader.inc
BS_OEMName db 'Plain ' ; 8个字节
BPB_BytsPerSec dw 512 ; 每扇区512个字节
BPB_SecPerClus db 1 ; 每簇固定1个扇区
BPB_RsvdSecCnt dw 1 ; MBR固定占用1个扇区
BPB_NumFATs db 2 ; FAT12文件系统固定2个FAT表
BPB_RootEntCnt dw 224 ; FAT12文件系统中根目录最大224个文件
BPB_TotSec16 dw 2880 ; 1.44MB磁盘固定2880个扇区
BPB_Media db 0xF0 ; 介质描述符,固定为0xF0
BPB_FATSz16 dw 9 ; 一个FAT表所占的扇区数FAT12文件系统固定为9个扇区
BPB_SecPerTrk dw 18 ; 每磁道扇区数,固定为18
BPB_NumHeads dw 2 ; 磁头数
BPB_HiddSec dd 0 ; 隐藏扇区数,没有
BPB_TotSec32 dd 0 ; 直接置0即可
BS_DrvNum db 0 ; int 13h 调用时所读取的驱动器号,由于只有一个软盘所以是0
BS_Reserved1 db 0 ; 未使用,预留
BS_BootSig db 0x29 ; 扩展引导标记,固定为0x29
BS_VolID dd 0 ; 卷序列号,由于只挂载一个软盘所以为0
BS_VolLab db 'Plain - OS ' ; 卷标,11个字节
BS_FileSysType db 'FAT12 ' ; 由于是 FAT12 文件系统,所以写入 FAT12 后补齐8个字节
FATSz equ 9 ; BPB_FATSz16
RootDirSectors equ 14 ; 根目录大小
SectorNoOfRootDirectory equ 19 ; 根目录起始扇区
SectorNoOfFAT1 equ 1 ; 第一个FAT表的开始扇区
DeltaSectorNo equ 17 ; 由于第一个簇不用,所以RootDirSectors要-2再加上根目录区首扇区和偏移才能得到真正的地址,故把RootDirSectors-2封装成一个常量(17)
DA_32 equ 0x4000
DA_LIMIT_4K equ 0x8000
DA_DPL0 equ 0x00
DA_DPL1 equ 0x20
DA_DPL2 equ 0x40
DA_DPL3 equ 0x60
DA_DR equ 0x90
DA_DRW equ 0x92
DA_DRWA equ 0x93
DA_C equ 0x98
DA_CR equ 0x9A
DA_CCO equ 0x9C
DA_CCOR equ 0x9E
DA_LDT equ 0x82
DA_TaskGate equ 0x85
DA_386TSS equ 0x89
DA_386CGate equ 0x8C
DA_386IGate equ 0x8E
DA_386TGate equ 0x8F
SA_RPL0 equ 0
SA_RPL1 equ 1
SA_RPL2 equ 2
SA_RPL3 equ 3
SA_TIG equ 0
SA_TIL equ 4
PG_P equ 1
PG_RWR equ 0
PG_RWW equ 2
PG_USS equ 0
PG_USU equ 4
%macro Descriptor 3
dw %2 & 0xFFFF
dw %1 & 0xFFFF
db (%1 >> 16) & 0xFF
dw ((%2 >> 8) & 0xF00) | (%3 & 0xF0FF)
db (%1 >> 24) & 0xFF
%endmacro
%macro Gate 4
dw (%2 & 0xFFFF)
dw %1
dw (%3 & 0x1F) | ((%4 << 8) & 0xFF00)
dw ((%2 >> 16) & 0xFFFF)
%endmacro
BaseOfLoader equ 09000h ; Loader的基址
OffsetOfLoader equ 0100h ; Loader的偏移
BaseOfLoaderPhyAddr equ BaseOfLoader * 10h ; Loader被装载到的物理地址
BaseOfKernelFile equ 08000h ; Kernel的基址
OffsetOfKernelFile equ 0h ; Kernel的偏移
BaseOfKernelFilePhyAddr equ BaseOfKernelFile * 10h ; Kernel被装载到的物理地址
KernelEntryPointPhyAddr equ 0x100000 ; Kernel入口点,一定要与编译命令一致!!!
Makefile
all:
make bin
make img
make run
bin:
nasm boot.asm -o boot.bin
nasm loader.asm -o loader.bin
#gcc -c -O0 -fno-builtin -m32 -fno-stack-protector -o monitor.o monitor.c
#gcc -c -O0 -fno-builtin -m32 -fno-stack-protector -o common.o common.c
#gcc -c -O0 -fno-builtin -m32 -fno-stack-protector -o main.o main.c
#nasm -f elf -o kernel.o kernel.asm
#nasm -f elf -o io.o io.asm
#i686-elf-ld -s -Ttext 0x100000 -o kernel.bin kernel.o io.o
img : boot.bin loader.bin kernel.bin
#dd if=boot.bin of=a.img bs=512 count=1
#dd if=loader.bin of=a.img bs=512 seek=1 conv=notrunc
#python img.py
edimg imgin:1.img \
wbinimg src:boot.bin len:512 from:0 to:0 \
copy from:loader.bin to:@: \
#copy from:kernel.bin to:@: \
imgout:a.img
run : a.img
qemu-system-i386 -fda a.img
一个make直接编译运行
显示 Kernel Not Found 即成功
至于1.img
这是ztools工具链edimg必须的,具体可以参考30day里的
为什么要有这种恶心的东西不要问我,问edimg作者

文件内容如图
依赖:
mtools (用于编译)
edimg (30day的写盘工具)
qemu (虚拟机)
i686-elf-mtools (后面用来链接)
3925

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



