第二步 完善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只有一点点大小,不过为了方便,直接设置为4
    call 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], 0xA4
    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

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

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

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

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

	;LBA地址7~0位写入端口0x1f3
    mov dx, 0x1f3
    out dx, al

    ;LBA地址15~8位写入端口0x1f4
    mov cl, 8
    shr eax, cl
    mov dx, 0x1f4
    out dx, al

    ;LBA地址23~16位写入端口0x1f5
    shr eax, cl
    mov dx, 0x1f5
    out dx, al

    ;设置device
    shr eax, cl
    and al, 0x0f   ;设置LB地址24~27位
    or al, 0xe0    ;0xe0 -> 11100000 ,设置7~4位为1110,表示为LBA模式
    mov dx, 0x1f6
    out dx, al     ;将配置信息写入端口0x1f6

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

	mov dx, 0x1f7
    mov al, 0x20
    out dx, al

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

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

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

    mov ax, di   ;di为待读入的扇区数
    mov dx, 256  ;一个扇区512字节,每次读入一字,即两字节,共要读256次
    mul dx       ;乘扇区数
    mov cx, ax
    mov dx, 0x1f0

.go_on_read:
    in ax, dx
    mov [bx], ax      ;存入内存
    add bx, 2         ;指向下一个地址
    loop .go_on_read
    ret               ;返回

四、实践检验!

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

%include "boot.inc"
; 加载器加载到内存中的位置
SECTION LOADER vstart=LOADER_BASE_ADDR

	mov byte [gs:0x50], '2'
    mov byte [gs:0x51], 0xA4
    mov byte [gs:0x52], ' '
    mov byte [gs:0x53], 0xA4
    mov byte [gs:0x54], 'L'
    mov byte [gs:0x55], 0xA4
    mov byte [gs:0x56], 'O'
    mov byte [gs:0x57], 0xA4
    mov byte [gs:0x58], 'A'
    mov byte [gs:0x59], 0xA4
    mov byte [gs:0x5a], 'D'
    mov byte [gs:0x5b], 0xA4
    mov byte [gs:0x5c], 'E'
    mov byte [gs:0x5d], 0xA4
    mov byte [gs:0x5e], 'R'
    mov byte [gs:0x5f], 0xA4
    
	jmp $

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

%include "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

    ;清屏
    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], 0xA4
    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

    ;接下来用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,cx
    mov esi, eax
    mov di, cx

;第一步:设置要读取的扇区数
    mov dx, 0x1f2 
    mov al,cl
    out dx,al

	mov eax, esi

;第二步,将LBA地址存入0x1f3 ~ 0x1f6
    ;LBA地址7~0位写入端口0x1f3
    mov dx, 0x1f3
    out dx, al

    ;LBA地址15~8位写入端口0x1f4
    mov cl, 8
    shr eax, cl
    mov dx, 0x1f4
    out dx, al

    ;LBA地址23~16位写入端口0x1f5
    shr eax, cl
    mov dx, 0x1f5
    out dx, al

    ;设置device
    shr eax, cl
    and al, 0x0f   ;设置LB地址24~27位
    or al, 0xe0    ;0xe0 -> 11100000 ,设置7~4位为1110,表示为LBA模式
    mov dx, 0x1f6
    out dx, al     ;将配置信息写入端口0x1f6

;第三步:向0x1f7端口写入读命令(0x20)
    mov dx, 0x1f7
    mov al, 0x20
    out dx, al

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

;第五步:从0x1f0端口读入数据
    mov ax, di   ;di为待读入的扇区数
    mov dx, 256  ;一个扇区512字节,每次读入一字,即两字节,共要读256次
    mul dx
    mov cx, ax
    mov dx, 0x1f0

.go_on_read:
    in ax, dx
    mov [bx], ax
    add bx, 2
    loop .go_on_read
    ret

;填充空白符,保证整段程序大小为512字节
times 510-($-$$) db 0

