This commit is contained in:
Pavel 2022-09-29 17:17:37 +03:00
parent 45493c1fca
commit edf8dc7a25
8 changed files with 3899 additions and 311 deletions

View File

@ -31,7 +31,7 @@
<PackageName Value="LCL"/>
</Item1>
</RequiredPackages>
<Units Count="91">
<Units Count="92">
<Unit0>
<Filename Value="fpPS4.lpr"/>
<IsPartOfProject Value="True"/>
@ -324,6 +324,7 @@
<Unit71>
<Filename Value="src\ps4_libscenet.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="ps4_libSceNet"/>
</Unit71>
<Unit72>
<Filename Value="src\ps4_libscepad.pas"/>
@ -345,10 +346,12 @@
<Unit76>
<Filename Value="src\ps4_libscesavedata.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="ps4_libSceSaveData"/>
</Unit76>
<Unit77>
<Filename Value="src\ps4_libscesystemservice.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="ps4_libSceSystemService"/>
</Unit77>
<Unit78>
<Filename Value="src\ps4_libsceuserservice.pas"/>
@ -390,6 +393,7 @@
<Unit86>
<Filename Value="src\np\ps4_libscenpscore.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="ps4_libSceNpScore"/>
</Unit86>
<Unit87>
<Filename Value="src\np\ps4_libscenpsignaling.pas"/>
@ -398,6 +402,7 @@
<Unit88>
<Filename Value="src\np\ps4_libscenptrophy.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="ps4_libSceNpTrophy"/>
</Unit88>
<Unit89>
<Filename Value="sys\signal.inc"/>
@ -407,6 +412,10 @@
<Filename Value="sys\sys_context.pas"/>
<IsPartOfProject Value="True"/>
</Unit90>
<Unit91>
<Filename Value="rtl\mmap.pas"/>
<IsPartOfProject Value="True"/>
</Unit91>
</Units>
</ProjectOptions>
<CompilerOptions>

332
kernel/mm.txt Normal file
View File

@ -0,0 +1,332 @@
int sceKernelMapDirectMemory
(void **virtualAddrDest,qword length,int protections,int flags,qword physicalAddr,
qword alignment)
{
int iVar1;
ulong in_stack_00000000;
pthread_once((pthread_once_t *)&_mem_init_ctl,_mem_init);
iVar1 = _sceKernelMapDirectMemory
(_direct_pool_id,virtualAddrDest,length,protections,flags,physicalAddr,alignment
,in_stack_00000000);
return iVar1;
}
int _sceKernelMapDirectMemory
(uint pool_id,void **virtualAddrDest,qword length,int protections,int flags,
qword physicalAddr,qword alignment,ulong param_8)
{
int last;
int *perror;
uint _flags;
dword *poffset;
void *adr;
qword align;
int ret1;
uint _len;
pthread_once((pthread_once_t *)&_mem_init_ctl,_mem_init);
ret1 = L'\x80020016';
if (pool_id < 3) {
adr = *virtualAddrDest;
if ((((_direct_pool_id == 1) && ((DAT_01084c7c & 2) == 0)) &&
(((long)physicalAddr < 0x3000000000 || (0x301fffffff < physicalAddr)))) &&
(((flags & 0x400U) == 0 && (0x24fffff < DAT_01059790)))) {
ret1 = sceKernelMapDirectMemory2
(virtualAddrDest,length,-1,protections,flags,physicalAddr,alignment);
return ret1;
}
if (((((flags & 0xff9ffb6fU) == 0) && ((protections & 0xffffffc8U) == 0)) &&
(_len = (uint)length,
(((uint)adr | (uint)alignment | (uint)physicalAddr | _len) & 0x3fff) == 0)) &&
((~-alignment & alignment) == 0)) {
_flags = flags & 0xfffffbff;
if (((flags & 0x10U) != 0) && (adr == (void *)0x0)) {
if (0x16fffff < DAT_01059790) {
return L'\x80020016';
}
_flags = flags & 0xfffffbef;
puts("[WARNING] map(addr=0, flags=MAP_FIXED)");
}
if (adr == (void *)0x0) {
if (param_8 >> 0x1e == 0x20) {
adr = (void *)0x880000000;
}
else {
adr = (void *)((ulong)((DAT_01084c7c & 2) == 0) << 0x21);
}
}
align = 0x4000;
if (0x4000 < alignment) {
align = alignment;
}
last = flsl(align);
if (last + -1 < 31) {
poffset = &DAT_01059578;
if (0x301fffffff < physicalAddr) {
poffset = DWORD_ARRAY_01059570 + (int)pool_id;
}
if ((long)physicalAddr < 0x3000000000) {
poffset = DWORD_ARRAY_01059570 + (int)pool_id;
}
adr = mmap(adr,length,protections,_flags | (last + -1) * 0x1000000 | MAP_SHARED,*poffset,physicalAddr);
if (adr == MAP_FAILED) {
perror = (int *)__error();
last = *perror;
ret1 = last + -0x7ffe0000;
if (last == 0) {
ret1 = last;
}
}
else {
*virtualAddrDest = adr;
ret1 = 0;
}
}
}
}
return ret1;
}
int sceKernelMapDirectMemory2
(void **virtualAddrDest,qword length,int memoryType,int protections,int flags,
qword physicalAddr,qword alignment)
{
int last;
void *adr;
int *perror;
int ret1;
qword align;
pthread_once((pthread_once_t *)&_mem_init_ctl,_mem_init);
ret1 = L'\x8002002d';
if ((((_direct_pool_id == 1) && ((DAT_01084c7c & 2) == 0)) &&
(ret1 = -0x7ffdffea, (flags & 0x1f000000U) == 0)) &&
(((alignment & 0x3fff) == 0 && ((~-alignment & alignment) == 0)))) {
align = 0x4000;
if (0x4000 < alignment) {
align = alignment;
}
last = flsl(align);
if (last + -1 < 31) {
adr = (void *)sys_mmap_dmem(*virtualAddrDest,length,memoryType,protections,
(last + -1) * 0x1000000 | flags,physicalAddr);
if (adr == MAP_FAILED) {
perror = (int *)__error();
last = *perror;
ret1 = last + -0x7ffe0000;
if (last == 0) {
ret1 = last;
}
}
else {
*virtualAddrDest = adr;
ret1 = 0;
}
}
}
return ret1;
}
int sceKernelMapFlexibleMemory(void **virtualAddrDest,qword length,int protections,int flags)
{
int iVar1;
undefined in_stack_00000000;
undefined7 in_stack_00000001;
iVar1 = _sceKernelMapFlexibleMemory
(virtualAddrDest,length,protections,flags,
CONCAT71(in_stack_00000001,in_stack_00000000));
return iVar1;
}
int _sceKernelMapFlexibleMemory
(void **virtualAddrDest,qword length,int protections,int flags,ulong param)
{
int *perror;
int ret1;
void *adr;
int err;
ret1 = -0x7ffdffea;
if (((0x3fff < length) && ((length & 0x3fff) == 0)) &&
((flags & 0xffbfff6fU | protections & 0xffffffc8U) == 0)) {
adr = *virtualAddrDest;
if (((flags & 0x10U) != 0) && (adr == (void *)0x0)) {
if (0x16fffff < DAT_01059790) {
return L'\x80020016';
}
flags = flags & 0xffffffef;
puts("[WARNING] map(addr=0, flags=MAP_FIXED)");
}
if (adr == (void *)0x0) {
if (param >> 0x1e == 0x20) {
adr = (void *)0x880000000;
}
else {
adr = (void *)((ulong)((DAT_01084c7c & 2) == 0) << 0x21);
}
}
adr = (void *)mmap(adr,length,protections,flags | MAP_ANON,-1,0);
if (adr == MAP_FAILED) {
perror = (int *)__error();
err = *perror;
ret1 = err + -0x7ffe0000;
if (err == 0) {
ret1 = err;
}
}
else {
*virtualAddrDest = adr;
ret1 = 0;
}
}
return ret1;
}
int sceKernelReserveVirtualRange(void **addr,size_t len,int flags,size_t alignment)
{
int last;
int *perror;
size_t align;
int ret1;
void *adr;
ret1 = -0x7ffdffea;
if ((((flags & 0xffbfff6fU) == 0) &&
(adr = *addr, (((uint)adr | (uint)alignment | (uint)len) & 0x3fff) == 0)) &&
((~-alignment & alignment) == 0)) {
align = 0x4000;
if (0x4000 < alignment) {
align = alignment;
}
last = flsl(align);
if (last + -1 < 0x1f) {
if (((flags & 0x10U) != 0) && (adr == (void *)0x0)) {
if (0x16fffff < DAT_01059790) {
return -0x7ffdffea;
}
flags = flags & 0xffffffef;
puts("[WARNING] map(addr=0, flags=MAP_FIXED)");
}
adr = (void *)mmap(adr,len,0,(last + -1) * 0x1000000 | flags | MAP_VOID | MAP_SHARED,-1,0);
if (adr == MAP_FAILED) {
perror = (int *)__error();
last = *perror;
ret1 = last + -0x7ffe0000;
if (last == 0) {
ret1 = last;
}
}
else {
*addr = adr;
ret1 = 0;
}
}
}
return ret1;
}
int sceKernelMprotect(void *addr,size_t len,int prot)
{
int ret1;
int *perror;
int err;
ret1 = mprotect(addr,len,prot);
if (ret1 < 0) {
perror = (int *)__error();
err = *perror;
ret1 = err + -0x7ffe0000;
if (err == 0) {
ret1 = err;
}
}
return ret1;
}
int sceKernelMsync(void *addr,size_t len,int flags)
{
int ret1;
int *perror;
int err;
ret1 = msync(addr,len,flags);
if (ret1 < 0) {
perror = (int *)__error();
err = *perror;
ret1 = err + -0x7ffe0000;
if (err == 0) {
ret1 = err;
}
}
return ret1;
}
int sceKernelMmap(void *addr,size_t len,int prot,int flags,int fd,size_t offset,void **res)
{
int iVar1;
int err;
void *adr;
int *perror;
adr = mmap(addr,len,prot,flags,fd,offset);
if (adr != MAP_FAILED) {
*res = adr;
return 0;
}
perror = (int *)__error();
iVar1 = *perror;
err = iVar1 + -0x7ffe0000;
if (iVar1 == 0) {
err = iVar1;
}
return err;
}
int sceKernelMunmap(void *addr,size_t len)
{
int ret1;
int *perror;
int err;
ret1 = munmap(addr,len);
if (ret1 < 0) {
perror = (int *)__error();
err = *perror;
ret1 = err + -0x7ffe0000;
if (err == 0) {
ret1 = err;
}
}
return ret1;
}
int sceKernelReleaseFlexibleMemory(void *addr,size_t len)
{
int ret2;
int ret1;
ret1 = -0x7ffdffea;
if ((((uint)addr | (uint)len) & 0x3fff) == 0) {
ret2 = madvise(addr,len,MADV_FREE);
ret1 = -0x7ffdffea;
if (ret2 != -1) {
ret1 = 0;
}
}
return ret1;
}

