FPPS4/sys/kern/kern_sysctl.pas

1150 lines
27 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_SDKVERSION=38; //SDK version
KERN_FSST_PARAM=40; //file system service threads (FSST)
KERN_CPUMODE =41;
KERN_RNG_PSEUDO=47;
KERN_SMP =$485; //(OID_AUTO) Kernel SMP
KERN_SCHED =$2A0; //(OID_AUTO) Scheduler
KERN_NEOMODE =$50F; //(OID_AUTO) Neo mode
//CTL_VM subtypes
KERN_VM_PS4DEV=1; //vm parameters for PS4 (DevKit only)
KERN_VM_BUDGETS=$139; //(OID_AUTO) VM budgets
//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=$48A; //(OID_AUTO) Number of CPUs online
//KERN_SCHED subtypes
KERN_SCHED_CPUSETSIZE=$4E4; //(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 =$1EC; //(OID_AUTO) Time Stamp Counter frequency
MACHDEP_BOOTPARAMS =$14D; //(OID_AUTO) orbis bootparams
MACHDEP_CPUMODE_PLATFORM=$600; //(OID_AUTO) CPU mode platform (PS4/PS5)
//BOOTPARAMS subtypes
BOOTPARAMS_IS_MAIN_ON_STANDBY=$100; //(OID_AUTO) Is main on standby mode
BOOTPARAMS_BASE_PS4_MODE =$151; //(OID_AUTO) base ps4 mode
//KERN_VM_PS4DEV subtypes
KERN_VM_PS4DEV_TRCMEM_TOTAL=$23B; //(OID_AUTO) trace memory total
KERN_VM_PS4DEV_TRCMEM_AVAIL=$23C; //(OID_AUTO) trace memory available
//KERN_VM_BUDGETS
KERN_VM_BUDGETS_MLOCK_AVAIL=$13A; //(OID_AUTO) Available MLOCK budget
KERN_VM_BUDGETS_MLOCK_TOTAL=$13B; //(OID_AUTO) Total MLOCK budget
//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
sysutils,
errno,
systm,
vmparam,
vm_map,
kern_thr,
kern_sx,
time,
elf64,
subr_dynlib,
kern_authinfo,
md_arc4random,
sys_bootparam,
kern_proc,
md_proc,
kern_budget,
subr_backtrace;
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;
var
vms:p_vmspace;
begin
vms:=p_proc.p_vmspace;
Result:=SYSCTL_OUT(req,@vms^.sv_usrstack,SizeOf(Pointer));
end;
function sysctl_kern_arandom(oidp:p_sysctl_oid;arg1:Pointer;arg2:ptrint;req:p_sysctl_req):Integer;
type
t_data_256=array[0..255] of Byte;
var
len:Integer;
data:t_data_256;
begin
len:=256;
if (req^.oldlen < 256) then
begin
len:=req^.oldlen;
end;
data:=Default(t_data_256);
arc4rand(@data,len,0); //ASLR?
Result:=SYSCTL_OUT(req,@data,len);
end;
type
t_set_fsst_param=packed record
mask :QWORD;
prio :Integer;
align:Integer;
end;
function sysctl_kern_fsst_param(oidp:p_sysctl_oid;arg1:Pointer;arg2:ptrint;req:p_sysctl_req):Integer;
var
params:t_set_fsst_param;
begin
params:=Default(t_set_fsst_param);
Result:=SYSCTL_IN(req,@params,SizeOf(t_set_fsst_param));
if (Result<>0) then Exit;
if (params.prio<255) or
(params.prio>767) then
begin
Exit(EINVAL);
end;
if (params.mask=0) then
begin
Exit(EDEADLK);
end;
Exit(0);
end;
function sysctl_kern_rng_pseudo(oidp:p_sysctl_oid;arg1:Pointer;arg2:ptrint;req:p_sysctl_req):Integer;
type
t_data_64=array[0..63] of Byte;
var
data:t_data_64;
begin
data:=Default(t_data_64);
arc4rand(@data,64,0);
Result:=SYSCTL_OUT(req,@data,64);
end;
function sysctl_kern_proc_appinfo(oidp:p_sysctl_oid;arg1:Pointer;arg2:ptrint;req:p_sysctl_req):Integer;
var
pid:Integer;
flags:Integer;
appinfo:t_appinfo;
begin
if (req^.oldlen > 72) then Exit(EINVAL);
pid:=PInteger(arg1)^;
if (pid<>p_proc.p_pid) then Exit(EINVAL);
//sceSblACMgrIsSystemUcred()!=0 -> any proc
//sceSblACMgrIsSystemUcred()==0 -> cur proc
Result:=SYSCTL_OUT(req,@g_appinfo,SizeOf(t_appinfo));
if (Result=0) and (req^.newlen=SizeOf(t_appinfo)) then
begin
Result:=SYSCTL_IN(req,@appinfo,SizeOf(t_appinfo));
if (Result=0) then
begin
flags:=g_appinfo.mmap_flags;
g_appinfo:=appinfo;
g_appinfo.mmap_flags:=g_appinfo.mmap_flags or (flags and 2);
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));
//
if (Result=0) then
begin
//save a ptr to guest memory (libkernel) to modify later
//when the process resume (support in debug/pause?)
p_proc.p_guest_ptc:=req^.oldptr;
end;
end;
function _copy_libkernel_addr(req:p_sysctl_req):Integer;
var
addr_out:array[0..1] of Pointer;
begin
addr_out[0]:=p_proc.p_libkernel_start_addr;
addr_out[1]:=p_proc.p_libkernel___end_addr;
Result:=SYSCTL_OUT(req,@addr_out,SizeOf(addr_out));
end;
function sysctl_kern_text_segment(oidp:p_sysctl_oid;arg1:Pointer;arg2:ptrint;req:p_sysctl_req):Integer;
var
addr_out:array[0..1] of Pointer;
libc_param:TSceLibcParam;
sceLibcHeapDebugFlags:Integer;
begin
Result:=0;
addr_out[0]:=nil;
addr_out[1]:=nil;
if false then //sceSblACMgrIsShellcoreProces
//sceSblACMgrIsSystemUcred && sceRegMgrSrvGetQAFforReg && sceRegMgrGetInt(sys_heap_trace)
//sceSblACMgrIsWebcoreProcess && sceKernelIsDevelopmentMode
//sceRegMgrSrvGetQAFforReg && sceRegMgrGetInt(game_heap_trace)
//sceKernelIsDevelopmentMode && sceKernelIsAssistMode && sceRegMgrGetInt(game_intmem_dbg)
begin
Exit(_copy_libkernel_addr(req));
end;
Result:=copy_libc_param(@libc_param);
if (Result=0) then
if (libc_param.entry_count>8) then
begin
if (libc_param.SceLibcInternalHeap=1) then
begin
Result:=copyin(libc_param.sceLibcHeapDebugFlags,@sceLibcHeapDebugFlags,4);
if (Result=0) and ((sceLibcHeapDebugFlags and 8)<>0) then
begin
Exit(_copy_libkernel_addr(req));
end else
begin
Result:=0;
end;
end;
if (libc_param.entry_count > 11) and (libc_param.SceLibcInternalHeap=1) then
begin
Result:=copyin(libc_param.sceKernelInternalMemoryDebugFlags,@sceLibcHeapDebugFlags,4);
if (Result=0) and ((sceLibcHeapDebugFlags and 8)<>0) then
begin
Exit(_copy_libkernel_addr(req));
end else
begin
Result:=0;
end;
end;
end;
SYSCTL_OUT(req,@addr_out,SizeOf(addr_out));
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.sdk_version':
begin
oid[0]:=CTL_KERN;
oid[1]:=KERN_SDKVERSION;
len^ :=2;
end;
'kern.fsst_param':
begin
oid[0]:=CTL_KERN;
oid[1]:=KERN_FSST_PARAM;
len^ :=2;
end;
'kern.cpumode':
begin
oid[0]:=CTL_KERN;
oid[1]:=KERN_CPUMODE;
len^ :=2;
end;
'kern.rng_pseudo':
begin
oid[0]:=CTL_KERN;
oid[1]:=KERN_RNG_PSEUDO;
len^ :=2;
end;
'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;
'kern.neomode':
begin
oid[0]:=CTL_KERN;
oid[1]:=KERN_NEOMODE;
len^ :=2;
end;
'machdep.tsc_freq':
begin
oid[0]:=CTL_MACHDEP;
oid[1]:=MACHDEP_TSC_FREQ;
len^ :=2;
end;
'machdep.bootparams.base_ps4_mode':
begin
oid[0]:=CTL_MACHDEP;
oid[1]:=MACHDEP_BOOTPARAMS;
oid[2]:=BOOTPARAMS_BASE_PS4_MODE;
len^ :=3;
end;
'machdep.cpumode_platform':
begin
oid[0]:=CTL_MACHDEP;
oid[1]:=MACHDEP_CPUMODE_PLATFORM;
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;
'vm.budgets.mlock_avail':
begin
oid[0]:=CTL_VM;
oid[1]:=KERN_VM_BUDGETS;
oid[2]:=KERN_VM_BUDGETS_MLOCK_AVAIL;
len^ :=3;
end;
'vm.budgets.mlock_total':
begin
oid[0]:=CTL_VM;
oid[1]:=KERN_VM_BUDGETS;
oid[2]:=KERN_VM_BUDGETS_MLOCK_TOTAL;
len^ :=3;
end;
else
print_error_td('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;
type
t_path=array[0..MAXPATHLEN] of AnsiChar;
var
new:t_path;
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);
new:=Default(t_path);
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);
KERN_PROC_TEXT_SEGMENT:Result:=SYSCTL_HANDLE(noid,name,$80040001,@sysctl_kern_text_segment);
else
begin
print_error_td('Unhandled sysctl_kern_proc:'+IntToStr(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
print_error_td('Unhandled sysctl_kern_smp:'+IntToStr(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
print_error_td('Unhandled sysctl_kern_sched:'+IntToStr(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_SDKVERSION:Result:=SYSCTL_HANDLE(noid,name,$80048006,p_system_sdk_version,@sysctl_handle_int);
KERN_FSST_PARAM:Result:=SYSCTL_HANDLE(noid,name,$50040005,@sysctl_kern_fsst_param);
KERN_CPUMODE :Result:=SYSCTL_HANDLE(noid,name,$80040002,p_cpumode,@sysctl_handle_int);
KERN_RNG_PSEUDO:Result:=SYSCTL_HANDLE(noid,name,$80040005,@sysctl_kern_rng_pseudo);
KERN_SMP :Result:=sysctl_kern_smp (name+1,namelen-1,noid,req);
KERN_SCHED :Result:=sysctl_kern_sched(name+1,namelen-1,noid,req);
KERN_NEOMODE :Result:=SYSCTL_HANDLE(noid,name,$80040002,p_neomode,@sysctl_handle_int);
else
begin
print_error_td('Unhandled sysctl_kern:'+IntToStr(name[0]));
Assert(False);
end;
end;
end;
function sysctl_mlock_avail(oidp:p_sysctl_oid;arg1:Pointer;arg2:ptrint;req:p_sysctl_req):Integer;
var
val:QWORD;
begin
val:=get_mlock_avail;
Result:=SYSCTL_OUT(req,@val,SizeOf(QWORD));
end;
function sysctl_mlock_total(oidp:p_sysctl_oid;arg1:Pointer;arg2:ptrint;req:p_sysctl_req):Integer;
var
val:QWORD;
begin
val:=get_mlock_total;
Result:=SYSCTL_OUT(req,@val,SizeOf(QWORD));
end;
function sysctl_vm_budgets(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_VM_BUDGETS_MLOCK_AVAIL:Result:=SYSCTL_HANDLE(noid,name,$80000008,@sysctl_mlock_avail); //sceKernelAvailableFlexibleMemorySize
KERN_VM_BUDGETS_MLOCK_TOTAL:Result:=SYSCTL_HANDLE(noid,name,$80000008,@sysctl_mlock_total); //sceKernelConfiguredFlexibleMemorySize
else
begin
print_error_td('Unhandled sysctl_vm_budgets:'+IntToStr(name[0]));
Assert(False);
end;
end;
end;
function sysctl_vm(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_VM_BUDGETS:Result:=sysctl_vm_budgets(name+1,namelen-1,noid,req);
else
begin
print_error_td('Unhandled sysctl_vm:'+IntToStr(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
print_error_td('Unhandled sysctl_sysctl:'+IntToStr(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
print_error_td('Unhandled sysctl_hw:'+IntToStr(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_bootparams(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
BOOTPARAMS_BASE_PS4_MODE:Result:=SYSCTL_HANDLE(noid,name,$80040002,p_base_ps4_mode,@sysctl_handle_int);
else
begin
print_error_td('Unhandled sysctl_bootparams:'+IntToStr(name[0]));
Assert(False);
end;
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);
MACHDEP_BOOTPARAMS :Result:=sysctl_bootparams(name+1,namelen-1,noid,req);
MACHDEP_CPUMODE_PLATFORM:Result:=SYSCTL_HANDLE(noid,name,$80000002,0,@sysctl_handle_int);
else
begin
print_error_td('Unhandled sysctl_machdep:'+IntToStr(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_VM :Result:=sysctl_vm (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
print_error_td('Unhandled sysctl_root:'+IntToStr(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.