FPPS4/sys/vm/vm_mmap.pas

1503 lines
32 KiB
Plaintext

unit vm_mmap;
{$mode ObjFPC}{$H+}
{$CALLING SysV_ABI_CDecl}
interface
uses
vm,
vm_map,
sys_vm_object;
type
p_query_memory_prot=^t_query_memory_prot;
t_query_memory_prot=packed record
start:Pointer;
__end:Pointer;
prot :Integer;
eflags:Integer;
end;
{$IF sizeof(t_query_memory_prot)<>24}{$STOP sizeof(t_query_memory_prot)<>24}{$ENDIF}
function sys_mlock(addr:Pointer;len:QWORD):Integer;
function sys_mmap(vaddr:Pointer;
vlen :QWORD;
prot :Integer;
flags:Integer;
fd :Integer;
pos :QWORD):Pointer;
function sys_munmap(addr:Pointer;len:QWORD):Integer;
function sys_msync(addr:Pointer;len:QWORD;flags:Integer):Integer;
function sys_mprotect(addr:Pointer;len:QWORD;prot:Integer):Integer;
function sys_mtypeprotect(addr:Pointer;len:QWORD;mtype,prot:Integer):Integer;
function sys_madvise(addr:Pointer;len:QWORD;behav:Integer):Integer;
function sys_mname(addr:Pointer;len:QWORD;name:PChar):Integer;
function sys_query_memory_protection(addr:Pointer;info:Pointer):Integer;
function sys_batch_map(fd :Integer;
flags :DWORD;
entries :Pointer;
numberOfEntries :Integer;
numberOfEntriesOut:PInteger):Integer;
function sys_get_page_table_stats(vm_container,cpu_gpu:Integer;p_total,p_available:PInteger):Integer;
function vm_mmap_to_errno(rv:Integer):Integer; inline;
function vm_mmap2(map :vm_map_t;
addr :p_vm_offset_t;
size :vm_size_t;
prot :vm_prot_t;
maxprot :vm_prot_t;
flags :Integer;
handle_type:objtype_t;
handle :Pointer;
foff :vm_ooffset_t;
anon :Pointer):Integer;
function mirror_map (paddr:Pointer;psize:QWORD):Pointer;
procedure mirror_unmap(base:Pointer;size:QWORD);
procedure gpu_get_bound(var start,__end:QWORD);
implementation
uses
vcapability,
md_systm,
systm,
errno,
kern_thr,
kern_proc,
vmparam,
vm_pmap,
kern_dmem,
sys_resource,
kern_resource,
kern_mtx,
kern_descrip,
kern_authinfo,
vmount,
vstat,
vfile,
vfcntl,
vnode,
vfs_subr,
vnode_if,
sys_conf,
vm_pager;
function sys_mlock(addr:Pointer;len:QWORD):Integer;
var
_adr,_end,last,start,size:vm_offset_t;
map:vm_map_t;
error:Integer;
begin
_adr :=vm_offset_t(addr);
size :=len;
last :=_adr + size;
start:=trunc_page(_adr);
_end :=round_page(last);
if (last < _adr) or (_end < _adr) then
begin
Exit(EINVAL);
end;
map:=p_proc.p_vmspace;
error:=vm_map_wire(map, start, _end, VM_MAP_WIRE_USER or VM_MAP_WIRE_NOHOLES);
if (error=KERN_SUCCESS) then
begin
Result:=0;
end else
begin
Result:=ENOMEM;
end;
end;
function vm_mmap_cdev(objsize :vm_size_t;
prot :vm_prot_t;
maxprotp :p_vm_prot_t;
flagsp :PInteger;
cdev :p_cdev;
foff :p_vm_ooffset_t;
objp :p_vm_object_t):Integer;
var
obj:vm_object_t;
dsw:p_cdevsw;
error,flags,ref:Integer;
begin
flags:=flagsp^;
dsw:=dev_refthread(cdev, @ref);
if (dsw=nil) then
begin
Exit(ENXIO);
end;
if ((dsw^.d_flags and D_MMAP_ANON)<>0) then
begin
dev_relthread(cdev, ref);
maxprotp^:=$33;
flagsp^:=flagsp^ or MAP_ANON;
Exit(0);
end;
{
* cdevs do not provide private mappings of any kind.
}
if ((maxprotp^ and VM_PROT_WRITE)=0) and
((prot and VM_PROT_WRITE)<>0) then
begin
dev_relthread(cdev, ref);
Exit(EACCES);
end;
if ((flags and MAP_PRIVATE)<>0) then
begin
dev_relthread(cdev, ref);
Exit(EINVAL);
end;
{
* Force device mappings to be shared.
}
flags:=flags or MAP_SHARED;
error:=dsw^.d_mmap_single2(cdev, foff, objsize, objp, prot, maxprotp, @flags);
if (error<>ENODEV) then
begin
dev_relthread(cdev, ref);
flagsp^:=flags;
Exit(error);
end;
error:=dsw^.d_mmap_single(cdev, foff, objsize, objp, prot);
dev_relthread(cdev, ref);
if (error<>ENODEV) then
begin
Exit(error);
end;
obj:=vm_pager_allocate(OBJT_DEVICE, cdev, objsize, prot, foff^);
if (obj=nil) then
begin
Exit(EINVAL);
end;
objp^:=obj;
flagsp^:=flags;
Exit(0);
end;
function vm_mmap_vnode(objsize :vm_size_t;
prot :vm_prot_t;
maxprotp :p_vm_prot_t;
flagsp :PInteger;
vp :p_vnode;
foffp :p_vm_ooffset_t;
objp :p_vm_object_t;
writecounted:PBoolean):Integer;
label
mark_atime,
done;
var
va:t_vattr;
obj:vm_object_t;
foff:vm_offset_t;
mp:p_mount;
error,flags,locktype,vfslocked:Integer;
begin
mp:=vp^.v_mount;
if ((maxprotp^ and VM_PROT_WRITE)<>0) and ((flagsp^ and MAP_SHARED)<>0) then
locktype:=LK_EXCLUSIVE
else
locktype:=LK_SHARED;
vfslocked:=VFS_LOCK_GIANT(mp);
error:=vget(vp, locktype);
if (error<>0) then
begin
VFS_UNLOCK_GIANT(vfslocked);
Exit(error);
end;
foff :=foffp^;
flags:=flagsp^;
obj:=vp^.v_object;
case vp^.v_type of
VREG:
begin
{
* Get the proper underlying object
}
if (obj=nil) then
begin
error:=EINVAL;
goto done;
end;
if (obj^.handle<>vp) then
begin
vput(vp);
vp:=obj^.handle;
{
* Bypass filesystems obey the mpsafety of the
* underlying fs.
}
error:=vget(vp, locktype);
if (error<>0) then
begin
VFS_UNLOCK_GIANT(vfslocked);
Exit(error);
end;
end;
if (locktype=LK_EXCLUSIVE) then
begin
writecounted^:=TRUE;
//vnode_pager_update_writecount(obj, 0, objsize);
end;
end;
VCHR:
begin
error:=vm_mmap_cdev(objsize, prot, maxprotp, flagsp, vp^.v_rdev, foffp, objp);
if (error=0) then goto mark_atime;
goto done;
end
else
begin
error:=EINVAL;
goto done;
end;
end;
error:=VOP_GETATTR(vp, @va);
if (error<>0) then
begin
goto done;
end;
if ((flags and MAP_SHARED)<>0) then
begin
if ((va.va_flags and (SF_SNAPSHOT or IMMUTABLE or APPEND))<>0) then
begin
if ((prot and VM_PROT_WRITE)<>0) then
begin
error:=EPERM;
goto done;
end;
maxprotp^:=maxprotp^ and (not VM_PROT_WRITE);
end;
end;
{
* If it is a regular file without any references
* we do not need to sync it.
* Adjust object size to be the size of actual file.
}
objsize:=round_page(va.va_size);
if (va.va_nlink=0) then
begin
flags:=flags or MAP_NOSYNC;
end;
obj:=vm_pager_allocate(OBJT_VNODE, vp, objsize, prot, foff);
if (obj=nil) then
begin
error:=ENOMEM;
goto done;
end;
objp^:=obj;
flagsp^:=flags;
mark_atime:
vfs_mark_atime(vp);
done:
if (error<>0) and writecounted^ then
begin
writecounted^:=FALSE;
//vnode_pager_update_writecount(obj, objsize, 0);
end;
vput(vp);
VFS_UNLOCK_GIANT(vfslocked);
Result:=(error);
end;
function vm_mmap_shm(objsize :vm_size_t;
prot :vm_prot_t;
maxprotp :p_vm_prot_t;
flagsp :PInteger;
shmfd :Pointer; //shmfd
foff :p_vm_ooffset_t;
objp :p_vm_object_t):Integer;
var
error:Integer;
begin
if ((flagsp^ and MAP_SHARED)<>0) and
((maxprotp^ and VM_PROT_WRITE)=0) and
((prot and VM_PROT_WRITE)<>0) then
begin
Exit(EACCES);
end;
//error:=shm_mmap(shmfd, objsize, foff, objp);
error:=EOPNOTSUPP;
Exit(error);
end;
function IDX_TO_OFF(x:QWORD):QWORD; inline;
begin
Result:=QWORD(x) shl PAGE_SHIFT;
end;
function vm_mmap_dmem(handle :Pointer;
objsize :vm_size_t;
foff :vm_ooffset_t;
objp :p_vm_object_t):Integer;
var
obj:vm_object_t;
len:vm_size_t;
begin
obj:=handle; //t_physhmfd *
len:=IDX_TO_OFF(obj^.size);
if (foff<0) or
(len<foff) or
((len-foff)<objsize) then
begin
Exit(EINVAL);
end;
vm_object_reference(obj);
objp^:=obj;
Result:=0;
end;
function vm_mmap_to_errno(rv:Integer):Integer; inline;
begin
Case rv of
KERN_SUCCESS :Result:=0;
KERN_INVALID_ADDRESS,
KERN_NO_SPACE :Result:=ENOMEM;
KERN_PROTECTION_FAILURE:Result:=EACCES;
KERN_RESOURCE_SHORTAGE :
begin
Result:=ENOMEM;
if (p_proc.p_sdk_version < $3500000) then
begin
Result:=EINVAL;
end;
end;
else
Result:=EINVAL;
end;
end;
function VMFS_ALIGNED_SPACE(x:QWORD):QWORD; inline; // find a range with fixed alignment
begin
Result:=x shl 8;
end;
function vm_mmap2(map :vm_map_t;
addr :p_vm_offset_t;
size :vm_size_t;
prot :vm_prot_t;
maxprot :vm_prot_t;
flags :Integer;
handle_type:objtype_t;
handle :Pointer;
foff :vm_ooffset_t;
anon :Pointer):Integer;
var
obj:vm_object_t;
docow,error,findspace,rv:Integer;
fitit:Boolean;
writecounted:Boolean;
begin
Result:=0;
if (size=0) then Exit;
obj:=nil;
size:=round_page(size);
if (map^.size + size) > lim_cur(RLIMIT_VMEM) then
begin
Exit(ENOMEM);
end;
if (foff and PAGE_MASK)<>0 then
begin
Exit(EINVAL);
end;
if ((flags and MAP_FIXED)=0) then
begin
fitit:=TRUE;
addr^:=round_page(addr^);
end else
begin
if (addr^<>trunc_page(addr^)) then
begin
Exit(EINVAL);
end;
fitit:=FALSE;
end;
writecounted:=False;
Case handle_type of
OBJT_DEVICE:
begin
error:=vm_mmap_cdev(size,prot,@maxprot,@flags,handle,@foff,@obj);
end;
OBJT_VNODE:
begin
error:=vm_mmap_vnode(size,prot,@maxprot,@flags,handle,@foff,@obj,@writecounted);
end;
OBJT_SWAP:
begin
error:=vm_mmap_shm(size,prot,@maxprot,@flags,handle,@foff,@obj);
end;
OBJT_PHYSHM:
begin
error:=EACCES;
if ((prot and (VM_PROT_WRITE or VM_PROT_GPU_WRITE))=0) or
((maxprot and VM_PROT_WRITE)<>0) then
begin
error:=vm_mmap_dmem(handle,size,foff,@obj);
end;
end;
OBJT_SELF, //same as default
OBJT_DEFAULT:
begin
if (handle=nil) then
begin
error:=0;
end else
begin
error:=EINVAL;
end;
end;
else
error:=EINVAL;
end;
if (error<>0) then Exit(error);
if ((flags and MAP_ANON)<>0) then
begin
obj:=nil;
docow:=0;
if (handle=nil) then foff:=0;
end else
if ((flags and MAP_PREFAULT_READ)<>0) then
docow:=MAP_PREFAULT
else
docow:=MAP_PREFAULT_PARTIAL;
if ((flags and (MAP_ANON or MAP_SHARED))=0) then
begin
docow:=docow or MAP_COPY_ON_WRITE;
end;
if ((flags and MAP_NOSYNC)<>0) then
begin
docow:=docow or MAP_DISABLE_SYNCER;
end;
if ((flags and MAP_NOCORE)<>0) then
begin
docow:=docow or MAP_DISABLE_COREDUMP;
end;
if ((flags and MAP_SYSTEM)<>0) then
begin
docow:=docow or MAP_COW_SYSTEM;
end;
if ((flags and MAP_SANITIZER)<>0) then
begin
docow:=docow or MAP_COW_SYSTEM or MAP_COW_NO_BUDGET;
end;
// Shared memory is also shared with children.
if ((flags and MAP_SHARED)<>0) then
begin
docow:=docow or MAP_INHERIT_SHARE;
end;
if (writecounted) then
begin
docow:=docow or MAP_VN_WRITECOUNT;
end;
if (handle_type=OBJT_BLOCKPOOL) then
begin
docow:=docow or (MAP_COW_NO_BUDGET or MAP_COW_NO_COALESCE);
end else
begin
docow:=docow or (flags and MAP_NO_COALESCE);
end;
rv:=KERN_PROTECTION_FAILURE;
if ((maxprot and prot)=prot) or
((addr^ shr 34) < 63) or
((addr^ + size) < QWORD($fc00000001)) then
begin
if ((flags and MAP_STACK)<>0) then
begin
rv:=vm_map_stack(map, addr^, size,
prot, maxprot,
docow or MAP_STACK_GROWS_DOWN,
anon);
end else
if (fitit) then
begin
if ((flags and MAP_ALIGNMENT_MASK)=MAP_ALIGNED_SUPER) then
begin
findspace:=VMFS_SUPER_SPACE;
end else
if ((flags and MAP_ALIGNMENT_MASK)<>0) then
begin
findspace:=VMFS_ALIGNED_SPACE(flags shr MAP_ALIGNMENT_SHIFT);
end else
begin
findspace:=VMFS_OPTIMAL_SPACE;
end;
rv:=vm_map_find(map, obj, foff, addr, size, findspace,
prot, maxprot,
docow,
anon);
end else
begin
rv:=vm_map_fixed(map, obj, foff, addr^, size,
prot, maxprot,
docow,
ord((flags and MAP_NO_OVERWRITE)=0),
anon);
end;
end;
if (rv=KERN_SUCCESS) then
begin
if ((flags and MAP_SHARED)<>0) then
begin
Result:=vm_map_inherit(map,addr^,addr^ + size,VM_INHERIT_SHARE);
if (Result<>0) then
begin
vm_map_remove(map,addr^,addr^ + size);
Exit;
end;
end;
if ((map^.flags and MAP_WIREFUTURE)=0) or
((flags and (MAP_SANITIZER or MAP_VOID))<>0) then
begin
Exit;
end;
Result:=vm_map_wire(map,addr^,addr^ + size,
(ord((map^.flags and 4)<>0)*8) or VM_MAP_WIRE_USER or VM_MAP_WIRE_HOLESOK);
if (Result<>0) then
begin
vm_map_remove(map,addr^,addr^ + size);
Exit;
end;
end else
begin
if (writecounted) then
begin
//vnode_pager_release_writecount(vm_obj, 0, size);
end;
vm_object_deallocate(obj);
addr^:=0;
end;
Exit(vm_mmap_to_errno(rv));
end;
procedure vm_map_set_name_str(map:vm_map_t;start,__end:vm_offset_t;const name:RawByteString); inline;
begin
vm_map_set_name(map,start,__end,PChar(name));
end;
function sys_mmap(vaddr:Pointer;
vlen :QWORD;
prot :Integer;
flags:Integer;
fd :Integer;
pos :QWORD):Pointer;
label
_map,
_done;
var
td:p_kthread;
map:vm_map_t;
fp:p_file;
vp:p_vnode;
addr:vm_offset_t;
size,pageoff:vm_size_t;
cap_maxprot,maxprot:vm_prot_t;
handle:Pointer;
handle_type:obj_type;
align:Integer;
rights:cap_rights_t;
rbp:PPointer;
rip:Pointer;
stack_addr:Pointer;
begin
td:=curkthread;
if (td=nil) then Exit(Pointer(-1));
map:=p_proc.p_vmspace;
addr:=vm_offset_t(vaddr);
size:=vlen;
prot:=prot and VM_PROT_ALL;
//backtrace
rbp:=Pointer(td^.td_frame.tf_rbp);
stack_addr:=nil;
while (QWORD(rbp) < QWORD($800000000000)) do //sv_maxuser
begin
rip:=md_fuword(rbp[1]);
rbp:=md_fuword(rbp[0]);
if (QWORD(rip)=QWORD(-1)) or
(QWORD(rbp)=QWORD(-1)) then
begin
Break;
end;
if (p_proc.p_libkernel_start_addr > rip) or
(p_proc.p_libkernel___end_addr <= rip) then
begin
stack_addr:=rip;
Break;
end;
end;
//backtrace
fp:=nil;
if ((flags and MAP_SANITIZER)<>0) {and (devkit_parameter(0)=0)} then
begin
Exit(Pointer(EINVAL));
end;
if (size = 0) and
{(sv_flags > -1) and}
(p_proc.p_osrel > $c3567) then
begin
Exit(Pointer(EINVAL));
end;
if ((flags and (MAP_VOID or MAP_ANON))<>0) then
begin
if (pos<>0) or (fd<>-1) then
begin
Exit(Pointer(EINVAL));
end;
end;
if ((flags and MAP_ANON)<>0) then
begin
pos:=0;
end;
if ((flags and MAP_STACK)<>0) then
begin
if (fd<>-1) or
((prot and (VM_PROT_READ or VM_PROT_WRITE))<>(VM_PROT_READ or VM_PROT_WRITE)) then
begin
Exit(Pointer(EINVAL));
end;
flags:=flags or MAP_ANON;
pos:=0;
end;
pageoff:=(pos and PAGE_MASK);
pos:=pos-pageoff;
// Adjust size for rounding (on both ends).
size:=size+pageoff; // low end...
size:=round_page(size); // hi end
// Ensure alignment is at least a page and fits in a pointer.
align:=flags and MAP_ALIGNMENT_MASK;
if (align<>0) and
(align<>Integer(MAP_ALIGNED_SUPER)) and
(((align shr MAP_ALIGNMENT_SHIFT)>=sizeof(Pointer)*NBBY) or
((align shr MAP_ALIGNMENT_SHIFT) < PAGE_SHIFT)) then
begin
Exit(Pointer(EINVAL));
end;
if ((flags and MAP_FIXED)<>0) then
begin
addr:=addr-pageoff;
if (addr and PAGE_MASK)<>0 then
begin
Exit(Pointer(EINVAL));
end;
//Address range must be all in user VM space.
if (addr < vm_map_min(map)) or
(addr + size > vm_map_max(map)) then
begin
Exit(Pointer(EINVAL));
end;
if (addr+size<addr) then
begin
Exit(Pointer(EINVAL));
end;
end else
begin
if (addr=0) then
begin
if ((g_appinfo.mmap_flags and 2)=0) then
begin
addr:=SCE_USR_HEAP_START;
end;
end else
if ((addr and QWORD($fffffffdffffffff))=0) then
begin
addr:=SCE_USR_HEAP_START;
end else
if (addr=QWORD($880000000)) then
begin
addr:=SCE_SYS_HEAP_START;
end;
end;
if ((flags and MAP_VOID)<>0) then
begin
//MAP_VOID
handle:=nil;
handle_type:=OBJT_DEFAULT;
maxprot:=0;
cap_maxprot:=0;
flags:=flags or MAP_ANON;
rights:=0;
prot:=0;
goto _map;
end;
if ((flags and MAP_ANON)<>0) then
begin
//Mapping blank space is trivial.
handle:=nil;
handle_type:=OBJT_DEFAULT;
maxprot:=VM_PROT_ALL;
cap_maxprot:=VM_PROT_ALL;
goto _map;
end;
//Mapping file
rights:=CAP_MMAP;
if ((prot and (VM_PROT_READ or VM_PROT_GPU_READ))<>0) then
begin
rights:=rights or CAP_READ;
end;
if ((flags and MAP_SHARED)<>0) then
begin
if ((prot and (VM_PROT_WRITE or VM_PROT_GPU_WRITE))<>0) then
begin
rights:=rights or CAP_WRITE;
end;
end;
if ((prot and VM_PROT_EXECUTE)<>0) then
begin
rights:=rights or CAP_MAPEXEC;
end;
Result:=Pointer(fget_mmap(fd,rights,@cap_maxprot,@fp));
if (Result<>nil) then goto _done;
case fp^.f_type of
DTYPE_VNODE:
begin
vp:=fp^.f_vnode;
maxprot:=VM_PROT_EXECUTE;
if (vp^.v_mount<>nil) then
if ((p_mount(vp^.v_mount)^.mnt_flag and MNT_NOEXEC)<>0) then
begin
maxprot:=VM_PROT_NONE;
end;
if ((fp^.f_flag and FREAD)<>0) then
begin
maxprot:=maxprot or (VM_PROT_READ or VM_PROT_GPU_READ);
end else
if ((prot and (VM_PROT_READ or VM_PROT_GPU_READ))<>0) then
begin
Result:=Pointer(EACCES);
goto _done;
end;
if ((flags and MAP_SHARED)<>0) then
begin
if ((fp^.f_flag and FWRITE)<>0) then
begin
maxprot:=maxprot or (VM_PROT_WRITE or VM_PROT_GPU_WRITE);
end else
if ((prot and (VM_PROT_WRITE or VM_PROT_GPU_WRITE))<>0) then
begin
Result:=Pointer(EACCES);
goto _done;
end;
end else
if (vp^.v_type<>VCHR) or ((fp^.f_flag and FWRITE)<>0) then
begin
maxprot:=maxprot or (VM_PROT_WRITE or VM_PROT_GPU_WRITE);
cap_maxprot:=cap_maxprot or (VM_PROT_WRITE or VM_PROT_GPU_WRITE);
end;
handle:=vp;
handle_type:=OBJT_VNODE;
end;
DTYPE_SHM:
begin
handle:=fp^.f_data;
handle_type:=OBJT_SWAP;
maxprot:=VM_PROT_NONE;
// FREAD should always be set.
if ((fp^.f_flag and FREAD)<>0) then
begin
maxprot:=maxprot or (VM_PROT_EXECUTE or VM_PROT_READ or VM_PROT_GPU_READ);
end;
if ((fp^.f_flag and FWRITE)<>0) then
begin
maxprot:=maxprot or (VM_PROT_WRITE or VM_PROT_GPU_WRITE);
end;
goto _map;
end;
DTYPE_PHYSHM:
begin
handle:=fp^.f_data;
handle_type:=OBJT_PHYSHM;
prot:=VM_PROT_READ or VM_PROT_GPU_READ;
if ((fp^.f_flag and FREAD)=0) then
begin
prot:=VM_PROT_NONE;
end;
maxprot:=prot or (VM_PROT_WRITE or VM_PROT_GPU_WRITE);
if ((fp^.f_flag and FWRITE)=0) then
begin
maxprot:=prot;
end;
end;
DTYPE_BLOCKPOOL:
begin
handle:=fp^.f_data;
handle_type:=OBJT_BLOCKPOOL;
maxprot:=VM_PROT_ALL;
end;
else
begin
Writeln('DTYPE_',fp^.f_type,' TODO');
Result:=Pointer(ENODEV);
goto _done;
end;
end;
_map:
td^.td_fpop:=fp;
maxprot:=maxprot and cap_maxprot;
if (((flags and MAP_SANITIZER) <> 0) and (addr < QWORD($800000000000))) then //sv_maxuser
begin
if (QWORD($fc00000000) < (addr + size)) then
begin
prot:=prot and $cf;
end;
if ((addr shr 34) > 62) then
begin
prot:=prot and $cf;
end;
end;
if (addr=0) and ((g_appinfo.mmap_flags and 2)<>0) then
begin
addr:=SCE_REPLAY_EXEC_START;
end;
Result:=Pointer(vm_mmap2(map,@addr,size,prot,maxprot,flags,handle_type,handle,pos,stack_addr));
td^.td_fpop:=nil;
td^.td_retval[0]:=(addr+pageoff);
if (Result=nil) then
if (stack_addr<>nil) then
begin
//Do you really need it?
vm_map_set_name_str(map,addr,size + addr,'anon:'+HexStr(QWORD(stack_addr),11));
end;
Writeln('0x',HexStr(QWORD(stack_addr),11),'->',
'sys_mmap(','0x',HexStr(QWORD(vaddr),11),
',0x',HexStr(vlen,11),
',0x',HexStr(prot,1),
',0x',HexStr(flags,6),
',',fd,
',0x',HexStr(pos,11),
'):',Integer(Result),
':0x',HexStr(td^.td_retval[0],11),'..0x',HexStr(td^.td_retval[0]+size,11));
_done:
if (fp<>nil) then
begin
fdrop(fp);
end;
end;
function sys_munmap(addr:Pointer;len:QWORD):Integer;
var
map:vm_map_t;
size,pageoff:vm_size_t;
begin
size:=len;
if (size=0) then
begin
Exit(EINVAL);
end;
pageoff:=(vm_size_t(addr) and PAGE_MASK);
addr:=addr-pageoff;
size:=size+pageoff;
size:=round_page(size);
if (addr + size < addr) then
begin
Exit(EINVAL);
end;
map:=p_proc.p_vmspace;
{
* Check for illegal addresses. Watch out for address wrap...
}
if (qword(addr) < vm_map_min(map)) or (qword(addr) + size > vm_map_max(map)) then
begin
Exit(EINVAL);
end;
Result:=vm_map_remove(map, qword(addr), qword(addr) + size);
Writeln('sys_munmap(','0x',HexStr(QWORD(addr),11),
',0x',HexStr(len,11),
'):',Integer(Result)
);
Result:=vm_mmap_to_errno(Result);
end;
function sys_msync(addr:Pointer;len:QWORD;flags:Integer):Integer;
var
map:vm_map_t;
_addr:vm_offset_t;
pageoff:vm_size_t;
begin
_addr:=vm_offset_t(addr);
pageoff:=(_addr and PAGE_MASK);
_addr:=_addr-pageoff;
len:=len+pageoff;
len:=round_page(len);
if ((_addr + len) < _addr) then
begin
Exit(EINVAL);
end;
if ((flags and (MS_ASYNC or MS_INVALIDATE))=(MS_ASYNC or MS_INVALIDATE)) then
begin
Exit(EINVAL);
end;
map:=p_proc.p_vmspace;
// Clean the pages and interpret the Exit value.
Result:=vm_map_sync(map,
_addr,
_addr + len,
(flags and MS_ASYNC)=0,
(flags and MS_INVALIDATE)<>0);
case Result of
KERN_SUCCESS :Result:=0;
KERN_INVALID_ADDRESS :Result:=ENOMEM;
KERN_INVALID_ARGUMENT:Result:=EBUSY;
KERN_FAILURE :Result:=EIO;
else
Result:=EINVAL;
end;
end;
function sys_mprotect(addr:Pointer;len:QWORD;prot:Integer):Integer;
var
size,pageoff:vm_size_t;
begin
size:=len;
pageoff:=(vm_size_t(addr) and PAGE_MASK);
addr:=addr-pageoff;
size:=size+pageoff;
size:=round_page(size);
if (addr + size < addr) then
begin
Exit(EINVAL);
end;
prot:=((Byte(prot) shr 1) and 1) or (Byte(prot) and $37);
Result:=vm_map_protect(p_proc.p_vmspace, QWORD(addr), QWORD(addr) + size, prot, FALSE);
case Result of
KERN_SUCCESS :Exit(0);
KERN_PROTECTION_FAILURE:Exit(EACCES);
KERN_RESOURCE_SHORTAGE :Exit(ENOMEM);
else
Exit(EINVAL);
end;
end;
function sys_mtypeprotect(addr:Pointer;len:QWORD;mtype,prot:Integer):Integer;
var
__end_u:QWORD;
__end_a:QWORD;
begin
__end_u:=QWORD(addr) + len;
__end_a:=(__end_u + PAGE_MASK) and QWORD(not PAGE_MASK);
if (__end_u < QWORD(addr)) or
(__end_a < __end_u) or
(DWORD(mtype) > 10) or
((prot and $c8) <> 0) then
begin
Exit(EINVAL);
end;
prot:=((Byte(prot) shr 1) and 1) or Byte(prot);
Result:=vm_map_type_protect(p_proc.p_vmspace, QWORD(addr) and QWORD(not PAGE_MASK), __end_a, mtype, prot);
case Result of
KERN_SUCCESS :Result:=0;
KERN_INVALID_ADDRESS :Result:=EINVAL;
KERN_PROTECTION_FAILURE:Result:=EACCES;
KERN_NO_SPACE :Result:=EINVAL;
KERN_INVALID_ARGUMENT :Result:=EINVAL;
KERN_FAILURE :Result:=EOPNOTSUPP;
KERN_RESOURCE_SHORTAGE :Result:=ENOMEM;
KERN_NOT_RECEIVER :Result:=EINVAL;
KERN_NO_ACCESS :Result:=EINVAL;
KERN_BUSY :Result:=EBUSY;
else
Result:=EINVAL;
end;
end;
function sys_madvise(addr:Pointer;len:QWORD;behav:Integer):Integer;
var
map:vm_map_t;
start,__end:vm_offset_t;
begin
{
* Check for our special case, advising the swap pager we are
* "immortal."
}
if (behav=MADV_PROTECT) then
begin
Exit(0);
end;
{
* Check for illegal behavior
}
if (behav < 0) or (behav > MADV_CORE) then
begin
Exit(EINVAL);
end;
map:=p_proc.p_vmspace;
{
* Check for illegal addresses. Watch out for address wrap... Note
* that VM_*_ADDRESS are not constants due to casts (argh).
}
if (vm_offset_t(addr) < vm_map_min(map)) or
(vm_offset_t(addr) + len > vm_map_max(map)) then
begin
Exit(EINVAL);
end;
if (vm_offset_t(addr) + len) < vm_offset_t(addr) then
begin
Exit(EINVAL);
end;
{
* Since this routine is only advisory, we default to conservative
* behavior.
}
start:=trunc_page(vm_offset_t(addr));
__end:=round_page(vm_offset_t(addr) + len);
if (vm_map_madvise(map, start, __end, behav))<>0 then
begin
Exit(EINVAL);
end;
Exit(0);
end;
function sys_mname(addr:Pointer;len:QWORD;name:PChar):Integer;
var
map:vm_map_t;
start,__end:vm_offset_t;
_name:array[0..31] of Char;
begin
map:=p_proc.p_vmspace;
if (vm_offset_t(addr) < vm_map_min(map)) or
(vm_offset_t(addr) + len > vm_map_max(map)) then
begin
Exit(EINVAL);
end;
if (vm_offset_t(addr) + len) < vm_offset_t(addr) then
begin
Exit(EINVAL);
end;
Result:=copyinstr(name,@_name,32,nil);
if (Result<>0) then Exit;
start:=trunc_page(vm_offset_t(addr));
__end:=round_page(vm_offset_t(addr) + len);
vm_map_set_name(map,start,__end,@_name);
Writeln('sys_mname(','0x',HexStr(QWORD(addr),11),
',0x',HexStr(len,11),
',','"',name,'"',
')'
);
end;
function sys_query_memory_protection(addr:Pointer;info:Pointer):Integer;
var
map:vm_map_t;
_addr:vm_offset_t;
__end:vm_offset_t;
entry:vm_map_entry_t;
data:t_query_memory_prot;
begin
Result:=EINVAL;
_addr:=trunc_page(vm_offset_t(addr));
map:=p_proc.p_vmspace;
__end:=vm_map_max(map);
if (_addr<__end) or (_addr=__end) then
begin
vm_map_lock(map);
if not vm_map_lookup_entry(map,_addr,@entry) then
begin
vm_map_unlock(map);
Result:=EACCES;
end else
begin
data.start:=Pointer(entry^.start);
data.__end:=Pointer(entry^.__end);
data.prot:=(entry^.max_protection and entry^.protection);
data.eflags:=entry^.eflags;
vm_map_unlock(map);
Result:=copyout(@data,info,SizeOf(t_query_memory_prot));
end;
end;
end;
const
SCE_KERNEL_MAP_OP_MAP_DIRECT =0;
SCE_KERNEL_MAP_OP_UNMAP =1;
SCE_KERNEL_MAP_OP_PROTECT =2;
SCE_KERNEL_MAP_OP_MAP_FLEXIBLE=3;
SCE_KERNEL_MAP_OP_TYPE_PROTECT=4;
type
PSceKernelBatchMapEntry=^SceKernelBatchMapEntry;
SceKernelBatchMapEntry=packed record
start :Pointer;
offset :QWORD;
length :QWORD;
protection:Byte;
mtype :Byte;
pad :WORD;
operation :Integer;
end;
{$IF sizeof(SceKernelBatchMapEntry)<>32}{$STOP sizeof(SceKernelBatchMapEntry)<>32}{$ENDIF}
function sys_batch_map(fd :Integer;
flags :DWORD;
entries :Pointer;
numberOfEntries :Integer;
numberOfEntriesOut:PInteger):Integer;
var
i,num_out:Integer;
node:SceKernelBatchMapEntry;
__end:QWORD;
begin
Result:=0;
if (numberOfEntries <= -1) then
begin
if (numberOfEntriesOut<>nil) then
begin
suword32(PDWORD(numberOfEntriesOut)^,0);
end;
Exit(EINVAL);
end;
if ((flags and $e0bffb6f) <> 0) then
begin
Exit(EINVAL);
end;
if (numberOfEntries < 1) then
begin
Result :=0;
num_out:=0;
end else
begin
num_out:=0;
node:=Default(SceKernelBatchMapEntry);
For i:=0 to numberOfEntries-1 do
begin
Result:=copyin(@PSceKernelBatchMapEntry(entries)[i],@node,SizeOf(node));
if (Result<>0) then Break;
case node.operation of
SCE_KERNEL_MAP_OP_MAP_DIRECT:
begin
if (p_proc.p_pool_id <> 1) or
((g_appinfo.mmap_flags and 2) <> 0) or
((flags and MAP_STACK) <> 0) or
(p_proc.p_sdk_version < $2500000) then
begin
if ((QWORD(node.start) and PAGE_MASK) = 0) and
((node.length and PAGE_MASK) = 0) and
((node.offset and QWORD($8000000000003fff)) = 0) and
((node.protection and $C8) = 0) then
begin
Result:=Integer(sys_mmap(node.start,
node.length,
node.protection,
flags or MAP_SHARED,
fd,
node.offset));
end else
begin
Result:=EINVAL;
Break;
end;
end else
begin
Result:=Integer(sys_mmap_dmem(node.start,
node.length,
DWORD(-1),
node.protection,
flags,
node.offset));
end;
end; //SCE_KERNEL_MAP_OP_MAP_DIRECT
SCE_KERNEL_MAP_OP_UNMAP:
begin
if ((QWORD(node.start) and PAGE_MASK) <> 0) or
((node.length and PAGE_MASK) <> 0) then
begin
Result:=EINVAL;
Break;
end;
Result:=sys_munmap(node.start,node.length);
end; //SCE_KERNEL_MAP_OP_UNMAP
SCE_KERNEL_MAP_OP_PROTECT:
begin
__end:=QWORD(node.start) + ((node.length + PAGE_MASK) and QWORD(not PAGE_MASK));
if ((QWORD(node.start) and PAGE_MASK) <> 0) or
((node.length and PAGE_MASK) <> 0) or
((node.protection and $c8) <> 0) or
(__end < QWORD(node.start)) then
begin
Result:=EINVAL;
Break;
end;
Result:=sys_mprotect(node.start,node.length,node.protection);
end; //SCE_KERNEL_MAP_OP_PROTECT
SCE_KERNEL_MAP_OP_MAP_FLEXIBLE:
begin
if ((QWORD(node.start) and PAGE_MASK) <> 0) or
((node.length and PAGE_MASK) <> 0) or
((node.protection and $c8) <> 0) then
begin
Result:=EINVAL;
Break;
end;
Result:=Integer(sys_mmap(node.start,
node.length,
node.protection,
flags or MAP_ANON,
-1,
0));
end; //SCE_KERNEL_MAP_OP_MAP_FLEXIBLE
SCE_KERNEL_MAP_OP_TYPE_PROTECT:
begin
__end:=QWORD(node.start) + node.length;
if (__end < QWORD(node.start)) or
(((__end + PAGE_MASK) and QWORD(not PAGE_MASK)) < __end) or
(DWORD(node.mtype) > 10) or
((node.protection and $c8) <> 0) then
begin
Result:=EINVAL;
Break;
end;
Result:=sys_mtypeprotect(node.start,node.length,node.mtype,node.protection);
end; //SCE_KERNEL_MAP_OP_TYPE_PROTECT
else
begin
Result:=EINVAL;
Break;
end;
end; //case
if (Result<>0) then Break;
end; //For
end;
if (numberOfEntriesOut<>nil) then
begin
suword32(PDWORD(numberOfEntriesOut)^,num_out);
end;
end;
function sys_get_page_table_stats(vm_container,cpu_gpu:Integer;p_total,p_available:PInteger):Integer;
begin
Exit(ENOENT); //devkit_parameter(0)=0
end;
function mirror_map(paddr:Pointer;psize:QWORD):Pointer;
var
map:vm_map_t;
begin
if (paddr=nil) or (psize=0) then Exit(nil);
map:=p_proc.p_vmspace;
Result:=pmap_mirror_map(map^.pmap,QWORD(paddr),QWORD(paddr)+psize);
end;
procedure mirror_unmap(base:Pointer;size:QWORD);
var
map:vm_map_t;
begin
if (base=nil) then Exit;
map:=p_proc.p_vmspace;
pmap_mirror_unmap(map^.pmap,base,size);
end;
procedure gpu_get_bound(var start,__end:QWORD);
var
map:vm_map_t;
begin
map:=p_proc.p_vmspace;
pmap_gpu_get_bound(map^.pmap,start,__end);
end;
end.