BootLoader引导启动程序

Boot引导程序

写一个Boot引导程序

起始地址
org 0x7c00
BaseOfStack equ 0x7c00
初始化
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
mov sp, BaseOfStack

进行地址段寄存器(ds)、附加段寄存器(es)、堆栈段寄存器(ss)初始化,并将堆栈指针(sp)初始化为BaseOfStack,代表引导程序地址设在0x7c00处。

BIOS中断服务

使用x86汇编语言INT指令

该os常用的BIOS 中断向解释:

  • INT 10h

显示服务 , 由BIOS或操作系统设定以供软件调用。AH=00h 设定显示模式;AH=01h 设定游标形态;AH=02h 设置游标位置;AH=03h 获取光标位置与形态;AH=04h 获取光标位置;AH=05h 设置显示页;AH=06h 清除或滚动栏画面(上);AH=07h 清除或滚动栏画面(下);AH=08h 读取游标处字符与属性;AH=09h 更改游标处字符与属性;AH=0Ah 更改游标处字符;AH=0Bh 设定边界颜色;AH=0Eh 在TTY模式下写字符;AH=0Fh 获取当前显示模式;AH=13h 写字符串。

  • INT 13h

低级磁盘服务。AH=00h 复位磁盘驱动器;AH=01h 检查磁盘驱动器状态;AH=02h 读扇区;AH=03h 写扇区;AH=04h 校验扇区;AH=05h 格式化磁道;AH=08h 获取驱动器参数;AH=09h 初始化硬盘驱动器参数;AH=0Ch 寻道;AH=0Dh 复位硬盘控制器;AH=15h 获取驱动器类型;AH=16h 获取软驱中盘片的状态。

  • INT 15h

其它(系统支持例程)。AH=4FH 键盘拦截;AH=83H事件等待;AH=84H读游戏杆;AH=85HSysRq 键;AH=86H等待;AH=87H块移动;AH=88H获取扩展内存容量;AH=C0H获取系统参数;AH=C1H获取扩展 BIOS 数据区段;AH=C2H指针设备功能;AH=E8h, AL=01h (AX = E801h)获取扩展内存容量(自从 1994 年引入的新功能),可获取到 64MB 以上的内存容量;AH=E8h, AL=20h (AX = E820h)查询系统地址映射;该功能取代了 AX=E801h 和 AH=88h。

清屏
mov ax, 0600h  ;06,按指定范围滚动窗口
mov bx, 0700h 
mov cx, 0
mov dx, 0184fh
int 10h

在接下来程序中

AX: 用于指定调用哪个的子功能。

BX: 通常用于设置文本和背景的颜色属性。

CX: 通常用于指定要操作的字符数或其他数量。

DX: 通常用于设置光标的位置。

AH=06h 清除或滚动栏画面

0700h=0000 0111

依照BH=颜色属性

  • bit 0~2:字体颜色(0:黑,1:蓝,2:绿,3:青,4:红,5:紫,6:综,7:白)。

  • bit 3:字体亮度(0:字体正常,1:字体高亮度)

  • bit 4~6:背景颜色(0:黑,1:蓝,2:绿,3:青,4:红,5:紫,6:综,7:白)。

  • bit 7:字体闪烁(0:不闪烁,1:字体闪烁)。

bit 0~2为111,即白色字体;bit 3为0,即字体正常;bit 4~6为000,即黑色背景;bit 7为0,即字体不闪烁

光标
mov ax, 0200h
mov bx, 0000h
mov dx, 0000h
int 10h

AH=02h 设置游标位置

mov bx, 0000hmov dx, 0000h 代表光标位置位于屏幕左上角(0,0)处

初始屏幕
mov ax, 1301h
mov bx, 000fh
mov dx, 0000h
mov cx, 10
push ax
mov ax, ds
mov es, ax
pop ax
mov bp, StartBootMessage 
int 10h

AH=13h 写字符串

AL=01h 光标会移到字符串尾端位置(AL=00h 光标会移到字符串前端位置)

