From 5bd549328fe1721eeb79773705666953970e94cb Mon Sep 17 00:00:00 2001 From: pointer-to-bios Date: Sun, 18 Feb 2024 03:53:54 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0c=E8=AF=AD=E8=A8=80=E9=83=A8?= =?UTF-8?q?=E5=88=86=E7=9A=84=E6=96=87=E6=A1=A3=E6=B3=A8=E9=87=8A=EF=BC=8C?= =?UTF-8?q?=E6=AD=A3=E5=9C=A8=E5=BC=80=E5=8F=91=E7=9A=84=E6=96=87=E6=A1=A3?= =?UTF-8?q?=E7=94=9F=E6=88=90=E5=99=A8=E5=B0=86=E4=BC=9A=E4=BB=8E=E6=BA=90?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=9A=84=E6=96=87=E6=A1=A3=E6=B3=A8=E9=87=8A?= =?UTF-8?q?=E7=94=9F=E6=88=90markdown=E6=A0=BC=E5=BC=8F=E6=96=87=E6=A1=A3?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 14 +- docs/contribution.md | 13 ++ include/kernel/arch/x86_64/interrupt.h | 21 +- include/kernel/arch/x86_64/kernel.h | 10 +- include/kernel/arch/x86_64/memm.h | 177 +++++++++++++-- include/kernel/arch/x86_64/syscall.h | 63 +++-- include/kernel/clock/time.h | 33 +++ include/kernel/interrupt.h | 21 ++ include/kernel/kernel.h | 36 ++- include/kernel/memm.h | 303 +++++++++++++++++++------ include/kernel/memm/allocator/raw.h | 27 +++ include/kernel/syscall.h | 9 + 12 files changed, 610 insertions(+), 117 deletions(-) create mode 100644 docs/contribution.md diff --git a/README.md b/README.md index 4600d15..d8f2512 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,8 @@ make debug * [x] raw_allocator * [x] tty * [x] 内核日志 +* [ ] 系统调用 +* [ ] 中断管理 * [ ] 文件系统 * [ ] vfs * [ ] fat32驱动(移植) @@ -64,9 +66,19 @@ make debug * [ ] 驱动管理 * [ ] 进程管理 +## 文档 + +* 从源代码注释生成文档 + +```bash +make doc +``` + +(开发中) + ## 作出贡献 -通过向此仓库发送PR为我们作出贡献。 +通过向此仓库发送PR为我们作出贡献,详见[contribution.md](docs/contribution.md)。 ## 版权声明 diff --git a/docs/contribution.md b/docs/contribution.md new file mode 100644 index 0000000..622a26b --- /dev/null +++ b/docs/contribution.md @@ -0,0 +1,13 @@ +# 向Metaverse内核贡献代码 + +通过如下方式向内核增加你的代码: + +* 从[github仓库](https://github.com/metaverse-kernel/kernel-dev)或[Random World Studio内部仓库](http://git.suthby.org:2024/metaverse/kernel-dev)创建一个分支 +* 在你的分支中增加代码 +* 测试你增加的代码的正确性,并尽量确保对原有代码没有影响 +* 无需在注释中加入代码更改日志,git可以做到 +* 在文档的适当的位置增加对新特性的描述 +* 完成编码和文档的工作后向主仓库发送PR +* 等待审核代码 + +若你的代码通过审核,将会把你的PR合并到主分支中。 diff --git a/include/kernel/arch/x86_64/interrupt.h b/include/kernel/arch/x86_64/interrupt.h index fb6b536..04c9dfd 100644 --- a/include/kernel/arch/x86_64/interrupt.h +++ b/include/kernel/arch/x86_64/interrupt.h @@ -4,6 +4,12 @@ #include #include +/** + * @name gate_descriptor_t + * @addindex 平台依赖结构 x86_64 + * + * 门描述符的结构体形式。 + */ typedef struct __gate_descriptor_t { u16 offset_01; @@ -14,14 +20,25 @@ typedef struct __gate_descriptor_t u32 reserved; } DISALIGNED gate_descriptor_t; -// interrupt stack table,每个表项都指向tss -// 需要加载寄存器IA32_INTERRUPT_SSP_TABLE +/** + * @name INTERRUPT_DESCRIPTOR_FLAG_IST + * @addindex 平台依赖结构 x86_64 + * + * `gate_descriptor_t`的`flags`的标志位。 + * + * `ssp`代表一个tss描述符在任务段中的的索引。 + */ #define INTERRUPT_DESCRIPTOR_FLAG_IST(ssp) (ssp) // 在第15位上有一个表示代码段是否存在的标志位,代码段总是存在,故直接设置为1 #define INTERRUPT_DESCRIPTOR_FLAG_TYPE_INTERRUPT (0x8e << 8) #define INTERRUPT_DESCRIPTOR_FLAG_TYPE_TRAP (0x8f << 8) +/** + * @name idt + * + * 中断描述符表。 + */ extern gate_descriptor_t idt[256]; #endif diff --git a/include/kernel/arch/x86_64/kernel.h b/include/kernel/arch/x86_64/kernel.h index 65462a5..5ac5529 100644 --- a/include/kernel/arch/x86_64/kernel.h +++ b/include/kernel/arch/x86_64/kernel.h @@ -3,7 +3,13 @@ #include -// 具有返回值是为了留出一个寄存器用于调整栈顶 -extern usize prepare_stack(); +/** + * @name prepare_stack + * + * ```c + * void prepare_stack(); + * ``` + */ +extern void prepare_stack(); #endif diff --git a/include/kernel/arch/x86_64/memm.h b/include/kernel/arch/x86_64/memm.h index 65401f0..2702399 100644 --- a/include/kernel/arch/x86_64/memm.h +++ b/include/kernel/arch/x86_64/memm.h @@ -4,8 +4,18 @@ #include #include -/* 页大小,以MEMM_PAGE_SIZE为单位 */ +/** + * @name MEMM_PAGE_SIZE + * @addindex 平台定制宏 + * + * 最小的页大小。 + * + * @if arch == x86_64 then + * 4096 + * @endif + */ #define MEMM_PAGE_SIZE 4096 + typedef enum __memm_page_size { MEMM_PAGE_SIZE_4K = 1, // 1个4KB页大小 @@ -15,14 +25,49 @@ typedef enum __memm_page_size extern u64 PML4[512]; +/** + * @name MEMM_PAGE_TABLE_FLAGS_MASK + * @addindex 平台依赖宏 x86_64 + * + * 页表项中属性标志位使用的最低12位的掩码`0xfff`。 + */ #define MEMM_PAGE_TABLE_FLAGS_MASK ((u64)0xfff) -/* 页对齐掩码 */ +/** + * @name MEMM_xx_ALIGN_MASK + * @addindex 平台依赖宏 x86_64 + * + * 页对齐掩码。 + * `xx`为`x86_64`架构的页的三种大小,分别为`4K`、`2M`和`1G`。这些页一定是以它们自己的大小对齐,因此会出现低n位总为0的情况。 + * `4K`对应`0xfff`;`2M`对应`0x1fffff`;`1G`对应`0x3fffffff`。 + */ #define MEMM_4K_ALIGN_MASK ((u64)0xfff) #define MEMM_2M_ALIGN_MASK ((u64)0x1fffff) #define MEMM_1G_ALIGN_MASK ((u64)0x3fffffff) -/* 页表项属性FLAGS */ +/** + * @name MEMM_ENTRY_FLAG_xx + * @addindex 平台依赖宏 x86_64 + * + * 页表项属性标志位。定义如下: + * + * ```c + * #define MEMM_ENTRY_FLAG_PRESENT ((u64)1) + * #define MEMM_ENTRY_FLAG_WRITE ((u64)1 << 1) + * #define MEMM_ENTRY_FLAG_USER ((u64)1 << 2) + * #define MEMM_ENTRY_FLAG_PWT ((u64)1 << 3) + * #define MEMM_ENTRY_FLAG_PCD ((u64)1 << 4) + * #define MEMM_ENTRY_FLAG_ACCECED ((u64)1 << 5) + * #define MEMM_ENTRY_FLAG_DIRTY ((u64)1 << 6) + * #define MEMM_ENTRY_FLAG_PS ((u64)1 << 7) + * #define MEMM_ENTRY_FLAG_GLOBAL ((u64)1 << 8) + * #define MEMM_ENTRY_FLAG_PAT ((u64)1 << 12) + * #define MEMM_PTE_ENTRY_FLAG_PAT ((u64)1 << 7) + * #define MEMM_ENTRY_FLAG_XD ((u64)1 << 63) + * ``` + * + * 其中`MEMM_PTE_ENTRY_FLAG_PAT`的`pte`表示此属性标志位只存在与`pte`页表项中。 + */ #define MEMM_ENTRY_FLAG_PRESENT ((u64)1) #define MEMM_ENTRY_FLAG_WRITE ((u64)1 << 1) #define MEMM_ENTRY_FLAG_USER ((u64)1 << 2) @@ -35,18 +80,47 @@ extern u64 PML4[512]; #define MEMM_ENTRY_FLAG_PAT ((u64)1 << 12) #define MEMM_PTE_ENTRY_FLAG_PAT ((u64)1 << 7) #define MEMM_ENTRY_FLAG_XD ((u64)1 << 63) + +/** + * @name memm_entry_flag_get(entry, flag) + * @addindex 平台依赖宏 x86_64 + * + * 获取页表项中某个属性标志位,得到布尔值。 + * + * 其中`flag`是`MEMM_ENTRY_FLAG_xx`。 + */ #define memm_entry_flag_get(entry, flag) \ ((entry & flag) ? true : false) -/* 页表(大型页)项地址域掩码 */ +/** + * @name MEMM_ENTRY_ADDRESS_MASK, MEMM_BP_ENTRY_ADDRESS_MASK + * @addindex 平台依赖宏 x86_64 + * + * 页表项地址域掩码。将页表项与掩码作与运算可得到页表项指向的**下一级页表的起始地址**或**页框的起始地址**。 + * + * 含`BP`的为大型页页表项的地址域掩码。 + * + * 定义如下: + * + * ```c + * #define MEMM_ENTRY_ADDRESS_MASK ((u64)0x000ffffffffff000) + * #define MEMM_BP_ENTRY_ADDRESS_MASK ((u64)0x000fffffffffe000) + * ``` + */ #define MEMM_ENTRY_ADDRESS_MASK ((u64)0x000ffffffffff000) #define MEMM_BP_ENTRY_ADDRESS_MASK ((u64)0x000fffffffffe000) + +/** + * @name memm_entry_get_address(entry) + * @addindex 平台依赖宏 x86_64 + * + * 获取页表项指向的地址。 + */ #define memm_entry_get_address(entry) \ ((entry) & (memm_entry_flag_get(entry, MEMM_ENTRY_FLAG_PS) \ ? MEMM_BP_ENTRY_ADDRESS_MASK \ : MEMM_ENTRY_ADDRESS_MASK)) -/* 线性地址表项索引或页内偏移掩码 */ #define MEMM_LA_PML4EI_MASK ((u64)0x0000ff8000000000) #define MEMM_LA_PDPTEI_MASK ((u64)0x0000007fc0000000) #define MEMM_LA_PDEI_MASK ((u64)0x000000003fe00000) @@ -56,50 +130,119 @@ extern u64 PML4[512]; #define MEMM_LA_2MB_PAGE_OFFSET_MASK ((u64)0x00000000001fffff) #define MEMM_LA_4KB_PAGE_OFFSET_MASK ((u64)0x0000000000000fff) -/* 线性地址表项索引偏移位数 */ #define MEMM_LA_PML4EI_OFFSET (39) #define MEMM_LA_PDPTEI_OFFSET (30) #define MEMM_LA_PDEI_OFFSET (21) #define MEMM_LA_PEI_OFFSET (12) -/* 获取线性地址中某个表项索引以及获取页内偏移 */ +/** + * @name MEMM_LA_xxxxI + * @addindex 平台依赖宏 x86_64 + * + * 在4级分页中,线性地址的四个页表项索引宏。其中`xxxx`分别为`PML4E`、`PDPTE`、`PDE`和`PE`。 + */ #define MEMM_LA_PML4EI #define MEMM_LA_PDPTEI #define MEMM_LA_PDEI #define MEMM_LA_PEI + +/** + * @name memm_la_get_entry_index(addr, entry) + * @addindex 平台依赖宏 x86_64 + * + * 获取线性地址`addr`中的`entry`页表项索引。 + * + * 其中`entry`应为宏`MEMM_LA_xxxxI`。 + */ #define memm_la_get_entry_index(addr, entry) \ (((addr) & (entry##_MASK)) >> (entry##_OFFSET)) +/** + * @name MEMM_LA_xxx_PAGE_OFFSET + * @addindex 平台依赖宏 x86_64 + * + * 线性地址的页内偏移宏。其中`xxx`为三种页容量`4KB`、`2MB`、`1GB`。 + */ #define MEMM_LA_1GB_PAGE_OFFSET #define MEMM_LA_2MB_PAGE_OFFSET #define MEMM_LA_4KB_PAGE_OFFSET + +/** + * @name memm_la_get_offset(addr, page_type) + * @addindex 平台依赖宏 x86_64 + * + * 获取线性地址的页内偏移部分。 + * + * 其中`page_type`应为宏`MEMM_LA_xxx_PAGE_OFFSET`。 + */ #define memm_la_get_offset(addr, page_type) \ ((addr) & (page_type##_MASK)) -/* -仅支持canonical型地址 - -target与physical至少都是以MEMM_PAGE_SIZE对齐的 - -没有MEMM_PAGE_SIZE对齐的,和非canonical型地址都会返回false - -当剩余长度超过1GB的一半且地址1GB对齐,则会映射一个1GB页; -当剩余长度超过2MB的一半且地址2MB对齐,则会映射一个2MB页; -否则映射4KB页。 +/** + * @name memm_map_pageframes_to + * + * ```c + * bool memm_map_pageframes_to( + * u64 target, u64 physical, + * usize size, + * bool user, bool write); + * ``` + * + * 仅支持**canonical**型地址 + * + * `target`与`physical`保证至少都是以MEMM_PAGE_SIZE对齐的。 + * + * 没有MEMM_PAGE_SIZE对齐的,和非canonical型地址都会返回false + * + * 当剩余长度超过1GB的一半且地址1GB对齐,则会映射一个1GB页; + * 当剩余长度超过2MB的一半且地址2MB对齐,则会映射一个2MB页; + * 否则映射4KB页。 */ bool memm_map_pageframes_to( u64 target, u64 physical, usize size, bool user, bool write); +/** + * @name reload_pml4 + * @addindex 平台依赖宏 x86_64 + * + * ```c + * void reload_pml4(); + * ``` + */ extern void reload_pml4(); +/** + * @name is_user_address(addr) + * @addindex 平台定制宏 + * + * 判断`addr`是否是一个用户空间地址,得到一个布尔值。 + * + * @if arch == x86_64 + * `canonical`型地址的高地址为用户空间,低地址为内核空间。 + * @endif + */ #define is_user_address(addr) \ (((addr) > 0xffff7fffffffffff) ? true : false) +/** + * @name is_cannonical(addr) + * @addindex 平台依赖宏 x86_64 + * + * 判断`addr`是否是一个cannonical型地址。 + */ #define is_cannonical(addr) \ (((addr) < 0x0000800000000000 || (addr) > 0xffff7fffffffffff) ? true : false) +/** + * @name memm_get_page_align(addr) + * @addindex 平台依赖宏 x86_64 + * + * 获取地址`addr`的页对齐大小,得到一个`memm_page_size`类型值。 + * + * 当地址`addr`是*4KB对齐*或*没有4KB对齐时*,都得到`MEMM_PAGE_SIZE_4K`。 + */ #define memm_get_page_align(addr) \ (is_aligned(addr, MEMM_PAGE_SIZE_1G) \ ? MEMM_PAGE_SIZE_1G \ diff --git a/include/kernel/arch/x86_64/syscall.h b/include/kernel/arch/x86_64/syscall.h index 3ed2abf..71f4e5c 100644 --- a/include/kernel/arch/x86_64/syscall.h +++ b/include/kernel/arch/x86_64/syscall.h @@ -5,27 +5,50 @@ extern void *system_calls_table[256]; -// 系统调用使用的寄存器: -// rax - 调用号 -// rbx - 系统调用程序保留 -// rcx - rip寄存器缓存 -// rdi - 系统调用程序保留 -// rdx - 参数1 -// r8 - 参数2 -// r9 - 参数3 -// r10 - 参数4 -// r11 - rflags寄存器缓存 -// r12 - 参数5 -// r13 - 参数6 -// r14 - 参数7 -// r15 - 参数8 - -// 系统调用时,使用内核主堆栈 -// 故设置一组函数,用于在sysret前保存和在syscall后加载 -// rbp, rsp的函数 -extern void save_kernel_stack(); -extern void load_kernel_stack(); +/** + * @brief 系统调用规范 + * @addindex x86_64 + * + * 系统调用使用的寄存器: + * rax - 调用号 + * rbx - 系统调用程序保留 + * rcx - rip寄存器缓存 + * rdi - 系统调用程序保留 + * rdx - 参数1 + * r8 - 参数2 + * r9 - 参数3 + * r10 - 参数4 + * r11 - rflags寄存器缓存 + * r12 - 参数5 + * r13 - 参数6 + * r14 - 参数7 + * r15 - 参数8 + * + * 系统调用时,使用内核主堆栈。 + */ +/** + * @name set_kernel_stack_cache + * @addindex 平台依赖函数 x86_64 + * + * ```c + * void set_kernel_stack_cache(usize stack); + * ``` + * + * 将堆栈缓存设为一个`stack`。 + */ extern void set_kernel_stack_cache(usize stack); +/** + * @name return_from_systemcall + * @addindex 平台依赖函数 x86_64 + * + * ```c + * void return_from_systemcall(); + * ``` + * + * 执行`sysret`指令。 + */ +extern void return_from_systemcall(); + #endif diff --git a/include/kernel/clock/time.h b/include/kernel/clock/time.h index b6cb4de..b680658 100644 --- a/include/kernel/clock/time.h +++ b/include/kernel/clock/time.h @@ -4,12 +4,45 @@ #include // 使用UNIX时间戳 +/** + * @name system_time_get + * + * ```c + * usize system_time_get(); + * ``` + * + * 系统时间。 + * + * 系统时间使用精确到毫秒的unix时间,即值`0`代表1970-1-1 00:00:00的第一毫秒前。 + */ usize system_time_get(); // 如果硬件支持更高的计时精度, // 此函数提供从系统unix时间开始到现在的纳秒为单位的时间 +/** + * @name system_time_ns_get + * + * ```c + * usize system_time_ns_get(); + * ``` + * + * 纳秒级系统时间。 + * + * 如果硬件支持更高的计时精度,此函数返回以纳秒为单位的时间。但不表明硬件必须支持纳秒级的计时。 + * + * 即使硬件支持更高的计时精度,内核也会根据情况自主选择是否使用更高的精度计时。 + */ usize system_time_ns_get(); +/** + * @name system_time_increase + * + * ```c + * void system_time_increase(); + * ``` + * + * 将毫秒级系统时间增加。 + */ void system_time_increase(); #endif diff --git a/include/kernel/interrupt.h b/include/kernel/interrupt.h index b2f703b..4897ea0 100644 --- a/include/kernel/interrupt.h +++ b/include/kernel/interrupt.h @@ -1,7 +1,28 @@ #ifndef INTERRUPT_H #define INTERRUPT_H 1 +/** + * @name interrupt_open + * @addindex 平台定制函数 + * + * ```c + * void interrupt_open(); + * ``` + * + * 开启中断 + */ void interrupt_open(); + +/** + * @name interrupt_close + * @addindex 平台定制函数 + * + * ```c + * void interrupt_close(); + * ``` + * + * 开启中断 + */ void interrupt_close(); #endif diff --git a/include/kernel/kernel.h b/include/kernel/kernel.h index 7d84b16..673dd1d 100644 --- a/include/kernel/kernel.h +++ b/include/kernel/kernel.h @@ -11,11 +11,33 @@ #endif +/** + * @name KERNEL_TODO + * + * 表示此处还没有实现代码。 + */ #define KERNEL_TODO() \ while (true) \ { \ } +/** + * @name simple_lock + * + * 简易同步锁。有如下两个方法: + * + * ```c + * #define simple_lock_lock(lock) + * ``` + * + * 获取一个锁。 + * + * ```c + * #define simple_lock_unlock(lock) + * ``` + * + * 解开一个锁。 + */ #define simple_lock_lock(lock) \ { \ while (lock == true) \ @@ -24,8 +46,20 @@ } #define simple_lock_unlock(lock) (lock) = false; +/** + * @name kmain_rust + * + * rust内核主程序。 + */ extern void kmain_rust(); -extern void *kend; // 内核结束的标记 +/** + * @name kend + * + * 内核结束的标记。 + * + * 此变量不代表任何值,但是此变量的地址被安排到了内核镜像的末尾,用于标志内核结束的位置。 + */ +extern void *kend; #endif diff --git a/include/kernel/memm.h b/include/kernel/memm.h index 432c72c..0074ca8 100644 --- a/include/kernel/memm.h +++ b/include/kernel/memm.h @@ -8,57 +8,127 @@ #include /** - * @brief 内存管理模块 + * @name MEMM_MAX_SUPPORTED_MEMORY * - * TODO 还没设计页回收算法 + * 支持的最大物理内存,为固定值`1TB`。 */ - -/* 最大支持1TB内存 */ #define MEMM_MAX_SUPPORTED_MEMORY (1024 * (1024 * (1024 * (usize)1024))) -/* 最大支持的分页数量 */ -// 这里的页均以最小的页大小计算 +/** + * @name MEMM_MAX_SUPPORTED_PAGES + * + * 支持的最大页数量,通过宏`MEMM_MAX_SUPPORTED_MEMORY`与宏`MEMM_PAGE_SIZE`相除得到。 + */ #define MEMM_MAX_SUPPORTED_PAGES (MEMM_MAX_SUPPORTED_MEMORY / MEMM_PAGE_SIZE) -/* 只分配不映射空间 */ +/** + * @name MEMM_ALLOC_ONLY_MEMORY + * + * 只分配不映射空间,暂时为固定值`128MB`。物理地址`0`\~`MEMM_ALLOC_ONLY_MEMORY`的空间在进入内核前已经映射至内核空间。 + * + * 这段内存空间包含**1MB以内低地址**、**内核镜像**以及未分配空间,未分配空间被一个分配器独占。 + */ #define MEMM_ALLOC_ONLY_MEMORY (128 * 1024 * 1024) +/** + * @name memm_allocate_t, memm_free_t + * + * 分配器的一对`分配`、`释放`函数指针。内核中可以根据情况使用多种不同的分配器来分配内存,`allocator`中提供一对此类型的变量,用于 + * 动态绑定不同的分配器。 + * + * 分配器在`kernel/memm/allocator/`中定义。 + * + * 分配器**必须**实现的行为: + * + * **`memm_allocate_t`**: + * + * ```c + * typedef void *(*memm_allocate_t)(void *allocator, usize size); + * ``` + * + * 从分配器`allocator`中分配`size`字节的内存。 + * + * 无法分配空间时返回`nullptr`;当参数`size`为0时,需要检查分配器占有的空间的可用性,无可用空间时需要返回`nullptr`; + * **返回的地址的16字节前**必须保留8字节空间用于存放内存所在分配器的内核空间地址。 + * + * **`memm_free_t`**: + * + * ```c + * typedef void (*memm_free_t)(void *allocator, void *mem); + * ``` + * + * 释放分配器`allocator`中的内存`mem`。 + * + * 由于此函数只由内核调用,因此对参数作出保证,保证地址`mem`属于这个`allocator`。 + */ typedef void *(*memm_allocate_t)(void *allocator, usize size); typedef void (*memm_free_t)(void *allocator, void *mem); -/* -内存分配器 -分配器对象的首地址永远是MEMM_PAGE_SIZE对齐的 +/** + * @name allocator_t + * + * ```c + * typedef struct { } allocator_t; + * ``` + * + * 内存分配器。 + * + * 内存分配器用于为`memm_allocate`函数提供管理数据以及分配空间。 + * + * 在**内核镜像结尾**至`MEMM_ALLOC_ONLY_MEMORY`空间中,包含一个分配器`内核大分配器`。 + * + * 分配器指针**必须**使用内核地址。 + * + * @internal full + * + * 调用分配器的`allocate`方法后,在返回`nullptr`时会设为`true`。 + * 调用分配器的`free`方法时设为`false`。 + * + * @internal pid + * + * 进程标志服,表示此分配器所属的进程,为0代表属于内核。 + * + * @internal type + * + * 分配器类型。在目录`include/kernel/memm/allocator`中对每个分配器分别定义一个唯一值。 + * + * @internal allocate + * + * 分配器实例的allocate函数。当无法分配空间时返回nullptr。在size参数为0时,保证不可以分配空间, + * 但是如果空间已满依然返回nullptr。 + * + * @internal free + * + * 分配器实例的free函数。若不是allocate得到的地址则什么都不做。 + * + * @internal allocator_instance + * + * 分配器实例。 */ typedef struct __allocator_t { - #define MEMM_ALLOCATOR_MAGIC_NUM 0x271fe441 +#define MEMM_ALLOCATOR_MAGIC_NUM 0x271fe441 u32 magic; bool initialized; - // 在本分配器中调用allocate返回nullptr后为true - // 调用free后为false + // 调用分配器的`allocate`方法后,在返回`nullptr`时会设为`true`。 + // 调用分配器的`free`方法时设为`false`。 bool full; - // 进程id,当pid=0时代表内核 + // 进程标志服,表示此分配器所属的进程,为0代表属于内核。 usize pid; - // 分配器类型 + // 分配器类型。在目录`include/kernel/memm/allocator`中对每个分配器分别定义一个唯一值。 usize type; usize size; - // 分配器实例的allocate函数 - // 无法分配空间返回nullptr - // 在size参数为0时,保证不可以分配空间,但是如果空间已满依然返回nullptr + // 分配器实例的allocate函数。当无法分配空间时返回nullptr。在size参数为0时, + // 保证不可以分配空间,但是如果空间已满依然返回nullptr。 memm_allocate_t allocate; - - // 分配器实例的free函数 - // 若不是allocate得到的地址则什么都不做 + // 分配器实例的free函数。若不是allocate得到的地址则什么都不做。 memm_free_t free; - // 分配器实例 - // 对应`type`类型使用 - // 在kernel/memm/allocator/中是所有的内存分配器 + // 分配器实例。 u64 allocator_instance[0]; } allocator_t; @@ -68,93 +138,178 @@ typedef struct __allocator_iterator_t struct __allocator_iterator_t *left, *right; } allocator_iterator_t; -/* -内存管理器 -内存分配分成两个阶段:映射和分配 -映射后的页进入allocator记录中,具体的分配工作由allocator完成 - -在page_map中置位、在map_with_allocator中复位、在map_with_destructed_allocator中复位 -且不在available_pages_table中的页,是页表、程序代码段、内核代码等使用的页 -*/ +/** + * @name 内存管理器 + * + * @internal alloc_only_memory + * + * 在进入内核主程序之前,有些不在内核中的虚拟内存空间已经被页表映射,这部分内存不可以再映射到物理页框。 + * + * @internal mapped_page_amount + * + * 已经映射的页数量。若不是最小的页会被视作多个最小页计数。 + * + * @internal mapped_4k_page, mapped_2m_page, mapped_1g_page + * @addindex 平台依赖宏 x86_64 + * + * 分别记录已经映射的三种大小页的数量。 + * + * @internal page_map + * + * 页地图,每个bit表示对应的最小页是否被映射。 + * + * @internal allocator_map + * + * 分配器地图。每个bit表示对应的最小页是否被一个分配器控制。 + * + * @internal destructed_allocator_map + * + * 释放的分配器页地图。每个bit表示对应的最小页是否曾经被分配器控制并且现在控制这个页的分配器已经释放。 + * + * 值为1的bit位对应的最小页可以直接**取消映射**、**重新构造一个分配器**、**加载可执行程序**等。 + * + * @internal available_pages_table + * + * 空闲页线段搜索表。 + * + * @internal allocators + * + * 分配器二叉树。 + */ typedef struct __mem_manager_t { usize memory_size; usize page_amount; - // 这里记录的数量为最小的页的数量 - usize mapped_page_amount; - - // 在进入内核主程序之前,有些不在内核中的虚拟内存空间已经被 - // 页表映射,这部分内存不可以再映射到物理页框 + // 在进入内核主程序之前,有些不在内核中的虚拟内存空间已经被页表映射,这部分内存不可以再映射到物理页框 usize alloc_only_memory; + + // 已经映射的页数量。若不是最小的页会被视作多个最小页计数。 + usize mapped_page_amount; #ifdef __x86_64__ - // 在这里三种页的数量分别记录 usize mapped_4k_page; usize mapped_2m_page; usize mapped_1g_page; #endif - // 页地图 - // 每个bit都表示这个页是否被映射 + + // 页地图。每个bit都表示这个页是否被映射。 u8 *page_map; - // 分配器页地图 - // 每个bit表示这个页是否被内存分配器控制 - // (不代表每个页都包含完整的分配器) - u8 *map_with_allocator; - // 分配器释放页地图 - // 每个bit表示这个页是否曾经被内存分配器控制且现在被释放 - // 需要取消映射 - u8 *map_with_destructed_allocator; + // 分配器页地图。每个bit表示这个页是否被内存分配器控制。 + u8 *allocator_map; + // 释放的分配器页地图。每个bit表示这个页是否曾经被内存分配器控制且现在被释放。 + // 值为1的bit位对应的最小页可以直接**取消映射**、**重新构造一个分配器**、**加载可执行程序**等。 + u8 *destructed_allocator_map; // 空闲页线段搜索表 lst_iterator_t *available_pages_table; - // 分配器树 - // 为方便查找,以二叉树的形式存储 - // index=0为无效项 + // 分配器二叉树 allocator_iterator_t *allocators; -} mem_manager_t; +} memory_manager_t; -mem_manager_t *memm_new(usize mem_size); +/** + * @name memm_new + * + * ```c + * memory_manager_t *memm_new(usize mem_size); + * ``` + * + * 初始化内存管理结构。 + */ +memory_manager_t *memm_new(usize mem_size); -/* -在`start`处创建一个长度为`length`的内存分配器 -当`pid`为0时,表示这个分配器只给内核使用 +/** + * @name memm_get_manager + * + * ```c + * memory_manager_t *memm_get_manager(); + * ``` + * + * 在其它源代码文件中,获取内存管理结构的方式。 + */ +memory_manager_t *memm_get_manager(); + +/** + * @name memm_allocator_new + * + * ```c + * allocator_t *memm_allocator_new(void *start, usize length, usize type, usize pid); + * ``` + * + * 在`start`处创建一个长度为`length`的内存分配器,当`pid`为0时,表示这个分配器只给内核使用。 */ allocator_t *memm_allocator_new(void *start, usize length, usize type, usize pid); -/* -释放分配器对象 - -只能被内存回收模块调用 +/** + * @name memm_allocator_destruct + * + * ```c + * void memm_allocator_destruct(allocator_t *allocator); + * ``` + * + * 释放分配器对象。 + * + * 只能被**内存回收模块**调用。 */ void memm_allocator_destruct(allocator_t *allocator); -/* -申请内存 -pid=0时为内核分配 -所有内存在内核空间都有对物理内存空间的直接映射,也就是线性地址与物理地址相同,称为内核地址 - -allocator对象在进程与内核之间传递时一律使用内核空间的映射地址 - -## 要求在返回的地址前16字节处保留8字节空间作为它所在的allocator地址,并且不需要分配器的具体实现做这个事 +/** + * @name memm_allocate + * + * ```c + * void *memm_allocate(usize size, usize pid); + * ``` + * + * 申请内存。`pid`为0时为内核分配。 + * + * 所有内存在内核空间都有对物理内存空间的直接映射。 */ void *memm_allocate(usize size, usize pid); #define memm_addr_set_allocator(mem, allocator) \ - *(allocator_t **)((void *)(mem) - 16) = allocator; + *(allocator_t **)((void *)(mem)-16) = allocator; #define memm_addr_get_allocator(mem) \ - ((*(allocator_t **)((void *)(mem) - 16))) + ((*(allocator_t **)((void *)(mem)-16))) +/** + * @name memm_kernel_allocate + * + * ```c + * void *memm_kernel_allocate(usize size); + * ``` + * + * 为内核空间申请内存。 + */ void *memm_kernel_allocate(usize size); +/** + * @name memm_user_allocate + * + * ```c + * void *memm_user_allocate(usize size, usize pid); + * ``` + * + * 为用户空间申请内存。 + */ void *memm_user_allocate(usize size, usize pid); -/* -释放内存 +/** + * @name memm_free + * + * ```c + * void memm_free(void *mem); + * ``` + * + * 释放内存。 */ void memm_free(void *mem); -/* -寻找大小合适的一组页 +/** + * @name find_fitable_pages + * + * ```c + * usize find_fitable_pages(usize page_count); + * ``` + * 寻找大小合适的一组连续页 */ usize find_fitable_pages(usize page_count); diff --git a/include/kernel/memm/allocator/raw.h b/include/kernel/memm/allocator/raw.h index 9dc1784..a8d4112 100644 --- a/include/kernel/memm/allocator/raw.h +++ b/include/kernel/memm/allocator/raw.h @@ -24,6 +24,19 @@ typedef struct __raw_allocator_cell // // 统计从上次细胞合并以来free的调用次数,当调用次数很多或可用空间不足时 // 触发细胞合并。 +/** + * @name raw_allocator_t + * + * 原始分配器。包括至少一个cell,分配时像cell的分裂一样将空白的一段分成两段,释放时,只把length归零,并不将cell合并。 + * + * `length`为0的cell称为空cell。 + * + * 统计从上次细胞合并以来free的调用次数,当调用次数达到`RAW_ALLOCATOR_FREE_MAX`或无可用空间时触发细胞合并。 + * + * @internal free_count + * + * free方法的调用次数,达到`RAW_ALLOCATOR_FREE_MAX`时归零。 + */ typedef struct __raw_allocator_t { usize size; @@ -34,8 +47,22 @@ typedef struct __raw_allocator_t } raw_allocator_t; #define raw_allocator_end(allocator) ((void *)(allocator) + (allocator)->size) +/** + * @name raw_allocator_new + * + * ```c + * void raw_allocator_new(raw_allocator_t *allocator, usize size); + * ``` + * + * 初始化一个`raw_allocator`。 + */ void raw_allocator_new(raw_allocator_t *allocator, usize size); +/** + * @name raw_allocator_allocate, raw_allocator_free + * + * `raw_allocator`的一对allocate, free方法。 + */ void *raw_allocator_allocate(raw_allocator_t *allocator, usize size); void raw_allocator_free(raw_allocator_t *allocator, void *mem); diff --git a/include/kernel/syscall.h b/include/kernel/syscall.h index 1c9507a..fc2709b 100644 --- a/include/kernel/syscall.h +++ b/include/kernel/syscall.h @@ -5,6 +5,15 @@ #include #endif +/** + * @name syscall_init + * + * ```c + * void syscall_init(); + * ``` + * + * 初始化系统调用。 + */ void syscall_init(); #endif