diff --git a/sys/kern/kern_patcher.pas b/sys/kern/kern_patcher.pas
index c56c8e2c..f38a8917 100644
--- a/sys/kern/kern_patcher.pas
+++ b/sys/kern/kern_patcher.pas
@@ -22,6 +22,7 @@ type
procedure add_patch_link (_obj,vaddr:Pointer;ptype:t_patch_type;stub:p_stub_chunk);
procedure free_patch_link(_obj:Pointer;node:p_patch_node);
+procedure vm_object_patch_remove(_obj:Pointer;start,__end:DWORD);
procedure patcher_process_section(_obj,data,vaddr:Pointer;filesz:QWORD);
@@ -32,6 +33,7 @@ uses
kern_rwlock,
kern_thr,
vm,
+ vmparam,
vm_map,
vm_mmap,
vm_object,
@@ -67,6 +69,33 @@ begin
FreeMem(node);
end;
+function OFF_TO_IDX(x:Pointer):DWORD; inline;
+begin
+ Result:=QWORD(x) shr PAGE_SHIFT;
+end;
+
+procedure vm_object_patch_remove(_obj:Pointer;start,__end:DWORD);
+var
+ obj:vm_object_t;
+ entry,next:p_patch_node;
+begin
+ obj:=_obj;
+
+ entry:=TAILQ_FIRST(@obj^.patchq);
+ while (entry<>nil) do
+ begin
+ next:=TAILQ_NEXT(entry,@entry^.link);
+ //
+ if ((start=0) or (OFF_TO_IDX(entry^.vaddr)>=start)) and
+ ((__end=0) or (OFF_TO_IDX(entry^.vaddr)<=__end)) then
+ begin
+ free_patch_link(_obj,entry);
+ end;
+ //
+ entry:=next;
+ end;
+end;
+
{
64 48 A1 [0000000000000000] mov rax,fs:[$0000000000000000] -> 65 48 A1 [0807000000000000] mov rax,gs:[$0000000000000708]
64 48 8B 04 25 [00000000] mov rax,fs:[$00000000] -> 65 48 8B 04 25 [08070000] mov rax,gs:[$00000708]
diff --git a/sys/kern/kern_reloc.pas b/sys/kern/kern_reloc.pas
index 923a66e3..4dce5609 100644
--- a/sys/kern/kern_reloc.pas
+++ b/sys/kern/kern_reloc.pas
@@ -443,6 +443,8 @@ end;
function relocate_one_object(obj:p_lib_info;jmpslots:Integer):Integer;
begin
+ Writeln(' relocate:',dynlib_basename(obj^.lib_path));
+
Result:=reloc_non_plt(obj);
if (Result<>0) then
begin
diff --git a/sys/kern/kern_rtld.pas b/sys/kern/kern_rtld.pas
index ebad31f9..40cd7b10 100644
--- a/sys/kern/kern_rtld.pas
+++ b/sys/kern/kern_rtld.pas
@@ -524,6 +524,19 @@ begin
end;
end;
+function get_char_sep(path:pchar):char; inline;
+const
+ c_host='/host/';
+begin
+ if (StrLComp(path,c_host,Length(c_host))=0) then
+ begin
+ Result:='\';
+ end else
+ begin
+ Result:='/';
+ end;
+end;
+
function rtld_dirname(path,bname:pchar):Integer;
var
endp:pchar;
@@ -539,13 +552,7 @@ begin
Exit(0);
end;
- if (StrLComp(path,'/host/',Length('/host/'))=0) then
- begin
- chr:='/';
- end else
- begin
- chr:='\';
- end;
+ chr:=get_char_sep(path);
{ Strip trailing slashes }
endp:=path + strlen(path) - 1;
@@ -1140,26 +1147,10 @@ begin
end;
function is_system_path(path:pchar):Boolean;
-var
- f:RawByteString;
begin
- f:='/'+p_proc.p_randomized_path;
- Result:=StrLComp(pchar(f),path,Length(f))=0;
-end;
-
-function is_libc_or_fios(path:pchar):Boolean;
-var
- f:RawByteString;
-begin
- f:=ExtractFileName(path);
- f:=ChangeFileExt(f,'');
- case f of
- 'libc',
- 'libSceFios2':
- Result:=True;
- else
- Result:=False;
- end;
+ if (path=nil) then Exit(False);
+ if (path[0]<>'/') then Exit(False);
+ Result:=StrLComp(p_proc.p_randomized_path,@path[1],Length(p_proc.p_randomized_path))=0;
end;
function dynlib_basename(path:pchar):pchar;
@@ -1167,13 +1158,7 @@ var
idx:pchar;
chr:char;
begin
- if (StrLComp(path,'/host/',Length('/host/'))=0) then
- begin
- chr:='/';
- end else
- begin
- chr:='\';
- end;
+ chr:=get_char_sep(path);
idx:=strrscan(path,chr);
if (idx=nil) then
@@ -1185,5 +1170,25 @@ begin
end;
end;
+function is_libc_or_fios(path:pchar):Boolean;
+const
+ c_libc='libc.';
+ c_libSceFios2='libSceFios2.';
+var
+ f:pchar;
+begin
+ f:=dynlib_basename(path);
+
+ if (StrLComp(f,c_libc,Length(c_libc))=0) or
+ (StrLComp(f,c_libSceFios2,Length(c_libSceFios2))=0) then
+ begin
+ Result:=True;
+ end else
+ begin
+ Result:=False;
+ end;
+end;
+
+
end.
diff --git a/sys/kern/kern_sysctl.pas b/sys/kern/kern_sysctl.pas
new file mode 100644
index 00000000..fdd1c193
--- /dev/null
+++ b/sys/kern/kern_sysctl.pas
@@ -0,0 +1,440 @@
+unit kern_sysctl;
+
+{$mode ObjFPC}{$H+}
+{$CALLING SysV_ABI_CDecl}
+
+interface
+
+
+const
+ CTL_MAXNAME=24; // largest number of components supported
+
+//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_ARND =37;
+
+//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_TEXT_SEGMENT=44; //kern_dynlib_get_libkernel_text_segment
+
+
+
+
+//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_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,
+ vmparam,
+ kern_thr,
+ kern_sx,
+ md_arc4random;
+
+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;func:Pointer):Integer; inline;
+begin
+ 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_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;
+
+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;
+
+ Writeln(StdErr,'sysctl_kern_proc:',name[0]);
+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_ARND:Result:=SYSCTL_HANDLE(noid,@sysctl_kern_arandom);
+ else
+ begin
+ Writeln(StdErr,'Unhandled sysctl_kern:',name[0]);
+ 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_KERN:Result:=sysctl_kern(name+1,namelen-1,noid,req);
+ else
+ begin
+ Writeln(StdErr,'Unhandled sysctl_find_oid:',name[0]);
+ end;
+ end;
+end;
+
+function sysctl_root(oidp:p_sysctl_oid;
+ arg1:PInteger;
+ arg2:DWORD;
+ req :p_sysctl_req):Integer;
+var
+ oid:t_sysctl_oid;
+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_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.
+
diff --git a/sys/kern/subr_dynlib.pas b/sys/kern/subr_dynlib.pas
index 4b057d52..ebdd4d0e 100644
--- a/sys/kern/subr_dynlib.pas
+++ b/sys/kern/subr_dynlib.pas
@@ -2044,6 +2044,8 @@ var
begin
Result:=nil;
+ Writeln(' do_load_object:',dynlib_basename(path));
+
new:=obj_new();
err:=self_load_shared_object(path,new,ord((flags and $20)<>0));
@@ -2158,6 +2160,8 @@ var
begin
Assert(root^.ref_count=0,'unload_object ref_count');
+ Writeln(' unload_object:',dynlib_basename(root^.lib_path));
+
{
* Pass over the DAG removing unreferenced objects from
* appropriate lists.
@@ -2225,7 +2229,7 @@ begin
begin
fname:='/'+fname;
end;
- fname:=p_proc.p_randomized_path+fname;
+ fname:='/'+p_proc.p_randomized_path+fname;
if rtld_file_exists(pchar(fname)) then goto _do_load;
diff --git a/sys/md/md_arc4random.pas b/sys/md/md_arc4random.pas
new file mode 100644
index 00000000..c084b592
--- /dev/null
+++ b/sys/md/md_arc4random.pas
@@ -0,0 +1,27 @@
+unit md_arc4random;
+
+{$mode ObjFPC}{$H+}
+{$CALLING SysV_ABI_CDecl}
+
+interface
+
+procedure arc4rand(ptr:Pointer;len,reseed:Integer);
+
+implementation
+
+const
+ BCRYPT_USE_SYSTEM_PREFERRED_RNG=2;
+
+function BCryptGenRandom(hAlgorithm:Pointer;
+ pbBuffer:PByte;
+ cbBuffer:DWORD;
+ dwFlags:DWORD):DWORD; stdcall; external 'Bcrypt';
+
+procedure arc4rand(ptr:Pointer;len,reseed:Integer);
+begin
+ BCryptGenRandom(nil,ptr,len,BCRYPT_USE_SYSTEM_PREFERRED_RNG);
+end;
+
+
+end.
+
diff --git a/sys/sys_sysinit.pas b/sys/sys_sysinit.pas
index cc14fb0e..f0f696b2 100644
--- a/sys/sys_sysinit.pas
+++ b/sys/sys_sysinit.pas
@@ -13,6 +13,7 @@ uses
time,
kern_time,
subr_sleepqueue,
+ kern_sysctl,
kern_thr,
kern_thread,
kern_sig,
@@ -74,6 +75,7 @@ procedure sys_init;
begin
timeinit;
init_sleepqueues;
+ sysctl_register_all;
PROC_INIT;
threadinit;
siginit;
diff --git a/sys/syscalls.pas b/sys/syscalls.pas
index cf84c8bb..3d0708be 100644
--- a/sys/syscalls.pas
+++ b/sys/syscalls.pas
@@ -90,6 +90,7 @@ function _fpathconf(fd,name:Integer):Integer;
function getrlimit(which:Integer;rlp:Pointer):Integer;
function setrlimit(which:Integer;rlp:Pointer):Integer;
function _getdirentries(fd:Integer;buf:Pointer;count:DWORD;basep:PInt64):Integer;
+function __sysctl(name:PInteger;namelen:DWORD;old:Pointer;oldlenp:PQWORD;new:Pointer;newlen:QWORD):Integer;
function futimes(fd:Integer;tptr:Pointer):Integer;
function getpgid(pid:Integer):Integer;
function poll(fds:Pointer;nfds:DWORD;timeout:Integer):Integer;
@@ -813,6 +814,13 @@ asm
jmp cerror
end;
+function __sysctl(name:PInteger;namelen:DWORD;old:Pointer;oldlenp:PQWORD;new:Pointer;newlen:QWORD):Integer; assembler; nostackframe;
+asm
+ movq $202,%rax
+ call fast_syscall
+ jmp cerror
+end;
+
function futimes(fd:Integer;tptr:Pointer):Integer; assembler; nostackframe;
asm
movq $206,%rax
diff --git a/sys/sysent.pas b/sys/sysent.pas
index d3dd405e..12d3484c 100644
--- a/sys/sysent.pas
+++ b/sys/sysent.pas
@@ -28,6 +28,7 @@ uses
kern_dynlib,
kern_ksched,
kern_rtprio,
+ kern_sysctl,
kern_thread,
sys_machdep,
kern_context,
@@ -1062,7 +1063,7 @@ const
),
(//[202]
sy_narg:6;
- sy_call:nil;
+ sy_call:@sys___sysctl;
sy_name:'sys___sysctl'
),
(//[203]
diff --git a/sys/test/project1.lpi b/sys/test/project1.lpi
index 49e81b43..5928abb9 100644
--- a/sys/test/project1.lpi
+++ b/sys/test/project1.lpi
@@ -597,6 +597,14 @@
+
+
+
+
+
+
+
+
diff --git a/sys/test/project1.lpr b/sys/test/project1.lpr
index a37c4c7f..95013c87 100644
--- a/sys/test/project1.lpr
+++ b/sys/test/project1.lpr
@@ -91,7 +91,8 @@ uses
kern_timeout,
kern_exec,
kern_dynlib,
- vmparam;
+ vmparam,
+ kern_sysctl;
const
PAGE_MAP_COUNT=(qword(VM_MAXUSER_ADDRESS) shr PAGE_SHIFT);
diff --git a/sys/vm/vm_object.pas b/sys/vm/vm_object.pas
index 3b6e91d4..dd96b3f6 100644
--- a/sys/vm/vm_object.pas
+++ b/sys/vm/vm_object.pas
@@ -107,7 +107,8 @@ implementation
uses
vmparam,
vnode,
- vfs_subr;
+ vfs_subr,
+ kern_patcher;
function IDX_TO_OFF(x:DWORD):QWORD; inline;
begin
@@ -225,6 +226,8 @@ begin
Assert(obj^.paging_in_progress=0,'vm_object_terminate: pageout in progress');
+ vm_object_patch_remove(obj,0,0);
+
{
* Clean and free the pages, as appropriate. All references to the
* obj are gone, so we don't need to lock it.
@@ -385,9 +388,7 @@ procedure vm_object_page_remove(obj:vm_object_t;
__end:vm_pindex_t;
options:Integer);
begin
- //OBJPR_CLEANONLY=$1; // Don't remove dirty pages.
- //OBJPR_NOTMAPPED=$2; // Don't unmap pages.
- //OBJPR_NOTWIRED =$4; // Don't remove wired pages.
+ vm_object_patch_remove(obj,start,__end);
end;
{