mov cx, 10 字符串长度为10(该字符串是StartBootMessage)

mov bp, StartBootMessage 将StartBootMessage 写入bp

复位
xor ah,ah
xor dl,dl
int 13h
    
jmp $

xor是异或,将ah和dl清0

填充
times 510-($-$$) db 0 ;$-$$ 
dw 0xaa55

将当前行被编译后的地址(机器码地址)减去本节 ( Section)程序的起始地址,将521B空间(扇区单位)填充

0xaa55引导扇区是以0xaa、0x55为结尾(默认),又因为Inter处理器是小段模式存储,所以这样写

创建虚拟软盘镜像

利用Bochs虚拟机自带的虚拟磁盘镜像创建工具bximage

运行命令

@ubuntu:~/Desktop$ bximage
========================================================================
                                bximage
  Disk Image Creation / Conversion / Resize and Commit Tool for Bochs
         $Id: bximage.cc 13069 2017-02-12 16:51:52Z vruppert $
========================================================================
​
1. Create new floppy or hard disk image
2. Convert hard disk image to other format (mode)
3. Resize hard disk image
4. Commit 'undoable' redolog to base image
5. Disk image info
​
0. Quit
​
Please choose one [0] 1
​
Create image
​
Do you want to create a floppy disk image or a hard disk image?
Please type hd or fd. [hd] fd
​
Choose the size of floppy disk image to create.
Please type 160k, 180k, 320k, 360k, 720k, 1.2M, 1.44M, 1.68M, 1.72M, or 2.88M.
 [1.44M] 
​
What should be the name of the image?
[a.img] boot.img
​
Creating floppy image 'boot.img' with 2880 sectors
​
The following line should appear in your bochsrc:
  floppya: image="boot.img", status=inserted

选择1,fd,软盘容量1.44MB是通用的3.5英寸软盘,然后对镜像文件取名

接下来可以选择5去查看磁盘信息,不过感觉内存少了点。查阅资料,正常3.5英寸软盘的容量是1.44 MB=1440×1024KB=1474560 B,软盘共包含2个磁头、80个磁道、18个扇区。此处的bximage工具只正确解析出虚拟磁盘容量是1474560 B,bximage工具是按照1MB进行计算的,确实不大对,不过应该不影响?

运行Boot程序

编译引导程序
nasm boot.asm -o boot.bin
使用dd命令把引导程序写入引导扇区
dd if=boot.bin of=./bochs-2.6.8/boot.img bs=512 count=1 conv=notrunc

运行成功

(root@localhost 1]# dd if=boot.bin of=./bochs-2.6.9/boot.img bs=512 count=1 conv=notrunc
1+0 records in
1+0 records out
512 bytes (512 B) copied, 0.000155041 s,2.2 MB/s 

成功的样子大概这样

bochs命令启动虚拟机
bochs -f ./bochsrc

这里的bochsrc我在bochs-2.6.8文件夹中没有找到,运行这个命令也会报错,我就上网搜了一下,发现这个bochsrc并不存在,需要自己写

bochsrc文件

终端输入生成文件

vi bochsrc

bochsrc内容为

