手写简易操作系统(三)--加载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,axmov es,axmov ss,axmov fs,axmov sp,0x7c00mov ax,0xb800mov gs,ax; 利用0x06号功能实现清理屏幕
; AL = 0x06 功能号
; AL 上卷的行数(如果为0,表示全部)
; BH 上卷行属性
; (CL,CH) = 窗口左上角的(X,Y)位置,这里是 (0,0)
; (DL,DH) = 窗口右下角的(X,Y)位置,这里是 (80,25)mov    ah, 0x06mov    al, 0x00mov    bh, 0x7mov    bl, 0x00mov    cx, 0           mov    dx, 0x184fint    0x10             ; int 0x10mov 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	       ; 备份eaxmov di,cx		   ; 备份cxmov dx,0x1f2       ; 设置要写入端口,即读取端口数mov al,cl          ; 设置要读取扇区数out dx,al          ; 设置mov eax,esi	       ; 恢复eaxmov dx,0x1f3       ; 设置要写入端口,即LBA低地址              out dx,al          mov cl,8           ; ax右移八位   shr eax,clmov dx,0x1f4       ; 设置要写入端口,即LBA中地址 out dx,alshr eax,cl         ; ax右移八位   mov dx,0x1f5       ; 设置要写入端口,即LBA高地址 out dx,alshr eax,cl         ; ax右移八位and al,0x0f	       ; 保留低4位,设置高4位为 0000or al,0xe0	       ; 保留低4位,设置高4位为 1110mov dx,0x1f6out dx,almov dx,0x1f7       ;mov al,0x20        ; 读扇区指令               out dx,al.not_ready:            ; 未准备好nop                ; 不执行任何指令,占用一个机器周期in al,dx           ; 查看读取状态and al,0x88        ; 与 10001000 做与运算cmp al,0x08        ; 比较第三位和第七位jnz .not_readymov ax, di         ; 要读的扇区数mov dx, 256        ; 乘以256,即要读多少次mul dxmov cx, ax	       ; 将要读的次数传给cxmov dx, 0x1f0      ; 要读的端口号.go_on_read:in ax,dx           ; 向ax中读,一次读两个字节mov [bx],ax        ; 将ax中数据给bx地址的内存add bx,2		   ; bx中内存地址加2loop .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.mzph.cn/news/733258.shtml

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

相关文章

docker部署springboot jar包项目

docker部署springboot jar包项目 前提,服务器环境是docker环境,如果服务器没有安装docker,可以先安装docker环境。 各个环境安装docker: Ubuntu上安装Docker: ubuntu离线安装docker: CentOS7离线安装Docker&#xff1…

可视化场景(2):电商大屏-引爆业绩,直观呈现

hello,我是贝格前端工场,本期分享可视化大屏在电商领域的应用,如需要定制,可以与我们联络,开始了。 电商领域的可视化大屏可以提供实时的销售数据、用户行为分析、库存管理等信息,帮助企业实时监控经营状况…

不知道吧,腾讯云轻量应用服务器使用有一些限制!

腾讯云轻量应用服务器相对于云服务器CVM是有一些限制的,比如轻量服务器不支持更换内网IP地址,不支持自定义私有网络VPC,内网连通性方面也有限制,轻量不支持CPU内存、带宽或系统盘单独升级,只能整个套餐整体升级&#x…

Anthropic 公司最新宣布,他们的 AI 聊天机器人模型击败了 OpenAI 的 GPT-4

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…

Unity Text文本实现滚动跑马灯效果

在一些公告上我们经常会看到文字滚动跑马灯的效果。 那么在Unity上如何实现? 1、首先创建一个Text(或者TextMeshPro)组件,然后输入需要显示的文本内容,如图: 2、编写控制脚本TextRoll.cs: using System.Collections…

钉钉h5应用 globalthis is not defined vite client

钉钉h5应用 globalthis is not defined vite client problem 背景 钉钉h5应用使用 vue3 vite 构建的前端工程 问题 h5页面在pc端浏览器和pc端钉钉打开正常h5页面在移动端钉钉打开异常 页面空白 通过调试工具找到报错信息 globalthis is not defined vite client reason …

ULTRAL SCALE FPGA TRANSCEIVER速率

CPLL支持2-6.25速率 QPLL支持速率 实际使用CPLL最高可以超过这个,QPLL最低也可以低于这个,xilinx留的阈量还是比较大。

这是谁的女儿?其母亲早已红过头了,现在小小年纪的她也爆红网络,没想到吧?

