FPPS4/sys/md/vm_pmap_prot.pas

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.