summaryrefslogtreecommitdiff
path: root/src/kernel/arch
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel/arch')
-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
7 files changed, 65 insertions, 52 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