1063
kernel/mm_adr_direct.pas Normal file

File diff suppressed because it is too large Load Diff

739
kernel/mm_adr_pool.pas Normal file
View File

@ -0,0 +1,739 @@
unit mm_adr_pool;
{$mode ObjFPC}{$H+}
interface
uses
Classes,
SysUtils,
g23tree,
bittype,
spinlock;
{
Free pool node:
[
offset 12..39:28
size 12..39:28
free 0..1 :1
Ext 0..6 :7
]
}
type
TPoolAdrNode=packed object
private
//free: [Size] |[Offset]
//alloc: [Offset]
Function GetOffset:QWORD; inline;
Procedure SetOffset(q:qword); inline;
Function GetSize:QWORD; inline;
Procedure SetSize(q:qword); inline;
Function GetIsFree:Boolean; inline;
Procedure SetIsFree(b:Boolean); inline;
public
F:bitpacked record
Offset:bit28;
Size :bit28;
Free :bit1;
Ext :bit7;
end;
property Offset:QWORD read GetOffset write SetOffset;
property Size:QWORD read GetSize write SetSize;
property IsFree:Boolean read GetIsFree write SetIsFree;
end;
type
TPoolAdrFreeCompare=object
function c(const a,b:TPoolAdrNode):Integer; static;
end;
TPoolAdrAllcCompare=object
function c(const a,b:TPoolAdrNode):Integer; static;
end;
TPoolManager=class
private
type
TFreePoolNodeSet=specialize T23treeSet<TPoolAdrNode,TPoolAdrFreeCompare>;
TAllcPoolNodeSet=specialize T23treeSet<TPoolAdrNode,TPoolAdrAllcCompare>;
var
Flo,Fhi:QWORD;
FFreeSet:TFreePoolNodeSet;
FAllcSet:TAllcPoolNodeSet;
public
property lo:QWORD read Flo;
property hi:QWORD read Fhi;
Constructor Create(_lo,_hi:QWORD);
private
procedure _Insert(const key:TPoolAdrNode);
Function _FetchFree_a(Size,Align:QWORD;var R:TPoolAdrNode):Boolean;
Function _FetchFree_s(ss,se,Size,Align:QWORD;var R:TPoolAdrNode):Boolean;
Function _FetchNode_a(mode:Byte;var R:TPoolAdrNode):Boolean;
Function _FetchNode_m(mode:Byte;cmp:QWORD;var R:TPoolAdrNode):Boolean;
Function _Find_m(mode:Byte;var R:TPoolAdrNode):Boolean;
procedure _Merge(key:TPoolAdrNode);
procedure _Devide(Offset,Size:QWORD;var key:TPoolAdrNode);
public
Function Alloc_any(Size,Align:QWORD;ext:Byte;var AdrOut:QWORD):Integer;
Function Alloc_search(ss,se,Size,Align:QWORD;ext:Byte;var AdrOut:QWORD):Integer;
Function CheckedAvailable(ss,se,Align:QWORD;var AdrOut,SizeOut:QWORD):Integer;
Function CheckedAlloc(Offset,Size:QWORD):Integer;
Function CheckedRelease(Offset,Size:QWORD):Integer;
Function Release(Offset,Size:QWORD):Integer;
procedure Print;
end;
implementation
const
ENOENT= 2;
ENOMEM=12;
EINVAL=22;
//
function TPoolAdrFreeCompare.c(const a,b:TPoolAdrNode):Integer;
begin
//1 FSize
Result:=Integer(a.F.Size>b.F.Size)-Integer(a.F.Size<b.F.Size);
if (Result<>0) then Exit;
//2 FOffset
Result:=Integer(a.F.Offset>b.F.Offset)-Integer(a.F.Offset<b.F.Offset);
end;
function TPoolAdrAllcCompare.c(const a,b:TPoolAdrNode):Integer;
begin
//1 FOffset
Result:=Integer(a.F.Offset>b.F.Offset)-Integer(a.F.Offset<b.F.Offset);
end;
//
Function TPoolAdrNode.GetOffset:QWORD; inline;
begin
Result:=QWORD(F.Offset) shl 12;
end;
Procedure TPoolAdrNode.SetOffset(q:qword); inline;
begin
F.Offset:=DWORD(q shr 12);
Assert(GetOffset=q);
end;
Function TPoolAdrNode.GetSize:QWORD; inline;
begin
Result:=QWORD(F.Size) shl 12;
end;
Procedure TPoolAdrNode.SetSize(q:qword); inline;
begin
F.Size:=DWORD(q shr 12);
Assert(GetSize=q);
end;
Function TPoolAdrNode.GetIsFree:Boolean; inline;
begin
Result:=Boolean(F.Free);
end;
Procedure TPoolAdrNode.SetIsFree(b:Boolean); inline;
begin
F.Free:=Byte(b);
end;
///
Constructor TPoolManager.Create(_lo,_hi:QWORD);
var
key:TPoolAdrNode;
begin
Assert(_lo<_hi);
Flo:=_lo;
Fhi:=_hi;
key:=Default(TPoolAdrNode);
key.IsFree:=True;
key.Offset:=_lo;
key.Size :=(_hi-_lo+1);
_Insert(key);
end;
procedure TPoolManager._Insert(const key:TPoolAdrNode);
begin
if key.IsFree then
begin
FFreeSet.Insert(key);
end;
FAllcSet.Insert(key);
end;
//free: [Size] |[Offset]
Function TPoolManager._FetchFree_a(Size,Align:QWORD;var R:TPoolAdrNode):Boolean;
var
It:TFreePoolNodeSet.Iterator;
key:TPoolAdrNode;
Offset:QWORD;
begin
Result:=false;
key:=Default(TPoolAdrNode);
key.Size:=Size;
It:=FFreeSet.find_be(key);
if (It.Item=nil) then Exit;
repeat
key:=It.Item^;
Offset:=System.Align(key.Offset,Align);
if (Offset+Size)<=(key.Offset+key.Size) then
begin
R:=key;
FAllcSet.delete(key);
FFreeSet.erase(It);
Exit(True);
end;
until not It.Next;
end;
Function TPoolManager._FetchFree_s(ss,se,Size,Align:QWORD;var R:TPoolAdrNode):Boolean;
var
It:TFreePoolNodeSet.Iterator;
key:TPoolAdrNode;
Offset:QWORD;
FEndN,FEndO:QWORD;
begin
Result:=false;
key:=Default(TPoolAdrNode);
key.Offset:=ss;
key.Size :=Size;
It:=FFreeSet.find_be(key);
if (It.Item=nil) then Exit;
repeat
key:=It.Item^;
Offset:=System.Align(key.Offset,Align);
if (se>=Offset) then
begin
FEndN:=key.Offset+key.Size;
FEndO:=Offset+Size;
if (FEndO<=FEndN) then
begin
R:=key;
FAllcSet.delete(key);
FFreeSet.erase(It);
Exit(True);
end;
end;
until not It.Next;
end;
const
M_LE=0;
M_BE=1;
C_UP=2;
C_DW=4;
C_LE=6;
C_BE=8;
//alloc: [Offset]
Function TPoolManager._FetchNode_a(mode:Byte;var R:TPoolAdrNode):Boolean;
var
It:TAllcPoolNodeSet.Iterator;
key,rkey:TPoolAdrNode;
begin
Result:=false;
key:=R;
Case mode of
M_LE:It:=FAllcSet.find_le(key);
M_BE:It:=FAllcSet.find_be(key);
else
Exit;
end;
if (It.Item=nil) then Exit;
rkey:=It.Item^;
if (rkey.IsFree<>key.IsFree) then Exit;
if (rkey.F.Ext <>key.F.Ext ) then Exit;
R:=rkey;
FAllcSet.erase(It);
FFreeSet.delete(rkey);
Result:=True;
end;
Function TPoolManager._FetchNode_m(mode:Byte;cmp:QWORD;var R:TPoolAdrNode):Boolean;
var
It:TAllcPoolNodeSet.Iterator;
key,rkey:TPoolAdrNode;
begin
Result:=false;
key:=R;
Case (mode and 1) of
M_LE:It:=FAllcSet.find_le(key);
M_BE:It:=FAllcSet.find_be(key);
else
Exit;
end;
if (It.Item=nil) then Exit;
rkey:=It.Item^;
if (rkey.IsFree<>key.IsFree) then Exit;
if (rkey.F.Ext <>key.F.Ext ) then Exit;
Case (mode and (not 1)) of
C_UP:if ((rkey.Offset+rkey.Size)<>cmp) then Exit;
C_DW:if (rkey.Offset<>cmp) then Exit;
C_LE:if ((rkey.Offset+rkey.Size)<cmp) then Exit;
C_BE:if (key.Offset<cmp) then Exit;
else
Exit;
end;
R:=rkey;
FAllcSet.erase(It);
FFreeSet.delete(rkey);
Result:=True;
end;
Function TPoolManager._Find_m(mode:Byte;var R:TPoolAdrNode):Boolean;
var
It:TAllcPoolNodeSet.Iterator;
begin
Result:=false;
Case mode of
M_LE:It:=FAllcSet.find_le(R);
M_BE:It:=FAllcSet.find_be(R);
else
Exit;
end;
if (It.Item=nil) then Exit;
R:=It.Item^;
Result:=True;
end;
//
procedure TPoolManager._Merge(key:TPoolAdrNode);
var
rkey:TPoolAdrNode;
begin
//prev union
repeat
rkey:=key;
rkey.F.Offset:=rkey.F.Offset-1; //hack
if not _FetchNode_m(M_LE or C_UP,key.Offset,rkey) then Break;
key.F.Size :=key.F.Size+(key.F.Offset-rkey.F.Offset); //hack
key.F.Offset:=rkey.F.Offset; //hack
until false;
//next union
repeat
rkey:=key;
rkey.F.Offset:=rkey.F.Offset+rkey.F.Size; //hack
if not _FetchNode_m(M_BE or C_DW,(key.Offset+key.Size),rkey) then Break;
key.F.Size :=key.F.Size+rkey.F.Size; //hack
until false;
_Insert(key);
end;
procedure TPoolManager._Devide(Offset,Size:QWORD;var key:TPoolAdrNode);
var
FOffset:QWORD;
FSize:QWORD;
FEndN,FEndO:QWORD;
begin
FOffset:=key.Offset;
FSize :=key.Size;
FEndN:=Offset +Size;
FEndO:=FOffset+FSize;
if (Offset>FOffset) then //prev save
begin
key.Size:=Offset-FOffset;
_Merge(key);
end;
if (FEndO>FEndN) then //next save
begin
key.Offset:=FEndN;
key.Size :=FEndO-FEndN;
_Merge(key);
end else
if (FEndO<>FEndN) then //tunc size
begin
Size:=FEndO-Offset;
end;
//new save
key.Offset:=Offset;
key.Size :=Size;
end;
Function TPoolManager.Alloc_any(Size,Align:QWORD;ext:Byte;var AdrOut:QWORD):Integer;
var
key:TPoolAdrNode;
Offset:QWORD;
begin
Result:=0;
if (Size=0) or (Align=0) then Exit(EINVAL);
key:=Default(TPoolAdrNode);
if _FetchFree_a(Size,Align,key) then
begin
Offset:=System.Align(key.Offset,Align);
_Devide(Offset,Size,key);
//new save
key.IsFree:=False;
key.F.Ext :=ext;
_Merge(key);
AdrOut:=key.Offset;
Result:=0;
end else
begin
Result:=ENOMEM;
end;
end;
Function TPoolManager.Alloc_search(ss,se,Size,Align:QWORD;ext:Byte;var AdrOut:QWORD):Integer;
var
key:TPoolAdrNode;
Offset:QWORD;
begin
Result:=0;
if (Size=0) or (Align=0) then Exit(EINVAL);
if (ss<Flo) or (ss>Fhi) then Exit(EINVAL);
if (se<Flo) or (se<ss) then Exit(EINVAL);
key:=Default(TPoolAdrNode);
if _FetchFree_s(ss,se,Size,Align,key) then
begin
Offset:=System.Align(key.Offset,Align);
_Devide(Offset,Size,key);
//new save
key.IsFree:=False;
key.F.Ext :=ext;
_Merge(key);
AdrOut:=key.Offset;
Result:=0;
end else
begin
Result:=ENOMEM;
end;
end;
Function TPoolManager.CheckedAvailable(ss,se,Align:QWORD;var AdrOut,SizeOut:QWORD):Integer;
var
It:TFreePoolNodeSet.Iterator;
key:TPoolAdrNode;
Offset:QWORD;
Size:QWORD;
begin
Result:=ENOMEM;
if (Align=0) then Exit(EINVAL);
if (ss<Flo) or (ss>Fhi) then Exit(EINVAL);
if (se<Flo) or (se<ss) then Exit(EINVAL);
key:=Default(TPoolAdrNode);
key.Offset:=ss;
It:=FAllcSet.find_le(key);
While (It.Item<>nil) do
begin
key:=It.Item^;
Offset:=System.Align(key.Offset,Align);
if (se>=Offset) then
begin
Size:=key.Size-(Offset-key.Offset);
AdrOut :=Offset;
SizeOut:=Size;
Exit(0);
end;
It.Next
end;
end;
Function TPoolManager.CheckedAlloc(Offset,Size:QWORD):Integer;
var
It:TAllcPoolNodeSet.Iterator;
key:TPoolAdrNode;
FEndN,FEndO:QWORD;
begin
Result:=ENOMEM;
if (Size=0) then Exit(EINVAL);
if (Offset<Flo) or (Offset>Fhi) then Exit(EINVAL);
key:=Default(TPoolAdrNode);
key.Offset:=Offset;
It:=FAllcSet.find_le(key);
if (It.Item<>nil) then
begin
key:=It.Item^;
FEndN:=key.Offset+key.Size;
if key.IsFree then
if (Offset>=key.Offset) then
begin
FEndO:=Offset+Size;
FEndN:=key.Offset+key.Size;
if (FEndN>=FEndO) then
begin
Result:=0;
end;
end;
end;
end;
Function TPoolManager.CheckedRelease(Offset,Size:QWORD):Integer;
var
It:TAllcPoolNodeSet.Iterator;
key:TPoolAdrNode;
FEndO:QWORD;
begin
Result:=ENOENT;
if (Size=0) then Exit(EINVAL);
if (Offset<Flo) or (Offset>Fhi) then Exit(EINVAL);
FEndO:=Offset+Size;
key:=Default(TPoolAdrNode);
key.Offset:=Offset;
It:=FAllcSet.find_le(key);
While (It.Item<>nil) do
begin
key:=It.Item^;
if not key.IsFree then
begin
if (key.Offset>=FEndO) then Break;
Result:=0;
Break;
end;
It.Next;
end;
end;
Function TPoolManager.Release(Offset,Size:QWORD):Integer;
var
key:TPoolAdrNode;
FEndN,FEndO:QWORD;
FSize:QWORD;
begin
Result:=0;
if (Size=0) then Exit(EINVAL);
if (Offset<Flo) or (Offset>Fhi) then Exit(EINVAL);
repeat
key:=Default(TPoolAdrNode);
key.IsFree:=False;
key.Offset:=Offset;
if _FetchNode_m(M_LE or C_LE,Offset,key) then
begin
FEndN:=Offset+Size;
FEndO:=key.Offset+key.Size;
_Devide(Offset,Size,key);
//new save
key.IsFree :=True;
key.F.ext :=0;
_Merge(key);
if (FEndO>=FEndN) then Break;
FSize:=FEndO-Offset;
Offset:=Offset+FSize;
Size :=Size -FSize;
end else
if _FetchNode_m(M_BE or C_BE,Offset,key) then
begin
FEndN:=Offset+Size;
FEndO:=key.Offset+key.Size;
_Devide(key.Offset,FEndN-key.Offset,key);
//new save
key.IsFree :=True;
key.F.ext :=0;
_Merge(key);
if (FEndO>=FEndN) then Break;
FSize:=FEndO-Offset;
Offset:=Offset+FSize;
Size :=Size -FSize;
end else
if _Find_m(M_LE,key) then
begin
FEndN:=Offset+Size;
FEndO:=key.Offset+key.Size;
if (FEndO>=FEndN) then Break;
FSize:=FEndO-Offset;
Offset:=Offset+FSize;
Size :=Size -FSize;
end else
if _Find_m(M_BE,key) then
begin
FEndN:=Offset+Size;
FEndO:=key.Offset+key.Size;
if (FEndO>=FEndN) then Break;
FSize:=FEndO-Offset;
Offset:=Offset+FSize;
Size :=Size -FSize;
end else
begin
Break;
end;
until false;
end;
function _alloc_str(IsFree:Boolean):RawByteString;
begin
Case IsFree of
True :Result:='FREE';
FAlse:Result:='ALLC';
end;
end;
procedure TPoolManager.Print;
var
key:TPoolAdrNode;
It:TAllcPoolNodeSet.Iterator;
begin
It:=FAllcSet.cbegin;
While (It.Item<>nil) do
begin
key:=It.Item^;
Writeln(HexStr(key.Offset,10),'..',
HexStr(key.Offset+key.Size,10),':',
HexStr(key.Size,10),'#',
_alloc_str(key.IsFree),'#',
key.F.Ext);
It.Next;
end;
end;
procedure itest;
var
test:TPoolManager;
addr:array[0..3] of qword;
begin
test:=TPoolManager.Create($7FFFFC000,$FFFFFFFFF);
test.Alloc_any(4*1024,1,0,addr[0]);
Writeln(HexStr(addr[0],16));
test.Alloc_any(4*1024,1,0,addr[1]);
Writeln(HexStr(addr[1],16));
test.Alloc_any(4*1024,1,0,addr[2]);
Writeln(HexStr(addr[2],16));
test.Alloc_any(4*1024,1,0,addr[3]);
Writeln(HexStr(addr[3],16));
writeln;
test.Print;
writeln;
test.Release(addr[0],4*1024);
test.Release(addr[1],4*1024);
writeln;
test.Print;
writeln;
writeln(test.CheckedRelease(addr[1],4*1024*2));
test.Release(addr[1],4*1024*2);
//test.Release(addr[0],4*1024);
//test.Release(addr[2],4*1024);
//test.Release(addr[1],4*1024);
//test.Release(addr[0],4*1024);
//test.Release(addr[1],4*1024);
//test.Release(addr[2],4*1024);
//test.Release(addr[2],4*1024);
//writeln(test.CheckedRelease(addr[1],4*1024));
//writeln(test.CheckedRelease(addr[2],4*1024));
writeln(test.CheckedRelease(addr[3]+4*1024,4*1024));
test.Release(addr[3]+4*1024,4*1024);
writeln;
test.Print;
writeln;
test.Alloc_any(4*1024,1,0,addr[0]);
Writeln(HexStr(addr[0],16));
test.Alloc_any(4*1024,1,0,addr[1]);
Writeln(HexStr(addr[1],16));
test.Alloc_any(4*1024,1,0,addr[2]);
Writeln(HexStr(addr[2],16));
readln;
end;
initialization
//itest
end.

