Overview
这个学期有OS的系统实践课程,在此记录下我的实验步骤,方便各位同学学习。这篇主要是环境搭建的过程,包括bochs 3.0和qemu的环境搭建
Bochs-3.0
安装
在官网下载源码,链接
tar -zxvf bochs-3.0.tar.gz
cd bochs-3.0/Bash安装依赖
sudo apt install libx11-dev libc6-dev build-essential xorg-dev libgtk2.0-dev libreadline-dev libsdl2-devBash编写配置文件
./configure --with-sdl2 --enable-debugger --enable-all-optimizations --enable-readline --enable-debugger-gui --enable-x86-debugger --enable-a20-pin --enable-fast-function-callsBash--enable-debugger和--gdb-stub不能同时开启
安装
sudo make all-clean
sudo make -j 20
sudo make installBash
安装成功
制作一个可启动的软盘
首先写入以下代码
org 07c00h
mov ax, cs
mov ds, ax
mov es, ax
call DispStr
jmp $
DispStr:
mov ax, BootMessage
mov bp, ax
mov cx, 16
mov ax, 01301h
mov bx, 000ch
mov dl, 0
int 10h
ret
BootMessage: db 'Hello, World! 123', 0
times 510 - ($ - $$) db 0
dw 0xaa55ASM然后编译源码
nasm boot.asm -o boot.bin # 生成引导文件
nasm boot.asm -o boot.com # 生成com文件Bash没有nasm的需要自行安装sudo apt install nasm
制作一张虚拟软驱
bximage
bximage> 0
bximage> fd
bximage> 1.44M
bximage> a.imgBash写引导盘
dd if=boot.bin of=a.img bs=512 count=1Bashif=boot.bin→ 输入文件of=a.img→ 输出文件(目标软盘镜像)bs=512 count=1→ 只写 1 个扇区(512 字节)conv=notrunc→ 不截断a.img的大小
这样 a.img 就变成了一个可以引导的软盘镜像。
编写bochsrc
bochsrc相当于bochs的配置文件,里面写的是虚拟机的硬件参数:内存大小、CPU类型、加载哪个软盘/硬盘镜像,用什么GUI等等
在这里我列出我自己写的bochsrc文件
megs: 16
romimage: file=/usr/local/share/bochs/BIOS-bochs-latest
vgaromimage: file=/usr/local/share/bochs/VGABIOS-lgpl-latest.bin
floppya: 1_44=a.img, status=inserted
boot: a
log: bochsout.txtBash其中romimage和vgaromimage可以使用以下命令查找
sudo find / -name 'BIOS-bochs-latest'
sudo find / -name 'VGABIOS-lgpl-latest.bin'Bash当然如果你虚拟机文件很多,其实也可以在/usr下找
a.img是我们先前创建好的软盘镜像
运行
bochs -f ./bochsrc # 引导过一次后续好像就不需要引导了Bash
但是要注意,如果你是vmware虚拟机,不需要关心调试的问题,但是如果是wsl还需要再启动时添加一个参数
bochs -debugger # 立即开启调试窗口Bash
然后就可以开心的调试了,要不是这个代码是i8086的,gdb原生不支持,直接qemu启动了
qemu
前面的操作都一样,我们从制作一个可启动的软盘开始
制作一个可启动的软盘
先写入asm文件
org 07c00h
mov ax, cs
mov ds, ax
mov es, ax
call DispStr
jmp $
DispStr:
mov ax, BootMessage
mov bp, ax
mov cx, 16
mov ax, 01301h
mov bx, 000ch
mov dl, 0
int 10h
ret
BootMessage: db 'Hello, World! 123', 0
times 510 - ($ - $$) db 0
dw 0xaa55ASM然后制作软盘
nasm -f bin boot.asm -o boot.bin
dd if=/dev/zero of=boot.img bs=512 count=2880
dd if=boot.bin of=boot.img conv=notruncBashqemu运行
qemu-system-i386 -fda boot.imgBash
调试运行
qemu-system-i386 -fda boot.img -s -SBash-s= 开启 gdbserver,监听在:1234-S= 启动后暂停 CPU,不会立即运行
起一个gdb
gdb
pwndbg> target remote :1234
pwndbg> b *0x7c00
pwndbg> cBash
但是无法识别i8086的汇编
实验内容
删除0xaa55
结果
首先放结果,No bootable device

