再次改进MBR(从磁盘读入Loader加载器)

news2024/9/22 5:55:38

文章目录

  • 前言
  • 前置知识
  • 代码说明
  • 实验操作

前言

本博客记录《操作系统真象还原》第二章第2个实验操作~

实验环境:ubuntu18.04+VMware , Bochs下载安装

实验内容:从磁盘读入Loader加载器

实验思路: MBR 受到512字节大小的限制,小的内存空间无法为内核准备环境。因此,我们要在另一个程序中完成初始化环境及加载内核的任务,这个程序称之loader ,即加载器。现在MBR要做的工作是:负责从硬盘上把 loader 加载到内存,并将接力棒交给它。

前置知识

硬盘的工作原理

硬盘的内部结构

硬盘的表面由一些磁性物质组成,可以用这些磁性物质来记录二进制数据。

在这里插入图片描述
硬盘整体示意图

说明:

  • 盘片固定在主轴上随主轴高速转动。
  • 每个盘片分上下两面,每面都存储数据。
  • 每个盘面都各由一个磁头来读取数据,故一个盘片上对应一个磁头。故用磁头号来表示盘面
  • 所有盘面中相对位置相同的磁道组成柱面

在这里插入图片描述
因此,可用(柱面号,盘面号,扇区号)来定位任意一个“磁盘块”。

  • CHS(Cylinder Head Sector):用(柱面号,盘面号,扇区号)来定位任意一个“磁盘块”。
  • LAB(Logical Block Address):用比特位来描述扇区的信息。

磁盘,磁道,扇区

  • 磁道:磁盘的盘面被划分成一个个磁道。这样的一个“圈”就是一个磁道。如下图中指向的灰色圈就是一个扇区。
  • 扇区:一个磁道又被划分成一个个扇区,每个扇区就是一个“磁盘块”。各个扇区存放的数据量相同。【最内侧磁道上的扇区面积最小,因此数据密度最大】

在这里插入图片描述

硬盘控制器端口

硬盘控制器属于 IO 接口,端口就是位于 IO制器上的寄存器,此处的端口是指硬盘控制器上的寄存器。

(待继续填坑。。。)

硬盘操作方法

硬盘操作流程

  1. 先选择通道,往该通道的 sector count 寄存器中写入待操作的扇区数。
  2. 往该通道上的三个 LBA 寄存器写入扇区起始地址的低 24 位。
  3. 往 device 寄存器中写入 LBA 地址的 24 ~ 27 位,并置第 6 位为 1 ,使其为 LBA 模式,设置第 4 位,选择操作的硬盘( master 硬盘或 slave 硬盘)。
  4. 往该通道上的 command 寄存器写入操作命令。
  5. 读取该通道上的 status 寄存器,判断硬盘工作是否完成。
  6. 如果以上步骤是读硬盘,进入下 一 个步骤。否则,完工。
  7. 将硬盘数据读出。

硬盘工作完成后,需要设定数据传送的方式。一般用“查询传送方式”和“中断传送方式”传送数据。

代码说明

include/boot.inc

boot.inc文件:关于加载器的配置信息。

;-------------	 loader和kernel   ----------
LOADER_BASE_ADDR equ 0x900 
LOADER_START_SECTOR equ 0x2

boot.inc代码说明:

  1. LOADER BASE ADDR 定义了 loader 在内存中的位置, MBR 要把 loader 硬盘读入后放在内存地址 0x900 处。
  2. LOADER_START SECTOR 定义 loader 在硬盘上的逻辑扇区地址,即 LBA 地址。这里等于 0x2 ,说明 loader 放在了第 2 块扇区。

mbr.S

;主引导程序 
;------------------------------------------------------------
%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
      mov dx, 256
      mul dx
      mov cx, ax	   ; di为要读取的扇区数,一个扇区有512字节,每次读入一个字,
			   ; 共需di*512/2次,所以di*256
      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

