手写简易操作系统(三)--加载Loader

news2025/6/16 12:48:47

前情提要

上一节我们讲了如何启动计算机,这一节我们讲如何加载内核,内核是存在于硬盘上的一段程序,要加载这段程序,那么必然需要从硬盘上读取数据,这里我们就需要使用 ATA PIO 模式

根据ATA规范,所有符合ATA的驱动器必须始终支持PIO模式作为默认的数据传输机制。

现在较为流行的SATA硬盘也是一种符合ATA标准的硬盘,所以当然也需要支持 ATA PIO,而 ATA PIO 较为简单,所以我们就将其当做默认的读取硬盘的模式

在实际应用中,为了获得更好的性能和效率,通常会选择更高级的硬盘访问模式,如 DMA 或 Ultra DMA,以及操作系统提供的直接访问硬盘的接口(如 Windows 的AHCI模式)。这些模式能够更有效地利用系统资源,提供更快速的数据传输速度。甚至是NVME,直接走PCIE通道与CPU直连。但是这些比较复杂,不在本文的考虑范围内。

一、硬盘的主要端口

image-20240309213607741

其中Primary为主通道,Secondary为从通道

其中主通道读时

  • 0x1F0 是数据端口
  • 0x1F1 是错误端口,可以返回错误信息,每一位都是一个错误信息,包括(0、AMNF未找到地址标记。1、TKZNF未找到零磁道。2、ABRT中止命令。3、MCR变更请求。4、IDNF未找到ID。5、MC 发生了变化。6、UNC不可纠正的数据错误。7、BBK检测到坏块。)
  • 0x1F2 是扇区数量端口
  • 0x1F3 是LBA低地址
  • 0x1F4 是LBA中地址
  • 0x1F5 是LBA高地址
  • 0x1F6 0-3位,在CHS寻址中表示柱头位,在LBA寻址中,表示LBA地址的24-27位。4位DRV,表示选择主盘或者从盘。5位、永远为1。6位、如果为0则为CHS寻址,如果为1则为LBA寻址。7位、永远为1。
  • 0x1F7 是状态寄存器端口 ,0位ERR,如果为1则表示出错了。3位Data ,如果为1表示硬盘已经把数据准备好了。6位DRDY,表示硬盘检测正常,可以执行命令。7位BSY,如果为1表示硬盘正繁忙,此寄存器中的其他位都无效。

主通道写时有一些yu寄存器有了不同的用途

  • 0x1F1 是参数端口,用于传递写硬盘时的参数
  • 0x1F7 是指令端口,我们主要用到了这么几个指令。0xEC,硬盘识别。0x20,读扇区。0x30,写扇区。

二、加载Loader

哈哈哈哈,上面说的是加载内核,现在又成了加载loader,没办法,加载内核之前就得加载Loader,Loader的作用有

  1. 加载内核:loader 负责将操作系统内核从存储设备(如硬盘、闪存)中读取到内存中,以便后续执行。
  2. 确认内核完整性:loader 在加载内核之前通常会对内核进行校验,以确保内核文件的完整性和正确性,避免因为损坏或错误的内核文件导致系统启动失败。
  3. 设置环境:loader 在加载内核前会设置好适当的执行环境,包括初始化硬件设备、建立内存映射关系等,为内核的正常执行做好准备工作。
  4. 启动内核:加载完内核后,loader 会将控制权转交给内核的起始地址,启动内核的执行,让操作系统开始运行。

由于MBR是占据了硬盘的第0扇区(以逻辑LBA方式,扇区从0开始编号,若是以物理CHS方式,扇区则从1开始编号),所以我们的loader就放在第1扇区,可以看第二章的内存布局,现在有两块内存可用,0x500~0x7BFF0x7E00~9FBFF,那我们就放在 0x600 的地方吧。下面我们接着改MBR

2.1、修改Mbr使其可以加载Loader

这里我们添加一点宏定义

; os/src/boot/boot.inc
LOADER_BASE_ADDR equ 0x600
LOADER_START_SECTOR equ 0x1

然后改写mbr

