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时间
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
.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)
// TODO 应该要检查一下这两个返回参数
- // 返回用户态的eip
- // sysexit指令从edx中恢复用户态eip
- movl %edi, %edx
- // 在系统调用前,用户态的esp保存在ebp中
- // sysexit指令从ecx中恢复用户态esp
- movl %ebp, %ecx
sysexit
.section .sysexit
.align 0x1000
sysexit:
- popl %ebp;
- popl %edx;
- popl %ecx;
+ nop
+ nop
+ nop
ret
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);
{
// 在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));
}
"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__;
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;
}
}
- // paging for user space
- extern void sysexit();
- set_page_shared(sysexit);
-
set_cr3(va2pa(init_pgd));
// 测试显存
*--------------------------------------------------------------------------
*/
+ /* VMA = Virtual Memory Address */
+ /* LMA = Load Memory Address */
+ /* ADDR(section): 计算该节的 VMA */
+ /* LOADADDR(section): 计算该节的 LMA */
+ /* SIZEOF(section): 计算该节的大小 */
+
OUTPUT_FORMAT("elf32-i386")
ENTRY(kernel_entry)
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 = .;