# configuration file generated by Bochs
plugin_ctrl: unmapped=1, biosdev=1, speaker=1, extfpuirq=1, parallel=1, serial=1, iodebug=1
config_interface: textconfig
display_library: x
#memory: host=2048, guest=2048
romimage: file="/usr/local/share/bochs/BIOS-bochs-latest"
vgaromimage: file="/usr/local/share/bochs/VGABIOS-lgpl-latest"
boot: floppy
floppy_bootsig_check: disabled=0
floppya: type=1_44, 1_44="boot.img", status=inserted, write_protected=0
# no floppyb
ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
ata0-master: type=none
ata0-slave: type=none
ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15
ata1-master: type=none
ata1-slave: type=none
ata2: enabled=0
ata3: enabled=0
pci: enabled=1, chipset=i440fx
vga: extension=vbe, update_freq=5
​
cpu: count=1:1:1, ips=4000000, quantum=16, model=corei7_haswell_4770,reset_on_triple_fault=1, cpuid_limit_winnt=0, ignore_bad_msrs=1, mwait_is_nop=0, msrs="msrs.def"
​
cpuid: x86_64=1,level=6, mmx=1, sep=1, simd=avx512, aes=1, movbe=1, xsave=1,apic=x2apic,sha=1,movbe=1,adx=1,xsaveopt=1,avx_f16c=1,avx_fma=1,bmi=bmi2,1g_pages=1,pcid=1,fsgsbase=1,smep=1,smap=1,mwait=1,vmx=1
cpuid: family=6, model=0x1a, stepping=5, vendor_string="GenuineIntel", brand_string="Intel(R) Core(TM) i7-4770 CPU (Haswell)"
​
print_timestamps: enabled=0
debugger_log: -
magic_break: enabled=0
port_e9_hack: enabled=0
private_colormap: enabled=0
clock: sync=none, time0=local, rtc_sync=0
# no cmosimage
# no loader
log: -
logprefix: %t%e%d
debug: action=ignore
info: action=report
error: action=report
panic: action=ask
keyboard: type=mf, serial_delay=250, paste_delay=100000, user_shortcut=none
mouse: type=ps2, enabled=0, toggle=ctrl+mbutton
speaker: enabled=1, mode=system
parport1: enabled=1, file=none
parport2: enabled=0
com1: enabled=1, mode=null
com2: enabled=0
com3: enabled=0
com4: enabled=0
​
megs: 2048

这个文件配置网上有很多说法,但是我通过后面一些debug发现这个是最合适的,其他会出错

然后ESC输入”:wq“保存就可以了

然后运行

bochs -f ./bochsrc

生成成功后大概是这样

@ubuntu:~/bochs-2.6.9$ bochs -f ./bochsrc
========================================================================
                       Bochs x86 Emulator 2.6.9
               Built from SVN snapshot on April 9, 2017
                  Compiled on Aug 15 2023 at 23:59:28
========================================================================
00000000000i[      ] BXSHARE not set. using compile time default '/usr/local/share/bochs'
00000000000i[      ] reading configuration from ./bochsrc
------------------------------
Bochs Configuration: Main Menu
------------------------------
​
This is the Bochs Configuration Interface, where you can describe the
machine that you want to simulate.  Bochs has already searched for a
configuration file (typically called bochsrc.txt) and loaded it if it
could be found.  When you are satisfied with the configuration, go
ahead and start the simulation.
​
You can also start bochs with the -q option to skip these menus.
​
1. Restore factory default configuration
2. Read options from...
3. Edit options
4. Save options to...
5. Restore the Bochs state from...
6. Begin simulation
7. Quit now
​
Please choose one: [6] 
​

默认选择6(表示开始运行虚拟机)

运行

刚开始就是黑框

image-20230830205648163

然后在终端输入c/cont/continue任意一个就行

boot运行成功

ok,引导程序运行成功

加载Loader到内存

选择FAT12文件系统来装载Loader程序和内核程序

FAT类文件系统会对软盘里的扇区进行结构化处理,进而把软盘扇区划分成引导扇区、FAT表、根目录区和数据区4部分。

软盘文件系统分配图

加载Loader到内存

引导扇区
jmp short Lable_Start
nop
BS_OEMName      db 'Mi64boot'
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 29h
BS_VolTD        dd 0
BS_VolLab       db 'boot loader'
BS_FileSysType  db 'FAT12'

jmp short Lable_Start 无条件短跳转指令,使程序跳到标签 label_start指向的代码地址开始执行

BS_OEMName 生产厂商名,自定义取名

BPB_BytesPerSec 每扇区字节数,一个扇区为512B

BPB_SecPerClus 每簇扇区数。簇是FAT类文件系统的最小存储单位