; os/src/boot/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号功能实现清理屏幕
; AL = 0x06 功能号
; AL 上卷的行数(如果为0,表示全部)
; BH 上卷行属性
; (CL,CH) = 窗口左上角的(X,Y)位置,这里是 (0,0)
; (DL,DH) = 窗口右下角的(X,Y)位置,这里是 (80,25)
    mov    ah, 0x06
    mov    al, 0x00
    mov    bh, 0x7
    mov    bl, 0x00
    mov    cx, 0           
    mov    dx, 0x184f
    int    0x10             ; int 0x10

    mov byte [gs:0x00],'M'  ; 字符为M的ascii值
    mov byte [gs:0x01],0x0F	; 11100001b 即背景色为黑,字体为白,不闪烁 
    mov byte [gs:0x02],'B'  ;
    mov byte [gs:0x03],0x0F	; 
    mov byte [gs:0x04],'R'  ;
    mov byte [gs:0x05],0x0F	;

    mov eax,LOADER_START_SECTOR	 ; Loader起始扇区 
    mov bx, LOADER_BASE_ADDR     ; Loader起始内存地址
    mov cx, 1			         ; 待写入扇区数
    call rd_disk_m_16		     ; 执行读取硬盘程序
  
    jmp LOADER_BASE_ADDR         ; 跳转到Loader执行
       

rd_disk_m_16:	   
				       ; eax=LBA扇区号
				       ; ebx=Loader内存
				       ; ecx=扇区数量
    mov esi,eax	       ; 备份eax
    mov di,cx		   ; 备份cx

    mov dx,0x1f2       ; 设置要写入端口,即读取端口数
    mov al,cl          ; 设置要读取扇区数
    out dx,al          ; 设置
    mov eax,esi	       ; 恢复eax

    mov dx,0x1f3       ; 设置要写入端口,即LBA低地址              
    out dx,al          

    mov cl,8           ; ax右移八位   
    shr eax,cl
    mov dx,0x1f4       ; 设置要写入端口,即LBA中地址 
    out dx,al

    shr eax,cl         ; ax右移八位   
    mov dx,0x1f5       ; 设置要写入端口,即LBA高地址 
    out dx,al

    shr eax,cl         ; ax右移八位
    and al,0x0f	       ; 保留低4位,设置高4位为 0000
    or al,0xe0	       ; 保留低4位,设置高4位为 1110
    mov dx,0x1f6
    out dx,al

    mov dx,0x1f7       ;
    mov al,0x20        ; 读扇区指令               
    out dx,al


.not_ready:            ; 未准备好
    nop                ; 不执行任何指令,占用一个机器周期
    in al,dx           ; 查看读取状态
    and al,0x88        ; 与 10001000 做与运算
    cmp al,0x08        ; 比较第三位和第七位
    jnz .not_ready
    mov ax, di         ; 要读的扇区数
    mov dx, 256        ; 乘以256,即要读多少次
    mul dx
    mov cx, ax	       ; 将要读的次数传给cx
    mov dx, 0x1f0      ; 要读的端口号

.go_on_read:
    in ax,dx           ; 向ax中读,一次读两个字节
    mov [bx],ax        ; 将ax中数据给bx地址的内存
    add bx,2		   ; bx中内存地址加2
    loop .go_on_read   ; 循环cx次
    ret
         
; 将510个字节中剩余的空间填充为0
; $ 是当前地址
; $$ 是本节开头地址,也就是0x7c00
times 510-($-$$) db 0
db 0x55,0xaa

2.2、写一个小Loader

; os/src/boot/loader.s
%include "boot.inc" 
section loader vstart=LOADER_BASE_ADDR 
.begin_loader:
    mov byte [gs:0x00],'L'  ; 字符为M的ascii值
    mov byte [gs:0x01],0x0F	; 11100001b 即背景色为黑,字体为白,不闪烁 
    mov byte [gs:0x02],'O'  ;
    mov byte [gs:0x03],0x0F	; 
    mov byte [gs:0x04],'A'  ;
    mov byte [gs:0x05],0x0F	;
    mov byte [gs:0x06],'D'  ;
    mov byte [gs:0x07],0x0F	;
    mov byte [gs:0x08],'E'  ;
    mov byte [gs:0x09],0x0F	;
    mov byte [gs:0x0A],'R'  ;
    mov byte [gs:0x0B],0x0F	;

; 程序在此处卡住
jmp $

这里loader的作用还是输出一些内容作为指示

2.3、执行

执行前需要把脚本更新一下

# os/run.sh
# 编译mbr
nasm -I src/boot/ -o bin/mbr.bin src/boot/mbr.s 
nasm -I src/boot/ -o bin/loader.bin src/boot/loader.s 