mbr.S代码说明:

  1. 第50 ~ 52 行为函数 rd disk_m_ 16 传递参数。这里选择用ax, bx, ex 寄存器来传递参数。
  2. 第64 ~ 65 行备份数据。
  3. 第67 ~ 70 行 先选定一个通道,再往 sector count 寄存器中写扇区数。
  4. 第74 ~ 95 行是将 LBA 地址写入 LBA 寄存器和 device 寄存器的低位。端口 0x1f3 是寄存器 LBA
    low ,端口 0x1f4 是寄存器 LBA mid ,端口 0x1f5 是寄存器 LBA high。
  5. 第97 ~100 行便是写入命令啦。这里做读操作,所以读扇区的命令是 0x20 。
  6. 第102 ~ 109 行检测 status 寄存器的 BSY 位。
  7. 第111 ~ 122 行是从硬盘取数据的过程。

【这部分详细解读请看原书】

loader.S

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

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

mov byte [gs:0x22],' '
mov byte [gs:0x23],0xA4

mov byte [gs:0x24],'L'
mov byte [gs:0x25],0xA4   

mov byte [gs:0x26],'O'
mov byte [gs:0x27],0xA4

mov byte [gs:0x28],'A'
mov byte [gs:0x29],0xA4

mov byte [gs:0x2a],'D'
mov byte [gs:0x2b],0xA4

mov byte [gs:0x2c],'E'
mov byte [gs:0x2d],0xA4

mov byte [gs:0x2e],'R'
mov byte [gs:0x2f],0xA4

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

代码说明

MBR 与之前的代码较为接近,功能是打印的字符串是“ loader"。

实验操作

1.创建/include/boot.inc文件

(base) user@ubuntu:/home/cooiboi/bochs$ sudo mkdir include
(base) user@ubuntu:/home/cooiboi/bochs$ ls
bin  include  share
(base) user@ubuntu:/home/cooiboi/bochs$ cd include/
(base) user@ubuntu:/home/cooiboi/bochs/include$ sudo vim boot.inc

2.创建mbr.S并对其进行编译

创建mbr.S

(base) user@ubuntu:/home/cooiboi/bochs$ sudo vim mbr.S

nasm编译

参数-I:表明指定库目录

(base) user@ubuntu:/home/cooiboi/bochs$ sudo nasm -I include/ -o mbr.bin mbr.S
  1. MBR 写入进磁盘0中
sudo dd if=/home/cooiboi/bochs/mbr.bin of=/home/cooiboi/bochs/hd60M.img bs=512 count=1 conv=notrunc
(base) user@ubuntu:/home/cooiboi/bochs$ sudo dd if=/home/cooiboi/bochs/mbr.bin of=/home/cooiboi/bochs/hd60M.img bs=512 count=1 conv=notrunc
1+0 records in
1+0 records out
512 bytes copied, 0.00026721 s, 1.9 MB/s

4.简单整理了一下文件目录(可以跳过)

笔者这里觉得有点乱,因此创建boot文件夹放入相关编写文件。

# 移动一个文件夹到另一个文件夹下
sudo mv 文件名 目标文件夹路径
(base) user@ubuntu:/home/cooiboi/bochs$ sudo mkdir boot
(base) user@ubuntu:/home/cooiboi/bochs$ sudo mv bochsrc.disk /home/cooiboi/bochs/boot/
(base) user@ubuntu:/home/cooiboi/bochs$ sudo mv mbr.bin /home/cooiboi/bochs/boot/
(base) user@ubuntu:/home/cooiboi/bochs$ sudo mv mbr.S /home/cooiboi/bochs/boot/
(base) user@ubuntu:/home/cooiboi/bochs$ sudo mv hd60M.img /home/cooiboi/bochs/boot/

5.创建loader.S并对其进行编译

(base) user@ubuntu:/home/cooiboi/bochs/boot$ sudo vim loader.S
(base) user@ubuntu:/home/cooiboi/bochs/boot$ cd ..
(base) user@ubuntu:/home/cooiboi/bochs$ sudo nasm -I include/ -o boot/loader.bin boot/loader.S

6.将生成的loader.bin写入硬盘的第二个扇区

