第二步 完善MBR

文章目录

  • 前言
  • 一、什么是MBR?
  • 二、我们需要什么样的MBR?
  • 三、设计我们的MBR!
    • 1、打印“1 MBR”
    • 2、加载次引导程序——loader
  • 四、实践检验!


查看系列文章点这里: 操作系统真象还原

前言

  在上一篇文章 第一步 从启动BIOS开始 中,我们介绍了BIOS系统,知道了它只负责做一些硬件检测和初始化的工作,然后控制权就到 MBR 手中了,那我们这一节就来介绍一下 MBR 是什么,又有什么作用叭!


一、什么是MBR?

  MBR 也叫做“ 主引导程序 ”,从名字不难看出,它是主要的引导程序。引导的程序就是“ 次引导程序 ”,可以叫做“ 内核加载器 ”,总的来说就是加载内核也就是操作系统的程序。

  也就是 MBR 并不加载操作系统,其原因在于有时候我们希望计算机可以在不同的分区使用不同的操作系统,所以 MBR 的工作就只能是挑选合适的“ 次引导程序 ”。至于BIOS为什么不直接完成挑选过程,原因很简单,因为空间太小不够用,心有余力不足。

二、我们需要什么样的MBR?

  知道了什么是 MBR 后,我们就来来编写属于我们的 MBR 了,首先我们先来看看真正的 MBR 是什么样的,如下所示:

  • 446字节的引导程序及参数;
  • 64字节的分区表;
  • 2字节的魔数,0x55和0xaa;

  这是真正的 MBR ,那我们的 MBR 并不需要和上述那样,因为我们注定只会加载我们自己以后编写的操作系统,因此我们不需要分区表,引导程序要实现的功能也仅仅是把“ 次引导程序 ”从磁盘加载到内存中,并跳转过去就可以了。

  但是为了方便我们看到结果,我们再在屏幕上输出一句话“1 MBR”,表示 MBR 被成功加载运行。

  解下来我们就要开始编写 MBR 了,如果你还不了解如何在屏幕输出内容请看x86 文本模式显示适配器,如果你还不知道如何操控硬盘,请看x86 汇编如何控制硬盘?。

三、设计我们的MBR!

  上一节我们已经讲了我们的 MBR 长什么样了,因此我们的程序的“ 主函数 ”就像下面展示的一样,非常简洁!

	mov eax, LOADER_START_SECTOR   ;待读入扇区的起始地址(0x2)mov bx, LOADER_BASE_ADDR       ;数据从硬盘读入后存放的地址(0x900)mov cx, 4                      ;待读入的扇区数目;当前loader只有一点点大小,不过为了方便,直接设置为4call rd_disk_m_16              ;执行该函数在"16位模式下读硬盘"jmp LOADER_BASE_ADDR           ;跳转到LOADER程序

  可以看到我们将地址设置成了常量,因为以后还有非常多的常量,因此,我在code目录下新建目录include,并新建boot.inc文件,专门用来存储将来会用到的常量。
在这里插入图片描述

; 加载器在硬盘上的位置(LBA)
LOADER_START_SECTOR  equ 0x2; 加载器加载到内存中的位置
LOADER_BASE_ADDR equ 0x900

  本节就一些关键步骤和代码做出解释说明,完整代码见文章末尾。

1、打印“1 MBR”

(1)清屏:

	mov ax, 0x0600   ;AL:上卷的行数(为0表示全部),AH:功能号,0x06表示清屏功能mov bx, 0x0700   ;上卷行属性mov cx, 0x0      ;左上角(0,0)mov dx, 0x184f   ;右下角(80,25),在VGA文本模式中,一行只能容纳80个字符,一共25行int 0x10         ;调用BIOS的视频服务中断

(2)打印:

	;0x1010 0100 -> 前景色(字的颜色)为红色,背景色为绿色,闪烁(字闪烁)mov byte [gs:0x00], '1'mov byte [gs:0x01], 0xA4mov byte [gs:0x02], ' 'mov byte [gs:0x03], 0xA4mov byte [gs:0x04], 'M'mov byte [gs:0x05], 0xA4mov byte [gs:0x06], 'B'mov byte [gs:0x07], 0xA4mov byte [gs:0x08], 'R'mov byte [gs:0x09], 0xA4

2、加载次引导程序——loader

(1)第1步:设置带读入的扇区数

	mov dx, 0x1f2mov al,cl      ;使用cx寄存器存储待读入的扇区数out dx,al

