Linux小型操作系统项目,《操作系统真象还原》第三章——完善MBR

前引

        上一章我们完成了MBR的雏形编写,但是只打印了几个字符,这一章我们才要真正地去完成MBR的功能。

        在完成MBR的功能之前我们要先了解一些知识,首先介绍什么是实模式。

        书上的内容实在繁杂,简单地说,实模式没有虚拟和抽象这一概念,程序员写的代码,只要写清楚放在什么地方就是放在内存的什么地方,没有系统进行保护,其他程序可以轻松覆盖、内存对于程序员来说是可随意访问的。因此会有很大的操作隐患。但是电脑开机后是先进入实模式的,然后再进入保护模式,这之间的过渡即MBR的作用。

        


        在上一章中BIOS建立了中断向量表,我们可以通过中断打印MBR几个字符;但是中断向量表只能在实模式下存在,等进入保护模式就不能运行了。所以我们需要换一种方式打印字符。

         这种方式即直接通过CPU控制显卡的显存来操作显卡;CPU通过操作这部分内存,就可以通过显示器打印字符了;

        

        显示器上每个字在内存中占2字节16位的内存,其中低八位是字符的ASCII码,高八位是控制字符颜色的;具体哪一位对应什么颜色可以搜索资料;

        有了这些基础知识,我们就可以对上一章的MBR代码进行改造了;

MBR程序编写

代码逻辑:

1.指定vstart=0x7c00,告诉编译器本程序起始地址请帮我放到0x7c00处

2.查询调用BIOS清屏(后面会直接通过显卡实现)

3.指定段基址,gs=0xb800

4.死循环,填入MBR规定510字节大小剩下的0;固定结尾两字节0x55 和0xaa

                                        ;主引导程序 
                                        ;
                                        ;LOADER_BASE_ADDR equ 0xA000 
                                        ;LOADER_START_SECTOR equ 0x2
                                        ;------------------------------------------------------------
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

                                        ; 清屏
                                        ;利用0x06号功能,上卷全部行,则可清屏。
                                        ; -----------------------------------------------------------
                                        ;INT 0x10   功能号:0x06	   功能描述:上卷窗口
                                        ;------------------------------------------------------
                                        ;输入:
                                        ;AH 功能号= 0x06
                                        ;AL = 上卷的行数(如果为0,表示全部)
                                        ;BH = 上卷行属性
                                        ;(CL,CH) = 窗口左上角的(X,Y)位置
                                        ;(DL,DH) = 窗口右下角的(X,Y)位置
                                        ;无返回值:
    mov ax, 0600h
    mov bx, 0700h
    mov cx, 0                           ; 左上角: (0, 0)
    mov dx, 184fh	                    ; 右下角: (80,25),
			                            ; 因为VGA文本模式中,一行只能容纳80个字符,共25行。
			                            ; 下标从0开始,所以0x18=24,0x4f=79
    int 10h                             ; int 10h

                                        ; 输出背景色绿色,前景色红色,并且跳动的字符串"1 MBR"
    mov byte [gs:0x00],'1'
    mov byte [gs:0x01],0xA4             ; A表示绿色背景闪烁,4表示前景色为红色

    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

    jmp $		                        ; 通过死循环使程序悬停在此

    times 510-($-$$) db 0
    db 0x55,0xaa


        当然,这并没有完,只是换了一个方式重新打印了MBR字符而已;下面我们要让MBR做一点实事了;即加载操作系统的loader(因为MBR程序被锁死了只有510字节,无法完成太多功能),为进入保护模式做准备;

        简单地说,我们要用MBR这个加载器,去加载另一个加载器;另一个加载器(即loader)的功能是加载操作系统;

        如何实现呢?我们需要在实模式下,用in 和out 这两个指令与磁盘的一些寄存器进行交互;

这里放一下书上的磁盘IO的寄存器表

  在这里插入图片描述

 

操作磁盘的方式方法:

        在这里插入图片描述

 

MBR程序再编写

1、include boot.inc ,这里面定义了loader在磁盘中的位置(磁盘2号扇区)和loader加载进内存后的位置(0x900)

2、vstart=0x7c00,告诉编译器将这段代码放到0x7c00

3、按照上面操作磁盘的方法将磁盘数据取出放到指定内存区域

4、跳转到loader位置

