mirror of https://github.com/red-prig/fpPS4.git
294 lines
5.4 KiB
Plaintext
294 lines
5.4 KiB
Plaintext
unit vm_pmap_prot;
|
|
|
|
{$mode ObjFPC}{$H+}
|
|
{$CALLING SysV_ABI_CDecl}
|
|
|
|
interface
|
|
|
|
uses
|
|
atomic,
|
|
vm,
|
|
vmparam,
|
|
md_map;
|
|
|
|
const
|
|
PMAPP_SHIFT=MD_PAGE_SHIFT; //12;
|
|
PMAPP_SIZE =MD_PAGE_SIZE; //1 shl PMAPP_SHIFT; //4*1024
|
|
PMAPP_MASK =MD_PAGE_MASK; //PMAPP_SIZE-1;
|
|
|
|
PAGE_MAP_COUNT_ALL=(QWORD(VM_MAXUSER_ADDRESS) shr PMAPP_SHIFT);
|
|
PAGE_MAP_MASK_ALL =PAGE_MAP_COUNT_ALL-1;
|
|
|
|
PAGE_MAP_COUNT_LV1=PAGE_MAP_COUNT_ALL shr 16;
|
|
PAGE_MAP_COUNT_LV2=1 shl 16; //64KB
|
|
|
|
PAGE_MAP_COUNT_SZ1=PAGE_MAP_COUNT_LV1*SizeOf(Pointer);
|
|
PAGE_MAP_COUNT_SZ2=PAGE_MAP_COUNT_LV2*SizeOf(Byte);
|
|
|
|
PAGE_PROT_READ =VM_PROT_READ;
|
|
PAGE_PROT_WRITE =VM_PROT_WRITE;
|
|
PAGE_PROT_EXECUTE=VM_PROT_EXECUTE;
|
|
|
|
PAGE_PROT_RW =PAGE_PROT_READ or PAGE_PROT_WRITE;
|
|
PAGE_PROT_RWX =PAGE_PROT_READ or PAGE_PROT_WRITE or PAGE_PROT_EXECUTE;
|
|
|
|
PAGE_TRACK_R =$08;
|
|
PAGE_TRACK_W =$10;
|
|
PAGE_TRACK_X =$20;
|
|
PAGE_TRACK_RWX =PAGE_TRACK_R or PAGE_TRACK_W or PAGE_TRACK_X;
|
|
PAGE_TRACK_SHIFT =3;
|
|
|
|
TRACK_PROT=1; //Take tracking bits into account
|
|
REMAP_PROT=2; //Ignore protect bit checking
|
|
|
|
var
|
|
PAGE_PROT:PPBYTE=nil;
|
|
|
|
procedure ppmap_mark_rwx (start,__end:vm_offset_t;prots:Byte);
|
|
procedure ppmap_unmark (start,__end:vm_offset_t;prots:Byte);
|
|
procedure ppmap_track (start,__end:vm_offset_t;prots:Byte);
|
|
//procedure ppmap_untrack (start,__end:vm_offset_t;prots:Byte);
|
|
function ppmap_scan (start,__end:vm_offset_t):vm_offset_t;
|
|
function ppmap_scan_rwx (start,__end:vm_offset_t):vm_offset_t;
|
|
function ppmap_get_prot (addr:vm_offset_t):Byte;
|
|
function ppmap_get_prot (addr,size:vm_offset_t):Byte;
|
|
|
|
implementation
|
|
|
|
//PAGE_MAP
|
|
|
|
function IDX_TO_OFF(x:QWORD):QWORD; inline;
|
|
begin
|
|
Result:=QWORD(x) shl PMAPP_SHIFT;
|
|
end;
|
|
|
|
function OFF_TO_IDX(x:QWORD):QWORD; inline;
|
|
begin
|
|
Result:=QWORD(x) shr PMAPP_SHIFT;
|
|
end;
|
|
|
|
function MAX_IDX(x:QWORD):QWORD; inline;
|
|
begin
|
|
if (x>PAGE_MAP_MASK_ALL) then
|
|
Result:=PAGE_MAP_MASK_ALL
|
|
else
|
|
Result:=x;
|
|
end;
|
|
|
|
function LV1_IDX(x:QWORD):DWORD; inline;
|
|
begin
|
|
Result:=x shr 16;
|
|
end;
|
|
|
|
function LV2_IDX(x:QWORD):DWORD; inline;
|
|
begin
|
|
Result:=x and (PAGE_MAP_COUNT_LV2-1);
|
|
end;
|
|
|
|
procedure prealloc(i:QWORD);
|
|
var
|
|
ptr:Pointer;
|
|
r:Integer;
|
|
begin
|
|
repeat
|
|
|
|
if (PAGE_PROT[LV1_IDX(i)]=nil) then
|
|
begin
|
|
|
|
ptr:=kmem_alloc(PAGE_MAP_COUNT_SZ2,VM_RW);
|
|
Assert((ptr<>nil),'prealloc');
|
|
|
|
if (System.InterlockedCompareExchange(PAGE_PROT[LV1_IDX(i)],ptr,nil)=nil) then
|
|
begin
|
|
Exit;
|
|
end;
|
|
|
|
kmem_free(ptr,PAGE_MAP_COUNT_SZ2);
|
|
|
|
end else
|
|
begin
|
|
Exit;
|
|
end;
|
|
|
|
until false;
|
|
end;
|
|
|
|
procedure ppmap_mark_rwx(start,__end:vm_offset_t;prots:Byte);
|
|
var
|
|
P:PByte;
|
|
clear:Byte;
|
|
begin
|
|
prots:=prots and PAGE_PROT_RWX;
|
|
clear:=(not prots) and PAGE_PROT_RWX;
|
|
start:=OFF_TO_IDX(start);
|
|
__end:=OFF_TO_IDX(__end);
|
|
start:=MAX_IDX(start);
|
|
__end:=MAX_IDX(__end);
|
|
while (start<__end) do
|
|
begin
|
|
//
|
|
prealloc(start);
|
|
//
|
|
P:=@PAGE_PROT[LV1_IDX(start)][LV2_IDX(start)];
|
|
atomic_clear_byte(P,clear);
|
|
atomic_set_byte (P,prots);
|
|
Inc(start);
|
|
end;
|
|
WriteBarrier;
|
|
end;
|
|
|
|
procedure ppmap_unmark(start,__end:vm_offset_t;prots:Byte);
|
|
begin
|
|
start:=OFF_TO_IDX(start);
|
|
__end:=OFF_TO_IDX(__end);
|
|
start:=MAX_IDX(start);
|
|
__end:=MAX_IDX(__end);
|
|
while (start<__end) do
|
|
begin
|
|
if (PAGE_PROT[LV1_IDX(start)]<>nil) then
|
|
begin
|
|
atomic_clear_byte(@PAGE_PROT[LV1_IDX(start)][LV2_IDX(start)],prots);
|
|
end;
|
|
Inc(start);
|
|
end;
|
|
WriteBarrier;
|
|
end;
|
|
|
|
procedure ppmap_track(start,__end:vm_offset_t;prots:Byte);
|
|
var
|
|
P:PByte;
|
|
s_prots:Byte;
|
|
c_prots:Byte;
|
|
begin
|
|
s_prots:=prots and PAGE_TRACK_RWX;
|
|
c_prots:=(not prots) and PAGE_TRACK_RWX;
|
|
|
|
start:=OFF_TO_IDX(start);
|
|
__end:=OFF_TO_IDX(__end);
|
|
start:=MAX_IDX(start);
|
|
__end:=MAX_IDX(__end);
|
|
while (start<__end) do
|
|
begin
|
|
//
|
|
prealloc(start);
|
|
//
|
|
P:=@PAGE_PROT[LV1_IDX(start)][LV2_IDX(start)];
|
|
atomic_set_byte (P,s_prots);
|
|
atomic_clear_byte(P,c_prots);
|
|
Inc(start);
|
|
end;
|
|
WriteBarrier;
|
|
end;
|
|
|
|
{
|
|
procedure ppmap_untrack(start,__end:vm_offset_t;prots:Byte);
|
|
begin
|
|
prots:=prots and PAGE_TRACK_RWX;
|
|
start:=OFF_TO_IDX(start);
|
|
__end:=OFF_TO_IDX(__end);
|
|
start:=MAX_IDX(start);
|
|
__end:=MAX_IDX(__end);
|
|
while (start<__end) do
|
|
begin
|
|
atomic_clear_byte(@PAGE_PROT[start],prots);
|
|
Inc(start);
|
|
end;
|
|
WriteBarrier;
|
|
end;
|
|
}
|
|
|
|
function _get_prot(addr:QWORD):Byte; inline;
|
|
begin
|
|
if (addr>PAGE_MAP_MASK_ALL) then
|
|
begin
|
|
Result:=0
|
|
end else
|
|
if (PAGE_PROT[LV1_IDX(addr)]=nil) then
|
|
begin
|
|
Result:=0
|
|
end else
|
|
begin
|
|
Result:=PAGE_PROT[LV1_IDX(addr)][LV2_IDX(addr)];
|
|
end;
|
|
end;
|
|
|
|
function ppmap_scan(start,__end:vm_offset_t):vm_offset_t;
|
|
var
|
|
b,v:Byte;
|
|
begin
|
|
start:=OFF_TO_IDX(start);
|
|
__end:=OFF_TO_IDX(__end);
|
|
start:=MAX_IDX(start);
|
|
__end:=MAX_IDX(__end);
|
|
|
|
ReadBarrier;
|
|
|
|
b:=_get_prot(start);
|
|
Inc(start);
|
|
|
|
while (start<__end) do
|
|
begin
|
|
v:=_get_prot(start);
|
|
|
|
if (b<>v) then
|
|
begin
|
|
start:=IDX_TO_OFF(start);
|
|
Exit(start);
|
|
end;
|
|
|
|
Inc(start);
|
|
end;
|
|
|
|
__end:=IDX_TO_OFF(__end);
|
|
|
|
Result:=__end;
|
|
end;
|
|
|
|
function ppmap_scan_rwx(start,__end:vm_offset_t):vm_offset_t;
|
|
var
|
|
b,v:Byte;
|
|
begin
|
|
start:=OFF_TO_IDX(start);
|
|
__end:=OFF_TO_IDX(__end);
|
|
start:=MAX_IDX(start);
|
|
__end:=MAX_IDX(__end);
|
|
|
|
ReadBarrier;
|
|
|
|
b:=(_get_prot(start) and PAGE_PROT_RWX);
|
|
Inc(start);
|
|
|
|
while (start<__end) do
|
|
begin
|
|
v:=(_get_prot(start) and PAGE_PROT_RWX);
|
|
|
|
if (b<>v) then
|
|
begin
|
|
start:=IDX_TO_OFF(start);
|
|
Exit(start);
|
|
end;
|
|
|
|
Inc(start);
|
|
end;
|
|
|
|
__end:=IDX_TO_OFF(__end);
|
|
|
|
Result:=__end;
|
|
end;
|
|
|
|
function ppmap_get_prot(addr:vm_offset_t):Byte;
|
|
begin
|
|
Result:=_get_prot(OFF_TO_IDX(addr));
|
|
end;
|
|
|
|
function ppmap_get_prot(addr,size:vm_offset_t):Byte;
|
|
begin
|
|
Result:=ppmap_get_prot(addr) or ppmap_get_prot(addr+size);
|
|
end;
|
|
|
|
|
|
end.
|
|
|
|
|
|
|