# 复制mbr二进制程序到硬盘
dd if=bin/mbr.bin of=/home/lyj/bochs/bin/hd60M.img bs=512 count=1 seek=0 conv=notrunc
dd if=bin/loader.bin of=/home/lyj/bochs/bin/hd60M.img bs=512 count=2 seek=1 conv=notrunc

# 启动仿真
/home/lyj/bochs/bin/bochs -f /home/lyj/bochs/bin/bochsrc.disk 

执行!

image-20240309225254582

结束语

第三章也结束了,这一章我们讲了如何加载一个Loader,以及如何读写硬盘,下一章,我们就要开始讲一些有关于保护模式的东西了,先将这个Loader完善一下。

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

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

相关文章

基于java+springboot+vue实现的学生信息管理系统(文末源码+Lw+ppt)23-54

摘 要 人类现已进入21世纪,科技日新月异,经济、信息等方面都取得了长足的进步,特别是信息网络技术的飞速发展,对政治、经济、军事、文化等方面都产生了很大的影响。 利用计算机网络的便利,开发一套基于java的大学生…

「蓝桥·算法双周赛」第七场分级赛——小白入门赛

题目列表 说明 好久没打蓝桥杯的比赛&#xff0c;回来试试水&#xff0c;就开了第1、2、3一共三个题&#xff0c;第4题可惜了。1.thanks,mom【算法赛】 思路&#xff1a; 没什么好说的&#xff0c;但是当时比赛刚开始服务器有问题&#xff0c;基本提交的全WA了。#include <…

Learn OpenGL 04 纹理

纹理环绕方式 纹理坐标的范围通常是从(0, 0)到(1, 1)&#xff0c;那如果我们把纹理坐标设置在范围之外会发生什么&#xff1f;OpenGL默认的行为是重复这个纹理图像&#xff08;我们基本上忽略浮点纹理坐标的整数部分&#xff09;&#xff0c;但OpenGL提供了更多的选择&#xf…

java中的字符串比较(题目作示例)

