Skip to content

Commit

Permalink
comment
Browse files Browse the repository at this point in the history
Signed-off-by: digmouse233 <[email protected]>
  • Loading branch information
anjieyang committed Sep 25, 2021
1 parent b1ad5a8 commit 1714b65
Show file tree
Hide file tree
Showing 66 changed files with 2,817 additions and 1,279 deletions.
25 changes: 16 additions & 9 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,41 +1,48 @@

# This file is a part of Simple-XX/SimpleKernel (https://github.com/Simple-XX/SimpleKernel).
# This file is a part of Simple-XX/SimpleKernel
# (https://github.com/Simple-XX/SimpleKernel).
# Based on https://github.com/SynestiaOS/SynestiaOS
# CMakeLists.txt for Simple-XX/SimpleKernel.
# CMake 入口

# Set minimum cmake version
# 设置最小 cmake 版本
cmake_minimum_required(VERSION 3.10)

# skip cmake compiler check
# 跳过编译器检查
set(CMAKE_C_COMPILER_WORKS TRUE)
set(CMAKE_CXX_COMPILER_WORKS TRUE)

# 设置项目名与使用的语言
project(SimpleKernel LANGUAGES CXX ASM)

# 禁止原地编译
if(${SimpleKernel_SOURCE_DIR} STREQUAL ${SimpleKernel_BINARY_DIR})
message(FATAL_ERROR "In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there.")
endif()

# Set C gnu11
# 设置使用的 C/C++ 版本
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)

# Set cmake moudle path
# 设置辅助 cmake 脚本路径
set(CMAKE_MODULE_PATH "${SimpleKernel_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})

# Set arch
# 设置 arch
include(${SimpleKernel_SOURCE_DIR}/cmake/arch_detector.cmake)
# Set header files
# 引入添加头文件函数
include(${SimpleKernel_SOURCE_DIR}/cmake/header_files.cmake)
# Find asm source files
# 引入添加汇编文件函数
include(${SimpleKernel_SOURCE_DIR}/cmake/find_asm_files.cmake)

# 设置输出路径
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)

# Set kernel name
# 设置内核名称
set(KernelName kernel.elf)

# 设置 src 路径
set(SimpleKernel_SOURCE_CODE_DIR ${SimpleKernel_SOURCE_DIR}/src)
# 跳转到 SimpleKernel_SOURCE_CODE_DIR 下的 CMakeLists
add_subdirectory(${SimpleKernel_SOURCE_CODE_DIR})
11 changes: 9 additions & 2 deletions cmake/arch_detector.cmake
Original file line number Diff line number Diff line change
@@ -1,21 +1,28 @@

# This file is a part of Simple-XX/SimpleKernel (https://github.com/Simple-XX/SimpleKernel).
# This file is a part of Simple-XX/SimpleKernel
# (https://github.com/Simple-XX/SimpleKernel).
# Based on https://github.com/SynestiaOS/SynestiaOS
# arch_detector.cmake for Simple-XX/SimpleKernel.
# CMakeLists.txt for Simple-XX/SimpleKernel.
# 对 shell 传入的 ARCH 参数进行处理

# TODO: 优化 CMake 流程,环境搭建由自动脚本实现

# 如果 ARCH 为 i386 或 x86_64,统一添加 ia32 前缀
if (ARCH STREQUAL i386)
set(SimpleKernelArch "ia32/i386")
elseif (ARCH STREQUAL x86_64)
set(SimpleKernelArch "ia32/x86_64")
# 其它情况不变
elseif (ARCH STREQUAL arm)
set(SimpleKernelArch arm)
elseif (ARCH STREQUAL riscv64)
set(SimpleKernelArch riscv64)
else ()
# 不支持的 ARCH
message(WARNING "unexpected ARCH: ${ARCH}, using default value \"riscv64\"")
# 默认设为 riscv64
set(SimpleKernelArch riscv64)
endif ()

# 输出 SimpleKernelArch
message(STATUS "SimpleKernelArch is ${SimpleKernelArch}")
6 changes: 4 additions & 2 deletions cmake/find_asm_files.cmake
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@

