手写简易操作系统(二)--启动计算机

前情提要

在上一部分的内容中,我们已经做好了模拟仿真的整个准备工作,这一节我们就先把计算机启动起来。

一、Bochs配置

1.1、配置启动盘

创建硬盘的工具是bximage,这个工具在我们的Bochs目录下,使用命令行创建硬盘

image-20240309173637499

第一个选择 1,即创建新的硬盘或者软盘

第二个选择 hd,即创建硬盘

第三个选择 flat,即创建flat格式的硬盘,还有一些诸如sparse, growing, vpc or vmware4格式的硬盘。

第四个选择 512,即一个扇区有512字节

第五个选择 60,即硬盘的大小为60MB

第六个选择 hd60M.img,这个是硬盘的名字

1.2、配置启动文件

在bin目录下新建一个启动文件 bochsrc.disk

# 设置内存为32MB
megs: 32# 设置对应机器的BIOS
romimage: file=/home/lyj/bochs/share/bochs/BIOS-bochs-latest 
# 设置对应机器的VGA BIOS
vgaromimage: file=/home/lyj/bochs/share/bochs/VGABIOS-lgpl-latest # 选择启动盘符,默认为从软盘启动,但是这里设置为硬盘,软盘太古老了
boot: disk # 设置日志文件的输出
log: bochs_out.log# 关闭鼠标功能,打开键盘功能,并且设置键盘的映射
mouse: enabled=0 
keyboard: keymap=/home/lyj/bochs/share/bochs/keymaps/x11-pc-us.map # 硬盘设置
ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 
ata0-master: type=disk, path="/home/lyj/bochs/bin/hd60M.img", mode=flat

其中的大部分设置都做了详细的注释,这里我们对硬盘部分做出一些更详细的解释

  • enabled=1:表示 ATA0 控制器被启用。这意味着 Bochs 将会模拟一个 ATA0 控制器,并允许虚拟机使用这个控制器来访问硬盘或光驱设备。

  • ioaddr1=0x1f0:表示 ATA0 控制器的 I/O 端口地址。在计算机体系结构中,I/O 端口用于与外部设备进行数据交换。这里指定了 ATA0 控制器的主要 I/O 端口地址为 0x1f0。

  • ioaddr2=0x3f0:表示 ATA0 控制器的备用(secondary)I/O 端口地址。有些设备可能需要额外的 I/O 端口进行通信,这里指定了 ATA0 控制器的备用 I/O 端口地址为 0x3f0。

  • irq=14:表示 ATA0 控制器的中断请求线(IRQ)。中断请求线用于处理硬件设备发出的中断信号,这里指定了 ATA0 控制器的中断请求线为 14。

ata0可以挂载两个硬盘,其中一个是主盘一个是从盘。这部分内容我们会在讲解硬盘时详细说。

1.3、启动Bochs

./bochs -f bochsrc.disk

在bochs的命令行中先输入 6,即开始仿真

在输入 c,即开始执行

然后我们就看到了下面的画面

image-20240309173917596

系统提示没有可引导的启动设备,也就是我们设置的硬盘是一个空的硬盘,里面并没有程序可以执行,所以直接报错退出了。接下来我们让整个程序先能跑起来。

二、MBR主引导记录

好了,我们要开始写代码了,在写代码之前先普及一点小知识,x86架构的处理器,由于历史原因,一开始是先进入实模式,再进入保护模式的。实模式下,只有20根地址线,因此只能访问到2的20次方Byte的数据,也就是1MB。这1MB又被分为了几个部分,我们可以看一下

image-20240309193017875

这一部分如果我们学过《汇编语言》或者《微机原理》之类的课程是比较好理解的

2.1、BIOS启动

开机的一瞬间,BIOS被启动,BIOS中的代码就存在于 0xF0000~0xFFFFF 这个地址了,但实际上这个地址不是内存,是的,你没听错,不是内存,是一块ROM。

为了统一管理计算机中的端口,内存,ROM等等设备,计算机将这些东西统一了,就像访问内存那样去访问这些资源。

所以在开机的一瞬间,CPU的cs:ip寄存器被强制初始化为0xF000:0xFFF0,这样就可以直接执行BIOS中的程序。BIOS开始检测内存,显卡等外设信息,当外设准备好后,开始在 0x000~0x3FF 处建立中断向量表,这些中断就是BIOS提供的基础功能,可以帮助我们操作系统做一些基础操作。

