一个操作系统的实现:BOOT

参考书籍为《一个64位操作系统的设计与实现》、《30天自制操作系统》

Boot的作用主要是当BIOS将执行权交给boot后,初始化文件系统,然后寻找Loader文件,如果找到则将其载入内存中并移交执行权

之前在BS_OEMName处使用了自定义的厂商名,发现软盘无法挂载,后来发现此项长度要求为8

Boot引导如下:

org 0x7c00

BaseOfStack equ 0x7c00
BaseOfLoader equ 0x1000     ; loder基地址
OffsetOfLoader equ 0x00     ; loder偏移

RootDirSectors	equ	14      ; 根目录所占扇区数
SectorNumOfRootDirStart	equ	19      ; 根目录起始扇区号
SectorNumOfFAT1Start	equ	1       ; FAT1表的起始扇区号
SectorBalance	equ	17	    ; 平衡文件\目录的起始簇号与数据区起始簇号的差值
                            ; 簇号对应扇区位置=根目录占用扇区数+根目录起始扇区号+(FAT表项-2)=根目录占用扇区数+FAT表项+SectorBalance


; FAT12文件系统引导扇区结构
jmp	short Label_Start       
	nop                            ;  BS_jmpBoot
	BS_OEMName	db	'QKKKboot'        ; 注意这此项长度为8,否则将导致软盘无法挂载
	BPB_BytesPerSec	dw	512
	BPB_SecPerClus	db	1
	BPB_RsvdSecCnt	dw	1
	BPB_NumFATs	db	2
	BPB_RootEntCnt	dw	224
	BPB_TotSec16	dw	2880
	BPB_Media	db	0xf0
	BPB_FATSz16	dw	9
	BPB_SecPerTrk	dw	18
	BPB_NumHeads	dw	2
	BPB_HiddSec	dd	0
	BPB_TotSec32	dd	0
	BS_DrvNum	db	0
	BS_Reserved1	db	0
	BS_BootSig	db	0x29
	BS_VolID	dd	0
	BS_VolLab	db	'boot loader'
	BS_FileSysType	db	'FAT12   '


Label_Start:

; 初始化寄存器
    mov ax, cs
	mov ds, ax
    mov es, ax
    mov ss, ax
    mov sp, BaseOfStack

; 清屏
    mov ax, 0600h
    mov	bx,	0700h
	mov	cx,	0
	mov	dx,	0184fh
    int 10h

; 设置光标位置
    mov ax, 0002h
    mov bx, 0000h
    mov dx, 0000h

; 显示字符串  
    mov ax, 1301h
    mov cx, 25
    mov dx, 0000h
    mov bx, 0083h
    push ax
    mov ax, ds
    mov es, ax
    pop ax
    mov bp, StartBootMessage
    int 10h

; 重置软盘
    xor ah, ah
    xor dl, dl
    int 13h


; 文件搜索(loader.bin)
    mov     word    [SectorNo],    SectorNumOfRootDirStart  ; 根目录起始扇区号

Label_Search_In_Root_Dir_Begin:

    cmp word [RootDirSizeForLoop], 0
    jz Label_No_LoaderBin
    dec word [RootDirSizeForLoop]
    mov ax, 00h
    mov es, ax
    mov bx, 8000h      ; 设置缓冲区ES:BX
    mov ax, [SectorNo]
    mov cl, 1
    call Func_ReadOneSector
    mov di, 8000h
    mov si, LoaderFileName      ;设置di和si,方便后面使用lodsb指令
    cld     ;复位DF(DF=0)
    mov dx, 10h     ; 每个扇区可容纳得目录项个数

Label_Search_For_LoaderBin:

    cmp dx, 0
    jz Label_Goto_Next_Sector_In_Root_Dir
    dec dx
    mov cx, 11      ; 目录项的文件名长度11B

Label_Cmp_FileName:

    ; 逐个字节比较文件名
    cmp cx,0
    jz Label_FileName_Found
    dec cx
    lodsb       ;   (DS:SI)->(AL),(SI++)
    cmp al, byte [es:di]
    jz Label_Go_On
    jmp Label_Different

Label_Go_On:

    inc di
    jmp Label_Cmp_FileName

Label_Different:

    and di, 0ffe0h      ; di后5位置0,该语句将di恢复为8000h
    add di, 20h     ; 增加一个目录项长度
    mov si, LoaderFileName
    jmp Label_Search_For_LoaderBin

Label_Goto_Next_Sector_In_Root_Dir:

    ; 在下一个扇区搜索
    add word [SectorNo], 1
    jmp Label_Search_In_Root_Dir_Begin

