Browse Source

:new: do_execve函数,跳转至应用层

fslongjin 3 năm trước cách đây
mục cha
commit
0757e7a3cd
8 tập tin đã thay đổi với 178 bổ sung93 xóa
  1. 4 6
      README.md
  2. 30 18
      kernel/common/glib.h
  3. 32 0
      kernel/exception/entry.S
  4. 28 26
      kernel/head.S
  5. 1 1
      kernel/main.c
  6. 2 1
      kernel/mm/mm.c
  7. 79 40
      kernel/process/process.c
  8. 2 1
      kernel/process/process.h

+ 4 - 6
README.md

@@ -1,12 +1,14 @@
 # DragonOS
 
+**Languages** 中文|[English](README_EN.md)
+
  
 
 这是一个运行于x86_64平台的64位操作系统。目前正在开发之中!
 
 ## 开发环境
 
-GCC==8.0
+GCC>=8.0
 
 bochs==2.7
 
@@ -48,7 +50,7 @@ bximage
 
 - [ ] 图形驱动
 
-- [ ] 第一个进程
+- [x] 第一个进程
 
 - [ ] 进程管理
 
@@ -101,7 +103,3 @@ fslongjin
 ## 赞赏者列表
 
 暂无
-
-
-
-

+ 30 - 18
kernel/common/glib.h

@@ -90,22 +90,6 @@ static inline void list_append(struct List *entry, struct List *node)
     list_add(tail, node);
 }
 
