summaryrefslogtreecommitdiff
path: root/src/kernel/arch/amd64/sysenter.s
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel/arch/amd64/sysenter.s')
-rw-r--r--src/kernel/arch/amd64/sysenter.s81
1 files changed, 51 insertions, 30 deletions
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