(2)第2步:设置LBA地址

	;LBA地址7~0位写入端口0x1f3mov dx, 0x1f3out dx, al;LBA地址15~8位写入端口0x1f4mov cl, 8shr eax, clmov dx, 0x1f4out dx, al;LBA地址23~16位写入端口0x1f5shr eax, clmov dx, 0x1f5out dx, al;设置deviceshr eax, cland al, 0x0f   ;设置LB地址24~27位or al, 0xe0    ;0xe0 -> 11100000 ,设置7~4位为1110,表示为LBA模式mov dx, 0x1f6out dx, al     ;将配置信息写入端口0x1f6

(3)第3步:发送读命令

	mov dx, 0x1f7mov al, 0x20out dx, al

(4)第4步:检测硬盘状态

.not_ready:mov dx, 0x1f7   ;同一端口,写时表示写入命令,读时表示读入硬盘状态in al, dxand al, 0x88    ;第3位为1表示硬盘控制器已经准备好数据传输;第7位为1表示硬盘忙cmp al, 0x08jnz .not_ready  ;若为准备好,则跳回not_ready处继续等待

(5)第5步:从硬盘读数据

    mov ax, di   ;di为待读入的扇区数mov dx, 256  ;一个扇区512字节,每次读入一字,即两字节,共要读256次mul dx       ;乘扇区数mov cx, axmov dx, 0x1f0.go_on_read:in ax, dxmov [bx], ax      ;存入内存add bx, 2         ;指向下一个地址loop .go_on_readret               ;返回

四、实践检验!

  现在我们来检验一下,我们的 MBR 是否编写正确,等一下,我们貌似还没有loader程序,虽然我们还不知道loader要干嘛,不过不妨碍我们验证 MBR,我们直接随便在code目录下新建一个假的loader,打印几个字符“2 LOADER”,宣告一下现在是我LOADER的天下啦!

%include "boot.inc"
; 加载器加载到内存中的位置
SECTION LOADER vstart=LOADER_BASE_ADDRmov byte [gs:0x50], '2'mov byte [gs:0x51], 0xA4mov byte [gs:0x52], ' 'mov byte [gs:0x53], 0xA4mov byte [gs:0x54], 'L'mov byte [gs:0x55], 0xA4mov byte [gs:0x56], 'O'mov byte [gs:0x57], 0xA4mov byte [gs:0x58], 'A'mov byte [gs:0x59], 0xA4mov byte [gs:0x5a], 'D'mov byte [gs:0x5b], 0xA4mov byte [gs:0x5c], 'E'mov byte [gs:0x5d], 0xA4mov byte [gs:0x5e], 'R'mov byte [gs:0x5f], 0xA4jmp $

  下面我们来看看完整 MBR 长什么样。

%include "boot.inc"
SECTION MBR vstart=0x7c00;初始化寄存器mov ax, csmov ds, axmov es, axmov ss, axmov fs, axmov sp, 0x7c00;图形卡文本模式的起始地址mov ax, 0xb800mov gs, ax;清屏mov ax, 0x0600   ;AL:上卷的行数(为0表示全部),AH:功能号,0x06表示清屏功能mov bx, 0x0700   ;上卷行属性mov cx, 0x0      ;左上角(0,0)mov dx, 0x184f   ;右下角(80,25),在VGA文本模式中,一行只能容纳80个字符,一共25行int 0x10         ;调用BIOS的视频服务中断;在屏幕上显示字符串"1 MBR";0x1010 0100 -> 前景色(字的颜色)为红色,背景色为绿色,闪烁(字闪烁)mov byte [gs:0x00], '1'mov byte [gs:0x01], 0xA4mov byte [gs:0x02], ' 'mov byte [gs:0x03], 0xA4mov byte [gs:0x04], 'M'mov byte [gs:0x05], 0xA4mov byte [gs:0x06], 'B'mov byte [gs:0x07], 0xA4mov byte [gs:0x08], 'R'mov byte [gs:0x09], 0xA4;接下来用eax,bx,cx三个寄存器传递参数,故先将值存进寄存器中mov eax, LOADER_START_SECTOR   ;待读入扇区的起始地址(0x2)mov bx, LOADER_BASE_ADDR       ;数据从硬盘读入后存放的地址(0x900)mov cx, 4                      ;待读入的扇区数目call rd_disk_m_16              ;执行该函数在"16位模式下读硬盘"jmp LOADER_BASE_ADDR           ;跳转到LOADER程序; ============================================================
; 功能:读取硬盘n(由cx寄存器决定读几个扇区)个扇区
; ============================================================
rd_disk_m_16:;备份eax,cxmov esi, eaxmov di, cx;第一步:设置要读取的扇区数mov dx, 0x1f2 mov al,clout dx,almov eax, esi;第二步,将LBA地址存入0x1f3 ~ 0x1f6;LBA地址7~0位写入端口0x1f3mov dx, 0x1f3out dx, al;LBA地址15~8位写入端口0x1f4mov cl, 8shr eax, clmov dx, 0x1f4out dx, al;LBA地址23~16位写入端口0x1f5shr eax, clmov dx, 0x1f5out dx, al;设置deviceshr eax, cland al, 0x0f   ;设置LB地址24~27位or al, 0xe0    ;0xe0 -> 11100000 ,设置7~4位为1110,表示为LBA模式mov dx, 0x1f6out dx, al     ;将配置信息写入端口0x1f6;第三步:向0x1f7端口写入读命令(0x20)mov dx, 0x1f7mov al, 0x20out dx, al;第四步:检测硬盘状态
.not_ready:;同一端口,写时表示写入命令,读时表示读入硬盘状态nopin al, dxand al, 0x88    ;第3位为1表示硬盘控制器已经准备好数据传输;第7位为1表示硬盘忙cmp al, 0x08jnz .not_ready  ;若为准备好,则跳回not_ready处继续等待;第五步:从0x1f0端口读入数据mov ax, di   ;di为待读入的扇区数mov dx, 256  ;一个扇区512字节,每次读入一字,即两字节,共要读256次mul dxmov cx, axmov dx, 0x1f0.go_on_read:in ax, dxmov [bx], axadd bx, 2loop .go_on_readret;填充空白符,保证整段程序大小为512字节
times 510-($-$$) db 0;定义MBR中最后两个字节的魔数,表示这个扇区包含可加载的程序
db 0x55, 0xaa

  接下来就是编译和传输,如下:

  	nasm -I ./include/ -o mbr.bin mbr.Sdd if=./mbr.bin of=../bochs/hd60M.img bs=512 count=1 conv=notruncnasm -I ./include/ -o loader.bin loader.Sdd if=./loader.bin of=../bochs/hd60M.img bs=512 count=4 seek=2 conv=notrunc

  注意,传输loader的时候,跳过两个扇区,避免覆盖了我们的 MBR

