# 设计思路

#### 语言上

​		在语言上，我们的系统完全采用C++进行开发，因此在实现的过程中，不会拘泥于各教程中C语言的形式，而会考虑灵活采用对应的C++特性。例如，我们没有实现printf，这在其他C语言系统中几乎是必实现的一个内容，不过我们认为C++的cout实现起来会更容易且易用，并为其添加了多种强大功能，详细介绍见0x81的KOUT文档。

​		我们也充分利用构造函数和析构函数，提供了已于使用的临界区保护方案，调用栈调试器等功能。因为它与变量的生命周期相关联，因此可以在需要利用这些特性的地方使用。

​		对于直接指认内存布局为某种结构体/类的情况，这时构造函数和析构函数不会被调用，因此我们约定编写成员函数Init和Destroy用于充当构造和析构的功能，即使用时需要主动调用这两个函数。

​		C语言的一个强大功能是宏，我也是很喜欢宏的，可以用于实现很多单纯语法做不到的东西，不过其中C++语法提出改进的方面，我们采用C++的写法，例如定义函数、常量、标志等采用内联函数、常量表达式等来实现，这样能保证接受类型检查，并且受到命名空间的约束，不容易出错，更好管理。



#### 内核对象抽象

​		内核里的各种结构的设计我们会尽量抽象成类，将其相关的操作作为成员函数，这样结构清晰，易于维护和使用。对于一些特定的类，例如文件系统里的文件、文件系统等，则是会作为基类（或接口类），用于屏蔽具体实现差异，而这些基类也只提供有必要的功能，不会随意增加相关性不够的功能。

​		在类的权限控制上，我们基本只使用protected和public的成员权限控制，继承仅使用public，其原因一方面在于我们认为继承者是可以相信的，认为他对基类有足够的了解，另一方面是因为我们认为我们对基类的设计还需要探索学习，所以要在派生下来的时候探索基类设计方法。



#### 接口设计

​		我们的接口设计的想法是，要使用的时候感觉语义自然而灵活。例如在我们虚拟内存的设计中，有两个方法是Enter()和Leave()，其含义与名字相对应，即进入一个虚拟内存空间和离开一个虚拟内存空间；在我们进程的设计中，有Run()、Rest()、Start()等方法，分别表示进程运行、进程休息、进程从某状态准备开始执行。那么进程切换就可以理解成这样一个过程，首先是"进入"(Enter)到对方的地址空间，然后自己”休息“(Rest)让对方”执行"(Run)这样一个过程，概念上比较清晰。



#### 类型相关设计

​		C++对于类型的要求比C语言更为严格，我们遵从这一想法，对不同的东西使用不同的类型，例如所有的错误都是用ErrorType这一类型，并且只返回定义了的Error枚举。在模板工具箱的使用上也有相关想法的体现，我们使用模板实现了泛型的Memset，Memcpy等，一方面效率高，另一方面适用性更广。

​		另一方面，很多教程和例子中喜欢用宏来定义各种符号量，我们选择采用枚举来实现，这样方便放入命名空间或类内部进行管理，并且在部分情况下可以利用自动编号而无需手动编号，也可以在需要的时候给它加上强类型要求。



#### 一些通用的成员命名规则

​		全局性的变量命名规则为大驼峰式命名，即每个单词的首字母大写直接拼在一起。对于某个简单的量，需要被外部获取，会提供GetXXX方法，虽然看上去多次一举，但是以后如果需要增加额外流程则会很有帮助。类内成员Flags一般用来按位表示对象的属性，其属性用枚举来描述并大多以"F_"作为前缀。

​		对于表示大小的量，如果是字节，则命名为size，如果是表示数量，则命名为count，避免size的二义性。



#### 进线程设计

​		在我们的PAL_OS中，目前仅实现了Process类，与Linux类似，我认为线程可以通过对进程共享同一地址空间来实现，因此一个Process对象就对应着一个执行流，无论是用户进程、用户线程、还是内核线程，都是通过同一个类实现的，这样在后续添加或修改功能时就具有统一性，不至于混乱。进程设计上必须属于一个进程管理器，被统一管理，目前进程管理器系统中只有一个，以后可能会扩展成多个。与Linux不一样的是，我们不强制要求进程必须拥有父进程，这样新创建出来的进程不需要父进程的等待就会自行销毁(也可以认为就是调度器的子进程)，从而避免僵尸进程的问题，因为我认为有很多进程与父进程关系没那么紧密的。进程其他还拥有相关属性，如栈、堆、执行时间、文件表、等待信号量等。具体设计详见0x3X章节文档。



#### 虚拟内存设计

​		虚拟内存总体上最重要的类是虚拟内存空间（Virtual Memory Space，简称VMS），VMS代表整个64位的逻辑地址空间。VMS与一个根页表相对应，因此，可以认为切换根页表就是切换VMS。此外，VMS的工作即是对虚拟内存区域（Virtual Memory Region，简称VMR）进行管理，VMR是VMS中的一个可用区间，标记了这段区间的属性，如读写权限等。整个VMS即是由若干的VMR组成的链表构成的。具体描述可以见对应文档0x42。



#### 文件系统设计

​		文件系统我们进行了充分的抽象和分层设计。目前有4个类，分别为虚拟文件系统管理器(VirtualFileSystemManager 简称VFSM)、虚拟文件系统(VirtualFileSystem 简称VFS)、文件结点(FileNode)、文件句柄(FileHandle)。

​		全局来看，整个目录树由VFSM进行管理，它负责管理所有打开的文件结点和VFS，VFS实际上也是作为一个子树挂在全局的大树上。全局的目录树的结点即是FileNode，进程要使用文件时会使用FileNode来获得一个引用它的FileHandle，读写操作通过FileHandle进行，在FileHandle里会对读写权限进行限制，也会记录读写的位置。

​		对于具体的文件系统，如FAT32，实现者需要继承VFS和FileNode，实现具体的文件系统相关派生类，从而将自己的数据放在派生类里，通过虚函数提供给基类。具体方案详见0x5X章节文档。



#### 系统调用设计

​		系统调用的实现我们的想法是，对于已经有的功能，我们和给出的Syscall要求进行对接，对于不完善的功能，我们在参考了Syscall 的要求后进行自己的设计，然后进行对接。这样的优点是我们的设计自由度大，可以按自己的想法实现一些内容，但缺点是可能一些Syscall不太好对接上，因此需要通过一些Trick来实现或部分实现。具体设计细节见0x6X章节文档。

​		另一方面，我们参考了Windows调用子系统模块的想法，预计设计调用子系统模块，从而对各类不同的ABI进行兼容。



#### 基础设施库设计

​		我们在实现操作系统的过程中，取消使用了标准库，即添加`-nostdlib`选项，因此我们需要自己实现一套基础设施，包括输入输出、字符串操作、调试工具、模板工具箱等。如果一个基础设施完全不依赖外部库，并且是模板实现的，则放到模板工具箱中，其他的则分是否需要外部库放入到不同的文件中，这样便于移植到除了我们系统以外的各个地方。详细设计方案见0x8X章节文档。



#### 部分机制的设计

​		部分机制在设计的时候，我们不完全按照Linux的方案来处理，我们尝试探索各种不同的设计方案，并用我们设计的方案来实现所需的系统调用。我们希望在实现所需功能的情况下，打造具有自身特色的操作系统。



--------------------

By：qianpinyi

2022.06.04