- CPU:I386
- 内存:32MB
- 汇编代码:x86(NASM)+ AT&T语法格式
- 内存布局(前1MB):
- 寄存器:
计算机类型: Deepin or Ubuntu20 or MacOS
sudo apt-get update
sudo apt-get install git nasm bximage gcc qemu-system-i386 qemu-utils
sudo apt-get install gdb # debug using
git clone [email protected]:Huzhiwen1208/Transition-OS-Dev.git
cd Transition-OS-Dev
make build # build project
make run # execute the project
make debug # should use vscode launch.json with gdb
- 我决定采用驼峰式的代码风格,在C语言中用驼峰式或许非常别扭,但是我还是决定用它。这有点像Java。
- 在代码中尽量使用
const u32 MAX = 1024;
来代替宏定义#define MAX 1024
,这样做是有缺点的,它会带来更大的运行时开销(多头文件使用)。但是可以规避#define MAX 256 * 4
这种容易出错的定义。而且我更想做的和C语言不一样,这也是个大胆的尝试。并且把所有的常亮,枚举都抽取到common
模块中。 - 不使用
int, long long, unsigned int...
,而是使用i32, i64, u32...
代替。这有点像Rust。 - 在项目文件布局上,我采用了新的模式,每个模块
modelName
都有三个头文件modelName.h, type.h, method.h
。其中我们只使用modelName.h
作为导出(这有点像Rust),其内容框架是// modelName.h #pragma once #include "type.h" #include "method.h" // type.h #pragma once #include "../common/common.h" /// @brief 使用到的struct类型,以及其他类型定义 // method.h #pragma once #inlude "type.h" /// @brief 对外暴露的方法,功能
- 整体的开发过程,会尽量解耦,并且采用需要什么添加什么的逻辑,所以前期可扩展性要好(虽然不是商业化工程开发)
- 每个内容块都会单独开个分支,每个分支对应了一个README.md中的二级标题。其中所有的资源采用垂直记录。分支只能采用PR形式提交到master,并做好合并说明。我们保留每一个分支,所以在Merge时,需要Squash Commits(有可能并没有Squash,hhh)。这样可以在master上看到有多少个模块合入,在每个具体分支上可以看Commit信息。
- feat/xxx: 一个新的xxx功能分支开发
- fix/xxx: 修复xxx功能或模块
- 对应分支:feat/entry-kernel
- 内容概述:实现了从裸机(CPU,内存,硬盘)进入内核。
- 详情链接:进入内核文字描述
在你的虚拟机(或者物理机,总之是你的运行代码的物理机不是远程开发机)上执行make run
,你会看到类似下图的界面,那么恭喜你你的初始环境搭建好了。当然,如果出现难以解决的问题,请联系我的邮箱[email protected]
。我会把它贴在FAQ中。如果我遇到什么问题,也会分享到FAQ中。
- 对应分支:feat/console-and-memory
- 内容概述:实现了内核控制台输出,日志输出,还进行了物理页帧分配管理器初始化,使用伙伴算法实现内核堆内存管理。
- 详情链接:文本显存和内存管理初步
在你的虚拟机(或者物理机,总之是你的运行代码的物理机不是远程开发机)上执行make debug
,并在main.c
中打上断点,调试到执行完最后一行代码,查看globalBuddyAllocator
中的结点数,如果是两个,那么恭喜你实现了输出和内存管理初步。后续会使用键盘中断实现输入。当然,如果出现难以解决的问题,请联系我的邮箱[email protected]
。我会把它贴在FAQ中。如果我遇到什么问题,也会分享到FAQ中。
- 对应分支:feat/int
- 内容概述:实现了中断处理、特权级切换以及进程管理初步。
- 详情链接:中断和特权级
在你的虚拟机(或者物理机,总之是你的运行代码的物理机不是远程开发机)上执行make run
,你会看到类似下图界面,那么恭喜你实现了中断处理和特权级切换。后续会实现一些经典的系统调用。当然,如果出现难以解决的问题,请联系我的邮箱[email protected]
。我会把它贴在FAQ中。如果我遇到什么问题,也会分享到FAQ中。
- 对应分支:feat/mm
- 内容概述:实现了分页。
- 详情链接:内存映射-分页
- 对应分支:feat/fork-related
- 内容概述:我们实现了系统调用
fork
,exit
,wait
。这可以很容易的实现子进程创建,但是我们没有实现copy-on-write,后续有兴趣可以补充下。 - 详情链接:创建子进程
在你的虚拟机(或者物理机,总之是你的运行代码的物理机不是远程开发机)上执行make run
,你会看到类似下图界面,那么恭喜你实现了子进程的创建并了解了进程树的概念。这为后续实现多任务的加载和执行提供了便利。当然,如果出现难以解决的问题,请联系我的邮箱[email protected]
。我会把它贴在FAQ中。本章节我遇到的一个问题是:在fork-复制页表步骤中,我们是不可以复制内核页表的,因为这会导致我们的内核页表等值映射失效,从而在设置完CR3寄存器后会出现错误,这个需要自行体会下
- 对应分支:feat/device-disk
- 内容概述:我们创建了IDE的两个磁盘(主从各一个),从盘会在后面用来加载文件系统。我们还创建了设备表,但是我们没有把显示屏和键盘安装成设备(可以很容易地安装下)。
- 详情链接:设备安装-IDE磁盘
在你的虚拟机(或者物理机,总之是你的运行代码的物理机不是远程开发机)上执行make debug
,并把断点打在main.c:21
,并看到如下图1;再执行make run
,看到如下图2。那么恭喜你完成了磁盘设备的安装和读写。这为后续文件系统的实现打下了基础。当然,如果出现难以解决的问题,请联系我的邮箱[email protected]
。我会把它贴在FAQ中。
- Mac和Ubuntu中的bximage命令中,需要使用-func代替-mode来创建硬盘,而Deepin只需要使用-mode选项。
- 在本操作系统开发中,我们关闭了所有的warning(据说linux开发把所有的warning看成error)。并且数组下标越界是没有Warning和Error的,所以在开发中如果出现了下标越界,可能访问到其他我们并不想读/写的数据,所以需要严谨对待数组下标越界。
- 在Deepin系统中GDB无法进入汇编代码单步调试,经调研发现GDB版本比较旧,但是Deepin并不支持源码安装的高版本GDB。所以使用了mac版的Makefile,只需要在macOS执行
make debug-mac
即可在Mac上进行汇编单步调试。不知道为什么在做fork
那一节的时候gdb可用了,所以就不维护Mac的Makefile了。 - 如果不显式的加载TSS段,而只是简单的放在GDT中,CPU会找不到TSS位置,从而在用户态系统调用时会导致TSS invalid之类的错误。