【操作系统】调用硬盘并且实现MBR与Loader的过渡——实战篇

一.概述

        有了上一篇文章:【操作系统】调用硬盘并且实现MBR与Loader的过渡——原理篇的理论支持,我们就可以开始代码实操了,接下来我们将优化MBR程序,使其从扇区中读取出loader加载器,并将其存放到内存处,将权限交付给loader加载器。

二.MBR代码优化

        在开始之前我们还需要注意一些细节问题:

  1. 由于MBR程序已经占据了0扇区,所以loader加载器只能放在其他位置,本文就将加载器放在2扇区,如果你想放其他地方也可以,只要保证不被覆盖就行。
  2. 读取出来的加载器应该放在内存的什么位置?答案可以参考之前写过的一篇文章:【操作系统】BIOS开机自检,在内存布局中我们得知了“可用区域”0x500~0x7BFF和0X7E00~0X9FBFF,所以我们只要把加载器放在这两个区间就可以,本文就将加载器放在内存的0x900的位置处。

        万事俱备,我们就可以开始编写代码了:

 1 SECTION MBR vstart=0x7c002         mov ax,cs3         mov ds,ax4         mov es,ax5         mov ss,ax6         mov fs,ax7         mov sp,0x7c008 9         mov ax,0xb80010         mov gs,ax11 12         mov ax,0x60013         mov bx,0x70014         mov cx,015         mov dx,0x184f16 17         int 0x1018 19         mov byte [gs:0x00],'1'20         mov byte [gs:0x01],0xA421 22         mov byte [gs:0x02],' '23         mov byte [gs:0x03],0xA424 25         mov byte [gs:0x04],'M'26         mov byte [gs:0x05],0xA427 28         mov byte [gs:0x06],'B'29         mov byte [gs:0x07],0xA430 31         mov byte [gs:0x08],'R'32         mov byte [gs:0x09],0xA433 34         mov eax,LOADER_START_SECTOR35         mov bx,LOADER_BASE_ADDR36         mov cx,137         call rd_disk_m_1638         jmp LOADER_BASE_ADDR39 40 rd_disk_m_16:41         mov esi,eax42         mov di,cx43 44         mov dx,0x1f245         mov al,cl46         out dx,al47 48         mov eax,esi49 50         mov dx,0x1f351         out dx,al52 53         mov cl,854         shr eax,cl55         mov dx,0x1f456         out dx,al57 58         shr eax,cl59         mov dx,0x1f560         out dx,al61 62         shr eax,cl63         and al,0x0f64         or al,0xe065         mov dx,0x1f666         out dx,al67 68         mov dx,0x1f769         mov al,0x2070         out dx,al71 72 .not_ready:73         nop74         in al,dx75         and al,0x8876         cmp al,0x0877         jnz .not_ready78 79         mov ax,di80         mov dx,25681         mul dx82         mov cx,ax83 84         mov dx,0x1f085 86 .go_on_read:87         in ax,dx88         mov [bx],ax89         add bx,290         loop .go_on_read91         ret92 93         times 510-($-$$) db 094         db 0x55,0xaa

三.MBR代码解析

        在第一行的“%include”是我们的配置文件,我们可以将加载器的配置信息填写在里面,目前配置信息就只有两个:

LOADER_BASE_ADDR equ 0x900  //定义loader在内存的位置