这是谁的女儿?其母亲早已红过头了,现在小小年纪的她也爆红网络,没想到吧? 原来,作母亲的她在红极一时后似乎沉寂了下来,没想到她11岁的女儿近年来也在社交媒体上走红,她为何也成了小网红呢&…

数字化转型导师坚鹏:大模型的应用实践(金融)

大模型的应用实践 ——开启人类AI新纪元 打造数字化转型新利器 课程背景: 很多企业和员工存在以下问题: 不清楚大模型对我们有什么影响? 不知道大模型的发展现状及作用? 不知道大模型的针对性应用案例? 课程…

C# 高级特性(十一):多线程之async,await

之前使用Thread和Task启动多线程时都会遇到一个麻烦,就是如何反馈结果。在代码里就是如何设计回调函数。如果带界面还得考虑UI线程的问题。 而使用async,await可以达到两个效果。 1 不用设计回调函数,直接按单线程的格式写。 2 不用考虑UI…

【决策树】预测用户用电量

决策树预测用户用电量 文章目录 决策树预测用户用电量  👉引言💎一、 数据预处理数据预处理初步数据分析 二、 机器学习算法决策树回归预测用电量决策树模型介绍:回归预测 三、 可视化结果四、 数据分析与结论代码如下 👉引言&a…

代码随想录算法训练营第四天|24.两两交换链表中的节点、19.删除链表的倒数第N的节点、07.链表相交、142.环形链表II

代码随想录算法训练营第四天|24.两两交换链表中的节点、19.删除链表的倒数第N的节点、07.链表相交、142.环形链表II 24.两两交换链表中的节点 给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成…

Vue+OpenLayers7入门到实战:OpenLayers7点聚合(聚散点)功能,地图缩小显示聚集数量,点击聚集点散开和地图放大后显示要素图片

返回《Vue+OpenLayers7》专栏目录:Vue+OpenLayers7入门到实战 前言 本章介绍如何使用OpenLayers7在地图上实现地图点聚合(聚散点)功能,实现地图缩小显示聚集数量,点击聚集点和地图放大后显示要素对应icon图片的功能。 二、依赖和使用 "ol": "7.5.2"…

猫头虎分享已解决Bug || 云服务中断:CloudOutage, CloudProviderError

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

markdown页面宽度放宽

变成以上样式 ------------------------------------------------ 然后最后一行加上 #write{ max-width: 90%; } /* 调整源码正文宽度 */ #typora-source .CodeMirror-lines { max-width: 90%; } /* 调整输出 PDF 文件宽度 */ media print { #write{ max-w…

图|dfs bfs|最小生成树|最短路|一篇搞定图的所有知识点

文章目录 图前言项目代码仓库图的基本概念图的表示方法邻接矩阵邻接表图的一些相关概念 图的遍历bfsdfs如果给的图不是连通图? 最小生成树Kruskal算法Prim算法 最短路径单源最短路径--Dijkstra算法单源最短路径--Bellman-Ford算法多源最短路径--Floyd-Warshall算法 …

WiFi模块助力少儿编程:创新学习与实践体验

随着科技的飞速发展,少儿编程已经成为培养孩子们创造力和问题解决能力的重要途径之一。在这个过程中,WiFi模块的应用为少儿编程领域注入了新的活力,使得学习编程不再是单一的代码教学,而是一个充满创新与实践的综合性体验。 物联网…

Python快速入门系列-2(Python基础语法)

第三章:Python基础语法 3.1 变量与数据类型3.1.1 变量的定义与赋值3.1.2 数据类型3.1.3 类型转换 3.2 注释与缩进3.2.1 注释3.2.2 缩进 3.3 条件语句与循环结构3.3.1 条件语句3.3.2 循环结构 3.4 函数与模块3.4.1 函数3.4.2 参数和返回值3.4.3 模块3.4.4 标准库中的…

链表|142.环形链表

ListNode *detectCycle(ListNode *head) {ListNode *fast head, *slow head;while (fast && fast->next) {// 这里判断两个指针是否相等,所以移位操作放在前面slow slow->next;fast fast->next->next;if (slow fast) { // 相交&#xff0c…

考研复试要想顺利通关,务必掌握的一些问题

亲爱的学弟学妹们,大家好! 我是研一的学姐,深知考研路上的艰辛与不易。如今,为了回馈广大考研学子,我决定将自己精心整理的考研复试资料拿出来与大家分享,希望能为你们的复试之路添砖加瓦,助你…