BPB_RsvdSecCnt 保留扇区数,保留扇区起始于FAT12文件系统的第一个扇区,引导扇区包含在保留扇区内,FAT表从软盘的第二个扇区开始。

BPB_NumFATs FAT12文件系统中FAT表的份数,建议FAT类文件都设为2,给FAT表准备备份表

BPB_RootEntCnt 根目录可容纳的目录项数,

BPB_TotSec16 如果总扇区数小于65536,则为总扇区数

BPB_Media 媒体类型

BPB_FATSz16 每个FAT表的扇区数

BPB_SecPerTrk 每磁道的扇区数

BPB_NumHeads 硬盘的磁头数

BPB_hiddSec 分区之前的隐藏扇区数

BPB_TotSec32 如果总扇区数大于65535,则为总扇区数

BS_DrvNum 驱动器号

BS_Reserved1 保留字节

BS_BootSig 引导签名,值为29h表示后面是卷序列号、卷标和文件系统类型

BS_VolTD 卷序列号

BS_VolLab 卷标

BS_FileSysType 文件系统类型,这里为"FAT12"

Loader中的数据定义

起始地址

BaseOfLoader equ 0x10000
OffsetOfLoader equ 0x00

Loader的起始物理地址为:BaseOfLoader << 4 + OffsetOfLoader = 0x10000

根目录占用扇区数

RootDirSectors equ 14

计算公式:BPB_RootEntCnt * 32 + BPB_BytesPerSec

根目录起始扇区号

SectorNumOfRootDirStart equ 19

计算公式:保留扇区数 + FAT表扇区数 * FAT表份数 = 1 + 9 * 2 = 19

因为从0开始,所以接下来就从19开始

FAT1表起始扇区号

SectorNumOfFAT1Start equ 1

前面说了保留扇区起始于FAT12文件系统的第一个扇区,所以起始我们就用第二个。而扇区编号从0开始,所以这个值为1

平衡文件(或者目录)的起始簇号与数据区起始簇号的差值

SectorBalance equ 17

在FAT12中FAT[0]和FAT[1]是保留项,不能用于数据区的簇索引

为了正确计算出FAT表项对应的数据区起始扇区号,则必须将FAT表项值减2

这里将根目录起始扇区减2(19 - 2 = 17),就等于间接把数据区的起始扇区号(数据区起始扇区号=根目录起始扇区号+根目录所占扇区数)减2

软盘读取
Func_ReadOneSector:
    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]
Label_Go_On_Reading:
    mov ah, 2
    mov al, byte [bp-2]
    int 13h
    jc Label_Go_On_Reading
    add esp, 2
    pop bp
    ret

用到了BIOS中断服务的INT 13h

AH=02h 是读取磁盘扇区

因为Func_ReadOnesector模块传入的磁盘扇区号是LBA(Logical Block Address,逻辑块寻址)格式的,而INT 13h,AH=02h中断服务程序只能受理CHS (Cylinder/Head/Sector,柱面/磁头/扇区)格式的磁盘扇区号,那么必须将LBA格式转换为CHS格式

转换公式为:

img

读取软盘前需要先保存栈帧寄存器和栈寄存器的数值,可以利用[bp-2] 开辟两个空间放

div bl 代表ax/bl,并将值存在ax中,即计算出目标磁道号

inc ah 将ax/bl余存入ah中,即目标磁道内的起始扇区号,磁道内的起始扇区号从1开始计数,故此将余数值加1

编译

与编译boot.asm程序相似

nasm loader.asm -o loader.bin
loader.bin复制到虚拟软盘镜像文件boot.img中

借助挂载命令mount和复制命令cp,把引导加载程序loader.bin复制到文件系统中

sudo mount -o loop ./bochs-2.6.8/boot.img /media/img
sudo cp loader.bin  /media/img
sudo sync
sudo umount /media/img

运行成功如下:

48Y6NWIK{`X5EU{1D`FU2TK

补充:

boot.img格式化
sudo mkfs.ext4 boot.img
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值