sudo dd if=/home/cooiboi/bochs/boot/loader.bin of=/home/cooiboi/bochs/boot/hd60M.img bs=512 count=1 seek=2 conv=notrunc
(base) user@ubuntu:/home/cooiboi/bochs/boot$ sudo dd if=/home/cooiboi/bochs/boot/loader.bin of=/home/cooiboi/bochs/boot/hd60M.img bs=512 count=1 seek=2 conv=notrunc
0+1 records in
0+1 records out
98 bytes copied, 0.000113617 s, 863 kB/s

7.启动Bochs

sudo bin/bochs -f boot/bochsrc.disk

依次输入6c.

在这里插入图片描述
在这里插入图片描述
最后,本节的文件结构

在这里插入图片描述

【补充】bochsre.disk中的hd60M.img写成了绝对地址~

ata0-master: type=disk, path="/home/cooiboi/bochs/boot/hd60M.img", mode=flat,cylinders=121,heads=16,spt=63

参考资料

  • 《操作系统真象还原》
  • 《操作系统真象还原》第三章 ---- 完善MBR 尝汇编先苦涩后甘甜而再战MBR!(内有闲聊)
  • 王道计算机考研 操作系统 磁盘结构

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

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

相关文章

kernel pwn gdb调试

前言 对于Linux的二进制程序,gdb调试是十分重要的,可以清楚的了解程序是如何运行的,这里单独拉一篇记录我在kernel pwn中遇到的一些调试 GDB选择 在三大件pwndbg,gef,peda中,用了一圈下来感觉gef和pwndbg都挺好 gdb安装 简单…

PaddleNLP教程文档

文章目录一、快速开始1.1 安装PaddleNLP并 加载数据集1.2 数据预处理1.3 加载预训练模型1.4 设置评价指标和训练策略1.5 模型训练与评估1.6 模型预测二、数据处理2.1 整体介绍2.2 加载内置数据集2.3 自定义数据集2.3.1 从本地文件创建数据集2.3.2 paddle.io.Dataset/IterableDa…

OpenShift Security - 用 RHACS 为应用自动生成 NetworkPolicy

《OpenShift / RHEL / DevSecOps / Ansible 汇总目录》 说明:本文已经在 OpenShift 4.12 RHACS 3.73.1 环境中验证 文章目录什么是 NP-Guard用 NP-Guard 自动生成 NetworkPolicy参考什么是 NP-Guard NP-Guard 是 IBM 发起的一个开源项目,用来自动创建 …

WindowsTerminal 安装 oh-my-posh

文章目录1 前言2 安装过程3 Posh Themes 自定义主题参考1 前言 在Linux中,有非常好用的oh-my-zsh,最近使用WindowsTerminal时想想有没有和oh-my-zsh相同好用的插件呢,答案是:oh-my-posh 2 安装过程 进入最新版PowerShell&#…

干货 | 解决 App 自动化测试的常见痛点(弹框及首页启动加载完成判断处理)

1. 常见痛点App 自动化测试中有些常见痛点问题,如果框架不能很好的处理,就可能出现元素定位超时找不到的情况,自动化也就被打断终止了。很容易打消做自动化的热情,导致从入门到放弃。比如下面的两个问题:一是 App 启动…

【代码题】链表面试题

目录 1.链表分割 2.相交链表 3.环形链表 4.环形链表 II 1.链表分割 点击进入该题 现有一链表的头指针 ListNode* pHead,给一定值x,编写一段代码将所有小于x的结点排在其余结点之前,且不能改变原来的数据顺序,返回重新排列后的…

国内注册Steam账号的快捷方法

本文介绍在国内注册Steam账号的快速、简便方法。 目前,在国内注册新的Steam账号变得越来越麻烦;尤其在最近,无论是无休止的谷歌人机身份验证,还是无法收到的验证邮件,都使得新建一个Steam账号与原来相比变得更加困难。…

[Linux_]make/Makefile

[Linux_]make/Makefile 心有所向,日复一日,必有精进专栏:《Linux_》作者:沂沐沐目录 [Linux]make/Makefile 前言 一、Mikefile 二、如何写Mikefile文件 三、原理 四、项目清理 报错:missing separator 前言 一个工…