-  void list_add_to_behind(struct List * entry,struct List * new)	////add to entry behind
-{
-	new->next = entry->next;
-	new->prev = entry;
-	new->next->prev = new;
-	entry->next = new;
-}
-
-  void list_add_to_before(struct List * entry,struct List * new)	////add to entry behind
-{
-	new->next = entry;
-	entry->prev->next = new;
-	new->prev = entry->prev;
-	entry->prev = new;
-}
-
 static inline void list_del(struct List *entry)
 {
     /**
@@ -274,7 +258,6 @@ void io_out32(unsigned short port, unsigned int value)
                          : "memory");
 }
 
-
 /**
  * @brief 读取rsp寄存器的值(存储了页目录的基地址)
  *
@@ -342,4 +325,33 @@ unsigned long *get_rbx()
         "movq %%rbx, %0\n\t"
         : "=r"(tmp)::"memory");
     return tmp;
-}
+}
+
+// ========= MSR寄存器组操作 =============
+/**
+ * @brief 向msr寄存器组的address处的寄存器写入值value
+ *
+ * @param address 地址
+ * @param value 要写入的值
+ */
+void wrmsr(ul address, ul value)
+{
+    __asm__ __volatile__("wrmsr    \n\t" ::"d"(value >> 32), "a"(value & 0xffffffff), "c"(address)
+                         : "memory");
+}
+
+/**
+ * @brief 从msr寄存器组的address地址处读取值
+ *
+ * @param address 地址
+ * @return ul address处的寄存器的值
+ */
+ul rdmsr(ul address)
+{
+    unsigned int tmp0, tmp1;
+    __asm__ __volatile__("rdmsr \n\t"
+                         : "=d"(tmp0), "=a"(tmp1)
+                         : "c"(address)
+                         : "memory");
+    return ((ul)tmp0 << 32) | tmp1;
+}

+ 32 - 0
kernel/exception/entry.S

@@ -99,6 +99,38 @@ Err_Code:
 
     jmp ret_from_exception
 
+// 从系统调用中返回
+ENTRY(ret_from_system_call)
+    movq %rax, 0x80(%rsp)   // 将当前rax的值先存到栈中rax的位置
+
+    popq %r15
+    popq %r14
+    popq %r13
+    popq %r12
+    popq %r11
+    popq %r10
+    popq %r9
+    popq %r8
+    popq %rbx
+    popq %rcx
+    popq %rdx
+    popq %rsi
+    popq %rdi
+    popq %rbp
+
+    popq %rax   //  不允许直接pop到ds
+    movq %rax, %ds
+
+    popq %rax
+    movq %rax, %es
+
+    popq %rax
+
+    addq $0x38, %rsp
+
+    .byte 0x48
+    sysexit
+
 
 // 0 #DE 除法错误
 ENTRY(divide_error)

+ 28 - 26
kernel/head.S

@@ -111,12 +111,12 @@ SetUp_TSS64:
     addq $103, %rax // 设置段长度
 
     leaq GDT_Table(%rip), %rdi
-    movq %rax, 64(%rdi) // 把低八B存储到GDT第8
+    movq %rax, 80(%rdi) // 把低八B存储到GDT第10
     shrq $32, %rdx
-    movq %rdx, 72(%rdi) // 高8B存到GDT低9
+    movq %rdx, 88(%rdi) // 高8B存到GDT第11
 
     // 装载任务状态段寄存器(已改为在main.c中使用load_TR宏进行装载)
-    // mov $0x40, %ax // 设置起始地址为64
+    // mov $0x50, %ax // 设置起始地址为80
     // ltr %ax
 
     // 切换到内核主程序
@@ -152,7 +152,7 @@ ENTRY(_stack_start)
 .org 0x1000 //设置页表位置为内核执行头程序的0x1000处
 
 __PML4E:
-    .quad 0x102007 // 系统访问,可读写,已存在, 地址在31~12位
+    .quad 0x102007 // 用户访问,可读写,已存在, 地址在31~12位
     .fill	255,8,0
 	.quad	0x102007
 	.fill	255,8,0
@@ -161,26 +161,26 @@ __PML4E:
 
 __PDPTE:
 
-	.quad	0x103003 // 用户访问,可读写,已存在
+	.quad	0x103007 // 用户访问,可读写,已存在
 	.fill	511,8,0
 
 .org	0x3000
 
 __PDE:
 
-	.quad	0x000083    // 用户访问,可读写,已存在
-	.quad	0x200083
-	.quad	0x400083
-	.quad	0x600083
-	.quad	0x800083
-	.quad	0xe0000083		/*0x a00000*/
-	.quad	0xe0200083
-	.quad	0xe0400083
-	.quad	0xe0600083		/*0x1000000*/
-	.quad	0xe0800083
-	.quad	0xe0a00083
-	.quad	0xe0c00083
-	.quad	0xe0e00083
+	.quad	0x000087    // 用户访问,可读写,已存在
+	.quad	0x200087
+	.quad	0x400087
+	.quad	0x600087
+	.quad	0x800087
+	.quad	0xe0000087		/*0x a00000*/
+	.quad	0xe0200087
+	.quad	0xe0400087
+	.quad	0xe0600087		/*0x1000000*/
+	.quad	0xe0800087
+	.quad	0xe0a00087
+	.quad	0xe0c00087
+	.quad	0xe0e00087
 	.fill	499,8,0
 
 // GDT表
@@ -188,14 +188,16 @@ __PDE:
 .global GDT_Table // 使得GDT可以被外部程序引用或者访问
 
 GDT_Table:
-    .quad 0x0000000000000000 // 0 空描述符 00
-    .quad 0x0020980000000000 // 1 内核64位代码段描述符 08
-    .quad 0x0000920000000000 // 2 内核64位数据段描述符 10
-    .quad 0x0020f80000000000 // 3 用户64位代码段描述符 18
-    .quad 0x0000f20000000000 // 4 用户64位数据段描述符 20
-    .quad 0x00cf9a000000ffff // 5 内核32位代码段描述符 28
-    .quad 0x00cf92000000ffff // 6 内核32位数据段描述符 30
-    .fill 10, 8, 0           // 8~9 TSS(跳过了第七段)  重复十次填充8字节的空间,赋值为0
+    .quad 0x0000000000000000 // 0 空描述符 0x00
+    .quad 0x0020980000000000 // 1 内核64位代码段描述符 0x08
+    .quad 0x0000920000000000 // 2 内核64位数据段描述符 0x10
+    .quad 0x0000000000000000 // 3 用户32位代码段描述符 0x18
+    .quad 0x0000000000000000 // 4 用户32位数据段描述符 0x20
+    .quad 0x0020f80000000000 // 5 用户64位代码段描述符 0x28
+    .quad 0x0000f20000000000 // 6 用户64位数据段描述符 0x30
+    .quad 0x00cf9a000000ffff // 7 内核32位代码段描述符 0x38
+    .quad 0x00cf92000000ffff // 8 内核32位数据段描述符 0x40
+    .fill 10, 8, 0           // 10-11 TSS(跳过了第9段)  重复十次填充8字节的空间,赋值为0
 GDT_END:
 
 GDT_POINTER:

+ 1 - 1
kernel/main.c

@@ -65,7 +65,7 @@ void system_initialize()
 // 初始化printk
     init_printk(1440, 900, FR_address, 1440 * 900 * 4, 8, 16);
 
-    load_TR(8); // 加载TR寄存器
+    load_TR(10); // 加载TR寄存器
 
     // 初始化任务状态段表
     ul tss_item_addr = 0xffff800000007c00;

+ 2 - 1
kernel/mm/mm.c

@@ -191,10 +191,11 @@ void mm_init()
     */
 
    
+    /*
     // 消除一致性页表映射,将页目录(PML4E)的前10项清空
     for (int i = 0; i < 10; ++i)
         *(phys_2_virt(global_CR3) + i) = 0UL;
-        
+    */  
 
     flush_tlb();
 

+ 79 - 40
kernel/process/process.c

@@ -26,7 +26,38 @@ void __switch_to(struct process_control_block *prev, struct process_control_bloc
 
     __asm__ __volatile__("movq	%0,	%%fs \n\t" ::"a"(next->thread->fs));
     __asm__ __volatile__("movq	%0,	%%gs \n\t" ::"a"(next->thread->gs));
+}
 
+/**
+ * @brief 这是一个用户态的程序
+ *
+ */
+void user_level_function()
+{
+    kinfo("Program (user_level_function) is runing...");
+    
+    while(1);
+}
+/**
+ * @brief 使当前进程去执行新的代码
+ *
+ * @param regs 当前进程的寄存器
+ * @return ul 错误码
+ */
+ul do_execve(struct pt_regs *regs)
+{
+    // 选择这两个寄存器是对应了sysexit指令的需要
+    regs->rdx = 0x800000; // rip 应用层程序的入口地址   这里的地址选择没有特殊要求,只要是未使用的内存区域即可。
+    regs->rcx = 0xa00000; // rsp 应用层程序的栈顶地址
+
+    regs->rax = 1;
+    regs->ds = 0;
+    regs->es = 0;
+
+    kdebug("do_execve is running...");
+    // 将程序代码拷贝到对应的内存中
+    memcpy((void *)0x800000, user_level_function, 1024);
+    return 0;
 }
 
 /**
@@ -38,6 +69,21 @@ void __switch_to(struct process_control_block *prev, struct process_control_bloc
 ul initial_kernel_thread(ul arg)
 {
     kinfo("initial proc running...\targ:%#018lx", arg);
+    
+    struct pt_regs *regs;
+
+    current_pcb->thread->rip = (ul)ret_from_system_call;
+    current_pcb->thread->rsp = (ul)current_pcb + STACK_SIZE - sizeof(struct pt_regs);
+
+    regs = (struct pt_regs *)current_pcb->thread->rsp;
+
+    // 将返回用户层的代码压入堆栈,向rdx传入regs的地址,然后jmp到do_execve这个系统调用api的处理函数  这里的设计思路和switch_proc类似
+    __asm__ __volatile__("movq %1, %%rsp   \n\t"
+                         "pushq %2    \n\t"
+                         "jmp do_execve  \n\t" ::"D"(regs),
+                         "m"(current_pcb->thread->rsp), "m"(current_pcb->thread->rip)
+                         : "memory");
+
     return 1;
 }
 
@@ -62,35 +108,33 @@ ul do_exit(ul code)
  */
 
 extern void kernel_thread_func(void);
-__asm__ (
-"kernel_thread_func:	\n\t"
-"	popq	%r15	\n\t"
-"	popq	%r14	\n\t"	
-"	popq	%r13	\n\t"	
-"	popq	%r12	\n\t"	
-"	popq	%r11	\n\t"	
-"	popq	%r10	\n\t"	
-"	popq	%r9	\n\t"	
-"	popq	%r8	\n\t"	
-"	popq	%rbx	\n\t"	
-"	popq	%rcx	\n\t"	
-"	popq	%rdx	\n\t"	
-"	popq	%rsi	\n\t"	
-"	popq	%rdi	\n\t"	
-"	popq	%rbp	\n\t"	
-"	popq	%rax	\n\t"	
-"	movq	%rax,	%ds	\n\t"
-"	popq	%rax		\n\t"
-"	movq	%rax,	%es	\n\t"
-"	popq	%rax		\n\t"
-"	addq	$0x38,	%rsp	\n\t"
-/////////////////////////////////
-"	movq	%rdx,	%rdi	\n\t"
-"	callq	*%rbx		\n\t"
-"	movq	%rax,	%rdi	\n\t"
-"	callq	do_exit		\n\t"
-);
-
+__asm__(
+    "kernel_thread_func:	\n\t"
+    "	popq	%r15	\n\t"
+    "	popq	%r14	\n\t"
+    "	popq	%r13	\n\t"
+    "	popq	%r12	\n\t"
+    "	popq	%r11	\n\t"
+    "	popq	%r10	\n\t"
+    "	popq	%r9	\n\t"
+    "	popq	%r8	\n\t"
+    "	popq	%rbx	\n\t"
+    "	popq	%rcx	\n\t"
+    "	popq	%rdx	\n\t"
+    "	popq	%rsi	\n\t"
+    "	popq	%rdi	\n\t"
+    "	popq	%rbp	\n\t"
+    "	popq	%rax	\n\t"
+    "	movq	%rax,	%ds	\n\t"
+    "	popq	%rax		\n\t"
+    "	movq	%rax,	%es	\n\t"
+    "	popq	%rax		\n\t"
+    "	addq	$0x38,	%rsp	\n\t"
+    /////////////////////////////////
+    "	movq	%rdx,	%rdi	\n\t"
+    "	callq	*%rbx		\n\t"
+    "	movq	%rax,	%rdi	\n\t"
+    "	callq	do_exit		\n\t");
 
 /**
  * @brief 初始化内核进程
@@ -116,7 +160,6 @@ int kernel_thread(unsigned long (*fn)(unsigned long), unsigned long arg, unsigne
     regs.cs = KERNEL_CS;
     regs.ss = KERNEL_DS;
 
-
     // 置位中断使能标志位
     regs.rflags = (1 << 9);
 
@@ -129,7 +172,6 @@ int kernel_thread(unsigned long (*fn)(unsigned long), unsigned long arg, unsigne
 void process_init()
 {
 
-
     initial_mm.pgd = (pml4t_t *)global_CR3;
 
     initial_mm.code_addr_start = memory_management_struct.kernel_code_start;
@@ -146,23 +188,24 @@ 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);
 
     initial_tss[0].rsp0 = initial_thread.rbp;
-   
 
     // 初始化进程的循环链表
     list_init(&initial_proc_union.pcb.list);
 
-
     kernel_thread(initial_kernel_thread, 10, CLONE_FS | CLONE_FILES | CLONE_SIGNAL); // 初始化内核进程
     initial_proc_union.pcb.state = PROC_RUNNING;
 
     // 获取新的进程的pcb
     struct process_control_block *p = container_of(list_next(&current_pcb->list), struct process_control_block, list);
 
-	// 切换到新的内核线程
+    // 切换到新的内核线程
     switch_proc(current_pcb, p);
 }
 
@@ -180,14 +223,11 @@ unsigned long do_fork(struct pt_regs *regs, unsigned long clone_flags, unsigned
 {
     struct process_control_block *tsk = NULL;
 
-
     // 获取一个物理页并在这个物理页内初始化pcb
     struct Page *pp = alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED | PAGE_ACTIVE | PAGE_KERNEL);
 
-
     tsk = (struct process_control_block *)phys_2_virt(pp->addr_phys);
 
-
     memset(tsk, 0, sizeof(*tsk));
 
     // 将当前进程的pcb复制到新的pcb内
@@ -198,7 +238,6 @@ unsigned long do_fork(struct pt_regs *regs, unsigned long clone_flags, unsigned
 
     list_add(&initial_proc_union.pcb.list, &tsk->list);
 
-
     ++(tsk->pid);
     tsk->state = PROC_UNINTERRUPTIBLE;
 
@@ -214,9 +253,9 @@ unsigned long do_fork(struct pt_regs *regs, unsigned long clone_flags, unsigned
     thd->rip = regs->rip;
     thd->rsp = (ul)tsk + STACK_SIZE - sizeof(struct pt_regs);
 
-    // 若进程不是内核层的进程,则跳转到ret from intr
+    // 若进程不是内核层的进程,则跳转到ret from system call
     if (!(tsk->flags & PF_KTHREAD))
-        thd->rip = regs->rip = (ul)ret_from_intr;
+        thd->rip = regs->rip = (ul)ret_from_system_call;
 
     tsk->state = PROC_RUNNING;
 

+ 2 - 1
kernel/process/process.h

@@ -16,7 +16,8 @@
 #include "ptrace.h"
 
 extern unsigned long _stack_start; // 导出内核层栈基地址(定义在head.S)
-extern void ret_from_intr();	   // 导出从中断返回的函数(定义在entry.S)
+extern void ret_from_intr(void);	   // 导出从中断返回的函数(定义在entry.S)
+extern void ret_from_system_call(void);	   // 导出从中断返回的函数(定义在entry.S)
 
 // 进程的内核栈大小 32K
 #define STACK_SIZE 32768