diff --git a/.gitignore b/.gitignore index d907548..6cd1797 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -/.vscode /test/metaverse.img *.o *.map diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..fe4e235 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,16 @@ +{ + "configurations": [ + { + "name": "Linux", + "includePath": [ + "${workspaceFolder}/include" + ], + "defines": [], + "compilerPath": "/usr/bin/gcc", + "cStandard": "c17", + "intelliSenseMode": "linux-gcc-x64", + "configurationProvider": "ms-vscode.makefile-tools" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..6970732 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,9 @@ +{ + "C_Cpp.errorSquiggles": "disabled", + "files.associations": { + "*.s": "nasm", + "LICENCE": "plaintext", + "*.h": "c" + }, + "rust-analyzer.imports.preferNoStd" : true, +} \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index d2d3873..44bc550 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ name = "metaverse" version = "0.1.0" edition = "2021" +crate-type = ["staticlib"] # 此Cargo.toml仅用于rust-analyzer识别rust部分的代码 # 不应使用cargo编译 diff --git a/Makefile b/Makefile index a77927d..64f711c 100644 --- a/Makefile +++ b/Makefile @@ -1,27 +1,42 @@ -SOURCE := $(shell pwd)/src/scripts +SOURCE := $(shell pwd)/scripts -.PHONY: all clear run debug config +.PHONY: all clear run debug disass -all: config +all: metaverse_kernel @make -C src all --no-print-directory -clear: config +clear: metaverse_kernel @make -C src clear --no-print-directory -run: config +run: metaverse_kernel @make -C test run --no-print-directory -debug: config +debug: metaverse_kernel @make -C test debug --no-print-directory -config: +metaverse_kernel: @if [ "${shell uname -s}" != "Linux" ]; then \ echo -e "\e[1;33mMetaverse\e[0m must build under \e[1;35mLinux\e[0m or itself."; \ exit -1; \ fi - @if [ -f "metaverse_kernel" ]; then \ - echo; \ - else \ - touch metaverse_kernel; \ - "${SOURCE}/depcheck"; \ + @"${SOURCE}/depcheck"; + @if [ $$? != 0 ]; then \ + exit $$?; \ fi + @touch metaverse_kernel + +disass: + objdump -D src/metaverse.elf > kerndisass.txt + +install-grub: + @cp src/metaverse.elf /boot/ + @if ! grep -q "Metaverse" /boot/grub/grub.cfg; then \ + echo -e 'menuentry "Metaverse" {\n set root=(hd0,gpt1)\n multiboot2 /metaverse.elf\n}\n' >> \ + /boot/grub/grub.cfg; \ + echo -e 'Added Metaverse into grub entries.'; \ + else \ + echo -e 'Metaverse entry exists.'; \ + fi + +remove-grub: + @-rm /boot/metaverse.elf 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..e66325d --- /dev/null +++ b/docs/contribution.md @@ -0,0 +1,20 @@ +# 向Metaverse内核贡献代码 + +通过如下方式向内核增加你的代码: + +* 从[github仓库](https://github.com/metaverse-kernel/kernel-dev)或[Random World Studio内部仓库](http://git.suthby.org:2024/metaverse/kernel-dev)创建一个分支 +* 在你的分支中增加代码 +* 测试你增加的代码的正确性,并尽量确保对原有代码没有影响 +* 无需在注释中加入代码更改日志,git可以做到 +* 在文档的适当的位置增加对新特性的描述 +* 完成编码和文档的工作后向主仓库发送PR +* 等待审核代码 + +若你的代码通过审核,将会把你的PR合并到主分支中。 + +## 需要注意的还未解决的问题 + +* rust中所有有关字符串格式化的宏中,出现超过一个不止是`{}`的格式化占位符时内核必然崩溃。 +* rust中所有有关字符串格式化的宏中,出现需要调用自定义的`Debug trait`的类型时内核必然崩溃,推荐定义`ToString trait`并调用`.to_string()`后传入宏参数。 +* 鉴于以上两条原因,不建议在复杂的字符串格式化任务中使用`format!()`宏。推荐通过使用`::kernel::tty::tty::MessageBuilder`构造`kernel::tty::tty::Message`对象,或使用 + `message`宏,并调用此对象的`.to_string()`方法实现格式化字符串。 diff --git a/include/kernel/arch/x86_64/interrupt.h b/include/kernel/arch/x86_64/interrupt.h new file mode 100644 index 0000000..1f3cf86 --- /dev/null +++ b/include/kernel/arch/x86_64/interrupt.h @@ -0,0 +1,69 @@ +#ifndef X86_64_INTERRUPT_H +#define X86_64_INTERRUPT_H 1 + +#include +#include + +/** + * @name gate_descriptor_t + * @addindex 平台依赖结构 x86_64 + * + * 门描述符的结构体形式。 + */ +typedef struct __gate_descriptor_t +{ + u16 offset_01; + u16 segment_selector; // for code segment + u16 flags; + u16 offset_23; + u32 offset_4567; + u32 reserved; +} DISALIGNED gate_descriptor_t; + +/** + * @name INTERRUPT_DESCRIPTOR_FLAG_IST + * @addindex 平台依赖结构 x86_64 + * + * `gate_descriptor_t`的`flags`的标志位。 + * + * `ssp`代表一个tss描述符在任务段中的的索引。 + */ +#define INTERRUPT_DESCRIPTOR_FLAG_IST 1 + +// 在第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]; + +#define interrupt_gate_generate(desc, addr) \ + { \ + (desc).segment_selector = 0x8; \ + (desc).flags = INTERRUPT_DESCRIPTOR_FLAG_TYPE_INTERRUPT | \ + INTERRUPT_DESCRIPTOR_FLAG_IST; \ + (desc).reserved = 0; \ + (desc).offset_01 = (u16)((u64)(addr)); \ + (desc).offset_23 = (u16)(((u64)(addr)) >> 16); \ + (desc).offset_4567 = (u32)(((u64)(addr)) >> 32); \ + } + +#define trap_gate_generate(desc, addr) \ + { \ + (desc).segment_selector = 0x8; \ + (desc).flags = INTERRUPT_DESCRIPTOR_FLAG_TYPE_TRAP | \ + INTERRUPT_DESCRIPTOR_FLAG_IST; \ + (desc).reserved = 0; \ + (desc).offset_01 = (u16)((u64)(addr)); \ + (desc).offset_23 = (u16)(((u64)(addr)) >> 16); \ + (desc).offset_4567 = (u32)(((u64)(addr)) >> 32); \ + } + +#define interrupt_register_gate(desc, index) \ + idt[index] = desc; + +#endif diff --git a/include/kernel/arch/x86_64/interrupt_procs.h b/include/kernel/arch/x86_64/interrupt_procs.h new file mode 100644 index 0000000..cd6d2a0 --- /dev/null +++ b/include/kernel/arch/x86_64/interrupt_procs.h @@ -0,0 +1,87 @@ +#ifndef X86_64_INTERRUPT_PROCS_H +#define X86_64_INTERRUPT_PROCS_H 1 + +#include + +/** + * @name interrupt_entry + * @addindex 平台定制函数 x86_64 + * + * 中断入口程序。 + * + * ```c + * void interrupt_entry(); + * ``` + * + * ```asm + * interrupt_entry_xx: + * ; 保存寄存器上下文 + * interrupt_entry_enter + * + * ; 调用真正的中断处理函数 + * ... + * + * ; 恢复寄存器上下文 + * interrupt_entry_leave + * iret + * ``` + */ +typedef void (*interrupt_entry)(); + +/** + * @name interrupt_entry_gen + * @addindex 平台定制宏 x86_64 + * + * 导入一个中断入口函数声明。 + * + * ```c + * #define interrupt_entry_gen(interrupt) + * ``` + */ +#define interrupt_entry_gen(interrupt) \ + extern void interrupt_entry_##interrupt() +#define interrupt_entry_sym(interrupt) \ + interrupt_entry_##interrupt + +/** + * @name interrupt_request + * @addindex 平台定制函数 + * + * 中断请求处理程序。 + * + * ```c + * void interrupt_request(u64 rip, u64 rsp); + * ``` + * + * 由中断入口程序调用。 + */ +typedef void (*interrupt_request)(u64 rip, u64 rsp, u64 errcode); + +/** + * @name interrupt_req_gen + * @addindex 平台定制宏 x86_64 + * + * 声明一个中断处理函数。 + * + * ```c + * #define interrupt_req_gen(interrupt) + * ``` + */ +#define interrupt_req_gen(interrupt) \ + void interrupt_req_##interrupt(u64 rip, u64 rsp, u64 errcode) +#define interrupt_req_sym(interrupt) \ + interrupt_req_##interrupt + +#define UNSUPPORTED + +#define DE +#define NMI +#define BP + +interrupt_entry_gen(UNSUPPORTED); + +interrupt_entry_gen(DE); +interrupt_entry_gen(NMI); +interrupt_entry_gen(BP); + +#endif diff --git a/include/kernel/arch/x86_64/kernel.h b/include/kernel/arch/x86_64/kernel.h index 65462a5..af07ab4 100644 --- a/include/kernel/arch/x86_64/kernel.h +++ b/include/kernel/arch/x86_64/kernel.h @@ -3,7 +3,15 @@ #include -// 具有返回值是为了留出一个寄存器用于调整栈顶 -extern usize prepare_stack(); +/** + * @name prepare_stack + * + * ```c + * void prepare_stack(); + * ``` + */ +extern void prepare_stack(); + +extern u32 TSS[26]; #endif diff --git a/include/kernel/arch/x86_64/memm.h b/include/kernel/arch/x86_64/memm.h index a8594ee..98664b4 100644 --- a/include/kernel/arch/x86_64/memm.h +++ b/include/kernel/arch/x86_64/memm.h @@ -4,8 +4,33 @@ #include #include -/* 页大小,以MEMM_PAGE_SIZE为单位 */ +/** + * @details x86_64 + * + * 物理地址空间: + * + * * 0 \~ 1MB:保留。 + * * 1MB \~ 2MB:内核头。 + * * 2MB \~ 4MB:中断栈。 + * * 4MB \~ 16MB:内核栈。 + * * 16MB \~ ?:内核镜像。 + * * ? \~ 128MB:内核大分配器。 + */ + +/** + * @name MEMM_PAGE_SIZE + * @addindex 平台定制宏 + * + * 最小的页大小。 + * + * @if arch == x86_64 then + * 4096 + * @endif + */ #define MEMM_PAGE_SIZE 4096 + +#define MEMM_PAGE_TABLE_SIZE 4096 + typedef enum __memm_page_size { MEMM_PAGE_SIZE_4K = 1, // 1个4KB页大小 @@ -15,14 +40,49 @@ typedef enum __memm_page_size extern u64 PML4[512]; -#define MEMM_PAGE_TABLE_FLAGS_AREA ((u64)0xfff) +/** + * @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 +95,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 +145,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 \ @@ -107,4 +265,21 @@ extern void reload_pml4(); ? MEMM_PAGE_SIZE_2M \ : MEMM_PAGE_SIZE_4K)) +/** + * @name memm_page_counter + * @addindex 平台定制结构 + * + * 页计数器 + * + * @if arch == x86_64 + * 使用三个成员分别记录`4KB`、`2MB`、`1GB`页的大小。 + * @endif + */ +typedef struct __memm_page_counter +{ + usize mapped_4k_page; + usize mapped_2m_page; + usize mapped_1g_page; +} memm_page_counter; + #endif diff --git a/include/kernel/arch/x86_64/proc.h b/include/kernel/arch/x86_64/proc.h new file mode 100644 index 0000000..9bf923e --- /dev/null +++ b/include/kernel/arch/x86_64/proc.h @@ -0,0 +1,25 @@ +#ifndef X86_64_PROC_H +#define X86_64_PROC_H 1 + +#include + +/** + * @name proc_texture_registers_t + * @addindex 平台定制宏 x86_64 + * + * 进程上下文的寄存器上下文。 + */ +typedef struct __proc_texture_registers_t +{ + u16 es, ds; + u32 reserved; + u64 r15, r14, r13, r12; + u64 r11, r10, r9, r8; + u64 rdi, rsi, rdx, rbx, rcx, rax; + u64 rbp; + u64 rip, cs; + u64 rflags; + u64 rsp, ss; +} proc_texture_registers_t; + +#endif diff --git a/include/kernel/arch/x86_64/syscall.h b/include/kernel/arch/x86_64/syscall.h new file mode 100644 index 0000000..107d5bd --- /dev/null +++ b/include/kernel/arch/x86_64/syscall.h @@ -0,0 +1,56 @@ +#ifndef X86_64_SYSCALL +#define X86_64_SYSCALL 1 + +#include + +extern void *system_calls_table[256]; + +/** + * @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 + * + * 返回值 - rax + * + * 系统调用时,使用内核主堆栈。 + */ + +/** + * @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 new file mode 100644 index 0000000..a918aa3 --- /dev/null +++ b/include/kernel/interrupt.h @@ -0,0 +1,45 @@ +#ifndef INTERRUPT_H +#define INTERRUPT_H 1 + + +#ifdef __x86_64__ +#include +#endif + +/** + * @name interrupt_open + * @addindex 平台定制函数 + * + * ```c + * void interrupt_open(); + * ``` + * + * 开启中断 + */ +void interrupt_open(); + +/** + * @name interrupt_close + * @addindex 平台定制函数 + * + * ```c + * void interrupt_close(); + * ``` + * + * 开启中断 + */ +void interrupt_close(); + +/** + * @name interrupt_init + * @addindex 平台定制函数 + * + * ```c + * void interrupt_init(); + * ``` + * + * 初始化中断功能。 + */ +void interrupt_init(); + +#endif diff --git a/include/kernel/interrupt/procs.h b/include/kernel/interrupt/procs.h new file mode 100644 index 0000000..16e9ed0 --- /dev/null +++ b/include/kernel/interrupt/procs.h @@ -0,0 +1,8 @@ +#ifndef INTERRUPT_PROCS +#define INTERRUPT_PROCS 1 + +#ifdef __x86_64__ +#include +#endif + +#endif diff --git a/include/kernel/kernel.h b/include/kernel/kernel.h index 7d84b16..7b4247e 100644 --- a/include/kernel/kernel.h +++ b/include/kernel/kernel.h @@ -2,20 +2,44 @@ #define KERNEL_H 1 #include +#include #ifdef __x86_64__ - #include - #define ISA_NAME "x86_64" - #endif +#ifndef BUILD_ID +#define BUILD_ID 0 +#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 +48,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/klog.h b/include/kernel/klog.h deleted file mode 100644 index 7415cc0..0000000 --- a/include/kernel/klog.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef KLOG_H -#define KLOG_H 1 - -#include - -#define KLOG_BUFFER_SIZE 2 * 1024 * 1024 - -typedef struct __klogger -{ - usize tty; - char buffer[KLOG_BUFFER_SIZE]; - usize index; -} klogger; - -#endif diff --git a/include/kernel/memm.h b/include/kernel/memm.h index f4714ae..9d561b4 100644 --- a/include/kernel/memm.h +++ b/include/kernel/memm.h @@ -8,153 +8,227 @@ #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) -/* 只分配不映射空间 */ -#define MEMM_ALLOC_ONLY_MEMORY (128 * 1024 * 1024) +/** + * @name MEMM_ALLOC_ONLY_MEMORY + * + * 只分配不映射空间,暂时为固定值`64MB`。物理地址`0`\~`MEMM_ALLOC_ONLY_MEMORY`的空间在进入内核前已经映射至内核空间。 + * + * 这段内存空间包含**1MB以内低地址**、**内核镜像**以及未分配空间,未分配空间被一个分配器独占。 + */ +#define MEMM_ALLOC_ONLY_MEMORY (64 * 1024 * 1024) -typedef void *(*memm_allocate_t)(void *allocator, usize size, usize align); +#define MEMM_PAGE_TABLE_AREA_MAX (4 * 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 magic + * + * 分配器有效性由此检验,不为`MEMM_ALLOCATOR_MAGIC_NUM`说明获得了一个错误的分配器地址。 + * + * @internal full + * + * 调用分配器的`allocate`方法后,在返回`nullptr`时会设为`true`。 + * 调用分配器的`free`方法时设为`false`。 + * + * @internal pid + * + * 进程标志服,表示此分配器所属的进程,为0代表属于内核。 + * + * @internal userspace + * + * 若分配器不属于内核,此成员储存此分配器的用户空间地址。 + * + * @internal type + * + * 分配器类型。在目录`include/kernel/memm/allocator`中对每个分配器分别定义一个唯一值。 + * + * @internal allocate + * + * 分配器实例的allocate函数。当无法分配空间时返回nullptr。在size参数为0时,保证不可以分配空间, + * 但是如果空间已满依然返回nullptr。 + * + * @internal free + * + * 分配器实例的free函数。若不是allocate得到的地址则什么都不做。 + * + * @internal allocator_instance + * + * 分配器实例。 */ typedef struct __allocator_t { - bool initialized; +#ifndef MEMM_ALLOCATOR_MAGIC +#define MEMM_ALLOCATOR_MAGIC ((u32)0x271fe441) +#endif + // 分配器有效性由此检验,不为`MEMM_ALLOCATOR_MAGIC_NUM`说明获得了一个错误的分配器地址。 + // 此值在编译时通过各种方式确定,若 + u32 magic; - // 在本分配器中调用allocate返回nullptr后为true - // 调用free后为false + // 调用分配器的`allocate`方法后,在返回`nullptr`时会设为`true`。 + // 调用分配器的`free`方法时设为`false`。 bool full; - // 进程id,当pid=0时代表内核 - usize pid; - // 分配器类型 + // 分配器类型。在目录`include/kernel/memm/allocator`中对每个分配器分别定义一个唯一值。 usize type; usize size; - // 分配器实例的allocate函数 - // 无法分配空间返回nullptr - // 在size参数为0时,保证不可以分配空间,但是如果空间已满依然返回nullptr - // 当参数align=0时表示不需要对齐 + // 分配器实例的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; -typedef struct __allocator_iterator_t -{ - allocator_t *allocator; - 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 + * + * 在进入内核主程序之前,有些不在内核中的虚拟内存空间已经被页表映射,这部分内存不可以再映射到物理页框。 + */ typedef struct __mem_manager_t { usize memory_size; usize page_amount; - // 这里记录的数量为最小的页的数量 - usize mapped_page_amount; - - // 在进入内核主程序之前,有些不在内核中的虚拟内存空间已经被 - // 页表映射,这部分内存不可以再映射到物理页框 usize alloc_only_memory; -#ifdef __x86_64__ - // 在这里三种页的数量分别记录 - usize mapped_4k_page; - usize mapped_2m_page; - usize mapped_1g_page; -#endif - // 页地图 - // 每个bit都表示这个页是否被映射 - u8 *page_map; - // 分配器页地图 - // 每个bit表示这个页是否被内存分配器控制 - // (不代表每个页都包含完整的分配器) - u8 *map_with_allocator; - // 分配器释放页地图 - // 每个bit表示这个页是否曾经被内存分配器控制且现在被释放 - // 需要取消映射 - u8 *map_with_destructed_allocator; - // 空闲页线段搜索表 - lst_iterator_t *available_pages_table; + allocator_t *kernel_base_allocator; - // 分配器树 - // 为方便查找,以二叉树的形式存储 - // index=0为无效项 - allocator_iterator_t *allocators; -} mem_manager_t; + usize page_table_area; +} 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_kernel_allocate + * + * ```c + * void *memm_kernel_allocate(usize size); + * ``` + * + * 为内核空间申请内存。 */ -void *memm_allocate(usize size, usize pid); -#define memm_addr_set_allocator(mem, allocator) \ - *(allocator_t **)((void *)(mem) - 16) = allocator; -#define memm_addr_get_allocator(mem) \ - ((*(allocator_t **)((void *)(mem) - 16))) - void *memm_kernel_allocate(usize size); -void *memm_user_allocate(usize size, usize pid); - -/* -释放内存 +/** + * @name memm_free + * + * ```c + * void memm_free(void *mem); + * ``` + * + * 释放内存。 */ void memm_free(void *mem); -/* -寻找大小合适的一组页 - */ -usize find_fitable_pages(usize page_count); +void *memm_allcate_pagetable(); #endif diff --git a/include/kernel/memm/allocator/raw.h b/include/kernel/memm/allocator/raw.h index 96fbe90..4b1741c 100644 --- a/include/kernel/memm/allocator/raw.h +++ b/include/kernel/memm/allocator/raw.h @@ -10,20 +10,25 @@ typedef struct __raw_allocator_cell { usize capacity; // 是content的长度 usize length; // 是实际使用的长度 - allocator_t *allocator; // 所在的分配器 - usize reserved; u8 content[0]; } raw_allocator_cell; #define raw_allocator_next_cell(cell) (raw_allocator_cell *)((void *)((cell)->content) + (cell)->capacity) -// 原始分配器 -// -// 包括至少一个cell,分配时像cell的分裂一样将空白的一段分成两段, -// 释放时,只把length归零,并不将cell合并。 -// length=0的cell称为空cell -// -// 统计从上次细胞合并以来free的调用次数,当调用次数很多或可用空间不足时 -// 触发细胞合并。 +/** + * @name raw_allocator_t + * + * 原始分配器。包括至少一个cell,分配时像cell的分裂一样将空白的一段分成两段,释放时,只把length归零,并不将cell合并。 + * + * `length`为0的cell称为空cell。 + * + * 统计从上次细胞合并以来free的调用次数,当调用次数达到`RAW_ALLOCATOR_FREE_MAX`或无可用空间时触发细胞合并。 + * + * 使用建议:只在少量allocate和free的情况下使用。使用大量allocate时效率低下并难以得到内存安全保证。 + * + * @internal free_count + * + * free方法的调用次数,达到`RAW_ALLOCATOR_FREE_MAX`时归零。 + */ typedef struct __raw_allocator_t { usize size; @@ -34,9 +39,23 @@ 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); -void *raw_allocator_allocate(raw_allocator_t *allocator, usize size, usize align); +/** + * @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); #endif diff --git a/include/kernel/syscall.h b/include/kernel/syscall.h new file mode 100644 index 0000000..fc2709b --- /dev/null +++ b/include/kernel/syscall.h @@ -0,0 +1,19 @@ +#ifndef SYSCALL_H +#define SYSCALL_H 1 + +#ifdef __x86_64__ +#include +#endif + +/** + * @name syscall_init + * + * ```c + * void syscall_init(); + * ``` + * + * 初始化系统调用。 + */ +void syscall_init(); + +#endif diff --git a/include/kernel/tty.h b/include/kernel/tty.h index 2a1e6c3..6edf00d 100644 --- a/include/kernel/tty.h +++ b/include/kernel/tty.h @@ -99,8 +99,8 @@ tty **tty_get(usize id); /** * @brief 获取tty的id - * - * @return usize + * + * @return usize */ usize tty_get_id(tty *__tty); @@ -121,6 +121,16 @@ void tty_set_framebuffer(tty *ttyx, framebuffer *fb); void tty_text_print(tty *ttyx, char *string, u32 color, u32 bgcolor); #define gen_color(r, g, b) (((r) << 16) | ((g) << 8) | (b)) +#define WHITE gen_color(0xee, 0xee, 0xee) +#define BLACK gen_color(0, 0, 0) +#define RED gen_color(0xee, 0x22, 0x22) +#define GREEN gen_color(0x22, 0xee, 0x22) +#define BLUE gen_color(0x22, 0x22, 0xee) +#define YELLOW gen_color(0xee, 0xee, 0x22) +#define ORANGE gen_color(0xee, 0xaa, 0x22) +#define PURPLE gen_color(0xee, 0, 0xee) +#define PINK gen_color(0xee, 0x44, 0x66) +#define GRAY gen_color(0xaa, 0xaa, 0xaa) usize tty_get_width(tty *ttyx); usize tty_get_height(tty *ttyx); @@ -132,8 +142,8 @@ bool tty_is_enabled(tty *ttyx); /** * @brief 打开某个tty - * - * @param ttyx + * + * @param ttyx * @return true 打开成功 * @return false 已经打开 * 或作为raw_framebuffer类型的tty,framebuffer已被其它raw_framebuffer diff --git a/include/libk/lst.h b/include/libk/lst.h index 4cc7e4d..205217c 100644 --- a/include/libk/lst.h +++ b/include/libk/lst.h @@ -33,7 +33,7 @@ bool lst_remove(lst_iterator_t *lst, usize left, usize right, bool force); /* 在`lst`中添加一个线段[left,right) force=true时忽略已经存在于`lst`中的线段 -force=false时若有存在于`lst`中的线段,只添加这些部分之外的线段,返回false,否则返回true +force=false时若有存在于`lst`中的线段,不添加任何线段,返回false,否则返回true */ bool lst_add(lst_iterator_t *lst, usize left, usize right, bool force); diff --git a/include/utils.h b/include/utils.h index 4050e10..22d08a3 100644 --- a/include/utils.h +++ b/include/utils.h @@ -3,14 +3,25 @@ #include -#define UTILS_BIT_GET(byte, bit) ((byte) & (1 << (bit))) -#define UTILS_BIT_SET(byte, bit) ((byte) |= (1 << (bit))); -#define UTILS_BIT_RESET(byte, bit) ((byte) &= ~(1 << (bit))); - -#define UTILS_BITMAP_GET(map, bit) (((u8 *)(map))[bit / 8] & (1 << ((bit) % 8))) -#define UTILS_BITMAP_SET(map, bit) (((u8 *)(map))[bit / 8] |= (1 << ((bit) % 8))); -#define UTILS_BITMAP_RESET(map, bit) (((u8 *)(map))[bit / 8] &= ~(1 << ((bit) % 8))); - #define DISALIGNED __attribute__((packed)) +#define into_bytes(addr) ((u8 *)(addr)) +#define bytes_into(bytes, type) ((type *)(bytes)) + +void pointer_to_string(u64 addr, char *dest); + +typedef struct __va_args +{ + usize length; + void *args[0]; +} va_args; + +#define va_args_gen(result, length) \ + void *__reserved__[length]; \ + va_args __va_args__; \ + result = &__va_args__; + +#define va_args_set(vaargs, index, val) \ + vaargs->args[index] = &val; + #endif diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..292fe49 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "stable" diff --git a/rustlib b/rustlib index 087c479..6a2ca2a 160000 --- a/rustlib +++ b/rustlib @@ -1 +1 @@ -Subproject commit 087c4795bbc23cd0baee060bda8c1159a971a542 +Subproject commit 6a2ca2afcd651e46f1c19f8d8a3f685fd982d824 diff --git a/src/scripts/colorize b/scripts/colorize similarity index 100% rename from src/scripts/colorize rename to scripts/colorize diff --git a/src/scripts/depcheck b/scripts/depcheck similarity index 68% rename from src/scripts/depcheck rename to scripts/depcheck index 9b20fda..295d7f1 100755 --- a/src/scripts/depcheck +++ b/scripts/depcheck @@ -49,15 +49,17 @@ for mod in kernel_modules: print(" " + color['lpink'] + f"{mod}" + color['reset'] + " exists.") else: print(" " + color['lred'] + f"{mod}" + color['reset'] + " not found.") - print("Kernel module " + - color['lred'] + f"{mod}" + color['reset'] + " is not installed.") + print( + "Kernel module " + + color['lred'] + f"{mod}" + color['reset'] + " is not installed.") exit(-1) # 检查软件依赖 pathsenv = os.environ.get("PATH").split(":") for software, progs in softwares.items(): - print("Checking " + color['lcyan'] + - f"{software}" + color['reset'] + " ...") + print( + "Checking " + color['lcyan'] + + f"{software}" + color['reset'] + " ...") for program in progs: exists = False for path in pathsenv: @@ -65,15 +67,19 @@ for software, progs in softwares.items(): exists = True break if exists: - print(" " + color['lyellow'] + - f"{program}" + color['reset'] + " existed.") + print( + " " + color['lyellow'] + + f"{program}" + color['reset'] + " existed.") else: - print(" " + color['lred'] + - f"{program}" + color['reset'] + " not found.") + print( + " " + color['lred'] + + f"{program}" + color['reset'] + " not found.") - print("Software " + color['lred'] + f"{software}" + - color['reset'] + " is not installed or completed.") + print( + "Software " + color['lred'] + f"{software}" + + color['reset'] + " is not installed or completed.") exit(-2) -print("All dependencies are " + - color['lgreen'] + "satisfied." + color['reset']) +print( + "All dependencies are " + + color['lgreen'] + "satisfied." + color['reset']) diff --git a/scripts/magicgen b/scripts/magicgen new file mode 100755 index 0000000..8b9d824 --- /dev/null +++ b/scripts/magicgen @@ -0,0 +1,7 @@ +#!/usr/bin/python + +import time + +curtime = str(int(time.time() * 1000)) + +print(curtime) diff --git a/src/Makefile b/src/Makefile index 7ccfc6c..ffbdcc9 100644 --- a/src/Makefile +++ b/src/Makefile @@ -2,7 +2,7 @@ ARCH := $(shell uname -m) PWD := $(shell pwd) -SOURCE := ${PWD}/scripts +SOURCE := ${PWD}/../scripts ifeq (${ARCH},x86_64) ASM = nasm ASMFLAGS = -f elf64 @@ -12,9 +12,14 @@ ifdef release release = 1 endif +ALLOCATOR_MAGIC = $(shell "${SOURCE}/magicgen" | sha512sum | head -c 128 | md5sum | head -c 8) + +BUILD_ID = $(shell "${SOURCE}/magicgen" | sha512sum | head -c 128 | md5sum | head -c 4) + SUBOBJS = kernel/kernel.o libk/libk.o rust.o -DEFINES = ARCH="${ARCH}" ASM="${ASM}" ASMFLAGS="${ASMFLAGS}" SOURCE="${SOURCE}" PWD="${PWD}" +DEFINES = ARCH="${ARCH}" ASM="${ASM}" ASMFLAGS="${ASMFLAGS}" SOURCE="${SOURCE}" PWD="${PWD}" \ + ALLOCATOR_MAGIC="${ALLOCATOR_MAGIC}" BUILD_ID="${BUILD_ID}" ifdef release DEFINES := ${DEFINES} release=1 endif @@ -25,24 +30,21 @@ endif RSCFLAGS = --emit obj --crate-type staticlib --verbose \ --crate-name=metaverse \ --edition 2021 \ - -L crate="${PWD}/../rustlib/${ARCH}/src/" \ + -L crate="${PWD}/../rustlib/src/" \ -C code-model=large \ -C relocation-model=static \ -C embed-bitcode=no ifeq (${ARCH},x86_64) RSCFLAGS := ${RSCFLAGS} --target x86_64-unknown-none -endif - -ifdef release - RSCFLAGS := -O -endif - -ifeq (${ARCH},x86_64) RSCFLAGS := ${RSCFLAGS} -C target-feature=-sse endif -RUSTLIB_PATH = ../rustlib/${ARCH}/lib +ifdef release + RSCFLAGS := ${RSCFLAGS} -O +endif + +RUSTLIB_PATH = ../rustlib/${ARCH} RUST_LIBS = "${RUSTLIB_PATH}/liballoc.rlib" "${RUSTLIB_PATH}/libcompiler_builtins.rlib" \ "${RUSTLIB_PATH}/libcore.rlib" "${RUSTLIB_PATH}/librustc_std_workspace_core.rlib" @@ -56,6 +58,8 @@ metaverse.elf: kernel libk rust metaverse.lds .PHONY: kernel libk all clear postproc rust all: postproc metaverse.elf + @echo -e "Build \e[1;32msucceeded\e[0m." + @echo -e "Build ID \e[1;31m${BUILD_ID}\e[0m." postproc: @echo -n -e "\e[36m" @@ -67,16 +71,24 @@ postproc: @echo -e "\e[0m" kernel: - @echo -e "\e[33m__\e[0m \e[1;35m[Building kernel]\e[0m \e[33m____\e[0m" + @if [ ! ${release} ]; then \ + echo -e "\e[33m__\e[0m \e[1;35m[Building kernel]\e[0m \e[33m____\e[0m"; \ + fi @make -C kernel all --no-print-directory ${DEFINES} - @echo -e "\e[33m-------------------------\e[0m" + @if [ ! ${release} ]; then \ + echo -e "\e[33m-------------------------\e[0m"; \ + fi libk: - @echo -e "\e[33m__\e[0m \e[1;35m[Building libk]\e[0m \e[33m______\e[0m" + @if [ ! ${release} ]; then \ + echo -e "\e[33m__\e[0m \e[1;35m[Building libk]\e[0m \e[33m______\e[0m"; \ + fi @make -C libk all --no-print-directory ${DEFINES} - @echo -e "\e[33m-------------------------\e[0m" + @if [ ! ${release} ]; then \ + echo -e "\e[33m-------------------------\e[0m"; \ + fi -rust: +rust: postproc @echo -e "\e[1m\e[33mrustc\e[0m \e[34m-->\e[0m \e[1m\e[32m$@.o\e[0m" @rustc ${RSCFLAGS} lib.rs -o rust.o diff --git a/src/kernel/Makefile b/src/kernel/Makefile index 093fa03..7346f5b 100644 --- a/src/kernel/Makefile +++ b/src/kernel/Makefile @@ -6,12 +6,15 @@ CC = gcc CCFLAGS = -m64 -mcmodel=large -I ../../include \ -fno-stack-protector -fno-exceptions \ - -fno-builtin -nostdinc -nostdlib + -fno-builtin -nostdinc -nostdlib \ + -DMEMM_ALLOCATOR_MAGIC="(u32)(0x${ALLOCATOR_MAGIC})" \ + -DBUILD_ID="${BUILD_ID}" ifdef release CCFLAGS := ${CCFLAGS} -O2 endif -C_SRCS = main.c tty.c font.c memm.c memm_${ARCH}.c raw.c time.c +C_SRCS = main.c tty.c font.c memm.c memm_${ARCH}.c raw.c time.c syscall_${ARCH}.c interrupt_${ARCH}.c \ + interrupt_procs.c C_OBJS = ${C_SRCS:.c=.c.o} ################################ @@ -26,7 +29,8 @@ endif ASMFLAGS := ${ASMFLAGS} ASMFLAGS32 = -f elf32 -S_SRCS = entry32.s entry.s memm_${ARCH}.s kernel.s +S_SRCS = entry32.s entry.s memm_${ARCH}.s kernel.s syscall_${ARCH}.s interrupt_${ARCH}.s \ + interrupt_procs.s S_OBJS = ${S_SRCS:.s=.s.o} ################################ diff --git a/src/kernel/arch/x86_64/entry.s b/src/kernel/arch/x86_64/entry.s index 04f86fd..2647c42 100644 --- a/src/kernel/arch/x86_64/entry.s +++ b/src/kernel/arch/x86_64/entry.s @@ -1,13 +1,32 @@ section .entry align=8 extern kmain + extern systemcall_procedure global init64 init64: endbr64 cli + mov rax, 0x1000000 mov rbp, rax mov rsp, rax mov rdi, rbx + + lidt [0x104010] + + ; 加载系统调用相关寄存器 + ; IA32_STAR = 0x0018_0008_0000_0000 + mov rcx, 0xc0000081 + mov rax, 0x0018000800000000 + wrmsr + ; IA32_FMASK = 0xffff_ffff + inc rcx + mov rax, 0xffffffff + wrmsr + ; IA32_LSTAR = [systemcall_procedure] + lea rcx, [rcx + 2] + lea rax, [systemcall_procedure] + wrmsr + jmp kmain section .multiboot2 align=8 diff --git a/src/kernel/arch/x86_64/entry32.s b/src/kernel/arch/x86_64/entry32.s index 57d618b..d6f99f6 100644 --- a/src/kernel/arch/x86_64/entry32.s +++ b/src/kernel/arch/x86_64/entry32.s @@ -1,9 +1,6 @@ section .entry extern init64 ; 寄存器ebx是multiboot2 information,不可以使用 - ; - ; 由于这个代码是32位环境的代码,而链接器链接时会把它当作64位代码链接 - ; 所以这里所有的使用了常数的位置都要通过指令写入 init32: cli @@ -37,18 +34,17 @@ init32: add edi, 4 loop init32_loop0 - ; 设置gdt_ptr - mov eax, 0x10402a ; gdt_ptr + 2 - mov dword [eax], 0x104000 ; gdt - ; 加载GDTR和段寄存器 + ; 加载GDTR、段寄存器和TR寄存器 db 0x66 - lgdt [0x104028] ; gdt_ptr + lgdt [0x104000] ; gdt_ptr mov ax, 0x10 mov ds, ax mov ss, ax mov es, ax mov fs, ax mov gs, ax + mov ax, 0x30 + ltr ax ; 打开PAE mov eax, cr4 @@ -77,7 +73,6 @@ init32: section .cpumeta align=4096 global PML4 ; 分页 - ; 链接器会把这些数据替换掉所以要在代码中重新设置 PML4: dq 0x003 + PDPT0 resq 511 @@ -89,15 +84,43 @@ PDPT0: PD0: resq 512 - ; 分段 -gdt: - dq 0 - dq 0x0020980000000000 ; 内核态代码段 - dq 0x0000920000000000 ; 内核态数据段 - dq 0x0020f80000000000 ; 用户态代码段 - dq 0x0000f20000000000 ; 用户态数据段 -gdt_end: + section .cpumeta.tblptrs -gdt_ptr: +gdt_ptr: ; 0x104000 dw gdt_end - gdt - 1 dq gdt + + dd 0 + dw 0 + +idt_ptr: ; 0x104010 + dw 0x7ff + dq idt + + section .cpumeta.gdt align=4096 +gdt: + dq 0 + dq 0x0020980000000000 ; 内核态代码段 + dq 0x0000920000000000 ; 内核态数据段 + dq 0x0020f80000000000 ; 用户态代码段 + dq 0x0000f20000000000 ; 用户态数据段 + dq 0 + dq 0x0000891070000068 ; TSS段(低64位) + dq 0 ; TSS段(高64位) +gdt_end: + + section .cpumeta.idt align=4096 + global idt +idt: + resq 512 ; 16 bytes per descriptor (512 q-bytes) + + section .cpumeta.tss align=4096 + global TSS +TSS: + dd 0 + dq 0x1000000 ; (rsp0)内核栈 + dq 0 ; (rsp1) + dq 0 ; (rsp2) + dq 0 + dq 0x400000 ; (ist1)中断栈 + resb 104 - ($ - TSS) diff --git a/src/kernel/arch/x86_64/interrupt.in b/src/kernel/arch/x86_64/interrupt.in new file mode 100644 index 0000000..9d9e9bf --- /dev/null +++ b/src/kernel/arch/x86_64/interrupt.in @@ -0,0 +1,79 @@ +%macro store_regs 0 + push rax + push rcx + push rbx + push rdx + push rsi + push rdi + push r8 + push r9 + push r10 + push r11 + push r12 + push r13 + push r14 + push r15 +%endmacro + +%macro retrieve_regs 0 + pop r15 + pop r14 + pop r13 + pop r12 + pop r11 + pop r10 + pop r9 + pop r8 + pop rdi + pop rsi + pop rdx + pop rbx + pop rcx + pop rax +%endmacro + +%macro switch_section 0 + sub rsp, 4 + mov ax, ds + push ax + mov ax, es + push ax + mov ax, 0x10 + mov ds, ax + mov es, ax +%endmacro + +%macro retrieve_section 0 + pop ax + mov es, ax + pop ax + mov ds, ax + add rsp, 4 +%endmacro + +%macro interrupt_entry_enter 0 + push rbp + lea rbp, [rsp] + store_regs + switch_section +%endmacro + +%macro interrupt_entry_leave 0 + retrieve_section + retrieve_regs + leave +%endmacro + +; 用于带有错误码的中断,创建一个没有错误码的上下文拷贝 +%macro interrupt_stack_wrap_texture 0 + extern memcpy + sub rsp, 21 * 8 + mov rdi, rsp + lea rsi, [rsp + 21 * 8] + mov rdx, 16 * 8 + call memcpy + lea rdi, [rsp + 16 * 8] + lea rsi, [rsp + 38 * 8] + mov rdx, 5 * 8 + call memcpy +%endmacro diff --git a/src/kernel/arch/x86_64/interrupt_procs.c b/src/kernel/arch/x86_64/interrupt_procs.c new file mode 100644 index 0000000..92359ac --- /dev/null +++ b/src/kernel/arch/x86_64/interrupt_procs.c @@ -0,0 +1,190 @@ +#include +#include +#include +#include +#include +#include + +interrupt_req_gen(UNSUPPORTED) +{ + tty **tty0_option = tty_get(0); + if (tty0_option == nullptr) + { + KERNEL_TODO(); + } + tty *tty0 = *tty0_option; + tty_text_print(tty0, "Panic: Unsupported interrupt.", RED, BLACK); + KERNEL_TODO(); +} + +static void rip_not_cannonical(u64 rip, tty *tty0) +{ + char num[17]; + memset(num, 0, sizeof(num)); + pointer_to_string(rip, num); + tty_text_print(tty0, "Panic", RED, BLACK); + tty_text_print(tty0, ": Unexpected non-cannonical %rip value ", WHITE, BLACK); + tty_text_print(tty0, num, ORANGE, BLACK); + tty_text_print(tty0, ".\n", WHITE, BLACK); + KERNEL_TODO(); +} + +interrupt_req_gen(DE) +{ + tty **tty0_option = tty_get(0); + if (tty0_option == nullptr) + { + KERNEL_TODO(); + } + tty *tty0 = *tty0_option; + if (!is_cannonical(rip)) + { + rip_not_cannonical(rip, tty0); + } + if (!is_user_address(rip)) + { + char nums[34]; + memset(nums, 0, sizeof(nums)); + pointer_to_string(rip, nums); + pointer_to_string(rsp, nums + 17); + tty_text_print(tty0, "Panic", RED, BLACK); + tty_text_print(tty0, ": Divided by zero occurs in kernel,\n\t", WHITE, BLACK); + tty_text_print(tty0, "with %rip=", WHITE, BLACK); + tty_text_print(tty0, "0x", ORANGE, BLACK); + tty_text_print(tty0, nums, ORANGE, BLACK); + tty_text_print(tty0, ", %rsp=", WHITE, BLACK); + tty_text_print(tty0, "0x", ORANGE, BLACK); + tty_text_print(tty0, nums + 17, ORANGE, BLACK); + tty_text_print(tty0, ".\n", WHITE, BLACK); + KERNEL_TODO(); + } + else + { // TODO 转储并结束进程 + KERNEL_TODO(); + } +} + +interrupt_req_gen(BP) +{ + tty **tty0_option = tty_get(0); + if (tty0_option == nullptr) + { + KERNEL_TODO(); + } + tty *tty0 = *tty0_option; + if (!is_cannonical(rip)) + { + rip_not_cannonical(rip, tty0); + } + proc_texture_registers_t *texture = (void *)errcode; + if (!is_user_address(rip)) + { + char nums[34]; + memset(nums, 0, sizeof(nums)); + pointer_to_string(rip, nums); + pointer_to_string(rsp, nums + 17); + tty_text_print(tty0, "Debug", PURPLE, BLACK); + tty_text_print(tty0, ": Kernel hit a breakpoint,\n\t", WHITE, BLACK); + tty_text_print(tty0, "with %rip=", WHITE, BLACK); + tty_text_print(tty0, "0x", ORANGE, BLACK); + tty_text_print(tty0, nums, ORANGE, BLACK); + tty_text_print(tty0, ", %rsp=", WHITE, BLACK); + tty_text_print(tty0, "0x", ORANGE, BLACK); + tty_text_print(tty0, nums + 17, ORANGE, BLACK); + tty_text_print(tty0, ",\n\t", WHITE, BLACK); + tty_text_print(tty0, "on texture: \n", WHITE, BLACK); + pointer_to_string(texture->rax, nums); + tty_text_print(tty0, "rax\t", WHITE, BLACK); + tty_text_print(tty0, nums, BLUE, BLACK); + tty_text_print(tty0, "\t", WHITE, BLACK); + pointer_to_string(texture->rcx, nums); + tty_text_print(tty0, "rcx\t", WHITE, BLACK); + tty_text_print(tty0, nums, BLUE, BLACK); + tty_text_print(tty0, "\n", WHITE, BLACK); + pointer_to_string(texture->rbx, nums); + tty_text_print(tty0, "rbx\t", WHITE, BLACK); + tty_text_print(tty0, nums, BLUE, BLACK); + tty_text_print(tty0, "\t", WHITE, BLACK); + pointer_to_string(texture->rdx, nums); + tty_text_print(tty0, "rdx\t", WHITE, BLACK); + tty_text_print(tty0, nums, BLUE, BLACK); + tty_text_print(tty0, "\n", WHITE, BLACK); + pointer_to_string(texture->rsi, nums); + tty_text_print(tty0, "rsi\t", WHITE, BLACK); + tty_text_print(tty0, nums, BLUE, BLACK); + tty_text_print(tty0, "\t", WHITE, BLACK); + pointer_to_string(texture->rdi, nums); + tty_text_print(tty0, "rdi\t", WHITE, BLACK); + tty_text_print(tty0, nums, BLUE, BLACK); + tty_text_print(tty0, "\n", WHITE, BLACK); + pointer_to_string(texture->rbp, nums); + tty_text_print(tty0, "rbp\t", WHITE, BLACK); + tty_text_print(tty0, nums, BLUE, BLACK); + tty_text_print(tty0, "\t", WHITE, BLACK); + pointer_to_string(texture->rsp, nums); + tty_text_print(tty0, "rsp\t", WHITE, BLACK); + tty_text_print(tty0, nums, BLUE, BLACK); + tty_text_print(tty0, "\n", WHITE, BLACK); + pointer_to_string(texture->rip, nums); + tty_text_print(tty0, "rip\t", WHITE, BLACK); + tty_text_print(tty0, nums, BLUE, BLACK); + tty_text_print(tty0, "\t", WHITE, BLACK); + pointer_to_string(texture->rflags, nums); + tty_text_print(tty0, "rflags\t", WHITE, BLACK); + tty_text_print(tty0, nums, BLUE, BLACK); + tty_text_print(tty0, "\n", WHITE, BLACK); + pointer_to_string(texture->r8, nums); + tty_text_print(tty0, "r8\t", WHITE, BLACK); + tty_text_print(tty0, nums, BLUE, BLACK); + tty_text_print(tty0, "\t", WHITE, BLACK); + pointer_to_string(texture->r9, nums); + tty_text_print(tty0, "r9\t", WHITE, BLACK); + tty_text_print(tty0, nums, BLUE, BLACK); + tty_text_print(tty0, "\n", WHITE, BLACK); + pointer_to_string(texture->r10, nums); + tty_text_print(tty0, "r10\t", WHITE, BLACK); + tty_text_print(tty0, nums, BLUE, BLACK); + tty_text_print(tty0, "\t", WHITE, BLACK); + pointer_to_string(texture->r11, nums); + tty_text_print(tty0, "r11\t", WHITE, BLACK); + tty_text_print(tty0, nums, BLUE, BLACK); + tty_text_print(tty0, "\n", WHITE, BLACK); + pointer_to_string(texture->r12, nums); + tty_text_print(tty0, "r12\t", WHITE, BLACK); + tty_text_print(tty0, nums, BLUE, BLACK); + tty_text_print(tty0, "\t", WHITE, BLACK); + pointer_to_string(texture->r13, nums); + tty_text_print(tty0, "r13\t", WHITE, BLACK); + tty_text_print(tty0, nums, BLUE, BLACK); + tty_text_print(tty0, "\n", WHITE, BLACK); + pointer_to_string(texture->r14, nums); + tty_text_print(tty0, "r14\t", WHITE, BLACK); + tty_text_print(tty0, nums, BLUE, BLACK); + tty_text_print(tty0, "\t", WHITE, BLACK); + pointer_to_string(texture->r15, nums); + tty_text_print(tty0, "r15\t", WHITE, BLACK); + tty_text_print(tty0, nums, BLUE, BLACK); + tty_text_print(tty0, "\n", WHITE, BLACK); + pointer_to_string(texture->cs, nums); + tty_text_print(tty0, "cs\t", WHITE, BLACK); + tty_text_print(tty0, nums, BLUE, BLACK); + tty_text_print(tty0, "\t", WHITE, BLACK); + pointer_to_string(texture->ss, nums); + tty_text_print(tty0, "ss\t", WHITE, BLACK); + tty_text_print(tty0, nums, BLUE, BLACK); + tty_text_print(tty0, "\n", WHITE, BLACK); + pointer_to_string(texture->ds, nums); + tty_text_print(tty0, "ds\t", WHITE, BLACK); + tty_text_print(tty0, nums, BLUE, BLACK); + tty_text_print(tty0, "\t", WHITE, BLACK); + pointer_to_string(texture->es, nums); + tty_text_print(tty0, "es\t", WHITE, BLACK); + tty_text_print(tty0, nums, BLUE, BLACK); + tty_text_print(tty0, "\n", WHITE, BLACK); + KERNEL_TODO(); + } + else + { // TODO 将当前进程的状态设置为暂停并通知当前进程的调试程序 + KERNEL_TODO(); + } +} diff --git a/src/kernel/arch/x86_64/interrupt_procs.s b/src/kernel/arch/x86_64/interrupt_procs.s new file mode 100644 index 0000000..d83e19e --- /dev/null +++ b/src/kernel/arch/x86_64/interrupt_procs.s @@ -0,0 +1,97 @@ +%include "arch/x86_64/interrupt.in" + +; 栈中的寄存器上下文 +; +------------ +; | ss +; +------------<-- rsp+168(+160) +; | rsp +; +------------<-- rsp+160(+152) +; | rflags +; +------------<-- rsp+152(+144) +; | cs +; +------------<-- rsp+144(+136) +; | rip +; +------------<-- rsp+136(+128) +; | (err code) +; +------------<-- rsp+128 +; | rbp +; +------------<-- rsp+120 +; | rax +; +------------<-- rsp+112 +; | rcx +; +------------<-- rsp+104 +; | rbx +; +------------<-- rsp+96 +; | rdx +; +------------<-- rsp+88 +; | rsi +; +------------<-- rsp+80 +; | rdi +; +------------<-- rsp+72 +; | r8 +; +------------<-- rsp+64 +; | r9 +; +------------<-- rsp+56 +; | r10 +; +------------<-- rsp+48 +; | r11 +; +------------<-- rsp+40 +; | r12 +; +------------<-- rsp+32 +; | r13 +; +------------<-- rsp+24 +; | r14 +; +------------<-- rsp+16 +; | r15 +; +------------<-- rsp+8 +; | reserved +; +------------<-- rsp+4 +; | ds +; +------------<-- rsp+2 +; | es +; +------------<-- rsp+0 + + section .text + + global interrupt_entry_UNSUPPORTED + extern interrupt_req_UNSUPPORTED +interrupt_entry_UNSUPPORTED: + interrupt_entry_enter + + mov rdi, [rsp + 128] + mov rsi, [rsp + 152] + call interrupt_req_UNSUPPORTED + + interrupt_entry_leave + iret + + global interrupt_entry_DE + extern interrupt_req_DE +interrupt_entry_DE: + interrupt_entry_enter + + mov rdi, [rsp + 128] + mov rsi, [rsp + 152] + call interrupt_req_DE + + interrupt_entry_leave + iret + + global interrupt_entry_DE +interrupt_entry_NMI: + ; TODO 暂时不需要为这个中断实现任何功能 + iret + + global interrupt_entry_BP + extern interrupt_req_BP +interrupt_entry_BP: + interrupt_entry_enter + + mov rdi, [rsp + 128] + mov rsi, [rsp + 152] + mov dword [rsp + 4], 0 + mov rdx, rsp + call interrupt_req_BP + + interrupt_entry_leave + iret diff --git a/src/kernel/arch/x86_64/interrupt_x86_64.c b/src/kernel/arch/x86_64/interrupt_x86_64.c new file mode 100644 index 0000000..6879f22 --- /dev/null +++ b/src/kernel/arch/x86_64/interrupt_x86_64.c @@ -0,0 +1,25 @@ +#include +#include + +#include + +void interrupt_init() +{ + gate_descriptor_t gate; + trap_gate_generate(gate, interrupt_entry_sym(UNSUPPORTED)); + for (usize i = 4; i < 256; i++) + { + interrupt_register_gate(gate, i); + } + + trap_gate_generate(gate, interrupt_entry_sym(DE)); + interrupt_register_gate(gate, 0); + trap_gate_generate(gate, interrupt_entry_sym(UNSUPPORTED)); + interrupt_register_gate(gate, 1); + trap_gate_generate(gate, interrupt_entry_sym(NMI)); + interrupt_register_gate(gate, 2); + trap_gate_generate(gate, interrupt_entry_sym(BP)); + interrupt_register_gate(gate, 3); + + interrupt_open(); +} diff --git a/src/kernel/arch/x86_64/interrupt_x86_64.s b/src/kernel/arch/x86_64/interrupt_x86_64.s new file mode 100644 index 0000000..5ca55b7 --- /dev/null +++ b/src/kernel/arch/x86_64/interrupt_x86_64.s @@ -0,0 +1,11 @@ + section .text + + global interrupt_open +interrupt_open: + sti + ret + + global interrupt_close +interrupt_close: + cli + ret diff --git a/src/kernel/arch/x86_64/memm_x86_64.c b/src/kernel/arch/x86_64/memm_x86_64.c index cd86dba..913e919 100644 --- a/src/kernel/arch/x86_64/memm_x86_64.c +++ b/src/kernel/arch/x86_64/memm_x86_64.c @@ -9,8 +9,9 @@ map_pageframe_to((u64)addr, (u64)addr, false, true, MEMM_PAGE_SIZE_4K); // 这里的physical必须保证根据ps对齐 -static void map_pageframe_to(u64 target, u64 physical, - bool user, bool write, memm_page_size ps) +static void map_pageframe_to( + u64 target, u64 physical, + bool user, bool write, memm_page_size ps) { if (!is_cannonical(target)) return; @@ -22,7 +23,7 @@ static void map_pageframe_to(u64 target, u64 physical, PDPT = (u64 *)memm_entry_get_address(pml4e); else { - PDPT = (u64 *)(find_fitable_pages(1) * MEMM_PAGE_SIZE); + PDPT = memm_allcate_pagetable(); map_pagemap(PDPT); memset(PDPT, 0, MEMM_PAGE_SIZE); @@ -50,7 +51,7 @@ static void map_pageframe_to(u64 target, u64 physical, PDT = (u64 *)memm_entry_get_address(pdpte); else { - PDT = (u64 *)(find_fitable_pages(1) * MEMM_PAGE_SIZE); + PDT = memm_allcate_pagetable(); map_pagemap(PDT); memset(PDT, 0, MEMM_PAGE_SIZE); @@ -78,7 +79,7 @@ static void map_pageframe_to(u64 target, u64 physical, PT = (u64 *)memm_entry_get_address(pde); else { - PT = (u64 *)(find_fitable_pages(1) * MEMM_PAGE_SIZE); + PT = memm_allcate_pagetable(); map_pagemap(PT); memset(PT, 0, MEMM_PAGE_SIZE); @@ -110,7 +111,6 @@ bool memm_map_pageframes_to( return false; while (size != 0) { - // 这是当前需要映射的页的内存对齐(或者说是当前映射的页的大小) memm_page_size align = memm_get_page_align(physical); if (align == MEMM_PAGE_SIZE_1G) { diff --git a/src/kernel/arch/x86_64/syscall_x86_64.c b/src/kernel/arch/x86_64/syscall_x86_64.c new file mode 100644 index 0000000..0d2ea49 --- /dev/null +++ b/src/kernel/arch/x86_64/syscall_x86_64.c @@ -0,0 +1,8 @@ +#include + +#include + +void syscall_init() +{ + memset(&system_calls_table, 0, sizeof(system_calls_table)); +} diff --git a/src/kernel/arch/x86_64/syscall_x86_64.s b/src/kernel/arch/x86_64/syscall_x86_64.s new file mode 100644 index 0000000..d8220b7 --- /dev/null +++ b/src/kernel/arch/x86_64/syscall_x86_64.s @@ -0,0 +1,91 @@ + section .data + global system_calls_table +system_calls_table: + resq 256 + +kernel_stack_cache: + dq 0, 0 ; 分别为 rbp, rsp + + section .text + global systemcall_procedure + global save_kernel_stack +systemcall_procedure: + endbr64 + call load_kernel_stack + push rbp + mov rbp, rsp + + shl rax, 3 ; rax *= 8 + ; 将对应调用号的系统调用加载至rax + lea rdi, [system_calls_table] + lea rax, [rax + rdi] + ; 判断是否为空调用 + cmp rax, 0 + je systemcall_procedure_none_call + mov rax, [rax] + ; 调用对应的系统调用 + call rax + + leave + call save_kernel_stack + sysret + +systemcall_procedure_none_call: + ; TODO 调用了不存在的系统调用,属于无法恢复的错误,应保存错误状态并结束调用进程 + ; 暂时直接sysret + leave + call save_kernel_stack + sysret + +; void set_kernel_stack_cache(usize stack) +set_kernel_stack_cache: + endbr64 + push rax + + lea rax, [kernel_stack_cache] + mov [rax], rdi + lea rax, [rax + 8] + mov [rax], rdi + + pop rax + ret + +; void return_from_systemcall() +return_from_systemcall: + sysret + +save_kernel_stack: + endbr64 + lea rbx, [kernel_stack_cache] + ; 交换[rbx]与rbp + mov rdi, [rbx] + xor rbp, rdi + xor rdi, rbp + xor rbp, rdi + mov [rbx], rdi + lea rbx, [rbx + 8] + ; 交换[rbx]与rsp + mov rdi, [rbx] + xor rsp, rdi + xor rdi, rsp + xor rsp, rdi + mov [rbx], rdi + ret + +load_kernel_stack: + endbr64 + lea rbx, [kernel_stack_cache] + ; 交换[rbx]与rbp + mov rdi, [rbx] + xor rbp, rdi + xor rdi, rbp + xor rbp, rdi + mov [rbx], rdi + lea rbx, [rbx + 8] + ; 交换[rbx]与rsp + mov rdi, [rbx] + xor rsp, rdi + xor rdi, rsp + xor rsp, rdi + mov [rbx], rdi + ret diff --git a/src/kernel/klog.rs b/src/kernel/klog.rs index 756d84d..8c55f00 100644 --- a/src/kernel/klog.rs +++ b/src/kernel/klog.rs @@ -1,4 +1,3 @@ -use alloc::string::ToString; use alloc::vec; use alloc::vec::Vec; @@ -140,7 +139,7 @@ impl KernelLogger { return false; } } - return true; + true }; while !all_end(&indeces, &logs) { let mut min_ind = None; @@ -181,7 +180,7 @@ impl<'a> Iterator for LogIterator<'a> { let res = if let Some((time, msg)) = self.logs.first() { Some( MessageBuilder::new() - .message(&time.to_string()) + .message(time) .append(MessageBuilder::from_message(msg.clone())) .build(), ) diff --git a/src/kernel/main.c b/src/kernel/main.c index 70f8871..495e4b2 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -1,6 +1,8 @@ #include #include #include +#include +#include #include #include @@ -33,7 +35,7 @@ void kmain(void *mb2_bootinfo) } // 初始化内存管理模块 - mem_manager_t *memm = memm_new(mem_size); + memory_manager_t *memm = memm_new(mem_size); // 初始化tty模块 tty_controller_t *tty_controler = tty_controller_new(); @@ -41,6 +43,13 @@ void kmain(void *mb2_bootinfo) get_frame_buffer_with_bootinfo(&fb, &bootinfo); tty *tty0 = tty_new(tty_type_raw_framebuffer, tty_mode_text); tty_set_framebuffer(tty0, &fb); + tty_enable(tty0); + + // 初始化中断管理 + interrupt_init(); + + // 初始化系统调用 + syscall_init(); // 为rust准备正确对齐的栈 prepare_stack(); diff --git a/src/kernel/main.rs b/src/kernel/main.rs index d50d8b1..4bb1227 100644 --- a/src/kernel/main.rs +++ b/src/kernel/main.rs @@ -8,7 +8,6 @@ use super::{ #[no_mangle] extern "C" fn kmain_rust() -> ! { let tty = Tty::from_id(0).unwrap(); - tty.enable(); let mut logger = KernelLogger::new(); logger.info(message!( Msg("Hello, "), diff --git a/src/kernel/memm/allocator/raw.c b/src/kernel/memm/allocator/raw.c index ce158de..8080fee 100644 --- a/src/kernel/memm/allocator/raw.c +++ b/src/kernel/memm/allocator/raw.c @@ -13,7 +13,7 @@ void raw_allocator_new(raw_allocator_t *allocator, usize size) allocator->cells[0].length = 0; } -void *raw_allocator_allocate(raw_allocator_t *allocator, usize size, usize align) +void *raw_allocator_allocate(raw_allocator_t *allocator, usize size) { usize real_size = size; align_to(real_size, 16); @@ -72,7 +72,7 @@ void raw_allocator_free(raw_allocator_t *allocator, void *mem) { raw_allocator_cell *cell = allocator->cells; while ((void *)cell < raw_allocator_end(allocator)) - { + { // TODO 内存错误 if (mem == cell->content) { cell->length = 0; @@ -83,7 +83,7 @@ void raw_allocator_free(raw_allocator_t *allocator, void *mem) allocator->rest_memory += cell->capacity + sizeof(raw_allocator_cell); allocator->free_count++; if ( // 可用内存不超过当前allocator的 5% 或调用free次数很多时 - allocator->size / allocator->rest_memory > 20 && + allocator->size / allocator->rest_memory > 20 || allocator->free_count > RAW_ALLOCATOR_FREE_MAX) { raw_allocator_cellmerge(allocator); diff --git a/src/kernel/memm/memm.c b/src/kernel/memm/memm.c index 787befa..c2ae788 100644 --- a/src/kernel/memm/memm.c +++ b/src/kernel/memm/memm.c @@ -5,9 +5,9 @@ #include #include -mem_manager_t memory_manager; +memory_manager_t memory_manager; -mem_manager_t *memm_new(usize mem_size) +memory_manager_t *memm_new(usize mem_size) { memset(&memory_manager, 0, sizeof(memory_manager)); memory_manager.memory_size = mem_size; @@ -17,62 +17,25 @@ mem_manager_t *memm_new(usize mem_size) usize kernel_initial_size = (usize)&kend; align_to(kernel_initial_size, MEMM_PAGE_SIZE); - // 配置分配器树 allocator_t *allocator0 = memm_allocator_new( (void *)kernel_initial_size, - memory_manager.alloc_only_memory - kernel_initial_size, + memory_manager.alloc_only_memory - MEMM_PAGE_TABLE_AREA_MAX - kernel_initial_size, MEMM_RAW_ALLOCATOR, 0); - allocator_iterator_t *alcatr_ind = allocator0->allocate( - &allocator0->allocator_instance, sizeof(allocator_iterator_t), 0); + memory_manager.kernel_base_allocator = allocator0; - alcatr_ind->allocator = allocator0; - alcatr_ind->left = nullptr; - alcatr_ind->right = nullptr; - - memory_manager.allocators = alcatr_ind; - - // 配置页映射地图 - usize pmc_size = memory_manager.page_amount; - align_to(pmc_size, 8); - pmc_size /= 8; - - memory_manager.page_map = allocator0->allocate(&allocator0->allocator_instance, pmc_size, 0); - memset(memory_manager.page_map, 0, pmc_size); - memset(memory_manager.page_map, 0xff, MEMM_ALLOC_ONLY_MEMORY / MEMM_PAGE_SIZE / 8); - for (usize i = (MEMM_ALLOC_ONLY_MEMORY / MEMM_PAGE_SIZE / 8) * (u8)8; - i < MEMM_ALLOC_ONLY_MEMORY / MEMM_PAGE_SIZE % 8; i++) - { - bitmap_set(memory_manager.page_map, i); - } - - // 配置分配器页地图 - memory_manager.map_with_allocator = - allocator0->allocate(&allocator0->allocator_instance, pmc_size, 0); - memset(memory_manager.map_with_allocator, 0, pmc_size); - for (usize i = kernel_initial_size / MEMM_PAGE_SIZE; - i < MEMM_ALLOC_ONLY_MEMORY / MEMM_PAGE_SIZE; - i += MEMM_PAGE_SIZE) - { - bitmap_set(memory_manager.map_with_allocator, i); - } - - // 分配器释放页地图 - memory_manager.map_with_destructed_allocator = - allocator0->allocate(&allocator0->allocator_instance, pmc_size, 0); - memset(memory_manager.map_with_destructed_allocator, 0, pmc_size); - - // 配置空闲页线段搜索表 - memory_manager.available_pages_table = lst_new(0, memory_manager.page_amount); - lst_remove(memory_manager.available_pages_table, 0, MEMM_ALLOC_ONLY_MEMORY / MEMM_PAGE_SIZE, false); + return &memory_manager; +} +memory_manager_t *memm_get_manager() +{ return &memory_manager; } allocator_t *memm_allocator_new(void *start, usize length, usize type, usize pid) { allocator_t *allocator = start; - allocator->initialized = true; + allocator->magic = MEMM_ALLOCATOR_MAGIC; allocator->full = false; allocator->pid = 0; allocator->size = length; @@ -85,166 +48,47 @@ allocator_t *memm_allocator_new(void *start, usize length, usize type, usize pid allocator->free = (memm_free_t)raw_allocator_free; break; default: - allocator->initialized = false; + allocator->magic = 0; break; } } void memm_allocator_destruct(allocator_t *allocator) { - allocator->initialized = false; + allocator->magic = 0; // TODO 从分配器树中删除这个分配器 KERNEL_TODO(); } -void *memm_find_and_allocate(allocator_iterator_t *allocator_ind, usize size, usize pid, allocator_t **writeback) -{ - void *ptr; - allocator_t *allocator = allocator_ind->allocator; - if (allocator->pid == pid && allocator->full == false) - { // 尝试用本节点分配 - if ((ptr = allocator->allocate(&allocator->allocator_instance, size, 0)) != nullptr) - { - *writeback = allocator; - return ptr; - } - else - { - if ((ptr = allocator->allocate(&allocator->allocator_instance, 0, 0)) == nullptr) - allocator->full = true; - } - } - if (allocator_ind->left != nullptr) - { // 尝试用左子树分配 - ptr = memm_find_and_allocate(allocator_ind->left, size, pid, writeback); - if (ptr != nullptr) - return ptr; - } - if (allocator_ind->right != nullptr) - { // 尝试用右子树分配 - ptr = memm_find_and_allocate(allocator_ind->right, size, pid, writeback); - if (ptr != nullptr) - return ptr; - } - // 都不行就只能返回nullptr - return nullptr; -} - -static void insert_allocator(allocator_iterator_t *iter, allocator_iterator_t *inserter) -{ - if (inserter->allocator < iter->allocator) - { - if (iter->left == nullptr) - { - iter->left = inserter; - return; - } - else - { - insert_allocator(iter->left, inserter); - } - } - else if (inserter->allocator > iter->allocator) - { - if (iter->right == nullptr) - { - iter->right = inserter; - return; - } - else - { - insert_allocator(iter->right, inserter); - } - } -} - -void *memm_allocate(usize size, usize pid) -{ - usize orgsize = size; - // 从分配器树中分配内存 - allocator_t *allocator; - void *ptr = memm_find_and_allocate(memory_manager.allocators, size, pid, &allocator); - if (ptr != nullptr) - goto after_allocation; - - // 分配器树中没有可分配的内存 - size += sizeof(allocator_t) + MEMM_PAGE_SIZE; - align_to(size, MEMM_PAGE_SIZE); - size /= MEMM_PAGE_SIZE; - usize allocator_start = find_fitable_pages(size); - if (allocator_start == 0) - return nullptr; // 内存中已经没有可分配的页了 - for (usize i = allocator_start; i < allocator_start + size; i++) - { - bitmap_set(memory_manager.map_with_allocator, i); - } - memm_map_pageframes_to( - allocator_start * MEMM_PAGE_SIZE, allocator_start * MEMM_PAGE_SIZE, - size * MEMM_PAGE_SIZE, - false, // 用户空间标志 - true // 写权限 - ); - - // 在新映射的页中创建一个分配器 - // TODO 在用户态可能需要实现一个效率更高的分配器 - allocator_t *new_allocator = - memm_allocator_new((void *)(allocator_start * MEMM_PAGE_SIZE), size * MEMM_PAGE_SIZE, - MEMM_RAW_ALLOCATOR, pid); - allocator = new_allocator; - - allocator_iterator_t *allind = memm_kernel_allocate(sizeof(allocator_iterator_t)); - allind->allocator = new_allocator; - allind->left = nullptr; - allind->right = nullptr; - insert_allocator(memory_manager.allocators, allind); - ptr = new_allocator->allocate(&new_allocator->allocator_instance, orgsize, 0); - -after_allocation: - if (ptr != nullptr) - memm_addr_set_allocator(ptr, allocator); - return ptr; -} - void *memm_kernel_allocate(usize size) { - return memm_allocate(size, 0); -} - -void *memm_user_allocate(usize size, usize pid) -{ - void *res = memm_allocate(size, pid); - // TODO 将内存空间映射到用户空间 - return res; + allocator_t *allocator = memory_manager.kernel_base_allocator; + return allocator->allocate(allocator->allocator_instance, size); } void memm_free(void *mem) { - allocator_t *allocator = memm_addr_get_allocator(mem); + allocator_t *allocator = memory_manager.kernel_base_allocator; + if (allocator->magic != MEMM_ALLOCATOR_MAGIC) + return; if (is_user_address((u64)mem)) - { // TODO 对于用户空间的地址需要先转换到内核地址后释放 + { + mem = mem - allocator->userspace + (void *)allocator; } allocator->free(allocator->allocator_instance, mem); if (allocator->full) allocator->full = false; } -usize find_fitable_pages(usize page_count) +void *memm_allcate_pagetable() { - usize res = 0; - lst_iterator_t *iter = memory_manager.available_pages_table; - do + if (memory_manager.page_table_area < MEMM_PAGE_TABLE_AREA_MAX) { - if (iter->line.right - iter->line.left > page_count) - { - res = iter->line.left; - lst_remove(iter, res, res + page_count, false); - for (usize i = res; i < res + page_count; i++) - { - bitmap_set(memory_manager.page_map, i); - } - break; - } - } while ((iter = lst_next(iter)) != nullptr); - memory_manager.mapped_page_amount += page_count; - return res; + memory_manager.page_table_area += MEMM_PAGE_TABLE_SIZE; + return memory_manager.alloc_only_memory - memory_manager.page_table_area; + } + else + { + // TODO + } } diff --git a/src/kernel/tty/tty.c b/src/kernel/tty/tty.c index 2d63e9d..21e1418 100644 --- a/src/kernel/tty/tty.c +++ b/src/kernel/tty/tty.c @@ -58,8 +58,8 @@ void tty_set_framebuffer(tty *ttyx, framebuffer *fb) ttyx->height = ttyx->typeinfo.raw_framebuffer.height; if (ttyx->mode == tty_mode_text) { - ttyx->text.width = fb->width / tty_get_font()->char_width; - ttyx->text.height = fb->height / tty_get_font()->char_height; + ttyx->text.width = fb->width / (TTY_FONT_SCALE * tty_get_font()->char_width); + ttyx->text.height = fb->height / (TTY_FONT_SCALE * tty_get_font()->char_height); ttyx->text.line = 0; ttyx->text.column = 0; } @@ -175,17 +175,20 @@ void tty_text_print(tty *ttyx, char *string, u32 color, u32 bgcolor) } else if (c == '\t') { // 水平制表符 + putchar(ttyx, ' ', 0, 0); ttyx->text.column += 8; ttyx->text.column -= ttyx->text.column % 8; continue; } else if (c == '\r') { // 回到行首 + putchar(ttyx, ' ', 0, 0); ttyx->text.column = 0; continue; } else if (c == '\v') { // 垂直制表符 + putchar(ttyx, ' ', 0, 0); ttyx->text.line++; if (ttyx->text.line == ttyx->text.height) { diff --git a/src/kernel/tty/tty.rs b/src/kernel/tty/tty.rs index 50b1470..3fe729e 100644 --- a/src/kernel/tty/tty.rs +++ b/src/kernel/tty/tty.rs @@ -150,10 +150,11 @@ impl Color { pub const RED: Color = Color(0xee, 0x22, 0x22); pub const GREEN: Color = Color(0x22, 0xee, 0x22); pub const BLUE: Color = Color(0x22, 0x22, 0xee); - pub const YELLOW: Color = Color(0xee, 0x22, 0x22); - pub const ORANGE: Color = Color(0xee, 0xee, 0x22); - pub const PURPLE: Color = Color(0xee, 0, 0xee); + pub const YELLOW: Color = Color(0xee, 0xee, 0x22); + pub const ORANGE: Color = Color(0xee, 0xaa, 0x22); + pub const PURPLE: Color = Color(0xee, 0x22, 0xee); pub const PINK: Color = Color(0xee, 0x44, 0x66); + pub const GRAY: Color = Color(0xaa, 0xaa, 0xaa); } impl From for u32 { @@ -181,6 +182,16 @@ pub struct MessageSection { #[derive(Clone)] pub struct Message(Vec); +impl ToString for Message { + fn to_string(&self) -> String { + let mut res = String::new(); + for MessageSection { msg, .. } in self.0.iter() { + res += msg; + } + res + } +} + /// ## MessageBuilder /// /// 使用链式调用模式构造一个消息. @@ -196,6 +207,19 @@ pub struct Message(Vec); /// .build(); /// ``` /// +/// 定义了`message!`宏,简化构造消息的代码: +/// +/// ```rust +/// use crate::kernel::tty::tty::BuilderFunctions::*; +/// +/// message!( +/// Msg("Hello, "), +/// Msg("Metaverse"), +/// FgColor(Color::GREEN), +/// Msg("!\n"), +/// ); +/// ``` +/// /// 对于特殊情况可以使用非链式调用: /// ```rust /// let mut msg = MessageBuilder::new(); @@ -226,7 +250,7 @@ impl MessageBuilder { Self { msg } } - pub fn message(mut self, msg: &str) -> Self { + pub fn message(mut self, msg: &T) -> Self { self.msg.0.push(MessageSection { msg: msg.to_string(), fgcolor: Color(0xee, 0xee, 0xee), @@ -235,7 +259,7 @@ impl MessageBuilder { self } - pub fn message_mut(&mut self, msg: &str) { + pub fn message_mut(&mut self, msg: &T) { self.msg.0.push(MessageSection { msg: msg.to_string(), fgcolor: Color(0xee, 0xee, 0xee), diff --git a/src/libk/Makefile b/src/libk/Makefile index 6f49226..56776b3 100644 --- a/src/libk/Makefile +++ b/src/libk/Makefile @@ -11,7 +11,7 @@ ifdef release CCFLAGS := ${CCFLAGS} -O2 endif -C_SRCS = bootinfo.c lst.c +C_SRCS = bootinfo.c lst.c utils.c C_OBJS = ${C_SRCS:.c=.c.o} ################################ diff --git a/src/libk/utils.c b/src/libk/utils.c new file mode 100644 index 0000000..8e986f9 --- /dev/null +++ b/src/libk/utils.c @@ -0,0 +1,11 @@ +#include + +void pointer_to_string(u64 addr, char *dest) +{ + for (u8 i = 0; i < 16; i++) + { + char c = addr & 0xf; + dest[15 - i] = (c < 10) ? c + '0' : c - 10 + 'a'; + addr >>= 4; + } +} diff --git a/src/metaverse.lds b/src/metaverse.lds index 87da7f2..1c8009e 100644 --- a/src/metaverse.lds +++ b/src/metaverse.lds @@ -13,10 +13,26 @@ SECTIONS { { *(.multiboot2) } - .cpumeta : + .cpumeta ALIGN(4096) : { *(.cpumeta) } + .cpumeta.tblptrs ALIGN(4096) : + { + *(cpumeta.tblptrs) + } + .cpumeta.gdt ALIGN(4096) : + { + *(.cpumeta.gdt) + } + .cpumeta.idt ALIGN(4096) : + { + *(.cpumeta.idt) + } + .cpumeta.tss ALIGN(4096) : + { + *(.cpumeta.tss) + } . = 16M; .text : {