--- /dev/null
+extern allstop
+extern printk
+extern print_decode_p
+extern test_address
+
+global getrflags:function
+getrflags:
+ pushf
+ mov rax, [rsp]
+ popf
+ ret
+
+global switch_task:function
+
+; this needs to be in sync with the definition in process.h
+struc reg
+ .kerrno resq 1 ;
+ .rax resq 1 ;
+ .rbx resq 1 ;
+ .rcx resq 1 ;
+ .rdx resq 1 ;
+ .rdi resq 1 ;
+ .rsi resq 1 ;
+ .rsp resq 1 ;
+ .rbp resq 1 ;
+ .r8 resq 1 ;
+ .r9 resq 1 ;
+ .r10 resq 1 ;
+ .r11 resq 1 ;
+ .r12 resq 1 ;
+ .r13 resq 1 ;
+ .r14 resq 1 ;
+ .r15 resq 1 ;
+ .rip resq 1 ;
+ .rflags resq 1 ;
+ .cr3 resq 1 ;
+ .kernel_stack resq 1 ;
+ .cs resq 1 ;
+ .ss resq 1 ;
+endstruc
+
+%macro multipush 1-*
+
+ %rep %0
+ push %1
+ %rotate 1
+ %endrep
+
+%endmacro
+
+; first arg rdi is old register pointer, second arg is new register pointer
+switch_task:
+ ; save old registers
+ mov [rdi + reg.rax], rax
+ mov [rdi + reg.rbx], rbx
+ mov [rdi + reg.rcx], rcx
+ mov [rdi + reg.rdx], rdx
+ mov [rdi + reg.rdi], rdi ; a pointer to the current task
+ mov [rdi + reg.rsi], rsi ; though rsi is just a pointer to the new task...
+ mov [rdi + reg.rbp], rbp
+ mov [rdi + reg.r8], r8
+ mov [rdi + reg.r9], r9
+ mov [rdi + reg.r10], r10
+ mov [rdi + reg.r11], r11
+ mov [rdi + reg.r12], r12
+ mov [rdi + reg.r13], r13
+ mov [rdi + reg.r14], r14
+ mov [rdi + reg.r15], r15
+ ; save rip for return from stack
+ ; mov? we're going to switch the stack anyway
+ pop rax
+ mov [rdi + reg.rip], rax
+
+; push rdi
+; push rsi
+; mov rdi, qword printrrip
+; mov rsi, [rsp]
+; call printk
+; pop rsi
+; pop rdi
+
+ mov [rdi + reg.rsp], rsp
+
+ ; save rflags
+ pushf
+ pop rax
+ mov [rdi + reg.rflags], rax
+ ; and the address space
+ ; TODO skip, shouldn't change
+ mov rax, cr3
+ mov [rdi + reg.cr3], rax
+
+.loadregisters
+ ; Ok. now load up the new registers
+ ; we're going to use rax and rbx, and rsi needs
+ ; to be last
+ mov rcx, [rsi + reg.rcx]
+ mov rdx, [rsi + reg.rdx]
+ mov rdi, [rsi + reg.rdi]
+ mov rbp, [rsi + reg.rbp]
+ mov r8, [rsi + reg.r8]
+ mov r9, [rsi + reg.r9]
+ mov r10, [rsi + reg.r10]
+ mov r11, [rsi + reg.r11]
+ mov r12, [rsi + reg.r12]
+ mov r13, [rsi + reg.r13]
+ mov r14, [rsi + reg.r14]
+ mov r15, [rsi + reg.r15]
+
+; push rdi
+; push rsi
+; mov rdi, qword printsp
+; mov rsi, [rsi + reg.rsp]
+; call printk
+; pop rsi
+; pop rdi
+
+
+ ; and the address space
+ ; rsi should be pointing into the kernel
+ ; memory, so we can still load from that
+ ; address
+ mov rax, cr3
+ mov rbx, [rsi + reg.cr3]
+ mov dr1, rax
+ mov dr2, rbx
+ cmp rbx, rax
+ je .skipspaceload
+
+ mov cr3, rbx
+ mov rbx, cr3
+ mov dr3, rbx
+ ; switch to new stack, has to be after the address space switch, otherwise the
+ ; stack isn't mapped
+
+.skipspaceload:
+
+ mov rsp, [rsi + reg.rsp]
+
+ ; load rflags
+ mov rax, [rsi + reg.rflags]
+ ;call printrax
+ push rax
+ popf
+
+ ; push rip for return from stack
+ ; must be done after we switch address space
+ mov rax, [rsi + reg.rip]
+ push rax
+
+; push rdi
+; push rsi
+; mov rdi, qword printrip
+; ;mov rsi, [rsi + reg.rip]
+; mov rsi, [rsp]
+; call printk
+; pop rsi
+; pop rdi
+
+ ; restore registers we used for the switch
+ mov rbx, [rsi + reg.rbx]
+ mov rax, [rsi + reg.rax]
+ mov rsi, [rsi + reg.rsi] ; have to do this one last
+
+ ret
+
+global usermodetrampoline:function
+
+usermodetrampoline:
+ ; sysret wants return rip in rcx
+ ; rflags in r11
+
+ ; user mode function in rdi (i.e. first argument)
+ push rdi
+
+ mov rax, rdi
+ call printrax
+ mov ecx, 0xc0000082
+ rdmsr
+ shl rdx, 32
+ or rdx, rax
+ mov rax, rdx
+ call printrax
+
+; TODO clear out all the other registers to not leak anything
+; to userspace
+
+ pop rcx
+ mov r11, 0x202 ; make sure interrupts will be enabled
+ mov dr0, rdi
+thesysret:
+ db 0x48 ; need rex prefix for 64 bit mode returns
+ sysret
+
+section .data
+printcr3: db 'cr3 = %llx', 0xA, 0
+printsp: db 'setting rsp %llx', 0xA, 0
+printrip: db 'returning to %llx', 0xA, 0
+printrrip: db 'saving return to %llx', 0xA, 0
+
+printcr3s: db 'old cr3 = %llx, new cr3 = %llx', 0xA, 0
+
+section .text
+dumpcr3:
+ push rdi
+ push rsi
+ push rdx
+ push rbx
+ push rax
+ mov rdi, qword printcr3s
+ mov rsi, rax
+ mov rdx, rbx
+ call printk
+ pop rax
+ pop rbx
+ pop rdx
+ pop rsi
+ pop rdi
+ ret
+
+printraxs:
+ push rdi
+ push rsi
+ push rax
+ mov rdi, qword raxprintf
+ mov rsi, rax
+ call printk
+ call allstop
+ pop rax
+ pop rsi
+ pop rdi
+ ret
+printrax:
+ push rdi
+ push rsi
+ push rax
+ mov rdi, qword raxprintf
+ mov rsi, rax
+ call printk
+ pop rax
+ pop rsi
+ pop rdi
+ ret
+
+global printistack:function
+printistack:
+ push rdi
+ push rsi
+ mov rdi, qword ssprintf
+ mov rsi, [rbx + 32]
+ call printk
+ mov rdi, qword rspprintf
+ mov rsi, [rbx + 24]
+ call printk
+ mov rdi, qword rfprintf
+ mov rsi, [rbx + 16]
+ call printk
+ mov rdi, qword csprintf
+ mov rsi, [rbx + 8]
+ call printk
+ mov rdi, qword ripprintf
+ mov rsi, [rbx + 0]
+ call printk
+ pop rsi
+ pop rdi
+ ret
+
+rfprintf: db 'rflags : %llx', 10, 0
+csprintf: db 'cs : %hx', 10, 0
+ripprintf: db 'rip : %llx', 10, 0
+raxprintf: db 'rax : %llx', 10, 0
+rspprintf: db 'rsp : %llx', 10, 0
+ssprintf: db 'ss : %hx', 10, 0
+csvprintf: db 'gdt : %016llx', 10, 0