Browse Source

:new: syscall模块,实现了第一个系统调用函数sys_printf

fslongjin 3 năm trước cách đây
mục cha
commit
d3a5048f66

+ 1 - 1
README.md

@@ -56,7 +56,7 @@ bximage
 
 - [ ] IPC进程间通信
 
-- [ ] 第一个系统调用函数
+- [x] 第一个系统调用函数
 
 - [ ] 在物理平台上启动DragonOS
 

+ 1 - 1
README_EN.md

@@ -56,7 +56,7 @@ bximage
 
 - [ ] IPC
 
-- [ ] First system call function
+- [x] First system call function
 
 - [ ] Start dragonos on the physical platform
 

+ 4 - 2
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)

+ 40 - 0
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的位置

+ 15 - 1
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)
         ;
 }

+ 4 - 0
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();
 }
 

+ 14 - 2
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(&regs, 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);

+ 2 - 1
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

+ 72 - 0
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 &&regs->r10 == 0)
+        printk((char*)regs->r8);
+    else printk_color(regs->r9, regs->r10, (char*)regs->r8);
+
+    return 0;
+}

+ 62 - 0
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
+    };

+ 4 - 0
kernel/syscall/syscall_num.h

@@ -0,0 +1,4 @@
+#pragma once
+
+#define SYS_NOT_EXISTS 0
+#define SYS_PRINTF 1