LOADER_START_SECTOR equ 0x2  //定义loader在硬盘上的LBA地址

        接下来的第2行~第32行是上一篇文章(【操作系统】优化MBR程序:让MBR调用显存吧)的原始代码,就不在此赘述了。第34行~第35行使用了上述配置文件的信息,是第40行函数rd_disk_m_16的传参,这个函数需要三个参数,用eax\bx\cx三个寄存器来传递参数。

        寄存器eax中保存了待读取的扇区起始地址,根据第四节的要求,加载器放在了2扇区的位置。寄存器cx中保存了读取扇区的数量,此处要读入1个扇区。寄存器bx保存从硬盘中读取出来的数据放在内存的什么位置,同样按照第四节的要求,将其放在0x900的位置。紧接着开始调用函数rd_disk_m_16,该函数的功能为读取硬盘的指定扇区数据。

        首先我们将eax和cx的值备份在esi中,因为后面al寄存器需要用到,所以为了避免数据覆盖进行备份操作。

        按照上一篇文章第三节的调用步骤,我们先来选择通道,往该通道的sector count寄存器中写入代操作的扇区数。根据之前写过的一篇文章:【操作系统】Bochs安装和配置,我们的模拟硬件的配置信息为:

        ata0是Primary通道,所以sector count寄存器是端口0x1F2来调用。Out指令用于往端口写入数据,dx保存端口信息,al保存cx的信息也就是待读取的扇区数。

        使用完al之后,我们回复一下eax的值,让其重新保存待读取的扇区起始地址。

         本段主要实现上一篇文章第三节的第二和第三个步骤,将LBA地址分别写入到三个LBA寄存器中,端口名0x1f3~0x1f5的作用在第一节已经给出,不在赘述。Shr指令为右移指令,作用是将一个寄存器或内存单元中的数据向右移指定位数,并将溢出标志 CF 作为进位标志。此处主要通过右移置换出地址写入相应的LBA寄存器。“and  al ,0x0f”将LBA的第24~27位放进device寄存器的低四位中,“or al,0xe0”把“0xe0”进行了或运算,拼出device寄存器的值,将高四位设置为“1110”,具体作用参考上一篇文章第一节内容。

         这段代码实现上一篇文章第三小节的第四个步骤,对2扇区进行读取操作。通过out指令写入command端口0x1F7,硬盘开始工作。

         本段代码主要用于检测status寄存器的BSY状态,“nop”指令的功能与sleep函数相当,延迟一下从而减少打扰硬盘的工作。“in al,dx”将status寄存器的值读入到al寄存器中,通过“cmp  al,0x88”的与操作,保留第4位和第7位,第4位为1表示硬盘控制器已经准备好数据传输,第7位为1表示硬盘在忙,所以我们只要判断第4位是否为1即可,顾使用“cmp  al ,0x08”对第四位进行判断。最后使用“jnz not_ready”来判断结果是否等于0,若为0,则表示可以读数据了,反之则不断循环读取状态。

         该段代码用于从0x1F0端口中读取数据,di寄存器中的值为要读取的扇区数,一个扇区有512个字节,data寄存器位16位,每次in操作读入2字节,所以需要指令di*512/2次,也就是di*256次。

         这段代码用于把从扇区读取到的loader加载器写入到bx寄存器所指的内存(0x900)中,每读入2个字节,bx所致的地址便+2,一直循环。待执行完成后,“ret”跳出函数回到上面的第38行中去:

         也就是跳转到内存0x900的位置,loader加载器的位置,自此MBR的任务到此结束,完成了MBR与loader的过渡,并且将权限交付给loader。

四.LOADER加载器代码实现

         接下来我们来编写一个简易版的loader加载器,这个加载器主要是为了验证MBR是否能够顺利过渡到Loader这里,所以就让它显示一些信息出来就好了,至于如何从实模式到保护模式的过渡,并最终在保护模式下加载内核,等我们继续深入学习到其他东西后再进行代码的优化。

         话不多说,直接上代码:

%include "boot.inc"
section loader vstart=LOADER_BASE_ADDRmov byte [gs:0x00],'A'mov     byte [gs:0x01],0xA4mov byte [gs:0x02],'K'mov     byte [gs:0x03],0xA4mov byte [gs:0x04],'A'mov     byte [gs:0x05],0xA4mov byte [gs:0x06],'H'mov     byte [gs:0x07],0xA4mov byte [gs:0x08],'A'mov     byte [gs:0x09],0xA4mov byte [gs:0x0a],'!'mov     byte [gs:0x0b],0xA4jmp $

         这段代码其实不用太多的解析,因为之前和上一篇MBR程序(参考:【操作系统】优化MBR程序:让MBR调用显存吧)是一样的,只需要注意一下第2行中将逻辑编译地址(也即是动态重定向,有兴趣可以参考:【计算机组成】实模式/保护模式下地址分段(基段地址+偏移地址)的原因)定义在了LOADER_BASE_ADDR,也就是0x900处。