在这里插入图片描述

  然后就可以运行我们的bochs啦!

在这里插入图片描述

  可以看到我们的 MBR 已经成功完成任务啦!


  持续更新中~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/12646.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

社交电商的三大模式,新零售招商模式策划

链动21奖励模式,七人拼团模式拆解,分享购模式解析 坐标:厦门,我是易创客肖琳 深耕社交新零售行业10年,主要提供新零售系统工具及顶层商业模式设计、全案策划运营陪跑等。 随着数字时代的到来,“互联网”概…

PyCharm2023 社区版安装 +中文语言包+配置教程+Python环境搭建

一、Python 安装 我们在安装Pycharm之前,首先要先安装Python环境也就是安装Python解释器 因为PyCharm是一个用于编写和调试Python代码的开发工具,而Python解释器是用于解释执行Python代码PyCharm需要依赖Python解释器来执行Python代码,因此…

R语言贝叶斯方法在生态环境领域中的应用

贝叶斯统计已经被广泛应用到物理学、生态学、心理学、计算机、哲学等各个学术领域,其火爆程度已经跨越了学术圈,如促使其自成统计江湖一派的贝叶斯定理在热播美剧《The Big Bang Theory》中都要秀一把。贝叶斯统计学即贝叶斯学派是一门基本思想与传统基于…

R语言基础--文件读写

From生物技能树(R第五节) 文章目录 一、文件读写1.注意用project管理工作目录2、文件读取1、读取.txt文件2、读取.csv文件注意:数据框不允许重复的行名 3.数据框的导出4.读取文件的其他方式(用于读取/导出文件的R包)--经验1.base2.readr3.dat…

图搜索算法-最小生成树问题-克鲁斯卡尔算法(kruskal)

相关文章: 数据结构–图的概念 图搜索算法 - 深度优先搜索法(DFS) 图搜索算法 - 广度优先搜索法(BFS) 图搜索算法 - 拓扑排序 图搜索算法-最短路径算法-戴克斯特拉算法 图搜索算法-最短路径算法-贝尔曼-福特算法 最小生…

【Redis】数据类型

Redis数据类型(5 3 1) 五种基本数据类型 String字符串 特点 二进制安全,可以包含任何数据,如数字,字符串,jpg图片或者序列化的对象 应用场景 缓存: redis作为缓存层,mysql做持…

【ORACLE战报】2024.4月最新OCP考试喜报.

课程介绍 DBA数据库管理必备认证:ORACLE OCP 19C 教材下载 ORACLE OCP 19C 官方电子教材 ORACLE OCP 12C官方电子教材 题库下载 ORACLE 19C题库 (083384题、082362题)-2024答案修正版.rar 所有的收获都是默默耕耘的成果 2024.4月【最新考试成…

