Skip to main content

Command Palette

Search for a command to run...

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

Updated
3 min readView as Markdown

查看本系列文章目录

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

从 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

More from this blog

[4.2] 操作系统学习 (深入保护模式)

接下来我们将讲上节没有讲完的内容, GDT 全局描述符表 我们之前说过了在保护模式下为了安全着想, 引入了 GDT, 内存段(如数据段, 代码段等)不再是简单地用段寄存器加载一下段基址就能用啦,段的信息增加了很多, 需要提前把段定义好才能使用 全局描述符表(GDT)就是为此而生, GDT 其实就是一个用于登记内存段信息的东西, GDT 因为要记录很多的东西, 所以寄存器的装不了的, GDT 通常都储存再内存中 GDT 的结构一般都是这样的: 其中 GDT 的位置不是固定的, 要使用某个寄存器指...

Aug 17, 20215 min read78

[4.1] 操作系统学习 (保护模式)

本节我们将会学习保护模式 保护模式是怎么来的? 我们都知道实模式下存在很多安全问题, 这主要表现在: 操作系统和用户程序的特权级是一样的 (坏处: 用户程序想干嘛就干嘛, 操作系统根本管不了) 用户程序所使用的地址都是会指向真正的物理地址, 用户程序能读取任意内存 (坏处: 用户程序能随便读取和修改内存, 造成系统不稳定) 一次只能运行一个程序 (坏处: 浪费资源) 只有 20 条地址总线, 寻址范围小 (坏处: 只能范围 1MB 内存) 为了解决这个问题工程师发明了 保护模式 其实在保护模...

Aug 12, 20212 min read28

[3.2] 操作系统学习 (完善 MBR,进入 loader)

查看本系列文章目录 下列内容可能有出错的地方, 毕竟只是个人理解, 有问题评论区🥲🥲 本节将会彻底完善 mbr 扇区,进入 loader 硬盘介绍 现在硬盘大多分为 2 类 固态硬盘 机械硬盘 我们主要讲机械硬盘 机械硬盘其实就像唱片机一样, 一个磁头不断的在磁盘上读取数据 一个机械硬盘由许多的磁头和磁盘组成 而每一个磁盘的构造都是一样的 我们的 mbr 扇区就是里面最开始的扇区 这是一个简单的磁盘运行过程图 我们可以用 CHS 和 LBA 的方式来表示每一个扇区 CHS 就是以硬...

Aug 4, 20214 min read86

[3.1] 操作系统学习 (深入了解并完善 Mbr)

查看本系列文章目录 下列内容可能有出错的地方, 毕竟只是个人理解, 有问题评论区🥲🥲 本篇文章将会让你了解一点关于汇编的知识, 还会介绍一下 CPU 实模式, 最后我们会完善 MBR 分区 MBR 是怎么输出 HelloWorld 上篇文章我们让 MBR 输出了 HelloWorld, 接下来我们要了解其中的奥秘 我们先看看SECTION MBR vstart=0x7c00, 看一眼代码我们发现了 3 个关键词 SECTION vstart 0x7c00 先说说 SECTION 这个单...

Jul 31, 20215 min read44

FengZi ‘s Blog

11 posts