错误的代码 import java.util.Scanner; public class one {public static void main(String[] args) {Scanner scnew Scanner(System.in);String b"47568";int i0;for ( i 0; i <3; i){String asc.next();if(ab){System.out.println("密码正确&#xff0c;登…

鸿蒙开发(二)-项目结构

鸿蒙开发(二)-项目结构 上篇文章我们讲了如何配置鸿蒙开发的基础环境&#xff0c;以及创建了第一个鸿蒙程序。 这篇我们讲述了鸿蒙应用的项目目录结构。 如图所示&#xff1a;我们切换项目project可以看到。 另一种则是Ohos模式: AppScope->app.json5 应用的全局配置 {&q…

300分钟吃透分布式缓存-23讲:Redis是如何淘汰key的?

淘汰原理 首先我们来学习 Redis 的淘汰原理。 系统线上运行中&#xff0c;内存总是昂贵且有限的&#xff0c;在数据总量远大于 Redis 可用的内存总量时&#xff0c;为了最大限度的提升访问性能&#xff0c;Redis 中只能存放最新最热的有效数据。 当 key 过期后&#xff0c;或…

【vue.js】文档解读【day 2】 | 响应式基础

如果阅读有疑问的话&#xff0c;欢迎评论或私信&#xff01;&#xff01; 本人会很热心的阐述自己的想法&#xff01;谢谢&#xff01;&#xff01;&#xff01; 文章目录 响应式基础声明响应式状态(属性)响应式代理 vs 原始值声明方法深层响应性DOM 更新时机有状态方法 响应式…

html--彩虹爱心

文章目录 js内容cssreset.min.cssstyle.css html内容 js内容 const colors ["#e03776","#8f3e98","#4687bf","#3bab6f","#f9c25e","#f47274"]; const SVG_NS http://www.w3.org/2000/svg; const SVG_XLINK &q…

VUE3 使用axios网络请求

1.新建工程 参考&#xff0c;VUE3 环境搭建&#xff1a;https://blog.csdn.net/LQ_001/article/details/136293795&#xff0c;运行命令 vue create vue-demo 2.引入axios 不管何种引用&#xff0c;都要在工程中安装 axios 包。安装命令&#xff1a;npm install --save axio…

基于springboot实现数据资产管理系统 项目【项目源码+论文说明】

基于springboot实现数据资产管理系统演示 摘要 固定资产管理系统主要是完成对系统用户管理、资产信息管理、资产变更管理、资产用途管理、资产类别管理和资产增减管理。因为利用本系统管理员可以直接录入信息&#xff0c;修改信息&#xff0c;删除信息&#xff0c;并且若在录入…

智能革新:2024年AI辅助研发的挑战、机遇与未来展望

引言 在进入2024年的门槛时&#xff0c;我们站在了一个科技飞速发展的新纪元&#xff0c;其中&#xff0c;人工智能&#xff08;AI&#xff09;的持续进步和应用扩展无疑是推动这一变革的强大动力。AI辅助研发&#xff0c;作为将人工智能技术应用于科研和产品开发过程的一种模…

C++内存管理篇

文章目录 1. C/C内存分布2. C中的内存管理方式3. operator new和operator delete函数4. new和delete的实现原理5. 定位new表达式(placement-new) 1. C/C内存分布 C语言中&#xff0c;为了方便管理内存空间&#xff0c;将内存分成了不同的区域&#xff0c;每个区域管理不同的数据…

未来已来!AI大模型引领科技革命

未来已来&#xff01;AI大模型正以惊人的速度引领着科技革命。随着科技的发展&#xff0c;人工智能在各个领域展现出了非凡的能力和潜力&#xff0c;大模型更是成为了科技领域的明星。从自然语言处理到图像识别&#xff0c;从智能推荐到语音识别&#xff0c;大模型的应用正在改…

计算机找不到api-ms-win-core-path-l1-1-0的5种解决方法

在计算机使用过程中&#xff0c;我们可能会遇到各种问题&#xff0c;其中之一就是找不到某些系统文件。最近&#xff0c;许多用户反映他们在使用电脑时遇到了“找不到api-ms-win-core-path-l1-1-0文件”的问题。这个问题通常出现在Windows操作系统中&#xff0c;可能会影响到一…

《vtk9 book》 官方web版 第3章 - 计算机图形基础 (3 / 6)

3.8 演员几何 我们已经看到了光照属性如何控制演员的外观&#xff0c;以及相机如何结合变换矩阵将演员投影到图像平面上。剩下的是定义演员的几何形状&#xff0c;以及如何将其定位在世界坐标系中。 建模 计算机图形学研究中的一个重要主题是建模或表示物体的几何形状。…

HarmonyOS ArkTS工程目录结构(Stage模型)

1. ArkTS工程目录结构&#xff08;Stage模型&#xff09; 官方文档&#xff08;https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V2/start-with-ets-stage-0000001477980905-V2&#xff09; 1.1. AppScope AppScope > app.json5&#xff1a;应用的全局配…

高级语言讲义2010计专(仅高级语言部分)

1.编写一程序&#xff0c;对输入的正整数&#xff0c;求他的约数和。 如&#xff1a;18的约数和为1236939 #include <stdio.h>int getsum(int n){int i,sum0;for(i1;i<n;i)if(n%i0)sumi;return sum; } int main(){int sum getsum(18);printf("%d",sum); …

【UE5】游戏框架GamePlay

项目资源文末百度网盘自取 游戏框架 游戏 由 游戏模式(GameMode) 和 游戏状态(GameState) 所组成 加入游戏的 人类玩家 与 玩家控制器(PlayerController) 相关联 玩家控制器允许玩家在游戏中拥有 HUD&#xff0c;这样他们就能在关卡中拥有物理代表 玩家控制器还向玩家提供 …

XSS靶场-DOM型初级关卡

一、环境 XSS靶场 二、闯关 1、第一关 先看源码 使用DOM型&#xff0c;获取h2标签&#xff0c;使用innerHTML将内容插入到h2中 我们直接插入<script>标签试一下 明显插入到h2标签中了&#xff0c;为什么不显示呢&#xff1f;看一下官方文档 尽管插入进去了&#xff0…

腾讯云轻量服务器流量用完了怎么办?停机吗?

腾讯云轻量服务器流量用完了怎么办&#xff1f;超额流量另外支付流量费&#xff0c;流量价格为0.8元/GB&#xff0c;会自动扣你的腾讯云余额&#xff0c;如果你的腾讯云账号余额不足&#xff0c;那么你的轻量应用服务器会面临停机&#xff0c;停机后外网无法访问&#xff0c;继…