【操作系统】调用硬盘并且实现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,一经查实,立即删除!

相关文章

springboot(ssm环保网站 绿色环保宣传系统Java系统

springboot(ssm环保网站 绿色环保宣传系统Java系统 开发语言:Java 框架:springboot(可改ssm) vue JDK版本:JDK1.8(或11) 服务器:tomcat 数据库:mysql 5.7&#xff0…

C++ easyX小程序:画五角星

//本小程序通过调用easyX的moveto、lineto函数画出五角星编写了FiveStar函数&#xff0c;在调用这个函数时setbkcolor、setlinecolor、setfillcolor设置了背景、线及填充颜色&#xff0c;又调用floodfill函数对五角星进行颜色填充。 //代码及注释如下&#xff1a; #include<…

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

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

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

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

delphi fmxui 做的一些跨平台app

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

【Spring连载】使用Spring Data访问Redis(一)----快速指南

【Spring连载】使用Spring Data访问Redis&#xff08;一&#xff09;----快速指南 一、导入依赖二、Hello World程序 一、导入依赖 在pom.xml文件加入如下依赖就可以下载到spring data redis的jar包了&#xff1a; <dependency><groupId>org.springframework.boot…

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

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

STM32——点灯

STM32——点灯 1.开发准备 开发环境:keil5&#xff0c;STM32CubeMX 开发语言:C语言 烧录工具:ST-Link 库函数:HAL库 2.点灯 常用的GPIO HAL库函数&#xff1a; //GPIO初始化 void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init); //调制电平 void H…

怎么创建docker镜像

创建Docker镜像可以通过以下几个步骤&#xff1a; 编写Dockerfile&#xff1a;Dockerfile是一个文本文件&#xff0c;定义了镜像的构建过程。在Dockerfile中&#xff0c;可以指定基础镜像、添加应用程序代码和依赖、设置环境变量、运行命令等。根据应用程序的需求&#xff0c;编…

Labview 图像处理系统设计

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

mysql .ibd 文件过大清理方法

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

javaScript遍历数组的一些方法

1&#xff0c;for循环 for循环是最基础并且是比较常用的一种 let arr[1,2,3,4,5]for(let i0;i<arr.length;i){//分别输出1,2,3,4,5console.log(arrarr[i])} 2&#xff0c;for...of循环 使用for...of循环可以遍历数组&#xff0c;并且直接获取里面的每个元素 let arr[1,2,…

向上调整向下调整算法

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

【每日一题】YACS 473:栈的判断

这是上海计算机学会竞赛 P 473 P473 P473&#xff1a;栈的判断&#xff08; 2021 2021 2021年 8 8 8月月赛 丙组 T 4 T4 T4&#xff09;标签&#xff1a;栈题意&#xff1a;给定 n n n个数字&#xff0c;已知这些数字的入栈顺序为 1 , 2 , 3... , n 1,2,3...,n 1,2,3...,n&…

1.30贪心(简单)

目录 1.分发饼干 2. ​​​​​​​种花问题 3. 赢得比赛需要的最少训练时长 1.分发饼干 假设你是一位很棒的家长&#xff0c;想要给你的孩子们一些小饼干。但是&#xff0c;每个孩子最多只能给一块饼干。 对每个孩子 i&#xff0c;都有一个胃口值 g[i]&#xff0c;这是能让…

基础算法(二)

一 高精度计算 int能表示范围为2^32&#xff0c;这看起来很大&#xff0c;但在大数据时代的如今&#xff0c;不说是int 哪怕是long long也是不够的&#xff0c;那么为了使用或计算这些超出或远超整形大小的数&#xff0c;我们这些数的计算方法称为高精度计算。 &#xff08;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…

QT 打开项目时显示 “No valid settings file could be found” 错误信息

QT 打开项目时显示“No valid settings file could be found”的错误信息&#xff0c;这通常意味着找不到有效的设置文件。此时&#xff0c;可以尝试以下几种解决方案&#xff1a; 删除项目中的.user文件。这是QT自动生成的用户设置文件&#xff0c;有时候会因为某些原因导致文…

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

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

Java 异常处理中篇:finally 中的陷阱(finally 中 return 会发生什么)

文章目录 前言版本finally 中的陷阱finally 中使用 returnfinally 中修改数据的影响基本类型引用类型 finally 中的代码 “非最后” 执行finally 代码块一定会执行&#xff1f;异常丢失finally 底层原理分析 总结个人简介 前言 在上一篇文章中&#xff0c;我们介绍了 Java 异常…