系统环境:
OS:CentOS Stream release 9 (cmd: cat /etc/redhat-release)
Linux Kernel:Linux 5.14.0-142.el9.x86_64 (cmd: uname -a)
1. Bochs 虚拟机
Bochs
是一个开源的虚拟机软件,并且提供了利于系统开发的相关调试功能,如果你也是研究操作系统或对 Linux
内核感兴趣的读者,那么这款软件将会帮助你更好的调试和完善开发内容。
下载链接:
Bochs 官网:https://bochs.sourceforge.io/
Sourceforge下载:https://sourceforge.net/projects/bochs/files/bochs/
Github 下载:https://github.com/stlintel/Bochs
2. 编译并安装 Bochs
笔者选择在 sourceforge
上下载
2.2. 解压源码包
下载后需要解压源码包。
[imaginemiracle@imos-ws Downloads]$ tar -zxvf bochs-2.7.tar.gz
2.3. 安装依赖并配置 Bochs
安装相关依赖,否则配置或编译会出先缺少依赖的情况。
[imaginemiracle@imos-ws bochs-2.7]$ sudo yum install gcc-c++
[imaginemiracle@imos-ws bochs-2.7]$ sudo yum install gtk2-devel
[imaginemiracle@imos-ws bochs-2.7]$ sudo yum install readline-devel
[imaginemiracle@imos-ws bochs-2.7]$ sudo yum install xorg-x11-server-Xdmx.x86_64
2.3.1. 使用 configure 配置生成 Makefile
进入解压后的源码目录,使用 configure
对源码进行配置,这里笔者使用 --prefix
将其安装目录配置为指定位置,不需要指定的读者可以不用加该参数。
[imaginemiracle@imos-ws bochs-2.7]$ ./configure --prefix=/pgm/bochs --with-x11 --with-wx --enable-debugger --enable-all-optimizations --enable-readline --enable-long-phy-address --enable-ltdl-install --enable-idle-hack --enable-a20-pin --enable-x86-64 --enable-smp --enable-cpu-level=6 --enable-large-ramfile --enable-repeat-speedups --enable-fast-function-calls --enable-handlers-chaining --enable-trace-linking --enable-configurable-msrs --enable-show-ips --enable-cpp --enable-debugger-gui --enable-iodebug --enable-logging --enable-assert-checks --enable-fpu --enable-vmx=2 --enable-svm --enable-3dnow --enable-alignment-check --enable-monitor-mwait --enable-avx --enable-evex --enable-x86-debugger --enable-pci --enable-usb --enable-voodoo
2.3.2. make 编译
配置没有报错后,便可以直接编译了。
[imaginemiracle@imos-ws bochs-2.7]$ make
2.3.3. 报错:No rule to make target ‘parser.cc’, needed by ‘parser.o’.
编译时可能会遇到这样或类似的错误:
make[1]: *** No rule to make target 'parser.cc', needed by 'parser.o'. Stop.
2.3.4. 解决没有 parser.cc 问题
只需要将对应的 .cpp
文件拷贝为 .cc
文件即可:
[imaginemiracle@imos-ws bochs-2.7]$ cp bx_debug/parser.cpp bx_debug/parser.cc
[注]:不要疑问要怎么找到复制文件的目录所在。出错行紧后会提示从出错目录退出,这个目录便是缺少文件的目录,需要复制文件的目录也就在这里了。
2.3.5. 继续 make,继续报错:fatal error: config.h: No such file or directory
继续执行 make
命令,但是又会出现这样的错误:提示没有找到 config.h
cd bx_debug && \
make libdebug.a
make[1]: Entering directory '/home/imaginemiracle/Downloads/bochs-2.7/bx_debug'
g++ -g -O2 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILES -c -o parser.o parser.cc
In file included from parser.y:8:
debug.h:25:10: fatal error: config.h: No such file or directory
25 | #include "config.h"
| ^~~~~~~~~~
compilation terminated.
make[1]: *** [<builtin>: parser.o] Error 1
make[1]: Leaving directory '/home/imaginemiracle/Downloads/bochs-2.7/bx_debug'
make: *** [Makefile:327: bx_debug/libdebug.a] Error 2
2.3.6. 解决没有找到 config.h 问题
关于这个头文件,我们在源码的主目录下可以看得到
[imaginemiracle@imos-ws bochs-2.7]$ ls
aclocal.m4 bxversion.rc configure gui ltdl.c osdep.cpp README
bios bxversion.rc.in configure.in host ltdlconf.h osdep.h README-wxWidgets
bochs.h CHANGES COPYING install-sh ltdlconf.h.in param_names.h TESTFORM.txt
build config.cpp cpu instrument ltmain.sh PARAM_TREE.txt TODO
bx_debug config.guess cpudb.h iodev main.cpp patches win32_enh_dbg.rc
bxdisasm.cpp config.h crc.cpp libtool Makefile pc_system.cpp win32res.rc
bxthread.cpp config.h.in doc LICENSE Makefile.in pc_system.h wxbochs.rc
bxthread.h config.log docs-html logio.cpp memory plugin.cpp
bxversion.h config.status extplugin.h logio.h misc plugin.h
bxversion.h.in config.sub gdbstub.cpp ltdl-bochs.h msrs.def qemu-queue.h
打开报错文件
[imaginemiracle@imos-ws bochs-2.7]$ vim bx_debug/debug.h
修改第 25
行的 #include "config.h"
为 #include "../config.h"
即可。
2.3.7. 继续 make,继续报错:fatal error: osdep.h: No such file or directory 和 fatal error: cpu/decoder/decoder.h: No such file or directory
与上一个错误类似的还有两个,同样可以在主目录下找到 osdep.h
,因此同样打开 bx_debug/debug.h
将 #include “osdep.h”
修改为 #include "../osdep.h"
,第 36
行的 #include "cpu/decoder/decoder.h"
同样修改一下。
2.3.8. 继续 make,没错的话还会报错:No rule to make target ‘misc/bximage.cc’, needed by ‘misc/bximage.o’ 等一系列这样的问题
这类问题与第一个错误类似,在出错目录下也会有对应的 .cpp
文件,将其复制一份为 .cc
文件即可。
[imaginemiracle@imos-ws bochs-2.7]$ cp misc/bximage.cpp misc/bximage.cc
[imaginemiracle@imos-ws bochs-2.7]$ cp iodev/hdimage/hdimage.cpp iodev/hdimage/hdimage.cc
[imaginemiracle@imos-ws bochs-2.7]$ cp iodev/hdimage/vmware3.cpp iodev/hdimage/vmware3.cc
[imaginemiracle@imos-ws bochs-2.7]$ cp iodev/hdimage/vmware4.cpp iodev/hdimage/vmware4.cc
[imaginemiracle@imos-ws bochs-2.7]$ cp iodev/hdimage/vpc.cpp iodev/hdimage/vpc.cc
[imaginemiracle@imos-ws bochs-2.7]$ cp iodev/hdimage/vbox.cpp iodev/hdimage/vbox.cc
2.3.9. 继续 make 没错后 make install 安装
这个时候执行 make
应该不会有错了,执行 make install
命令安装。
[imaginemiracle@imos-ws bochs-2.7]$ make install
查看一下安装目录,如果使用的是默认安装目录的话,则直接键入 boch
然后使用 tab
键可以补齐。
[imaginemiracle@imos-ws ~]$ ls /pgm/bochs/bin/
bochs bximage
OK,如果看到有可执行文件生成到这里的话,那就说明 bochs
算是安装好了。
3. 制作软盘镜像文件
我们刚安装的 Bochs
配带了一个叫 bximage
的工具,这个工具变是用来创建虚拟机镜像的。
来看具体的使用方法:
(1) 直接执行 bximage
(如果是像笔者一样安装到指定目录的话则首先需要将其添加进 在 ~/.bashrc
文件中,并更新环境变量 source ~/.bashrc
,例:export PATH=$PATH:/pgm/bochs/bin
)
[imaginemiracle@imos-ws img]$ bximage
========================================================================
bximage
Disk Image Creation / Conversion / Resize and Commit Tool for Bochs
$Id: bximage.cc 14091 2021-01-30 17:37:42Z sshwarts $
========================================================================
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
(2) 这里输入 1
,表示选择要创建一个软盘或者硬盘,按下回车则会出现如下内容;
Create image
Do you want to create a floppy disk image or a hard disk image?
Please type hd or fd. [hd] fd
(3) 这里让我们选择创建的类型是软盘 (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]
(4) 接下来会让选择创建的软盘大小,默认值是 1.44MB
,这里直接回车使用默认值就好;
What should be the name of the image?
[a.img] imboot.img
Creating floppy image 'imboot.img' with 2880 sectors
The following line should appear in your bochsrc:
floppya: image="imboot.img", status=inserted
(5) 下一步会询问创建的软盘名字是什么,默认名为 a.img
,这里笔者输入的名为 imboot.img
,因为之后将会使用这个软盘作为一个 boot
程序用来启动操作系统使用。
ok,到这里软盘镜像文件创建完成。
4. Bochs 运行环境配置
在 Bochs
的安装目录下会提供一个供我们参考的一份配置文件 /pgm/bochs/share/doc/bochs/bochsrc-sample.txt
,复制一份到本地来参考或者直接拷贝笔者的配置。
# 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: wx
display_library: x
romimage: file=$BXSHARE/BIOS-bochs-latest, options=fastboot
romimage: file=/pgm/bochs/share/bochs/BIOS-bochs-latest
vgaromimage: file=/pgm/bochs/share/bochs/VGABIOS-lgpl-latest
# choose the boot disk
boot: floppy
floppy_bootsig_check: disabled=0
floppya: type=1_44, 1_44=/home/imaginemiracle/Miracle/Projects/imOS/img/imboot.img, status=inserted, write_protected=0
cpu: model=corei7_haswell_4770, count=1:1:1, ips=50000000, reset_on_triple_fault=1, ignore_bad_msrs=1, msrs="msrs.def"
cpu: cpuid_limit_winnt=0
cpuid: x86_64=1, mmx=1, level=6, sep=1, simd=sse4_2, apic=xapic, aes=1, movbe=1, xsave=1, apic=x2apic, sha=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)"
#memory: guest=512, host=256
pci: enabled=1, chipset=i440fx
vga: extension=vbe, update_freq=5
#voodoo: enabled=1, model=voodoo1
keyboard: type=mf, serial_delay=250, paste_delay=100000, user_shortcut=none
mouse: enabled=0, type=ps2, toggle=ctrl+mbutton
clock: sync=none, time0=local, rtc_sync=0
#cmosimage: file=cmos.img, rtc_init=time0
private_colormap: enabled=0
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, ioaddr1=0x1e8, ioaddr2=0x3e0, irq=11
ata3: enabled=0, ioaddr1=0x168, ioaddr2=0x360, irq=9
boot: floppy
#boot: disk
floppy_bootsig_check: disabled=0
#log: /dev/null
log: bochsout.txt
logprefix: %t%e%d
panic: action=ask
error: action=report
info: action=report
debug: action=ignore, pci=report # report BX_DEBUG from module 'pci'
debugger_log: -
#com1: enabled=1, mode=term, dev=/dev/ttyp9
parport1: enabled=1, file="parport.out"
#sound: driver=default, waveout=/dev/dsp. wavein=, midiout=
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
#e1000: enabled=1, mac=52:54:00:12:34:56, ethmod=slirp, script=slirp.conf
magic_break: enabled=0
#debug_symbols: file="kernel.sym"
print_timestamps: enabled=1
port_e9_hack: enabled=0
private_colormap: enabled=0
megs: 2048
需要注意的是其中有一个 floppya
的配置,这里的镜像大小和文件路径是之前我们使用 bximage
工具创建出来的 imboot.img
,这里的路径和大小一定要写正确,否则将无法启动。
floppya: type=1_44, 1_44=/home/imaginemiracle/Miracle/Project/imOS/img/imboot.img, status=inserted, write_protected=0
5. 写一个简单的 Boot 引导程序
新建并打开一个文件 imboot.S
,编写基于 BIOS
的 boot
代码:
org 0x7c00 ; BIOS 会加载引导程序到内存地址 0x7c00 处
BaseOfStack equ 0x7c00 ; 定义一个标识符 BaseOfStack,代表值 0x7c00
Start:
mov ax, cs ; 将代码寄存器 cs 的段基地址设置到 ds、es、ss寄存器
mov ds, ax
mov es, ax
mov ss, ax
mov sp, BaseOfStack
; 清屏
mov ax, 0600h
mov bx, 0700h
mov cx, 0h
mov dx, 0184fh
int 10h
; 设置光标位置
mov ax, 0200h
mov bx, 0000h
mov dx, 0000h
int 10h
; 在屏幕上打印字符串 "The imboot is working!"
mov ax, 1301h
mov bx, 000fh
mov dx, 0000h
mov cx, 22
push ax
mov ax, ds
mov es, ax
pop ax
mov bp, IMBootMessage
int 10h
; 软盘驱动器复位
xor ah, ah
xor dl, dl
int 13h
jmp $
IMBootMessage: dd "The imboot is working!"
; 填充 0 到结尾前 2 个字节
times 510 - ($ - $$) db 0
dw 0xaa55 ; BIOS会检测软盘的第 0 磁头第 1 扇区最后两个字节是否为 0x55aa(代码中写成 0xaa55 是由于x86 使用小端存储),以确定这个扇区是否是引导扇区
这段汇编代码主要使用 BIOS
中断服务程序 int 10h
和 int 13h
完成屏幕操作和驱动器复位的功能。
通过改变保存 int 10h
的主功能编号的 ah
寄存器使用不同功能,int 13h
也同样。
中断服务 | 主功能号 AH 值 | 功能描述 | AL 功能 | BH 功能 | BL 功能 | CH 功能 | CL 功能 | DH 功能 | DL 功能 | ES:BP |
---|---|---|---|---|---|---|---|---|---|---|
INT 10h | 02h | 设置光标位置 | 页码 | - | - | - | - | 光标的列号 | 光标的行号 | - |
INT 10h | 06h | 按指定范围滚动窗口 | 滚动的列数; 为 0 表示清屏,此时其它属性无效 | 设置滚动后空出位置的属性 颜色属性: * bit 0~2:字体颜色(0:黑1:蓝2:绿3:青4:红5:紫6:棕7:白) * bit 3:字体亮度(0:默认1:高亮) * bit 4~6:背景颜色(颜色的数值同上) * bit 7:字体闪烁(0:关闭1:使能) | - | 滚动范围的左上角坐标列号 | 滚动范围的左上角坐标行号 | 滚动范围右下角坐标列号 | 滚动范围右下角坐标行号 | - |
INT 10h | 13h | 显示一行字符串 | 写入模式:00h : 字符串属性由 BL 控制,长度由 CX 控制(单位: Byte),不改变光标位置;01h : 同上,但显示结束更新光标到字符串结尾处;02h : 字符串由其最后的字节控制,CX 控制单位变为 Word ,不改变光标位置;03h : 同 02h ,但更新光标位置到字符串结尾 | 页码 | 字符属性,同 06h | 字符串长度 | 字符串长度 | 光标所在行号 | 光标所在列号 | 要显示字符串的内存地址 |
INT 13h | 00h | 重置磁盘驱动器 | - | - | - | - | - | - | 00h : 第一个软盘驱动器( drive A: );01h : 第二个软盘驱动器( drive B: );… 7fh :第 128 个软盘驱动器;80h : 第一个硬盘驱动器;… ffh :第128个硬盘驱动器 | - |
6. 在 Bochs 运行 Boot 程序
6.1. 下载安装 NASM 编译器
上面我们已经将代码写好了,但还未编译,编译会用到 NASM
编译器,先来安装它。
先安装其它依赖:如果是 Ubuntu
系统则可以直接使用 sudo apt-get install build-essential
即可
# Ubuntu 系统
imaginemiracle:~$ sudo apt-get install build-essential
imaginemiracle:~$ sudo apt-get install curl
# CentOS 系统
[imaginemiracle@imos-ws imboot]$ sudo yum install make automake gcc gcc-c++ kernel-devel
[imaginemiracle@imos-ws imboot]$ sudo yum install -y curl
下载并安装 nasm
编译器。
[imaginemiracle@imos-ws Downloads]$ curl -O -L https://www.nasm.us/pub/nasm/releasebuilds/2.15/nasm-2.15.tar.gz
[imaginemiracle@imos-ws Downloads]$ tar -zxvf nasm-2.15.tar.gz
[imaginemiracle@imos-ws Downloads]$ cd nasm-2.15/
[imaginemiracle@imos-ws nasm-2.15]$ ./autogen.sh
[imaginemiracle@imos-ws nasm-2.15]$ ./configure --prefix=/pgm/nasm
[imaginemiracle@imos-ws nasm-2.15]$ make install
添加 nasm
到环境变量中 vim ~/.bashrc
,添加如下内容
export PATH=$PATH:/pgm/bochs/bin:/pgm/nasm/bin
更新环境变量
source ~/.bashrc
6.2. 编译程序并烧写进软盘
用刚刚安装好的 nasm
工具编译 boot
代码:
[imaginemiracle@imos-ws imboot]$ nasm imboot.S -o imboot.bin
[imaginemiracle@imos-ws imboot]$ ls
imboot.bin imboot.S
编译将会生成一个二进制文件,将这个文件烧写进之前制作好的 imboot.img
软盘中:
[imaginemiracle@imos-ws img]$ dd if=../imboot/imboot.bin of=./imboot.img bs=512 count=1 conv=notrunc
1+0 records in
1+0 records out
512 bytes copied, 0.000104768 s, 4.9 MB/s
打开镜像文件 imboot.img
检验烧写或者代码编写是否正确。
[imaginemiracle@imos-ws img]$ vim imboot.img
因为文件是二进制文件,因此打开后会看到 “乱码” 的现象,没关系,使用 %!xxd
工具即可将其转换为 16
进制查看。
转换后,我们就可以看到如下内容。
我们需要检验的主要是该软盘的第一个扇区最后两个字节是否为 0x55aa
,这是标识着是否作为引导扇区的结尾。一个扇区大小为 512
字节,这里的一行有 16
个字节,因此第 511
和 512
字节应该会出现在第 32
行的末尾。(512 / 16 = 32
)
ok,看起来我们的代码和烧写是没有问题的,可以继续下一步了。
7. 用 Bochs 启动我们的 Boot 代码
使用 bochs
命令并指定配置文件为之前写好的配置文件。
[imaginemiracle@imos-ws bochs-run]$ bochs -f bochsrc
运行后将会有如下输出:
========================================================================
Bochs x86 Emulator 2.7
Built from SVN snapshot on August 1, 2021
Timestamp: Sun Aug 1 10:07:00 CEST 2021
========================================================================
00000000000i[ ] BXSHARE not set. using compile time default '/pgm/bochs/share/bochs'
00000000000i[ ] reading configuration from bochsrc
00000000000i[ ] Ignoring magic break points
------------------------------
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
,正是开始运行我们给的镜像文件,因此这里直接输入回车即可。
这个时候应该会看到一个黑屏的界面,这个时候需要继续在命令行中输入 c
或 continue
来告诉 bochs
运行 boot
程序。
这个时候可以看到代码中的字符串 The imboot is working!
已经被打印了出来,就说明 Boot
程序已经执行了。
#本文完
到此你已经掌握了 BIOS
和 boot
程序的工作流程,以及在虚拟机上的实际模拟。
觉得这篇文章对你有帮助的话,就留下一个赞吧^v^*
请尊重作者,转载还请注明出处!感谢配合~
[作者]: Imagine Miracle
[版权]: 本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
[本文链接]: https://blog.csdn.net/qq_36393978/article/details/126260487