篇首语:迎接开源,拥抱成长,加油。。。。。。。。。
最近跟着教程完成了一个十分简单的操作系统,下面是主要步骤和我遇见的坑。
- 首先介绍一下我的安装环境:virtualBox 5.13.0 + ubuntu 20.04 x86_64(uname -a);
- 再查看虚拟机的网络情况,主机和虚拟机互ping一下,看看通不通,这里我遇见的问题是:虚拟机ping主机是通的,但是主机ping虚拟机是不通的,解决方案是:
- 查看虚拟机ip ($ip addr 或是 $ifconfig)都可以查到
inet 后面就是虚拟机的ip,(10.0.2.15)
- 在主机命令行,ping一下这个ip(10.0.2.15) 显示 请求超时;
- 打开虚拟机 -> 设置 -> 网络 ->连接方式,选择桥接网卡;
- $reboot;
- Ctrl+alt+T $ifconfig
- 这时再次查看ip,就变成和windows上同一个网段的了,(我的是 192.168.1.x)
- 再次打开windows cmd ping下,这时是通的,ok!!!
(后面会介绍:连接方式那么多,为啥就桥接好用,其他的连接方式都是啥,为什么不能用,又在何种情况下会用到它们???)
- 主机和虚拟机的网络通了,方便互传文件,那么如何互传文件呢?
多种方式,我用的是ssh ,用的工具软件是 WinSCP ,下面是操作的步骤:
- 查看虚拟机上是否安装ssh服务 $ ssh localhost
- 如果显示(ssh: connection refused )表示没安装
- 先更新已经安装的工具包:$ sudo apt-get update;
- 再安装ssh: $ sudo apt-get install openssh-server
- 如果安装失败,估计是没联网,可以查看2
- 下载WinSCP, 分享个百度云,有需要自取();
- 打开WinSCP,新建站点,在会话填写主机名,用户名和密码,然后登录。
主机名:zhangqi-VirtualBox 用户名:zhangqi
(8) 如果你忘记密码,$passwd 就重置一下吧~;
(9) 至此,安装步骤就完成了,下图是winSCP打开
(备注下:主机->虚拟机: 上传; 虚拟机->主机: 下载)
下面还会去介绍ssh是个啥,为什么它能传输文件,还有哪些宝藏功能。。。
- 有了传文件的工具,就可以把主机的文件传给虚拟机,emmm….我太懒。。。
1-3是准备工作,下面正式开始我们的小小OS之旅。。。
- 首先有个大体流程:
- PC机的引导流程(我理解:启动流程);
看了流程,可能会有一些疑问:
(1) BIOS固件是什么?为什么PC机加电后首先就需要加载它?都干了啥?
(2) 加载BIOS是为加载可引导设备吗?可引导设备是什么样子的,是不是依赖于GRUB,GRUB是不是决定可引导设备是什么?
(3) Hello OS是个什么类型的文件?里面的内容是操作系统吗?都写得是什么?
(4)PC开机,加载引导程序,找到存放OS文件的内存地址,加载,是这样吗?
解答:
复制一段文字…………:
PC 机 BIOS 固件是固化在 PC 机主板上的 ROM 芯片中的,掉电也能保存,PC 机上电后的第一条指令就是 BIOS 固件中的,
它负责检测和初始化 CPU、内存及主板平台,
然后加载引导设备(大概率是硬盘)中的第一个扇区数据,
到 0x7c00 地址开始的内存空间,
再接着跳转到 0x7c00 处执行指令,在我们这里的情况下就是 GRUB 引导程序。
(此处是待填充的空白。。。。。。。)
- Hello OS引导汇编代码(也就是GRUB的引导程序)
下面有些自己的理解。。。
引导程序就是告诉用户要安装OS了,先做哪一步,再做哪一步。
GRUB(GRand Unified Bootloader)多操作系统启动程序,允许用户在计算机内同时拥有多个操作系统。
为什么GRUB引导程序要用汇编?
答:底层语言无外乎是C和汇编,汇编比C更加底层,更底层就意味着,给计算机发指令更加直白,(汇编难点就在于,你要明白1+1=2的在计算机中完整的实现流程,并写出来),C 作为通用的高级语言,不能直接操作特定的硬件,而且 C 语言的函数调用、函数传参,都需要用栈。(我理解:汇编可以直接操作硬件,并且数据可以直接访问寄存器,创建栈内存空间)
汇编学习-----看书王爽的《汇编语言》
这段引导程序都写点啥?
答:(1) 定义GRUB多引导协议头,目的是让GRUB可以识别我们自己写的Hello OS的操作系统,就是按照GRUB的方式来让它认识我们自定义的操作系统;
(2)关掉终端,设定CPU的工作模式;(不懂。。。)
(3)初始化CPU的寄存器和C语言的运行环境;(也就是开始创建栈内存,以及我们用C语言写的操作系统的内容了)
(4)GDT_START开始的,是CPU工作模式所需要的数据。(我写了什么。。。不懂);
这一步最后,我一直在纠结为什么引导,从PC加电到访问准备好CPU所需要的数据,都经历了哪些步骤?于是有个大神的原文如下:
答:在你安装完一个操作系统之后(就是把光盘镜像的文件或者GHOST文件丢到主分区)或者开机后,需要让计算机在开机的时候能识别电脑中的系统,这个过程就是系统引导,计算机系统引导的过程就是在保证硬件设备正常后,计算机利用CPU运行特定程序,通过程序识别硬盘,识别硬盘分区,识别硬盘分区上的操作系统,最后又通过程序启动操作系统。
我理解:说到底,并不是开机了就安装操作系统了,而是需要一步确认(硬件,CPU,硬盘等等都是好的),一步引导,我告诉你哪里可以找到操作系统。问题来了,如果一台裸机,没有OS,怎么去安装OS呢?
(64条消息) 操作系统引导详细过程_Adenialzz的博客-优快云博客_系统引导
还得再看。。。
- Hello OS的主函数
//彭东 @ 2021.01.09
#include "vgastr.h"
void main()
{
printf("Hello OS!");
return;
}
(这里的printf需要自定义,为什么?看下一步)
- 控制计算机屏幕
需求:我们要在屏幕上显示字符,
方案:就要编程操作显卡。
如何操作?
首先,无论何种显卡都支持VESA标准,这种标准下有两种工作模式:字符模式和图形模式。显卡们为了兼容这种标准,不得不自己提供一种叫 VGABIOS 的固件程序。
显卡的字符模式的工作细节:
它把屏幕分成 24 行,每行 80 个字符,把这(24*80)个位置映射到以 0xb8000 地址开始的内存中,每两个字节对应一个字符,其中一个字节是字符的 ASCII 码,另一个字节为字符的颜色值。
//彭东 @ 2021.01.09
void _strwrite(char* string)
{
char* p_strdst = (char*)(0xb8000);//指向显存的开始地址
while (*string)
{
*p_strdst = *string++;
p_strdst += 2;//我理解:完整存储一个字符
}
return;
}
void printf(char* fmt, ...)
{
_strwrite(fmt);
return;
}
- 编译和安装Hello OS
这里编译和安装需要准备nasm和gcc两个编译工具,如果没有自行下载
$sudo apt-get install -y nasm
$sudo apt-get install gcc
编译:
首先nasm是编译.asm汇编文件,命令 $nasm -f entry.asm -o entry.o -w-orphan-labels(后面-w-orphan-labels)表示不显示警告信息,;
然后gcc编译.c, 可以直接 $gcc HelloOS.c -c -o HelloOS.o;
也可以一步步来:其实编译.c程序主要分四步:
第一步:预处理 $gcc HelloWorld.c -E -o HelloWorld.i;
目的是加入头文件,替换宏。
第二步:编译 $ gcc HelloWorld.c -S -c -o HelloWorld.s
包含预处理,将 C 程序转换成汇编程序。
第三步:汇编 $ gcc HelloWorld.c -c -o HelloWorld.o
包含预处理和编译,将汇编程序转换成可链接的二进制程序。
第四步:链接 $ gcc HelloWorld.c -o HelloWorld
包含以上所有操作,将可链接的二进制程序和其它别的库链接在一起,形成可执行的程序文件。
但是如何将多个.o文件链接到一个项目中,这里还需要再看。。。
这里是用$make -f Makefile,直接完成编译,链接,生成.bin文件
下图,讲的很明白了。。。
(6)Make工具
这个后面补充详细的文章,因为它很重要它很重要它很重要!!!
(7)编译
就是最后生成的.bin文件。
(8)安装Hello OS
为什么要将HelloOS.bin文件放到GRUB能找到的地方?
答:因为我们像让它开机时选择HelloOS后显示“HelloOS”,更cool😎一点。
GRUB的路径怎么找?
答:找grub.cfg(/boot/grub)
(65条消息) ubuntu下查找文件位置的方法_慢下去、静下来的博客-优快云博客_ubuntu查找文件所在位置
这篇博客提供不同情况下找文件路径的方法。
对grub.cfg修改插入内容(65条消息) Linux下如何修改grub.cfg_想入非非、的博客-优快云博客_grub.cfg修改
$sudo chmod +w /boot/grub/grub.cfg
$sudo gedit /boot/grub/grub.cfg
然后将下面代码插到最后:
menuentry 'HelloOS' {
insmod part_msdos #GRUB加载分区模块识别分区
insmod ext2 #GRUB加载ext文件系统模块识别ext文件系统
set root='hd0,msdos5' #注意boot目录挂载的分区,这是我机器上的情况
multiboot2 /boot/HelloOS.bin #GRUB以multiboot2协议加载HelloOS.bin
boot #GRUB启动HelloOS.bin
}
这里注意boot目录挂载分区,查询 $df /boot/
文件系统 1K-块 已用 可用 已用% 挂载点
/dev/sda4 48752308 8087584 38158536 18% /
复制大神的原文:
其中的“sda4”就是硬盘的第四个分区(硬件分区选择 MBR),但是 GRUB 的 menuentry 中不能写 sda4,而是要写“hd0,msdos4”,这是 GRUB 的命名方式,hd0 表示第一块硬盘,结合起来就是第一块硬盘的第四个分区。
这里面,什么时挂载,硬盘的分区是什么,一共有几个分区,为什么就选择第5个分区了?(不懂啊。。。)
最后重启Ubuntu,按esc键,结果,就启动了HelloOS,虽然没懂什么,但还是很高兴。。。下面贴个图,分享喜悦…………
篇尾语:感谢彭东大神,感谢上面博客的大佬们。。。。。。