mirror of https://github.com/red-prig/fpPS4.git
932 lines
22 KiB
Plaintext
932 lines
22 KiB
Plaintext
unit kern_sysctl;
|
|
|
|
{$mode ObjFPC}{$H+}
|
|
{$CALLING SysV_ABI_CDecl}
|
|
|
|
interface
|
|
|
|
|
|
const
|
|
CTL_MAXNAME=24; // largest number of components supported
|
|
|
|
CTLTYPE =$f; // Mask for the type
|
|
CTLTYPE_NODE =1; // name is a node
|
|
CTLTYPE_INT =2; // name describes an integer
|
|
CTLTYPE_STRING=3; // name describes a string
|
|
CTLTYPE_S64 =4; // name describes a signed 64-bit number
|
|
CTLTYPE_OPAQUE=5; // name describes a structure
|
|
CTLTYPE_STRUCT=CTLTYPE_OPAQUE; // name describes a structure
|
|
CTLTYPE_UINT =6; // name describes an unsigned integer
|
|
CTLTYPE_LONG =7; // name describes a long
|
|
CTLTYPE_ULONG =8; // name describes an unsigned long
|
|
CTLTYPE_U64 =9; // name describes an unsigned 64-bit number
|
|
|
|
CTLFLAG_RD =$80000000; // Allow reads of variable
|
|
CTLFLAG_WR =$40000000; // Allow writes to the variable
|
|
CTLFLAG_RW =(CTLFLAG_RD or CTLFLAG_WR);
|
|
CTLFLAG_ANYBODY=$10000000; // All users can set this var
|
|
CTLFLAG_SECURE =$08000000; // Permit set only if securelevel<=0
|
|
CTLFLAG_PRISON =$04000000; // Prisoned roots can fiddle
|
|
CTLFLAG_DYN =$02000000; // Dynamic oid - can be freed
|
|
CTLFLAG_SKIP =$01000000; // Skip this sysctl when listing
|
|
CTLMASK_SECURE =$00F00000; // Secure level
|
|
CTLFLAG_TUN =$00080000; // Tunable variable
|
|
CTLFLAG_RDTUN =(CTLFLAG_RD or CTLFLAG_TUN);
|
|
CTLFLAG_RWTUN =(CTLFLAG_RW or CTLFLAG_TUN);
|
|
CTLFLAG_MPSAFE =$00040000; // Handler is MP safe
|
|
CTLFLAG_VNET =$00020000; // Prisons with vnet can fiddle
|
|
CTLFLAG_DYING =$00010000; // oid is being removed
|
|
CTLFLAG_CAPRD =$00008000; // Can be read in capability mode
|
|
CTLFLAG_CAPWR =$00004000; // Can be written in capability mode
|
|
CTLFLAG_CAPRW =(CTLFLAG_CAPRD or CTLFLAG_CAPWR);
|
|
|
|
OID_AUTO=(-1);
|
|
|
|
CTL_AUTO_START=$100;
|
|
|
|
//Top-level identifiers
|
|
CTL_UNSPEC = 0; // unused
|
|
CTL_KERN = 1; // "high kernel": proc, limits
|
|
CTL_VM = 2; // virtual memory
|
|
CTL_VFS = 3; // filesystem, mount type is next
|
|
CTL_NET = 4; // network, see socket.h
|
|
CTL_DEBUG = 5; // debugging parameters
|
|
CTL_HW = 6; // generic cpu/io
|
|
CTL_MACHDEP = 7; // machine dependent
|
|
CTL_USER = 8; // user-level
|
|
CTL_P1003_1B= 9; // POSIX 1003.1B
|
|
CTL_MAXID =10; // number of valid top-level ids
|
|
|
|
|
|
//CTL_KERN identifiers
|
|
KERN_PROC =14;
|
|
KERN_USRSTACK=33;
|
|
KERN_ARND =37;
|
|
|
|
KERN_SMP =$100; //(OID_AUTO) Kernel SMP
|
|
KERN_SCHED =$101; //(OID_AUTO) Scheduler
|
|
|
|
//CTL_VM subtypes
|
|
KERN_VM_PS4DEV=1; //vm parameters for PS4 (DevKit only)
|
|
|
|
//KERN_PROC subtypes
|
|
KERN_PROC_APPINFO =35; //Application information
|
|
KERN_PROC_SDK_VERSION =36; //SDK version of the executable file
|
|
KERN_PROC_IDTABLE =37; //ID table information
|
|
|
|
KERN_PROC_SANITIZER =41; //kern_sanitizer (Sanitizing mode)
|
|
KERN_PROC_PTC =43; //Process time counter (value at program start)
|
|
KERN_PROC_TEXT_SEGMENT=44; //kern_dynlib_get_libkernel_text_segment
|
|
|
|
//KERN_SMP subtypes
|
|
KERN_CPUS=$100; //(OID_AUTO) Number of CPUs online
|
|
|
|
//KERN_SCHED subtypes
|
|
KERN_SCHED_CPUSETSIZE=$100; //(OID_AUTO) sizeof(cpuset_t)
|
|
|
|
//CTL_HW identifiers
|
|
HW_MACHINE = 1; // string: machine class
|
|
HW_MODEL = 2; // string: specific machine model
|
|
HW_NCPU = 3; // int: number of cpus
|
|
HW_BYTEORDER = 4; // int: machine byte order
|
|
HW_PHYSMEM = 5; // int: total memory
|
|
HW_USERMEM = 6; // int: non-kernel memory
|
|
HW_PAGESIZE = 7; // int: software page size
|
|
HW_DISKNAMES = 8; // strings: disk drive names
|
|
HW_DISKSTATS = 9; // struct: diskstats[]
|
|
HW_FLOATINGPT =10; // int: has HW floating point?
|
|
HW_MACHINE_ARCH=11; // string: machine architecture
|
|
HW_REALMEM =12; // int: 'real' memory
|
|
HW_MAXID =13; // number of valid hw ids
|
|
|
|
//MACHDEP subtypes
|
|
MACHDEP_TSC_FREQ=$100; //(OID_AUTO) Time Stamp Counter frequency
|
|
|
|
//KERN_VM_PS4DEV subtypes
|
|
KERN_VM_PS4DEV_TRCMEM_TOTAL=$100; //(OID_AUTO) trace memory total
|
|
KERN_VM_PS4DEV_TRCMEM_AVAIL=$101; //(OID_AUTO) trace memory available
|
|
|
|
//SYSCTL_HANDLER_ARGS oidp:p_sysctl_oid;arg1:Pointer;arg2:ptrint;req:p_sysctl_req
|
|
|
|
type
|
|
p_sysctl_req=^t_sysctl_req;
|
|
|
|
t_sysctl_func=function(req:p_sysctl_req;p:Pointer;s:QWORD):Integer;
|
|
|
|
t_sysctl_req=record
|
|
td :Pointer; //p_kthread
|
|
lock :Integer;
|
|
oldptr :Pointer;
|
|
oldlen :QWORD;
|
|
oldidx :QWORD;
|
|
oldfunc :t_sysctl_func;
|
|
newptr :Pointer;
|
|
newlen :QWORD;
|
|
newidx :QWORD;
|
|
newfunc :t_sysctl_func;
|
|
validlen:QWORD;
|
|
flags :Integer;
|
|
end;
|
|
|
|
p_sysctl_oid=^t_sysctl_oid;
|
|
|
|
t_oid_handler=function(oidp:p_sysctl_oid;arg1:Pointer;arg2:ptrint;req:p_sysctl_req):Integer;
|
|
|
|
t_sysctl_oid=record
|
|
oid_arg1 :Pointer;
|
|
oid_arg2 :Integer;
|
|
oid_kind :DWORD;
|
|
oid_name :PInteger;
|
|
oid_handler:t_oid_handler;
|
|
end;
|
|
|
|
function sys___sysctl(name :PInteger;
|
|
namelen:DWORD;
|
|
old :Pointer;
|
|
oldlenp:PQWORD;
|
|
new :Pointer;
|
|
newlen :QWORD):Integer;
|
|
|
|
procedure sysctl_register_all(); //SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_register_all, 0);
|
|
|
|
implementation
|
|
|
|
uses
|
|
errno,
|
|
systm,
|
|
vfile,
|
|
vmparam,
|
|
vm_map,
|
|
kern_thr,
|
|
kern_sx,
|
|
time,
|
|
md_arc4random,
|
|
md_proc;
|
|
|
|
var
|
|
sysctllock :t_sx;
|
|
sysctlmemlock:t_sx;
|
|
|
|
procedure sysctl_register_all();
|
|
begin
|
|
sx_init(@sysctlmemlock, 'sysctl mem');
|
|
sx_init(@sysctllock , 'sysctl lock');
|
|
end;
|
|
|
|
procedure SYSCTL_XLOCK(); inline;
|
|
begin
|
|
sx_xlock(@sysctllock)
|
|
end;
|
|
|
|
procedure SYSCTL_XUNLOCK(); inline;
|
|
begin
|
|
sx_xunlock(@sysctllock);
|
|
end;
|
|
|
|
procedure SYSCTL_ASSERT_XLOCKED(); inline;
|
|
begin
|
|
sx_assert(@sysctllock)
|
|
end;
|
|
|
|
function SYSCTL_IN(req:p_sysctl_req;p:Pointer;s:QWORD):Integer; inline;
|
|
begin
|
|
Result:=req^.newfunc(req,p,s);
|
|
end;
|
|
|
|
function SYSCTL_OUT(req:p_sysctl_req;p:Pointer;s:QWORD):Integer; inline;
|
|
begin
|
|
Result:=req^.oldfunc(req,p,s);
|
|
end;
|
|
|
|
function SYSCTL_HANDLE(noid:p_sysctl_oid;
|
|
name:PInteger;
|
|
kind:DWORD;
|
|
func:Pointer):Integer; inline;
|
|
begin
|
|
noid^.oid_name :=name+1;
|
|
noid^.oid_kind :=kind;
|
|
noid^.oid_arg1 :=nil;
|
|
noid^.oid_arg2 :=0;
|
|
noid^.oid_handler:=t_oid_handler(func);
|
|
Result:=0
|
|
end;
|
|
|
|
function SYSCTL_HANDLE(noid:p_sysctl_oid;
|
|
name:PInteger;
|
|
kind:DWORD;
|
|
arg1:Pointer;
|
|
func:Pointer):Integer; inline;
|
|
begin
|
|
noid^.oid_name :=name+1;
|
|
noid^.oid_kind :=kind;
|
|
noid^.oid_arg1 :=arg1;
|
|
noid^.oid_arg2 :=0;
|
|
noid^.oid_handler:=t_oid_handler(func);
|
|
Result:=0
|
|
end;
|
|
|
|
function SYSCTL_HANDLE(noid:p_sysctl_oid;
|
|
name:PInteger;
|
|
kind:DWORD;
|
|
arg2:Integer;
|
|
func:Pointer):Integer; inline;
|
|
begin
|
|
noid^.oid_name :=name+1;
|
|
noid^.oid_kind :=kind;
|
|
noid^.oid_arg1 :=nil;
|
|
noid^.oid_arg2 :=arg2;
|
|
noid^.oid_handler:=t_oid_handler(func);
|
|
Result:=0
|
|
end;
|
|
|
|
function SYSCTL_HANDLE(noid:p_sysctl_oid;
|
|
name:PInteger;
|
|
kind:DWORD;
|
|
arg1:Pointer;
|
|
arg2:Integer;
|
|
func:Pointer):Integer; inline;
|
|
begin
|
|
noid^.oid_name :=name+1;
|
|
noid^.oid_kind :=kind;
|
|
noid^.oid_arg1 :=arg1;
|
|
noid^.oid_arg2 :=arg2;
|
|
noid^.oid_handler:=t_oid_handler(func);
|
|
Result:=0
|
|
end;
|
|
|
|
//Transfer function to/from user space.
|
|
function sysctl_old_user(req:p_sysctl_req;p:Pointer;l:QWORD):Integer;
|
|
var
|
|
i,len,origidx:QWORD;
|
|
error:Integer;
|
|
begin
|
|
origidx:=req^.oldidx;
|
|
Inc(req^.oldidx,l);
|
|
|
|
if (req^.oldptr=nil) then
|
|
begin
|
|
Exit(0);
|
|
end;
|
|
|
|
i:=l;
|
|
len:=req^.validlen;
|
|
if (len <= origidx) then
|
|
begin
|
|
i:=0;
|
|
end else
|
|
begin
|
|
if (i > len - origidx) then
|
|
begin
|
|
i:=len - origidx;
|
|
end;
|
|
//if (req^.lock=REQ_WIRED) then
|
|
//begin
|
|
// error:=copyout_nofault(p, req^.oldptr + origidx, i);
|
|
//end else
|
|
begin
|
|
error:=copyout(p, req^.oldptr + origidx, i);
|
|
end;
|
|
if (error<>0) then
|
|
begin
|
|
Exit(error);
|
|
end;
|
|
end;
|
|
if (i < l) then
|
|
begin
|
|
Exit(ENOMEM);
|
|
end;
|
|
Exit(0);
|
|
end;
|
|
|
|
function sysctl_new_user(req:p_sysctl_req;p:Pointer;l:QWORD):Integer;
|
|
var
|
|
error:Integer;
|
|
begin
|
|
if (req^.newptr=nil) then
|
|
begin
|
|
Exit(0);
|
|
end;
|
|
|
|
if ((req^.newlen - req^.newidx) < l) then
|
|
begin
|
|
Exit(EINVAL);
|
|
end;
|
|
|
|
error:=copyin(req^.newptr + req^.newidx, p, l);
|
|
|
|
Inc(req^.newidx,l);
|
|
Exit(error);
|
|
end;
|
|
|
|
//Exit(ENOTDIR);
|
|
//Exit(ENOENT);
|
|
|
|
function sysctl_kern_proc_idtable(oidp:p_sysctl_oid;arg1:Pointer;arg2:ptrint;req:p_sysctl_req):Integer;
|
|
begin
|
|
//get idtable key count
|
|
Exit(ENOENT); //sceSblACMgrIsSystemUcred
|
|
end;
|
|
|
|
function sysctl_kern_usrstack(oidp:p_sysctl_oid;arg1:Pointer;arg2:ptrint;req:p_sysctl_req):Integer;
|
|
begin
|
|
Result:=SYSCTL_OUT(req,@g_vmspace.sv_usrstack,SizeOf(Pointer));
|
|
end;
|
|
|
|
function sysctl_kern_arandom(oidp:p_sysctl_oid;arg1:Pointer;arg2:ptrint;req:p_sysctl_req):Integer;
|
|
var
|
|
len:Integer;
|
|
data:array[0..254] of Byte;
|
|
begin
|
|
len:=256;
|
|
if (req^.oldlen < 256) then
|
|
begin
|
|
len:=req^.oldlen;
|
|
end;
|
|
|
|
arc4rand(@data,len,0);
|
|
|
|
Result:=SYSCTL_OUT(req,@data,len);
|
|
end;
|
|
|
|
const
|
|
//eLoadOptions
|
|
LOAD_OPTIONS_DEFAULT =$0000;
|
|
LOAD_OPTIONS_LOAD_SUSPENDED =$0001;
|
|
LOAD_OPTIONS_USE_SYSTEM_LIBRARY_VERIFICATION =$0002;
|
|
LOAD_OPTIONS_SLV_MODE_WARN =$0004;
|
|
LOAD_OPTIONS_ARG_STACK_SIZE =$0008;
|
|
LOAD_OPTIONS_FULL_DEBUG_REQUIRED =$0010;
|
|
|
|
//mmap_flags
|
|
//bit 1 -> is_big_app
|
|
//bit 2 -> first find addr is (1 shl 33) ->
|
|
// _sceKernelMapFlexibleMemory
|
|
// _sceKernelMapDirectMemory
|
|
// sceKernelMapDirectMemory2
|
|
|
|
//excp_flags
|
|
//bit 1 -> use in [libkernel_exception] ->
|
|
// -> sceKernelInstallExceptionHandler
|
|
// -> sceKernelRemoveExceptionHandler
|
|
// -> sceKernelAddGpuExceptionEvent
|
|
// -> sceKernelDeleteGpuExceptionEvent
|
|
// -> sceKernelBacktraceSelf
|
|
//bit 2 -> sys_mdbg_service
|
|
|
|
type
|
|
TCUSANAME=array[0..9] of AnsiChar;
|
|
|
|
PSCE_APP_ENV=^TSCE_APP_ENV;
|
|
TSCE_APP_ENV=packed record
|
|
AppId :Integer; //4
|
|
mmap_flags :Integer; //4
|
|
excp_flags :Integer; //4
|
|
AppType :Integer; //4 5?
|
|
CUSANAME :TCUSANAME; //10
|
|
debug_level:Byte; //1
|
|
slv_flags :Byte; //1 eLoadOptions
|
|
f_1c :Byte;
|
|
f_1d :Byte;
|
|
f_1e :Byte;
|
|
f_1f :Byte;
|
|
f_20 :QWORD;
|
|
f_28 :Integer;
|
|
f_2c :Integer;
|
|
f_30 :Integer;
|
|
f_34 :Integer;
|
|
f_38 :QWORD;
|
|
f_40 :QWORD;
|
|
end;
|
|
{$IF sizeof(TSCE_APP_ENV)<>72}{$STOP sizeof(TSCE_APP_ENV)<>72}{$ENDIF}
|
|
|
|
var
|
|
G_APPINFO:TSCE_APP_ENV;
|
|
|
|
function sysctl_kern_proc_appinfo(oidp:p_sysctl_oid;arg1:Pointer;arg2:ptrint;req:p_sysctl_req):Integer;
|
|
var
|
|
pid:Integer;
|
|
|
|
APPINFO:TSCE_APP_ENV;
|
|
begin
|
|
if (req^.oldlen > 72) then Exit(EINVAL);
|
|
|
|
pid:=PInteger(arg1)^;
|
|
|
|
if (pid<>g_pid) then Exit(EINVAL);
|
|
|
|
//G_APPINFO.mmap_flags:=G_APPINFO.mmap_flags or 1;
|
|
if (p_proc.p_sce_replay_exec<>0) then
|
|
begin
|
|
G_APPINFO.mmap_flags:=G_APPINFO.mmap_flags or 2;
|
|
end;
|
|
|
|
//sceSblACMgrIsSystemUcred()!=0 -> any proc
|
|
//sceSblACMgrIsSystemUcred()==0 -> cur proc
|
|
|
|
Result:=SYSCTL_OUT(req,@G_APPINFO,SizeOf(TSCE_APP_ENV));
|
|
|
|
if (Result=0) and (req^.newlen=SizeOf(TSCE_APP_ENV)) then
|
|
begin
|
|
Result:=SYSCTL_IN(req,@APPINFO,SizeOf(TSCE_APP_ENV));
|
|
if (Result=0) then
|
|
begin
|
|
G_APPINFO:=APPINFO;
|
|
if (p_proc.p_sce_replay_exec<>0) then
|
|
begin
|
|
G_APPINFO.mmap_flags:=G_APPINFO.mmap_flags or 2;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
|
|
function sysctl_kern_proc_sanitizer(oidp:p_sysctl_oid;arg1:Pointer;arg2:ptrint;req:p_sysctl_req):Integer;
|
|
var
|
|
Sanitizer:Integer;
|
|
begin
|
|
Sanitizer:=0;
|
|
Result:=SYSCTL_OUT(req,@Sanitizer,SizeOf(Integer));
|
|
end;
|
|
|
|
function sysctl_kern_proc_ptc(oidp:p_sysctl_oid;arg1:Pointer;arg2:ptrint;req:p_sysctl_req):Integer;
|
|
begin
|
|
Result:=SYSCTL_OUT(req,@p_proc.p_ptc,SizeOf(Int64));
|
|
end;
|
|
|
|
function sysctl_handle_int(oidp:p_sysctl_oid;arg1:Pointer;arg2:ptrint;req:p_sysctl_req):Integer;
|
|
var
|
|
tmpout:Integer;
|
|
begin
|
|
if (arg1<>nil) then
|
|
begin
|
|
tmpout:=PInteger(arg1)^;
|
|
end else
|
|
begin
|
|
tmpout:=arg2;
|
|
end;
|
|
|
|
Result:=SYSCTL_OUT(req,@tmpout,SizeOf(Integer));
|
|
|
|
if (Result<>0) or (req^.newptr=nil) then Exit;
|
|
|
|
if (arg1=nil) then Exit(EPERM);
|
|
|
|
Result:=SYSCTL_IN(req, arg1, sizeof(Integer));
|
|
end;
|
|
|
|
function sysctl_handle_64(oidp:p_sysctl_oid;arg1:Pointer;arg2:ptrint;req:p_sysctl_req):Integer;
|
|
var
|
|
tmpout:QWORD;
|
|
begin
|
|
if (arg1=nil) then
|
|
begin
|
|
Exit(EINVAL);
|
|
end;
|
|
|
|
tmpout:=PInteger(arg1)^;
|
|
|
|
Result:=SYSCTL_OUT(req,@tmpout,SizeOf(QWORD));
|
|
|
|
if (Result<>0) or (req^.newptr=nil) then Exit;
|
|
|
|
if (arg1=nil) then Exit(EPERM);
|
|
|
|
Result:=SYSCTL_IN(req, arg1, sizeof(QWORD));
|
|
end;
|
|
|
|
function name2oid(name:pchar;oid,len:PInteger):Integer;
|
|
begin
|
|
Result:=0;
|
|
|
|
case RawByteString(name) of
|
|
'kern.smp.cpus':
|
|
begin
|
|
oid[0]:=CTL_KERN;
|
|
oid[1]:=KERN_SMP;
|
|
oid[2]:=KERN_CPUS;
|
|
len^ :=3;
|
|
end;
|
|
'kern.proc.ptc':
|
|
begin
|
|
oid[0]:=CTL_KERN;
|
|
oid[1]:=KERN_PROC;
|
|
oid[2]:=KERN_PROC_PTC;
|
|
len^ :=3;
|
|
end;
|
|
'kern.sched.cpusetsize':
|
|
begin
|
|
oid[0]:=CTL_KERN;
|
|
oid[1]:=KERN_SCHED;
|
|
oid[2]:=KERN_SCHED_CPUSETSIZE;
|
|
len^ :=3;
|
|
end;
|
|
'machdep.tsc_freq':
|
|
begin
|
|
oid[0]:=CTL_MACHDEP;
|
|
oid[1]:=MACHDEP_TSC_FREQ;
|
|
len^ :=2;
|
|
end;
|
|
'vm.ps4dev.trcmem_total':
|
|
begin
|
|
oid[0]:=CTL_VM;
|
|
oid[1]:=KERN_VM_PS4DEV;
|
|
oid[2]:=KERN_VM_PS4DEV_TRCMEM_TOTAL;
|
|
len^ :=3;
|
|
end;
|
|
'vm.ps4dev.trcmem_avail':
|
|
begin
|
|
oid[0]:=CTL_VM;
|
|
oid[1]:=KERN_VM_PS4DEV;
|
|
oid[2]:=KERN_VM_PS4DEV_TRCMEM_AVAIL;
|
|
len^ :=3;
|
|
end;
|
|
|
|
else
|
|
Writeln(StdErr,'Unhandled name2oid:',name);
|
|
Assert(False);
|
|
Result:=ENOENT;
|
|
end;
|
|
end;
|
|
|
|
function sysctl_sysctl_name2oid(oidp:p_sysctl_oid;arg1:Pointer;arg2:ptrint;req:p_sysctl_req):Integer;
|
|
var
|
|
new:array[0..MAXPATHLEN] of AnsiChar;
|
|
oid:array[0..CTL_MAXNAME-1] of Integer;
|
|
len:Integer;
|
|
begin
|
|
if (req^.newlen=0) then Exit(ENOENT);
|
|
|
|
if (req^.newlen >= MAXPATHLEN) then Exit(ENAMETOOLONG);
|
|
|
|
FillChar(new,SizeOf(new),0);
|
|
|
|
Result:=SYSCTL_IN(req, @new, req^.newlen);
|
|
if (Result<>0) then Exit;
|
|
|
|
Result:=name2oid(@new, @oid, @len);
|
|
if (Result<>0) then Exit;
|
|
|
|
Result:=SYSCTL_OUT(req, @oid, len*sizeof(Integer));
|
|
end;
|
|
|
|
function sysctl_kern_proc(name:PInteger;namelen:DWORD;noid:p_sysctl_oid;req:p_sysctl_req):Integer;
|
|
begin
|
|
if (namelen=0) then Exit(ENOTDIR);
|
|
Result:=ENOENT;
|
|
|
|
case name[0] of
|
|
KERN_PROC_APPINFO :Result:=SYSCTL_HANDLE(noid,name,$C0040001,@sysctl_kern_proc_appinfo);
|
|
KERN_PROC_SANITIZER:Result:=SYSCTL_HANDLE(noid,name,$80040001,@sysctl_kern_proc_sanitizer);
|
|
KERN_PROC_PTC :Result:=SYSCTL_HANDLE(noid,name,$90040009,@sysctl_kern_proc_ptc);
|
|
else
|
|
begin
|
|
Writeln(StdErr,'Unhandled sysctl_kern_proc:',name[0]);
|
|
Assert(False);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function sysctl_kern_smp(name:PInteger;namelen:DWORD;noid:p_sysctl_oid;req:p_sysctl_req):Integer;
|
|
const
|
|
smp_cpus=8;
|
|
begin
|
|
if (namelen=0) then Exit(ENOTDIR);
|
|
Result:=ENOENT;
|
|
|
|
case name[0] of
|
|
KERN_CPUS:Result:=SYSCTL_HANDLE(noid,name,$80048002,smp_cpus,@sysctl_handle_int);
|
|
|
|
else
|
|
begin
|
|
Writeln(StdErr,'Unhandled sysctl_kern_smp:',name[0]);
|
|
Assert(False);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function sysctl_kern_sched(name:PInteger;namelen:DWORD;noid:p_sysctl_oid;req:p_sysctl_req):Integer;
|
|
begin
|
|
if (namelen=0) then Exit(ENOTDIR);
|
|
Result:=ENOENT;
|
|
|
|
case name[0] of
|
|
KERN_SCHED_CPUSETSIZE:Result:=SYSCTL_HANDLE(noid,name,$80040002,8,@sysctl_handle_int);
|
|
|
|
else
|
|
begin
|
|
Writeln(StdErr,'Unhandled sysctl_kern_sched:',name[0]);
|
|
Assert(False);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function sysctl_kern(name:PInteger;namelen:DWORD;noid:p_sysctl_oid;req:p_sysctl_req):Integer;
|
|
begin
|
|
if (namelen=0) then Exit(ENOTDIR);
|
|
Result:=ENOENT;
|
|
|
|
case name[0] of
|
|
KERN_PROC :Result:=sysctl_kern_proc(name+1,namelen-1,noid,req);
|
|
|
|
KERN_USRSTACK:Result:=SYSCTL_HANDLE(noid,name,$80008008,@sysctl_kern_usrstack);
|
|
KERN_ARND :Result:=SYSCTL_HANDLE(noid,name,$80048005,@sysctl_kern_arandom);
|
|
|
|
KERN_SMP :Result:=sysctl_kern_smp (name+1,namelen-1,noid,req);
|
|
KERN_SCHED :Result:=sysctl_kern_sched(name+1,namelen-1,noid,req);
|
|
else
|
|
begin
|
|
Writeln(StdErr,'Unhandled sysctl_kern:',name[0]);
|
|
Assert(False);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function sysctl_sysctl(name:PInteger;namelen:DWORD;noid:p_sysctl_oid;req:p_sysctl_req):Integer;
|
|
begin
|
|
if (namelen=0) then Exit(ENOTDIR);
|
|
Result:=ENOENT;
|
|
|
|
case name[0] of
|
|
3:Result:=SYSCTL_HANDLE(noid,name,$D004C002,@sysctl_sysctl_name2oid);
|
|
|
|
else
|
|
begin
|
|
Writeln(StdErr,'Unhandled sysctl_sysctl:',name[0]);
|
|
Assert(False);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function sysctl_hw(name:PInteger;namelen:DWORD;noid:p_sysctl_oid;req:p_sysctl_req):Integer;
|
|
begin
|
|
if (namelen=0) then Exit(ENOTDIR);
|
|
Result:=ENOENT;
|
|
|
|
case name[0] of
|
|
HW_PAGESIZE:Result:=SYSCTL_HANDLE(noid,name,$80048002,PAGE_SIZE,@sysctl_handle_int);
|
|
|
|
else
|
|
begin
|
|
Writeln(StdErr,'Unhandled sysctl_hw:',name[0]);
|
|
Assert(False);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function sysctl_machdep_tsc_freq(oidp:p_sysctl_oid;arg1:Pointer;arg2:ptrint;req:p_sysctl_req):Integer;
|
|
var
|
|
freq:QWORD;
|
|
begin
|
|
freq:=System.InterlockedExchangeAdd64(tsc_freq,0);
|
|
if (freq=0) then Exit(EOPNOTSUPP);
|
|
|
|
Result:=sysctl_handle_64(oidp, @freq, 0, req);
|
|
if (Result=0) and (req^.newptr<>nil) then
|
|
begin
|
|
System.InterlockedExchange64(tsc_freq,freq);
|
|
end;
|
|
end;
|
|
|
|
function sysctl_machdep(name:PInteger;namelen:DWORD;noid:p_sysctl_oid;req:p_sysctl_req):Integer;
|
|
begin
|
|
if (namelen=0) then Exit(ENOTDIR);
|
|
Result:=ENOENT;
|
|
|
|
case name[0] of
|
|
MACHDEP_TSC_FREQ:Result:=SYSCTL_HANDLE(noid,name,$C0000009,@sysctl_machdep_tsc_freq);
|
|
|
|
else
|
|
begin
|
|
Writeln(StdErr,'Unhandled sysctl_machdep:',name[0]);
|
|
Assert(False);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function sysctl_find_oid(name :PInteger;
|
|
namelen:DWORD;
|
|
noid :p_sysctl_oid;
|
|
req :p_sysctl_req):Integer;
|
|
begin
|
|
if (namelen=0) then Exit(ENOENT);
|
|
Result:=ENOENT;
|
|
|
|
case name[0] of
|
|
CTL_UNSPEC :Result:=sysctl_sysctl (name+1,namelen-1,noid,req);
|
|
CTL_KERN :Result:=sysctl_kern (name+1,namelen-1,noid,req);
|
|
CTL_HW :Result:=sysctl_hw (name+1,namelen-1,noid,req);
|
|
CTL_MACHDEP:Result:=sysctl_machdep(name+1,namelen-1,noid,req);
|
|
else
|
|
begin
|
|
Writeln(StdErr,'Unhandled sysctl_root:',name[0]);
|
|
Assert(False);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function sysctl_root(oidp:p_sysctl_oid;
|
|
arg1:PInteger;
|
|
arg2:DWORD;
|
|
req :p_sysctl_req):Integer;
|
|
var
|
|
oid:t_sysctl_oid;
|
|
indx:Integer;
|
|
begin
|
|
oid:=Default(t_sysctl_oid);
|
|
|
|
Result:=sysctl_find_oid(arg1, arg2, @oid, req);
|
|
if (Result<>0) then Exit;
|
|
|
|
if (oid.oid_handler=nil) then Exit(EINVAL);
|
|
if (oid.oid_name =nil) then Exit(EINVAL);
|
|
|
|
// Is this sysctl writable?
|
|
if (req^.newptr<>nil) and ((oid.oid_kind and CTLFLAG_WR)=0) then
|
|
begin
|
|
Exit(EPERM);
|
|
end;
|
|
|
|
// Is this sysctl writable by only privileged users?
|
|
if (req^.newptr<>nil) and ((oid.oid_kind and CTLFLAG_ANYBODY)=0) then
|
|
begin
|
|
//if (oid^.oid_kind and CTLFLAG_PRISON)
|
|
// priv:=PRIV_SYSCTL_WRITEJAIL;
|
|
//else
|
|
// priv:=PRIV_SYSCTL_WRITE;
|
|
//
|
|
//error:=priv_check(req^.td, priv);
|
|
//
|
|
//if (error<>0) then Ext(error);
|
|
|
|
Exit(EPERM);
|
|
end;
|
|
|
|
indx:=oid.oid_name-arg1;
|
|
|
|
if ((oid.oid_kind and CTLTYPE)=CTLTYPE_NODE) then
|
|
begin
|
|
arg1:=arg1 + indx;
|
|
arg2:=arg2 - indx;
|
|
end else
|
|
begin
|
|
arg1:=oid.oid_arg1;
|
|
arg2:=oid.oid_arg2;
|
|
end;
|
|
|
|
Result:=oid.oid_handler(@oid, arg1, arg2, req);
|
|
|
|
end;
|
|
|
|
function userland_sysctl(name :PInteger;
|
|
namelen :DWORD;
|
|
old :Pointer;
|
|
oldlenp :PQWORD;
|
|
inkernel:Integer;
|
|
new :Pointer;
|
|
newlen :QWORD;
|
|
retval :PQWORD;
|
|
flags :Integer):Integer;
|
|
var
|
|
error,memlocked:Integer;
|
|
req:t_sysctl_req;
|
|
begin
|
|
error:=0;
|
|
|
|
req:=Default(t_sysctl_req);
|
|
|
|
req.td :=curkthread;
|
|
req.flags:=flags;
|
|
|
|
if (oldlenp<>nil) then
|
|
begin
|
|
if (inkernel<>0) then
|
|
begin
|
|
req.oldlen:=oldlenp^;
|
|
end else
|
|
begin
|
|
error:=copyin(oldlenp, @req.oldlen, sizeof(Pointer));
|
|
if (error<>0) then Exit(error);
|
|
end;
|
|
end;
|
|
req.validlen:=req.oldlen;
|
|
|
|
if (old<>nil) then
|
|
begin
|
|
//if (!useracc(old, req.oldlen, VM_PROT_WRITE))
|
|
// Exit(EFAULT);
|
|
req.oldptr:=old;
|
|
end;
|
|
|
|
if (new<>nil) then
|
|
begin
|
|
//if (!useracc(new, newlen, VM_PROT_READ))
|
|
// Exit(EFAULT);
|
|
req.newlen:=newlen;
|
|
req.newptr:=new;
|
|
end;
|
|
|
|
req.oldfunc:=@sysctl_old_user;
|
|
req.newfunc:=@sysctl_new_user;
|
|
//req.lock:=REQ_UNWIRED;
|
|
|
|
if (req.oldlen > PAGE_SIZE) then
|
|
begin
|
|
memlocked:=1;
|
|
sx_xlock(@sysctlmemlock);
|
|
end else
|
|
begin
|
|
memlocked:=0;
|
|
end;
|
|
|
|
repeat
|
|
req.oldidx:=0;
|
|
req.newidx:=0;
|
|
SYSCTL_XLOCK();
|
|
error:=sysctl_root(nil, name, namelen, @req);
|
|
SYSCTL_XUNLOCK();
|
|
if (error<>EAGAIN) then
|
|
begin
|
|
break;
|
|
end;
|
|
//kern_yield(PRI_USER);
|
|
until false;
|
|
|
|
//if (req.lock=REQ_WIRED) and (req.validlen > 0) then
|
|
//begin
|
|
// vsunlock(req.oldptr, req.validlen);
|
|
//end;
|
|
|
|
if (memlocked<>0) then
|
|
begin
|
|
sx_xunlock(@sysctlmemlock);
|
|
end;
|
|
|
|
if (error<>0) and (error<>ENOMEM) then
|
|
begin
|
|
Exit(error);
|
|
end;
|
|
|
|
if (retval<>nil) then
|
|
begin
|
|
if (req.oldptr<>nil) and (req.oldidx > req.validlen) then
|
|
retval^:=req.validlen
|
|
else
|
|
retval^:=req.oldidx;
|
|
end;
|
|
Exit(error);
|
|
end;
|
|
|
|
function sys___sysctl(name :PInteger;
|
|
namelen:DWORD;
|
|
old :Pointer;
|
|
oldlenp:PQWORD;
|
|
new :Pointer;
|
|
newlen :QWORD):Integer;
|
|
var
|
|
error,i:Integer;
|
|
_name:array[0..CTL_MAXNAME-1] of Integer;
|
|
j:QWORD;
|
|
begin
|
|
if (namelen > CTL_MAXNAME) or (namelen < 2) then
|
|
begin
|
|
Exit(EINVAL);
|
|
end;
|
|
|
|
error:=copyin(name, @_name, namelen * sizeof(Integer));
|
|
if (error<>0) then Exit(error);
|
|
|
|
error:=userland_sysctl(@_name,
|
|
namelen,
|
|
old,
|
|
oldlenp,
|
|
0,
|
|
new,
|
|
newlen,
|
|
@j,
|
|
0);
|
|
|
|
if (error<>0) and (error<>ENOMEM) then
|
|
begin
|
|
Exit(error);
|
|
end;
|
|
|
|
if (oldlenp<>nil) then
|
|
begin
|
|
i:=copyout(@j, oldlenp, sizeof(j));
|
|
if (i<>0) then
|
|
begin
|
|
Exit(i);
|
|
end;
|
|
end;
|
|
|
|
Exit(error);
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
end.
|
|
|