# This file is a part of Simple-XX/SimpleKernel (https://github.com/Simple-XX/SimpleKernel).
# This file is a part of Simple-XX/SimpleKernel
# (https://github.com/Simple-XX/SimpleKernel).
# Based on https://github.com/SynestiaOS/SynestiaOS
# find_asm_files.cmake for Simple-XX/SimpleKernel.
# CMakeLists.txt for Simple-XX/SimpleKernel.
# 在 Directory 目录下寻找 .s/.S 格式的文件,并添加到 OutValue 中

macro(find_asm_source_files OutValue Directory)
file(GLOB ${OutValue} LIST_DIRECTORIES false ${Directory}/*.[sS])
Expand Down
6 changes: 4 additions & 2 deletions cmake/header_files.cmake
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@

# This file is a part of Simple-XX/SimpleKernel (https://github.com/Simple-XX/SimpleKernel).
# This file is a part of Simple-XX/SimpleKernel
# (https://github.com/Simple-XX/SimpleKernel).
# Based on https://github.com/SynestiaOS/SynestiaOS
# header_files.cmake for Simple-XX/SimpleKernel.
# CMakeLists.txt for Simple-XX/SimpleKernel.
# 将头文件路径添加到 Target 的搜索路径中

function(target_include_libc_header_files Target)
target_include_directories(${Target} PRIVATE ${SimpleKernel_SOURCE_CODE_DIR}/libc/include)
Expand Down
45 changes: 45 additions & 0 deletions docs/-1_参考资料汇总.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# SimpleKernel 参考资料汇总

关于交叉编译的一些说明:https://wiki.osdev.org/GCC_Cross-Compiler

arm 工具链:https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-a/downloads

riscv 工具链:https://github.com/riscv/riscv-gnu-toolchain

GCC 安装: https://gcc.gnu.org/install/

i386 的启动代码:https://wiki.osdev.org/Bare_Bones

grub:https://www.gnu.org/software/grub/manual/grub/grub.html

multiboot2 规范:https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html

opensbi:https://github.com/riscv/opensbi

c++ 的使用:https://wiki.osdev.org/C++

如何对全局对象进行构造:https://wiki.osdev.org/Calling_Global_Constructors

c++ abi 支持:https://wiki.osdev.org/C%2B%2B_Exception_Support

gcc 内嵌汇编:https://gcc.gnu.org/onlinedocs/gcc/Using-Assembly-Language-with-C.html

IA32 prots:https://wiki.osdev.org/I/O_Ports

IA32 VGA:https://wiki.osdev.org/VGA_Hardware

IA32 text ui:https://wiki.osdev.org/Text_UI

IA32 text 模式的光标:https://wiki.osdev.org/Text_Mode_Cursor

IA32 text 模式在屏幕上输出:https://wiki.osdev.org/Printing_To_Screen

device-tree:https://github.com/devicetree-org/devicetree-specification

dtb解析0: https://e-mailky.github.io/2016-12-06-dts-introduce

dtb解析1: https://e-mailky.github.io/2019-01-14-dts-1

dtb解析2: https://e-mailky.github.io/2019-01-14-dts-2

dtb解析3: https://e-mailky.github.io/2019-01-14-dts-3
120 changes: 120 additions & 0 deletions docs/0_工具链.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# SimpleKernel 工具链

SimpleKernel 为了保证在各个平台上的可用性,选择了较为通用的工具链,主要分为三个部分

1. 构建系统

使用 CMake 对代码进行管理,同时控制编译选项

2. 内核的编译

使用 g++, ld 进行编译与链接

3. 虚拟机

对于 x86/x86_64 架构,使用 bochs

对于其它架构,使用 qemu

4. 辅助脚本

在根目录下的 run.sh/run.py 属于此类,此外还有 tools/ 目录下的 *.sh



## GCC

GCC 需要根据目标平台与宿主机进行配置,即 target 与 host。

一般而言,网上有编译好的可以直接拿来用。

以 target=riscv64,host=osx 为例,可以在 https://github.com/riscv/homebrew-riscv 找到现成的,只需要按照说明使用 brew 安装即可。

对于特殊情况,可能需要自己手动编译 gcc,大致步骤如下[^1]

1. 安装依赖
2. 下载源码
3. 配置
4. 编译

其中比较重要的地方是第三步,需要根据需要进行配置,你可以参考 tools/x86_64-elf-gcc.sh 的内容进行编译。



## CMake

CMake 可以分为两个部分

1. 主要 cmake 规则

所有 CMakeLists.txt 文件,规定了内核的编译方式。其中

- /CMakeLists.txt

设置了一些 CMake 选项,并在最后通过 `add_subdirectory(${SimpleKernel_SOURCE_CODE_DIR})` 将控制权转移到 src/CMakeLists.txt

- src/CMakeLists.txt

规定了 gcc 的编译选项,指定生成的二进制文件名称,并规定生成二进制文件所需的模块

- src/*/CMakeLists.txt

各个模块的编译规则

2. 辅助 cmake 规则

用于辅助主要规则,保存在 /cmake 目录下

- toolchain_*.cmake 用于判断依赖是否已安装
- header_files.cmake 用于添加头文件
- find_asm_files.cmake 用于讲汇编文件添加到编译列表
- arch_detector.cmake 用于判断目标架构

更多细节请查看注释。



## BOCHS

bochs 是专门用于 x86/x86_64 的虚拟机。

tools/bochsrc_*.txt 规定了虚拟机的一些选项

tools/bochsinit 规定在虚拟机启动后执行的命令

更多细节请查看注释



## QEMU

qemu 是支持范围更大的虚拟机,支持多种架构。



## 辅助脚本

- tools/env.sh

设置目标架构,并根据设置的目标架构初始化相关变量。

更多细节请查看注释。

- run.sh

根据 tools/env.sh 的设置在虚拟机中运行内核。

更多细节请查看注释。



## 相关文档

关于交叉编译的一些说明:https://wiki.osdev.org/GCC_Cross-Compiler

arm 工具链:https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-a/downloads

riscv 工具链:https://github.com/riscv/riscv-gnu-toolchain

[^1]: https://gcc.gnu.org/install/

73 changes: 73 additions & 0 deletions docs/1.5_cpp的初始化.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# SimpleKernel cpp 的初始化

Simplekernel 主要是用 C++ 完成的,为了最大化 C++ 的优势,得对 C++ 的一些基础设施进行初始化。

这一工作大致分为两部分。

## cxxabi

cxxabi 是 C++ 特性的支持者,一些特性必须由 cxxabi 实现后才能使用。

在 src/libcxx/include/cxxabi.h 与 src/libcxx/cxxabi.cpp 两个文件中定义了相关数据与函数。在链接阶段将这些定义链接上就可以正常使用相关特性了。

这部分不进行深究,水太深了。

## 全局对象的构造

另一个重点是全局对象的构造。

在通常场景下,C++ 的全局对象会在进入 main 函数之前进行构造,在 main 返回后析构。在内核里也是一样,我们需要在进入 kernel_main 之前完成构造,不同的是我们不需要考虑析构问题,因为内核是不会返回的,当它结束的时候意味着关机了。

编译器在链接时,会将所有的全局对象的构造函数函数指针收集在一起,放在一个名为 `.init_array` 的段中,在 src/arch/*/link.ld 中,有这么一段规则:

```
/* 只读数据段 */
.rodata : ALIGN(4K) {
/* 构造函数起点 */
PROVIDE(ctors_start = .);
*(SORT_BY_INIT_PRIORITY (.init_array.*))
*(SORT_BY_INIT_PRIORITY (.ctors.*))
*(.init_array .ctors)
/* 构造函数终点 */
PROVIDE(ctors_end = .);
/* 析构函数起点 */
PROVIDE(dtors_start = .);
*(.dtor*)
/* 析构函数终点 */
PROVIDE(dtors_end = .);
*(.rodata*)
*(.gcc_except_table)
}
```

这部分规定将构造函数放在 .rodata 段里,并将这段内存用 `ctors_start``ctors_end` 两个地址进行标识,以便在代码中访问。

初始化由 `cpp_init` 执行,定义在 src/libcxx/src/cxxabi.cpp 中

```c++
typedef void (*ctor_t)(void);
extern ctor_t ctors_start[];
extern ctor_t ctors_end[];
void cpp_init(void) {
ctor_t *f;
for (f = ctors_start; f < ctors_end; f++) {
(*f)();
}
return;
}
```
遍历这一区域的所有函数并执行,这样就完成了全局对象的构造。
更多细节请查看注释。
## 相关文档
https://wiki.osdev.org/C++
https://wiki.osdev.org/Calling_Global_Constructors
Loading

0 comments on commit 1714b65

Please sign in to comment.