五.编译和运行

         到目前为止,我们整理下已经编写完成的代码并且着手开始编译:

  • 首先是改造版的MBR程序,为了方便记忆,本文命名为MBR.S
  • 然后是boot.inc配置信息文件
  • 再来就是新编写的loader程序,为了方便记忆命名为loader.S
  • 最后是虚拟硬盘hd60M.img,这个在之前的文章(参考:【操作系统】Bochs安装和配置)中有说明怎么生成,就不在次赘述了。

        我们首先编译MBR程序,使用以下指令即可进行简单的编译(注意你的硬盘、程序路径可能与我的不一样,请选择正确的路径):

        需要注意的是,Nasm的参数“-I”,意思是指定库目录的路径,现阶段也就是boot.inc的路径。假如如果你的boot.inc在AAA文件夹下,那么就写“nasm  –I  /AAA(文件夹的路径)  其他省略”,如果boot.inc和MBR在同一个路径下,就写“nasm   -I  ./   其他省略”,以此类推。

        接下来按照同样的方式编译loader加载器(注意你的硬盘、程序路径可能与我的不一样,请选择正确的路径):

        然后将MBR的二进制文件写入到0扇区中去(注意你的硬盘、程序路径可能与我的不一样,请选择正确的路径):

        最后再将loader加载器也写入到2扇区中去(注意你的硬盘、程序路径可能与我的不一样,请选择正确的路径):

        将代码写入到镜像后,我们再将镜像文件加入到Bochs的模拟硬件环境配置文件中,根据文章中所描述的,我们直接将新生成的镜像写入配置文件的以下位置即可:

        保存一下修改后的配置文件,我们开始运行Bochs模拟器进行模拟操作:

./Bochs  –f   boch.disk(你自己的硬件配置文件名)

        运行成功后,会显示以下信息,并且默认为【6】:

        此时我们再按一次回车,即可开始模拟:

        我们在控制台中输入“c”(具体含义请查看上面所说的文章),继续往下运行,就能看到弹出的窗口中出现了我们所要的字符串:

​​​​​​​

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

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

相关文章

excel怎么设置密码?轻松保护您的工作表

在数字化时代,数据的安全性显得尤为重要。excel作为我们日常工作中广泛使用的办公软件,其中可能包含了大量的敏感数据。为了确保这些数据不被未授权的人访问,本文将为您详细介绍excel怎么设置密码,从而有效地保护您的数据安全。 方…

基于Redis的高可用分布式锁——RedLock

目录 RedLock简介 RedLock工作流程 获取锁 释放锁 RedLock简介 Redis作者提出来的高可用分布式锁由多个完全独立的Redis节点组成,注意是完全独立,而不是主从关系或者集群关系,并且一般是要求分开机器部署的利用分布式高可以系统中大多数存…

delphi fmxui 做的一些跨平台app

pascal语音显然已经没落,但delphi还在坚挺着,每年都会发布新版本, 主要是做跨平台应用。 如果你觉得qt qml 写android app 比较麻烦,那可以尝试delphi 12,可以用c builder 尝试 android,ios 开发 下面的…

适用于 Windows 7/8/10/11电脑的 12 款顶级数据恢复软件

很多时候,我们在 Windows 7 /8/10/11下不小心按了删除键,从而丢失了硬盘或 USB 驱动器中的重要文件和数据。在某些情况下,病毒或软件错误可能会损坏您的硬盘,从而影响您的文件。在这种情况下,您迫切需要一款适用于 Win…

Labview 图像处理系统设计

1. 总体主界面设计 前面板界面如下: 界面总共分为一个实时采集加拍照控制模块,两个图像显示模块(实时图像显示和直方图显示)以及三个图像处理模块 前面板中各模块具体功能及使用说明如下: 1.当实时按钮关闭时&#x…

mysql .ibd 文件过大清理方法

问题 有一个 info_track 表用来临时存储告警推送数据,逻辑处理完成后,会执行 Delete 语句删除对应的记录。 问题:项目现场运行了几个月后,发现磁盘空间莫名占用了过多的存储,> 100GB,且无法释放。 生…

向上调整向下调整算法

目录 AdjustUp向上调整 AdjustDown向下调整 AdjustUp向上调整 前提是:插入数据之后,除去插入的数据其他的数据还是为堆 应用:插入数据。 先插入一个10到数组的尾上,再进行向上调整算法,直到满足堆。 性质&#xff1…