原因
0xaa55是引导扇区的魔术签名(Boot Signature),这是BIOS识别有效引导扇区的关键标识。
- BIOS引导检查机制:
- BIOS在启动时会检查第一个扇区(引导扇区)的最后两个字节
- 这两个字节必须是
0x55 0xAA(小端格式存储) - 如果没有这个签名,BIOS会认为这不是一个有效的引导扇区
- 引导扇区结构要求:
- 引导扇区必须是512字节
- 前510字节是代码和数据
- 最后2字节必须是0xaa55
- 没有0xaa55的后果:
- BIOS不会将控制权交给你的代码
- 系统会继续寻找其他可引导设备
- 最终显示”No bootable device found”
可以在输出中发现

依次找了Hard Disk -> Floppy -> DVD/CD -> ROM -> network,最后返回了No bootable device
为什么要jmp $
jmp $相当于一个无限循环,表示跳转到当前位置,这样做有两个目的:
- 程序需要打印
hello world,防止打印完成之后被后续的内容刷新掉 - 避免执行垃圾代码,如果没有这个循环,
CPU会继续执行后面的数据区域,把数据当作指令执行,那系统就跑飞了,容易造成损坏

可以发现当程序执行到这里会一直执行跳转
修改后

会将后续的数据区域当作代码执行
如何让输出过程执行100次
思路就是设置一个cx计数器循环并设置一个行号dh,同时更新字符串末尾,添加计数器
具体代码如下,已在具体位置写入注释便于理解
org 07c00h
mov ax, cs
mov ds, ax
mov es, ax
mov cx, 100
mov dh, 0 ; 初始化行号
mov si, 0 ; 初始计数器
loop1:
call UpdateCounter ; 在字符串末尾添加计数器
call DispStr
inc dh ; 行号加1
cmp dh, 25 ; 检查是否超过屏幕行数
jl no_reset ; 如果没超过,继续
mov dh, 0 ; 重置到第0行
no_reset:
loop loop1
jmp $
UpdateCounter:
push ax
push bx
push cx
push dx
; 计算当前计数器的十位和个位
mov ax, si
mov bx, 10
xor dx, dx
div bx ; ax = si / 10, dx = si % 10
; 更新字符串的个位数字
add dl, '0' ; 将个位数字转换为字符
mov [BootMessage + 27], dl
; 更新字符串的十位数字
cmp ax, 0 ; 检查十位是否为0
je skip_tens ; 如果为0,跳过
add al, '0' ; 将十位数字转换为字符
mov [BootMessage + 26], al
jmp update_done
skip_tens:
mov byte [BootMessage + 28], ' ' ; 个位数时十位显示空格
update_done:
inc si ; 计数器加1
pop dx
pop cx
pop bx
pop ax
ret
DispStr:
push ax
push bp
push cx
push bx
push dx
mov ax, BootMessage
mov bp, ax
mov cx, 28
mov ax, 01301h
mov bx, 000ch
mov dl, 0 ; 列号保持0(最左边)
; dh已经在主循环中设置了行号
int 10h
pop dx
pop bx
pop cx
pop bp
pop ax
ret
BootMessage: db 'Hello, World! 123, index: ', 0
times 510 - ($ - $$) db 0
dw 0xaa55ASM
总结
这次实验主要是基础实验环境的搭建,为后续实验打下基础,同时熟悉bochs和qemu的基本使用方法




太有说法了
大佬