FPPS4/sys/md/md_context.pas

913 lines
20 KiB
Plaintext

unit md_context;
{$mode ObjFPC}{$H+}
{$CALLING SysV_ABI_CDecl}
interface
uses
Windows,
ntapi,
ucontext,
kern_thr,
kern_proc;
const
XSTATE_LEGACY_FLOATING_POINT=0;
XSTATE_LEGACY_SSE =1;
XSTATE_GSSE =2;
XSTATE_AVX =XSTATE_GSSE;
XSTATE_MASK_LEGACY_FLOATING_POINT=(1 shl XSTATE_LEGACY_FLOATING_POINT);
XSTATE_MASK_LEGACY_SSE =(1 shl XSTATE_LEGACY_SSE);
XSTATE_MASK_LEGACY =(XSTATE_MASK_LEGACY_FLOATING_POINT or XSTATE_MASK_LEGACY_SSE);
XSTATE_MASK_GSSE =(1 shl XSTATE_GSSE);
XSTATE_MASK_AVX =(XSTATE_MASK_GSSE);
const
CONTEXT_XSTATE =(CONTEXT_AMD64 or $0040);
CONTEXT_ALLX =(CONTEXT_ALL or CONTEXT_XSTATE);
type
PYMMCONTEXT=^TYMMCONTEXT;
TYMMCONTEXT=packed record
Ymm0 :M128A;
Ymm1 :M128A;
Ymm2 :M128A;
Ymm3 :M128A;
Ymm4 :M128A;
Ymm5 :M128A;
Ymm6 :M128A;
Ymm7 :M128A;
Ymm8 :M128A;
Ymm9 :M128A;
Ymm10:M128A;
Ymm11:M128A;
Ymm12:M128A;
Ymm13:M128A;
Ymm14:M128A;
Ymm15:M128A;
end;
PXSTATE=^TXSTATE;
TXSTATE=packed record
Mask:QWORD;
CompactionMask:QWORD;
Reserved:array[0..5] of QWORD;
YmmContext:TYMMCONTEXT;
end;
TXmmSaveArea = Windows.TXmmSaveArea;
PXmmSaveArea = Windows.PXmmSaveArea;
PCONTEXT_CHUNK=^TCONTEXT_CHUNK;
TCONTEXT_CHUNK=packed record
Offset:LONG;
Length:ULONG;
end;
PCONTEXT_EX=^TCONTEXT_EX;
TCONTEXT_EX=packed record
All :TCONTEXT_CHUNK;
Legacy:TCONTEXT_CHUNK;
XState:TCONTEXT_CHUNK;
_align:QWORD;
end;
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;
__INITIAL_FPUCW__ =$037F;
__INITIAL_MXCSR__ =$1F80;
__INITIAL_MXCSR_MASK__=$FFBF;
procedure teb_set_kernel(td:p_kthread);
procedure teb_set_user (td:p_kthread);
Function GetContextSize(ContextFlags:DWORD):QWORD;
function InitializeContextExtended(data:Pointer;ContextFlags:DWORD):Pointer;
function _get_ctx_flags(src:p_ucontext_t):DWORD;
procedure _get_fpcontext(src:PCONTEXT;xstate:Pointer);
procedure _set_fpcontext(dst:PCONTEXT;xstate:Pointer);
procedure fpuinit(td:p_kthread);
procedure _get_frame(src:PCONTEXT;dst:p_trapframe;xstate:Pointer;is_jit:Boolean);
procedure _set_frame(dst:PCONTEXT;src:p_trapframe;xstate:Pointer;is_jit:Boolean);
procedure _get_ucontext(src:PCONTEXT;dst:p_ucontext_t);
procedure _set_ucontext(dst:PCONTEXT;src:p_ucontext_t);
function md_get_fpcontext(td:p_kthread;mcp:p_mcontext_t;xstate:Pointer):Integer;
procedure ipi_sigreturn;
function ipi_send_cpu(td:p_kthread):Integer;
implementation
uses
errno,
systm,
kern_psl,
signal,
md_sleep;
//
procedure teb_set_kernel(td:p_kthread);
begin
//teb stack
if ((td^.pcb_flags and PCB_IS_JIT)=0) then
begin
td^.td_teb^.sttop:=td^.td_kstack.sttop;
td^.td_teb^.stack:=td^.td_kstack.stack;
end;
//teb stack
end;
procedure teb_set_user(td:p_kthread);
begin
//teb stack
if ((td^.pcb_flags and PCB_IS_JIT)=0) then
begin
if (sigonstack(td^.td_frame.tf_rsp)<>0) then
begin
td^.td_teb^.stack:=td^.td_sigstk.ss_sp;
td^.td_teb^.sttop:=td^.td_sigstk.ss_sp-td^.td_sigstk.ss_size;
end else
begin
td^.td_teb^.stack:=td^.td_ustack.stack;
td^.td_teb^.sttop:=td^.td_ustack.sttop;
end;
end;
//teb stack
end;
function GetEnabledXStateFeatures:QWORD; stdcall external 'kernel32';
function InitializeContext(
Buffer:Pointer;
ContextFlags:DWORD;
Context:Pointer;
ContextLength:PDWORD
):BOOL; stdcall external 'kernel32';
function SetXStateFeaturesMask(
Context:PCONTEXT;
FeatureMask:QWORD
):BOOL; stdcall external 'kernel32';
Function GetContextSize(ContextFlags:DWORD):QWORD;
begin
Result:=0;
InitializeContext(nil,
ContextFlags,
nil,
@Result);
end;
function InitializeContextExtended(data:Pointer;ContextFlags:DWORD):Pointer;
var
ContextSize:DWORD;
FeatureMask:QWORD;
XstateMaskf:QWORD;
XstateMaskr:QWORD;
begin
Result:=nil;
if (data=nil) then Exit;
ContextSize:=GetContextSize(ContextFlags);
if (ContextSize=0) then Exit;
FillChar(data^,ContextSize,0);
if not InitializeContext(data,
ContextFlags,
@Result,
@ContextSize) then
begin
Exit(nil);
end;
if ((ContextFlags and $40)<>0) then
begin
FeatureMask:=GetEnabledXStateFeatures;
XstateMaskf:=FeatureMask and (XSTATE_MASK_LEGACY or XSTATE_MASK_AVX);
XstateMaskr:=ContextFlags and (XSTATE_MASK_LEGACY or XSTATE_MASK_AVX);
if (XstateMaskf<>XstateMaskr) then
begin
Exit(nil);
end;
if not SetXStateFeaturesMask(Result,XstateMaskr) then
begin
Exit(nil);
end;
end;
end;
function _get_ctx_flags(src:p_ucontext_t):DWORD;
begin
Result:=0;
if ((src^.uc_flags and _UC_CPU)<>0) then
begin
Result:=Result or CONTEXT_INTEGER or CONTEXT_CONTROL;
end;
if ((src^.uc_mcontext.mc_flags and _MC_HASSEGS)<>0) then
begin
Result:=Result or CONTEXT_SEGMENTS;
end;
if ((src^.uc_mcontext.mc_flags and _MC_HASFPXSTATE)<>0) then
begin
Result:=Result or CONTEXT_FLOATING_POINT or CONTEXT_XSTATE;
end;
Result:=Result and (not CONTEXT_AMD64);
end;
function _get_ctx_flags(src:p_trapframe):DWORD;
begin
Result:=CONTEXT_INTEGER or CONTEXT_CONTROL;
if ((src^.tf_flags and _MC_HASSEGS)<>0) then
begin
Result:=Result or CONTEXT_SEGMENTS;
end;
if ((src^.tf_flags and _MC_HASFPXSTATE)<>0) then
begin
Result:=Result or CONTEXT_FLOATING_POINT or CONTEXT_XSTATE;
end;
Result:=Result and (not CONTEXT_AMD64);
end;
procedure _get_fpcontext(src:PCONTEXT;xstate:Pointer);
var
context_ex:PCONTEXT_EX;
xs:PXSTATE;
uc_xsave :PXmmSaveArea;
uc_xstate:PXSTATE;
begin
if (src=nil) or (xstate=nil) then Exit;
context_ex:=PCONTEXT_EX(src+1);
xs:=PXSTATE(PByte(context_ex)+context_ex^.XState.Offset);
uc_xsave :=PXmmSaveArea(xstate);
uc_xstate:=PXSTATE(uc_xsave+1);
uc_xsave^:=src^.FltSave;
uc_xstate^:=xs^;
end;
procedure _set_fpcontext(dst:PCONTEXT;xstate:Pointer);
var
context_ex:PCONTEXT_EX;
xs:PXSTATE;
uc_xsave :PXmmSaveArea;
uc_xstate:PXSTATE;
begin
if (dst=nil) or (xstate=nil) then Exit;
context_ex:=PCONTEXT_EX(dst+1);
xs:=PXSTATE(PByte(context_ex)+context_ex^.XState.Offset);
uc_xsave :=PXmmSaveArea(xstate);
uc_xstate:=PXSTATE(uc_xsave+1);
dst^.MxCsr:=uc_xsave^.MxCsr;
dst^.FltSave:=uc_xsave^;
xs^:=uc_xstate^;
end;
procedure fpuinit(td:p_kthread);
var
uc_xsave :PXmmSaveArea;
uc_xstate:PXSTATE;
begin
if (td=nil) then Exit;
uc_xsave :=PXmmSaveArea(@td^.td_fpstate);
uc_xstate:=PXSTATE(uc_xsave+1);
//uc_xstate^.Mask:=
uc_xstate^.CompactionMask:=GetEnabledXStateFeatures;
uc_xstate^.CompactionMask:=uc_xstate^.CompactionMask and (XSTATE_MASK_LEGACY or XSTATE_MASK_AVX);
uc_xstate^.CompactionMask:=uc_xstate^.CompactionMask or QWORD(1 shl 63);
uc_xsave^.ControlWord:=__INITIAL_FPUCW__;
//uc_xsave^.StatusWord: WORD;
uc_xsave^.MxCsr :=__INITIAL_MXCSR__;
uc_xsave^.MxCsr_Mask :=__INITIAL_MXCSR_MASK__;
td^.td_frame.tf_flags:=td^.td_frame.tf_flags or TF_HASFPXSTATE;
end;
procedure _get_frame(src:PCONTEXT;dst:p_trapframe;xstate:Pointer;is_jit:Boolean);
var
flags:DWORD;
begin
if (src=nil) or (dst=nil) then Exit;
flags:=src^.ContextFlags and (not CONTEXT_AMD64);
if ((flags and CONTEXT_INTEGER)<>0) then
begin
dst^.tf_rax:=src^.Rax;
dst^.tf_rbx:=src^.Rbx;
dst^.tf_rcx:=src^.Rcx;
dst^.tf_rdx:=src^.Rdx;
dst^.tf_rsi:=src^.Rsi;
dst^.tf_rdi:=src^.Rdi;
dst^.tf_r8 :=src^.R8 ;
dst^.tf_r9 :=src^.R9 ;
dst^.tf_r10:=src^.R10;
dst^.tf_r11:=src^.R11;
dst^.tf_r12:=src^.R12;
if not is_jit then
begin
dst^.tf_r13:=src^.R13;
dst^.tf_r14:=src^.R14;
dst^.tf_r15:=src^.R15;
dst^.tf_rbp:=src^.Rbp;
end;
end;
if ((flags and CONTEXT_CONTROL)<>0) then
begin
if not is_jit then
begin
dst^.tf_rsp :=src^.Rsp;
dst^.tf_rip :=src^.Rip;
end;
dst^.tf_rflags:=src^.EFlags;
end;
if ((flags and CONTEXT_XSTATE)<>0) then
begin
_get_fpcontext(src,xstate);
dst^.tf_flags:=dst^.tf_flags or _MC_HASFPXSTATE;
end;
end;
procedure _set_frame(dst:PCONTEXT;src:p_trapframe;xstate:Pointer;is_jit:Boolean);
var
flags:DWORD;
begin
if (src=nil) or (dst=nil) then Exit;
flags:=_get_ctx_flags(src);
flags:=flags and dst^.ContextFlags; //filter
dst^.ContextFlags:=flags or CONTEXT_AMD64; //update
if ((flags and CONTEXT_INTEGER)<>0) then
begin
dst^.Rax:=src^.tf_rax;
dst^.Rbx:=src^.tf_rbx;
dst^.Rcx:=src^.tf_rcx;
dst^.Rdx:=src^.tf_rdx;
dst^.Rsi:=src^.tf_rsi;
dst^.Rdi:=src^.tf_rdi;
dst^.R8 :=src^.tf_r8;
dst^.R9 :=src^.tf_r9;
dst^.R10:=src^.tf_r10;
dst^.R11:=src^.tf_r11;
if not is_jit then
begin
dst^.R12:=src^.tf_r12;
dst^.R13:=src^.tf_r13;
dst^.R14:=src^.tf_r14;
dst^.R15:=src^.tf_r15;
dst^.Rbp:=src^.tf_rbp;
end;
end;
if ((flags and CONTEXT_CONTROL)<>0) then
begin
if not is_jit then
begin
dst^.Rsp :=src^.tf_rsp;
dst^.Rip :=src^.tf_rip;
end;
dst^.EFlags:=src^.tf_rflags;
end;
if ((flags and CONTEXT_FLOATING_POINT)<>0) or
((flags and CONTEXT_XSTATE)<>0) then
begin
_set_fpcontext(dst,xstate);
end;
end;
//
procedure _get_ucontext(src:PCONTEXT;dst:p_ucontext_t);
var
flags:DWORD;
begin
if (src=nil) or (dst=nil) then Exit;
flags:=src^.ContextFlags and (not CONTEXT_AMD64);
if ((flags and CONTEXT_INTEGER)<>0) then
begin
dst^.uc_flags:=dst^.uc_flags or _UC_CPU;
dst^.uc_mcontext.mc_rax:=src^.Rax;
dst^.uc_mcontext.mc_rbx:=src^.Rbx;
dst^.uc_mcontext.mc_rcx:=src^.Rcx;
dst^.uc_mcontext.mc_rdx:=src^.Rdx;
dst^.uc_mcontext.mc_rsi:=src^.Rsi;
dst^.uc_mcontext.mc_rdi:=src^.Rdi;
dst^.uc_mcontext.mc_r8 :=src^.R8 ;
dst^.uc_mcontext.mc_r9 :=src^.R9 ;
dst^.uc_mcontext.mc_r10:=src^.R10;
dst^.uc_mcontext.mc_r11:=src^.R11;
dst^.uc_mcontext.mc_r12:=src^.R12;
dst^.uc_mcontext.mc_r13:=src^.R13;
dst^.uc_mcontext.mc_r14:=src^.R14;
dst^.uc_mcontext.mc_r15:=src^.R15;
dst^.uc_mcontext.mc_rbp:=src^.Rbp;
end;
if ((flags and CONTEXT_CONTROL)<>0) then
begin
dst^.uc_flags:=dst^.uc_flags or _UC_CPU;
dst^.uc_mcontext.mc_rsp :=src^.Rsp;
dst^.uc_mcontext.mc_rip :=src^.Rip;
dst^.uc_mcontext.mc_rflags:=src^.EFlags;
dst^.uc_mcontext.mc_cs :=_ucodesel;
dst^.uc_mcontext.mc_ss :=_udatasel;
end;
if ((flags and CONTEXT_SEGMENTS)<>0) then
begin
dst^.uc_mcontext.mc_flags:=dst^.uc_mcontext.mc_flags or _MC_HASSEGS;
dst^.uc_mcontext.mc_ds:=_udatasel;
dst^.uc_mcontext.mc_es:=_udatasel;
dst^.uc_mcontext.mc_fs:=_ufssel;
dst^.uc_mcontext.mc_gs:=_ugssel;
end;
if ((flags and CONTEXT_XSTATE)<>0) then
begin
_get_fpcontext(src,@dst^.uc_mcontext.mc_fpstate);
dst^.uc_mcontext.mc_fpformat:=_MC_FPFMT_XMM;
dst^.uc_mcontext.mc_ownedfp :=_MC_FPOWNED_FPU;
dst^.uc_mcontext.mc_flags:=dst^.uc_mcontext.mc_flags or _MC_HASFPXSTATE;
end;
dst^.uc_mcontext.mc_len:=SizeOf(mcontext_t);
end;
procedure _set_ucontext(dst:PCONTEXT;src:p_ucontext_t);
var
flags:DWORD;
begin
if (src=nil) or (dst=nil) then Exit;
flags:=_get_ctx_flags(src);
flags:=flags and dst^.ContextFlags; //filter
dst^.ContextFlags:=flags or CONTEXT_AMD64; //update
if ((flags and CONTEXT_INTEGER)<>0) then
begin
dst^.Rax:=src^.uc_mcontext.mc_rax;
dst^.Rbx:=src^.uc_mcontext.mc_rbx;
dst^.Rcx:=src^.uc_mcontext.mc_rcx;
dst^.Rdx:=src^.uc_mcontext.mc_rdx;
dst^.Rsi:=src^.uc_mcontext.mc_rsi;
dst^.Rdi:=src^.uc_mcontext.mc_rdi;
dst^.R8 :=src^.uc_mcontext.mc_r8;
dst^.R9 :=src^.uc_mcontext.mc_r9;
dst^.R10:=src^.uc_mcontext.mc_r10;
dst^.R11:=src^.uc_mcontext.mc_r11;
dst^.R12:=src^.uc_mcontext.mc_r12;
dst^.R13:=src^.uc_mcontext.mc_r13;
dst^.R14:=src^.uc_mcontext.mc_r14;
dst^.R15:=src^.uc_mcontext.mc_r15;
dst^.Rbp:=src^.uc_mcontext.mc_rbp;
end;
if ((flags and CONTEXT_CONTROL)<>0) then
begin
dst^.Rsp :=src^.uc_mcontext.mc_rsp;
dst^.Rip :=src^.uc_mcontext.mc_rip;
dst^.EFlags:=src^.uc_mcontext.mc_rflags;
dst^.SegCs :=KGDT64_R3_CODE or RPL_MASK;
dst^.SegSs :=KGDT64_R3_DATA or RPL_MASK;
end;
if ((flags and CONTEXT_SEGMENTS)<>0) then
begin
dst^.SegDs:=KGDT64_R3_DATA or RPL_MASK;
dst^.SegEs:=KGDT64_R3_DATA or RPL_MASK;
dst^.SegFs:=KGDT64_R3_CMTEB or RPL_MASK;
dst^.SegGs:=KGDT64_R3_DATA or RPL_MASK;
end;
if ((flags and CONTEXT_FLOATING_POINT)<>0) or
((flags and CONTEXT_XSTATE)<>0) then
begin
_set_fpcontext(dst,@src^.uc_mcontext.mc_fpstate);
end;
end;
function cpu_get_iflag(td:p_kthread):PInteger; inline;
begin
Result:=@td^.td_teb^.iflag;
end;
function IS_TRAP_FUNC(rip:qword):Boolean; external;
function IS_JIT_FUNC (rip:qword):Boolean; 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;
function IS_SYSCALL(rip:qword):Boolean;
var
w:Word;
begin
Result:=False;
if (rip<>0) then
begin
w:=0;
NtReadVirtualMemory(NtCurrentProcess,@PWord(Rip)[-1],@w,SizeOf(Word),nil);
Result:=(w=$050F);
end;
end;
function get_top_mem_td(td:p_kthread;size,align:qword):Pointer;
begin
Result:=System.Align(td^.td_kstack.sttop,align);
if (SPtr>td^.td_kstack.sttop) and (SPtr<=td^.td_kstack.stack) then
begin
if ((Result+size)>=SPtr) then
begin
Result:=thread_get_local_buffer(td,size+align-1);
Result:=System.Align(Result,align);
end;
end;
end;
procedure _apc_null(dwParam:PTRUINT); stdcall;
begin
end;
function md_get_fpcontext(td:p_kthread;mcp:p_mcontext_t;xstate:Pointer):Integer;
var
td_handle:THandle;
Context :PCONTEXT;
begin
Result :=0;
td_handle:=td^.td_handle;
Context:=get_top_mem_td(td,GetContextSize(CONTEXT_XSTATE),16);
Assert(Context<>nil);
Context:=InitializeContextExtended(Context,CONTEXT_XSTATE);
if (NtGetContextThread(td_handle,Context)<>STATUS_SUCCESS) then
begin
Exit(ESRCH)
end;
//xmm,ymm
_get_fpcontext(Context,xstate);
mcp^.mc_flags :=mcp^.mc_flags or _MC_HASFPXSTATE;
mcp^.mc_fpformat:=_MC_FPFMT_XMM;
mcp^.mc_ownedfp :=_MC_FPOWNED_FPU;
//xmm,ymm
end;
procedure switch_to_jit(td:p_kthread); external;
procedure ipi_sigreturn;
var
td:p_kthread;
Context:PCONTEXT;
regs:p_trapframe;
R:DWORD;
begin
td:=curkthread;
if (td=nil) then
begin
Writeln(stderr,'ipi_sigreturn with zero thread');
Exit;
end;
//teb stack
teb_set_kernel(td);
//teb stack
switch_to_jit(td);
regs:=@td^.td_frame;
if ((regs^.tf_flags and TF_HASFPXSTATE)<>0) then
begin
//xmm,ymm
Context:=get_top_mem_td(td,GetContextSize(CONTEXT_ALLX),16);
Assert(Context<>nil);
Context:=InitializeContextExtended(Context,CONTEXT_ALLX);
end else
begin
//simple
Context:=get_top_mem_td(td,SizeOf(TCONTEXT),16);
Assert(Context<>nil);
Context^:=Default(TCONTEXT);
Context^.ContextFlags:=CONTEXT_INTEGER or CONTEXT_CONTROL;
end;
Context^.Rdi:=regs^.tf_rdi;
Context^.Rsi:=regs^.tf_rsi;
Context^.Rdx:=regs^.tf_rdx;
Context^.Rcx:=regs^.tf_rcx;
Context^.R8 :=regs^.tf_r8 ;
Context^.R9 :=regs^.tf_r9 ;
Context^.Rax:=regs^.tf_rax;
Context^.Rbx:=regs^.tf_rbx;
Context^.Rbp:=regs^.tf_rbp;
Context^.R10:=regs^.tf_r10;
Context^.R11:=regs^.tf_r11;
Context^.R12:=regs^.tf_r12;
Context^.R13:=regs^.tf_r13;
Context^.R14:=regs^.tf_r14;
Context^.R15:=regs^.tf_r15;
Context^.Rip :=regs^.tf_rip;
Context^.EFlags:=regs^.tf_rflags;
Context^.Rsp :=regs^.tf_rsp;
Context^.SegGs:=KGDT64_R3_DATA or RPL_MASK;
Context^.SegEs:=KGDT64_R3_DATA or RPL_MASK;
Context^.SegDs:=KGDT64_R3_DATA or RPL_MASK;
Context^.SegCs:=KGDT64_R3_CODE or RPL_MASK;
Context^.SegSs:=KGDT64_R3_DATA or RPL_MASK;
Context^.SegFs:=KGDT64_R3_CMTEB or RPL_MASK;
Context^.MxCsr:=td^.td_fpstate.XMM_SAVE_AREA.MxCsr;
//xmm,ymm
if ((regs^.tf_flags and TF_HASFPXSTATE)<>0) then
begin
_set_fpcontext(Context,@td^.td_fpstate);
regs^.tf_flags:=regs^.tf_flags and (not TF_HASFPXSTATE);
end;
//xmm,ymm
//teb stack
teb_set_user(td);
//teb stack
//Writeln('ipi_sigreturn');
R:=NtContinue(Context,False);
Writeln(stderr,'NtContinue:0x',HexStr(R,8));
end;
procedure host_sigipi; external;
procedure on_ipi(td :p_kthread;
ApcArgument2 :Pointer;
ApcArgument3 :Pointer;
ContextRecord:PCONTEXT); stdcall;
begin
if IS_SYSTEM_STACK(td,ContextRecord^.Rsp) or //system?
IS_TRAP_FUNC(ContextRecord^.Rip) or //syscall func?
IS_JIT_FUNC (ContextRecord^.Rip) then //syscall func?
begin
Exit;
end;
Writeln('TODO:on_ipi');
//Assert(false,'on_ipi');
end;
function ipi_send_cpu(td:p_kthread):Integer;
label
resume,
tryagain;
var
td_handle:THandle;
iflag :PInteger;
Context :PCONTEXT;
w:LARGE_INTEGER;
sf:sigframe;
sfp:p_sigframe;
regs:p_trapframe;
sp:QWORD;
oonstack:Integer;
begin
Result :=0;
//td_handle:=td^.td_handle;
//iflag :=cpu_get_iflag(td);
Result:=NtQueueApcThreadEx(
td^.td_handle,
QUEUE_USER_APC_FLAGS_SPECIAL_USER_APC,
@on_ipi,
td,
nil,
nil
);
Assert(Result=0,'NtQueueApcThreadEx failed');
{
PROC_LOCK;
tryagain:
if (NtSuspendThread(td_handle,nil)<>STATUS_SUCCESS) then
begin
PROC_UNLOCK;
Exit(ESRCH);
end;
w.QuadPart:=0;
if (NtWaitForSingleObject(td_handle,False,@w)<>STATUS_TIMEOUT) then
begin
Result:=ESRCH;
goto resume;
end;
if ((iflag^ and SIG_ALTERABLE)<>0) then //alterable?
begin
NtQueueApcThread(td_handle,@_apc_null,nil,nil,0);
Result:=0;
goto resume;
end else
if (iflag^<>0) then //locked?
begin
Result:=0;
goto resume;
end;
{
if (td^.td_teb^.jit_rsp<>nil) then //jit call?
begin
Result:=0;
goto resume;
end;
}
Context:=get_top_mem_td(td,GetContextSize(CONTEXT_ALLX),16);
Assert(Context<>nil);
Context:=InitializeContextExtended(Context,CONTEXT_ALLX);
if (NtGetContextThread(td_handle,Context)<>STATUS_SUCCESS) then
begin
Result:=ESRCH;
goto resume;
end;
if IS_SYSTEM_STACK(td,Context^.Rsp) or //system?
IS_TRAP_FUNC(Context^.Rip) or //syscall func?
IS_JIT_FUNC (Context^.Rip) then //syscall func?
begin
Result:=0;
goto resume;
end;
if IS_SYSCALL(Context^.Rip) then //system call in code without blocking
begin
NtResumeThread(td_handle,nil);
w.QuadPart:=-10000;
NtDelayExecution(False,@w); //100ms
goto tryagain;
end;
regs:=@td^.td_frame;
oonstack:=sigonstack(Context^.Rsp);
// Save user context.
sf:=Default(sigframe);
sf.sf_uc.uc_sigmask:=td^.td_sigmask;
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;
//copy frame
regs^.tf_rdi:=Context^.Rdi;
regs^.tf_rsi:=Context^.Rsi;
regs^.tf_rdx:=Context^.Rdx;
regs^.tf_rcx:=Context^.Rcx;
regs^.tf_r8 :=Context^.R8 ;
regs^.tf_r9 :=Context^.R9 ;
regs^.tf_rax:=Context^.Rax;
regs^.tf_rbx:=Context^.Rbx;
regs^.tf_rbp:=Context^.Rbp;
regs^.tf_r10:=Context^.R10;
regs^.tf_r11:=Context^.R11;
regs^.tf_r12:=Context^.R12;
regs^.tf_r13:=Context^.R13;
regs^.tf_r14:=Context^.R14;
regs^.tf_r15:=Context^.R15;
regs^.tf_rip :=Context^.Rip;
regs^.tf_rflags:=Context^.EFlags;
regs^.tf_rsp :=Context^.Rsp;
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:=TF_HASSEGS;
//copy frame
sf.sf_uc.uc_mcontext.mc_onstack:=oonstack;
Move(regs^.tf_rdi,sf.sf_uc.uc_mcontext.mc_rdi,tf_copy_1);
Move(regs^.tf_err,sf.sf_uc.uc_mcontext.mc_err,tf_copy_2);
sf.sf_uc.uc_mcontext.mc_len:=sizeof(mcontext_t);
sf.sf_uc.uc_mcontext.mc_fsbase:=QWORD(td^.pcb_fsbase);
sf.sf_uc.uc_mcontext.mc_gsbase:=QWORD(td^.pcb_gsbase);
sf.sf_uc.uc_mcontext.mc_flags:=_MC_HASSEGS or _MC_HASBASES or _MC_HASFPXSTATE;
//xmm,ymm
_get_fpcontext(Context,@sf.sf_uc.uc_mcontext.mc_fpstate);
sf.sf_uc.uc_mcontext.mc_fpformat:=_MC_FPFMT_XMM;
sf.sf_uc.uc_mcontext.mc_ownedfp :=_MC_FPOWNED_FPU;
//xmm,ymm
sp:=QWORD(td^.td_kstack.stack);
sp:=sp-sizeof(sigframe);
sfp:=p_sigframe(sp and (not $1F));
if (copyout(@sf,sfp,sizeof(sigframe))<>0) then
begin
Result:=EFAULT;
goto resume;
end;
Context^.Rsp:=QWORD(sfp);
Context^.Rip:=QWORD(@host_sigipi);
Context^.EFlags:=Context^.EFlags and (not (PSL_T or PSL_D));
set_pcb_flags(td,PCB_FULL_IRET);
if (NtSetContextThread(td_handle,Context)<>STATUS_SUCCESS) then
begin
Result:=ESRCH;
goto resume;
end;
//teb stack
teb_set_user(td);
//teb stack
resume:
NtResumeThread(td_handle,nil);
PROC_UNLOCK;
}
end;
end.