]> Zhao Yanbai Git Server - kernel.git/commitdiff
重写ring3的相关代码,系统调用返回不再返回到同一个内核地址而是返回到用户参数地址
authoracevest <zhaoyanbai@126.com>
Tue, 30 Dec 2025 12:01:26 +0000 (20:01 +0800)
committeracevest <zhaoyanbai@126.com>
Tue, 30 Dec 2025 12:01:26 +0000 (20:01 +0800)
include/page.h
kernel/sched.c
kernel/syscall.S
kernel/task_init.c
kernel/task_user.c
lib/lib.c
mm/mm.c
scripts/link.ld

index 2a226f91798931c528e8a9267cef1c2c7daf522a..6d15fb63d584209c24fbd947334c404990a79caa 100644 (file)
@@ -121,7 +121,16 @@ typedef unsigned long pte_t;
 
 #define MAX_ORDER (11)
 
-#define LoadCR3(cr3) asm volatile("movl %%edx, %%cr3" ::"d"(cr3))
+#define set_cr3(cr3) asm volatile("movl %0, %%cr3" ::"r"(cr3))
+static inline unsigned long get_cr3() {
+    unsigned long cr3;
+    asm volatile("movl %%cr3, %0" : "=r"(cr3));
+    return cr3;
+}
+
+static inline pde_t *get_pgd() {
+    return (pde_t *)(get_cr3() & PAGE_MASK);
+}
 
 typedef unsigned int gfp_t;
 
index f1751dee1ea4752e85ba14fce0f4374bf397d89f..73bfa5af8448890999204281ca15eb833a50cdfe 100644 (file)
@@ -40,7 +40,7 @@ pid_t get_next_pid() {
     return pid;
 }
 
-void load_cr3(task_t *tsk) { LoadCR3(tsk->cr3); }
+void load_cr3(task_t *tsk) { set_cr3(tsk->cr3); }
 
 extern pde_t __initdata init_pgd[PDECNT_PER_PAGE] __attribute__((__aligned__(PAGE_SIZE)));
 
