summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/kernel/arch/amd64/32/boot.s2
-rw-r--r--src/kernel/arch/amd64/boot64.s1
-rw-r--r--src/kernel/arch/amd64/interrupts/idt.c3
-rw-r--r--src/kernel/arch/amd64/pagedir.c5
-rw-r--r--src/kernel/arch/amd64/registers.h12
-rw-r--r--src/kernel/arch/amd64/sysenter.c13
-rw-r--r--src/kernel/arch/amd64/sysenter.s81
-rw-r--r--src/kernel/proc.c8
-rw-r--r--src/kernel/syscalls.c1
-rw-r--r--src/user/app/main.c1
-rw-r--r--src/user/lib/syscall.s24
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