5、填充剩下的0,定义结尾0x55和0xaa

                                    ;-------------	 loader和kernel   ----------
LOADER_BASE_ADDR equ 0x900 
LOADER_START_SECTOR equ 0x2
                                    ;主引导程序 
                                    ;------------------------------------------------------------
%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

                                    ; 清屏
                                    ;利用0x06号功能,上卷全部行,则可清屏。
                                    ; -----------------------------------------------------------
                                    ;INT 0x10   功能号:0x06	   功能描述:上卷窗口
                                    ;------------------------------------------------------
                                    ;输入:
                                    ;AH 功能号= 0x06
                                    ;AL = 上卷的行数(如果为0,表示全部)
                                    ;BH = 上卷行属性
                                    ;(CL,CH) = 窗口左上角的(X,Y)位置
                                    ;(DL,DH) = 窗口右下角的(X,Y)位置
                                    ;无返回值:
    mov ax, 0600h
    mov bx, 0700h
    mov cx, 0                       ; 左上角: (0, 0)
    mov dx, 184fh		            ; 右下角: (80,25),
				                    ; 因为VGA文本模式中,一行只能容纳80个字符,共25行。
				                    ; 下标从0开始,所以0x18=24,0x4f=79
    int 10h                         ; int 10h

                                    ; 输出字符串:MBR
    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	        ;A表示绿色背景闪烁,4表示前景色为红色

    mov byte [gs:0x06],'B'
    mov byte [gs:0x07],0xA4

    mov byte [gs:0x08],'R'
    mov byte [gs:0x09],0xA4
	 
    mov eax,LOADER_START_SECTOR	    ; 起始扇区lba地址
    mov bx,LOADER_BASE_ADDR         ; 写入的地址
    mov cx,1			            ; 待读入的扇区数
    call rd_disk_m_16		        ; 以下读取程序的起始部分(一个扇区)
  
    jmp LOADER_BASE_ADDR
       
                                    ;-------------------------------------------------------------------------------
                                    ;功能:读取硬盘n个扇区
rd_disk_m_16:	   
                                    ;-------------------------------------------------------------------------------
				                    ; eax=LBA扇区号
				                    ; ebx=将数据写入的内存地址
				                    ; ecx=读入的扇区数
    mov esi,eax	                    ;备份eax
    mov di,cx		                ;备份cx
                                    ;读写硬盘:
                                    ;第1步:选择特定通道的寄存器,设置要读取的扇区数
    mov dx,0x1f2
    mov al,cl
    out dx,al                       ;读取的扇区数

    mov eax,esi	                    ;恢复ax

                                    ;第2步:在特定通道寄存器中放入要读取扇区的地址,将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

    shr eax,cl
    and al,0x0f	                    ;lba第24~27位
    or al,0xe0	                    ; 设置7~4位为1110,表示lba模式
    mov dx,0x1f6
    out dx,al

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

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

                                    ;第5步:从0x1f0端口读数据
    mov ax, di                      ;di当中存储的是要读取的扇区数
    mov dx, 256                     ;每个扇区512字节,一次读取两个字节,所以一个扇区就要读取256次,与扇区数相乘,就等得到总读取次数
    mul dx                          ;8位乘法与16位乘法知识查看书p133,注意:16位乘法会改变dx的值!!!!
    mov cx, ax	                    ; 得到了要读取的总次数,然后将这个数字放入cx中
    mov dx, 0x1f0
.go_on_read:
    in ax,dx
    mov [bx],ax
    add bx,2		  
    loop .go_on_read
    ret

    times 510-($-$$) db 0
    db 0x55,0xaa

Loader程序编写检验MBR功能

        然后我们随便写个loader检验MBR是否能成功运行

        我就直接复制粘贴后面的loader打印字符程序了

%include "boot.inc"
section loader vstart=LOADER_BASE_ADDR

                                    ; 输出背景色绿色,前景色红色,并且跳动的字符串"1 MBR"
mov byte [gs:0x00],'2'
mov byte [gs:0x01],0xA4             ; A表示绿色背景闪烁,4表示前景色为红色

mov byte [gs:0x02],' '
mov byte [gs:0x03],0xA4

mov byte [gs:0x04],'L'
mov byte [gs:0x05],0xA4   

