[2] 操作系统学习 (开始动手实践, 编写一个简单的mbr)

·

3 min read

查看本系列文章目录

下列内容可能有出错的地方, 毕竟只是个人理解, 有问题评论区🥲🥲

从 BIOS 进入 MBR

实模式下的 1MB 内存布局

在开始讲之前, 我们要先了解一下 实模式下的 1MB 内存布局

1.png

我们可以看到 0x7c00~0x7dff 就是我们的 MBR 要加载的位置

对了再补充一下, 我们现在正常的内存条都有 4GB 了, 但是为什么我们只能使用 3.8GB 呢? 这是因为我们有 0.2GB 被用来作为外设的内存映射了

BIOS -> MBR

开机时 BIOS 先被加载, 然后它开始自检, 当一切都 ok 时, BIOS 就开始在 0:0:1(CHS 方法,即柱面(Cylinder):磁头(Header):扇区(Sector)查找有没有 MBR 分区(也就是查看这个扇区的结束的 2 个字节是不是 0x55,0xaa)

如果有就把 MBR 扇区的内容加载到 0x7c00~0x7dff, 并跳转过去.

怎么跳转呢? 就是 JMP 0:0x7c00

让 MBR HelloWorld

因为我们的 MBR 分区是 512 字节, 使用我们的程序也要 512 字节, 这要怎么做呢

在这里我们要开始接触一下汇编了

NASM中有 2 个符号$和$$来表示当前行和本 section 的地址,起到了标号的作用,它 是 NASM 提供的,并不是 CPU 原生支持的

好吧, 我们先看看代码

; 本代码来着<<操作系统真象还原>>
; 文件名 mbr.S
;主引导程序 
;------------------------------------------------------------
SECTION MBR vstart=0x7c00         
   mov ax,cs      
   mov ds,ax
   mov es,ax
   mov ss,ax
   mov fs,ax
   mov sp,0x7c00

; 清屏 利用0x06号功能,上卷全部行,则可清屏。
; -----------------------------------------------------------
;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, 10        ; 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 "HelloWorld"
   times 510-($-$$) db 0
   db 0x55,0xaa

我们可以看到最后第 2 行times 510-($-$$) db 0这里的$-$$就是整个程序的占用字节, 而 510 就是 512-2(0xaa55), 整句代码的意思就是把整个二进制文件用0补充到 512 字节

多说无益, 我们编译看看

先确保你的电脑已安装 NASM 编译器, 在终端输入nasm -v

提示向这样就是有安装 NASM, 如果没有提示请百度[怎么安装 nasm]

fengzi@fengzi-ubuntu:~$ nasm -v
NASM version 2.14.02

好的, 我们开始编译

在终端输入, 如果没有任何提示那就证明你编译成功了

nasm mbr.S

使用 ls 命令查看

fengzi@fengzi-ubuntu:~$ ls
mbr  mbr.S

我们可以看到一个叫 mbr 的二进制文件

所以 16 进制查看一下

2.png

调试

我们的代码已经编译好了, 我们就可以开始调试了.

相信大家应该bochs 应该已经安装好了

我们现在要所以 bochs 自带的一个工具bximage生成一个虚拟硬盘文件

fengzi@fengzi-ubuntu:~/WorkSpace/Study_OS/code/c2/a/boot$ bximage
========================================================================
                                bximage
  Disk Image Creation / Conversion / Resize and Commit Tool for Bochs
         $Id: bximage.cc 13481 2018-03-30 21:04:04Z 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] hd

What kind of image should I create?
Please type flat, sparse, growing, vpc or vmware4. [flat] flat

Choose the size of hard disk sectors.
Please type 512, 1024 or 4096. [512] 512

Enter the hard disk size in megabytes, between 10 and 8257535
[10] 10

What should be the name of the image?
[c.img] c.img

Creating hard disk image 'c.img' with CHS=20/16/63 (sector size = 512)

The following line should appear in your bochsrc:
  ata0-master: type=disk, path="c.img", mode=flat

像我这样输入我们就可以得到一个空白的硬盘文件, 因为是空白的, 所以也打不开

我们使用 dd 命令(正常 Linux 都会自带)把 mbr 复制到 c.img 里面

# if=你的 mbr 路径, of=你的 c.img 路径
fengzi@fengzi-ubuntu:~/WorkSpace/Study_OS/code/c2/a/boot$ dd if=mbr of=c.img bs=512 count=1 conv=notrunc
1+0 records in
1+0 records out
512 bytes copied, 0.000520566 s, 984 kB/s

好了, 现在这个 c.img 的 0:0:1(CHS)已经是我们的 mbr 了

现在我们要打开 bochs 进行调试

在打开 bochs 之前我们要编写一个配置文件

megs:32
# set memory
romimage: file=你的bochs根目录/share/bochs/BIOS-bochs-latest
# set bios
vgaromimage: file=你的bochs根目录/share/bochs/VGABIOS-lgpl-latest
# set vga bios
boot:disk # disk/floppy boot first
log:~/bochs.log
# log file path
mouse:enabled=0
# close mouse
#keyboard:enabled=1
# open keyboard(us)
ata0:enabled=1 # ,ioaddr1=0xr10,ioaddr2=0x3f0,irq=14
ata0-master: type=disk, mode=flat,path="你的c.img路径"#,cylinkers=121, head=16,spt=63
# set disk
# gdbstub:enabled=1,port=1234,text_base=0,data_base=0,bss_base=0 
# set gdb(can use gdb debug 1234 port

把他保存成bochsrc, 然后放在你的 bochs 目录的 bin 文件夹里

然后在终端输入

bochs -f 你的bochsrc绝对路径

因为过程比较难表达, 所以使用视频演示

好的, 这就是本文章所以内容, 下一篇文章开始深入 MBR 和完善 MBR 的功能


下一个: 深入了解并完善 MBR