@@ -112,7 +112,7 @@ task_t *alloc_task_t() {
 }
 
 void switch_to() {
-    LoadCR3(current->cr3);
+    set_cr3(current->cr3);
     tss.esp0 = current->esp0;
 #if FIXED_SYSENTER_ESP_MODE
     // do nothing
index 3b9b27ffcf79d0766a07f03a95e69afbbcc3c6bf..3efe83e211ccf96f28000a486302d124742457e1 100644 (file)
@@ -77,11 +77,13 @@ syscall_entry:
 
     RESTORE_REGS
 
+    // TODO 应该要检查一下这两个返回参数
+
     // 返回用户态的eip
     // sysexit指令从edx中恢复用户态eip
-    leal    sysexit, %edx
+    movl %edi, %edx
 
-    // 在系统调用前用户态的esp保存在ebp中
+    // 在系统调用前,用户态的esp保存在ebp中
     // sysexit指令从ecx中恢复用户态esp
     xchgl   %ebp, %ecx
 
index 6670b3d51483d934a01462b63d9f63870b6e07c0..2d987cba7c65e5bc34323df6fa42b110835dbb44 100644 (file)
@@ -194,7 +194,7 @@ void init_task_entry() {
 
 #if 1
     kernel_task("ide/1", disk_task_entry, (void *)1);
-    // kernel_task("user", user_task_entry, NULL);
+    kernel_task("user", user_task_entry, NULL);
     kernel_task("tskA", taskA_entry, NULL);
     kernel_task("tskB", taskB_entry, NULL);
     kernel_task("tskC", taskC_entry, NULL);
@@ -222,7 +222,7 @@ void init_task_entry() {
 
     printk("RING3 ENTRY %x page %x pgd inx %u pt inx %u\n", mod_start, text_at, pgd_index, pt_index);
 
-    LoadCR3(current->cr3);
+    set_cr3(current->cr3);
 
     asm("sysexit;" ::"d"(mod_start), "c"(mod_start + PAGE_SIZE - 4));
 #endif
index 47ca13123c6bb35e064f541e7cc43acaaa9cffd6..835c069d7a0caee4fae3f7e9918d95572dfbcb94 100644 (file)
 #include <system.h>
 #include <types.h>
 
-#define __ring3text__ __attribute__((__section__(".ring3.text")))
-
-int ring3_sysctest();
-void __ring3text__ __attribute__((__aligned__(PAGE_SIZE))) ring3_entry() {
+#define RING3_ENTRY __attribute__((__section__(".ring3.entry")))
+void RING3_ENTRY __attribute__((__aligned__(PAGE_SIZE))) ring3_entry() {
     while (1) {
         int __sysc_ret__ = 0;
 
-        // 下面这段汇编中的 ring3_entry 和 sysexit_return_address的地址都是内核地址
-        // 然而在用户态用的代码地址是从0x08000000开始的
-        // 因此为了算了systexit返回的正确地址
-        // 需要借助ring3_entry算出sysexit_return_address相对ring3_entry的偏移量
-        // 再把这个偏移量加上0x08000000就是正确的sysexit的地址
-
-        // 必需注意这里的sysexit_return_address并不是sysexit指令返回的地址
-        // sysexit指令返回的是编译在内核中的一段代码地址,这个地址已经被设成内核和用户态共享
-        // 在内核中的那段代码里会利用存在栈上的sysexit_return_address返回到
-        // sysexit_return_address处
+        // EDI = 用户态返回地址
+        // EBP = 用户态栈
         asm volatile(
-            "leal sysexit_return_address, %%ebx;"
-            "subl %%ecx, %%ebx;"
-            "addl $0x08000000, %%ebx;"  // 算出sysexit_return_address在用户态的实际地址
-            "pushl %%ebx;"  // 把这个地址保存在栈上,内核sysexit会返回到一段共享代码上
-                            // 共享代码会利用保存在栈上的地址返回到sysexit_return_address处
-            "pushl $0;"
-            "pushl $0;"
-            "movl $200, %%ebx;"
-            "pushl %%ebp;"
-            "movl  %%esp, %%ebp;"
+            "nop;"
+            "nop;"
+            "pusha;"
+            "call get_eip;"
+            "get_eip:"
+            "popl %%edi;" // 获得EIP的值,注意此时EIP的位置为这条pop指令的地址
+                          // 反汇编后计算了一下需要加8个字节才能跳到sysenter下一个指令
+            "addl $8, %%edi;"
+            "movl %%esp, %%ebp;"
             "sysenter;"
-            "sysexit_return_address:"
-            : "=a"(__sysc_ret__)
-            : "a"(SYSC_WAIT), "c"(ring3_entry));
-
-        for (int i = 10000000; i > 0; i--) {
-            for (int j = 1; j > 0; j--) {
-                asm("nop;nop;nop;");
-            }
-        }
+            "popa;"
+            "nop;"
+            "nop;"
+            :"=a"(__sysc_ret__)
+            :"a"(SYSC_WAIT)
+        );
     }
 }
 
+void flush_tlb() {
+    asm volatile("movl %%cr3, %%eax;"
+                "movl %%eax, %%cr3;"
+                :
+                :
+                : "eax");
+}
+
 void user_task_entry() {
     current->priority = 7;
 
-    unsigned long ring3_text_page = va2pa(ring3_entry);
-    unsigned long ring3_bss_page = (unsigned long)page2pa(alloc_one_page(0));
-
-    unsigned long *pt_text_page = (unsigned long *)page2va(alloc_one_page(0));
-    unsigned long *pt_bss_page = (unsigned long *)page2va(alloc_one_page(0));
+    // ring3只占用一个page,页的起始位置放的是代码,页的末尾当栈用
+    // ring3的地址直接是物理地址
+    extern unsigned long ring3_page_addr;
+    extern unsigned long ring3_page_end;
+    unsigned long ring3_text_page =(unsigned long) &ring3_page_addr; // 不在内核空间的物理地址
+    unsigned long ring3_stack_top = (unsigned long) &ring3_page_end;  // 不在内核空间的物理地址
 
-    unsigned long *p = (unsigned long *)(pa2va(current->cr3));
+    unsigned long ring3_page_vaddr = 0x08000000; // 指定的ring3的虚拟地址
+    unsigned long ring3_stack_top_vaddr = ring3_page_vaddr + (ring3_stack_top - ring3_text_page);
+    int npte = get_npte(ring3_page_vaddr);
+    int npde = get_npde(ring3_page_vaddr);
 
-    printd("page dir : %x %x %x %x\n", p, pt_text_page, ring3_text_page);
-    printd("pt bss page %x %x\n", pt_bss_page, ring3_bss_page);
+    // 分配一个页表在用户空间对这页进行映射
+    pte_t *pgt = (pte_t *)page2va(alloc_one_page(0));
 
-    // text: 0x0800_0000
-    //  bss: 0x3000_0000
-    unsigned long text_at = 0x08000000;
-    unsigned long bbs_at = 0x30000000;
+    memset(pgt, 0, PAGE_SIZE);
+    pgt[npte] = (pte_t)(ring3_text_page | PAGE_P | PAGE_US | PAGE_WR);
 
-    p[text_at >> 22] = (unsigned long)va2pa(pt_text_page) | PAGE_P | PAGE_US;
-    pt_text_page[0] = ring3_text_page | PAGE_P | PAGE_US;
-    p[bbs_at >> 22] = (unsigned long)va2pa(pt_bss_page) | PAGE_P | PAGE_WR | PAGE_US;
-    pt_bss_page[0] = ring3_bss_page | PAGE_P | PAGE_WR | PAGE_US;
+    // 把这个页表映射到页目录
+    pde_t *pgd = pa2va(get_pgd());
+    pgd[npde] = (pde_t)(((unsigned long)va2pa(pgt)) | PAGE_P | PAGE_US | PAGE_WR);
 
-    //
-    LoadCR3(current->cr3);
+    // 到此完成了 ring3_page_vaddr -> ring3_text_page的映射
+    // 刷新tlb
+    flush_tlb();
 
-    // 现在要准备返回用户态
-    // eip --> edx
-    // esp --> ecx
-    asm volatile("sysexit;" ::"d"(0x08000000), "c"(0x30000000 + PAGE_SIZE - 100));
+    // 现在准备返回用户态
+    asm volatile("sysexit;" ::"d"(ring3_page_vaddr), "c"(ring3_stack_top_vaddr - 0x10));
 }
index 80c515bb08765f24df020373ca920aef65182b24..72dfdeb2548bd8fcacf9e73941c98d3156a42304 100644 (file)
--- a/lib/lib.c
+++ b/lib/lib.c
@@ -24,15 +24,15 @@ int atoi(const char *s) {
     return i;
 }
 
-void reboot() { syscall1(SYSC_REBOOT, 0); }
+// void reboot() { syscall1(SYSC_REBOOT, 0); }
 
-void poweroff() { syscall1(SYSC_REBOOT, 1); }
+// void poweroff() { syscall1(SYSC_REBOOT, 1); }
 
-int systest() { return syscall0(SYSC_TEST); }
+// int systest() { return syscall0(SYSC_TEST); }
 
-int sysdebug(unsigned int v) { return syscall1(SYSC_DEBUG, v); }
+// int sysdebug(unsigned int v) { return syscall1(SYSC_DEBUG, v); }
 
-int pause(unsigned long tick) { return syscall1(SYSC_PAUSE, tick); }
+// int pause(unsigned long tick) { return syscall1(SYSC_PAUSE, tick); }
 
 int vsprintf(char *buf, const char *fmt, char *args);
 int sprintf(char *str, const char *fmtstr, ...) {
diff --git a/mm/mm.c b/mm/mm.c
index 15d5ed6acd1a9ea1279ce0050ee23bfd7b2bf426..128a3ad595cd9a7b1df45832b3c3e6d4f63e1d76 100644 (file)
--- a/mm/mm.c
+++ b/mm/mm.c
@@ -127,7 +127,7 @@ void init_paging() {
     extern void sysexit();
     set_page_shared(sysexit);
 
-    LoadCR3(va2pa(init_pgd));
+    set_cr3(va2pa(init_pgd));
 
     // 测试显存
     for (int i = 0; i < system.x_resolution * (system.y_resolution - 32); i++) {
index 5c624728e41c79b5ddea28e96dc7516f60005daf..693ba4d3720463628890798127b7d664b44d6f1c 100644 (file)
@@ -51,6 +51,15 @@ SECTIONS
     }
     eunpaged_rodata = .;
 
+    . = ALIGN(0x1000);
+    ring3_page_addr = .;
+    .ring3 :
+    {
+        *(.ring3.entry)
+    }
+    . = ALIGN(0x1000);
+    ring3_page_end = .;
+
     /* . = kernel_begin; */
     . += kernel_virtual_addr_start;
     . = ALIGN(0x1000);