基础算法(二)

一 高精度计算 int能表示范围为2^32,这看起来很大,但在大数据时代的如今,不说是int 哪怕是long long也是不够的,那么为了使用或计算这些超出或远超整形大小的数,我们这些数的计算方法称为高精度计算。 (1)…

代码随想录 Leetcode113. 路径总和 II

题目&#xff1a; 代码(首刷看解析 2024年1月30日&#xff09;&#xff1a; class Solution { public:vector<int> temp;vector<vector<int>> res;void recursion(TreeNode* cur, int sum) {if (!cur->left && !cur->right && sum 0…

Java进击框架:Spring-WebFlux(九)

Java进击框架&#xff1a;Spring-WebFlux&#xff08;九&#xff09; 前言Mono和FluxSpring WebFlux反应的核心DispatcherHandler带注释的控制器WebFlux配置 WebClient配置retrieve()交换请求正文Filters属性语境同步使用测试 RSocket反应库 前言 Spring框架中包含的原始web框…

Jmeter分布式场景

Jmeter分布式 1. 为什么使用Jmter分布式测试 1.1 需求 对学院接口(查询学院-所有)进行1000用户并发访问&#xff0c;测试服务器处理批量请求能力1.2 现状 我们单台电脑由于配置(CPU、内存)问题&#xff0c;最模拟500用户时&#xff0c;就出现卡死现象按照一般的压力机配置&…

1. 两数之和(力扣LeetCode)

文章目录 1. 两数之和题目描述哈希表&#xff1a;map二分查找暴力&#xff1a;双重for循环 1. 两数之和 题目描述 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可…

24. 两两交换链表中的节点(力扣LeetCode)

文章目录 24. 两两交换链表中的节点题目描述解题思路只使用一个临时节点使用两个临时节点 24. 两两交换链表中的节点 题目描述 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff0…

angular2 开发遇到的问题

1&#xff1a;插件使用&#xff0c;要一同引入 不然报错 “ \ Changes detected. Rebuilding...X [ERROR] NG8001: sf-dashboard-overview is not a known element:”

微信扫码登录流程

微信官方文档使用 搜索“微信开放平台”点击导航栏的“资源中心”点击“网站应用”下的“微信登录功能”地址微信扫码登录是基于OAuth2的&#xff0c;所以需要第三方应用&#xff08;就是实现微信扫码登录的应用&#xff09;成为微信的客户端&#xff0c;获取AppId和AppSecret…

Linux 进程管理

一、简述 当运行一个程序的时候&#xff0c;那么运行的这个程序就叫做进程。程序&#xff0c;是一个静态的概念统称为软件&#xff0c;相当于一个被编译好可执行的二进制文件&#xff0c;同时程序可以长期存在系统中&#xff1b;进程&#xff0c;是一个动态的概念&#xff0c;…

RHCE练习3

1.基于域名www.openlab.com可以访问网站内容为 welcome to openlab 2.给该公司创建三个子界面分别显示学生信息&#xff0c;教学资料和缴费网站&#xff0c;基于www.openlab.com/student 网站访问学生信息&#xff0c;www.openlab.com/data网站访问教学资料www.openlab.com/mo…

Unix环境高级编程-学习-04-匿名管道PIPE

目录 一、环境 二、介绍 三、C标准函数介绍 1、pipe 2、popen 3、pclose 4、注意 四、宏 五、常见的管道用法 1、一对一&#xff08;父进程读子进程写一条管道&#xff09; 2、一对一&#xff08;父进程写子进程读一条管道&#xff09; 3、一对多&#xff08;父进程…

leetcode—跳跃游戏—贪心算法

1 跳跃游戏1 给你一个非负整数数组 nums &#xff0c;你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标&#xff0c;如果可以&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 示例 1&a…

vue-computed 计算属性

一、computed 计算属性 在Vue应用中&#xff0c;在模板中双向绑定一些数据或者表达式&#xff0c;但是表达式如果过长&#xff0c;或者逻辑更为复杂 时&#xff0c;就会变得臃肿甚至难以维护和阅读&#xff0c;例如&#xff1a; <div>写在双括号中的表达式太长了,不利于阅…