Linux 命令

最基础的命令 1.我是谁 我用什么账号登录 whoami 2.我在那 在那个目录下 pwd 3.环顾四周 1.ll展示详细信息 2.ls 展示文件名称 4.cd 想去那 改变目录 cd 回家 cd ./ 定位到当前目录 cd../ 上级目录 cd../../上两级目录。 5.切换用户 su 从普通用户切换到root用户的…

C#应用程序配置文件(XML序列化) - 开源研究系列文章

上次写了一个C#线程池及管理器的博文( C#开发的线程池和管理器 - 开源研究系列文章 ),收到了不小的浏览量,在此感谢各位网友的支持。这次将另一个功能放出来单独讲解:C#应用程序的配置文件,使用的是XML文件保存程序的配置信息&…

数据结构(栈、队列、链表)

文章目录前言数据结构(栈、队列、链表)1、栈2、队列3、链表3.1、单向链表结构3.2、双向链表结构前言 如果您觉得有用的话,记得给博主点个赞,评论,收藏一键三连啊,写作不易啊^ _ ^。   而且听说点赞的人每天的运气都不会太差&…

多边形点集排序

一、问题描述已知多边形点集P {P1, P2, ... , PN},其排列顺序是杂乱,依次连接这N个点,无法形成确定的多边形,需要对点集P进行排序后,再绘制多边形。二、排序规则点集排序过程中,关键在于如何定义点的大小关…

STC32G 时钟系统

文章目录时钟系统代码配置总结时钟系统 系统时钟有4个时钟源可供选择: 内部高精度IRC内部32KHzIRC(精度较低)外部晶振内部PLL输出时钟 主要关心的是两个指标:SYSclk和HSCLK SYSclk是系统的时钟,决定了指令执行速度…

Android 深入系统完全讲解(三)

系统调用 操作系统提供了一些方法,让用户层可以调用,而为了安全起见,这些方法调用,都是在内核空间。于是,用户调用的时候,就会有个动作,叫做陷入内核。 当用户调用系统方法的时候,系…

【k8s-device plugin】如何编写 k8s device plugin

参考 Device Plugin 入门笔记(一) Device Plugin 入门笔记(二) 从零开始入门 K8s:GPU 管理和 Device Plugin 工作机制 Kubernetes开发知识–device-plugin的实现 https://github.com/oceanweave/cola-device-plugi…

基于springboot的智慧物业管理系统的设计与实现(前后端分离)

项目描述 临近学期结束,还是毕业设计,你还在做java程序网络编程,期末作业,老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据疫情当下,你想解决的问…

mysql 中间件 mycat2 的详细安装及配置步骤

下载 首先打开mycat官网:MyCat2 右上角下载里面有个文件下载服务,点进去发现无法访问 这里需要配置一下host,把下面内容复制到host文件中。host文件位置在C:\Windows\System32\drivers\etc 210.51.26.184 mycat.org.cn www.mycat.org.cn …

第五篇 - 数组的劫持

一,前言 上篇,主要介绍了 Vue 数据初始化流程中,对象属性的深层劫持是如何实现的 核心思路就是递归,主要流程如下; 1.通过 data isFunction(data) ? data.call(vm) : data;处理后的 data 一定是对象类型 2.通过 d…

如何定位Bug——Qt

1. 前言 在写程序的过程中,不可避免出现各种Bug,如何快速的定位到Bug的位置,是程序员必备的技能之一。 2. 几种方法 2.1. 逻辑分析 根据程序所出的问题,分析问题可能所在的几个位置,通过逻辑分析找出Bug&…

从 Nginx Ingress 窥探云原生网关选型

作者: 魁予 现今有越来越多的企业开始采纳云原生理念进行应用架构转型。而 K8s 和微服务是云原生的两大支柱,随着云原生浪潮而被广泛应用。 对多数应用而言,提供对外服务的使命并不会改变,相比于原来的单体应用,微服…