X-Git-Url: https://pd.if.org/git/?p=zos;a=blobdiff_plain;f=taskx64.s;fp=taskx64.s;h=5b2f8153da12d291c74a444624184b751409e918;hp=0000000000000000000000000000000000000000;hb=7c1b1bcd0cd0b3e3738afe96aa9b94a275a7951b;hpb=7b91cb3f96d7b8ba0874a1b24b19f624e43c99d5 diff --git a/taskx64.s b/taskx64.s new file mode 100644 index 0000000..5b2f815 --- /dev/null +++ b/taskx64.s @@ -0,0 +1,274 @@ +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