diff --git a/README.md b/README.md index a8c2ab2d..58668442 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ bximage - [ ] IPC进程间通信 -- [ ] 第一个系统调用函数 +- [x] 第一个系统调用函数 - [ ] 在物理平台上启动DragonOS diff --git a/README_EN.md b/README_EN.md index b4f2425f..3f440ca3 100644 --- a/README_EN.md +++ b/README_EN.md @@ -56,7 +56,7 @@ bximage - [ ] IPC -- [ ] First system call function +- [x] First system call function - [ ] Start dragonos on the physical platform diff --git a/kernel/Makefile b/kernel/Makefile index edac1278..61f9001e 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -10,8 +10,8 @@ all: kernel objcopy -I elf64-x86-64 -S -R ".eh_frame" -R ".comment" -O binary kernel ../bin/kernel/kernel.bin -kernel: head.o entry.o main.o printk.o trap.o mm.o irq.o 8259A.o process.o - ld -b elf64-x86-64 -z muldefs -o kernel head.o exception/entry.o main.o common/printk.o exception/trap.o exception/irq.o exception/8259A.o mm/mm.o process/process.o -T link.lds +kernel: head.o entry.o main.o printk.o trap.o mm.o irq.o 8259A.o process.o syscall.o + ld -b elf64-x86-64 -z muldefs -o kernel head.o exception/entry.o main.o common/printk.o exception/trap.o exception/irq.o exception/8259A.o mm/mm.o process/process.o syscall/syscall.o -T link.lds head.o: head.S gcc -E head.S > head.s # 预处理 @@ -46,6 +46,8 @@ mm.o: mm/mm.c process.o: process/process.c gcc -mcmodel=large -fno-builtin -m64 -c process/process.c -o process/process.o +syscall.o: syscall/syscall.c + gcc -mcmodel=large -fno-builtin -m64 -c syscall/syscall.c -o syscall/syscall.o clean: rm -rf $(GARBAGE) \ No newline at end of file diff --git a/kernel/exception/entry.S b/kernel/exception/entry.S index 88e1d4be..9d70d1e3 100644 --- a/kernel/exception/entry.S +++ b/kernel/exception/entry.S @@ -99,6 +99,46 @@ Err_Code: jmp ret_from_exception +// 系统调用入口 +// 保存寄存器 +ENTRY(system_call) + // 由于sysenter指令会禁用中断,因此要在这里手动开启中断 + sti; + + subq $0x38, %rsp + + cld; + + pushq %rax + movq %es, %rax + pushq %rax + movq %ds, %rax + pushq %rax + pushq %rbp + pushq %rdi + pushq %rsi + pushq %rdx + pushq %rcx + pushq %rbx + pushq %r8 + pushq %r9 + pushq %r10 + pushq %r11 + pushq %r12 + pushq %r13 + pushq %r14 + pushq %r15 + + movq $0x10, %rdx + movq %rdx, %ds + movq %rdx, %es + // 将rsp作为参数传递给system_call_function + movq %rsp, %rdi + + callq system_call_function + + + // 从系统调用中返回 ENTRY(ret_from_system_call) movq %rax, 0x80(%rsp) // 将当前rax的值先存到栈中rax的位置 diff --git a/kernel/exception/trap.c b/kernel/exception/trap.c index 150a987e..f04d7b37 100644 --- a/kernel/exception/trap.c +++ b/kernel/exception/trap.c @@ -212,7 +212,21 @@ void do_general_protection(struct pt_regs * regs, unsigned long error_code) printk("[ "); printk_color(RED, BLACK, "ERROR"); printk(" ] do_general_protection(13),\tError Code:%#18lx,\tRSP:%#18lx,\tRIP:%#18lx\n", error_code, regs->rsp, regs->rip); - return; + if(error_code & 0x01) + printk_color(RED,BLACK,"The exception occurred during delivery of an event external to the program,such as an interrupt or an earlier exception.\n"); + + if(error_code & 0x02) + printk_color(RED,BLACK,"Refers to a gate descriptor in the IDT;\n"); + else + printk_color(RED,BLACK,"Refers to a descriptor in the GDT or the current LDT;\n"); + + if((error_code & 0x02) == 0) + if(error_code & 0x04) + printk_color(RED,BLACK,"Refers to a segment or gate descriptor in the LDT;\n"); + else + printk_color(RED,BLACK,"Refers to a descriptor in the current GDT;\n"); + + printk_color(RED,BLACK,"Segment Selector Index:%#010x\n",error_code & 0xfff8); while (1) ; } diff --git a/kernel/main.c b/kernel/main.c index 5d6ee558..c37643a6 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -10,6 +10,7 @@ #include "exception/irq.h" #include "mm/mm.h" #include "process/process.h" +#include "syscall/syscall.h" unsigned int *FR_address = (unsigned int *)0xffff800000a00000; //帧缓存区的地址 // char fxsave_region[512] __attribute__((aligned(16))); @@ -84,6 +85,9 @@ void system_initialize() // 初始化中断模块 init_irq(); + // 先初始化系统调用模块 + syscall_init(); + // 再初始化进程模块。顺序不能调转 process_init(); } diff --git a/kernel/process/process.c b/kernel/process/process.c index 75ca57ee..265cb268 100644 --- a/kernel/process/process.c +++ b/kernel/process/process.c @@ -3,6 +3,8 @@ #include "../exception/gate.h" #include "../common/printk.h" #include "../common/kprint.h" +#include "../syscall/syscall.h" +#include "../syscall/syscall_num.h" /** * @brief 切换进程 @@ -28,6 +30,7 @@ void __switch_to(struct process_control_block *prev, struct process_control_bloc __asm__ __volatile__("movq %0, %%gs \n\t" ::"a"(next->thread->gs)); } + /** * @brief 这是一个用户态的程序 * @@ -35,7 +38,13 @@ void __switch_to(struct process_control_block *prev, struct process_control_bloc void user_level_function() { kinfo("Program (user_level_function) is runing..."); + kinfo("Try to enter syscall id 15..."); + enter_syscall(15,0,0,0,0,0,0,0,0); + + enter_syscall(SYS_PRINTF, (ul)"test_sys_printf\n", 0,0,0,0,0,0,0); + kinfo("Return from syscall id 15..."); + while(1); } /** @@ -169,6 +178,10 @@ int kernel_thread(unsigned long (*fn)(unsigned long), unsigned long arg, unsigne return do_fork(®s, flags, 0, 0); } +/** + * @brief 初始化进程模块 + * ☆前置条件:已完成系统调用模块的初始化 + */ void process_init() { @@ -188,8 +201,7 @@ void process_init() initial_mm.stack_start = _stack_start; - // 向MSR寄存器组中的 IA32_SYSENTER_CS寄存器写入内核的代码段的地址 - wrmsr(0x174, KERNEL_CS); + // 初始化进程和tss set_TSS64(initial_thread.rbp, initial_tss[0].rsp1, initial_tss[0].rsp2, initial_tss[0].ist1, initial_tss[0].ist2, initial_tss[0].ist3, initial_tss[0].ist4, initial_tss[0].ist5, initial_tss[0].ist6, initial_tss[0].ist7); diff --git a/kernel/process/process.h b/kernel/process/process.h index eeb90e11..20f8a757 100644 --- a/kernel/process/process.h +++ b/kernel/process/process.h @@ -13,11 +13,12 @@ #include "../common/cpu.h" #include "../common/glib.h" #include "../mm/mm.h" +#include "../syscall/syscall.h" #include "ptrace.h" extern unsigned long _stack_start; // 导出内核层栈基地址(定义在head.S) extern void ret_from_intr(void); // 导出从中断返回的函数(定义在entry.S) -extern void ret_from_system_call(void); // 导出从中断返回的函数(定义在entry.S) + // 进程的内核栈大小 32K #define STACK_SIZE 32768 diff --git a/kernel/syscall/syscall.c b/kernel/syscall/syscall.c new file mode 100644 index 00000000..0af0b15a --- /dev/null +++ b/kernel/syscall/syscall.c @@ -0,0 +1,72 @@ +#include "syscall.h" +#include "../process/process.h" + +// 导出系统调用入口函数,定义在entry.S中 +extern void system_call(void); + +/** + * @brief 系统调用函数,从entry.S中跳转到这里 + * + * @param regs 3特权级下的寄存器值,rax存储系统调用号 + * @return ul 对应的系统调用函数的地址 + */ +ul system_call_function(struct pt_regs *regs) +{ + return system_call_table[regs->rax](regs); +} + +/** + * @brief 初始化系统调用模块 + * + */ +void syscall_init() +{ + // 向MSR寄存器组中的 IA32_SYSENTER_CS寄存器写入内核的代码段的地址 + wrmsr(0x174, KERNEL_CS); + // 向MSR寄存器组中的 IA32_SYSENTER_ESP寄存器写入内核进程的rbp(在syscall入口中会将rsp减去相应的数值) + wrmsr(0x175, current_pcb->thread->rbp); + + // 向MSR寄存器组中的 IA32_SYSENTER_EIP寄存器写入系统调用入口的地址。 + wrmsr(0x176, (ul)system_call); +} + +long enter_syscall(ul syscall_id, ul arg0, ul arg1, ul arg2, ul arg3, ul arg4, ul arg5, ul arg6, ul arg7) +{ + long err_code; + __asm__ __volatile__("leaq sysexit_return_address(%%rip), %%rdx \n\t" + "movq %%rsp, %%rcx \n\t" + "movq %2, %%r8 \n\t" + "movq %3, %%r9 \n\t" + "movq %4, %%r10 \n\t" + "movq %5, %%r11 \n\t" + "movq %6, %%r12 \n\t" + "movq %7, %%r13 \n\t" + "movq %8, %%r14 \n\t" + "movq %9, %%r15 \n\t" + "sysenter \n\t" + "sysexit_return_address: \n\t" + : "=a"(err_code) + : "0"(syscall_id), "m"(arg0), "m"(arg1), "m"(arg2), "m"(arg3), "m"(arg4), "m"(arg5), "m"(arg6), "m"(arg7) + : "memory", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"); + return err_code; +} + +/** + * @brief 打印字符串的系统调用 + * + * 当arg1和arg2均为0时,打印黑底白字,否则按照指定的前景色和背景色来打印 + * + * @param regs 寄存器 + * @param arg0 要打印的字符串 + * @param arg1 前景色 + * @param arg2 背景色 + * @return ul 返回值 + */ +ul sys_printf(struct pt_regs *regs) +{ + if(regs->r9 == 0 &®s->r10 == 0) + printk((char*)regs->r8); + else printk_color(regs->r9, regs->r10, (char*)regs->r8); + + return 0; +} \ No newline at end of file diff --git a/kernel/syscall/syscall.h b/kernel/syscall/syscall.h new file mode 100644 index 00000000..6164a2d4 --- /dev/null +++ b/kernel/syscall/syscall.h @@ -0,0 +1,62 @@ +#pragma once + +#include "../common/glib.h" +#include "../common/kprint.h" +#include "../process/ptrace.h" + +// 定义最大系统调用数量 +#define MAX_SYSTEM_CALL_NUM 128 + +#define ESYSCALL_NOT_EXISTS 1 + + + +typedef unsigned long (*system_call_t)(struct pt_regs *regs); + +extern void ret_from_system_call(void); // 导出从系统调用返回的函数(定义在entry.S) + +/** + * @brief 初始化系统调用模块 + * + */ +void syscall_init(); + +/** + * @brief 用户态系统调用入口函数 + * 从用户态进入系统调用 + * @param syscall_id 系统调用id + * @return long 错误码 + */ +long enter_syscall(ul syscall_id,ul arg0, ul arg1, ul arg2, ul arg3, ul arg4, ul arg5, ul arg6, ul arg7); + +/** + * @brief 系统调用不存在时的处理函数 + * + * @param regs 进程3特权级下的寄存器 + * @return ul + */ +ul system_call_not_exists(struct pt_regs *regs) +{ + kerror("System call [ ID #%d ] not exists.", regs->rax); + return ESYSCALL_NOT_EXISTS; +} + +/** + * @brief 打印字符串的系统调用 + * + * 当arg1和arg2均为0时,打印黑底白字,否则按照指定的前景色和背景色来打印 + * + * @param regs 寄存器 + * @param arg0 要打印的字符串 + * @param arg1 前景色 + * @param arg2 背景色 + * @return ul 返回值 + */ +ul sys_printf(struct pt_regs *regs); + +system_call_t system_call_table[MAX_SYSTEM_CALL_NUM] = + { + [0] = system_call_not_exists, + [1] = sys_printf, + [2 ... MAX_SYSTEM_CALL_NUM - 1] = system_call_not_exists + }; diff --git a/kernel/syscall/syscall_num.h b/kernel/syscall/syscall_num.h new file mode 100644 index 00000000..94879fd9 --- /dev/null +++ b/kernel/syscall/syscall_num.h @@ -0,0 +1,4 @@ +#pragma once + +#define SYS_NOT_EXISTS 0 +#define SYS_PRINTF 1 \ No newline at end of file