Chromium 调试指南2024 Windows11篇-条件断点、函数断点(十一)

1. 前言 在调试过程中,步进代码和条件断点/函数断点是非常有用的工具和技术,它们可以帮助开发者更加精确地定位和解决问题。本文将介绍步进代码的常用工具以及条件断点/函数断点的设置方法,帮助开发者更加高效地进行调试工作。 2. 步进代码…

ControlNet原理解析

前排提示照片已经获得小姐姐许可。 光知道ControlNet好用,不想知道它背后的原理么?今天就看一看这篇论文,带大家了解一下ControlNet是如何炼成的。 ControlNet是干嘛的 我们知道现在文本到图像生成很火爆,你只需要输入文字就可以…

内存函数:memcpy(拷贝),memmove(拷贝),memcmp(比较),memset(设置)

内存函数 一.memcpy(内存拷贝1)1.函数使用2.模拟实现 二.memmove(内存拷贝2)1.函数使用2.模拟实现 三.memcmp(内存比较)1.函数使用2.模拟实现 四.memset(内存设置)1.函数使用2.模拟实…

【Linux】用户组、用户、文件权限(ugo权限),权限掩码,chmod,chown,suid,sgid,sticky,su,sudo

用户组 注意:普通用户只能查看有哪些组,不能创建/修改/删除,会提示:用户名 is not in the sudoers file.This incident will be reported. groupadd 用户组名新建用户组cat /etc/group查看有哪些组(普通用户可以操作…

Windows下配置TortoiseGit 访问Ubuntu虚拟机下Samba共享目录

前言: 本文记录学习使用 Git 版本管理工具的学习笔记,通过阅读参考链接中的博文和实际操作,快速的上手使用 Git 工具。 本文参考了引用链接博文里的内容。 引用: 【TortoiseGit】TortoiseGit安装和配置详细说明-CSDN博客 Git版本管理可视…

Java——对象的打印

当我们运行如下代码: public class Person {String name;String gender;int age;public Person(String name,String gender,int age){this.name name;this.gender gender;this.age age;}public static void main(String[] args){Person person new Person(&quo…

QT客户端开发的注意事项

QT客户端开发是一个涉及图形用户界面(GUI)设计、网络编程、数据库交互等多个方面的复杂过程。以下是在进行QT客户端开发时应注意的一些关键事项,通过关注这些事项,可以提高QT客户端应用的质量和开发效率。北京木奇移动技术有限公司…

Eclipse下载安装教程(包含JDK安装)【保姆级教学】【2024.4已更新】

目录 文章最后附下载链接 第一步:下载Eclipse,并安装 第二步:下载JDK,并安装 第三步:Java运行环境配置 安装Eclipse必须同时安装JDK !!! 文章最后附下载链接 第一步&#xf…

微软推出的Microsoft Fabric 到底是什么?

近期,总有客户问小编,微软推出的 Microsoft Fabric 是什么?这个产品有什么特别之处呢?希望下面这篇文章能为大家解开一些疑惑。 微软Fabric是2023年5月推出的一个数据分析平台,它将关键数据管理和分析工作负载整合到一…

【设计模式】JAVA Design Patterns——Acyclic Visitor(非循环访问者模式)

🔍目的 允许将新功能添加到现有的类层次结构中,而不会影响这些层次结构,也不会有四人帮访客模式中那样循环依赖的问题。 🔍解释 真实世界例子 我们有一个调制解调器类的层次结构。 需要使用基于过滤条件的外部算法(是…

奖金+1 万,OpenTenBase 开源核心贡献挑战赛,KB 专家助力其跑在 K8s 上

OpenTenBase 是由开放原子开源基金会孵化及运营的开源项目,是一款开放中立的企业级分布式 HTAP 开源数据库。OpenTenBase 具备高扩展性、商业数据库语法兼容、分布式 HTAP 引擎、多级容灾和多维度资源隔离等能力,已成功应用于金融、医疗、航天等行业的核…

FlyFlow:支持驳回后自动跨节点跳回

本周更新 新增:审批节点驳回(拒绝配置的驳回)支持自动跳回当前节点新增:修改数据节点新增:删除数据节点新增:子流程支持配置自动跳过发起人节点优化:两个项目合并一个单体项目优化:…

【C语言】水仙花数

问题 水仙花数(Narcissistic number)也被称为超完全数字不变数(pluperfect digital invariant, PPDI)、自恋数、自幂数或阿姆斯壮数数(Armstrong number)。 它是指一个n位数(n≥3)…