mirror of https://github.com/red-prig/fpPS4.git
251 lines
5.0 KiB
Plaintext
251 lines
5.0 KiB
Plaintext
unit machdep;
|
|
|
|
{$mode ObjFPC}{$H+}
|
|
{$CALLING SysV_ABI_CDecl}
|
|
|
|
interface
|
|
|
|
uses
|
|
signal,
|
|
signalvar,
|
|
ucontext,
|
|
kern_thr;
|
|
|
|
const
|
|
_ucodesel=(8 shl 3) or 3;
|
|
_udatasel=(7 shl 3) or 3;
|
|
_ufssel =(2 shl 3) or 3;
|
|
_ugssel =(3 shl 3) or 3;
|
|
|
|
procedure cpu_set_syscall_retval(td:p_kthread;error:Integer);
|
|
procedure sendsig(catcher:sig_t;ksi:p_ksiginfo;mask:p_sigset_t);
|
|
function sys_sigreturn(sigcntxp:p_ucontext_t):Integer;
|
|
|
|
implementation
|
|
|
|
uses
|
|
errno,
|
|
systm,
|
|
md_psl,
|
|
kern_sig,
|
|
trap;
|
|
|
|
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;
|
|
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;
|
|
|
|
Move(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
|
|
Move(xstate^,td^.td_fpstate,SizeOf(mcp^.mc_fpstate));
|
|
Exit(0);
|
|
end;
|
|
|
|
Exit(EINVAL);
|
|
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;
|
|
|
|
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
|
|
|
|
Move(regs^,sf.sf_uc.uc_mcontext.mc_rdi,SizeOf(trapframe));
|
|
|
|
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);
|
|
|
|
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;
|
|
|
|
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);
|
|
regs^.tf_rip:=QWORD(@sigcode);
|
|
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:p_ucontext_t):Integer;
|
|
var
|
|
td:p_kthread;
|
|
uc:ucontext_t;
|
|
regs:p_trapframe;
|
|
ucp:p_ucontext_t;
|
|
begin
|
|
td:=curkthread;
|
|
|
|
Result:=copyin(sigcntxp,@uc,sizeof(ucontext_t));
|
|
if (Result<>0) then Exit;
|
|
|
|
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;
|
|
|
|
regs^.tf_flags:=regs^.tf_flags or TF_HASFPXSTATE;
|
|
end;
|
|
//xmm,ymm
|
|
|
|
Move(ucp^.uc_mcontext.mc_rdi,regs^,sizeof(trapframe));
|
|
|
|
//pcb^.pcb_fsbase := ucp^.uc_mcontext.mc_fsbase;
|
|
//pcb^.pcb_gsbase := ucp^.uc_mcontext.mc_gsbase;
|
|
|
|
kern_sigprocmask(td,SIG_SETMASK,@ucp^.uc_sigmask,nil,0);
|
|
|
|
set_pcb_flags(td,PCB_FULL_IRET);
|
|
Result:=EJUSTRETURN;
|
|
end;
|
|
|
|
|
|
end.
|
|
|