Label_No_LoaderBin:

    ; 找不到文件则报错
    mov ax, 1301h
    mov cx, 21
    mov dx, 0100h
    mov bx, 000ch
    push ax
    mov ax, ds
    mov es, ax
    pop ax
    mov bp, NoLoaderMessage
    int 10h
    jmp $       ;无限循环


; 如果找到loader.bin
Label_FileName_Found:
    mov ax, RootDirSectors
    and di, 0ffe0h  ; 后五位清0,表示回到当前目录首地址
    add di, 01ah    ; 目录项的DIR_FSTCLUS位置,表示起始簇号
    mov cx, word    [es:di]
    push cx
    add cx, ax
    add cx, SectorBalance   ; 这一步得到了簇所在位置(扇区号)
    mov ax, BaseOfLoader
    mov es, ax
    mov bx, OffsetOfLoader  ; ES:BX为loader将要载入内存的位置
    mov ax, cx

Label_Go_On_Loading_File:
	push	ax
	push	bx
	mov	ah,	0eh
	mov	al,	'.'
	mov	bl,	0fh
	int	10h
	pop	bx
	pop	ax
    ; 以上功能为打印一个“.”可依此观察读了几个扇区数据,即loader占了多少扇区
	mov	cl,	1
	call	Func_ReadOneSector
	pop	ax
	call	Func_GetFATEntry
	cmp	ax,	0fffh       ; 0FFF是文件最后一个簇的标志
	jz	Label_File_Loaded
	push	ax
	mov	dx,	RootDirSectors
	add	ax,	dx
	add	ax,	SectorBalance   ; 重新计算扇区号
	add	bx,	[BPB_BytesPerSec]   ; bx表示内存偏移
	jmp	Label_Go_On_Loading_File

Label_File_Loaded:
	
	jmp	BaseOfLoader:OffsetOfLoader     ; 移交给loader

; 读取软盘功能实现
Func_ReadOneSector:

    ;  int 13h,AH=02h 读取磁盘扇区
    ;   AL=读入的扇区数, CH=磁道号,CL=扇区号,DH=磁头号,DL=驱动器号,ES:BX=数据缓冲区
    
    ;保存现场
    push bp
    mov bp, sp
    sub esp, 2
    mov byte [bp-2], cl
    push bx     

    ; LBA格式转CHS格式
    mov	bl,	[BPB_SecPerTrk]
    div bl      ; 余数在ah,商在al
    inc ah
    mov cl, ah
    mov dh, al
    shr al, 1
    mov ch, al
    and dh, 1
    pop bx
    mov dl, [BS_DrvNum]
Label_Go_On_Reading:
    mov ah, 2
    mov al, byte [bp-2]
    int 13h
    jc Label_Go_On_Reading     ; CF未复位则重新调用中断
    add esp, 2
    pop bp
    ret


Func_GetFATEntry:

    ;解析FAT表
    push es
    push bx
    push ax
    mov ax, 00
    mov es, ax      ; 初始化es
    pop ax
    mov byte [Odd], 0
    mov bx, 3
    mul bx
    mov bx, 2       ; ax为FAT表号,扩大1.5倍
    div bx          
    cmp dx, 0       ;判断当前表项是奇数还是偶数,
    jz  Label_Even
    mov byte [Odd], 1    ;奇数置1

Label_Even:

    xor dx,dx       
    mov bx, [BPB_BytesPerSec]
    div bx      ; 商为FAT表偏移扇区号,余数为FAT表项在扇区的偏移
    push	dx  
	mov	bx,	8000h       ; 设置缓冲区
	add	ax,	SectorNumOfFAT1Start
	mov	cl,	2
	call	Func_ReadOneSector      ;一次读出两个扇区,防止fat表横跨两个扇区
	
	pop	dx
	add	bx,	dx
	mov	ax,	[es:bx]
	cmp	byte	[Odd],	1
	jnz	Label_Even_2
	shr	ax,	4       ; 上一项为奇数,则下一项为偶数,右移4位是舍弃多余数据

Label_Even_2:
	and	ax,	0fffh   ; 上一项为偶数,下一项是奇数,前四位置0,舍弃多余数据
	pop	bx
	pop	es
	ret

; 中间变量
RootDirSizeForLoop	dw	RootDirSectors      ; 用于控制循环
SectorNo		dw	0      ; 当前扇区号
Odd			db	0       ; FAT表项奇偶标志


; 消息类型定义
StartBootMessage:	db	"Created by Qkk,Start Boot"
NoLoaderMessage:	db	"ERROR:No LOADER Found"
LoaderFileName:		db	"LOADER  BIN",0

; 填充及引导标志设置

	times	510 - ($ - $$)	db	0
	dw	0xaa55

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值