mirror of https://github.com/red-prig/fpPS4.git
1615 lines
33 KiB
Plaintext
1615 lines
33 KiB
Plaintext
unit vm_nt_map;
|
|
|
|
{$mode ObjFPC}{$H+}
|
|
{$CALLING SysV_ABI_CDecl}
|
|
|
|
interface
|
|
|
|
uses
|
|
sysutils,
|
|
vm,
|
|
kern_mtx,
|
|
systm,
|
|
vm_pmap_prot,
|
|
vm_nt_sub_map;
|
|
|
|
const
|
|
NT_FILE_FREE=1;
|
|
NT_MOBJ_FREE=2;
|
|
NT_UNION_OBJ=4;
|
|
|
|
MAX_UNION_SIZE=256*1024*1024;
|
|
|
|
type
|
|
bit29=0..536870911;
|
|
bit35=0..34359738367;
|
|
|
|
t_danger_range=bitpacked record
|
|
start:bit35; //47-12=35
|
|
_size:bit29; //64-35=29
|
|
end;
|
|
|
|
t_danger_zone=object
|
|
Flock :mtx;
|
|
Frange:t_danger_range;
|
|
procedure Init;
|
|
procedure Done;
|
|
function in_range(addr,size:vm_offset_t):Boolean;
|
|
procedure d_wait(addr,size:vm_offset_t);
|
|
procedure lock(start,__end:vm_offset_t);
|
|
procedure unlock;
|
|
end;
|
|
|
|
pp_vm_nt_file_obj=^p_vm_nt_file_obj;
|
|
p_vm_nt_file_obj=^vm_nt_file_obj;
|
|
|
|
t_nt_obj_free_cb=procedure(obj:p_vm_nt_file_obj);
|
|
|
|
vm_nt_file_obj=packed record
|
|
hfile:THandle;
|
|
free :t_nt_obj_free_cb;
|
|
refs :QWORD;
|
|
flags:Byte;
|
|
maxp :Byte;
|
|
end;
|
|
|
|
///
|
|
|
|
pp_vm_nt_entry=^p_vm_nt_entry;
|
|
p_vm_nt_entry=^vm_nt_entry;
|
|
vm_nt_entry=packed object
|
|
prev :p_vm_nt_entry; // previous entry
|
|
next :p_vm_nt_entry; // next entry
|
|
left :p_vm_nt_entry; // left child in binary search tree
|
|
right :p_vm_nt_entry; // right child in binary search tree
|
|
usize :vm_offset_t; // unaligned size
|
|
offset:vm_ooffset_t; // offset into object
|
|
obj :p_vm_nt_file_obj; // object I point to
|
|
sub :t_vm_nt_sub_map;
|
|
property start:vm_offset_t read sub.header.start write sub.header.start; // start address
|
|
property __end:vm_offset_t read sub.header.__end write sub.header.__end; // end address
|
|
end;
|
|
|
|
p_vm_nt_map=^t_vm_nt_map;
|
|
t_vm_nt_map=object
|
|
header :vm_nt_entry; // List of entries
|
|
lock :mtx; // Lock for map data
|
|
root :p_vm_nt_entry; // Root of a binary search tree
|
|
danger_zone:t_danger_zone;
|
|
property min_offset:vm_offset_t read header.sub.header.start write header.sub.header.start;
|
|
property max_offset:vm_offset_t read header.sub.header.__end write header.sub.header.__end;
|
|
end;
|
|
|
|
function vm_nt_file_obj_allocate (hfile:THandle;maxp:Byte):p_vm_nt_file_obj;
|
|
procedure vm_nt_file_obj_destroy (obj:p_vm_nt_file_obj);
|
|
procedure vm_nt_file_obj_reference (obj:p_vm_nt_file_obj);
|
|
procedure vm_nt_file_obj_deallocate(obj:p_vm_nt_file_obj);
|
|
|
|
function vm_nt_map_max(map:p_vm_nt_map):vm_offset_t;
|
|
function vm_nt_map_min(map:p_vm_nt_map):vm_offset_t;
|
|
|
|
procedure vm_nt_map_init(map:p_vm_nt_map;min,max:vm_offset_t);
|
|
|
|
function vm_nt_map_insert(
|
|
map :p_vm_nt_map;
|
|
obj :p_vm_nt_file_obj;
|
|
offset:vm_ooffset_t;
|
|
start :vm_offset_t;
|
|
__end :vm_offset_t;
|
|
usize :vm_offset_t;
|
|
prot :Integer):Integer;
|
|
|
|
function vm_nt_map_delete(map:p_vm_nt_map;start:vm_offset_t;__end:vm_offset_t):Integer;
|
|
|
|
//Change protection taking into account tracking
|
|
procedure vm_nt_map_protect(map :p_vm_nt_map;
|
|
start:vm_offset_t;
|
|
__end:vm_offset_t;
|
|
prot :Integer);
|
|
|
|
//Change protection tracking
|
|
procedure vm_nt_map_tracking(map :p_vm_nt_map;
|
|
start:vm_offset_t;
|
|
__end:vm_offset_t;
|
|
prot :Integer);
|
|
|
|
//Update page protection by mode
|
|
procedure vm_nt_map_prot_fix(map :p_vm_nt_map;
|
|
start:vm_offset_t;
|
|
__end:vm_offset_t;
|
|
mode :Integer);
|
|
|
|
procedure vm_nt_map_madvise(map :p_vm_nt_map;
|
|
start :vm_offset_t;
|
|
__end :vm_offset_t;
|
|
advise:Integer);
|
|
|
|
//Create a memory mirror of the current state of the pages
|
|
function vm_nt_map_mirror(map :p_vm_nt_map;
|
|
start:vm_offset_t;
|
|
__end:vm_offset_t):Pointer;
|
|
|
|
function vm_nt_map_fetch(map :p_vm_nt_map;
|
|
start :vm_offset_t;
|
|
__end :vm_offset_t;
|
|
var p__start:vm_offset_t;
|
|
var p____end:vm_offset_t;
|
|
var p_offset:vm_offset_t;
|
|
var p____obj:p_vm_nt_file_obj
|
|
):Boolean;
|
|
|
|
implementation
|
|
|
|
uses
|
|
time,
|
|
kern_param,
|
|
md_map;
|
|
|
|
type
|
|
p_range=^t_range;
|
|
t_range=record
|
|
start:vm_offset_t;
|
|
__end:vm_offset_t;
|
|
end;
|
|
|
|
t_range_stat=record
|
|
obj:p_vm_nt_file_obj;
|
|
//
|
|
case Byte of
|
|
0:(
|
|
rprev:t_range;
|
|
rcurr:t_range;
|
|
rnext:t_range;
|
|
);
|
|
1:(
|
|
range:array[0..2] of t_range;
|
|
);
|
|
end;
|
|
|
|
function vm_nt_file_obj_allocate(hfile:THandle;maxp:Byte):p_vm_nt_file_obj;
|
|
begin
|
|
Assert(maxp<>0);
|
|
|
|
Result:=AllocMem(SizeOf(vm_nt_file_obj));
|
|
|
|
Result^.hfile:=hfile;
|
|
Result^.refs :=1;
|
|
Result^.flags:=NT_FILE_FREE or NT_MOBJ_FREE or NT_UNION_OBJ;
|
|
Result^.maxp :=maxp;
|
|
end;
|
|
|
|
procedure vm_nt_file_obj_destroy(obj:p_vm_nt_file_obj);
|
|
var
|
|
r:Integer;
|
|
free :t_nt_obj_free_cb;
|
|
begin
|
|
if ((obj^.flags and NT_FILE_FREE)<>0) then
|
|
if (obj^.hfile<>0) then
|
|
begin
|
|
r:=md_memfd_close(obj^.hfile);
|
|
if (r<>0) then
|
|
begin
|
|
Writeln('failed md_memfd_close(',obj^.hfile,'):0x',HexStr(r,8));
|
|
Assert(false,'vm_nt_file_obj_destroy');
|
|
end;
|
|
obj^.hfile:=0;
|
|
end;
|
|
|
|
free:=obj^.free;
|
|
|
|
if ((obj^.flags and NT_MOBJ_FREE)<>0) then
|
|
begin
|
|
FreeMem(obj);
|
|
end;
|
|
|
|
if (free<>nil) then
|
|
begin
|
|
free(obj);
|
|
end;
|
|
end;
|
|
|
|
procedure vm_nt_file_obj_reference(obj:p_vm_nt_file_obj);
|
|
begin
|
|
if (obj=nil) then Exit;
|
|
|
|
System.InterlockedIncrement64(obj^.refs);
|
|
end;
|
|
|
|
procedure vm_nt_file_obj_deallocate(obj:p_vm_nt_file_obj);
|
|
begin
|
|
if (obj=nil) then Exit;
|
|
|
|
if (System.InterlockedDecrement64(obj^.refs)=0) then
|
|
begin
|
|
vm_nt_file_obj_destroy(obj);
|
|
end;
|
|
end;
|
|
|
|
//
|
|
|
|
procedure vm_init_stat(var stat:t_range_stat;entry:p_vm_nt_entry); inline;
|
|
begin
|
|
stat:=Default(t_range_stat);
|
|
stat.obj :=entry^.obj;
|
|
stat.rcurr.start:=entry^.start;
|
|
stat.rcurr.__end:=entry^.__end;
|
|
end;
|
|
|
|
procedure vm_get_space(map:p_vm_nt_map;entry:p_vm_nt_entry;var start,__end:vm_offset_t);
|
|
var
|
|
prev:p_vm_nt_entry;
|
|
next:p_vm_nt_entry;
|
|
begin
|
|
prev:=entry^.prev;
|
|
next:=entry^.next;
|
|
|
|
if (prev=@map^.header) then
|
|
begin
|
|
start:=map^.min_offset;
|
|
end else
|
|
begin
|
|
start:=prev^.__end;
|
|
end;
|
|
|
|
if (next=@map^.header) then
|
|
begin
|
|
__end:=map^.max_offset;
|
|
end else
|
|
begin
|
|
__end:=next^.start;
|
|
end;
|
|
end;
|
|
|
|
procedure vm_map(map :p_vm_nt_map;
|
|
entry:p_vm_nt_entry;
|
|
prot :Integer);
|
|
var
|
|
start:vm_offset_t;
|
|
__end:vm_offset_t;
|
|
size:vm_size_t;
|
|
max:Integer;
|
|
r:Integer;
|
|
begin
|
|
if (entry^.obj<>nil) then
|
|
begin
|
|
size:=entry^.__end-entry^.start;
|
|
|
|
vm_get_space(map,entry,start,__end);
|
|
|
|
if (start<>__end) then
|
|
if (entry^.start<>start) or
|
|
(entry^.__end<>__end) then
|
|
begin
|
|
r:=md_placeholder_split(Pointer(entry^.start),size);
|
|
if (r<>0) then
|
|
begin
|
|
Writeln('failed md_placeholder_split(',HexStr(entry^.start,11),',',HexStr(entry^.start+size,11),'):0x',HexStr(r,8));
|
|
Assert(false,'vm_map');
|
|
end;
|
|
end;
|
|
|
|
max:=entry^.obj^.maxp;
|
|
|
|
if (entry^.obj^.hfile<>0) then
|
|
begin
|
|
r:=md_placeholder_commit(Pointer(entry^.start),
|
|
entry^.usize, //unaligned size
|
|
(max and VM_RW),
|
|
entry^.obj^.hfile,
|
|
entry^.offset);
|
|
if (r<>0) then
|
|
begin
|
|
Writeln('failed md_placeholder_commit(',HexStr(entry^.start,11),',',HexStr(entry^.start+size,11),'):0x',HexStr(r,8));
|
|
Assert(false,'vm_map');
|
|
end;
|
|
end;
|
|
|
|
if ((prot and VM_RW)<>(max and VM_RW)) then
|
|
begin
|
|
r:=md_protect(Pointer(entry^.start),size,(prot and VM_RW));
|
|
if (r<>0) then
|
|
begin
|
|
Writeln('failed md_protect(',HexStr(entry^.start,11),',',HexStr(entry^.start+size,11),'):0x',HexStr(r,8));
|
|
Assert(false,'vm_map');
|
|
end;
|
|
end;
|
|
|
|
//Writeln('md_file_mmap(',HexStr(entry^.start,11),',',HexStr(entry^.start+size,11),'):0x',HexStr(r,8));
|
|
end;
|
|
end;
|
|
|
|
//
|
|
|
|
function MD_IDX_TO_OFF(x:QWORD):QWORD; inline;
|
|
begin
|
|
Result:=QWORD(x) shl MD_PAGE_SHIFT;
|
|
end;
|
|
|
|
function MD_OFF_TO_IDX(x:QWORD):QWORD; inline;
|
|
begin
|
|
Result:=QWORD(x) shr MD_PAGE_SHIFT;
|
|
end;
|
|
|
|
//
|
|
|
|
procedure t_danger_zone.Init;
|
|
begin
|
|
mtx_init(Flock,'danger_zone');
|
|
end;
|
|
|
|
procedure t_danger_zone.Done;
|
|
begin
|
|
mtx_destroy(Flock);
|
|
end;
|
|
|
|
function t_danger_zone.in_range(addr,size:vm_offset_t):Boolean;
|
|
var
|
|
range:t_danger_range;
|
|
begin
|
|
QWORD(range):=System.InterlockedExchangeAdd64(QWORD(Frange),0);
|
|
|
|
Result:=(addr<MD_IDX_TO_OFF(range.start+range._size)) and ((addr+size)>MD_IDX_TO_OFF(range.start));
|
|
end;
|
|
|
|
procedure t_danger_zone.d_wait(addr,size:vm_offset_t);
|
|
begin
|
|
mtx_lock(Flock);
|
|
|
|
if in_range(addr,size) then
|
|
begin
|
|
msleep(@Self,@Flock,PCATCH,'danger_zone',hz);
|
|
end;
|
|
|
|
mtx_unlock(Flock);
|
|
end;
|
|
|
|
procedure t_danger_zone.lock(start,__end:vm_offset_t);
|
|
var
|
|
range:t_danger_range;
|
|
begin
|
|
range.start:=MD_OFF_TO_IDX(start);
|
|
range._size:=MD_OFF_TO_IDX(__end-start);
|
|
|
|
System.InterlockedExchange64(QWORD(Frange),QWORD(range));
|
|
|
|
mtx_lock(Flock);
|
|
end;
|
|
|
|
procedure t_danger_zone.unlock;
|
|
begin
|
|
System.InterlockedExchange64(QWORD(Frange),0);
|
|
|
|
mtx_unlock(Flock);
|
|
|
|
wakeup(@Self);
|
|
end;
|
|
|
|
//
|
|
|
|
function vm_remap(map:p_vm_nt_map;
|
|
entry1:p_vm_nt_entry;
|
|
entry2:p_vm_nt_entry;
|
|
entry3:p_vm_nt_entry;
|
|
var stat:t_range_stat):Boolean;
|
|
var
|
|
ets:array[0..2] of p_vm_nt_entry;
|
|
first:p_vm_nt_entry;
|
|
curr :p_vm_nt_entry;
|
|
|
|
e_count:Integer;
|
|
r_count:Integer;
|
|
|
|
start:vm_offset_t;
|
|
__end:vm_offset_t;
|
|
size:vm_size_t;
|
|
|
|
max:Integer;
|
|
|
|
p:p_range;
|
|
i,r:Integer;
|
|
begin
|
|
Result:=False;
|
|
|
|
if (stat.obj=nil) then Exit(False);
|
|
|
|
ets[0]:=entry1;
|
|
ets[1]:=entry2;
|
|
ets[2]:=entry3;
|
|
|
|
//get first entry
|
|
first:=nil;
|
|
For i:=Low(ets) to High(ets) do
|
|
begin
|
|
curr:=ets[i];
|
|
|
|
if (curr<>nil) then
|
|
begin
|
|
first:=curr;
|
|
Break;
|
|
end;
|
|
end;
|
|
|
|
if (first=nil) then Exit(False);
|
|
|
|
if (stat.rcurr.start=first^.start) and
|
|
(stat.rcurr.__end=first^.__end) then Exit(False);
|
|
|
|
start:=0;
|
|
__end:=0;
|
|
e_count:=0;
|
|
r_count:=0;
|
|
|
|
//get range
|
|
For i:=Low(ets) to High(ets) do
|
|
begin
|
|
curr:=ets[i];
|
|
|
|
if (curr<>nil) then
|
|
begin
|
|
if (start=0) or (start>curr^.start) then
|
|
begin
|
|
start:=curr^.start;
|
|
end;
|
|
|
|
if (__end=0) or (__end<curr^.__end) then
|
|
begin
|
|
__end:=curr^.__end;
|
|
end;
|
|
|
|
Inc(e_count);
|
|
end;
|
|
end;
|
|
|
|
//danger zone
|
|
map^.danger_zone.lock(start,__end);
|
|
|
|
//unmap all
|
|
For i:=Low(stat.range) to High(stat.range) do
|
|
begin
|
|
p:=@stat.range[i];
|
|
//
|
|
if (p^.start<>0) and
|
|
(p^.start<>p^.__end) then
|
|
begin
|
|
//
|
|
if (stat.obj^.hfile<>0) then
|
|
begin
|
|
size:=p^.__end-p^.start;
|
|
|
|
r:=md_placeholder_decommit(Pointer(p^.start),size);
|
|
if (r<>0) then
|
|
begin
|
|
Writeln('failed md_placeholder_decommit(',HexStr(p^.start,11),',',HexStr(p^.__end,11),'):0x',HexStr(r,8));
|
|
Assert(false,'vm_remap');
|
|
end;
|
|
end;
|
|
//
|
|
//Writeln('md_file_unmap_ex(',HexStr(p^.start,11),',',HexStr(p^.__end,11),'):0x',HexStr(r,8));
|
|
//
|
|
Inc(r_count);
|
|
end;
|
|
end;
|
|
|
|
//union parts
|
|
if (r_count>1) then
|
|
begin
|
|
size:=__end-start;
|
|
|
|
r:=md_placeholder_union(Pointer(start),size);
|
|
if (r<>0) then
|
|
begin
|
|
Writeln('failed md_placeholder_union(',HexStr(start,11),',',HexStr(__end,11),'):0x',HexStr(r,8));
|
|
Assert(false,'vm_remap');
|
|
end;
|
|
//Writeln('md_union(',HexStr(start,11),',',HexStr(__end,11),'):0x',HexStr(r,8));
|
|
end;
|
|
|
|
//split to parts
|
|
if (e_count>1) then
|
|
For i:=Low(ets) to High(ets) do
|
|
begin
|
|
curr:=ets[i];
|
|
|
|
if (curr<>nil) and (curr<>first) then
|
|
begin
|
|
size:=curr^.__end-curr^.start;
|
|
|
|
r:=md_placeholder_split(Pointer(curr^.start),size);
|
|
if (r<>0) then
|
|
begin
|
|
Writeln('failed md_placeholder_split(',HexStr(curr^.start,11),',',HexStr(curr^.__end,11),'):0x',HexStr(r,8));
|
|
|
|
Writeln('(',HexStr(start,11),',',HexStr(__end,11),')');
|
|
|
|
Assert(false,'vm_remap');
|
|
end;
|
|
|
|
//Writeln('md_split(',HexStr(ets[i]^.start,11),',',HexStr(ets[i]^.__end,11),'):0x',HexStr(r,8));
|
|
|
|
Break; //middle or last splt
|
|
end;
|
|
end;
|
|
|
|
max:=stat.obj^.maxp;
|
|
|
|
//map new parts
|
|
For i:=Low(ets) to High(ets) do
|
|
begin
|
|
curr:=ets[i];
|
|
|
|
if (curr<>nil) then
|
|
begin
|
|
//map new
|
|
if (curr^.obj<>nil) then
|
|
if (stat.obj^.hfile<>0) then
|
|
begin
|
|
r:=md_placeholder_commit(Pointer(curr^.start),
|
|
curr^.usize, //unaligned size
|
|
(max and VM_RW),
|
|
stat.obj^.hfile,
|
|
curr^.offset);
|
|
if (r<>0) then
|
|
begin
|
|
Writeln('failed md_placeholder_commit(',HexStr(curr^.start,11),',',HexStr(curr^.__end,11),'):0x',HexStr(r,8));
|
|
Assert(false,'vm_remap');
|
|
end;
|
|
|
|
//Writeln('md_file_mmap_ex(',HexStr(ets[i]^.start,11),',',HexStr(ets[i]^.__end,11),'):0x',HexStr(r,8));
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//fix prot
|
|
|
|
For i:=Low(ets) to High(ets) do
|
|
begin
|
|
curr:=ets[i];
|
|
|
|
if (curr<>nil) then
|
|
begin
|
|
if (curr^.obj<>nil) then
|
|
if (stat.obj^.hfile<>0) then
|
|
begin
|
|
vm_nt_sub_map_prot_fixup(@curr^.sub,
|
|
curr^.start,
|
|
curr^.__end,
|
|
TRACK_PROT or REMAP_PROT //untrack trigger or restore track?
|
|
);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//danger zone
|
|
map^.danger_zone.unlock;
|
|
|
|
Result:=True;
|
|
end;
|
|
|
|
procedure vm_unmap(map:p_vm_nt_map;entry:p_vm_nt_entry);
|
|
var
|
|
start:vm_offset_t;
|
|
__end:vm_offset_t;
|
|
r:Integer;
|
|
begin
|
|
if (entry^.obj<>nil) then
|
|
if (entry^.obj^.hfile<>0) then
|
|
begin
|
|
r:=md_placeholder_decommit(Pointer(entry^.start),(entry^.__end-entry^.start));
|
|
if (r<>0) then
|
|
begin
|
|
Writeln('failed md_placeholder_decommit(',HexStr(entry^.start,11),',',HexStr(entry^.__end,11),'):0x',HexStr(r,8));
|
|
Assert(false,'vm_unmap');
|
|
end;
|
|
//Writeln('md_placeholder_decommit(',HexStr(entry^.start,11),',',HexStr(entry^.__end,11),'):0x',HexStr(r,8));
|
|
end;
|
|
|
|
vm_get_space(map,entry,start,__end);
|
|
|
|
if (start<>__end) then
|
|
if (entry^.start<>start) or
|
|
(entry^.__end<>__end) then
|
|
begin
|
|
r:=md_placeholder_union(Pointer(start),__end-start);
|
|
if (r<>0) then
|
|
begin
|
|
Writeln('failed md_placeholder_union(',HexStr(start,11),',',HexStr(__end,11),'):0x',HexStr(r,8));
|
|
|
|
Writeln('(',HexStr(entry^.start,11),',',HexStr(entry^.__end,11),'):0x',HexStr(r,8));
|
|
|
|
Assert(false,'vm_unmap');
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//
|
|
|
|
function vm_nt_map_max(map:p_vm_nt_map):vm_offset_t; inline;
|
|
begin
|
|
Result:=map^.max_offset;
|
|
end;
|
|
|
|
function vm_nt_map_min(map:p_vm_nt_map):vm_offset_t; inline;
|
|
begin
|
|
Result:=map^.min_offset;
|
|
end;
|
|
|
|
procedure VM_NT_MAP_RANGE_CHECK(map:p_vm_nt_map;var start,__end:vm_offset_t);
|
|
begin
|
|
if (start<vm_nt_map_min(map)) then
|
|
begin
|
|
start:=vm_nt_map_min(map);
|
|
end;
|
|
if (__end>vm_nt_map_max(map)) then
|
|
begin
|
|
__end:=vm_nt_map_max(map);
|
|
end;
|
|
if (start>__end) then
|
|
begin
|
|
start:=__end;
|
|
end;
|
|
end;
|
|
|
|
procedure vm_nt_map_init(map:p_vm_nt_map;min,max:vm_offset_t);
|
|
begin
|
|
map^.header.next:=@map^.header;
|
|
map^.header.prev:=@map^.header;
|
|
map^.min_offset:=min;
|
|
map^.max_offset:=max;
|
|
map^.root:=nil;
|
|
map^.danger_zone.Init;
|
|
mtx_init(map^.lock,'vm_nt_map');
|
|
end;
|
|
|
|
procedure vm_nt_map_lock(map:p_vm_nt_map); inline;
|
|
begin
|
|
mtx_lock(map^.lock);
|
|
end;
|
|
|
|
procedure vm_nt_map_unlock(map:p_vm_nt_map); inline;
|
|
begin
|
|
mtx_unlock(map^.lock);
|
|
end;
|
|
|
|
procedure vm_nt_entry_dispose(map:p_vm_nt_map;entry:p_vm_nt_entry); inline;
|
|
begin
|
|
FreeMem(entry);
|
|
end;
|
|
|
|
procedure vm_nt_entry_deallocate(map:p_vm_nt_map;entry:p_vm_nt_entry); inline;
|
|
begin
|
|
vm_nt_sub_map_free (@entry^.sub);
|
|
vm_nt_file_obj_deallocate(entry^.obj);
|
|
vm_nt_entry_dispose (map,entry);
|
|
end;
|
|
|
|
function vm_nt_entry_create(map:p_vm_nt_map):p_vm_nt_entry;
|
|
var
|
|
new_entry:p_vm_nt_entry;
|
|
begin
|
|
new_entry:=AllocMem(SizeOf(vm_nt_entry));
|
|
Assert((new_entry<>nil),'vm_nt_entry_create: kernel resources exhausted');
|
|
Result:=new_entry;
|
|
end;
|
|
|
|
function vm_nt_entry_splay(addr:vm_offset_t;root:p_vm_nt_entry):p_vm_nt_entry;
|
|
var
|
|
llist,rlist:p_vm_nt_entry;
|
|
ltree,rtree:p_vm_nt_entry;
|
|
y :p_vm_nt_entry;
|
|
begin
|
|
if (root=nil) then Exit(root);
|
|
|
|
llist:=nil;
|
|
rlist:=nil;
|
|
repeat
|
|
if (addr<root^.start) then
|
|
begin
|
|
y:=root^.left;
|
|
if (y=nil) then break;
|
|
if (addr<y^.start) and (y^.left<>nil) then
|
|
begin
|
|
root^.left:=y^.right;
|
|
y^.right:=root;
|
|
root:=y^.left;
|
|
y^.left:=rlist;
|
|
rlist:=y;
|
|
end else
|
|
begin
|
|
root^.left:=rlist;
|
|
rlist:=root;
|
|
root:=y;
|
|
end;
|
|
end else
|
|
if (addr>=root^.__end) then
|
|
begin
|
|
y:=root^.right;
|
|
if (y=nil) then break;
|
|
if (addr>=y^.__end) and (y^.right<>nil) then
|
|
begin
|
|
root^.right:=y^.left;
|
|
y^.left:=root;
|
|
root:=y^.right;
|
|
y^.right:=llist;
|
|
llist:=y;
|
|
end else
|
|
begin
|
|
root^.right:=llist;
|
|
llist:=root;
|
|
root:=y;
|
|
end;
|
|
end else
|
|
begin
|
|
break;
|
|
end;
|
|
until false;
|
|
|
|
ltree:=root^.left;
|
|
while (llist<>nil) do
|
|
begin
|
|
y:=llist^.right;
|
|
llist^.right:=ltree;
|
|
ltree:=llist;
|
|
llist:=y;
|
|
end;
|
|
rtree:=root^.right;
|
|
while (rlist<>nil) do
|
|
begin
|
|
y:=rlist^.left;
|
|
rlist^.left:=rtree;
|
|
rtree:=rlist;
|
|
rlist:=y;
|
|
end;
|
|
|
|
root^.left:=ltree;
|
|
root^.right:=rtree;
|
|
|
|
Result:=(root);
|
|
end;
|
|
|
|
procedure vm_nt_entry_link(
|
|
map :p_vm_nt_map;
|
|
after_where:p_vm_nt_entry;
|
|
entry :p_vm_nt_entry);
|
|
begin
|
|
entry^.prev:=after_where;
|
|
entry^.next:=after_where^.next;
|
|
entry^.next^.prev:=entry;
|
|
after_where^.next:=entry;
|
|
|
|
if (after_where<>@map^.header) then
|
|
begin
|
|
if (after_where<>map^.root) then
|
|
begin
|
|
vm_nt_entry_splay(after_where^.start, map^.root);
|
|
end;
|
|
entry^.right:=after_where^.right;
|
|
entry^.left:=after_where;
|
|
after_where^.right:=nil;
|
|
end else
|
|
begin
|
|
entry^.right:=map^.root;
|
|
entry^.left:=nil;
|
|
end;
|
|
map^.root:=entry;
|
|
end;
|
|
|
|
procedure vm_nt_entry_unlink(
|
|
map :p_vm_nt_map;
|
|
entry :p_vm_nt_entry);
|
|
var
|
|
next,prev,root:p_vm_nt_entry;
|
|
begin
|
|
if (entry<>map^.root) then
|
|
begin
|
|
vm_nt_entry_splay(entry^.start, map^.root);
|
|
end;
|
|
if (entry^.left=nil) then
|
|
begin
|
|
root:=entry^.right;
|
|
end else
|
|
begin
|
|
root:=vm_nt_entry_splay(entry^.start, entry^.left);
|
|
root^.right:=entry^.right;
|
|
end;
|
|
map^.root:=root;
|
|
|
|
prev:=entry^.prev;
|
|
next:=entry^.next;
|
|
next^.prev:=prev;
|
|
prev^.next:=next;
|
|
end;
|
|
|
|
function vm_nt_map_lookup_entry(
|
|
map :p_vm_nt_map;
|
|
address :vm_offset_t;
|
|
entry :pp_vm_nt_entry):Boolean;
|
|
var
|
|
cur:p_vm_nt_entry;
|
|
begin
|
|
cur:=map^.root;
|
|
if (cur=nil) then
|
|
begin
|
|
entry^:=@map^.header;
|
|
end else
|
|
if (address>=cur^.start) and (cur^.__end>address) then
|
|
begin
|
|
entry^:=cur;
|
|
Exit(TRUE);
|
|
end else
|
|
begin
|
|
|
|
cur:=vm_nt_entry_splay(address,cur);
|
|
map^.root:=cur;
|
|
|
|
if (address>=cur^.start) then
|
|
begin
|
|
entry^:=cur;
|
|
if (cur^.__end>address) then
|
|
begin
|
|
Exit(TRUE);
|
|
end;
|
|
end else
|
|
begin
|
|
entry^:=cur^.prev;
|
|
end;
|
|
end;
|
|
Result:=(FALSE);
|
|
end;
|
|
|
|
function vm_nt_map_simplify_entry(map:p_vm_nt_map;entry:p_vm_nt_entry;var sb:t_range_stat):Boolean; forward;
|
|
|
|
function _vm_nt_map_insert(
|
|
map :p_vm_nt_map;
|
|
obj :p_vm_nt_file_obj;
|
|
offset:vm_ooffset_t;
|
|
start :vm_offset_t;
|
|
__end :vm_offset_t;
|
|
usize :vm_offset_t; //unaligned size
|
|
prot :Integer):Integer;
|
|
var
|
|
new_entry :p_vm_nt_entry;
|
|
prev_entry:p_vm_nt_entry;
|
|
temp_entry:p_vm_nt_entry;
|
|
stat :t_range_stat;
|
|
begin
|
|
if (start<map^.min_offset) or (__end>map^.max_offset) or (start>=__end) then
|
|
begin
|
|
Exit(KERN_INVALID_ADDRESS);
|
|
end;
|
|
|
|
if vm_nt_map_lookup_entry(map,start,@temp_entry) then
|
|
begin
|
|
Exit(KERN_NO_SPACE);
|
|
end;
|
|
|
|
prev_entry:=temp_entry;
|
|
|
|
if (prev_entry^.next<>@map^.header) and
|
|
(prev_entry^.next^.start<__end) then
|
|
begin
|
|
Exit(KERN_NO_SPACE);
|
|
end;
|
|
|
|
new_entry:=vm_nt_entry_create(map);
|
|
new_entry^.start :=start;
|
|
new_entry^.__end :=__end;
|
|
new_entry^.usize :=usize; //unaligned size
|
|
new_entry^.obj :=obj;
|
|
new_entry^.offset:=offset;
|
|
|
|
vm_nt_sub_map_init (@new_entry^.sub,start,__end);
|
|
|
|
//fill full map
|
|
vm_nt_sub_map_insert(@new_entry^.sub,start,__end,prot);
|
|
|
|
vm_nt_entry_link(map, prev_entry, new_entry);
|
|
|
|
vm_map(map,new_entry,prot);
|
|
|
|
vm_nt_map_simplify_entry(map,new_entry,stat);
|
|
|
|
vm_remap(map,new_entry,nil,nil,stat);
|
|
|
|
Result:=KERN_SUCCESS;
|
|
end;
|
|
|
|
function vm_nt_map_insert(
|
|
map :p_vm_nt_map;
|
|
obj :p_vm_nt_file_obj;
|
|
offset:vm_ooffset_t;
|
|
start :vm_offset_t;
|
|
__end :vm_offset_t;
|
|
usize :vm_offset_t; //unaligned size
|
|
prot :Integer):Integer;
|
|
begin
|
|
if (start=__end) then
|
|
begin
|
|
Exit(KERN_SUCCESS);
|
|
end;
|
|
|
|
vm_nt_map_lock(map);
|
|
|
|
Result:=_vm_nt_map_insert(
|
|
map ,
|
|
obj ,
|
|
offset,
|
|
start ,
|
|
__end ,
|
|
usize ,
|
|
prot );
|
|
|
|
vm_nt_map_unlock(map);
|
|
end;
|
|
|
|
function vm_nt_map_simplify_entry(map:p_vm_nt_map;entry:p_vm_nt_entry;var sb:t_range_stat):Boolean;
|
|
var
|
|
next,prev:p_vm_nt_entry;
|
|
prevsize,esize:vm_size_t;
|
|
stat:t_range_stat;
|
|
begin
|
|
vm_init_stat(stat,entry);
|
|
|
|
if (stat.obj<>nil) then
|
|
if ((stat.obj^.flags and NT_UNION_OBJ)=0) then
|
|
begin
|
|
sb:=stat;
|
|
Exit(False);
|
|
end;
|
|
|
|
if ((stat.rcurr.__end-stat.rcurr.start)>MAX_UNION_SIZE) then
|
|
begin
|
|
sb:=stat;
|
|
Exit(False);
|
|
end;
|
|
|
|
prev:=entry^.prev;
|
|
if (prev<>@map^.header) then
|
|
begin
|
|
prevsize:=prev^.__end - prev^.start;
|
|
if (prev^.__end=stat.rcurr.start) and
|
|
(prevsize<=MAX_UNION_SIZE) and
|
|
(prev^.obj=stat.obj) and
|
|
((prev^.obj=nil) or (prev^.offset + prevsize=entry^.offset))
|
|
then
|
|
begin
|
|
vm_nt_entry_unlink(map, prev);
|
|
|
|
stat.rprev.start:=prev^.start;
|
|
stat.rprev.__end:=prev^.__end;
|
|
|
|
entry^.start :=prev^.start;
|
|
entry^.offset:=prev^.offset;
|
|
entry^.usize :=entry^.usize+prev^.usize; //unaligned size
|
|
|
|
//update (implicitly)
|
|
//entry^.sub.min_offset:=entry^.start;
|
|
|
|
//move
|
|
vm_nt_sub_map_move(@entry^.sub,@prev^.sub);
|
|
|
|
vm_nt_entry_deallocate(map,prev);
|
|
end;
|
|
end;
|
|
|
|
next:=entry^.next;
|
|
if (next<>@map^.header) then
|
|
begin
|
|
esize:=stat.rcurr.__end - entry^.start;
|
|
if (stat.rcurr.__end=next^.start) and
|
|
(esize<=MAX_UNION_SIZE) and
|
|
(next^.obj=stat.obj) and
|
|
((stat.obj=nil) or (entry^.offset + esize=next^.offset))
|
|
then
|
|
begin
|
|
vm_nt_entry_unlink(map, next);
|
|
|
|
stat.rnext.start:=next^.start;
|
|
stat.rnext.__end:=next^.__end;
|
|
|
|
entry^.__end:=next^.__end;
|
|
entry^.usize:=entry^.usize+next^.usize; //unaligned size
|
|
|
|
//update (implicitly)
|
|
//entry^.sub.max_offset:=entry^.__end;
|
|
|
|
//move
|
|
vm_nt_sub_map_move(@entry^.sub,@next^.sub);
|
|
|
|
vm_nt_entry_deallocate(map,next);
|
|
end;
|
|
end;
|
|
|
|
sb:=stat;
|
|
Result:=True;
|
|
end;
|
|
|
|
procedure vm_nt_map_simplify_entry(map:p_vm_nt_map;entry:p_vm_nt_entry);
|
|
var
|
|
stat:t_range_stat;
|
|
begin
|
|
vm_nt_map_simplify_entry(map,entry,stat);
|
|
|
|
vm_remap(map,entry,nil,nil,stat);
|
|
end;
|
|
|
|
procedure vm_nt_map_clip_start_end(map:p_vm_nt_map;entry:p_vm_nt_entry;start,__end:vm_offset_t);
|
|
var
|
|
prev:p_vm_nt_entry;
|
|
next:p_vm_nt_entry;
|
|
stat:t_range_stat;
|
|
begin
|
|
prev:=nil;
|
|
next:=nil;
|
|
|
|
vm_nt_map_simplify_entry(map,entry,stat);
|
|
|
|
//entry[start ,end]
|
|
//prev [start | entry[end]
|
|
|
|
if (start>entry^.start) then
|
|
begin
|
|
prev:=vm_nt_entry_create(map);
|
|
prev^:=entry^;
|
|
|
|
prev^.__end:=start;
|
|
prev^.usize:=(prev^.__end-prev^.start); //unaligned size
|
|
|
|
//new map
|
|
vm_nt_sub_map_init(@prev^.sub,prev^.start,prev^.__end);
|
|
|
|
//move
|
|
vm_nt_sub_map_clip(@prev^.sub,@entry^.sub);
|
|
|
|
entry^.offset:=entry^.offset + (start - entry^.start);
|
|
entry^.start :=start;
|
|
entry^.usize :=entry^.usize-prev^.usize; //unaligned size
|
|
|
|
//update (implicitly)
|
|
//prev ^.sub.max_offset:=start;
|
|
//entry^.sub.min_offset:=start;
|
|
|
|
vm_nt_entry_link(map, entry^.prev, prev);
|
|
vm_nt_file_obj_reference(prev^.obj);
|
|
end;
|
|
|
|
//entry[start ,end]
|
|
//entry[start | next[end]
|
|
|
|
if (__end<entry^.__end) then
|
|
begin
|
|
next:=vm_nt_entry_create(map);
|
|
next^:=entry^;
|
|
|
|
next^.start :=__end;
|
|
|
|
//new map
|
|
vm_nt_sub_map_init(@next^.sub,next^.start,next^.__end);
|
|
|
|
//move
|
|
vm_nt_sub_map_clip(@next^.sub,@entry^.sub);
|
|
|
|
entry^.__end:=__end;
|
|
entry^.usize:=(entry^.__end-entry^.start); //unaligned size
|
|
|
|
next^.offset:=next^.offset + (__end - entry^.start);
|
|
next^.usize :=next^.usize-entry^.usize; //unaligned size
|
|
|
|
//update (implicitly)
|
|
//next ^.sub.min_offset:=__end;
|
|
//entry^.sub.max_offset:=__end;
|
|
|
|
vm_nt_entry_link(map, entry, next);
|
|
vm_nt_file_obj_reference(next^.obj);
|
|
end;
|
|
|
|
//
|
|
|
|
if (prev<>nil) or (next<>nil) then
|
|
begin
|
|
//exclude entry
|
|
vm_nt_file_obj_deallocate(entry^.obj);
|
|
entry^.obj:=nil;
|
|
end;
|
|
|
|
vm_remap(map,prev,entry,next,stat);
|
|
|
|
end;
|
|
|
|
procedure vm_nt_map_clip_end(map:p_vm_nt_map;entry:p_vm_nt_entry;__end:vm_offset_t);
|
|
var
|
|
next:p_vm_nt_entry;
|
|
stat:t_range_stat;
|
|
begin
|
|
next:=nil;
|
|
|
|
vm_init_stat(stat,entry);
|
|
|
|
//
|
|
|
|
//entry[start ,end]
|
|
//entry[start | next[end]
|
|
|
|
if (__end<entry^.__end) then
|
|
begin
|
|
next:=vm_nt_entry_create(map);
|
|
next^:=entry^;
|
|
|
|
next^.start :=__end;
|
|
|
|
//new map
|
|
vm_nt_sub_map_init(@next^.sub,next^.start,next^.__end);
|
|
|
|
//move
|
|
vm_nt_sub_map_clip(@next^.sub,@entry^.sub);
|
|
|
|
entry^.__end:=__end;
|
|
entry^.usize:=(entry^.__end-entry^.start); //unaligned size
|
|
|
|
next^.offset:=next^.offset + (__end - entry^.start);
|
|
next^.usize :=next^.usize-entry^.usize; //unaligned size
|
|
|
|
//update (implicitly)
|
|
//next ^.sub.min_offset:=__end;
|
|
//entry^.sub.max_offset:=__end;
|
|
|
|
vm_nt_entry_link(map, entry, next);
|
|
vm_nt_file_obj_reference(next^.obj);
|
|
end;
|
|
|
|
//
|
|
|
|
if (next<>nil) then
|
|
begin
|
|
//exclude entry
|
|
vm_nt_file_obj_deallocate(entry^.obj);
|
|
entry^.obj:=nil;
|
|
end;
|
|
|
|
vm_remap(map,nil,entry,next,stat);
|
|
|
|
end;
|
|
|
|
procedure vm_nt_entry_delete(map:p_vm_nt_map;entry:p_vm_nt_entry); inline;
|
|
begin
|
|
vm_nt_entry_unlink (map, entry);
|
|
vm_nt_entry_deallocate(map, entry);
|
|
end;
|
|
|
|
function vm_nt_map_delete(map:p_vm_nt_map;start:vm_offset_t;__end:vm_offset_t):Integer;
|
|
var
|
|
entry :p_vm_nt_entry;
|
|
first_entry:p_vm_nt_entry;
|
|
next :p_vm_nt_entry;
|
|
begin
|
|
if (start=__end) then
|
|
begin
|
|
Exit(KERN_SUCCESS);
|
|
end;
|
|
|
|
vm_nt_map_lock(map);
|
|
|
|
if (not vm_nt_map_lookup_entry(map, start, @first_entry)) then
|
|
begin
|
|
entry:=first_entry^.next;
|
|
|
|
end else
|
|
begin
|
|
entry:=first_entry;
|
|
|
|
vm_nt_map_clip_start_end(map, entry, start, __end);
|
|
end;
|
|
|
|
while (entry<>@map^.header) and (entry^.start<__end) do
|
|
begin
|
|
|
|
vm_nt_map_clip_end(map, entry, __end);
|
|
|
|
next:=entry^.next;
|
|
|
|
vm_unmap(map,entry);
|
|
|
|
vm_nt_entry_delete(map, entry);
|
|
|
|
entry:=next;
|
|
end;
|
|
|
|
vm_nt_map_unlock(map);
|
|
|
|
Result:=(KERN_SUCCESS);
|
|
end;
|
|
|
|
procedure vm_nt_map_protect(map :p_vm_nt_map;
|
|
start:vm_offset_t;
|
|
__end:vm_offset_t;
|
|
prot :Integer);
|
|
var
|
|
entry:p_vm_nt_entry;
|
|
e_start:vm_offset_t;
|
|
e___end:vm_offset_t;
|
|
max:Integer;
|
|
begin
|
|
if (start=__end) then Exit;
|
|
|
|
vm_nt_map_lock(map);
|
|
|
|
if (not vm_nt_map_lookup_entry(map, start, @entry)) then
|
|
begin
|
|
entry:=entry^.next;
|
|
end else
|
|
begin
|
|
//
|
|
end;
|
|
|
|
while (entry<>@map^.header) and (entry^.start<__end) do
|
|
begin
|
|
e_start:=entry^.start;
|
|
e___end:=entry^.__end;
|
|
|
|
if (e_start<start) then
|
|
begin
|
|
e_start:=start;
|
|
end;
|
|
|
|
if (e___end>__end) then
|
|
begin
|
|
e___end:=__end;
|
|
end;
|
|
|
|
if (e___end>e_start) then
|
|
begin
|
|
|
|
if (entry^.obj<>nil) then
|
|
begin
|
|
max:=entry^.obj^.maxp;
|
|
end else
|
|
begin
|
|
max:=0;
|
|
end;
|
|
|
|
vm_nt_sub_map_protect(@entry^.sub,e_start,e___end,(prot and max and VM_RW));
|
|
end;
|
|
|
|
entry:=entry^.next;
|
|
end;
|
|
|
|
vm_nt_map_unlock(map);
|
|
end;
|
|
|
|
procedure vm_nt_map_tracking(map :p_vm_nt_map;
|
|
start:vm_offset_t;
|
|
__end:vm_offset_t;
|
|
prot :Integer);
|
|
var
|
|
entry:p_vm_nt_entry;
|
|
e_start:vm_offset_t;
|
|
e___end:vm_offset_t;
|
|
begin
|
|
if (start=__end) then Exit;
|
|
|
|
vm_nt_map_lock(map);
|
|
|
|
if (not vm_nt_map_lookup_entry(map, start, @entry)) then
|
|
begin
|
|
entry:=entry^.next;
|
|
end else
|
|
begin
|
|
//
|
|
end;
|
|
|
|
while (entry<>@map^.header) and (entry^.start<__end) do
|
|
begin
|
|
e_start:=entry^.start;
|
|
e___end:=entry^.__end;
|
|
|
|
if (e_start<start) then
|
|
begin
|
|
e_start:=start;
|
|
end;
|
|
|
|
if (e___end>__end) then
|
|
begin
|
|
e___end:=__end;
|
|
end;
|
|
|
|
if (e___end>e_start) then
|
|
begin
|
|
vm_nt_sub_map_tracking(@entry^.sub,e_start,e___end,prot);
|
|
end;
|
|
|
|
entry:=entry^.next;
|
|
end;
|
|
|
|
vm_nt_map_unlock(map);
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure vm_nt_map_prot_fix(map :p_vm_nt_map;
|
|
start:vm_offset_t;
|
|
__end:vm_offset_t;
|
|
mode :Integer);
|
|
var
|
|
entry:p_vm_nt_entry;
|
|
e_start:vm_offset_t;
|
|
e___end:vm_offset_t;
|
|
begin
|
|
if (start=__end) then Exit;
|
|
|
|
vm_nt_map_lock(map);
|
|
|
|
if (not vm_nt_map_lookup_entry(map, start, @entry)) then
|
|
begin
|
|
entry:=entry^.next;
|
|
end else
|
|
begin
|
|
entry:=entry;
|
|
end;
|
|
|
|
while (entry<>@map^.header) and (entry^.start<__end) do
|
|
begin
|
|
|
|
if (entry^.obj<>nil) then
|
|
begin
|
|
e_start:=entry^.start;
|
|
e___end:=entry^.__end;
|
|
|
|
if (e_start<start) then
|
|
begin
|
|
e_start:=start;
|
|
end;
|
|
|
|
if (e___end>__end) then
|
|
begin
|
|
e___end:=__end;
|
|
end;
|
|
|
|
if (e___end>e_start) then
|
|
begin
|
|
vm_nt_sub_map_prot_fixup(@entry^.sub,e_start,e___end,mode);
|
|
end;
|
|
end;
|
|
|
|
entry:=entry^.next;
|
|
end;
|
|
|
|
vm_nt_map_unlock(map);
|
|
end;
|
|
|
|
//rdi, rsi
|
|
procedure ZeroPages(addr:Pointer;size:Ptruint); assembler nostackframe SysV_ABI_CDecl;
|
|
label
|
|
_exit,
|
|
_rep;
|
|
asm
|
|
shr $5, %rsi // div 32
|
|
jz _exit
|
|
|
|
vpxor %ymm0, %ymm0, %ymm0 //zero
|
|
|
|
_rep:
|
|
|
|
vmovaps %ymm0, (%rdi)
|
|
|
|
lea 32(%rdi),%rdi
|
|
dec %rsi
|
|
|
|
jnz _rep
|
|
|
|
_exit:
|
|
end;
|
|
|
|
procedure vm_nt_map_madvise(map :p_vm_nt_map;
|
|
start :vm_offset_t;
|
|
__end :vm_offset_t;
|
|
advise:Integer);
|
|
var
|
|
entry:p_vm_nt_entry;
|
|
base,size:vm_size_t;
|
|
mirror:Pointer;
|
|
begin
|
|
if (start=__end) then Exit;
|
|
|
|
vm_nt_map_lock(map);
|
|
|
|
if (not vm_nt_map_lookup_entry(map, start, @entry)) then
|
|
begin
|
|
entry:=entry^.next;
|
|
end else
|
|
begin
|
|
entry:=entry;
|
|
end;
|
|
|
|
while (entry<>@map^.header) and (entry^.start<__end) do
|
|
begin
|
|
base:=entry^.start;
|
|
size:=entry^.__end;
|
|
|
|
if (base<start) then
|
|
begin
|
|
base:=start;
|
|
end;
|
|
|
|
if (size>__end) then
|
|
begin
|
|
size:=__end;
|
|
end;
|
|
|
|
size:=size-base;
|
|
|
|
case advise of
|
|
MADV_WILLNEED:md_activate(Pointer(base),size);
|
|
//
|
|
MADV_DONTNEED:md_dontneed(Pointer(base),size);
|
|
MADV_FREE :md_dontneed(Pointer(base),size);
|
|
//
|
|
MADV_NORMAL: //internal only
|
|
if (md_activate(Pointer(base),size)=0) then
|
|
begin
|
|
//page is restored, zero it
|
|
|
|
mirror:=vm_nt_map_mirror(map,base,base+size);
|
|
if (mirror<>nil) then
|
|
begin
|
|
ZeroPages (mirror,size);
|
|
md_placeholder_unmap(mirror,size);
|
|
end;
|
|
|
|
end;
|
|
else;
|
|
end;
|
|
|
|
//ignore errors
|
|
|
|
entry:=entry^.next;
|
|
end;
|
|
|
|
vm_nt_map_unlock(map);
|
|
end;
|
|
|
|
|
|
function vm_nt_map_mirror(map :p_vm_nt_map;
|
|
start:vm_offset_t;
|
|
__end:vm_offset_t):Pointer;
|
|
var
|
|
entry:p_vm_nt_entry;
|
|
base,b_end,size,prev:vm_size_t;
|
|
offset:vm_ooffset_t;
|
|
curr:Pointer;
|
|
obj:p_vm_nt_file_obj;
|
|
max:Integer;
|
|
r:Integer;
|
|
begin
|
|
Result:=nil;
|
|
if (start=__end) then Exit;
|
|
|
|
r:=md_placeholder_mmap(Result,__end-start);
|
|
if (r<>0) then
|
|
begin
|
|
Writeln('failed md_placeholder_mmap(',HexStr(__end-start,11),'):0x',HexStr(r,8));
|
|
Assert(false,'vm_map');
|
|
Exit;
|
|
end;
|
|
|
|
vm_nt_map_lock(map);
|
|
|
|
if (not vm_nt_map_lookup_entry(map, start, @entry)) then
|
|
begin
|
|
entry:=entry^.next;
|
|
end;
|
|
|
|
prev:=0;
|
|
|
|
while (entry<>@map^.header) and (entry^.start<__end) do
|
|
begin
|
|
obj:=entry^.obj;
|
|
|
|
if (obj<>nil) then
|
|
if (obj^.hfile<>0) then
|
|
begin
|
|
base :=entry^.start;
|
|
b_end :=entry^.__end;
|
|
offset:=entry^.offset;
|
|
|
|
if (base<start) then
|
|
begin
|
|
offset:=offset+(start-base);
|
|
base:=start;
|
|
end;
|
|
|
|
if (b_end>__end) then
|
|
begin
|
|
b_end:=__end;
|
|
end;
|
|
|
|
size:=b_end-base;
|
|
|
|
//addr in mirror
|
|
curr:=Result+(base-start);
|
|
|
|
if ((base<>start) and (base<>prev)) or
|
|
(b_end<>__end) then
|
|
begin
|
|
r:=md_placeholder_split(curr,size);
|
|
if (r<>0) then
|
|
begin
|
|
Writeln('failed md_placeholder_split(',HexStr(curr),',',HexStr(curr+size),'):0x',HexStr(r,8));
|
|
Assert(false,'vm_map');
|
|
end;
|
|
end;
|
|
|
|
prev:=b_end;
|
|
|
|
max:=obj^.maxp;
|
|
|
|
r:=md_placeholder_commit(curr,
|
|
size,
|
|
(max and VM_RW),
|
|
obj^.hfile,
|
|
offset);
|
|
if (r<>0) then
|
|
begin
|
|
Writeln('failed md_placeholder_commit(',HexStr(curr),',',HexStr(curr+size),'):0x',HexStr(r,8));
|
|
Assert(false,'vm_map');
|
|
end;
|
|
|
|
end;
|
|
|
|
entry:=entry^.next;
|
|
end;
|
|
|
|
vm_nt_map_unlock(map);
|
|
end;
|
|
|
|
function vm_nt_map_fetch(map :p_vm_nt_map;
|
|
start :vm_offset_t;
|
|
__end :vm_offset_t;
|
|
var p__start:vm_offset_t;
|
|
var p____end:vm_offset_t;
|
|
var p_offset:vm_offset_t;
|
|
var p____obj:p_vm_nt_file_obj
|
|
):Boolean;
|
|
var
|
|
entry:p_vm_nt_entry;
|
|
obj:p_vm_nt_file_obj;
|
|
begin
|
|
Result:=False;
|
|
if (start=__end) then Exit;
|
|
|
|
vm_nt_map_lock(map);
|
|
|
|
if (not vm_nt_map_lookup_entry(map, start, @entry)) then
|
|
begin
|
|
entry:=entry^.next;
|
|
end;
|
|
|
|
if (entry<>@map^.header) and (entry^.start<__end) then
|
|
begin
|
|
|
|
p__start:=entry^.start;
|
|
p____end:=entry^.__end;
|
|
p_offset:=entry^.offset;
|
|
p____obj:=nil;
|
|
|
|
obj:=entry^.obj;
|
|
|
|
if (obj<>nil) then
|
|
if (obj^.hfile<>0) then
|
|
begin
|
|
p____obj:=obj;
|
|
end;
|
|
|
|
Result:=True;
|
|
end;
|
|
|
|
vm_nt_map_unlock(map);
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
end.
|
|
|