From: acevest Date: Tue, 30 Dec 2025 12:01:26 +0000 (+0800) Subject: 重写ring3的相关代码,系统调用返回不再返回到同一个内核地址而是返回到用户参数地址 X-Git-Url: http://repos.zhaoyanbai.com/?a=commitdiff_plain;h=3acf4bc902639926dbee1b333248622f4ccddaf9;p=kernel.git 重写ring3的相关代码,系统调用返回不再返回到同一个内核地址而是返回到用户参数地址 --- diff --git a/include/page.h b/include/page.h index 2a226f9..6d15fb6 100644 --- a/include/page.h +++ b/include/page.h @@ -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; diff --git a/kernel/sched.c b/kernel/sched.c index f1751de..73bfa5a 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -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 diff --git a/kernel/syscall.S b/kernel/syscall.S index 3b9b27f..3efe83e 100644 --- a/kernel/syscall.S +++ b/kernel/syscall.S @@ -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 diff --git a/kernel/task_init.c b/kernel/task_init.c index 6670b3d..2d987cb 100644 --- a/kernel/task_init.c +++ b/kernel/task_init.c @@ -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 diff --git a/kernel/task_user.c b/kernel/task_user.c index 47ca131..835c069 100644 --- a/kernel/task_user.c +++ b/kernel/task_user.c @@ -18,76 +18,70 @@ #include #include -#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)); } diff --git a/lib/lib.c b/lib/lib.c index 80c515b..72dfdeb 100644 --- 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 15d5ed6..128a3ad 100644 --- 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++) { diff --git a/scripts/link.ld b/scripts/link.ld index 5c62472..693ba4d 100644 --- a/scripts/link.ld +++ b/scripts/link.ld @@ -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);