global flushTSS flushTSS: mov ax, 0x28 ltr ax ret global task_ptr task_ptr: equ (0x310000) ; extern void create_child(uint32_t esp, uint32_t eip, uint32_t argc, ...); global create_child create_child: mov eax, [esp] ; return address lea ecx, [esp+4] ; return stack, minus address call save_current_task mov eax, [esp+8] ; new eip mov ecx, [esp+12] ; argc mov esi, esp ; old esp mov esp, [esp+4] ; new esp lea esi, [esi+16] ; args mov edx, ecx neg edx lea esp, [esp+edx*4] ; adjust for args mov edi, esp ; copy varargs to new stack rep movsd push return_prev_task ; if child returns, return to prev task push eax ret ; extern void create_user_child(uint32_t esp, uint32_t eip, uint32_t argc, ...); global create_user_child create_user_child: mov eax, [esp] ; return address lea ecx, [esp+4] ; return stack, minus address call save_current_task mov eax, [esp+8] ; new eip mov ecx, [esp+12] ; argc mov esi, esp ; old esp mov esp, [esp+4] ; new esp lea esi, [esi+16] ; args mov edx, ecx neg edx lea esp, [esp+edx*4] ; adjust for args mov edi, esp ; copy varargs to new stack rep movsd push 0x00000000 ; if child returns, return to null, crashing mov ecx, 0x20 | 3 mov ds, cx mov es, cx mov fs, cx mov gs, cx mov ecx, esp push 0x20 | 3 push ecx pushfd push 0x18 | 3 push eax iret ; save task ; stack contains caller, eip, cs, eflags(, esp, ss) global save_current_task_new save_current_task_new: push ds push ebx push eax push 0x10 pop ds ; 0 eax, 4 ebx, 8 ds, 12 caller, 16 eip, 20 cs, 24 eflags(, 28 esp, 32 ss) ; location to save task mov ebx, dword [0x318000] ; code & stack mov eax, dword [esp+16] mov dword [ebx+0], eax ; eip mov eax, dword [esp+20] mov dword [ebx+4], eax ; cs cmp ax, 0x08 ; if we're not in code segment, save stack info je .curr_stack mov eax, dword [esp+24] mov dword [ebx+8], eax ; eflags mov eax, dword [esp+28] mov dword [ebx+12], eax ; esp mov eax, dword [esp+32] mov dword [ebx+16], eax ; ss jmp .seg_regs ; if we're in code segment, we save current info, minus interrupt stack .curr_stack: mov eax, dword [esp+24] mov dword [ebx+8], eax ; eflags lea eax, [esp+28] mov dword [ebx+12], eax ; esp before interrupt mov eax, ss mov dword [ebx+16], eax ; segment regs .seg_regs: mov eax, dword [esp+8] mov dword [ebx+20], eax ; ds mov eax, es mov dword [ebx+24], eax mov eax, fs mov dword [ebx+28], eax mov eax, gs mov dword [ebx+32], eax ; general regs besides esp mov eax, dword [esp+0] mov dword [ebx+36], eax ; eax mov eax, dword [esp+4] mov dword [ebx+40], eax ; ebx mov dword [ebx+44], ecx mov dword [ebx+48], edx mov dword [ebx+52], esi mov dword [ebx+56], edi mov dword [ebx+60], ebp pop eax pop ebx pop ds xchg bx,bx ret ; return to current task global ret_current_task ret_current_task: xchg bx,bx push 0x10 pop ds ; location to get task mov ebx, dword [0x318000] mov ebp, [ebx+60] mov edi, [ebx+56] mov esi, [ebx+52] mov edx, [ebx+48] mov ecx, [ebx+44] mov gs, [ebx+32] mov fs, [ebx+28] mov es, [ebx+24] mov ds, [ebx+20] mov eax, [ebx+4] ; cs cmp ax, 0x08 je .restore_stack mov eax, [ebx+36] mov esp, ebx mov ebx, [ebx+40] iret .restore_stack: mov esp, [ebx+12] mov ss, [ebx+16] mov eax, [ebx+36] push dword [ebx+8] push dword [ebx+4] push dword [ebx] mov ebx, [ebx+40] iret ; return address in EAX ; return stack in ECX ; we can modify EAX, ECX, EDX ; i.e. save all others in task global save_current_task save_current_task: push edx mov edx, esp ; EDX holds our tmp stack, unsaved mov esp, dword [task_ptr] ; load current task pointer push ss push ecx ; return stack pushfd push cs push eax ; return address push ds ; other segs, pop push es ; before iret push fs ; in exit handler push gs push ebp ; saved push ebx ; saved push esi ; saved push edi ; saved mov dword [task_ptr], esp ; save new task pointer mov esp, edx pop edx ret ; FIXME System will crash if last task is invalid global return_prev_task return_prev_task: mov ecx, eax ; save return value for later mov edx, dword [task_ptr] ; load current task pointer add dword [task_ptr], 52 ; adjust to last task pointer mov edi, [edx+0] mov esi, [edx+4] mov ebx, [edx+8] mov ebp, [edx+12] mov eax, [edx+0+16] ; gs mov gs, ax mov eax, [edx+4+16] ; fs mov fs, ax mov eax, [edx+8+16] ; es mov es, ax ; SS:ESP <- return stack push ecx mov eax, [edx+32+16] ; ss mov ecx, [edx+20+16] ; cs and eax, 3 and ecx, 3 or eax, ecx pop ecx cmp eax, 3 je .ret_stack .ret_no_stack: mov esp, [edx+28+16] ; esp mov eax, [edx+32+16] ; ss mov ss, ax mov eax, [edx+24+16] ; eflags push eax mov eax, [edx+20+16] ; cs push eax mov eax, [edx+16+16] ; eip push eax mov eax, [edx+12+16] ; ds mov ds, ax mov eax, ecx ; restore return value iret .ret_stack: mov eax, [edx+32+16] ; ss push eax mov eax, [edx+28+16] ; esp push eax mov eax, [edx+24+16] ; eflags push eax mov eax, [edx+20+16] ; cs push eax mov eax, [edx+16+16] ; eip push eax mov eax, [edx+12+16] ; ds mov ds, ax mov eax, ecx ; restore return value iret ; extern void enter_v86(uint32_t ss, uint32_t esp, uint32_t cs, uint32_t eip, union V86Regs_t *regs); global enter_v86 global _enter_v86_internal_no_task enter_v86: pop eax ; return address mov ecx, esp ; return stack call save_current_task _enter_v86_internal_no_task: mov ebp, esp ; save stack pointer ; push v86 stuff for iret mov eax, 0x3000 push eax ; gs push eax ; fs push eax ; ds push eax ; es push dword [ebp+0] ; ss push dword [ebp+4] ; esp pushfd ; eflags or dword [esp], (1 << 17) ; set VM flags ;or dword [esp], (3 << 12) ; IOPL 3 push dword [ebp+8] ; cs push dword [ebp+12] ; eip ; check if we have regs mov eax, dword [ebp+16] ; regs test eax, eax jz .no_regs ; load regs: ebp, edi, esi, ebx, edx, ecx, eax mov ebp, dword [eax+0] mov edi, dword [eax+4] mov esi, dword [eax+8] mov ebx, dword [eax+12] mov edx, dword [eax+16] mov ecx, dword [eax+20] mov eax, dword [eax+24] .no_regs: iret ; return address in eax, return stack in ebp ;extern save_current_task ;extern user_test ;global jmp_usermode_test ;jmp_usermode_test: ;pop eax ; return address ;mov ecx, esp ; return stack ;call save_current_task ;mov esp, 0x800000 ; usermode stack ;mov eax, 0x20 | 3 ;mov ds, ax ;mov es, ax ;mov fs, ax ;mov gs, ax ;mov eax, esp ;push 0x20 | 3 ;push eax ;pushfd ;push 0x18 | 3 ;push user_test ;iret