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

前情提要

上一节我们讲了如何启动计算机,这一节我们讲如何加载内核,内核是存在于硬盘上的一段程序,要加载这段程序,那么必然需要从硬盘上读取数据,这里我们就需要使用 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.mfbz.cn/a/443715.html

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

相关文章

猫头虎分享已解决Bug || 数据中心断电:PowerLoss, DataCenterBlackout

博主猫头虎的技术世界 🌟 欢迎来到猫头虎的博客 — 探索技术的无限可能! 专栏链接: 🔗 精选专栏: 《面试题大全》 — 面试准备的宝典!《IDEA开发秘籍》 — 提升你的IDEA技能!《100天精通鸿蒙》 …

WordPress 从入门到精通【设置 WordPress】

前言:为方便演示,前几张图使用 Playground 环境截取 如果你还不会部署WordPress,请看下面的链接并使用雨云可视化构建一个WordPress站点: 超简单EP面板搭建WordPress网站教程 - 风屿岛 10 (biliwind.com) 进入仪表盘 在搭建完…

C++内存管理篇

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

mysql-视图,创建表,存储过程,循环,判断实操命令

数据库操作命令在IDEA工具database的console命令 数据库表结构与视图 事务隔离级别RR(REPEATABLE-READ)解决不可重复读演示 mysql-RR隔离级别 -- 查询隔离级别 select transaction_isolation;-- 设置隔离级别 set session transaction isolation level …

基于Kronig-Penney能带模型的MATLAB求解与仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 基于Kronig-Penney能带模型的MATLAB求解与仿真.综合利用 MATLAB提供的求解常微分方程、矩阵行列式、代数表达式化简及绘图等函数 ,可使 Kronig-Penney能带模型分析…

P9238 [蓝桥杯 2023 省 A] 翻转硬币(杜教筛+莫比乌斯)

题目&#xff1a;https://www.luogu.com.cn/problem/P9238 思路&#xff1a; 代码&#xff1a; #define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<string> #include<cstring> #include<cmath> #include<ctime> #include<algo…

信息抽取在旅游行业的应用:以景点信息抽取为例

开源项目推荐 今天先给大家推荐一个开源项目&#xff0c;多模态AI能力引擎平台: 免费的自然语言处理、情感分析、实体识别、图像识别与分类、OCR识别、语音识别接口&#xff0c;功能强大&#xff0c;欢迎体验。 https://gitee.com/stonedtx/free-nlp-api 场景描述 在旅游行业…

酷开科技暖心推荐 酷开系统壁纸模式带来独特视觉享受

一款好看的壁纸能够让人眼前一亮&#xff0c;酷开科技倾心打造的酷开系统壁纸模式&#xff0c;以其独特的美学设计和视觉享受&#xff0c;为消费者提供了一种全新的使用体验。 首先&#xff0c;酷开系统壁纸模式的视觉效果十分出色。它采用了高清的图像质量和细腻的色彩渲染&a…

jvm堆概述

《java虚拟机规范》中对java堆的描述是&#xff1a;所有的对象实例以及数组都应当在运行时分配在堆上。 一个JVM实例只存在一个堆内存(就是new 出来一个对象)&#xff0c;java内存管理的核心区域 java堆区在jvm启动的时候就被创建&#xff0c;空间大小确定。是jvm管理的最大一…

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

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

把握机遇:2024年游戏行业春招提前批全攻略

当前&#xff0c;国内游戏行业正处于高速发展期&#xff0c;各大游戏公司对应届毕业生的人才需求十分旺盛。这一趋势不仅为即将步入职场的学生们提供了广阔的就业前景&#xff0c;也为游戏产业的创新和多元化发展注入了新鲜血液。 在这样的大环境下&#xff0c;2024年春季提前批…

基于qt的图书管理系统----05其他优化

参考b站&#xff1a;视频连接 源码github&#xff1a;github 目录 1 优化借阅记录显示2 时间显示为年月日3 注册接口 1 优化借阅记录显示 现在只能显示部分信息&#xff0c;把接的书名和人的信息全部显示 在sql语句里替换为这一句即可实现查询相关联的所有信息 QString str…

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…

训练验证码之ddddocr一个图文视频教学

目录 一、推荐文章视频一、ddddocr环境配置二、字符集验证码训练三、ocr_api_server服务搭建 一、推荐文章视频 文章原文来自这里&#xff1a;训练验证码-4、ddddocr训练字符验证码 &#xff0c; 原文文章末尾有视频介绍更多内容见训练验证码合集 一、ddddocr环境配置 1.打开…

【漏洞复现】Salia PLCC cPH2 远程命令执行漏洞(CVE-2023-46359)

0x01 漏洞概述 Salia PLCC cPH2 v1.87.0 及更早版本中存在一个操作系统命令注入漏洞&#xff0c;该漏洞可能允许未经身份验证的远程攻击者通过传递给连接检查功能的特制参数在系统上执行任意命令。 0x02 测绘语句 fofa&#xff1a;"Salia PLCC" 0x03 漏洞复现 ​…

300分钟吃透分布式缓存-24讲:Redis崩溃后,如何进行数据恢复的?

Redis 持久化是一个将内存数据转储到磁盘的过程。Redis 目前支持 RDB、AOF&#xff0c;以及混合存储三种模式。 RDB Redis 的 RDB 持久化是以快照的方式将内存数据存储到磁盘。在需要进行 RDB 持久化时&#xff0c;Redis 会将内存中的所有数据以二进制的格式落地&#xff0c;每…

Swift 入门学习:集合(Collection)类型趣谈-上

概览 集合的概念在任何编程语言中都占有重要的位置&#xff0c;正所谓&#xff1a;“古来聚散地&#xff0c;宿昔长荆棘&#xff1b;游人聚散中&#xff0c;一片湖光里”。把那一片片、一瓣瓣、一粒粒“可耐”的小精灵全部收拢、吸纳的井然有序、条条有理&#xff0c;怎能不让…

【C++专栏】C++入门 | 函数重载、引用、内联函数

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;C专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ C入门 | 函数重载、引用、内联函数 文章编号&#xff1a;C入门 / 02 文…

【机器学习】在Python中进行K-Means聚类和层次聚类

Python中聚类算法API的使用指南 聚类分析是数据分析中一种常见的无监督学习方法&#xff0c;通过将相似的对象分组在一起&#xff0c;我们能够识别出数据集中的自然分群。本文将介绍如何使用Python中的聚类算法接口&#xff0c;KMeans和层次聚类方法。 K-Means 聚类 K-Means…

利用 Redis 和 Lua 实现高效的限流功能

简介 在现代系统中&#xff0c;限流是一种重要的机制&#xff0c;用于控制服务端的流量并保护系统免受恶意攻击或请求泛滥的影响。本文将介绍如何利用 Redis 和 Lua 结合实现高效的限流功能。 一、什么是限流 限流指的是对系统中的请求进行控制和调节&#xff0c;确保系统在…
最新文章