;定义MBR中最后两个字节的魔数,表示这个扇区包含可加载的程序
db 0x55, 0xaa

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

  	nasm -I ./include/ -o mbr.bin mbr.S
  	dd if=./mbr.bin of=../bochs/hd60M.img bs=512 count=1 conv=notrunc

	nasm -I ./include/ -o loader.bin loader.S
	dd if=./loader.bin of=../bochs/hd60M.img bs=512 count=4 seek=2 conv=notrunc

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

在这里插入图片描述

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

在这里插入图片描述

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


  持续更新中~~

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

保障数据安全:数据防泄漏加密软件功能对比

在数字时代,数据安全成为企业必须重视的关键问题。随着信息技术的飞速发展,数据的传输、存储和处理变得愈发便捷,但这也为数据泄露带来了更大的风险。为了应对这一挑战,数据防泄漏加密软件应运而生,成为保障数据安全的…

解决 : ERROR: Rosdep experienced an error: The read operation timed out

问题描述 安装过程中的 rosdep update 报错超时问题,需要访问github进行更新,由于国内网络受限,不能正常访问github,从而导致 rosdep update超时。 解决方法 修改rosdep的python源文件,通过代理地址 https://ghprox…

华为认证大数据是什么?华为认证大数据有用吗?

华为大数据是用来搜集整理大数据,提供解决方案的数据中心。华为大数据解决方案是华为公司推出的一种综合性云解决方案,主要针对广告营销、电商、车联网等大数据应用场景的云计算大数据方案,帮助企业用户构建大数据平台,解决企业的…

【源码】购物返利源码每日分红 服务器打包完整版淘宝/京东/亚马逊等刷单平台源码

购物返利源码每日分红 服务器打包完整版淘宝/京东/亚马逊等刷单平台源码 好友分享的购物返利系统带分红,功能很强大的,类似矿机那种源码!请勿违法用途!源码和数据库都不缺。简单看了下搭建还是非常简单的! 东西如下图&…

数据结构与算法学习笔记九---循环队列的表示和实现(C++)

目录 前言 1.为什么要使用循环队列 2.队列的顺序存储方式的实现 1.定义 2.队列初始化 3.销毁 4.清空队列 5.队列是否为空 6.队列长度 7.队头 8.入队 9.出队 10.遍历队列 11.完整代码 3.参考资料 前言 这篇文章介绍循环队列的表示和用法。 1.为什么要使用循环队…

短视频赛道有哪些:成都鼎茂宏升文化传媒公司

短视频赛道有哪些:探索多元化的内容领域 随着科技的飞速发展和人们生活节奏的加快,短视频已成为现代人生活中不可或缺的一部分。它以其简短、直观、易于分享的特点,迅速占领了各个年龄层和社会群体的心智。然而,短视频的赛道并非…

vue2基础语法03——过滤器filter

vue2基础语法03——过滤器filter 1. 前言1.1 需求1.2 不用过滤器实现1.2.1 插值语法、计算属性、方法实现1.2.2 更多关于计算属性 和 方法 2. 使用过滤器实现2.1 说明2.2 例子12.3 例子2——优化2.3.1 默认字母不分割2.3.2 默认字母以分割 2.4 过滤器使用地方 3. 全局过滤器4. …

C++智能指针之唯一指针(std::unique_ptr)

1 概述 从C11开始C语言越来向现代化语言转变。尤其是智能指针的引入,代码中不会直接使用new/delete了。C11智能指针有三种分别是:shared_ptr,weak_ptr 和unique_ptr 。 2 唯一指针(unique_ptr) unique_ptr是C11引入的,用来管理指…

上位机图像处理和嵌入式模块部署(树莓派4b安装dockerros1、ros2)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 前面我们讨论过树莓派4b安装ros的问题,当时的解决方案就是利用docker来安装ros。我们都知道,每一个ros版本都是和特定的ubu…

mysql权限体系

提示:根据课程视频总结知识点------2024.05.15 文章目录 权限处理逻辑1、 能不能连接2、能不能执行操作 权限授予与回收1、创建用户2、授予权限3、查看权限4、回收权限5、 权限级别 账户安全管理1、用户权限设定原则2、历史文件泄密 用户权限设定原则1. 只读用户--数…

C++|树形关联式容器(set、map、multiset、multimap)介绍使用

