diff --git a/include/kernel/arch/x86_64/interrupt.h b/include/kernel/arch/x86_64/interrupt.h new file mode 100644 index 0000000..e4110a2 --- /dev/null +++ b/include/kernel/arch/x86_64/interrupt.h @@ -0,0 +1,26 @@ +#ifndef X86_64_INTERRUPT_H +#define X86_64_INTERRUPT_H 1 + +#include + +typedef struct __gate_descriptor_t +{ + u16 offset_01; + u16 segment_selector; // for code segment + u16 flags; + u16 offset_23; + u32 offset_4567; + u32 reserved; +} gate_descriptor_t; + +// interrupt stack table,每个表项都指向tss +// 需要加载寄存器IA32_INTERRUPT_SSP_TABLE +#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) + +extern gate_descriptor_t idt[256]; + +#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..3ed2abf --- /dev/null +++ b/include/kernel/arch/x86_64/syscall.h @@ -0,0 +1,31 @@ +#ifndef X86_64_SYSCALL +#define X86_64_SYSCALL 1 + +#include + +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(); + +extern void set_kernel_stack_cache(usize stack); + +#endif diff --git a/include/kernel/interrupt.h b/include/kernel/interrupt.h new file mode 100644 index 0000000..b2f703b --- /dev/null +++ b/include/kernel/interrupt.h @@ -0,0 +1,7 @@ +#ifndef INTERRUPT_H +#define INTERRUPT_H 1 + +void interrupt_open(); +void interrupt_close(); + +#endif diff --git a/include/kernel/syscall.h b/include/kernel/syscall.h new file mode 100644 index 0000000..1c9507a --- /dev/null +++ b/include/kernel/syscall.h @@ -0,0 +1,10 @@ +#ifndef SYSCALL_H +#define SYSCALL_H 1 + +#ifdef __x86_64__ +#include +#endif + +void syscall_init(); + +#endif diff --git a/src/kernel/Makefile b/src/kernel/Makefile index 093fa03..f47b005 100644 --- a/src/kernel/Makefile +++ b/src/kernel/Makefile @@ -11,7 +11,7 @@ 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 C_OBJS = ${C_SRCS:.c=.c.o} ################################ @@ -26,7 +26,7 @@ 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 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..efbb1ad 100644 --- a/src/kernel/arch/x86_64/entry.s +++ b/src/kernel/arch/x86_64/entry.s @@ -1,13 +1,31 @@ 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 + + ; 加载系统调用相关寄存器 + ; 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..f68326e 100644 --- a/src/kernel/arch/x86_64/entry32.s +++ b/src/kernel/arch/x86_64/entry32.s @@ -37,6 +37,13 @@ init32: add edi, 4 loop init32_loop0 + ; 设置idt_ptr + mov eax, 0x10403a ; idt_ptr + 2 + mov dword [eax], 0x104050 + ; 加载IDTR寄存器 + db 0x66 + lidt [0x104038] + ; 设置gdt_ptr mov eax, 0x10402a ; gdt_ptr + 2 mov dword [eax], 0x104000 ; gdt @@ -98,6 +105,18 @@ gdt: dq 0x0000f20000000000 ; 用户态数据段 gdt_end: -gdt_ptr: +gdt_ptr: ; 0x104028 dw gdt_end - gdt - 1 dq gdt + + resb 6 + +idt_ptr: ; 0x104038 + dw 0x7ff + dq idt + + resb 14 + + global idt +idt: + resq 512 ; 16 bytes per descriptor (512 q-bytes) diff --git a/src/kernel/arch/x86_64/kernel.s b/src/kernel/arch/x86_64/kernel.s index ddb5b2b..12e8a26 100644 --- a/src/kernel/arch/x86_64/kernel.s +++ b/src/kernel/arch/x86_64/kernel.s @@ -19,3 +19,13 @@ prepare_stack: mov rax, [rax] mov [rsp], rax ret + + global interrupt_open +interrupt_open: + sti + ret + + global interrupt_close +interrupt_close: + cli + ret 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..8b9ae7a --- /dev/null +++ b/src/kernel/arch/x86_64/syscall_x86_64.s @@ -0,0 +1,87 @@ + 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 + +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/main.c b/src/kernel/main.c index 70f8871..06be3cb 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -1,6 +1,8 @@ #include #include #include +#include +#include #include #include @@ -42,6 +44,9 @@ void kmain(void *mb2_bootinfo) tty *tty0 = tty_new(tty_type_raw_framebuffer, tty_mode_text); tty_set_framebuffer(tty0, &fb); + // 初始化系统调用 + syscall_init(); + // 为rust准备正确对齐的栈 prepare_stack();