diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/kernel/arch/amd64/32/boot.s | 2 | ||||
-rw-r--r-- | src/kernel/arch/amd64/boot64.s | 1 | ||||
-rw-r--r-- | src/kernel/arch/amd64/interrupts/idt.c | 3 | ||||
-rw-r--r-- | src/kernel/arch/amd64/pagedir.c | 5 | ||||
-rw-r--r-- | src/kernel/arch/amd64/registers.h | 12 | ||||
-rw-r--r-- | src/kernel/arch/amd64/sysenter.c | 13 | ||||
-rw-r--r-- | src/kernel/arch/amd64/sysenter.s | 81 | ||||
-rw-r--r-- | src/kernel/proc.c | 8 | ||||
-rw-r--r-- | src/kernel/syscalls.c | 1 | ||||
-rw-r--r-- | src/user/app/main.c | 1 | ||||
-rw-r--r-- | src/user/lib/syscall.s | 24 |
11 files changed, 76 insertions, 75 deletions
diff --git a/src/kernel/arch/amd64/32/boot.s b/src/kernel/arch/amd64/32/boot.s index eb33c28..06de66e 100644 --- a/src/kernel/arch/amd64/32/boot.s +++ b/src/kernel/arch/amd64/32/boot.s @@ -25,7 +25,7 @@ _start: mov $0xC0000080, %ecx // EFER MSR rdmsr - or $(1 | 1<<8 | 1<<11), %eax // sysenter | long mode | NX + or $(1 | 1<<8 | 1<<11), %eax // syscall/ret | long mode | NX wrmsr mov %cr0, %eax diff --git a/src/kernel/arch/amd64/boot64.s b/src/kernel/arch/amd64/boot64.s index 1dca0ca..af05ffe 100644 --- a/src/kernel/arch/amd64/boot64.s +++ b/src/kernel/arch/amd64/boot64.s @@ -4,7 +4,6 @@ boot64: mov $(5 << 3 | 3), %ax // SEG_TSS ltr %ax - xchgw %bx, %bx push %rdi // preserve multiboot struct call sysenter_setup pop %rdi diff --git a/src/kernel/arch/amd64/interrupts/idt.c b/src/kernel/arch/amd64/interrupts/idt.c index 9c71000..f9f3073 100644 --- a/src/kernel/arch/amd64/interrupts/idt.c +++ b/src/kernel/arch/amd64/interrupts/idt.c @@ -57,11 +57,8 @@ static void idt_load(void) { } static void idt_test(void) { - kprintf("idt test?\n"); - asm("xchgw %%bx, %%bx" ::: "memory"); asm("int $0x34" : : : "memory"); assert(isr_test_interrupt_called); - kprintf("done.\n"); } void idt_init(void) { diff --git a/src/kernel/arch/amd64/pagedir.c b/src/kernel/arch/amd64/pagedir.c index 135770d..56c541a 100644 --- a/src/kernel/arch/amd64/pagedir.c +++ b/src/kernel/arch/amd64/pagedir.c @@ -129,6 +129,7 @@ void pagedir_map(struct pagedir *dir, void __user *virt, void *phys, pml4e = &dir->e[v.pml4]; if (!pml4e->present) { + kprintf("allocating pdpt\n"); pml4e->as_ptr = addr_validate(page_zalloc(1)); pml4e->present = 1; pml4e->writeable = 1; @@ -138,6 +139,7 @@ void pagedir_map(struct pagedir *dir, void __user *virt, void *phys, pdpte = &((pe_generic_t*)addr_extract(*pml4e))[v.pdpt]; if (!pdpte->present) { + kprintf("allocating pd\n"); pdpte->as_ptr = addr_validate(page_zalloc(1)); pdpte->present = 1; pdpte->writeable = 1; @@ -147,6 +149,7 @@ void pagedir_map(struct pagedir *dir, void __user *virt, void *phys, pde = &((pe_generic_t*)addr_extract(*pdpte))[v.pd]; if (!pde->present) { + kprintf("allocating pt\n"); pde->as_ptr = addr_validate(page_zalloc(1)); pde->present = 1; pde->writeable = 1; @@ -156,7 +159,7 @@ void pagedir_map(struct pagedir *dir, void __user *virt, void *phys, pte = &((pe_generic_t*)addr_extract(*pde))[v.pt]; if (!pte->present) { - pte->as_ptr = addr_validate(page_zalloc(1)); + pte->address = ((uintptr_t)phys) >> 12; pte->present = 1; pte->writeable = writeable; pte->user = user; diff --git a/src/kernel/arch/amd64/registers.h b/src/kernel/arch/amd64/registers.h index e365e2c..c98c647 100644 --- a/src/kernel/arch/amd64/registers.h +++ b/src/kernel/arch/amd64/registers.h @@ -3,16 +3,14 @@ #include <stdint.h> struct registers { - uint64_t edi, esi; - userptr_t ebp, esp; - uint64_t ebx, edx, ecx, eax; - - userptr_t eip; + uint64_t r15, r14, r13, r12, r11, r10, r9, r8; + uint64_t rdi, rsi; + userptr_t rbp, rsp; + uint64_t rbx, rdx, rcx, rax; } __attribute__((__packed__)); // saves a return value according to the SysV ABI static inline uint64_t regs_savereturn(struct registers *regs, uint64_t value) { - regs->eax = value; - regs->edx = value >> 32; // TODO check ABI + regs->rax = value; return value; } diff --git a/src/kernel/arch/amd64/sysenter.c b/src/kernel/arch/amd64/sysenter.c index 75b825f..543e5bc 100644 --- a/src/kernel/arch/amd64/sysenter.c +++ b/src/kernel/arch/amd64/sysenter.c @@ -7,22 +7,17 @@ struct registers _sysexit_regs; void sysexit(struct registers regs) { _sysexit_regs = regs; - _sysexit_regs.ecx = (uintptr_t) regs.esp; - _sysexit_regs.edx = (uintptr_t) regs.eip; - kprintf("here we go!\n"); + kprintf("ring3...\n"); _sysexit_real(); __builtin_unreachable(); } _Noreturn void sysenter_stage2(void) { - kprintf("ring0 again!\n"); struct registers *regs = &process_current->regs; + *regs = _sysexit_regs; - *regs = _sysexit_regs; // save the registers - regs->esp = (userptr_t) regs->ecx; // fix them up - regs->eip = (userptr_t) regs->edx; + kprintf("ring0!\n"); - _syscall(regs->eax, regs->ebx, - regs->esi, regs->edi, (uintptr_t)regs->ebp); + _syscall(regs->rdi, regs->rsi, regs->rdx, regs->r10, regs->r8); process_switch_any(); } diff --git a/src/kernel/arch/amd64/sysenter.s b/src/kernel/arch/amd64/sysenter.s index 4dfe19d..74db018 100644 --- a/src/kernel/arch/amd64/sysenter.s +++ b/src/kernel/arch/amd64/sysenter.s @@ -3,9 +3,10 @@ .set SEG_r3code, 3 .set SEG_r3data, 4 -.set IA32_SYSENTER_CS, 0x174 -.set IA32_SYSENTER_ESP, 0x175 -.set IA32_SYSENTER_EIP, 0x176 +.set IA32_STAR, 0xC0000081 +.set IA32_LSTAR, 0xC0000082 +.set IA32_CSTAR, 0xC0000083 +.set IA32_FMASK, 0xC0000084 .section .text .global sysenter_setup @@ -13,81 +14,101 @@ sysenter_setup: xor %rdx, %rdx - mov $(SEG_r0code << 3), %rax - mov $IA32_SYSENTER_CS, %rcx + // the intel docs don't mention the lower 32 bits + mov $( ((SEG_r3code << 3 | 3) << 48) | ((SEG_r0code << 3) << 32) ), %rax + mov $IA32_STAR, %rcx wrmsr - mov $IA32_SYSENTER_ESP, %rcx - mov $0, %rax // unused - wrmsr - - mov $IA32_SYSENTER_EIP, %rcx + mov $IA32_LSTAR, %rcx mov $sysenter_stage1, %rax wrmsr + // hoping that the default RFLAGS mask is fine... + ret .section .shared -.global stored_eax -stored_eax: -.long 0 +.global stored_rsp +stored_rsp: + .skip 8 .global pagedir_current // a hack to maintain compat with the old arch api, TODO pagedir_current: -.long 0 + .skip 8 .global _sysexit_real .type _sysexit_real, @function _sysexit_real: - xchgw %bx, %bx + /* mov $(SEG_r3data << 3 | 3), %ax mov %ax, %ds mov %ax, %es mov %ax, %fs mov %ax, %gs + */ + + xchgw %bx, %bx - // restore the registers mov $_sysexit_regs, %rsp + pop %r15 + pop %r14 + pop %r13 + pop %r12 + + pop %r11 + pop %r10 + pop %r9 + pop %r8 + pop %rdi pop %rsi pop %rbp - add $8, %rsp + pop (stored_rsp) + pop %rbx pop %rdx pop %rcx pop %rax // enable paging - // %rsp used as a scratch register mov (pagedir_current), %rsp mov %rsp, %cr3 - sysexit + mov (stored_rsp), %rsp + nop + sysretq sysenter_stage1: - cli /* prevent random IRQs in the middle of kernel code */ + cli xchgw %bx, %bx - // disable paging - // I don't want to damage any of the registers passed in by the user, - // so i'm using ESP as a temporary register. At this point there's nothing - // useful in it, it's == _bss_end. - mov %cr0, %rsp - and $0x7FFFFFFF, %rsp // disable paging - mov %rsp, %cr0 + mov %rsp, (stored_rsp) + + mov $pml4_identity, %rsp + mov %rsp, %cr3 - // save the registers - mov $(_sysexit_regs + 64), %rsp + mov $(_sysexit_regs + 128), %rsp push %rax push %rcx push %rdx push %rbx - push $0x0 // pushal pushes %rsp here, but that's worthless + + push (stored_rsp) push %rbp push %rsi push %rdi + push %r8 + push %r9 + push %r10 + push %r11 + + push %r12 + push %r13 + push %r14 + push %r15 + mov $_bss_end, %rsp jmp sysenter_stage2 diff --git a/src/kernel/proc.c b/src/kernel/proc.c index 1cb6eb0..a202549 100644 --- a/src/kernel/proc.c +++ b/src/kernel/proc.c @@ -23,8 +23,10 @@ struct process *process_seed(struct kmain_info *info) { process_first->id = next_pid++; // map the stack to the last page in memory - pagedir_map(process_first->pages, (userptr_t)~PAGE_MASK, page_alloc(1), true, true); - process_first->regs.esp = (userptr_t) ~0xF; + kprintf("0x%x\n", (userptr_t)~PAGE_MASK); + pagedir_map(process_first->pages, (userptr_t)~PAGE_MASK, page_zalloc(1), true, true); + process_first->regs.rsp = (userptr_t) ~0xF; + kprintf("post stack\n"); // map .shared extern char _shared_len; @@ -36,7 +38,7 @@ struct process *process_seed(struct kmain_info *info) { for (uintptr_t off = 0; off < info->init.size; off += PAGE_SIZE) pagedir_map(process_first->pages, init_base + off, info->init.at + off, true, true); - process_first->regs.eip = init_base; + process_first->regs.rcx = init_base; // SYSRET jumps to %rcx return process_first; } diff --git a/src/kernel/syscalls.c b/src/kernel/syscalls.c index 1d18ad1..293edae 100644 --- a/src/kernel/syscalls.c +++ b/src/kernel/syscalls.c @@ -368,6 +368,7 @@ void _syscall_debug_klog(const void __user *buf, size_t len) { } int _syscall(int num, int a, int b, int c, int d) { + kprintf("%x %x %x %x %x\n", num, a, b, c, d); switch (num) { case _SYSCALL_EXIT: _syscall_exit(a); diff --git a/src/user/app/main.c b/src/user/app/main.c index ff47d4e..92aa56c 100644 --- a/src/user/app/main.c +++ b/src/user/app/main.c @@ -16,6 +16,7 @@ void read_file(const char *path, size_t len); __attribute__((section(".text.startup"))) int main(void) { + _syscall(1, 2, 3, 4, 5); // allocate bss _syscall_memflag(&_bss_start, &_bss_end - &_bss_start, MEMFLAG_PRESENT); diff --git a/src/user/lib/syscall.s b/src/user/lib/syscall.s index 0f9e444..07f5631 100644 --- a/src/user/lib/syscall.s +++ b/src/user/lib/syscall.s @@ -2,24 +2,8 @@ .global _syscall .type _syscall, @function _syscall: - push %rbx // preserve registers - push %rsi - push %rdi - push %rbp - - // NOT the calling convention TODO you lazy fuck - mov 20(%rsp), %rax - mov 24(%rsp), %rbx - mov %rsp, %rcx - mov $_syscall_ret, %rdx - mov 28(%rsp), %rsi - mov 32(%rsp), %rdi - mov 36(%rsp), %rbp - sysenter - -_syscall_ret: - pop %rbp - pop %rdi - pop %rsi - pop %rbx + push %r10 + mov %rcx, %r10 + syscall + pop %r10 ret |