1099
kernel/mm_adr_virtual.pas Normal file

File diff suppressed because it is too large Load Diff

View File

@ -975,9 +975,14 @@ begin
//mmap
lib^.set_proc($A4EF7A4F0CCE9B91,@ps4_sceKernelGetDirectMemorySize);
lib^.set_proc($AD35F0EB9C662C80,@ps4_sceKernelAllocateDirectMemory);
lib^.set_proc($07EBDCD803B666B7,@ps4_sceKernelAllocateMainDirectMemory);
lib^.set_proc($0B47FB4C971B7DA7,@ps4_sceKernelAvailableDirectMemorySize);
lib^.set_proc($047A2E2D0CE1D17D,@ps4_sceKernelDirectMemoryQuery);
lib^.set_proc($AD35F0EB9C662C80,@ps4_sceKernelAllocateDirectMemory);
lib^.set_proc($042F8E1B99BDF9BC,@ps4_sceKernelGetDirectMemoryType);
lib^.set_proc($8705523C29A9E6D3,@ps4_sceKernelCheckedReleaseDirectMemory);
lib^.set_proc($301B88B6F6DAEB3F,@ps4_sceKernelReleaseDirectMemory);
lib^.set_proc($2FF4372C48C86E00,@ps4_sceKernelMapDirectMemory);
lib^.set_proc($98BF0D0C7F3A8902,@ps4_sceKernelMapNamedFlexibleMemory);
lib^.set_proc($21620105D4C78ADE,@ps4_sceKernelMapFlexibleMemory);

