操作系统真相还原
1、部署工作环境
1.2 Bochs下载安装
下载
下载地址:https://sourceforge.net/projects/bochs/files/bochs/2.7/
解压:
crescentp@crescentp:~/bochs$ tar zxvf bochs-2.7.tar.gz
编译
./configure --prefix=/os/bochs --enable-debugger --enable-disasm --enable-iodebug --enable-x86-debugger --with-x --with-x11
make
make install
配置bochs
可以在安装目录下查看配置文件的样本文件
cat share/doc/bochs/bochsrc-sample.txt
在 bin目录下编写bochsrc.disk
代码
#############################################
# Configuration file for Bochs
# By CP
#############################################
# 第一步,首先设置Bochs在运行中过程中能够使用的内存,本列为32MB
# 关键字为:megs
megs: 32
# 第二步:设置对应真实机器的BIOS和VGA BIOS
# 对应的两个关键字为: romimage 和 vgaromimage
romimage: file=/os/bochs/share/bochs/BIOS-bochs-latest
vgaromimage: file=/os/bochs/share/bochs/VGABIOS-lgpl-latest
# 第三步,设置Bochs所使用的的磁盘,软盘的关键字为floppy
# 若只有一个软盘,则使用的floppya即可,若有多个,则为floppya,floppyb
# floppya: 1_44=a.img, status=inserted
# 第四步,选择启动盘符
#boot: floppy #默认从软盘启动
boot: disk #改为从硬盘启动,我们的任何代码都将直接写在硬盘上,所以不会再有读写软盘的操作了
# 第五步,设置日志文件的输出
log: bochs.out
# 第六步,开启或关闭某些功能
# 下面是关闭鼠标,并且打开键盘
mouse: enabled=0
# keyboard_mapping: enabled=1,
keyboard:keymap=/os/bochs/share/bochs/keymaps/x11-pc-us.map
# 硬盘设置
ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
# ata0-master: type=disk,path="hd60M.img",mode=flat
# 下面的是增加的bochs对gdb的支持,这样gdb便可以远程连接到此机器的1234端口调试了
gdbstub: enabled=1, port=1234, text_base=0, data_base=0, bss_base=0
运行
bochs
配置启动盘
没有启动盘,那我们就配置启动盘呗
/bin/bximage 是创建启动盘的工具
bin/bximage -hd=60M -q hd60M.img
2、编写MBR
mbr.S
;主引导程序
;---------------------------------------------------------------------
SECTION MBR vstart=0x7c00 ; 表示在本程序编译时,告诉编译器,把我的其实地址编译0x7c00
mov ax,cs ; 这一块是用cs寄存器的值,去初始化其它的寄存器
mov ds,ax ; 由于BIOS是通过 jmp 0:0x7c00 跳转到MBR的,故此时cs为0
mov es,ax
mov ss,ax
mov fs,ax
mov sp,0x7c00 ;初始化栈指针,0x7c00以下是安全的区域,可以用来当栈使用
;清屏利用0x6号功能,上卷全部行,即可清屏
;---------------------------------------------------------------------
;INT 0x10 功能号:0x06 功能描述:上卷屏幕
;---------------------------------------------------------------------
;输入;
;AH 功能号 = 0x06
;AL = 上卷的行数(如果为0,表示全部)
;BH = 上卷行的属性
;(CL,CH) = 窗口左上角的(X,Y)位置
;(DL,DH) = 窗口右下角的(X,Y)位置
;无返回值
mov ax,0x600
mov bx,0x700
mov cx,0 ;左上角:(0,0)
mov dx,0x184f ;右下角:(80,25)
;VGA文本模式中,一行只能容纳80个字符,共25行
;下标从0开始,所以0x18=24,0x4f=79
int 0x10 ;int 0x10
;;;;;;;; 下面这三行代码获取光标位置 ;;;;;;;;;;;;;
; .get_cursor 获取当前光标位置,在光标位置处打印字符
mov ah,3 ;输入:3号子功能是获取光标位置,需要存入ah寄存器
mov bh,0 ;bh寄存器存储的是待获取光标的页号
int 0x10 ;输出,ch=光标开始行,cl=光标结束行
;dh=光标所在行号,dl=光标所在列号
;;;;;;;; 获取光标结束位置 ;;;;;;;;;;;;
;;;;;;; 打印字符串 ;;;;;;;;;;;;
;还是用10h中断,不过这次调用13号子功能打印字符串
mov ax,message
mov bp,ax ;es:bp为串首地址,es此时和cs一致
;开头已经为sreg初始化
;光标位置要用到dx寄存器中的内容,cx中光标位置可忽略
mov cx,5 ;cx为串长度,不包括结束符0的字符个数
mov ax,0x1301 ;子功能号13显示字符及属性,要出入ah寄存器
;al设置写字符方式 ah = 01;显示字符串,光标跟随移动
mov bx,0x2 ;bh存储的是要显示的页号,此处是第0页
;bl是字符属性,属性为黑底绿字(bl = 02h)
int 0x10 ;执行BIOS 0x10中断
;;;;;;;; 打印字符串结束 ;;;;;;;;;;;;;;
jmp $ ;是程序悬停在此处
message db "1 MBR"
times 510-($-$$) db 0 ; $$ 是本section的地址,$是本行的地址,$-$$是本行到本section的偏移量,最后两个字节是确定的,这就把本扇区的剩余量补0
db 0x55,0xaa
编译
nasm -o mbr.bin mbr.S
将mbr.bin转载进入磁盘的第一个扇区
dd if=/os/bochs/mbr.bin of=/os/bochs/hd60M.img bs=512 count=1 conv=notrunc
运行
bin/bochs -f bin/bochsrc.disk
3、完善MBR
我们不适用int10中断来显示MBR,而是通过操控显存的方式
;主引导程序
;
;LOADER_BASE_ADDR equ 0xA00
;LOADER_START_SECTOR equ 0x2
;---------------------------------------------------------------------
SECTION MBR vstart=0x7c00 ; 表示在本程序编译时,告诉编译器,把我的其实地址编译0x7c00
mov ax,cs ; 这一块是用cs寄存器的值,去初始化其它的寄存器
mov ds,ax ; 由于BIOS是通过 jmp 0:0x7c00 跳转到MBR的,故此时cs为0
mov es,ax
mov ss,ax
mov fs,ax
mov sp,0x7c00 ;初始化栈指针,0x7c00以下是安全的区域,可以用来当栈使用
mov ax,0xb800 ;显存文本模式中,其内存地址是0xb8000
mov gs,ax
;清屏
;利用0x6号功能,上卷全部行,即可清屏
;---------------------------------------------------------------------
;INT 0x10 功能号:0x06 功能描述:上卷屏幕
;---------------------------------------------------------------------
;输入;
;AH 功能号 = 0x06
;AL = 上卷的行数(如果为0,表示全部)
;BH = 上卷行的属性
;(CL,CH) = 窗口左上角的(X,Y)位置
;(DL,DH) = 窗口右下角的(X,Y)位置
;无返回值
mov ax,0x600
mov bx,0x700
mov cx,0 ;左上角:(0,0)
mov dx,0x184f ;右下角:(80,25)
;VGA文本模式中,一行只能容纳80个字符,共25行
;下标从0开始,所以0x18=24,0x4f=79
int 0x10 ;int 0x10
;输出背景色绿色,前景色红色,并且跳动的字符串“1 MBR”
mov byte [gs:0x00],'1'
mov byte [gs:0x01],0xA4 ;A表示绿色背景闪烁,4表示前景位红色
mov byte [gs:0x02],' '
mov byte [gs:0x03],0xA4
mov byte [gs:0x04],'M'
mov byte [gs:0x05],0xA4
mov byte [gs:0x06],'B'
mov byte [gs:0x07],0xA4
mov byte [gs:0x08],'R'
mov byte [gs:0x09],0xA4
jmp $ ;是程序悬停在此处
message db "1 MBR"
times 510-($-$$) db 0 ; $$ 是本section的地址,$是本行的地址,$-$$是本行到本section的偏移量,最后两个字节是确定的,这就把本扇区的剩余量补0
db 0x55,0xaa
编译
nasm -o mbr.bin mbr.S
将mbr.bin装载进入磁盘的第一个扇区
dd if=/os/bochs/mbr.bin of=/os/bochs/hd60M.img bs=512 count=1 conv=notrunc
运行
bin/bochs -f bin/bochsrc.disk
可见这是跳动的
接下来我们通过从硬盘中读取加载信息,将内核加载器读入到内存,
mbr.S
;主引导程序
;------------------------------------------------------------------------------
%include "boot.inc" ;让编译器在编译之前,把boot.inc文件包含进来
SECTION MBR vstart=0x7c00
mov ax,cs
mov ds,ax
mov es,ax
mov ss,ax
mov fs,ax
mov sp,0x7c00
mov ax,0xb800
mov gs,ax
;清屏
;利用0x06功能,上卷所有行,则可清屏
;-------------------------------------------------------------------------------
;INT 0x10 功能号:0x06 功能描述:上卷窗口
;-------------------------------------------------------------------------------
;输入;
;AH 功能号:0x06
;AL = 上卷的行数(如果为0,表示全部)
;BH = 上卷行属性
;(CL,CH) = 窗口左上角(X,Y)位置
;(DL,DH) = 窗口右下角的(X,Y)位置
;无返回值
mov ax,0600h
mov bx,0700h
mov cx,0 ;左上角:(0,0)
mov dx,184fh ;右下角:(80,25)
;因为VGA文本模式中,一行只能容纳80个字符,共25行
; 下标从0开始,所有0x18=24,0x4f=79
int 10h ;int 10h
;输出字符串MBR
mov byte [gs:0x00],'1'
mov byte [gs:0x01],0xA4
mov byte [gs:0x02],' '
mov byte [gs:0x03],0xA4
mov byte [gs:0x04],'M'
mov byte [gs:0x05],0xA4 ;A表示绿色背景闪烁,4表示前景颜色为红色
mov byte [gs:0x06],'B'
mov byte [gs:0x07],0xA4
mov byte [gs:0x08],'R'
mov byte [gs:0x09],0xA4
mov eax,LOADER_START_SECTOR ;起始扇区lba地址,0x2
mov bx,LOADER_BASE_ADDR ;写入的地址,0x900
mov cx,1 ;待写入的扇区数
call rd_disk_m_16 ;以下读取程序的起始部分(一个扇区)
jmp LOADER_BASE_ADDR
;-------------------------------------------------------------------------------------
;功能:读取硬盘n个扇区
rd_disk_m_16:
;-------------------------------------------------------------------------------------
;eax=LBA扇区号
;bx=将数据写入的内存地址
;cx=读入的扇区数
mov esi,eax ;备份eax,因为al在out命令中会使用,会影响到eax的低8位
mov di,cx