目录 一、关联式容器介绍 1.1概念 1.2键值对 1.3树形结构的关联式容器 1.3.1pair模板介绍 1.3.2make_pair的介绍 二、set的介绍和使用 2.1set介绍 2.2set使用 2.2.1构造 2.2.2容量 2.2.3修改 三、map的介绍和使用 3.1map介绍 3.2map使用 3.2.1构造 3.2.2容量 …

VC++6.0 Sqlite3调用例子

1,为什么要使用Sqlite3? SQLite 是一个软件库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。SQLite 是在世界上最广泛部署的 SQL 数据库引擎。SQLite 源代码不受版权限制。 2,为什么使用SQLite version 3.8.4.3 2014-04-03 16:53:12的版本…

邮件发送API的功能有哪些?API的调用限制?

邮件发送API的响应速度如何?如何选择API发送邮件? 邮件发送API提供了高效、灵活且可靠的邮件发送功能,使得邮件营销、用户通知、系统告警等场景变得轻松自如。那么,邮件发送API具体都有哪些功能呢?让AokSend来探索吧&…

Spark SQL ---结构化数据文件处理

DataFrame概述 DataFrame的创建 创建DataFrame的两种基本方式: •已存在的RDD调用toDF()方法转换得到DataFrame。 •通过Spark读取数据源直接创建DataFrame。 若使用SparkSession方式创建DataFrame,可以使用spark.read从不同类型的文件中加载数据创建…

【美团面试2024/05/14】前端面试题滑动窗口

一、题目描述 设有一字符串序列 s&#xff0c;确定该序列中最长的无重复字母的子序列&#xff0c;并返回其长度。 备注 0 < s.length < 5 * 104 s 由英文字母、数字、符号和空格组成 示例1 输入 s "abcabcbb" 输出 3 二、原题链接 这道题在LeetCode上的原题链…

运维别卷系列 - 云原生监控平台 之 06.prometheus pushgateway 实践

文章目录 [toc]Pushgateway 简介Pushgateway 部署创建 svc创建 deployment Pushgateway 测试删除 Pushgateway 上对应 lable 的数据 Pushgateway 简介 WHEN TO USE THE PUSHGATEWAY Pushgateway 是一种中介服务&#xff0c;允许您从无法抓取的作业中推送指标。 The Pushgateway…

Python NumPy数组的创建方法

Numpy是Python中科学计算的基础包&#xff0c;其核心对象就是ndarray&#xff08;n维数组&#xff09;。利用数组可以快速执行逻辑&#xff0c;形状操作&#xff0c;统计和傅里叶变换等运算&#xff0c;其效率比Python原生的数组效率更高。因此使用Numpy的第一件事就是创建Nump…

构建第一个ArkTS应用之@LazyForEach:数据懒加载

LazyForEach从提供的数据源中按需迭代数据&#xff0c;并在每次迭代过程中创建相应的组件。当在滚动容器中使用了LazyForEach&#xff0c;框架会根据滚动容器可视区域按需创建组件&#xff0c;当组件滑出可视区域外时&#xff0c;框架会进行组件销毁回收以降低内存占用。 接口…

线性/非线性最小二乘 与 牛顿/高斯牛顿/LM 原理及算法

最小二乘分为线性最小二乘和非线性最小二乘 最小二乘目标函数都是min ||f(x)||2 若f(x) ax b&#xff0c;就是线性最小二乘&#xff1b;若f(x) ax2 b / ax2 bx 之类的&#xff0c;就是非线性最小二乘&#xff1b; 1. 求解线性最小二乘 【参考】 2. 求解非线性最小二乘…

玩转大模型 企业AI着陆新正解 神州问学AI原生赋能平台正式发布

在人工智能技术日新月异的今天&#xff0c;神州数码凭借深厚的行业洞察和技术积累&#xff0c;揭开了AI原生赋能平台——神州问学的神秘面纱。作为企业AI着陆的加速引擎&#xff0c;神州问学致力于通过AI原生场景赋能&#xff0c;为企业开辟一条通往智能未来的坦途。 神州问学—…