mov byte [gs:0x06],'O'
mov byte [gs:0x07],0xA4

mov byte [gs:0x08],'A'
mov byte [gs:0x09],0xA4

mov byte [gs:0x0a],'D'
mov byte [gs:0x0b],0xA4

mov byte [gs:0x0c],'E'
mov byte [gs:0x0d],0xA4

mov byte [gs:0x0e],'R'
mov byte [gs:0x0f],0xA4

jmp $		                        ; 通过死循环使程序悬停在此



编译运行

        用nasm编译我们的MBR程序和Loader程序

        nasm -o mbr mbr.s -I include/

        在include文件夹中放入我们的boot.inc

        用dd命令将mbr写入磁盘0号分区,loader写入2号分区

        dd if=loader of=/bochs/hd60M.img seek=2 bs=512 count=1 conv=notrunc

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

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

相关文章

VR内容定制 | VR内容中控管理平台可以带来哪些价值?

随着科技的不断发展,虚拟现实(VR)技术已经逐渐渗透到各个领域,其中教育领域也不例外。通过VR技术,学生可以身临其境地参与到各种场景中,获得更加直观、生动的学习体验。为了让教师更好地进行VR教学的设计和管理,提高教…

jmeter测试rpc接口-使用dubbo框架调用【杭州多测师_王sir】

1.基于SOAP架构。基于XML规范。基于WebService协议。特点:接口地址?wsdl结尾2.基于RPC架构,基于dubbo协议,thrift协议。SpringCloud微服务。3.基于RestFul架构,基于json规范。基于http协议(我们常用的都是这种,cms平台也是) Rest…

iOS开发-JsonModel的学习及使用

