From: zhaoyanbai Date: Sun, 16 Aug 2026 08:55:52 +0000 (+0800) Subject: 优化ring3代码的链接配置;重写调用系统调用的函数和sysexit;修复未将sysexit页设置为用户级共享的问题; X-Git-Url: http://repos.zhaoyanbai.com/?a=commitdiff_plain;h=0cbe73e1096e496522e263c98175044e36eba520;p=kernel.git 优化ring3代码的链接配置;重写调用系统调用的函数和sysexit;修复未将sysexit页设置为用户级共享的问题; --- diff --git a/kernel/ring3.S b/kernel/ring3.S index 59662ef..5774685 100644 --- a/kernel/ring3.S +++ b/kernel/ring3.S @@ -27,23 +27,35 @@ ring3_entry: nop nop - pushl $0 # 模拟一个内核不需要的参数1 - pushl $SYSC_TEST + pushl $5 #参数5 + pushl $4 #参数4 + pushl $3 #参数3 + pushl $2 #参数2 + pushl $1 #参数1 + pushl $SYSC_TEST # 系统调用号 call ring3_syscall - addl $8, %esp + addl $0x18, %esp - pushl $0 # 模拟一个内核不需要的参数1 + pushl $5 #参数5 + pushl $4 #参数4 + pushl $3 #参数3 + pushl $2 #参数2 + pushl $1 #参数1 pushl $SYSC_RAND # 系统调用号 call ring3_syscall - addl $8, %esp + addl $0x18, %esp movl %eax, %ecx andl $0x000000FF, %ecx - pushl %ecx # 参数1 + pushl $5 #参数5 + pushl $4 #参数4 + pushl $3 #参数3 + pushl $2 #参数2 + pushl %ecx #参数1 pushl $SYSC_WAIT # 系统调用号 call ring3_syscall - addl $8, %esp + addl $0x18, %esp # 纯消耗CPU时间 @@ -56,38 +68,55 @@ ring3_entry: nop jmp ring3_entry -# 传入: 系统调用号, 参数1 +# +# System V ABI +# 参数: 从右向左压栈,调用者清栈 +# 返回值: eax; 64位在edx:eax +# 调用者保存: eax ecx edx +# 被调用者保存: ebx esi edi ebp esp +# + +# +# 输入: +# eax: 系统调用号 +# ebx: 参数1 +# ecx: 参数2 +# edx: 参数3 +# esi: 参数4 +# edi: 参数5 +# 输出: +# eax: 返回码 +# ring3_syscall: + # 实现一个五个参数的完全版本,后续在lib/syscall.c里参数实现 + pushl %ebx + pushl %esi + pushl %edi pushl %ebp - movl %esp, %ebp - - pushl %ebx # 用于保存参数1 - pushl %edi # 用于保存sysexit后返回用户态的地址 - # ebp用于保存sysexit后的用户态栈,不过已经保存了,这里不用再保存 - - movl 0x08(%ebp), %eax # 系统调用号 - movl 0x0C(%ebp), %ebx # 参数1 - - # 获取call get_eip后的地址 - call get_eip -get_eip: - # 这里popl取得的就是上一个call指令自动压入栈中的地址 - # 这个地址就是当前指令的地址 - popl %edi - # 算出sysenter后的地地址 - addl $8, %edi + # sysexit页 ret 时会得到的返回地址 + pushl $1f - # 设置sysexit返回用户态后的栈位置 movl %esp, %ebp - sysenter + # 根据栈内容,准备寄存器参数 + movl 0x18(%esp), %eax + movl 0x1C(%esp), %ebx + movl 0x20(%esp), %ecx + movl 0x24(%esp), %edx + movl 0x28(%esp), %esi + movl 0x2C(%esp), %edi - # 从栈中恢复保存的易失寄存器 - popl %edi - popl %ebx + # 系统调用能保证除 eax ecx edx 外的寄存器都不会被修改 + sysenter +1: + # 此处不用恢复esp + # 因为esp已经通过ebp传进系统调用 + # 系统调用返回前已经根据ebp设置好了esp # popl %ebp - + popl %edi + popl %esi + popl %ebx ret diff --git a/kernel/syscall.S b/kernel/syscall.S index 657e4e5..46f3fcc 100644 --- a/kernel/syscall.S +++ b/kernel/syscall.S @@ -62,13 +62,13 @@ syscall_entry: .normal_syscall: call *sysc_handler_table(,%eax,4) -// normal_syscall_exit: -// leal sysexit, %edx -// movl %edx, PT_REGS_EDX(%esp) -// movl PT_REGS_EBP(%esp), %edx -// movl %edx, PT_REGS_ECX(%esp) +normal_syscall_exit: + leal sysexit, %edx + movl %edx, PT_REGS_EDX(%esp) + movl PT_REGS_EBP(%esp), %edx + movl %edx, PT_REGS_ECX(%esp) -//syscall_exit: +syscall_exit: // 保存返回值 movl %eax, PT_REGS_EAX(%esp) @@ -80,13 +80,7 @@ syscall_entry: // TODO 应该要检查一下这两个返回参数 - // 返回用户态的eip - // sysexit指令从edx中恢复用户态eip - movl %edi, %edx - // 在系统调用前,用户态的esp保存在ebp中 - // sysexit指令从ecx中恢复用户态esp - movl %ebp, %ecx sysexit @@ -119,7 +113,7 @@ ret_from_fork_krnl: .section .sysexit .align 0x1000 sysexit: - popl %ebp; - popl %edx; - popl %ecx; + nop + nop + nop ret diff --git a/kernel/task_user.c b/kernel/task_user.c index 0c9162b..31ee601 100644 --- a/kernel/task_user.c +++ b/kernel/task_user.c @@ -32,13 +32,13 @@ void user_task_entry() { task_reset_priority(TASK_PRIORITY_LEVEL_USER + 9); // ring3只占用一个page,页的起始位置放的是代码,页的末尾当栈用 - // ring3的地址直接是物理地址 - extern uint8_t ring3_page_begin; + extern uint8_t ring3_page_begin[]; + extern uint8_t ring3_lma[]; + extern uint32_t ring3_text_size[]; - paddr_t ring3_page_addr = (paddr_t)&ring3_page_begin; // 不在内核空间的物理地址 - // paddr_t ring3_stack_top = ring3_page_addr + PAGE_SIZE; + paddr_t ring3_page_addr = (paddr_t)ring3_lma; // 不在内核空间的物理地址 - vaddr_t ring3_page_vaddr = 0x08000000; // 指定的ring3的虚拟地址 + vaddr_t ring3_page_vaddr = (vaddr_t)ring3_page_begin; vaddr_t ring3_stack_top_vaddr = PAGE_OFFSET - 0x100000; page_map(ring3_page_vaddr, ring3_page_addr, PAGE_P | PAGE_US); @@ -48,12 +48,16 @@ void user_task_entry() { { // 在ring3_page里非代码的地方插入特征值方便调试 - extern uint8_t ring3_text_end; - uint32_t ring3_text_size = (&ring3_text_end) - (&ring3_page_begin); - for (uint32_t i = ring3_text_size; i < PAGE_SIZE; i++) { + for (uint32_t i = (uint32_t)ring3_text_size; i < PAGE_SIZE; i++) { ((uint8_t*)(pa2va(ring3_page_addr)))[i] = 0xCC; } } + asm volatile( + "mov %%ax, %%ds;" + "mov %%ax, %%es;" + "mov %%ax, %%fs;" + "mov %%ax, %%gs;" ::"a"(SELECTOR_USER_DS)); + asm volatile("sysexit;" ::"d"(ring3_page_vaddr), "c"(ring3_stack_top_vaddr)); } diff --git a/lib/syscall.c b/lib/syscall.c index 1570296..cf62cbb 100644 --- a/lib/syscall.c +++ b/lib/syscall.c @@ -18,31 +18,31 @@ "sysenter;" \ "1:" -static int __volatile__ __syscall0(int nr) { +static int volatile __syscall0(int nr) { int __sysc_ret__ = 0; asm(SYSENTER_ASM : "=a"(__sysc_ret__) : "a"(nr)); return __sysc_ret__; } -static int __volatile__ __syscall1(int nr, unsigned long a) { +static int volatile __syscall1(int nr, unsigned long a) { int __sysc_ret__ = 0; asm(SYSENTER_ASM : "=a"(__sysc_ret__) : "a"(nr), "b"(a)); return __sysc_ret__; } -static int __volatile__ __syscall2(int nr, unsigned long a, unsigned long b) { +static int volatile __syscall2(int nr, unsigned long a, unsigned long b) { int __sysc_ret__ = 0; asm(SYSENTER_ASM : "=a"(__sysc_ret__) : "a"(nr), "b"(a), "c"(b)); return __sysc_ret__; } -static int __volatile__ __syscall3(int nr, unsigned long a, unsigned long b, unsigned long c) { +static int volatile __syscall3(int nr, unsigned long a, unsigned long b, unsigned long c) { int __sysc_ret__ = 0; asm(SYSENTER_ASM : "=a"(__sysc_ret__) : "a"(nr), "b"(a), "c"(b), "d"(c)); return __sysc_ret__; } -static int __volatile__ __syscall4(int nr, unsigned long a, unsigned long b, unsigned long c, unsigned long d) { +static int volatile __syscall4(int nr, unsigned long a, unsigned long b, unsigned long c, unsigned long d) { int __sysc_ret__ = 0; asm(SYSENTER_ASM : "=a"(__sysc_ret__) : "a"(nr), "b"(a), "c"(b), "d"(c), "S"(d)); return __sysc_ret__; diff --git a/mm/mm.c b/mm/mm.c index 7179963..999e433 100644 --- a/mm/mm.c +++ b/mm/mm.c @@ -101,6 +101,10 @@ void init_paging() { init_pgd[i] = 0; } + // paging for user space + extern void sysexit(); + set_page_shared(sysexit); + #if 0 // 接下来为显存建立页映射 unsigned long vram_phys_addr = system.vbe_phys_addr; @@ -120,10 +124,6 @@ void init_paging() { } } - // paging for user space - extern void sysexit(); - set_page_shared(sysexit); - set_cr3(va2pa(init_pgd)); // 测试显存 diff --git a/scripts/link.ld b/scripts/link.ld index c003220..d80f375 100644 --- a/scripts/link.ld +++ b/scripts/link.ld @@ -14,6 +14,12 @@ *-------------------------------------------------------------------------- */ + /* VMA = Virtual Memory Address */ + /* LMA = Load Memory Address */ + /* ADDR(section): 计算该节的 VMA */ + /* LOADADDR(section): 计算该节的 LMA */ + /* SIZEOF(section): 计算该节的大小 */ + OUTPUT_FORMAT("elf32-i386") ENTRY(kernel_entry) @@ -53,19 +59,22 @@ SECTIONS eunpaged_rodata = .; . = ALIGN(0x1000); - ring3_page_begin = .; - .ring3 : + ring3_lma = .; + .ring3 0x08000000 : AT(ring3_lma) { + ring3_page_begin = .; *(.ring3.entry) . = ALIGN(0x100); - ring3_text_end = .; + ring3_text_size = SIZEOF(.ring3); + ring3_page_end = .; } - . = ALIGN(0x1000); - ring3_page_end = .; + /* 恢复LMA */ + /* 带绝对 VMA 的节写完后 . 不会自动接上,而是变成 该节VMA+SIZEOF(该节名) */ + . = ring3_lma + SIZEOF(.ring3); + . = ALIGN(0x1000); /* . = kernel_begin; */ . += kernel_virtual_addr_start; - . = ALIGN(0x1000); .text : AT(ADDR(.text)-kernel_virtual_addr_start) ALIGN(0x1000) { code = .;