unit machdep; {$mode ObjFPC}{$H+} {$CALLING SysV_ABI_CDecl} interface uses signal, signalvar, ucontext, kern_thr, kern_proc; const GUFS32_SEL = 2; // User 32 bit %fs Descriptor GUGS32_SEL = 3; // User 32 bit %gs Descriptor GUDATA_SEL = 7; // User 32/64 bit Data Descriptor GUCODE_SEL = 8; // User 64 bit Code Descriptor _ucodesel=(GUCODE_SEL shl 3) or 3; _udatasel=(GUDATA_SEL shl 3) or 3; _ufssel =(GUFS32_SEL shl 3) or 3; _ugssel =(GUGS32_SEL shl 3) or 3; procedure bzero(ptr:Pointer;size:ptrint); Procedure bmove(src,dst:Pointer;size:ptrint); function cpu_getstack(td:p_kthread):QWORD; procedure cpu_set_fsbase(td:p_kthread;base:Pointer); procedure cpu_set_gsbase(td:p_kthread;base:Pointer); procedure cpu_init_jit(td:p_kthread); procedure cpu_fini_jit(td:p_kthread); procedure cpu_fetch_syscall_args(td:p_kthread); procedure cpu_set_syscall_retval(td:p_kthread;error:Integer); procedure cpu_set_upcall_kse(td:p_kthread;entry,arg:Pointer;stack:p_stack_t); function get_mcontext(td:p_kthread;mcp:p_mcontext_t;flags:Integer):Integer; function get_mcontext2(td:p_kthread;mcp:p_mcontext_t;flags:Integer):Integer; function set_mcontext(td:p_kthread;mcp:p_mcontext_t):Integer; procedure sendsig(catcher:sig_t;ksi:p_ksiginfo;mask:p_sigset_t); // function sys_sigreturn(sigcntxp:Pointer):Integer; procedure exec_setregs(td:p_kthread;entry,stack_base,stack_top:QWORD); implementation uses errno, systm, kern_psl, vm_map, md_context; //clearing memory without AVX optimizations procedure bzero(ptr:Pointer;size:ptrint); begin while (size>0) do begin PByte(ptr)^:=0; Inc(ptr); Dec(size); end; end; //move memory without AVX optimizations Procedure bmove(src,dst:Pointer;size:ptrint); begin while (size>0) do begin PByte(dst)^:=PByte(src)^; Inc(src); Inc(dst); Dec(size); end; end; function cpu_getstack(td:p_kthread):QWORD; begin Result:=td^.td_frame.tf_rsp; end; procedure cpu_set_fsbase(td:p_kthread;base:Pointer); begin td^.pcb_fsbase:=base; td^.td_teb^.fsbase:=base; set_pcb_flags(td,PCB_FULL_IRET); end; procedure cpu_set_gsbase(td:p_kthread;base:Pointer); begin td^.pcb_gsbase:=base; td^.td_teb^.gsbase:=base; set_pcb_flags(td,PCB_FULL_IRET); end; procedure cpu_init_jit(td:p_kthread); begin //teb stack teb_set_kernel(td); //teb stack end; procedure cpu_fini_jit(td:p_kthread); begin //teb stack teb_set_user(td); //teb stack end; procedure cpu_fetch_syscall_args(td:p_kthread); begin td^.td_retval[0]:=0; td^.td_retval[1]:=td^.td_frame.tf_rdx; //teb stack teb_set_kernel(td); //teb stack end; procedure cpu_set_syscall_retval(td:p_kthread;error:Integer); begin Case error of 0:With td^.td_frame do begin tf_rax:=td^.td_retval[0]; tf_rdx:=td^.td_retval[1]; tf_rflags:=tf_rflags and (not PSL_C); end; ERESTART: With td^.td_frame do begin //tf_err = size of syscall cmd tf_rip:=tf_rip-td^.td_frame.tf_err; tf_r10:=tf_rcx; set_pcb_flags(td,PCB_FULL_IRET); end; EJUSTRETURN:; //nothing else With td^.td_frame do begin tf_rax:=error; tf_rflags:=tf_rflags or PSL_C; end; end; //teb stack teb_set_user(td); //teb stack end; procedure cpu_set_upcall_kse(td:p_kthread;entry,arg:Pointer;stack:p_stack_t); begin { * Set the trap frame to point at the beginning of the uts * function. } td^.td_frame.tf_rbp:=0; td^.td_frame.tf_rsp:=(ptruint(stack^.ss_sp) + stack^.ss_size) and (not $F); Dec(td^.td_frame.tf_rsp,8); td^.td_frame.tf_rip:=ptruint(entry); td^.td_frame.tf_ds:=_udatasel; td^.td_frame.tf_es:=_udatasel; td^.td_frame.tf_fs:=_ufssel; td^.td_frame.tf_gs:=_ugssel; td^.td_frame.tf_flags:=TF_HASSEGS; { * Pass the address of the mailbox for this kse to the uts * function as a parameter on the stack. } td^.td_frame.tf_rdi:=ptruint(arg); end; function get_fpcontext(td:p_kthread;mcp:p_mcontext_t;xstate:Pointer):Integer; begin Result:=0; mcp^.mc_flags :=mcp^.mc_flags or _MC_HASFPXSTATE; mcp^.mc_fpformat:=_MC_FPFMT_XMM; mcp^.mc_ownedfp :=_MC_FPOWNED_FPU; bmove(@td^.td_fpstate,xstate,SizeOf(mcp^.mc_fpstate)); end; function set_fpcontext(td:p_kthread;mcp:p_mcontext_t;xstate:Pointer):Integer; begin Result:=0; if (mcp^.mc_fpformat=_MC_FPFMT_NODEV) then Exit(0); if (mcp^.mc_fpformat<>_MC_FPFMT_XMM) then Exit(EINVAL); if (mcp^.mc_ownedfp=_MC_FPOWNED_NONE) then Exit(0); if (mcp^.mc_ownedfp=_MC_FPOWNED_FPU) or (mcp^.mc_ownedfp=_MC_FPOWNED_PCB) then begin bmove(xstate,@td^.td_fpstate,SizeOf(mcp^.mc_fpstate)); td^.td_frame.tf_flags:=td^.td_frame.tf_flags or TF_HASFPXSTATE; Exit(0); end; Exit(EINVAL); end; function get_mcontext(td:p_kthread;mcp:p_mcontext_t;flags:Integer):Integer; var tp:p_trapframe; begin tp:=@td^.td_frame; PROC_LOCK(); mcp^.mc_onstack:=sigonstack(tp^.tf_rsp); PROC_UNLOCK(); mcp^.mc_r15 :=tp^.tf_r15; mcp^.mc_r14 :=tp^.tf_r14; mcp^.mc_r13 :=tp^.tf_r13; mcp^.mc_r12 :=tp^.tf_r12; mcp^.mc_r11 :=tp^.tf_r11; mcp^.mc_r10 :=tp^.tf_r10; mcp^.mc_r9 :=tp^.tf_r9; mcp^.mc_r8 :=tp^.tf_r8; mcp^.mc_rdi :=tp^.tf_rdi; mcp^.mc_rsi :=tp^.tf_rsi; mcp^.mc_rbp :=tp^.tf_rbp; mcp^.mc_rbx :=tp^.tf_rbx; mcp^.mc_rcx :=tp^.tf_rcx; mcp^.mc_rflags:=tp^.tf_rflags; if ((flags and GET_MC_CLEAR_RET)<>0) then begin mcp^.mc_rax:=0; mcp^.mc_rdx:=0; mcp^.mc_rflags:=tp^.tf_rflags and (not PSL_C); end else begin mcp^.mc_rax:=tp^.tf_rax; mcp^.mc_rdx:=tp^.tf_rdx; end; mcp^.mc_rip :=tp^.tf_rip; mcp^.mc_cs :=tp^.tf_cs; mcp^.mc_rsp :=tp^.tf_rsp; mcp^.mc_ss :=tp^.tf_ss; mcp^.mc_ds :=tp^.tf_ds; mcp^.mc_es :=tp^.tf_es; mcp^.mc_fs :=tp^.tf_fs; mcp^.mc_gs :=tp^.tf_gs; mcp^.mc_flags:=tp^.tf_flags; mcp^.mc_len :=sizeof(mcontext_t); //xmm,ymm if ((tp^.tf_flags and TF_HASFPXSTATE)<>0) then begin Result:=get_fpcontext(td,mcp,@mcp^.mc_fpstate); end else begin Result:=md_get_fpcontext(td,mcp,@mcp^.mc_fpstate); end; if (Result<>0) then Exit; //xmm,ymm mcp^.mc_fsbase:=ptruint(td^.pcb_fsbase); mcp^.mc_gsbase:=ptruint(td^.pcb_gsbase); bzero(@mcp^.mc_spare,sizeof(mcp^.mc_spare)); Result:=0; end; //sce ext function get_mcontext2(td:p_kthread;mcp:p_mcontext_t;flags:Integer):Integer; var tp:p_trapframe; begin tp:=@td^.td_frame; mcp^.mc_onstack:=sigonstack(tp^.tf_rsp); mcp^.mc_r15 :=tp^.tf_r15; mcp^.mc_r14 :=tp^.tf_r14; mcp^.mc_r13 :=tp^.tf_r13; mcp^.mc_r12 :=tp^.tf_r12; mcp^.mc_r11 :=tp^.tf_r11; mcp^.mc_r10 :=tp^.tf_r10; mcp^.mc_r9 :=tp^.tf_r9; mcp^.mc_r8 :=tp^.tf_r8; mcp^.mc_rdi :=tp^.tf_rdi; mcp^.mc_rsi :=tp^.tf_rsi; mcp^.mc_rbp :=tp^.tf_rbp; mcp^.mc_rbx :=tp^.tf_rbx; mcp^.mc_rcx :=tp^.tf_rcx; mcp^.mc_rflags:=tp^.tf_rflags; mcp^.mc_rax :=tp^.tf_rax; mcp^.mc_rdx :=tp^.tf_rdx; mcp^.mc_rip :=tp^.tf_rip; mcp^.mc_cs :=tp^.tf_cs; mcp^.mc_rsp :=tp^.tf_rsp; mcp^.mc_ss :=tp^.tf_ss; mcp^.mc_ds :=tp^.tf_ds; mcp^.mc_es :=tp^.tf_es; mcp^.mc_fs :=tp^.tf_fs; mcp^.mc_gs :=tp^.tf_gs; mcp^.mc_flags :=tp^.tf_flags; mcp^.mc_len :=sizeof(mcontext_t); //xmm,ymm get_fpcontext(td,mcp,@mcp^.mc_fpstate); //xmm,ymm mcp^.mc_fsbase:=ptruint(td^.pcb_fsbase); mcp^.mc_gsbase:=ptruint(td^.pcb_gsbase); bzero(@mcp^.mc_spare,sizeof(mcp^.mc_spare)); Result:=0; end; //sce ext function set_mcontext(td:p_kthread;mcp:p_mcontext_t):Integer; var tp:p_trapframe; rflags:QWORD; begin tp:=@td^.td_frame; if (mcp^.mc_len<>sizeof(mcontext_t)) or ((mcp^.mc_flags and (not _MC_FLAG_MASK))<>0) then begin Exit(EINVAL); end; //xmm,ymm if ((mcp^.mc_rflags and _MC_HASFPXSTATE)<>0) then begin Result:=set_fpcontext(td,mcp,@mcp^.mc_fpstate); if (Result<>0) then Exit; end; //xmm,ymm rflags:=(mcp^.mc_rflags and PSL_USERCHANGE) or (tp^.tf_rflags and (not PSL_USERCHANGE)); tp^.tf_r15 :=mcp^.mc_r15; tp^.tf_r14 :=mcp^.mc_r14; tp^.tf_r13 :=mcp^.mc_r13; tp^.tf_r12 :=mcp^.mc_r12; tp^.tf_r11 :=mcp^.mc_r11; tp^.tf_r10 :=mcp^.mc_r10; tp^.tf_r9 :=mcp^.mc_r9; tp^.tf_r8 :=mcp^.mc_r8; tp^.tf_rdi :=mcp^.mc_rdi; tp^.tf_rsi :=mcp^.mc_rsi; tp^.tf_rbp :=mcp^.mc_rbp; tp^.tf_rbx :=mcp^.mc_rbx; tp^.tf_rdx :=mcp^.mc_rdx; tp^.tf_rcx :=mcp^.mc_rcx; tp^.tf_rax :=mcp^.mc_rax; tp^.tf_rip :=mcp^.mc_rip; tp^.tf_rflags:=rflags; tp^.tf_rsp :=mcp^.mc_rsp; tp^.tf_ss :=mcp^.mc_ss; tp^.tf_flags :=mcp^.mc_flags; if ((tp^.tf_flags and TF_HASSEGS)<>0) then begin tp^.tf_ds:=mcp^.mc_ds; tp^.tf_es:=mcp^.mc_es; tp^.tf_fs:=mcp^.mc_fs; tp^.tf_gs:=mcp^.mc_gs; end; if ((mcp^.mc_flags and _MC_HASBASES)<>0) then begin cpu_set_fsbase(td,Pointer(mcp^.mc_fsbase)); cpu_set_gsbase(td,Pointer(mcp^.mc_gsbase)); end; set_pcb_flags(td,PCB_FULL_IRET); Result:=0; end; procedure host_sigcode; external; function IS_SYSTEM_STACK(td:p_kthread;rsp:qword):Boolean; inline; begin Result:=(rsp<=QWORD(td^.td_kstack.stack)) and (rsp>(QWORD(td^.td_kstack.sttop))); end; procedure sendsig(catcher:sig_t;ksi:p_ksiginfo;mask:p_sigset_t); var td:p_kthread; sf:sigframe; sfp:p_sigframe; regs:p_trapframe; sp:QWORD; sig,oonstack:Integer; begin td:=curkthread; Writeln('sendsig'); sig:=ksi^.ksi_info.si_signo; regs:=@td^.td_frame; oonstack:=sigonstack(regs^.tf_rsp); // Save user context. sf:=Default(sigframe); sf.sf_uc.uc_sigmask:=mask^; sf.sf_uc.uc_stack :=td^.td_sigstk; if ((td^.td_pflags and TDP_ALTSTACK)<>0) then begin if (oonstack<>0) then begin sf.sf_uc.uc_stack.ss_flags:=SS_ONSTACK; end else begin sf.sf_uc.uc_stack.ss_flags:=0; end; end else begin sf.sf_uc.uc_stack.ss_flags:=SS_DISABLE; end; sf.sf_uc.uc_mcontext.mc_onstack:=oonstack; //set segs regs^.tf_cs:=_ucodesel; regs^.tf_ds:=_udatasel; regs^.tf_ss:=_udatasel; regs^.tf_es:=_udatasel; regs^.tf_fs:=_ufssel; regs^.tf_gs:=_ugssel; regs^.tf_flags:=regs^.tf_flags or TF_HASSEGS; //set segs bmove(@regs^.tf_rdi,@sf.sf_uc.uc_mcontext.mc_rdi,tf_copy_1); bmove(@regs^.tf_err,@sf.sf_uc.uc_mcontext.mc_err,tf_copy_2); sf.sf_uc.uc_mcontext.mc_lbrfrom:=QWORD(-1); sf.sf_uc.uc_mcontext.mc_lbrto :=QWORD(-1); sf.sf_uc.uc_mcontext.mc_len:=sizeof(mcontext_t); //xmm,ymm if ((regs^.tf_flags and TF_HASFPXSTATE)<>0) then begin get_fpcontext(td,@sf.sf_uc.uc_mcontext,@sf.sf_uc.uc_mcontext.mc_fpstate); //reset fpcontext usage regs^.tf_flags:=regs^.tf_flags and (not TF_HASFPXSTATE); end; //xmm,ymm sf.sf_uc.uc_mcontext.mc_flags :=sf.sf_uc.uc_mcontext.mc_flags or _MC_HASBASES; sf.sf_uc.uc_mcontext.mc_fsbase:=QWORD(td^.pcb_fsbase); sf.sf_uc.uc_mcontext.mc_gsbase:=QWORD(td^.pcb_gsbase); if ((td^.td_pflags and TDP_ALTSTACK)<>0) and (oonstack=0) and SIGISMEMBER(@p_sigacts.ps_sigonstack,sig) then begin sp:=QWORD(td^.td_sigstk.ss_sp)+td^.td_sigstk.ss_size; end else begin sp:=regs^.tf_rsp-128; end; if IS_SYSTEM_STACK(td,sp) then begin Assert(false,'System stack on guest context?'); end; sp:=sp-sizeof(sigframe); sfp:=p_sigframe(sp and (not $1F)); regs^.tf_rdi:=sig; regs^.tf_rdx:=QWORD(@sfp^.sf_uc); if (SIGISMEMBER(@p_sigacts.ps_siginfo,sig)) then begin regs^.tf_rsi:=QWORD(@sfp^.sf_si); sf.sf_ahu:=Pointer(catcher); sf.sf_si:=ksi^.ksi_info; sf.sf_si.si_signo:=sig; regs^.tf_rcx:=QWORD(ksi^.ksi_info.si_addr); end else begin regs^.tf_rsi:=ksi^.ksi_info.si_code; regs^.tf_rcx:=QWORD(ksi^.ksi_info.si_addr); sf.sf_ahu:=Pointer(catcher); end; ps_mtx_unlock; PROC_UNLOCK; if (copyout(@sf,sfp,sizeof(sigframe))<>0) then begin PROC_LOCK; sigexit(td,SIGILL); end; regs^.tf_rsp:=QWORD(sfp); if ((td^.pcb_flags and PCB_IS_JIT)=0) or ((td^.pcb_flags and PCB_IS_HLE)<>0) then begin regs^.tf_rip:=QWORD(@host_sigcode); end else begin regs^.tf_rip:=QWORD(p_vmspace(p_proc.p_vmspace)^.sv_usrstack); end; regs^.tf_rflags:=regs^.tf_rflags and (not (PSL_T or PSL_D)); set_pcb_flags(td,PCB_FULL_IRET); PROC_LOCK; ps_mtx_lock; end; function sys_sigreturn(sigcntxp:Pointer):Integer; var td:p_kthread; uc:ucontext_t; regs:p_trapframe; ucp:p_ucontext_t; begin td:=curkthread; Writeln('sys_sigreturn'); Result:=copyin(sigcntxp,@uc,sizeof(ucontext_t)); if (Result<>0) then Exit; if IS_SYSTEM_STACK(td,uc.uc_mcontext.mc_rsp) then begin Assert(false,'System stack on guest context?'); end; ucp:=@uc; if ((ucp^.uc_mcontext.mc_flags and (not _MC_FLAG_MASK))<>0) then begin Exit(EINVAL); end; regs:=@td^.td_frame; //xmm,ymm if ((uc.uc_mcontext.mc_flags and _MC_HASFPXSTATE)<>0) then begin Result:=set_fpcontext(td,@ucp^.uc_mcontext,@ucp^.uc_mcontext.mc_fpstate); if (Result<>0) then Exit; end; //xmm,ymm bmove(@ucp^.uc_mcontext.mc_rdi,@regs^.tf_rdi,tf_copy_1); bmove(@ucp^.uc_mcontext.mc_err,@regs^.tf_err,tf_copy_2); if ((ucp^.uc_mcontext.mc_flags and _MC_HASBASES)<>0) then begin cpu_set_fsbase(td,Pointer(ucp^.uc_mcontext.mc_fsbase)); cpu_set_gsbase(td,Pointer(ucp^.uc_mcontext.mc_gsbase)); end; kern_sigprocmask(td,SIG_SETMASK,@ucp^.uc_sigmask,nil,0); set_pcb_flags(td,PCB_FULL_IRET); Result:=EJUSTRETURN; end; procedure exec_setregs(td:p_kthread;entry,stack_base,stack_top:QWORD); var regs:p_trapframe; begin regs:=@td^.td_frame; cpu_set_fsbase(td,nil); cpu_set_gsbase(td,nil); set_pcb_flags(td,PCB_FULL_IRET); bzero(regs, sizeof(trapframe)); regs^.tf_rip :=entry; regs^.tf_rsp :=((stack_base - 8) and (not $F)) + 8; regs^.tf_rdi :=stack_base; // argv regs^.tf_rflags:=PSL_USER or (regs^.tf_rflags and PSL_T); regs^.tf_ss :=_udatasel; regs^.tf_cs :=_ucodesel; regs^.tf_ds :=_udatasel; regs^.tf_es :=_udatasel; regs^.tf_fs :=_ufssel; regs^.tf_gs :=_ugssel; regs^.tf_flags :=TF_HASSEGS; //init FPU fpuinit(td); Set8087CW(__INITIAL_FPUCW__); SetMXCSR (__INITIAL_MXCSR__); //teb stack td^.td_ustack.stack:=Pointer(stack_top ); td^.td_ustack.sttop:=Pointer(stack_base); //teb stack td^.td_retval[1]:=0; end; end.