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.