做完这些,BIOS的使命就要结束了,最后的一点任务,校验启动盘中位于0盘0道1扇区(也就是LBA地址为0的扇区)的内容,如果此扇区末尾的两个字节分别是魔数 0x550xaa,BIOS便认为此扇区中确实存在可执行的程序,并把这个扇区的内容加载到物理地址 0x7c00 的内存中,一个扇区的大小我们在上一节中设置硬盘扇区大小中设置过了,是512B。

最后BIOS通过跳转指令 jmp 0:0x7c00 跳转到 0x7c00 的地址开始执行用户的程序,这里用户的程序也就是我们的操作系统了。

问:为什么是魔数 0x550xaa

答:BIOS中设置好的,也是大家公认的,如果你自己写BIOS的话,也可以设置为别的,但是这就不通用了。

问:为什么是 0x7c00 的地址?

答:这也是一个写死了的地址,王八的屁股,规定。

2.2、编写MBR,并编译

这里我们还是用到了BIOS中自带的中断。代码如下所示

; os/src/boot/mbr.s
; 设置开始的地址,并且初始化寄存器
SECTION MBR vstart=0x7c00         mov ax,cs      mov ds,axmov es,axmov ss,axmov fs,axmov sp,0x7c00; 利用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 0x10; 获取光标位置 
; AL = 0x03 功能号
; bh 寄存器存储的是待获取光标的页号mov    ah, 3mov    bh, 0int    0x10; 打印字符串
; BP 字符串地址,BP需要通过AX访问,不能直接给BP内存数据
; AL = 0x13 功能号
; AL = 0x01 显示字符串,光标跟随移动
; CX = 0x03 字符串长度
; BH = 0x00 要显示的页号
; BL = 0x02 字符属性,属性黑底绿字mov ax, messagemov bp, axmov ax, 0x1301mov cx, 0x03mov bx, 0x02int 0x10	; 循环等待jmp $            
; 要显示的字符串message db "MBR"
; 将510个字节中剩余的空间填充为0
; $ 是当前地址
; $$ 是本节开头地址,也就是0x7c00times 510-($-$$) db 0db 0x55,0xaa

其实还是很简单的,就像是调用函数,然后我们往那些指定的寄存器中添加数据就可以了。

编译一下

nasm -o bin/mbr.bin src/boot/mbr.s

查看一下确实是512字节

image-20240309201604822

然后我们将这个文件直接通过dd指令存放到我们之前生成的虚拟硬盘中的0盘0道1扇区

dd if=./bin/mbr.bin of=~/bochs/bin/hd60M.img bs=512 count=1 conv=notrunc

然后运行Bochs

~/bochs/bin/bochs -f ~/bochs/bin/bochsrc.disk

可以看到,我们成功的运行起来了

image-20240309202030610

2.3、改进MBR,直接操作显卡

我们将输出字符串直接通过操作显存来完成。通过上表我们可以得知,显存是从0xB8000~0xBFFFF,范围是32KB,一屏可以显示2000个字符,显示器上的每个字符占2字节大小,故每屏字符实际占用4000字节。这样,我们的32KB的显存可以容纳8屏的数据。

屏幕上每个字符的低字节是字符的ASCII码,高字节是字符属性元信息。

image-20240309204513916

其中各个位的搭配为

image-20240309210135540

我们将程序修改为

; os/src/boot/mbr.s
; 设置开始的地址,并且初始化寄存器
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	; 00001111b 即背景色为黑,字体为白,不闪烁 mov byte [gs:0x02],'B'  ;mov byte [gs:0x03],0x0F	; mov byte [gs:0x04],'R'  ;mov byte [gs:0x05],0x0F	;; 循环等待jmp $            
; 要显示的字符串message db "MBR"
; 将510个字节中剩余的空间填充为0
; $ 是当前地址
; $$ 是本节开头地址,也就是0x7c00times 510-($-$$) db 0db 0x55,0xaa

之前的编译,写入硬盘,启动程序,这里也可以简单点写个脚本