IOS JsonModel的学习及使用 当我们从服务端获取到json数据后的时候,我们需要在界面上展示或者保存起来,下面来看下直接通过NSDictionary取出数据的情况。 NSDictionary直接取出数据的诟病。 NSString *name [self.responseObj objectForKey:"nam…

Flink源码之JobManager启动流程

从启动命令flink-daemon.sh中可以看出StandaloneSession入口类为org.apache.flink.runtime.entrypoint.StandaloneSessionClusterEntrypoint, 从该类的main方法会进入ClusterEntrypoint::runCluster中, 该方法中会创建出主要服务和组件。 StandaloneSessionClusterEntrypoint:…

Maven进阶1 -- 分模块开发、依赖管理、聚合与继承、属性、版本管理、多环境开发、跳过测试

目录 1.分模块开发 将原始模块按照功能拆分成若干个子模块&#xff0c;方便模块间的相互调用&#xff0c;接口共享。 案例&#xff1a;拆分一下这个SSM整合案例 ①创建maven模块 demo项目下的pom.xml文件&#xff08;主要看一下依赖&#xff09; <dependencies><!…

黑马头条项目学习--Day2: app端文章查看,静态化freemarker,分布式文件系统minIO

app端文章 Day02: app端文章查看&#xff0c;静态化freemarker,分布式文件系统minIOa. app端文章列表查询1) 需求分析2) 实现思路 b. app端文章详细1) 需求分析2) Freemarker概述a) 基础语法种类b) 集合指令&#xff08;List和Map&#xff09;c) if指令d) 运算符e) 空值处理f) …

GIS在地质灾害危险性评估与灾后重建中的应用教程

详情点击链接&#xff1a;GIS在地质灾害危险性评估与灾后重建中的实践技术应用 前言 地质灾害是指全球地壳自然地质演化过程中&#xff0c;由于地球内动力、外动力或者人为地质动力作用下导致的自然地质和人类的自然灾害突发事件。由于降水、地震等自然作用下&#xff0c;地质…

《合成孔径雷达成像算法与实现》Figure3.7

代码复现如下&#xff1a; clc clear all close all%参数设置 TBP 100; %时间带宽积 T 10e-6; %脉冲持续时间%参数计算 B TBP/T; …

MySQL — InnoDB介绍

文章目录 InnoDB 主要特点InnoDB 架构In-Memory StructuresBuffer PoolChange BufferAdaptive Hash IndexLog Buffer On-Disk StructuresSystem TablespaceFile-Per-Table TablespacesGeneral TablespacesUndo TablespacesTemporary TablespacesDoublewrite BufferRedo LogUndo…

半导体器件||的学习

电子管的介绍&#xff1a; 到底什么是电子管&#xff08;真空管&#xff09;&#xff1f; - 知乎 芯片破壁者&#xff08;一&#xff09;&#xff1a;从电子管到晶体管“奇迹”寻踪 - 知乎 晶体管&#xff1a; 什么是晶体管&#xff1f;它有什么作用&#xff1f; - 知乎 改…

多个配置WebMvcConfigurationSupport失效问题

最近在项目中用类继承WebMvcConfigurationSupport实现拦截器 Configuration RequiredArgsConstructor public class SpringWebSupport extends WebMvcConfigurationSupport {private final ProjectInterceptor projectInterceptor;// 拦截器 //设置拦截器对象和拦截请求Ove…

java 企业工程管理系统软件源码+Spring Cloud + Spring Boot +二次开发+ MybatisPlus + Redis em

​ 鸿鹄工程项目管理系统 Spring CloudSpring BootMybatisVueElementUI前后端分离构建工程项目管理系统 1. 项目背景 一、随着公司的快速发展&#xff0c;企业人员和经营规模不断壮大。为了提高工程管理效率、减轻劳动强度、提高信息处理速度和准确性&#xff0c;公司对内…

5G RedCap

5G RedCap指的是3GPP所提出的5G标准。与之前发布的5G标准相比&#xff0c;功能更加精简。5G RedCap于2019年6月首次被纳入3GPP R17研究项目。 把一些不必要的功能去掉就可以带来模组价格的降低。背后的基本想法是&#xff1a;为物联网应用定义一种新的、不那么复杂的NR设备。 …

php实现登录的例子

界面&#xff1a; 登录界面login.html代码&#xff1a; <!DOCUMENT html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns"http://www.w3.org/1999/xhtml"…

Java中String方法魔性学习

这里写目录标题 先进行专栏介绍String详解常用构造方法代码演示常用成员方法代码示例总结 先进行专栏介绍 本专栏是自己学Java的旅途&#xff0c;纯手敲的代码&#xff0c;自己跟着黑马课程学习的&#xff0c;并加入一些自己的理解&#xff0c;对代码和笔记 进行适当修改。希望…

循环队列详解

1. 循环队列 1.1 概念及结构 循环队列是一种特殊类型的队列数据结构&#xff0c;也被称为”唤醒缓冲器“。它在数组的基础上实现了循环利用空间的功能。在循环队列中&#xff0c;队尾和队头之间形成了一个循环&#xff0c;当队尾指针“追上”队头指针时&#xff0c;队列不再继…

OpenAI允许网站阻止其网络爬虫;谷歌推出类似Grammarly的语法检查功能

&#x1f989; AI新闻 &#x1f680; OpenAI推出新功能&#xff0c;允许网站阻止其网络爬虫抓取数据训练GPT模型 摘要&#xff1a;OpenAI最近推出了一个新功能&#xff0c;允许网站阻止其网络爬虫从其网站上抓取数据训练GPT模型。该功能通过在网站的Robots.txt文件中禁止GPTB…

【前端 | CSS】flex布局

基本概念 Flexible模型&#xff0c;通常被称为 flexbox&#xff0c;是一种一维的布局模型。它给 flexbox 的子元素之间提供了强大的空间分布和对齐能力 我们说 flexbox 是一种一维的布局&#xff0c;是因为一个 flexbox 一次只能处理一个维度上的元素布局&#xff0c;一行或者…

vscode运行python报错:ModuleNotFoundError:No module named ‘xxx‘

在乌班图上使用pycharm的时候&#xff0c;pycharm总是莫名其妙卡死&#xff0c;又说是搜狗输入法的锅&#xff0c;又说别的原因&#xff0c;一气之下不用pycharm,转到vscode上&#xff0c;没想到出现了如下报错。 就是vscode在运行python的时候&#xff0c;自定义模块的调用无…

03.利用Redis实现缓存功能---解决缓存穿透版

学习目标&#xff1a; 提示&#xff1a;学习如何利用Redis实现添加缓存功能解决缓存穿透版 学习产出&#xff1a; 缓存穿透讲解图&#xff1a; 解决方案&#xff1a; 采用缓存空对象采用布隆过滤器 解决方案流程图&#xff1a; 1. 准备pom环境 <dependency><gro…