View File

@ -9,6 +9,10 @@ uses
g23tree,
RWLock,
sys_types,
mmap,
mm_adr_direct,
mm_adr_virtual,
mm_adr_pool,
Classes,
SysUtils;
@ -37,57 +41,24 @@ User area : 0x0010 0000 0000 - 0x00FC 0000 0000 Size: 0x00EC 0000 0000
System reserved area: 0x00FC 0000 0000 - 0x00FF FFFF FFFF Size: 0x0003 FFFF FFFF (15GB)
}
var
DirectManager:TDirectManager;
Const
SCE_KERNEL_MAIN_DMEM_SIZE=$180000000; //6GB
// CPU
SCE_KERNEL_PROT_CPU_READ =$01;
SCE_KERNEL_PROT_CPU_WRITE=$02;
SCE_KERNEL_PROT_CPU_RW =(SCE_KERNEL_PROT_CPU_READ or SCE_KERNEL_PROT_CPU_WRITE);
SCE_KERNEL_PROT_CPU_EXEC =$04;
SCE_KERNEL_PROT_CPU_ALL =(SCE_KERNEL_PROT_CPU_RW or SCE_KERNEL_PROT_CPU_EXEC);
// GPU
SCE_KERNEL_PROT_GPU_READ =$10;
SCE_KERNEL_PROT_GPU_WRITE=$20;
SCE_KERNEL_PROT_GPU_RW =(SCE_KERNEL_PROT_GPU_READ or SCE_KERNEL_PROT_GPU_WRITE);
SCE_KERNEL_PROT_GPU_ALL =SCE_KERNEL_PROT_GPU_RW;
SCE_KERNEL_MAP_FIXED =$0010;
SCE_KERNEL_MAP_NO_OVERWRITE=$0080;
SCE_KERNEL_MAP_DMEM_COMPAT =$0400;
SCE_KERNEL_MAP_NO_COALESCE =$400000;
SCE_KERNEL_WB_ONION = 0;
SCE_KERNEL_WC_GARLIC = 3;
SCE_KERNEL_WB_GARLIC =10;
MAP_ANONYMOUS=1;
MAP_ANON =MAP_ANONYMOUS;
MAP_SHARED =2;
MAP_PRIVATE =4;
MAP_POPULATE =8;
MAP_NORESERVE=16;
MAP_FIXED =32;
PROT_NONE = 0;
PROT_READ = 1;
PROT_WRITE = 2;
PROT_EXEC = 4;
MAP_FAILED =Pointer(-1);
type
pSceKernelDirectMemoryQueryInfo=^SceKernelDirectMemoryQueryInfo;
SceKernelDirectMemoryQueryInfo=packed record
start:QWORD;
__end:QWORD;
memoryType:Integer;
__align:Integer;
mType:Integer;
align:Integer;
end;
const
SCE_KERNEL_VIRTUAL_RANGE_NAME_SIZE=32;
SCE_KERNEL_DMQ_FIND_NEXT=1;
SCE_KERNEL_VQ_FIND_NEXT=1;
type
@ -111,12 +82,6 @@ type
function ps4_sceKernelGetDirectMemorySize:Int64; SysV_ABI_CDecl;
function ps4_getpagesize:Integer; SysV_ABI_CDecl;
function ps4_sceKernelDirectMemoryQuery(
offset:QWORD;
flags:Integer;
info:pSceKernelDirectMemoryQueryInfo;
infoSize:QWORD):Integer; SysV_ABI_CDecl;
function ps4_sceKernelAllocateDirectMemory(
searchStart:QWORD;
searchEnd:QWORD;
@ -125,6 +90,12 @@ function ps4_sceKernelAllocateDirectMemory(
memoryType:Integer;
physicalAddrDest:PQWORD):Integer; SysV_ABI_CDecl;
function ps4_sceKernelAllocateMainDirectMemory(
length:QWORD;
alignment:QWORD;
memoryType:Integer;
physicalAddrDest:PQWORD):Integer; SysV_ABI_CDecl;
function ps4_sceKernelAvailableDirectMemorySize(
searchStart:QWORD;
searchEnd:QWORD;
@ -132,6 +103,23 @@ function ps4_sceKernelAvailableDirectMemorySize(
physAddrOut:PQWORD;
sizeOut:PQWORD):Integer; SysV_ABI_CDecl;
function ps4_sceKernelDirectMemoryQuery(
offset:QWORD;
flags:Integer;
info:pSceKernelDirectMemoryQueryInfo;
infoSize:QWORD):Integer; SysV_ABI_CDecl;
function ps4_sceKernelGetDirectMemoryType(
start:QWORD;
memoryTypeOut:PInteger;
regionStartOut:PQWORD;
regionEndOut:PQWORD):Integer; SysV_ABI_CDecl;
function ps4_sceKernelCheckedReleaseDirectMemory(start,len:QWORD):Integer; SysV_ABI_CDecl;
function ps4_sceKernelReleaseDirectMemory(start,len:QWORD):Integer; SysV_ABI_CDecl;
//mapping
function ps4_sceKernelMapDirectMemory(
virtualAddrDest:PPointer;
length:QWORD;
@ -262,65 +250,9 @@ begin
Result:=(x and (x - 1))=0;
end;
function _isgpu(prot:LongInt):Boolean; inline;
function fastIntLog2(i:QWORD):QWORD; inline;
begin
Result:=prot and (SCE_KERNEL_PROT_GPU_READ or SCE_KERNEL_PROT_GPU_WRITE)<>0;
end;
function __map_sce_prot_page(prot:LongInt):DWORD;
begin
Result:=0;
if (prot=0) then Exit(PAGE_NOACCESS);
if (prot and SCE_KERNEL_PROT_CPU_EXEC)<>0 then
begin
if (prot and (SCE_KERNEL_PROT_CPU_WRITE or SCE_KERNEL_PROT_GPU_WRITE) )<>0 then
begin
Result:=PAGE_EXECUTE_READWRITE;
end else
if (prot and (SCE_KERNEL_PROT_CPU_READ or SCE_KERNEL_PROT_GPU_READ) )<>0 then
begin
Result:=PAGE_EXECUTE_READ;
end else
begin
Result:=PAGE_EXECUTE;
end;
end else
if (prot and (SCE_KERNEL_PROT_CPU_WRITE or SCE_KERNEL_PROT_GPU_WRITE) )<>0 then
begin
Result:=PAGE_READWRITE;
end else
begin
Result:=PAGE_READONLY;
end;
end;
function __map_mmap_prot_page(prot:LongInt):DWORD;
begin
Result:=0;
if (prot=PROT_NONE) then Exit(PAGE_NOACCESS);
if (prot and PROT_EXEC)<>0 then
begin
if (prot and PROT_WRITE)<>0 then
begin
Result:=PAGE_EXECUTE_READWRITE;
end else
if (prot and PROT_READ)<>0 then
begin
Result:=PAGE_EXECUTE_READ;
end else
begin
Result:=PAGE_EXECUTE;
end;
end else
if (prot and PROT_WRITE)<>0 then
begin
Result:=PAGE_READWRITE;
end else
begin
Result:=PAGE_READONLY;
end;
Result:=BsfQWORD(i);
end;
function str_mem_type(memoryType:Integer):RawByteString;
@ -523,7 +455,7 @@ type
FLock:TRWLock;
FDirectSize:QWORD;
FDirectAdrSet:TDirectAdrSet;
//FDirectAdrSet:TDirectAdrSet;
FMapBlockSet:TBlockSet;
@ -564,7 +496,7 @@ var
block:PBlockBig;
begin
Result:=nil;
base:=VirtualAllocAlign(addr,len,alignment,MEM_COMMIT or MEM_RESERVE,__map_sce_prot_page(prot));
base:=VirtualAllocAlign(addr,len,alignment,MEM_COMMIT or MEM_RESERVE,__map_prot_page(prot));
if (base=nil) then Exit;
block:=AllocMem(SizeOf(TBlockBig));
if (block=nil) then
@ -593,7 +525,7 @@ var
i,c:Byte;
begin
Result:=nil;
base:=VirtualAllocAlign(addr,GRANULAR_PAGE_SIZE,alignment,MEM_COMMIT or MEM_RESERVE,__map_sce_prot_page(prot));
base:=VirtualAllocAlign(addr,GRANULAR_PAGE_SIZE,alignment,MEM_COMMIT or MEM_RESERVE,__map_prot_page(prot));
if (len<>GRANULAR_PAGE_SIZE) then
begin
VirtualFree(base+len,GRANULAR_PAGE_SIZE-len,MEM_DECOMMIT);
@ -764,7 +696,7 @@ begin
_map_64k_block_d(block);
Result:=block^.pAddr+(b*LOGICAL_PAGE_SIZE);
Result:=VirtualAlloc(Result,len,MEM_COMMIT,__map_sce_prot_page(prot));
Result:=VirtualAlloc(Result,len,MEM_COMMIT,__map_prot_page(prot));
end;
end;
@ -1044,7 +976,7 @@ begin
Case _pblock^.bType of
BT_DIRECT_BIG:
begin
if VirtualAlloc(curr,LOGICAL_PAGE_SIZE,MEM_COMMIT,__map_sce_prot_page(prot))=nil then Exit(False);
if VirtualAlloc(curr,LOGICAL_PAGE_SIZE,MEM_COMMIT,__map_prot_page(prot))=nil then Exit(False);
curr:=curr+LOGICAL_PAGE_SIZE;
if (direct<>INVALID_DIRECT) then
begin
@ -1053,7 +985,7 @@ begin
end;
BT_PHYSIC_BIG:
begin
if VirtualAlloc(curr,PHYSICAL_PAGE_SIZE,MEM_COMMIT,__map_sce_prot_page(prot))=nil then Exit(False);
if VirtualAlloc(curr,PHYSICAL_PAGE_SIZE,MEM_COMMIT,__map_prot_page(prot))=nil then Exit(False);
curr:=curr+PHYSICAL_PAGE_SIZE;
if (direct<>INVALID_DIRECT) then
begin
@ -1062,7 +994,7 @@ begin
end;
BT_DIRECT_64K:
begin
if VirtualAlloc(curr,LOGICAL_PAGE_SIZE,MEM_COMMIT,__map_sce_prot_page(prot))=nil then Exit(False);
if VirtualAlloc(curr,LOGICAL_PAGE_SIZE,MEM_COMMIT,__map_prot_page(prot))=nil then Exit(False);
i:=Get16kBlockCount(curr-_pblock^.pAddr);
_unmap_64k_block_d(PBlock64k(_pblock));
PBlock64k(_pblock)^.nodes[i].direct:=direct;
@ -1194,7 +1126,7 @@ function __mprotect(addr:Pointer;len:size_t;prot:Integer):Integer;
Var
newprotect,oldprotect:DWORD;
begin
newprotect:=__map_mmap_prot_page(prot);
newprotect:=__map_prot_page(prot);
oldprotect:=0;
if not VirtualProtect(addr,len,newprotect,oldprotect) then
@ -1312,7 +1244,225 @@ begin
Result:=PHYSICAL_PAGE_SIZE;
end;
//function sceKernelReleaseDirectMemory(physicalAddr:Pointer;length:Int64):Int64; cdecl;
function _test_mtype(mtype:Integer):Boolean; inline;
begin
Case mtype of
SCE_KERNEL_WB_ONION ,
SCE_KERNEL_WC_GARLIC,
SCE_KERNEL_WB_GARLIC:Result:=True;
else
Result:=False;
end;
end;
//direct
function _sceKernelAllocateDirectMemory(
searchStart:QWORD;
searchEnd:QWORD;
length:QWORD;
alignment:QWORD;
memoryType:Integer;
physicalAddrDest:PQWORD):Integer;
begin
Result:=EINVAL;
Writeln('srchd:',HexStr(searchStart,10),'..',HexStr(searchEnd,10),' len:',HexStr(length,10));
Writeln('align:',HexStr(alignment,10),' ','mType:',str_mem_type(memoryType));
if (physicalAddrDest=nil) or (length=0) or (searchEnd<=searchStart) then Exit;
if (searchEnd>SCE_KERNEL_MAIN_DMEM_SIZE) then Exit;
if (alignment=0) then alignment:=LOGICAL_PAGE_SIZE;
if not IsAlign(length ,LOGICAL_PAGE_SIZE) then Exit;
if not IsAlign(alignment,LOGICAL_PAGE_SIZE) then Exit;
if not IsPowerOfTwo(alignment) then Exit;
if (fastIntLog2(alignment)>31) then Exit;
if not _test_mtype(memoryType) then Exit;
_sig_lock;
rwlock_wrlock(PageMM.FLock);
Result:=DirectManager.Alloc_search(searchStart,searchEnd,length,alignment,Byte(memoryType),physicalAddrDest^);
rwlock_unlock(PageMM.FLock);
_sig_unlock;
end;
function _sceKernelAllocateMainDirectMemory(
length:QWORD;
alignment:QWORD;
memoryType:Integer;
physicalAddrDest:PQWORD):Integer;
begin
Result:=EINVAL;
Writeln('srchm: len:',HexStr(length,10));
Writeln('align:',HexStr(alignment,10),' ','mType:',str_mem_type(memoryType));
if (physicalAddrDest=nil) or (length=0) then Exit;
if (alignment=0) then alignment:=LOGICAL_PAGE_SIZE;
if not IsAlign(length ,LOGICAL_PAGE_SIZE) then Exit;
if not IsAlign(alignment,LOGICAL_PAGE_SIZE) then Exit;
if not IsPowerOfTwo(alignment) then Exit;
if (fastIntLog2(alignment)>31) then Exit;
if not _test_mtype(memoryType) then Exit;
_sig_lock;
rwlock_wrlock(PageMM.FLock);
Result:=DirectManager.Alloc_any(length,alignment,Byte(memoryType),physicalAddrDest^);
rwlock_unlock(PageMM.FLock);
_sig_unlock;
end;
function _sceKernelAvailableDirectMemorySize(
searchStart:QWORD;
searchEnd:QWORD;
alignment:QWORD;
physAddrOut:PQWORD;
sizeOut:PQWORD):Integer;
var
FAdrOut,FSizeOut:QWORD;
begin
Result:=EINVAL;
if (physAddrOut=nil) or (sizeOut=nil) or (searchEnd<=searchStart) then Exit;
if (searchEnd>SCE_KERNEL_MAIN_DMEM_SIZE) then Exit;
if (alignment=0) then alignment:=LOGICAL_PAGE_SIZE;
if not IsAlign(searchStart,LOGICAL_PAGE_SIZE) then Exit;
if not IsAlign(searchEnd ,LOGICAL_PAGE_SIZE) then Exit;
if not IsAlign(alignment ,LOGICAL_PAGE_SIZE) then Exit;
if not IsPowerOfTwo(alignment) then Exit;
if (fastIntLog2(alignment)>31) then Exit;
_sig_lock;
rwlock_wrlock(PageMM.FLock);
Result:=DirectManager.CheckedAvailable(searchStart,searchEnd,alignment,FAdrOut,FSizeOut);
rwlock_unlock(PageMM.FLock);
_sig_unlock;
if (Result=0) then
begin
if (physAddrOut<>nil) then
begin
physAddrOut^:=FAdrOut;
end;
if (sizeOut<>nil) then
begin
sizeOut^:=FSizeOut;
end;
end;
end;
function _sceKernelDirectMemoryQuery(
offset:QWORD;
flags:Integer;
info:pSceKernelDirectMemoryQueryInfo;
infoSize:QWORD):Integer;
var
ROut:TDirectAdrNode;
begin
Result:=EINVAL;
if (info=nil) or (infoSize<>SizeOf(SceKernelDirectMemoryQueryInfo)) then Exit;
if not IsAlign(offset,LOGICAL_PAGE_SIZE) then Exit;
_sig_lock;
rwlock_wrlock(PageMM.FLock);
Result:=DirectManager.Query(offset,(flags=SCE_KERNEL_DMQ_FIND_NEXT),ROut);
rwlock_unlock(PageMM.FLock);
_sig_unlock;
if (Result<>0) then
begin
info^:=Default(SceKernelDirectMemoryQueryInfo);
info^.start:=ROut.Offset;
info^.__end:=ROut.Offset+ROut.Size;
info^.mType:=ROut.F.mtype;
end;
end;
function _sceKernelGetDirectMemoryType(
start:QWORD;
memoryTypeOut:PInteger;
regionStartOut:PQWORD;
regionEndOut:PQWORD):Integer;
var
ROut:TDirectAdrNode;
begin
Result:=EINVAL;
if (memoryTypeOut=nil) then Exit;
if (regionStartOut=nil) then Exit;
if (regionEndOut=nil) then Exit;
start:=AlignDw(start,PHYSICAL_PAGE_SIZE);
_sig_lock;
rwlock_wrlock(PageMM.FLock);
Result:=DirectManager.QueryMType(start,ROut);
rwlock_unlock(PageMM.FLock);
_sig_unlock;
if (Result<>0) then
begin
memoryTypeOut ^:=ROut.F.mtype;
regionStartOut^:=ROut.Offset;
regionEndOut ^:=ROut.Offset+ROut.Size;
end;
end;
function _sceKernelCheckedReleaseDirectMemory(start,len:QWORD):Integer;
begin
Result:=EINVAL;
if not IsAlign(start,LOGICAL_PAGE_SIZE) then Exit;
if not IsAlign(len ,LOGICAL_PAGE_SIZE) then Exit;
_sig_lock;
rwlock_wrlock(PageMM.FLock);
Result:=DirectManager.CheckedRelease(start,len);
rwlock_unlock(PageMM.FLock);
_sig_unlock;
end;
function _sceKernelReleaseDirectMemory(start,len:QWORD):Integer;
begin
Result:=EINVAL;
if not IsAlign(start,LOGICAL_PAGE_SIZE) then Exit;
if not IsAlign(len ,LOGICAL_PAGE_SIZE) then Exit;
_sig_lock;
rwlock_wrlock(PageMM.FLock);
Result:=DirectManager.Release(start,len);
rwlock_unlock(PageMM.FLock);
_sig_unlock;
end;
//
function ps4_sceKernelAllocateDirectMemory(
searchStart:QWORD;
@ -1321,103 +1471,44 @@ function ps4_sceKernelAllocateDirectMemory(
alignment:QWORD;
memoryType:Integer;
physicalAddrDest:PQWORD):Integer; SysV_ABI_CDecl;
var
It:TDirectAdrSet.Iterator;
Adr,Tmp:TBlock;
m1,m2:Pointer;
begin
Writeln('srch:',HexStr(searchStart,16),'..',HexStr(searchEnd,16),' len:',HexStr(length,16));
Writeln('align:',HexStr(alignment,16),' ','mType:',str_mem_type(memoryType));
Result:=_sceKernelAllocateDirectMemory(
searchStart,
searchEnd,
length,
alignment,
memoryType,
physicalAddrDest);
if (physicalAddrDest=nil) or (length=0) or (searchEnd<=searchStart) then Exit(SCE_KERNEL_ERROR_EINVAL);
if (searchEnd>SCE_KERNEL_MAIN_DMEM_SIZE) then Exit(SCE_KERNEL_ERROR_EINVAL);
if (alignment=0) then alignment:=LOGICAL_PAGE_SIZE;
if not IsAlign(length ,LOGICAL_PAGE_SIZE) then Exit(SCE_KERNEL_ERROR_EINVAL);
if not IsAlign(alignment,LOGICAL_PAGE_SIZE) then Exit(SCE_KERNEL_ERROR_EINVAL);
if not IsPowerOfTwo(alignment) then Exit(SCE_KERNEL_ERROR_EINVAL);
Adr.pAddr:=AlignUp(Pointer(searchStart),alignment);
Adr.nSize:=length;
Adr.bType:=memoryType;
Result:=0;
_sig_lock;
rwlock_wrlock(PageMM.FLock);
if ((PageMM.FDirectSize+Adr.nSize)>SCE_KERNEL_MAIN_DMEM_SIZE) then
if (Result<>0) then
begin
rwlock_unlock(PageMM.FLock);
_sig_unlock;
Exit(SCE_KERNEL_ERROR_EAGAIN);
Writeln(StdErr,'[WARN]:sceKernelAllocateDirectMemory:',Result);
end;
_set_errno(Result);
repeat
if ((QWORD(Adr.pAddr)+Adr.nSize)>SCE_KERNEL_MAIN_DMEM_SIZE) then
begin
Result:=SCE_KERNEL_ERROR_EAGAIN;
Break;
end;
Tmp.pAddr:=Adr.pAddr+Adr.nSize-1;
Tmp.nSize:=0;
Tmp.bType:=0;
It:=PageMM.FDirectAdrSet.find_le(Tmp);
if (It.Item=nil) then Break;
Tmp:=It.Item^;
m1:=Tmp.pAddr+Tmp.nSize;
if (Adr.pAddr>=m1) then Break;
m1:=AlignUp(m1,alignment);
m2:=Adr.pAddr+alignment;
if (m1>m2) then
Adr.pAddr:=m1
else
Adr.pAddr:=m2;
if (Adr.pAddr>=Pointer(searchEnd)) then
begin
Result:=SCE_KERNEL_ERROR_EAGAIN;
Break;
end;
until false;
if (Result=0) then
begin
PageMM.FDirectSize:=PageMM.FDirectSize+Adr.nSize;
PageMM.FDirectAdrSet.Insert(Adr);
physicalAddrDest^:=QWORD(Adr.pAddr);
end;
rwlock_unlock(PageMM.FLock);
_sig_unlock;
Result:=0;
Result:=px2sce(Result);
end;
{
SCE_KERNEL_MAP_FIXED
0x0010
Fix map destination to *addr
function ps4_sceKernelAllocateMainDirectMemory(
length:QWORD;
alignment:QWORD;
memoryType:Integer;
physicalAddrDest:PQWORD):Integer; SysV_ABI_CDecl;
begin
Result:=_sceKernelAllocateMainDirectMemory(
length,
alignment,
memoryType,
physicalAddrDest);
SCE_KERNEL_MAP_NO_OVERWRITE
0x0080
Prohibit mapping when an area that is being used is included between *addr and *addr+len
if (Result<>0) then
begin
Writeln(StdErr,'[WARN]:sceKernelAllocateMainDirectMemory:',Result);
end;
_set_errno(Result);
SCE_KERNEL_MAP_NO_COALESCE
0x400000
Instruct sceKernelVirtualQuery() not to merge neighboring areas
}
Result:=px2sce(Result);
end;
function ps4_sceKernelAvailableDirectMemorySize(
searchStart:QWORD;
@ -1425,130 +1516,127 @@ function ps4_sceKernelAvailableDirectMemorySize(
alignment:QWORD;
physAddrOut:PQWORD;
sizeOut:PQWORD):Integer; SysV_ABI_CDecl;
var
It:TDirectAdrSet.Iterator;
offset,size:QWORD;
Tmp:TBlock;
begin
if (physAddrOut=nil) or (sizeOut=nil) or (searchEnd<=searchStart) then Exit(SCE_KERNEL_ERROR_EINVAL);
Result:=_sceKernelAvailableDirectMemorySize(
searchStart,
searchEnd,
alignment,
physAddrOut,
sizeOut);
if (searchEnd>SCE_KERNEL_MAIN_DMEM_SIZE) then Exit(SCE_KERNEL_ERROR_EINVAL);
if (Result<>0) then
begin
Writeln(StdErr,'[WARN]:sceKernelAvailableDirectMemorySize:',Result);
end;
_set_errno(Result);
if (alignment=0) then alignment:=LOGICAL_PAGE_SIZE;
if not IsAlign(searchStart,LOGICAL_PAGE_SIZE) then Exit(SCE_KERNEL_ERROR_EINVAL);
if not IsAlign(searchEnd ,LOGICAL_PAGE_SIZE) then Exit(SCE_KERNEL_ERROR_EINVAL);
if not IsAlign(alignment ,LOGICAL_PAGE_SIZE) then Exit(SCE_KERNEL_ERROR_EINVAL);
if not IsPowerOfTwo(alignment) then Exit(SCE_KERNEL_ERROR_EINVAL);
physAddrOut^:=0;
sizeOut^ :=0;
offset:=0;
Result:=0;
_sig_lock;
rwlock_wrlock(PageMM.FLock);
repeat
Tmp.pAddr:=AlignUp(Pointer(offset),alignment);
Tmp.nSize:=0;
Tmp.bType:=0;
It:=PageMM.FDirectAdrSet.find_be(Tmp);
if (It.Item=nil) then //nothing to be
begin
size:=searchEnd-offset;
if (size=0) then
begin
Result:=SCE_KERNEL_ERROR_EAGAIN;
Break;
end else
begin
physAddrOut^:=offset;
sizeOut^ :=size;
Break;
end;
end;
Tmp:=It.Item^;
size:=QWORD(Tmp.pAddr)-offset;
if (size<>0) then
begin
physAddrOut^:=offset;
sizeOut^ :=size;
Break;
end;
offset:=QWORD(Tmp.pAddr)+Tmp.nSize;
if (offset>=searchEnd) then
begin
Result:=SCE_KERNEL_ERROR_EAGAIN;
Break;
end;
until false;
rwlock_unlock(PageMM.FLock);
_sig_unlock;
Result:=0;
Result:=px2sce(Result);
end;
const
SCE_KERNEL_DMQ_FIND_NEXT=1;
function ps4_sceKernelDirectMemoryQuery(
offset:QWORD;
flags:Integer;
info:pSceKernelDirectMemoryQueryInfo;
infoSize:QWORD):Integer; SysV_ABI_CDecl;
var
It:TDirectAdrSet.Iterator;
Tmp:TBlock;
begin
if (info=nil) or (infoSize<>SizeOf(SceKernelDirectMemoryQueryInfo)) then Exit(SCE_KERNEL_ERROR_EINVAL);
Result:=_sceKernelDirectMemoryQuery(
offset,
flags,
info,
infoSize);
if not IsAlign(offset,LOGICAL_PAGE_SIZE) then Exit(SCE_KERNEL_ERROR_EINVAL);
info^:=Default(SceKernelDirectMemoryQueryInfo);
Tmp:=Default(TBlock);
Tmp.pAddr:=Pointer(offset);
Result:=0;
_sig_lock;
rwlock_wrlock(PageMM.FLock);
if (flags=SCE_KERNEL_DMQ_FIND_NEXT) then
if (Result<>0) then
begin
It:=PageMM.FDirectAdrSet.find_be(Tmp);
Writeln(StdErr,'[WARN]:sceKernelDirectMemoryQuery:',Result);
end;
_set_errno(Result);
Result:=px2sce(Result);
end;
function ps4_sceKernelGetDirectMemoryType(
start:QWORD;
memoryTypeOut:PInteger;
regionStartOut:PQWORD;
regionEndOut:PQWORD):Integer; SysV_ABI_CDecl;
begin
Result:=_sceKernelGetDirectMemoryType(
start,
memoryTypeOut,
regionStartOut,
regionEndOut);
if (Result<>0) then
begin
Writeln(StdErr,'[WARN]:sceKernelGetDirectMemoryType:',Result);
end;
_set_errno(Result);
Result:=px2sce(Result);
end;
function ps4_sceKernelCheckedReleaseDirectMemory(start,len:QWORD):Integer; SysV_ABI_CDecl;
begin
Result:=_sceKernelCheckedReleaseDirectMemory(start,len);
if (Result<>0) then
begin
Writeln(StdErr,'[WARN]:sceKernelCheckedReleaseDirectMemory:',Result);
end;
_set_errno(Result);
Result:=px2sce(Result);
end;
function ps4_sceKernelReleaseDirectMemory(start,len:QWORD):Integer; SysV_ABI_CDecl;
begin
Result:=_sceKernelReleaseDirectMemory(start,len);
if (Result<>0) then
begin
Writeln(StdErr,'[WARN]:sceKernelReleaseDirectMemory:',Result);
end;
_set_errno(Result);
Result:=px2sce(Result);
end;
//mapping
//flag:MAP_VOID fd=-1 //reserve
//flag:MAP_ANON fd=-1 //flex
//flag:MAP_SHARED fd=/dev/dmem%d offset=physicalAddr //direct
function __mmap(addr:Pointer;len,align:size_t;prot,flags:Integer;fd:Integer;offset:size_t;var res:Pointer):Integer;
begin
Result:=EINVAL;
if not IsAlign(addr ,PHYSICAL_PAGE_SIZE) then Exit;
if not IsAlign(len ,PHYSICAL_PAGE_SIZE) then Exit;
if not IsAlign(offset,PHYSICAL_PAGE_SIZE) then Exit;
if (flags and MAP_VOID)<>0 then //reserved
begin
Assert(false);
end else
if (flags and MAP_ANON)<>0 then //flex
begin
It:=PageMM.FDirectAdrSet.find(Tmp);
Assert(false);
end else
if (flags and MAP_SHARED)<>0 then
begin
if (fd=-1) then Exit;
if (fd=0) then //direct
begin
Assert(false);
end else
begin //file
Assert(false);
end;
end;
if (It.Item=nil) then
begin
Result:=SCE_KERNEL_ERROR_EACCES;
end else
begin
Tmp:=It.Item^;
info^.start:=QWORD(Tmp.pAddr);
info^.__end:=QWORD(Tmp.pAddr)+Tmp.nSize;
info^.memoryType:=Integer(Tmp.bType);
end;
rwlock_unlock(PageMM.FLock);
_sig_unlock;
end;
function ps4_sceKernelMapDirectMemory(
@ -1611,8 +1699,6 @@ begin
Result:=0;
end;
//sceKernelCheckedReleaseDirectMemory
function ps4_sceKernelMapNamedFlexibleMemory(
virtualAddrDest:PPointer;
length:QWORD;
@ -1802,7 +1888,7 @@ begin
Exit;
end;
protect:=__map_mmap_prot_page(prot);
protect:=__map_prot_page(prot);
SetLastError(0);
@ -1882,8 +1968,14 @@ begin
_sig_unlock;
end;
var
res:Pointer;
initialization
DirectManager:=TDirectManager.Create(0,SCE_KERNEL_MAIN_DMEM_SIZE-1);
PageMM.init;
__mmap(nil,4*1024,4*1024,0,0,0,0,res);
end.

249
rtl/mmap.pas Normal file
View File

@ -0,0 +1,249 @@
unit mmap;
{$mode ObjFPC}{$H+}
interface
uses
Windows;
const
// CPU
SCE_KERNEL_PROT_CPU_READ =$01;
SCE_KERNEL_PROT_CPU_WRITE=$02;
SCE_KERNEL_PROT_CPU_RW =(SCE_KERNEL_PROT_CPU_READ or SCE_KERNEL_PROT_CPU_WRITE);
SCE_KERNEL_PROT_CPU_EXEC =$04;
SCE_KERNEL_PROT_CPU_ALL =(SCE_KERNEL_PROT_CPU_RW or SCE_KERNEL_PROT_CPU_EXEC);
// GPU
SCE_KERNEL_PROT_GPU_READ =$10;
SCE_KERNEL_PROT_GPU_WRITE=$20;
SCE_KERNEL_PROT_GPU_RW =(SCE_KERNEL_PROT_GPU_READ or SCE_KERNEL_PROT_GPU_WRITE);
SCE_KERNEL_PROT_GPU_ALL =SCE_KERNEL_PROT_GPU_RW;
SCE_KERNEL_MAP_FIXED =$0010;
SCE_KERNEL_MAP_NO_OVERWRITE=$0080;
SCE_KERNEL_MAP_DMEM_COMPAT =$0400;
SCE_KERNEL_MAP_NO_COALESCE =$400000;
SCE_KERNEL_WB_ONION = 0;
SCE_KERNEL_WC_GARLIC = 3;
SCE_KERNEL_WB_GARLIC =10;
//mmap
PROT_NONE =$00; // no permissions
PROT_READ =$01; // pages can be read
PROT_WRITE =$02; // pages can be written
PROT_EXEC =$04; // pages can be executed
PROT_CPU_READ =PROT_READ;
PROT_CPU_WRITE =PROT_WRITE;
PROT_CPU_ALL =$07;
PROT_GPU_READ =$10;
PROT_GPU_WRITE =$20;
PROT_GPU_ALL =$30;
MAP_SHARED =$0001; // share changes
MAP_PRIVATE =$0002; // changes are private
MAP_FIXED =$0010; // map addr must be exactly as requested
MAP_NO_OVERWRITE=$0080;
MAP_VOID =$0100; // reserve
MAP_RENAME =$0020; // Sun: rename private pages to file
MAP_NORESERVE =$0040; // Sun: don't reserve needed swap area
MAP_HASSEMAPHORE=$0200; // region may contain semaphores
MAP_STACK =$0400; // region grows down, like a stack
MAP_NOSYNC =$0800; // page to but do not sync underlying file
MAP_FILE =$0000; // map from file (default)
MAP_ANON =$1000; // allocated from memory, swap space
MAP_ANONYMOUS =MAP_ANON; // For compatibility.
MAP_SYSTEM =$2000;
MAP_ALLAVAILABLE=$4000;
MAP_SELF =$00080000; // map decryped SELF file
MAP_ALIGNMENT_BIT =24;
MAP_ALIGNMENT_MASK=$1f000000;
MAP_ALIGNMENT_MUL =$01000000; //1 shl 24
MAP_FAILED =Pointer(-1);
function _isgpu(prot:Integer):Boolean; inline;
function __map_prot_page(prot:Integer):DWORD;
function __map_prot_file(prot:Integer):DWORD;
function _VirtualAlloc (Addr:Pointer;dwSize:PTRUINT;prot:Integer):Integer;
function _VirtualReserve (Addr:Pointer;dwSize:PTRUINT;prot:Integer):Integer;
function _VirtualCommit (Addr:Pointer;dwSize:PTRUINT;prot:Integer):Integer;
function _VirtualDecommit(Addr:Pointer;dwSize:PTRUINT):Integer;
function _VirtualFree (Addr:Pointer):Integer;
function _VirtualMmap (Addr:Pointer;len:size_t;prot,fd:Integer;offst:size_t):Integer;
function _VirtualUnmap (addr:Pointer):Integer;
implementation
const
FILE_MAP_EXECUTE=$0020;
function _isgpu(prot:Integer):Boolean; inline;
begin
Result:=prot and (SCE_KERNEL_PROT_GPU_READ or SCE_KERNEL_PROT_GPU_WRITE)<>0;
end;
function __map_prot_page(prot:Integer):DWORD;
begin
Result:=0;
if (prot=PROT_NONE) then Exit(PAGE_NOACCESS);
if (prot and PROT_EXEC)<>0 then
begin
if (prot and (PROT_WRITE or SCE_KERNEL_PROT_GPU_WRITE))<>0 then
begin
Result:=PAGE_EXECUTE_READWRITE;
end else
if (prot and (PROT_READ or SCE_KERNEL_PROT_GPU_READ))<>0 then
begin
Result:=PAGE_EXECUTE_READ;
end else
begin
Result:=PAGE_EXECUTE;
end;
end else
if (prot and (PROT_WRITE or SCE_KERNEL_PROT_GPU_WRITE))<>0 then
begin
Result:=PAGE_READWRITE;
end else
begin
Result:=PAGE_READONLY;
end;
end;
function __map_prot_file(prot:Integer):DWORD;
begin
Result:= 0;
if (prot=PROT_NONE) then Exit;
if (prot and PROT_READ) <>0 then Result:=Result or FILE_MAP_READ;
if (prot and PROT_WRITE)<>0 then Result:=Result or FILE_MAP_WRITE;
if (prot and PROT_EXEC) <>0 then Result:=Result or FILE_MAP_EXECUTE;
end;
function _VirtualAlloc(Addr:Pointer;dwSize:PTRUINT;prot:Integer):Integer;
begin
Result:=0;
if (Addr=nil) then Exit(-1);
Addr:=VirtualAlloc(Addr,dwSize,MEM_COMMIT or MEM_RESERVE,__map_prot_page(prot));
if (Addr<>nil) then Exit;
Result:=GetLastError;
end;
function _VirtualReserve(Addr:Pointer;dwSize:PTRUINT;prot:Integer):Integer;
begin
Result:=0;
if (Addr=nil) then Exit(-1);
Addr:=VirtualAlloc(Addr,dwSize,MEM_RESERVE,__map_prot_page(prot));
if (Addr<>nil) then Exit;
Result:=GetLastError;
end;
function _VirtualCommit(Addr:Pointer;dwSize:PTRUINT;prot:Integer):Integer;
var
new:Pointer;
begin
Result:=0;
if (Addr=nil) then Exit(-1);
new:=VirtualAlloc(Addr,dwSize,MEM_COMMIT,__map_prot_page(prot));
if (new<>nil) then
begin
Assert(new=Addr);
Exit;
end;
Result:=GetLastError;
end;
function _VirtualDecommit(Addr:Pointer;dwSize:PTRUINT):Integer;
begin
Result:=0;
if (Addr=nil) then Exit(-1);
if (dwSize=0) then Exit;
if not VirtualFree(Addr,dwSize,MEM_DECOMMIT) then
begin
Result:=GetLastError;
end;
end;
function _VirtualFree(Addr:Pointer):Integer;
begin
Result:=0;
if (Addr=nil) then Exit(-1);
if not VirtualFree(Addr,0,MEM_RELEASE) then
begin
Result:=GetLastError;
end;
end;
function _get_osfhandle(fd:Integer):THandle; cdecl; external 'msvcrt';
function MapViewOfFileEx(hFileMappingObject:HANDLE;
dwDesiredAccess:DWORD;
dwFileOffsetHigh:DWORD;
dwFileOffsetLow:DWORD;
dwNumberOfBytesToMap:SIZE_T;
lpBaseAddress:LPVOID):LPVOID; stdcall; external 'kernel32' name 'MapViewOfFileEx';
function _VirtualMmap(Addr:Pointer;len:size_t;prot,fd:Integer;offst:size_t):Integer;
Var
fm,h:THandle;
dwFileOffsetLow,dwFileOffsetHigh,protect,desiredAccess,dwMaxSizeLow,dwMaxSizeHigh:DWORD;
maxSize:size_t;
begin
if (Addr=nil) then Exit(-1);
h:=_get_osfhandle(fd);
if (h=INVALID_HANDLE_VALUE) then
begin
Exit(GetLastError);
end;
maxSize:=offst+len;
dwFileOffsetLow :=DWORD(offst and $FFFFFFFF);
dwFileOffsetHigh:=DWORD(offst shr 32);
dwMaxSizeLow :=DWORD(maxSize and $FFFFFFFF);
dwMaxSizeHigh :=DWORD(maxSize shr 32);
protect :=__map_prot_page(prot);
desiredAccess:=__map_prot_file(prot);
fm:=CreateFileMapping(h,nil,protect,dwMaxSizeHigh,dwMaxSizeLow,nil);
if (fm=0) then
begin
Exit(GetLastError);
end;
addr:=MapViewOfFileEx(fm,desiredAccess,dwFileOffsetHigh,dwFileOffsetLow,len,addr);
CloseHandle(fm);
if (addr=nil) then
begin
Exit(GetLastError);
end;
end;
function _VirtualUnmap(addr:Pointer):Integer;
begin
if (Addr=nil) then Exit(-1);
if UnmapViewOfFile(addr) then
begin
Result:=0;
end else
begin
Result:=GetLastError;
end;
end;
end.