# os/run.sh
# 编译mbr
nasm -o bin/mbr.bin src/boot/mbr.s # 复制mbr二进制程序到硬盘
dd if=./bin/mbr.bin of=/home/lyj/bochs/bin/hd60M.img bs=512 count=1 conv=notrunc# 启动仿真
/home/lyj/bochs/bin/bochs -f /home/lyj/bochs/bin/bochsrc.disk 

直接启动脚本

image-20240309210444176

结束语

好了第二章已经结束了,这一章我们生成了需要的硬盘以及写了一个简单的MBR引导程序,但是我们的内核还在硬盘中(实际上还没有写),下一章我们将在MBR中实现一个内核加载器出来。

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

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

相关文章

华为新发布磁电存储“王炸”,到底是什么?

最近,在巴塞罗那举行的2024年世界移动通信大会(MWC24)上,华为数据存储产品线总裁周彼得博士介绍了这款即将面世的产品。他向听众表示,与磁带存储相比,该设备可以降低20%的总连接成本,而与硬盘相…

如何在Linux上为PyCharm创建和配置Desktop Entry

在Linux操作系统中,.desktop 文件是一种桌面条目文件,用于在图形用户界面中添加程序快捷方式。本文将指导您如何为PyCharm IDE创建和配置一个 .desktop 文件,从而能够通过应用程序菜单或桌面图标快速启动PyCharm。 步骤 1: 确定PyCharm安装路…

c#触发事件

Demo1 触发事件 <Window x:Class"WPFExample.MainWindow"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml"Title"WPF Example" Height"600" Wi…

高度塌陷问题及解决

什么情况下产生 (when 父盒子没有定义高度&#xff0c;但是子元素有高度&#xff0c;希望用子盒子撑起父盒子的高度&#xff0c;但是子盒子添加了浮动属性之后&#xff0c;父盒子高度为0 <template><div class"father"><div class"son"&…

前端加密面面观:常见场景与方法解析

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

mtk平台ATF介绍

1、链接地址 uboot ATF 2、工具链 ARM 64位平台需要aarch64工具链&#xff0c;可以在staging_dir/toolchain- aarch64_xxxxx中找到。另外dtc工具来为ATF编译.dts文件&#xff0c;一般在 Ubuntu中的device-tree-compiler包&#xff0c;编译后的u-boot/kernel源代码树中的脚本…

【MySQL】MySQL 的 SSL 连接以及连接信息查看

MySQL 的 SSL 连接以及连接信息查看 在上篇文章中&#xff0c;我们学习过 MySQL 的两种连接方式&#xff0c;回忆一下&#xff0c;使用 -h 会走 TCP 连接&#xff0c;不使用 -h 可以使用另两种方式来走 UnixSocket 连接。我们就接着这个话题再聊点别的&#xff0c;首先要纠正一…

springMVC自定义异常处理器

目录 &#x1f331;使用原因 &#x1f333;优点 &#x1f331;实现 &#x1f333;自定义一个异常 &#x1f333;异常处理 &#x1f333;测试 使用原因 系统中会有各种各样的&#xff0c;意料之中和意料之外的结果&#xff0c;我们并不能做到完全针对每个异常时刻做出针对…

图像处理ASIC设计方法 笔记7 图像存储SPRAM控制

(一)图像存储SPRAM控制 P83 模块三 图像存储SPRAM控制 输入的图像要存放在这个模块中。这个SPRAM的数据组织和读/写控制是设计的重点之一。 SPRAM是多个块的形式。用的是单端口RAM,采用分时读或者写(读写不同时),起到双端口的效果。应该用的是单端口RAM(Single-por…

【鸿蒙开发】第十七章 Web组件(一)

1 Web概述 Web组件用于在应用程序中显示Web页面内容&#xff0c;为开发者提供页面加载、页面交互、页面调试等能力。 页面加载&#xff1a;Web组件提供基础的前端页面加载的能力&#xff0c;包括&#xff1a;加载网络页面、本地页面、html格式文本数据。 页面交互&#xff1a…

WebSocket:实现客户端与服务器实时通信的技术

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

RHCE——二、时间管理器与远程登陆服务

RHCE——二、时间管理器与远程登陆服务 一、chrony服务器1、简介重要性Linux的两个时钟设置日期时间timedatectl命令设置date命令设置 NTPChrony介绍 2、安装与配置安装&#xff1a;Chrony配置文件分析实验1实验2重启报错解决方法 二、远程登录服务 一、chrony服务器 1、简介 …