mirror of
https://github.com/red-prig/fpPS4.git
synced 2024-10-07 11:43:21 +00:00
2245 lines
52 KiB
ObjectPascal
2245 lines
52 KiB
ObjectPascal
unit ps4_map_mm;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Windows,
|
|
g23tree,
|
|
RWLock,
|
|
sys_types,
|
|
mmap,
|
|
mm_adr_direct,
|
|
mm_adr_virtual,
|
|
mm_adr_pool,
|
|
Classes,
|
|
SysUtils;
|
|
|
|
{
|
|
Flexible memory: elf sections, stack, calloc, cpu only
|
|
|
|
Direct memory: phisical mapped, cpu/gpu mem
|
|
|
|
Pooled memory: section of direct memory, 64 KiB blocks,
|
|
|
|
The application program can use a total of 5184 MiB (5824 MiB in NEO mode) physical memory.
|
|
|
|
If there is no specification, 448 MiB will be assigned as flexible memory.
|
|
|
|
Physical Address Space and Direct Memory Areas is guaranteed to be aligned to a 2 MiB boundary.
|
|
|
|
|
|
Unmapped area : 0x0000 0000 0000 - 0x0000 0040 0000 Size: 0x0000 0040 0000 (4MB)
|
|
|
|
System managed area : 0x0000 0040 0000 - 0x0007 FFFF C000 Size: 0x0007 FFBF C000 (31GB)
|
|
|
|
System reserved area: 0x0007 FFFF C000 - 0x0010 0000 0000 Size: 0x0008 0000 4000 (32GB)
|
|
|
|
User area : 0x0010 0000 0000 - 0x00FC 0000 0000 Size: 0x00EC 0000 0000 (944GB)
|
|
|
|
System reserved area: 0x00FC 0000 0000 - 0x00FF FFFF FFFF Size: 0x0003 FFFF FFFF (15GB)
|
|
}
|
|
|
|
var
|
|
DirectManager:TDirectManager;
|
|
VirtualManager:TVirtualManager;
|
|
|
|
Const
|
|
SCE_KERNEL_MAIN_DMEM_SIZE=$180000000; //6GB
|
|
|
|
type
|
|
pSceKernelDirectMemoryQueryInfo=^SceKernelDirectMemoryQueryInfo;
|
|
SceKernelDirectMemoryQueryInfo=packed record
|
|
start:QWORD;
|
|
__end:QWORD;
|
|
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
|
|
pSceKernelVirtualQueryInfo=^SceKernelVirtualQueryInfo;
|
|
SceKernelVirtualQueryInfo=packed record
|
|
pstart:Pointer;
|
|
pend :Pointer;
|
|
offset:QWORD;
|
|
protection:Integer;
|
|
memoryType:Integer;
|
|
bits:bitpacked record
|
|
isFlexibleMemory:0..1;
|
|
isDirectMemory :0..1;
|
|
isStack :0..1;
|
|
isPooledMemory :0..1;
|
|
isCommitted :0..1;
|
|
end;
|
|
name:array[0..SCE_KERNEL_VIRTUAL_RANGE_NAME_SIZE-1] of AnsiChar;
|
|
end;
|
|
|
|
function ps4_sceKernelGetDirectMemorySize:Int64; SysV_ABI_CDecl;
|
|
function ps4_getpagesize:Integer; SysV_ABI_CDecl;
|
|
|
|
function ps4_sceKernelAllocateDirectMemory(
|
|
searchStart:QWORD;
|
|
searchEnd:QWORD;
|
|
length:QWORD;
|
|
alignment:QWORD;
|
|
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;
|
|
alignment:QWORD;
|
|
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;
|
|
protections:Integer;
|
|
flags:Integer;
|
|
physicalAddr:QWORD;
|
|
alignment:QWORD):Integer; SysV_ABI_CDecl;
|
|
|
|
function ps4_sceKernelMapNamedFlexibleMemory(
|
|
virtualAddrDest:PPointer;
|
|
length:QWORD;
|
|
protections:Integer;
|
|
flags:Integer;
|
|
name:PChar):Integer; SysV_ABI_CDecl;
|
|
|
|
function ps4_sceKernelMapFlexibleMemory(
|
|
virtualAddrDest:PPointer;
|
|
length:QWORD;
|
|
protections:Integer;
|
|
flags:Integer):Integer; SysV_ABI_CDecl;
|
|
|
|
function ps4_sceKernelMunmap(addr:Pointer;len:size_t):Integer; SysV_ABI_CDecl;
|
|
function ps4_sceKernelQueryMemoryProtection(addr:Pointer;pStart,pEnd:PPointer;pProt:PInteger):Integer; SysV_ABI_CDecl;
|
|
|
|
function ps4_sceKernelVirtualQuery(addr:Pointer;
|
|
flags:Integer;
|
|
info:pSceKernelVirtualQueryInfo;
|
|
infoSize:QWORD):Integer; SysV_ABI_CDecl;
|
|
|
|
function ps4_sceKernelMprotect(addr:Pointer;len:QWORD;prot:Integer):Integer; SysV_ABI_CDecl;
|
|
function ps4_sceKernelSetVirtualRangeName(addr:Pointer;len:QWORD;name:Pchar):Integer; SysV_ABI_CDecl;
|
|
function ps4_mmap(addr:Pointer;len:size_t;prot,flags:Integer;fd:Integer;offset:size_t):Pointer; SysV_ABI_CDecl;
|
|
function ps4_munmap(addr:Pointer;len:size_t):Integer; SysV_ABI_CDecl;
|
|
function ps4_msync(addr:Pointer;len:size_t;flags:Integer):Integer; SysV_ABI_CDecl;
|
|
function ps4_mprotect(addr:Pointer;len:size_t;prot:Integer):Integer; SysV_ABI_CDecl;
|
|
|
|
type
|
|
TGpuMemAlloc=function(addr:Pointer;len:size_t):Pointer;
|
|
TGpuMemFree =procedure(h:Pointer);
|
|
|
|
TGpuMemBlock=record
|
|
pAddr:Pointer;
|
|
nSize:Int64;
|
|
Handle:Pointer;
|
|
end;
|
|
|
|
TGpuMemCb=record
|
|
Alloc:TGpuMemAlloc;
|
|
Free :TGpuMemFree;
|
|
end;
|
|
|
|
var
|
|
GpuMemCb:TGpuMemCb;
|
|
|
|
Function TryGetGpuMemBlockByAddr(addr:Pointer;var block:TGpuMemBlock):Boolean;
|
|
Procedure RegistredStack;
|
|
Procedure UnRegistredStack;
|
|
|
|
implementation
|
|
|
|
uses
|
|
sys_kernel,
|
|
sys_signal;
|
|
|
|
const
|
|
INVALID_DIRECT=QWORD(-1);
|
|
|
|
BT_STACK =0;
|
|
BT_DIRECT_BIG=1;
|
|
BT_DIRECT_64K=2;
|
|
BT_PHYSIC_BIG=3;
|
|
BT_PHYSIC_64K=4;
|
|
|
|
BS_FREE =0;
|
|
BS_RESERVE=1;
|
|
BS_COMMIT =2;
|
|
|
|
type
|
|
PBlock=^TBlock;
|
|
TBlock=object
|
|
pAddr:Pointer;
|
|
nSize:Int64;
|
|
bType:SizeUint;
|
|
end;
|
|
|
|
pdlist=^Tdlist;
|
|
|
|
Pdnode=^Tdnode;
|
|
Tdnode=object
|
|
pPrev,pNext:Pdnode;
|
|
end;
|
|
|
|
Tdlist=object
|
|
pHead,pTail:Pdnode;
|
|
function REMOVE_HEAD:Pdnode; inline;
|
|
procedure INSERT_TAIL(e:Pdnode); inline;
|
|
procedure REMOVE(e:Pdnode); inline;
|
|
end;
|
|
|
|
TnodeInfo=bitpacked record
|
|
id:Byte;
|
|
prot:Byte;
|
|
state:Byte;
|
|
len:Byte;
|
|
align2:DWORD;
|
|
end;
|
|
|
|
PdnodeAdr=^TdnodeAdr;
|
|
TdnodeAdr=object(Tdnode)
|
|
direct:QWORD;
|
|
info:TnodeInfo;
|
|
end;
|
|
|
|
PBlockBig=^TBlockBig;
|
|
TBlockBig=object(TBlock)
|
|
direct:QWORD;
|
|
Handle:Pointer;
|
|
prot:Byte;
|
|
end;
|
|
|
|
PBlock64k=^TBlock64k;
|
|
TBlock64k=object(TBlock)
|
|
nodes:array[0..3] of TdnodeAdr;
|
|
end;
|
|
|
|
function IsPowerOfTwo(x:QWORD):Boolean; inline;
|
|
begin
|
|
Result:=(x and (x - 1))=0;
|
|
end;
|
|
|
|
function fastIntLog2(i:QWORD):QWORD; inline;
|
|
begin
|
|
Result:=BsfQWORD(i);
|
|
end;
|
|
|
|
function str_mem_type(memoryType:Integer):RawByteString;
|
|
begin
|
|
Result:='';
|
|
Case memoryType of
|
|
SCE_KERNEL_WB_ONION :Result:='WB_ONION';
|
|
SCE_KERNEL_WC_GARLIC:Result:='WC_GARLIC';
|
|
SCE_KERNEL_WB_GARLIC:Result:='WB_GARLIC';
|
|
else
|
|
Result:=IntToStr(memoryType);
|
|
end;
|
|
end;
|
|
|
|
function test_KP_flags(flags:Integer):RawByteString;
|
|
begin
|
|
Result:='';
|
|
if (flags and SCE_KERNEL_PROT_CPU_READ) <>0 then Result:=Result+' CPU_READ';
|
|
if (flags and SCE_KERNEL_PROT_CPU_WRITE)<>0 then Result:=Result+' CPU_WRIT';
|
|
if (flags and SCE_KERNEL_PROT_CPU_EXEC) <>0 then Result:=Result+' CPU_EXEC';
|
|
if (flags and SCE_KERNEL_PROT_GPU_READ) <>0 then Result:=Result+' GPU_READ';
|
|
if (flags and SCE_KERNEL_PROT_GPU_WRITE)<>0 then Result:=Result+' GPU_WRIT';
|
|
end;
|
|
|
|
//
|
|
|
|
function Get16kBlockCount(len:PTRUINT):PTRUINT; inline;
|
|
begin
|
|
Result:=len div LOGICAL_PAGE_SIZE;
|
|
end;
|
|
|
|
function Get4kBlockCount(len:PTRUINT):PTRUINT; inline;
|
|
begin
|
|
Result:=len div PHYSICAL_PAGE_SIZE;
|
|
end;
|
|
|
|
//
|
|
|
|
function VirtualAllocAlign(Addr:Pointer;dwSize,alignment:PTRUINT;flAllocationType,flProtect:DWORD):Pointer;
|
|
begin
|
|
Result:=nil;
|
|
if (alignment<=GRANULAR_PAGE_SIZE) or (Addr<>nil) then
|
|
begin
|
|
Result:=VirtualAlloc(Addr,dwSize,flAllocationType,flProtect);
|
|
Exit;
|
|
end;
|
|
Addr:=Pointer($5400000);
|
|
Addr:=AlignUp(Addr,alignment);
|
|
repeat
|
|
Result:=VirtualAlloc(Addr,dwSize,flAllocationType,flProtect);
|
|
if (Result<>nil) then Exit;
|
|
Case GetLastError of
|
|
ERROR_INVALID_ADDRESS:;
|
|
else
|
|
Exit;
|
|
end;
|
|
Addr:=Addr+alignment;
|
|
until false;
|
|
end;
|
|
|
|
function VirtualQueryBase(Addr:Pointer):TBlock;
|
|
var
|
|
Info:TMemoryBasicInformation;
|
|
begin
|
|
Result:=Default(TBlock);
|
|
Info:=Default(TMemoryBasicInformation);
|
|
if (VirtualQuery(addr,Info,SizeOf(TMemoryBasicInformation))<>0) then
|
|
begin
|
|
Case Info.State of
|
|
MEM_FREE :Result.bType:=BS_FREE;
|
|
MEM_COMMIT :Result.bType:=BS_COMMIT;
|
|
MEM_RESERVE:Result.bType:=BS_RESERVE;
|
|
end;
|
|
Result.pAddr:=Info.AllocationBase;
|
|
Result.nSize:=Info.RegionSize+(ptruint(Info.BaseAddress)-ptruint(Info.AllocationBase));
|
|
end;
|
|
end;
|
|
|
|
function VirtualIsFullReserve(Addr:Pointer;dwSize:PTRUINT):Boolean;
|
|
var
|
|
curr:Pointer;
|
|
q:TBlock;
|
|
begin
|
|
Result:=True;
|
|
curr:=Addr;
|
|
While (curr<Addr+dwSize) do
|
|
begin
|
|
q:=VirtualQueryBase(curr);
|
|
Case q.bType of
|
|
BS_FREE:
|
|
begin
|
|
curr:=q.pAddr+q.nSize;
|
|
end;
|
|
BS_RESERVE:curr:=curr+PHYSICAL_PAGE_SIZE;
|
|
BS_COMMIT:Exit(False);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
///
|
|
|
|
function Tdlist.REMOVE_HEAD:Pdnode; inline;
|
|
begin
|
|
Result:=pHead;
|
|
if (pHead<>nil) then
|
|
begin
|
|
pHead:=pHead^.pNext;
|
|
if (pHead<>nil) then
|
|
begin
|
|
pHead^.pPrev:=nil;
|
|
end else
|
|
begin
|
|
pTail:=nil;
|
|
end;
|
|
Result^.pPrev:=nil;
|
|
Result^.pNext:=nil;
|
|
end;
|
|
end;
|
|
|
|
procedure Tdlist.INSERT_TAIL(e:Pdnode); inline;
|
|
begin
|
|
if (e=nil) then Exit;
|
|
if (e^.pPrev<>nil) or (e^.pNext<>nil) then Exit;
|
|
if (pHead=nil) then
|
|
begin
|
|
pHead:=e;
|
|
end else
|
|
begin
|
|
pTail^.pNext:=e;
|
|
e^.pPrev:=pTail;
|
|
end;
|
|
pTail:=e;
|
|
end;
|
|
|
|
procedure Tdlist.REMOVE(e:Pdnode); inline;
|
|
var
|
|
p,n:Pdnode;
|
|
begin
|
|
if (e=nil) then Exit;
|
|
if (pHead=e) then
|
|
begin
|
|
pHead:=pHead^.pNext;
|
|
if (pHead=nil) then pTail:=nil;
|
|
end else
|
|
if (pTail=e) then
|
|
begin
|
|
pTail:=pTail^.pPrev;
|
|
if (pTail=nil) then pHead:=nil;
|
|
end else
|
|
begin
|
|
p:=e^.pPrev;
|
|
n:=e^.pNext;
|
|
if (p<>nil) then p^.pNext:=n;
|
|
if (n<>nil) then n^.pPrev:=p;
|
|
end;
|
|
e^.pPrev:=nil;
|
|
e^.pNext:=nil;
|
|
end;
|
|
|
|
type
|
|
TBlockCompare=object
|
|
function c(const a,b:PBlock):Integer; static;
|
|
end;
|
|
|
|
function TBlockCompare.c(const a,b:PBlock):Integer; static;
|
|
begin
|
|
if (a^.pAddr=b^.pAddr) then
|
|
Result:=0
|
|
else
|
|
if (a^.pAddr<b^.pAddr) then
|
|
Result:=-1
|
|
else
|
|
Result:=1;
|
|
end;
|
|
|
|
type
|
|
TMemDirectAdrCompare=object
|
|
function c(const a,b:TBlock):Integer; static;
|
|
end;
|
|
|
|
function TMemDirectAdrCompare.c(const a,b:TBlock):Integer; static;
|
|
begin
|
|
if (a.pAddr=b.pAddr) then
|
|
Result:=0
|
|
else
|
|
if (a.pAddr<b.pAddr) then
|
|
Result:=-1
|
|
else
|
|
Result:=1;
|
|
end;
|
|
|
|
type
|
|
TDirectAdrSet=specialize T23treeSet<TBlock,TMemDirectAdrCompare>;
|
|
|
|
type
|
|
TBlockSet=specialize T23treeSet<PBlock,TBlockCompare>;
|
|
|
|
TPageMM=object
|
|
var
|
|
FLock:TRWLock;
|
|
|
|
FDirectSize:QWORD;
|
|
//FDirectAdrSet:TDirectAdrSet;
|
|
|
|
FMapBlockSet:TBlockSet;
|
|
|
|
//direct,num ,len
|
|
Falign:array[Boolean,0..3,1..3] of Tdlist;
|
|
|
|
Procedure Init;
|
|
|
|
function _new_big_block_d(addr:Pointer;len,alignment,direct:size_t;prot:Byte):Pointer;
|
|
function _new_64k_block_d(addr:Pointer;len,alignment,direct:size_t;prot:Byte):Pointer;
|
|
function _isfree_64k_block_d(block:PBlock64k):Boolean;
|
|
procedure _unmap_64k_block_d(block:PBlock64k);
|
|
procedure _map_64k_block_d(block:PBlock64k);
|
|
function _alloc_part_d(len,alignment,direct:size_t;prot:Byte):Pointer;
|
|
function _TryGetMapBlockByAddr(addr:Pointer;var _pblock:PBlock):Boolean;
|
|
procedure _DeleteBlockByAddr(addr:Pointer);
|
|
function _check_fixed(addr:Pointer;len:size_t;overwrite:Boolean):Boolean;
|
|
function _free_fixed(addr:Pointer;len:size_t):Boolean;
|
|
function _commit_fixed_d(addr:Pointer;len,direct:size_t;prot:Byte):Boolean;
|
|
|
|
function mmap_d(addr:Pointer;len,alignment,direct:size_t;prot:Byte;overwrite:Boolean):Pointer;
|
|
|
|
function unmap(addr:Pointer;len:size_t):Boolean;
|
|
|
|
function QueryProt(addr:Pointer;pStart,pEnd:PPointer;pProt:PInteger):Boolean;
|
|
function ChangeProt(addr:Pointer;len:QWORD;prot:Integer):Boolean;
|
|
end;
|
|
|
|
Procedure TPageMM.Init;
|
|
begin
|
|
FillChar(Self,SizeOf(TPageMM),0);
|
|
rwlock_init(FLock);
|
|
end;
|
|
|
|
function TPageMM._new_big_block_d(addr:Pointer;len,alignment,direct:size_t;prot:Byte):Pointer;
|
|
var
|
|
base:Pointer;
|
|
block:PBlockBig;
|
|
begin
|
|
Result:=nil;
|
|
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
|
|
begin
|
|
VirtualFree(base,0,MEM_RELEASE);
|
|
Exit;
|
|
end;
|
|
block^.pAddr:=base;
|
|
block^.nSize:=len;
|
|
block^.bType:=BT_DIRECT_BIG;
|
|
block^.direct:=direct;
|
|
block^.prot:=prot;
|
|
if _isgpu(prot) and (GpuMemCb.Alloc<>nil) then
|
|
begin
|
|
block^.Handle:=GpuMemCb.Alloc(base,len);
|
|
end;
|
|
Assert(block<>nil);
|
|
FMapBlockSet.Insert(block);
|
|
Result:=base;
|
|
end;
|
|
|
|
function TPageMM._new_64k_block_d(addr:Pointer;len,alignment,direct:size_t;prot:Byte):Pointer;
|
|
var
|
|
base:Pointer;
|
|
block:PBlock64k;
|
|
i,c:Byte;
|
|
begin
|
|
Result:=nil;
|
|
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);
|
|
end;
|
|
if (base=nil) then Exit;
|
|
block:=AllocMem(SizeOf(TBlock64k));
|
|
if (block=nil) then
|
|
begin
|
|
VirtualFree(base,0,MEM_RELEASE);
|
|
Exit;
|
|
end;
|
|
block^.pAddr:=base;
|
|
block^.nSize:=GRANULAR_PAGE_SIZE;
|
|
block^.bType:=BT_DIRECT_64K;
|
|
|
|
For i:=0 to 3 do
|
|
begin
|
|
if (direct=INVALID_DIRECT) then
|
|
begin
|
|
block^.nodes[i].direct:=INVALID_DIRECT;
|
|
end else
|
|
begin
|
|
block^.nodes[i].direct:=direct+(i*LOGICAL_PAGE_SIZE);
|
|
end;
|
|
block^.nodes[i].info.id:=i;
|
|
block^.nodes[i].info.prot:=prot;
|
|
block^.nodes[i].info.state:=BS_COMMIT;
|
|
end;
|
|
|
|
c:=Get16kBlockCount(len);
|
|
if (c<4) then
|
|
begin
|
|
For i:=c to 3 do
|
|
begin
|
|
block^.nodes[i].direct:=0;
|
|
block^.nodes[i].info.prot:=0;
|
|
block^.nodes[i].info.state:=BS_FREE;
|
|
end;
|
|
_map_64k_block_d(block);
|
|
end;
|
|
|
|
Assert(block<>nil);
|
|
FMapBlockSet.Insert(block);
|
|
Result:=base;
|
|
end;
|
|
|
|
function TPageMM._isfree_64k_block_d(block:PBlock64k):Boolean;
|
|
var
|
|
i:Byte;
|
|
begin
|
|
Result:=True;
|
|
For i:=0 to 3 do
|
|
begin
|
|
if (block^.nodes[i].info.state=BS_COMMIT) then Exit(false);
|
|
end;
|
|
end;
|
|
|
|
procedure TPageMM._unmap_64k_block_d(block:PBlock64k);
|
|
var
|
|
i:Byte;
|
|
begin
|
|
For i:=0 to 3 do
|
|
begin
|
|
Falign[block^.nodes[i].direct<>INVALID_DIRECT,
|
|
i,
|
|
block^.nodes[i].info.len].
|
|
REMOVE(@block^.nodes[i]);
|
|
end;
|
|
end;
|
|
|
|
procedure TPageMM._map_64k_block_d(block:PBlock64k);
|
|
var
|
|
ip,ic:Byte;
|
|
begin
|
|
ip:=0;
|
|
While (ip<=3) do
|
|
begin
|
|
if (block^.nodes[ip].info.state<>BS_COMMIT) then
|
|
begin
|
|
ic:=1;
|
|
While (ip+ic<=3) do
|
|
begin
|
|
if (block^.nodes[ip+ic].info.state<>BS_COMMIT) then
|
|
Inc(ic)
|
|
else
|
|
Break;
|
|
end;
|
|
block^.nodes[ip].info.len:=ic;
|
|
Falign[block^.nodes[ip].direct<>INVALID_DIRECT,ip,ic].INSERT_TAIL(@block^.nodes[ip]);
|
|
end;
|
|
Inc(ip);
|
|
end;
|
|
end;
|
|
|
|
// //num ,len
|
|
// Falign_d:array[0..3,1..3] of Tdlist;
|
|
|
|
function TPageMM._alloc_part_d(len,alignment,direct:size_t;prot:Byte):Pointer;
|
|
var
|
|
block:PBlock64k;
|
|
node:PdnodeAdr;
|
|
i,b,n,count:Byte;
|
|
|
|
function _find_by_len_16(len:Byte):PdnodeAdr;
|
|
var
|
|
i:Byte;
|
|
begin
|
|
Result:=nil;
|
|
For i:=0 to 3 do
|
|
begin
|
|
Result:=PdnodeAdr(Falign[direct<>INVALID_DIRECT,i,len].REMOVE_HEAD);
|
|
if (Result<>nil) then Break;
|
|
end;
|
|
end;
|
|
|
|
function _find_by_len_32(len:Byte):PdnodeAdr;
|
|
begin
|
|
Result:=PdnodeAdr(Falign[direct<>INVALID_DIRECT,0,len].REMOVE_HEAD);
|
|
if (Result<>nil) then Exit;
|
|
Result:=PdnodeAdr(Falign[direct<>INVALID_DIRECT,2,len].REMOVE_HEAD);
|
|
end;
|
|
|
|
begin
|
|
count:=Get16kBlockCount(len);
|
|
|
|
node:=nil;
|
|
if (alignment<=16*1024) then
|
|
begin //16k
|
|
node:=_find_by_len_16(count);
|
|
end else
|
|
if (alignment<=32*1024) then
|
|
begin //32k
|
|
node:=_find_by_len_32(count);
|
|
if (node=nil) and (count<=2) then
|
|
begin
|
|
node:=PdnodeAdr(Falign[direct<>INVALID_DIRECT,1,count].REMOVE_HEAD);
|
|
if (node<>nil) then Inc(node);
|
|
end;
|
|
end else
|
|
begin //64k
|
|
node:=PdnodeAdr(Falign[direct<>INVALID_DIRECT,0,count].REMOVE_HEAD);
|
|
end;
|
|
|
|
if (node=nil) then //not found
|
|
begin
|
|
Result:=_new_64k_block_d(nil,len,alignment,direct,prot);
|
|
end else
|
|
begin
|
|
b:=node^.info.id;
|
|
block:=Pointer(PtrUint(@node[-b])-PtrUint(@PBlock64k(nil)^.nodes));
|
|
|
|
n:=b+count-1;
|
|
|
|
For i:=b to n do
|
|
begin
|
|
if (direct=INVALID_DIRECT) then
|
|
begin
|
|
block^.nodes[i].direct:=INVALID_DIRECT;
|
|
end else
|
|
begin
|
|
block^.nodes[i].direct:=direct+((i-b)*LOGICAL_PAGE_SIZE);
|
|
end;
|
|
block^.nodes[i].info.prot:=prot;
|
|
block^.nodes[i].info.state:=BS_COMMIT;
|
|
block^.nodes[i].info.len:=0;
|
|
end;
|
|
|
|
_map_64k_block_d(block);
|
|
|
|
Result:=block^.pAddr+(b*LOGICAL_PAGE_SIZE);
|
|
Result:=VirtualAlloc(Result,len,MEM_COMMIT,__map_prot_page(prot));
|
|
end;
|
|
end;
|
|
|
|
function TPageMM._TryGetMapBlockByAddr(addr:Pointer;var _pblock:PBlock):Boolean;
|
|
var
|
|
It:TBlockSet.Iterator;
|
|
i:Integer;
|
|
begin
|
|
Result:=False;
|
|
It:=FMapBlockSet.find_le(@addr);
|
|
//if (It.Item=nil) then Exit;
|
|
|
|
if (It.Item=nil) then
|
|
begin
|
|
Writeln('Memory dump:',HexStr(addr));
|
|
It:=FMapBlockSet.cbegin;
|
|
While (It.Item<>nil) do
|
|
begin
|
|
_pblock:=It.Item^;
|
|
if (_pblock<>nil) then
|
|
begin
|
|
Case _pblock^.bType of
|
|
BT_STACK:
|
|
begin
|
|
Writeln('[BT_STACK]');
|
|
Writeln(' pAddr:',HexStr(_pblock^.pAddr));
|
|
Writeln(' nSize:',HexStr(_pblock^.nSize,16));
|
|
end;
|
|
BT_DIRECT_BIG:
|
|
begin
|
|
Writeln('[BT_DIRECT_BIG]');
|
|
Writeln(' pAddr:',HexStr(_pblock^.pAddr));
|
|
Writeln(' nSize:',HexStr(_pblock^.nSize,16));
|
|
Writeln(' direct:',HexStr(PBlockBig(_pblock)^.direct,16));
|
|
Writeln(' Handle:',HexStr(PBlockBig(_pblock)^.Handle));
|
|
Writeln(' prot:',test_KP_flags(PBlockBig(_pblock)^.prot));
|
|
end;
|
|
BT_DIRECT_64K:
|
|
begin
|
|
Writeln('[BT_DIRECT_64K]');
|
|
Writeln(' pAddr:',HexStr(_pblock^.pAddr));
|
|
Writeln(' nSize:',HexStr(_pblock^.nSize,16));
|
|
|
|
For i:=0 to 3 do
|
|
begin
|
|
Writeln(' [node]:',i);
|
|
Writeln(' direct:' ,HexStr(PBlock64k(_pblock)^.nodes[i].direct,16));
|
|
Writeln(' info.id:' ,HexStr(PBlock64k(_pblock)^.nodes[i].info.id,2));
|
|
Writeln(' info.prot:' ,test_KP_flags(PBlock64k(_pblock)^.nodes[i].info.prot));
|
|
Writeln(' info.state:',PBlock64k(_pblock)^.nodes[i].info.state);
|
|
Writeln(' info.len:' ,PBlock64k(_pblock)^.nodes[i].info.len);
|
|
end;
|
|
|
|
end;
|
|
BT_PHYSIC_BIG:
|
|
begin
|
|
Writeln('[BT_PHYSIC_BIG]');
|
|
Writeln(' pAddr:',HexStr(_pblock^.pAddr));
|
|
Writeln(' nSize:',HexStr(_pblock^.nSize,16));
|
|
end;
|
|
BT_PHYSIC_64K:
|
|
begin
|
|
Writeln('[BT_PHYSIC_64K]');
|
|
Writeln(' pAddr:',HexStr(_pblock^.pAddr));
|
|
Writeln(' nSize:',HexStr(_pblock^.nSize,16));
|
|
end;
|
|
|
|
else;
|
|
end;
|
|
end;
|
|
|
|
It.Next;
|
|
end;
|
|
Writeln('------------');
|
|
Assert(false);
|
|
Exit;
|
|
end;
|
|
|
|
_pblock:=It.Item^;
|
|
if (_pblock=nil) then Exit;
|
|
if (_pblock^.pAddr>addr) or (_pblock^.pAddr+_pblock^.nSize<=addr) then
|
|
begin
|
|
_pblock:=nil;
|
|
Exit;
|
|
end;
|
|
Result:=True;
|
|
end;
|
|
|
|
procedure TPageMM._DeleteBlockByAddr(addr:Pointer);
|
|
var
|
|
It:TBlockSet.Iterator;
|
|
_pblock:PBlock;
|
|
begin
|
|
It:=FMapBlockSet.find(@addr);
|
|
if (It.Item=nil) then Exit;
|
|
_pblock:=It.Item^;
|
|
FMapBlockSet.erase(It);
|
|
if (_pblock<>nil) then FreeMem(_pblock);
|
|
end;
|
|
|
|
function TPageMM._check_fixed(addr:Pointer;len:size_t;overwrite:Boolean):Boolean;
|
|
var
|
|
curr:Pointer;
|
|
q:TBlock;
|
|
_pblock:PBlock;
|
|
begin
|
|
Result:=true;
|
|
curr:=addr;
|
|
repeat
|
|
q:=VirtualQueryBase(curr);
|
|
Case q.bType of
|
|
BS_FREE:
|
|
begin
|
|
curr:=q.pAddr+q.nSize;
|
|
end;
|
|
BS_RESERVE,
|
|
BS_COMMIT:
|
|
begin
|
|
if (q.bType=BS_COMMIT) and (not overwrite) then Exit(False);
|
|
|
|
if not _TryGetMapBlockByAddr(curr,_pblock) then Exit;
|
|
|
|
Case _pblock^.bType of
|
|
BT_DIRECT_BIG,
|
|
BT_DIRECT_64K:
|
|
begin
|
|
curr:=curr+LOGICAL_PAGE_SIZE;
|
|
end;
|
|
BT_PHYSIC_BIG,
|
|
BT_PHYSIC_64K:
|
|
begin
|
|
curr:=curr+PHYSICAL_PAGE_SIZE;
|
|
end;
|
|
else
|
|
Exit(False);
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
until (curr>=addr+len);
|
|
end;
|
|
|
|
function TPageMM._free_fixed(addr:Pointer;len:size_t):Boolean;
|
|
var
|
|
curr:Pointer;
|
|
q:TBlock;
|
|
_pblock:PBlock;
|
|
i:Byte;
|
|
begin
|
|
Result:=true;
|
|
curr:=addr;
|
|
repeat
|
|
q:=VirtualQueryBase(curr);
|
|
Case q.bType of
|
|
BS_FREE:
|
|
begin
|
|
curr:=q.pAddr+q.nSize;
|
|
end;
|
|
BS_RESERVE,
|
|
BS_COMMIT:
|
|
begin
|
|
if not _TryGetMapBlockByAddr(curr,_pblock) then Exit;
|
|
|
|
Case _pblock^.bType of
|
|
BT_DIRECT_BIG:
|
|
begin
|
|
if (curr=q.pAddr) and (_pblock^.pAddr=q.pAddr) and (_pblock^.nSize=q.nSize) then
|
|
begin
|
|
if _isgpu(PBlockBig(_pblock)^.prot) and (GpuMemCb.Free<>nil) then
|
|
begin
|
|
GpuMemCb.Free(PBlockBig(_pblock)^.Handle);
|
|
end;
|
|
if not VirtualFree(q.pAddr,0,MEM_RELEASE) then Exit(False);
|
|
_DeleteBlockByAddr(q.pAddr);
|
|
curr:=q.pAddr+q.nSize;
|
|
end else
|
|
begin
|
|
VirtualFree(curr,LOGICAL_PAGE_SIZE,MEM_DECOMMIT);
|
|
curr:=curr+LOGICAL_PAGE_SIZE;
|
|
if VirtualIsFullReserve(q.pAddr,q.nSize) then
|
|
begin
|
|
if _isgpu(PBlockBig(_pblock)^.prot) and (GpuMemCb.Free<>nil) then
|
|
begin
|
|
GpuMemCb.Free(PBlockBig(_pblock)^.Handle);
|
|
end;
|
|
if not VirtualFree(q.pAddr,0,MEM_RELEASE) then Exit(False);
|
|
_DeleteBlockByAddr(q.pAddr);
|
|
curr:=q.pAddr+q.nSize;
|
|
end;
|
|
end;
|
|
end;
|
|
BT_PHYSIC_BIG:
|
|
begin
|
|
if (curr=q.pAddr) and (_pblock^.pAddr=q.pAddr) and (_pblock^.nSize=q.nSize) then
|
|
begin
|
|
if not VirtualFree(q.pAddr,0,MEM_RELEASE) then Exit(False);
|
|
_DeleteBlockByAddr(q.pAddr);
|
|
curr:=q.pAddr+q.nSize;
|
|
end else
|
|
begin
|
|
VirtualFree(curr,PHYSICAL_PAGE_SIZE,MEM_DECOMMIT);
|
|
curr:=curr+PHYSICAL_PAGE_SIZE;
|
|
if VirtualIsFullReserve(q.pAddr,q.nSize) then
|
|
begin
|
|
if not VirtualFree(q.pAddr,0,MEM_RELEASE) then Exit(False);
|
|
_DeleteBlockByAddr(q.pAddr);
|
|
curr:=q.pAddr+q.nSize;
|
|
end;
|
|
end;
|
|
end;
|
|
BT_DIRECT_64K:
|
|
if (q.bType=BS_COMMIT) then
|
|
begin
|
|
VirtualFree(curr,LOGICAL_PAGE_SIZE,MEM_DECOMMIT);
|
|
i:=Get16kBlockCount(curr-_pblock^.pAddr);
|
|
_unmap_64k_block_d(PBlock64k(_pblock));
|
|
if PBlock64k(_pblock)^.nodes[i].direct<>INVALID_DIRECT then
|
|
begin
|
|
PBlock64k(_pblock)^.nodes[i].direct:=0;
|
|
end;
|
|
PBlock64k(_pblock)^.nodes[i].info.prot:=0;
|
|
PBlock64k(_pblock)^.nodes[i].info.state:=BS_FREE;
|
|
if _isfree_64k_block_d(PBlock64k(_pblock)) then
|
|
begin
|
|
if not VirtualFree(_pblock^.pAddr,0,MEM_RELEASE) then Exit(False);
|
|
q.pAddr:=_pblock^.pAddr;
|
|
_DeleteBlockByAddr(q.pAddr);
|
|
end else
|
|
begin
|
|
_map_64k_block_d(PBlock64k(_pblock));
|
|
end;
|
|
curr:=curr+LOGICAL_PAGE_SIZE;
|
|
end else
|
|
begin
|
|
curr:=curr+LOGICAL_PAGE_SIZE;
|
|
end;
|
|
BT_PHYSIC_64K:Assert(False);
|
|
else
|
|
Exit(False);
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
until (curr>=addr+len);
|
|
end;
|
|
|
|
function TPageMM._commit_fixed_d(addr:Pointer;len,direct:size_t;prot:Byte):Boolean;
|
|
var
|
|
base:Pointer;
|
|
curr:Pointer;
|
|
q:TBlock;
|
|
_pblock:PBlock;
|
|
i:Byte;
|
|
begin
|
|
Result:=true;
|
|
curr:=addr;
|
|
repeat
|
|
q:=VirtualQueryBase(curr);
|
|
Case q.bType of
|
|
BS_FREE:
|
|
begin
|
|
base:=curr;
|
|
curr:=q.pAddr+q.nSize;
|
|
if (curr>addr+len) then curr:=addr+len;
|
|
if _new_big_block_d(base,curr-base,0,direct,prot)=nil then Exit(False);
|
|
if (direct<>INVALID_DIRECT) then
|
|
begin
|
|
direct:=direct+(curr-base);
|
|
end;
|
|
end;
|
|
BS_RESERVE:
|
|
begin
|
|
if not _TryGetMapBlockByAddr(curr,_pblock) then Exit;
|
|
|
|
Case _pblock^.bType of
|
|
BT_DIRECT_BIG:
|
|
begin
|
|
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
|
|
direct:=direct+LOGICAL_PAGE_SIZE;
|
|
end;
|
|
end;
|
|
BT_PHYSIC_BIG:
|
|
begin
|
|
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
|
|
direct:=direct+PHYSICAL_PAGE_SIZE;
|
|
end;
|
|
end;
|
|
BT_DIRECT_64K:
|
|
begin
|
|
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;
|
|
PBlock64k(_pblock)^.nodes[i].info.prot:=prot;
|
|
PBlock64k(_pblock)^.nodes[i].info.state:=BS_COMMIT;
|
|
_map_64k_block_d(PBlock64k(_pblock));
|
|
curr:=curr+LOGICAL_PAGE_SIZE;
|
|
if (direct<>INVALID_DIRECT) then
|
|
begin
|
|
direct:=direct+LOGICAL_PAGE_SIZE;
|
|
end;
|
|
end;
|
|
BT_PHYSIC_64K:Assert(False);
|
|
else
|
|
Exit(False);
|
|
end;
|
|
end;
|
|
BS_COMMIT:Exit(False);
|
|
end;
|
|
|
|
until (curr>=addr+len);
|
|
end;
|
|
|
|
function TPageMM.mmap_d(addr:Pointer;len,alignment,direct:size_t;prot:Byte;overwrite:Boolean):Pointer;
|
|
begin
|
|
Result:=nil;
|
|
rwlock_wrlock(FLock);
|
|
|
|
if _isgpu(prot) then
|
|
begin
|
|
Result:=_new_big_block_d(addr,len,alignment,direct,prot);
|
|
end else
|
|
if (addr<>nil) then //fixed adr
|
|
begin
|
|
if _check_fixed(addr,len,overwrite) then
|
|
begin
|
|
if _free_fixed(addr,len) then
|
|
begin
|
|
if _commit_fixed_d(addr,len,direct,prot) then
|
|
Result:=addr;
|
|
end;
|
|
end;
|
|
end else
|
|
begin //any addr
|
|
if (alignment<=GRANULAR_PAGE_SIZE) and (len<=GRANULAR_PAGE_SIZE) then //64k block
|
|
begin
|
|
if (len=GRANULAR_PAGE_SIZE) then //full
|
|
begin
|
|
Result:=_new_64k_block_d(addr,len,alignment,direct,prot);
|
|
end else
|
|
begin
|
|
Result:=_alloc_part_d(len,alignment,direct,prot);
|
|
end;
|
|
end else
|
|
if (len<=GRANULAR_PAGE_SIZE) then //64k but big aligned
|
|
begin
|
|
Result:=_new_64k_block_d(addr,len,alignment,direct,prot);
|
|
end else
|
|
begin //big block
|
|
Result:=_new_big_block_d(addr,len,alignment,direct,prot);
|
|
end;
|
|
end;
|
|
|
|
rwlock_unlock(FLock);
|
|
end;
|
|
|
|
function TPageMM.unmap(addr:Pointer;len:size_t):Boolean;
|
|
begin
|
|
Result:=false;
|
|
rwlock_wrlock(FLock);
|
|
|
|
Result:=_check_fixed(addr,len,true);
|
|
if Result then
|
|
begin
|
|
Result:=_free_fixed(addr,len);
|
|
end;
|
|
|
|
rwlock_unlock(FLock);
|
|
end;
|
|
|
|
function TPageMM.QueryProt(addr:Pointer;pStart,pEnd:PPointer;pProt:PInteger):Boolean;
|
|
var
|
|
_pblock:PBlock;
|
|
i,b,e:Byte;
|
|
begin
|
|
Result:=False;
|
|
rwlock_rdlock(FLock);
|
|
|
|
if _TryGetMapBlockByAddr(addr,_pblock) then
|
|
begin
|
|
Result:=True;
|
|
Case _pblock^.bType of
|
|
BT_DIRECT_BIG,
|
|
BT_PHYSIC_BIG:
|
|
begin
|
|
if (pStart<>nil) then pStart^:=_pblock^.pAddr;
|
|
if (pEnd<>nil) then pEnd^ :=_pblock^.pAddr+_pblock^.nSize-1;
|
|
if (pProt<>nil) then pProt^ :=PBlockBig(_pblock)^.prot;
|
|
end;
|
|
BT_DIRECT_64K:
|
|
begin
|
|
i:=Get16kBlockCount(addr-_pblock^.pAddr);
|
|
b:=i;
|
|
repeat
|
|
if (b=0) then Break;
|
|
if (PBlock64k(_pblock)^.nodes[b-1].info.state<>PBlock64k(_pblock)^.nodes[i].info.state) then Break;
|
|
if (PBlock64k(_pblock)^.nodes[b-1].info.prot<>PBlock64k(_pblock)^.nodes[i].info.prot) then Break;
|
|
Dec(b);
|
|
until false;
|
|
e:=i;
|
|
repeat
|
|
if (e=3) then Break;
|
|
if (PBlock64k(_pblock)^.nodes[e+1].info.state<>PBlock64k(_pblock)^.nodes[i].info.state) then Break;
|
|
if (PBlock64k(_pblock)^.nodes[e+1].info.prot<>PBlock64k(_pblock)^.nodes[i].info.prot) then Break;
|
|
Inc(e);
|
|
until false;
|
|
if (pStart<>nil) then pStart^:=_pblock^.pAddr+(b*LOGICAL_PAGE_SIZE);
|
|
if (pEnd<>nil) then pEnd^ :=_pblock^.pAddr+(e*LOGICAL_PAGE_SIZE)-1;
|
|
if (pProt<>nil) then pProt^ := PBlock64k(_pblock)^.nodes[i].info.prot;
|
|
end;
|
|
BT_PHYSIC_64K:Assert(False);
|
|
end;
|
|
end;
|
|
|
|
rwlock_unlock(FLock);
|
|
end;
|
|
|
|
function __mprotect(addr:Pointer;len:size_t;prot:Integer):Integer;
|
|
Var
|
|
newprotect,oldprotect:DWORD;
|
|
begin
|
|
newprotect:=__map_prot_page(prot);
|
|
oldprotect:=0;
|
|
|
|
if not VirtualProtect(addr,len,newprotect,oldprotect) then
|
|
begin
|
|
Exit(-1);
|
|
end;
|
|
|
|
Result:=0;
|
|
end;
|
|
|
|
function TPageMM.ChangeProt(addr:Pointer;len:QWORD;prot:Integer):Boolean;
|
|
var
|
|
_pblock:PBlock;
|
|
begin
|
|
Result:=False;
|
|
rwlock_rdlock(FLock);
|
|
|
|
repeat
|
|
|
|
if _TryGetMapBlockByAddr(addr,_pblock) then
|
|
begin
|
|
|
|
if (_pblock^.nSize>len) then
|
|
begin
|
|
Result:=(__mprotect(addr,len,prot)=0);
|
|
Break;
|
|
end else
|
|
begin
|
|
Result:=(__mprotect(addr,_pblock^.nSize,prot)=0);
|
|
end;
|
|
|
|
if (len>=_pblock^.nSize) then
|
|
begin
|
|
len:=len-_pblock^.nSize;
|
|
addr:=addr+_pblock^.nSize;
|
|
end else
|
|
begin
|
|
Break;
|
|
end;
|
|
|
|
end else
|
|
begin
|
|
|
|
if (len>=PHYSICAL_PAGE_SIZE) then
|
|
begin
|
|
len:=len-PHYSICAL_PAGE_SIZE;
|
|
addr:=addr+PHYSICAL_PAGE_SIZE;
|
|
end else
|
|
begin
|
|
Break;
|
|
end;
|
|
|
|
end;
|
|
|
|
until (len=0);
|
|
|
|
rwlock_unlock(FLock);
|
|
end;
|
|
|
|
///////
|
|
|
|
Var
|
|
PageMM:TPageMM;
|
|
|
|
Function TryGetGpuMemBlockByAddr(addr:Pointer;var block:TGpuMemBlock):Boolean;
|
|
var
|
|
_pblock:PBlock;
|
|
begin
|
|
Result:=False;
|
|
rwlock_rdlock(PageMM.FLock);
|
|
if PageMM._TryGetMapBlockByAddr(addr,_pblock) then
|
|
begin
|
|
Case _pblock^.bType of
|
|
BT_DIRECT_BIG:
|
|
if _isgpu(PBlockBig(_pblock)^.prot) then
|
|
begin
|
|
block.pAddr :=_pblock^.pAddr;
|
|
block.nSize :=_pblock^.nSize;
|
|
block.Handle:=PBlockBig(_pblock)^.Handle;
|
|
Result:=true;
|
|
end;
|
|
end;
|
|
end;
|
|
rwlock_unlock(PageMM.FLock);
|
|
end;
|
|
|
|
Procedure RegistredStack;
|
|
var
|
|
block:PBlock;
|
|
begin
|
|
rwlock_wrlock(PageMM.FLock);
|
|
block:=AllocMem(SizeOf(TBlock));
|
|
if (block=nil) then Exit;
|
|
block^.pAddr:=StackBottom;
|
|
block^.nSize:=StackLength;
|
|
block^.bType:=BT_STACK;
|
|
PageMM.FMapBlockSet.Insert(block);
|
|
rwlock_unlock(PageMM.FLock);
|
|
end;
|
|
|
|
Procedure UnRegistredStack;
|
|
begin
|
|
rwlock_wrlock(PageMM.FLock);
|
|
PageMM._DeleteBlockByAddr(StackBottom);
|
|
rwlock_unlock(PageMM.FLock);
|
|
end;
|
|
|
|
function ps4_sceKernelGetDirectMemorySize:Int64; SysV_ABI_CDecl;
|
|
begin
|
|
Result:=SCE_KERNEL_MAIN_DMEM_SIZE;
|
|
end;
|
|
|
|
function ps4_getpagesize:Integer; SysV_ABI_CDecl;
|
|
begin
|
|
Result:=PHYSICAL_PAGE_SIZE;
|
|
end;
|
|
|
|
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); //rw
|
|
|
|
Result:=DirectManager.Alloc(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); //rw
|
|
|
|
Result:=DirectManager.Alloc(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;
|
|
|
|
FAdrOut :=0;
|
|
FSizeOut:=0;
|
|
|
|
_sig_lock;
|
|
rwlock_rdlock(PageMM.FLock); //r
|
|
|
|
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;
|
|
|
|
ROut:=Default(TDirectAdrNode);
|
|
|
|
_sig_lock;
|
|
rwlock_rdlock(PageMM.FLock); //r
|
|
|
|
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);
|
|
|
|
ROut:=Default(TDirectAdrNode);
|
|
|
|
_sig_lock;
|
|
rwlock_rdlock(PageMM.FLock); //r
|
|
|
|
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_rdlock(PageMM.FLock); //r
|
|
|
|
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); //rw
|
|
|
|
Result:=DirectManager.Release(start,len);
|
|
|
|
rwlock_unlock(PageMM.FLock);
|
|
_sig_unlock;
|
|
end;
|
|
|
|
//
|
|
|
|
function ps4_sceKernelAllocateDirectMemory(
|
|
searchStart:QWORD;
|
|
searchEnd:QWORD;
|
|
length:QWORD;
|
|
alignment:QWORD;
|
|
memoryType:Integer;
|
|
physicalAddrDest:PQWORD):Integer; SysV_ABI_CDecl;
|
|
begin
|
|
Result:=_sceKernelAllocateDirectMemory(
|
|
searchStart,
|
|
searchEnd,
|
|
length,
|
|
alignment,
|
|
memoryType,
|
|
physicalAddrDest);
|
|
|
|
if (Result<>0) then
|
|
begin
|
|
Writeln(StdErr,'[WARN]:sceKernelAllocateDirectMemory:',Result);
|
|
end;
|
|
_set_errno(Result);
|
|
|
|
Result:=px2sce(Result);
|
|
end;
|
|
|
|
function ps4_sceKernelAllocateMainDirectMemory(
|
|
length:QWORD;
|
|
alignment:QWORD;
|
|
memoryType:Integer;
|
|
physicalAddrDest:PQWORD):Integer; SysV_ABI_CDecl;
|
|
begin
|
|
Result:=_sceKernelAllocateMainDirectMemory(
|
|
length,
|
|
alignment,
|
|
memoryType,
|
|
physicalAddrDest);
|
|
|
|
if (Result<>0) then
|
|
begin
|
|
Writeln(StdErr,'[WARN]:sceKernelAllocateMainDirectMemory:',Result);
|
|
end;
|
|
_set_errno(Result);
|
|
|
|
Result:=px2sce(Result);
|
|
end;
|
|
|
|
function ps4_sceKernelAvailableDirectMemorySize(
|
|
searchStart:QWORD;
|
|
searchEnd:QWORD;
|
|
alignment:QWORD;
|
|
physAddrOut:PQWORD;
|
|
sizeOut:PQWORD):Integer; SysV_ABI_CDecl;
|
|
begin
|
|
Result:=_sceKernelAvailableDirectMemorySize(
|
|
searchStart,
|
|
searchEnd,
|
|
alignment,
|
|
physAddrOut,
|
|
sizeOut);
|
|
|
|
if (Result<>0) then
|
|
begin
|
|
Writeln(StdErr,'[WARN]:sceKernelAvailableDirectMemorySize:',Result);
|
|
end;
|
|
_set_errno(Result);
|
|
|
|
Result:=px2sce(Result);
|
|
end;
|
|
|
|
function ps4_sceKernelDirectMemoryQuery(
|
|
offset:QWORD;
|
|
flags:Integer;
|
|
info:pSceKernelDirectMemoryQueryInfo;
|
|
infoSize:QWORD):Integer; SysV_ABI_CDecl;
|
|
begin
|
|
Result:=_sceKernelDirectMemoryQuery(
|
|
offset,
|
|
flags,
|
|
info,
|
|
infoSize);
|
|
|
|
if (Result<>0) then
|
|
begin
|
|
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,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 (align<PHYSICAL_PAGE_SIZE) then align:=PHYSICAL_PAGE_SIZE;
|
|
|
|
_sig_lock;
|
|
rwlock_wrlock(PageMM.FLock); //rw
|
|
|
|
if (flags and MAP_VOID)<>0 then //reserved
|
|
begin
|
|
flags:=flags and (not MAP_SHARED);
|
|
Result:=VirtualManager.mmap(addr,len,align,prot,flags,fd,offset,res);
|
|
end else
|
|
if (flags and MAP_ANON)<>0 then //flex
|
|
begin
|
|
Result:=VirtualManager.mmap(addr,len,align,prot,flags,fd,offset,res);
|
|
end else
|
|
if (flags and MAP_SHARED)<>0 then
|
|
begin
|
|
if (fd>=0) then
|
|
begin
|
|
if (fd=0) then //direct (psevdo dmem fd=0)
|
|
begin
|
|
Result:=DirectManager.CheckedMMap(offset,len);
|
|
|
|
if (Result=0) then
|
|
begin
|
|
|
|
Result:=VirtualManager.mmap(addr,len,align,prot,flags,fd,offset,res);
|
|
|
|
if (Result=0) then
|
|
begin
|
|
Result:=DirectManager.mmap_addr(offset,len,addr);
|
|
end;
|
|
|
|
end;
|
|
end else
|
|
begin //map file
|
|
Result:=VirtualManager.mmap(addr,len,align,prot,flags,fd,offset,res);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
rwlock_unlock(PageMM.FLock);
|
|
_sig_unlock;
|
|
end;
|
|
|
|
function __sys_mmap_dmem(
|
|
addr:Pointer;
|
|
length:QWORD;
|
|
alignment:QWORD;
|
|
mtype,prots,flags:Integer;
|
|
physicalAddr:QWORD;
|
|
var res:Pointer):Integer;
|
|
begin
|
|
Result:=0;
|
|
|
|
_sig_lock;
|
|
rwlock_wrlock(PageMM.FLock); //rw
|
|
|
|
Result:=DirectManager.CheckedMMap(physicalAddr,length);
|
|
|
|
if (Result=0) then
|
|
begin
|
|
flags:=flags or MAP_SHARED;
|
|
Result:=VirtualManager.mmap(addr,length,alignment,prots,flags,0,physicalAddr,res);
|
|
|
|
if (Result=0) then
|
|
begin
|
|
Result:=DirectManager.mmap_addr(physicalAddr,length,addr,mtype);
|
|
end;
|
|
end;
|
|
|
|
rwlock_unlock(PageMM.FLock);
|
|
_sig_unlock;
|
|
end;
|
|
|
|
function __munmap(addr:Pointer;len:size_t):Integer;
|
|
begin
|
|
Result:=VirtualManager.Release(addr,len);
|
|
end;
|
|
|
|
function _munmap(addr:Pointer;len:size_t):Integer;
|
|
begin
|
|
_sig_lock;
|
|
rwlock_wrlock(PageMM.FLock); //rw
|
|
|
|
Result:=VirtualManager.Release(addr,len);
|
|
|
|
rwlock_unlock(PageMM.FLock);
|
|
_sig_unlock;
|
|
end;
|
|
|
|
function __release_direct(Offset,Size:QWORD):Integer;
|
|
begin
|
|
Result:=DirectManager.Release(Offset,Size);
|
|
end;
|
|
|
|
function _sceKernelMapFlexibleMemory(
|
|
virtualAddrDest:PPointer;
|
|
length:QWORD;
|
|
prots,flags:Integer):Integer;
|
|
var
|
|
addr:Pointer;
|
|
begin
|
|
Result:=SCE_KERNEL_ERROR_EINVAL;
|
|
|
|
if ((flags and $ffbfff6f)<>0) then Exit;
|
|
if ((prots and $ffffffc8)<>0) then Exit;
|
|
|
|
if (length<LOGICAL_PAGE_SIZE) then Exit;
|
|
if not IsAlign(length,LOGICAL_PAGE_SIZE) then Exit;
|
|
|
|
addr:=virtualAddrDest^;
|
|
if not IsAlign(addr,LOGICAL_PAGE_SIZE) then Exit;
|
|
|
|
if (((flags and MAP_FIXED) <> 0) and (addr=nil)) then
|
|
begin
|
|
if (SDK_VERSION > $16fffff) then
|
|
begin
|
|
Exit(SCE_KERNEL_ERROR_EINVAL);
|
|
end;
|
|
flags:=flags and $ffffffef;
|
|
Writeln('[WARNING] map(addr=0, flags=MAP_FIXED)');
|
|
end;
|
|
|
|
if (addr=nil) then
|
|
begin
|
|
addr:=Pointer($880000000);
|
|
end;
|
|
|
|
Result:=__mmap(addr,length,0,prots,flags or MAP_ANON,-1,0,addr);
|
|
|
|
if (Result=0) then
|
|
begin
|
|
virtualAddrDest^:=addr;
|
|
Result:=0;
|
|
end;
|
|
end;
|
|
|
|
function _sceKernelReserveVirtualRange(
|
|
virtualAddrDest:PPointer;
|
|
length:QWORD;
|
|
flags:Integer;
|
|
alignment:QWORD):Integer;
|
|
var
|
|
addr:Pointer;
|
|
begin
|
|
Result:=SCE_KERNEL_ERROR_EINVAL;
|
|
|
|
if ((flags and $ffbfff6f)<>0) then Exit;
|
|
|
|
if (length<LOGICAL_PAGE_SIZE) then Exit;
|
|
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 (alignment<LOGICAL_PAGE_SIZE) then alignment:=LOGICAL_PAGE_SIZE;
|
|
if (fastIntLog2(alignment)>31) then Exit;
|
|
|
|
addr:=virtualAddrDest^;
|
|
if not IsAlign(addr,LOGICAL_PAGE_SIZE) then Exit;
|
|
|
|
if (((flags and MAP_FIXED) <> 0) and (addr=nil)) then
|
|
begin
|
|
if (SDK_VERSION > $16fffff) then
|
|
begin
|
|
Exit(SCE_KERNEL_ERROR_EINVAL);
|
|
end;
|
|
flags:=flags and $ffffffef;
|
|
Writeln('[WARNING] map(addr=0, flags=MAP_FIXED)');
|
|
end;
|
|
|
|
Result:=__mmap(addr,length,alignment,0,flags or MAP_VOID or MAP_SHARED,-1,0,addr);
|
|
|
|
if (Result=0) then
|
|
begin
|
|
virtualAddrDest^:=addr;
|
|
Result:=0;
|
|
end;
|
|
end;
|
|
|
|
function _sceKernelMapDirectMemory2(
|
|
virtualAddrDest:PPointer;
|
|
length:QWORD;
|
|
mtype,prots,flags:Integer;
|
|
physicalAddr:QWORD;
|
|
alignment:QWORD):Integer;
|
|
var
|
|
addr:Pointer;
|
|
begin
|
|
Result:=SCE_KERNEL_ERROR_EINVAL;
|
|
|
|
if ((flags and $1f000000)<>0) then Exit;
|
|
if ((prots and $ffffffc8)<>0) then Exit;
|
|
|
|
if (length<LOGICAL_PAGE_SIZE) then Exit;
|
|
if not IsAlign(length ,LOGICAL_PAGE_SIZE) then Exit;
|
|
if not IsAlign(physicalAddr,LOGICAL_PAGE_SIZE) then Exit;
|
|
if not IsAlign(alignment ,LOGICAL_PAGE_SIZE) then Exit;
|
|
if not IsPowerOfTwo(alignment) then Exit;
|
|
|
|
if (alignment<LOGICAL_PAGE_SIZE) then alignment:=LOGICAL_PAGE_SIZE;
|
|
if (fastIntLog2(alignment)>31) then Exit;
|
|
|
|
addr:=virtualAddrDest^;
|
|
if not IsAlign(addr,LOGICAL_PAGE_SIZE) then Exit;
|
|
|
|
Result:=__sys_mmap_dmem(addr,length,alignment,mtype,prots,flags,physicalAddr,addr);
|
|
|
|
if (Result=0) then
|
|
begin
|
|
virtualAddrDest^:=addr;
|
|
Result:=0;
|
|
end;
|
|
end;
|
|
|
|
function _sceKernelMapDirectMemory(
|
|
virtualAddrDest:PPointer;
|
|
length:QWORD;
|
|
prots,flags:Integer;
|
|
physicalAddr:QWORD;
|
|
alignment:QWORD):Integer;
|
|
var
|
|
addr:Pointer;
|
|
_flags:Integer;
|
|
begin
|
|
Result:=SCE_KERNEL_ERROR_EINVAL;
|
|
|
|
if ((physicalAddr < $3000000000) or (physicalAddr > $301fffffff)) and
|
|
((flags and SCE_KERNEL_MAP_DMEM_COMPAT)=0) and (SDK_VERSION > $24fffff) then
|
|
begin
|
|
Result:=_sceKernelMapDirectMemory2(virtualAddrDest,length,-1,prots,flags,physicalAddr,alignment);
|
|
Exit;
|
|
end;
|
|
|
|
if ((flags and $1f000000)<>0) then Exit;
|
|
if ((prots and $ffffffc8)<>0) then Exit;
|
|
|
|
if (length<LOGICAL_PAGE_SIZE) then Exit;
|
|
if not IsAlign(length ,LOGICAL_PAGE_SIZE) then Exit;
|
|
if not IsAlign(physicalAddr,LOGICAL_PAGE_SIZE) then Exit;
|
|
if not IsAlign(alignment ,LOGICAL_PAGE_SIZE) then Exit;
|
|
if not IsPowerOfTwo(alignment) then Exit;
|
|
|
|
if (alignment<LOGICAL_PAGE_SIZE) then alignment:=LOGICAL_PAGE_SIZE;
|
|
if (fastIntLog2(alignment)>31) then Exit;
|
|
|
|
addr:=virtualAddrDest^;
|
|
if not IsAlign(addr,LOGICAL_PAGE_SIZE) then Exit;
|
|
|
|
_flags:=flags and $fffffbff;
|
|
|
|
if (((flags and MAP_FIXED) <> 0) and (addr=nil)) then
|
|
begin
|
|
if (SDK_VERSION > $16fffff) then
|
|
begin
|
|
Exit(SCE_KERNEL_ERROR_EINVAL);
|
|
end;
|
|
_flags:=flags and $fffffbef;
|
|
Writeln('[WARNING] map(addr=0, flags=MAP_FIXED)');
|
|
end;
|
|
|
|
if (addr=nil) then
|
|
begin
|
|
addr:=Pointer($880000000);
|
|
end;
|
|
|
|
Result:=__mmap(addr,length,alignment,prots,_flags or MAP_SHARED,0,physicalAddr,addr);
|
|
|
|
if (Result=0) then
|
|
begin
|
|
virtualAddrDest^:=addr;
|
|
Result:=0;
|
|
end;
|
|
end;
|
|
|
|
|
|
////
|
|
////
|
|
|
|
|
|
|
|
function ps4_sceKernelMapDirectMemory(
|
|
virtualAddrDest:PPointer;
|
|
length:QWORD;
|
|
protections:Integer;
|
|
flags:Integer;
|
|
physicalAddr:QWORD;
|
|
alignment:QWORD):Integer; SysV_ABI_CDecl;
|
|
var
|
|
//flProtect:DWORD;
|
|
R:Pointer;
|
|
begin
|
|
if (virtualAddrDest=nil) or (length=0) then Exit(SCE_KERNEL_ERROR_EINVAL);
|
|
|
|
//Assert(flags=0);
|
|
|
|
//Writeln('AddrSrc:',HexStr(virtualAddrDest^));
|
|
|
|
Writeln('length:',HexStr(length,16),' ',
|
|
test_KP_flags(protections),' ',
|
|
'flags:',flags);
|
|
Writeln('length:',HexStr(length,16),' ',
|
|
'physicalAddr:',HexStr(physicalAddr,16),' ',
|
|
'alignment:',HexStr(alignment,16));
|
|
|
|
if (alignment=0) then alignment:=LOGICAL_PAGE_SIZE;
|
|
|
|
if not IsAlign(virtualAddrDest^,LOGICAL_PAGE_SIZE) then Exit(SCE_KERNEL_ERROR_EINVAL);
|
|
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);
|
|
|
|
if (flags and SCE_KERNEL_MAP_FIXED)<>0 then
|
|
begin
|
|
R:=virtualAddrDest^;
|
|
end else
|
|
begin
|
|
R:=nil;
|
|
end;
|
|
|
|
_sig_lock;
|
|
R:=PageMM.mmap_d(R,length,alignment,physicalAddr,protections,(flags and SCE_KERNEL_MAP_NO_OVERWRITE)=0);
|
|
_sig_unlock;
|
|
//Writeln('alloc:',HexStr(R),'..',HexStr(R+length));
|
|
virtualAddrDest^:=R;
|
|
|
|
if (R=nil) then
|
|
begin
|
|
Exit(SCE_KERNEL_ERROR_ENOMEM);
|
|
end;
|
|
|
|
if _isgpu(protections) then
|
|
begin
|
|
Writeln('GPU:',HexStr(R),'..',HexStr(R+length));
|
|
end;
|
|
|
|
Assert(IsAlign(R,alignment),'sceKernelMapDirectMemory not aligned!');
|
|
|
|
Result:=0;
|
|
end;
|
|
|
|
function ps4_sceKernelMapNamedFlexibleMemory(
|
|
virtualAddrDest:PPointer;
|
|
length:QWORD;
|
|
protections:Integer;
|
|
flags:Integer;
|
|
name:PChar):Integer; SysV_ABI_CDecl;
|
|
var
|
|
//flProtect:DWORD;
|
|
R:Pointer;
|
|
begin
|
|
Result:=SCE_KERNEL_ERROR_EINVAL;
|
|
if (virtualAddrDest=nil) or (length=0) then Exit;
|
|
|
|
//Assert(flags=0);
|
|
|
|
//Writeln('AddrSrc:',HexStr(virtualAddrDest^));
|
|
|
|
Writeln('length:',HexStr(length,16),' ',
|
|
test_KP_flags(protections),' ',
|
|
'flags:',flags);
|
|
Writeln('length:',HexStr(length,16),' ',
|
|
'name:',name);
|
|
|
|
if not IsAlign(virtualAddrDest^,LOGICAL_PAGE_SIZE) then Exit;
|
|
if not IsAlign(length,LOGICAL_PAGE_SIZE) then Exit;
|
|
|
|
if (flags and SCE_KERNEL_MAP_FIXED)<>0 then
|
|
begin
|
|
R:=virtualAddrDest^;
|
|
end else
|
|
begin
|
|
R:=nil;
|
|
end;
|
|
|
|
_sig_lock;
|
|
R:=PageMM.mmap_d(R,length,0,INVALID_DIRECT,protections,(flags and SCE_KERNEL_MAP_NO_OVERWRITE)=0);
|
|
_sig_unlock;
|
|
|
|
Writeln('alloc:',HexStr(R),'..',HexStr(R+length));
|
|
virtualAddrDest^:=R;
|
|
|
|
if (R=nil) then
|
|
begin
|
|
Exit(SCE_KERNEL_ERROR_ENOMEM);
|
|
end;
|
|
|
|
if _isgpu(protections) then
|
|
begin
|
|
Writeln('GPU:',HexStr(R),'..',HexStr(R+length));
|
|
end;
|
|
|
|
Result:=0;
|
|
end;
|
|
|
|
function ps4_sceKernelMapFlexibleMemory(
|
|
virtualAddrDest:PPointer;
|
|
length:QWORD;
|
|
protections:Integer;
|
|
flags:Integer):Integer; SysV_ABI_CDecl;
|
|
var
|
|
//flProtect:DWORD;
|
|
R:Pointer;
|
|
begin
|
|
Result:=SCE_KERNEL_ERROR_EINVAL;
|
|
if (virtualAddrDest=nil) or (length=0) then Exit;
|
|
|
|
//Assert(flags=0);
|
|
|
|
//Writeln('AddrSrc:',HexStr(virtualAddrDest^));
|
|
|
|
Writeln('length:',HexStr(length,16),' ',
|
|
test_KP_flags(protections),' ',
|
|
'flags:',flags);
|
|
Writeln('length:',HexStr(length,16));
|
|
|
|
if not IsAlign(virtualAddrDest^,LOGICAL_PAGE_SIZE) then Exit;
|
|
if not IsAlign(length,LOGICAL_PAGE_SIZE) then Exit;
|
|
|
|
if (flags and SCE_KERNEL_MAP_FIXED)<>0 then
|
|
begin
|
|
R:=virtualAddrDest^;
|
|
end else
|
|
begin
|
|
R:=nil;
|
|
end;
|
|
|
|
_sig_lock;
|
|
R:=PageMM.mmap_d(R,length,0,INVALID_DIRECT,protections,(flags and SCE_KERNEL_MAP_NO_OVERWRITE)=0);
|
|
_sig_unlock;
|
|
|
|
//Writeln('alloc:',HexStr(R),'..',HexStr(R+length));
|
|
virtualAddrDest^:=R;
|
|
|
|
if (R=nil) then
|
|
begin
|
|
Exit(SCE_KERNEL_ERROR_ENOMEM);
|
|
end;
|
|
|
|
if _isgpu(protections) then
|
|
begin
|
|
Writeln('GPU:',HexStr(R),'..',HexStr(R+length));
|
|
end;
|
|
|
|
Result:=0;
|
|
end;
|
|
|
|
//MEMORY_BASIC_INFORMATION = record
|
|
// BaseAddress : PVOID; addr to check
|
|
// AllocationBase : PVOID; addr to begin region
|
|
// AllocationProtect : DWORD; R/W/E
|
|
// RegionSize : PTRUINT; Full size-( (addr to begin)-(addr to check) )
|
|
// State : DWORD; MEM_COMMIT or MEM_RESERVE
|
|
// Protect : DWORD; R/W/E
|
|
// _Type : DWORD; MEM_PRIVATE
|
|
//end;
|
|
|
|
//flex
|
|
function ps4_sceKernelMunmap(addr:Pointer;len:size_t):Integer; SysV_ABI_CDecl;
|
|
begin
|
|
Result:=SCE_KERNEL_ERROR_EINVAL;
|
|
if (addr=nil) or (len=0) then Exit;
|
|
|
|
if not IsAlign(addr,LOGICAL_PAGE_SIZE) then Exit;
|
|
if not IsAlign(len,LOGICAL_PAGE_SIZE) then Exit;
|
|
|
|
_sig_lock;
|
|
if PageMM.unmap(addr,len) then Result:=0;
|
|
_sig_unlock;
|
|
end;
|
|
|
|
//flex
|
|
function ps4_sceKernelQueryMemoryProtection(addr:Pointer;pStart,pEnd:PPointer;pProt:PInteger):Integer; SysV_ABI_CDecl;
|
|
begin
|
|
Result:=SCE_KERNEL_ERROR_EACCES;
|
|
//Writeln(HexStr(addr));
|
|
//addr:=AlignDw(addr,LOGICAL_PAGE_SIZE);
|
|
_sig_lock;
|
|
if PageMM.QueryProt(addr,pStart,pEnd,pProt) then Result:=0;
|
|
_sig_unlock;
|
|
end;
|
|
|
|
function ps4_sceKernelVirtualQuery(addr:Pointer;
|
|
flags:Integer;
|
|
info:pSceKernelVirtualQueryInfo;
|
|
infoSize:QWORD):Integer; SysV_ABI_CDecl;
|
|
begin
|
|
Result:=0;
|
|
Assert(false,'TODO');
|
|
end;
|
|
|
|
function ps4_sceKernelMprotect(addr:Pointer;len:QWORD;prot:Integer):Integer; SysV_ABI_CDecl;
|
|
begin
|
|
Result:=SCE_KERNEL_ERROR_EINVAL;
|
|
|
|
_sig_lock;
|
|
if PageMM.ChangeProt(addr,len,prot) then Result:=0;
|
|
_sig_unlock;
|
|
|
|
end;
|
|
|
|
function ps4_sceKernelSetVirtualRangeName(addr:Pointer;len:QWORD;name:Pchar):Integer; SysV_ABI_CDecl;
|
|
begin
|
|
Writeln('sceKernelSetVirtualRangeName:',HexStr(addr),':',len,':',name);
|
|
Result:=0;
|
|
end;
|
|
|
|
function ps4_mmap(addr:Pointer;len:size_t;prot,flags:Integer;fd:Integer;offset:size_t):Pointer; SysV_ABI_CDecl;
|
|
Var
|
|
map:Pointer;
|
|
protect:DWORD;
|
|
begin
|
|
map:=MAP_FAILED;
|
|
|
|
if (fd<>-1) {or ((flags and MAP_ANONYMOUS)=0)} then
|
|
begin
|
|
SetLastError(EBADF);
|
|
Result:=MAP_FAILED;
|
|
Exit;
|
|
end;
|
|
|
|
if (not IsAlign(addr,PHYSICAL_PAGE_SIZE)) or
|
|
(not IsAlign(len,PHYSICAL_PAGE_SIZE)) or
|
|
(not IsAlign(offset,PHYSICAL_PAGE_SIZE)) then
|
|
begin
|
|
SetLastError(EINVAL);
|
|
Result:=MAP_FAILED;
|
|
Exit;
|
|
end;
|
|
|
|
protect:=__map_prot_page(prot);
|
|
|
|
SetLastError(0);
|
|
|
|
if (len=0) or
|
|
// Unsupported flag combinations
|
|
((flags and MAP_FIXED)<>0) then
|
|
// Usupported protection combinations
|
|
//(prot=PROT_EXEC) then
|
|
begin
|
|
SetLastError(EINVAL);
|
|
Result:=MAP_FAILED;
|
|
Exit;
|
|
end;
|
|
|
|
_sig_lock;
|
|
map:=VirtualAlloc(addr,len,MEM_COMMIT or MEM_RESERVE,Protect);
|
|
_sig_unlock;
|
|
|
|
if (map=nil) then
|
|
begin
|
|
Result:=MAP_FAILED;
|
|
Exit;
|
|
end;
|
|
|
|
Result:=map;
|
|
end;
|
|
|
|
function ps4_munmap(addr:Pointer;len:size_t):Integer; SysV_ABI_CDecl;
|
|
var
|
|
Info:TMemoryBasicInformation;
|
|
begin
|
|
Result:=-1;
|
|
if (addr=nil) or (len=0) then Exit;
|
|
|
|
if not IsAlign(len,PHYSICAL_PAGE_SIZE) then Exit;
|
|
|
|
Info:=Default(TMemoryBasicInformation);
|
|
_sig_lock;
|
|
if (VirtualQuery(addr,Info,len)=0) then
|
|
begin
|
|
_sig_unlock;
|
|
Writeln('GetLastError:',GetLastError);
|
|
Exit;
|
|
end;
|
|
_sig_unlock;
|
|
if (Info._Type=MEM_FREE) then
|
|
begin
|
|
Writeln('GetLastError:',GetLastError);
|
|
Exit;
|
|
end;
|
|
|
|
Assert((Info.BaseAddress=Info.AllocationBase) and (Info.RegionSize=len),'partial unmap not impliment!');
|
|
|
|
_sig_lock;
|
|
if not VirtualFree(addr,0,MEM_RELEASE) then
|
|
begin
|
|
_sig_unlock;
|
|
Writeln('GetLastError:',GetLastError);
|
|
Exit;
|
|
end;
|
|
_sig_unlock;
|
|
|
|
Result:=0;
|
|
end;
|
|
|
|
function ps4_msync(addr:Pointer;len:size_t;flags:Integer):Integer; SysV_ABI_CDecl;
|
|
begin
|
|
//Writeln('msync:',HexStr(addr));
|
|
System.ReadWriteBarrier;
|
|
Result:=0;
|
|
end;
|
|
|
|
function ps4_mprotect(addr:Pointer;len:size_t;prot:Integer):Integer; SysV_ABI_CDecl;
|
|
begin
|
|
_sig_lock;
|
|
Result:=__mprotect(addr,len,prot);
|
|
_sig_unlock;
|
|
end;
|
|
|
|
initialization
|
|
DirectManager :=TDirectManager .Create;
|
|
DirectManager .OnMemoryUnmapCb:=@__munmap;
|
|
VirtualManager:=TVirtualManager.Create($400000,$3FFFFFFFF);
|
|
VirtualManager.OnDirectUnmapCb:=@__release_direct;
|
|
PageMM.init;
|
|
|
|
end.
|
|
|