mirror of https://github.com/red-prig/fpPS4.git
1771 lines
36 KiB
Plaintext
1771 lines
36 KiB
Plaintext
unit vm_tracking_map;
|
|
|
|
{$mode ObjFPC}{$H+}
|
|
{$CALLING SysV_ABI_CDecl}
|
|
|
|
interface
|
|
|
|
uses
|
|
vm,
|
|
mqueue,
|
|
vm_pmap_prot,
|
|
//kern_mtx
|
|
kern_rangelock
|
|
;
|
|
|
|
type
|
|
p_vm_track_interval=^t_vm_track_interval;
|
|
t_vm_track_interval=record
|
|
start:vm_offset_t;
|
|
__end:vm_offset_t;
|
|
end;
|
|
|
|
const
|
|
PAGE_TRACK_R=vm_pmap_prot.PAGE_TRACK_R;
|
|
PAGE_TRACK_W=vm_pmap_prot.PAGE_TRACK_W;
|
|
|
|
DO_NOTHING =0;
|
|
DO_DELETE =1;
|
|
DO_INCREMENT=2;
|
|
|
|
type
|
|
T_THANDLE_TYPE=(H_ZERO,H_JIT_CHUNK,H_GPU_IMAGE,H_GPU_BUF);
|
|
T_TRIGGER_MODE=(M_CPU_WRITE,M_DMEM_WRITE,M_GPU_PLANNED,M_GPU_APPLY);
|
|
|
|
type
|
|
t_on_destroy=function(handle:Pointer):Integer;
|
|
t_on_trigger=function(handle:Pointer;mode:T_TRIGGER_MODE):Integer;
|
|
t_on_overlap=function(handle:Pointer;data:Pointer):Integer;
|
|
|
|
p_vm_track_object=^t_vm_track_object;
|
|
t_vm_track_object=packed record
|
|
del_link :TAILQ_ENTRY; //p_vm_track_map->delete_deferred
|
|
//iter_link :TAILQ_ENTRY;
|
|
//
|
|
handle :Pointer;
|
|
//
|
|
main :t_vm_track_interval;
|
|
align :t_vm_track_interval;
|
|
instances :TAILQ_HEAD; //p_vm_track_object_instance
|
|
//
|
|
on_destroy:t_on_destroy;
|
|
on_trigger:t_on_trigger;
|
|
on_overlap:t_on_overlap;
|
|
//
|
|
ref_count :DWORD;
|
|
htype :T_THANDLE_TYPE;
|
|
mark_del :Byte;
|
|
prot :Byte;
|
|
end;
|
|
|
|
pp_vm_track_map_entry=^p_vm_track_map_entry;
|
|
p_vm_track_map_entry=^t_vm_track_map_entry;
|
|
t_vm_track_map_entry=packed record
|
|
prev :p_vm_track_map_entry; // previous entry
|
|
next :p_vm_track_map_entry; // next entry
|
|
left :p_vm_track_map_entry; // left child in binary search tree
|
|
right :p_vm_track_map_entry; // right child in binary search tree
|
|
start :vm_offset_t; // start address
|
|
__end :vm_offset_t; // end address
|
|
instances:Pointer; // p_vm_track_object_instance
|
|
instcount:QWORD;
|
|
//
|
|
track_r :DWORD;
|
|
track_w :DWORD;
|
|
//
|
|
prot :Byte;
|
|
mark_cpu :Boolean;
|
|
end;
|
|
|
|
p_vm_track_object_instance=^t_vm_track_object_instance;
|
|
t_vm_track_object_instance=record
|
|
pLeft :p_vm_track_object_instance; //p_vm_track_map_entry->instances
|
|
pRight :p_vm_track_object_instance; //p_vm_track_map_entry->instances
|
|
obj_link :TAILQ_ENTRY; //p_vm_track_object ->instances
|
|
entry :p_vm_track_map_entry;
|
|
obj :p_vm_track_object;
|
|
source :vm_offset_t; // source of mirror
|
|
end;
|
|
|
|
p_vm_track_deferred=^t_vm_track_deferred;
|
|
t_vm_track_deferred=record
|
|
entry :TAILQ_ENTRY;
|
|
start :vm_offset_t;
|
|
__end :vm_offset_t;
|
|
source:vm_offset_t;
|
|
obj :p_vm_track_object;
|
|
end;
|
|
|
|
p_vm_track_map=^t_vm_track_map;
|
|
t_vm_track_map=object
|
|
header :t_vm_track_map_entry; // List of entries
|
|
//lock :mtx; // Lock for map data
|
|
vm_map :Pointer;
|
|
root :p_vm_track_map_entry; // Root of a binary search tree
|
|
nentries :Integer; // Number of entries
|
|
|
|
insert_deferred:record
|
|
free:TAILQ_HEAD; //p_vm_track_deferred
|
|
list:TAILQ_HEAD; //p_vm_track_deferred
|
|
stub:array[0..3] of t_vm_track_deferred;
|
|
end;
|
|
|
|
delete_deferred:TAILQ_HEAD; //p_vm_track_object
|
|
|
|
pmap :Pointer;
|
|
property min_offset:vm_offset_t read header.start write header.start;
|
|
property max_offset:vm_offset_t read header.__end write header.__end;
|
|
end;
|
|
|
|
procedure vm_track_map_init(map:p_vm_track_map;min,max:vm_offset_t;vm_map:Pointer);
|
|
|
|
//
|
|
|
|
function vm_track_object_allocate (handle:Pointer;start,__end:vm_offset_t;htype:T_THANDLE_TYPE;prot:Byte):p_vm_track_object;
|
|
procedure vm_track_object_deallocate(obj:p_vm_track_object);
|
|
procedure vm_track_object_reference (obj:p_vm_track_object);
|
|
|
|
//
|
|
|
|
procedure vm_track_map_lock (map:p_vm_track_map);
|
|
procedure vm_track_map_unlock(map:p_vm_track_map;def:Boolean=True);
|
|
|
|
function _vm_track_map_insert(map:p_vm_track_map;start,__end,source:vm_offset_t;obj:p_vm_track_object):Integer;
|
|
|
|
procedure _vm_track_map_insert_deferred(map:p_vm_track_map;start,__end,source:vm_offset_t;obj:p_vm_track_object);
|
|
function _vm_track_map_delete_deferred(map:p_vm_track_map;obj:p_vm_track_object):Boolean;
|
|
|
|
function _vm_track_map_insert_mirror(map:p_vm_track_map;start,__end,dst:vm_offset_t):Integer;
|
|
|
|
//
|
|
|
|
function vm_track_map_remove_object (map:p_vm_track_map;obj:p_vm_track_object):Integer;
|
|
function vm_track_map_remove_memory (map:p_vm_track_map;start,__end:vm_offset_t):Integer;
|
|
function vm_track_map_trigger (map:p_vm_track_map;start,__end:vm_offset_t;exclude:Pointer;mode:T_TRIGGER_MODE):Integer;
|
|
function vm_track_map_trigger2 (map:p_vm_track_map;var start,__end:vm_offset_t;exclude:Pointer;mode:T_TRIGGER_MODE):Integer;
|
|
|
|
function vm_track_map_next_object (map:p_vm_track_map;start:vm_offset_t;obj:p_vm_track_object;htype:T_THANDLE_TYPE):p_vm_track_object;
|
|
|
|
procedure vm_track_map_restore_object(map:p_vm_track_map;obj:p_vm_track_object);
|
|
|
|
procedure vm_track_map_set_prot (map:p_vm_track_map;obj:p_vm_track_object;prot:Byte);
|
|
|
|
function vm_track_map_overlap (map:p_vm_track_map;obj:p_vm_track_object;data:Pointer):Integer;
|
|
|
|
implementation
|
|
|
|
procedure pmap_prot_track(pmap :Pointer;
|
|
start:vm_offset_t;
|
|
__end:vm_offset_t;
|
|
prot :Byte); external;
|
|
|
|
function vm_track_object_allocate(handle:Pointer;start,__end:vm_offset_t;htype:T_THANDLE_TYPE;prot:Byte):p_vm_track_object;
|
|
begin
|
|
Result:=AllocMem(SizeOf(t_vm_track_object));
|
|
|
|
Result^.handle :=handle;
|
|
Result^.ref_count:=1;
|
|
|
|
TAILQ_INIT(@Result^.instances);
|
|
|
|
Result^.main.start:=start;
|
|
Result^.main.__end:=__end;
|
|
|
|
Result^.align.start:=start and (not PMAPP_MASK);
|
|
Result^.align.__end:=(__end+PMAPP_MASK) and (not PMAPP_MASK);
|
|
|
|
Result^.prot :=prot;
|
|
Result^.htype:=htype;
|
|
end;
|
|
|
|
procedure vm_track_object_destroy(obj:p_vm_track_object);
|
|
begin
|
|
FreeMem(obj);
|
|
end;
|
|
|
|
procedure vm_track_object_deallocate(obj:p_vm_track_object);
|
|
begin
|
|
if (obj=nil) then Exit;
|
|
|
|
if (System.InterlockedDecrement(obj^.ref_count)=0) then
|
|
begin
|
|
|
|
if (obj^.on_destroy<>nil) then
|
|
begin
|
|
if ((obj^.on_destroy(obj^.handle) and DO_DELETE)=0) then
|
|
begin
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
vm_track_object_destroy(obj);
|
|
end;
|
|
end;
|
|
|
|
procedure vm_track_object_reference(obj:p_vm_track_object);
|
|
begin
|
|
if (obj=nil) then Exit;
|
|
|
|
System.InterlockedIncrement(obj^.ref_count);
|
|
end;
|
|
|
|
{
|
|
procedure vm_track_list_add_obj(var list:TAILQ_HEAD;obj:p_vm_track_object);
|
|
begin
|
|
if (obj=nil) then Exit;
|
|
|
|
if (obj^.mark_del<>0) then Exit;
|
|
|
|
if (obj^.iter_link.tqe_prev<>nil) then Exit;
|
|
|
|
TAILQ_INSERT_TAIL(@list,obj,@obj^.iter_link);
|
|
end;
|
|
}
|
|
|
|
function vm_track_object_trigger(obj:p_vm_track_object;start,__end:vm_offset_t;mode:T_TRIGGER_MODE):Integer;
|
|
begin
|
|
Result:=DO_NOTHING;
|
|
|
|
if (obj=nil) then Exit;
|
|
|
|
if (obj^.mark_del<>0) then Exit;
|
|
|
|
//cross with main
|
|
if (obj^.main.__end>start) and (obj^.main.start<__end) then
|
|
begin
|
|
if (obj^.on_trigger<>nil) then
|
|
begin
|
|
Result:=obj^.on_trigger(obj^.handle,mode);
|
|
end else
|
|
begin
|
|
Result:=DO_INCREMENT;
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
|
|
//
|
|
|
|
procedure _vm_track_splay_instance(var root:p_vm_track_object_instance;obj:p_vm_track_object);
|
|
label
|
|
_left,
|
|
_right;
|
|
var
|
|
llist,rlist:p_vm_track_object_instance;
|
|
ltree,rtree:p_vm_track_object_instance;
|
|
y :p_vm_track_object_instance;
|
|
begin
|
|
if (root=nil) or (obj=nil) then Exit;
|
|
|
|
llist:=nil;
|
|
rlist:=nil;
|
|
repeat
|
|
|
|
if (obj<root^.obj) then
|
|
begin
|
|
y:=root^.pLeft;
|
|
if (y=nil) then break;
|
|
if (y^.pLeft=nil) then
|
|
begin
|
|
_left:
|
|
root^.pLeft:=rlist;
|
|
rlist:=root;
|
|
root:=y;
|
|
end else
|
|
if (obj<y^.obj) then
|
|
begin
|
|
root^.pLeft:=y^.pRight;
|
|
y^.pRight:=root;
|
|
root:=y^.pLeft;
|
|
y^.pLeft:=rlist;
|
|
rlist:=y;
|
|
end else
|
|
begin
|
|
goto _left;
|
|
end;
|
|
end else
|
|
if (obj>root^.obj) then
|
|
begin
|
|
y:=root^.pRight;
|
|
if (y=nil) then break;
|
|
if (y^.pRight=nil) then
|
|
begin
|
|
_right:
|
|
root^.pRight:=llist;
|
|
llist:=root;
|
|
root:=y;
|
|
end else
|
|
if (obj>y^.obj) then
|
|
begin
|
|
root^.pRight:=y^.pLeft;
|
|
y^.pLeft:=root;
|
|
root:=y^.pRight;
|
|
y^.pRight:=llist;
|
|
llist:=y;
|
|
end else
|
|
begin
|
|
goto _right;
|
|
end;
|
|
end else
|
|
begin
|
|
Break;
|
|
end;
|
|
until false;
|
|
|
|
ltree:=root^.pLeft;
|
|
while (llist<>nil) do
|
|
begin
|
|
y:=llist^.pRight;
|
|
llist^.pRight:=ltree;
|
|
ltree:=llist;
|
|
llist:=y;
|
|
end;
|
|
|
|
rtree:=root^.pRight;
|
|
while (rlist<>nil) do
|
|
begin
|
|
y:=rlist^.pLeft;
|
|
rlist^.pLeft:=rtree;
|
|
rtree:=rlist;
|
|
rlist:=y;
|
|
end;
|
|
|
|
root^.pLeft :=ltree;
|
|
root^.pRight:=rtree;
|
|
end;
|
|
|
|
procedure vm_track_insert_instance(var root:p_vm_track_object_instance;node:p_vm_track_object_instance);
|
|
begin
|
|
_vm_track_splay_instance(root,node^.obj);
|
|
|
|
if (root=nil) then
|
|
begin
|
|
//
|
|
end else
|
|
if (node^.obj>root^.obj) then
|
|
begin
|
|
node^.pRight:=root^.pRight;
|
|
node^.pLeft :=root;
|
|
root^.pRight:=nil;
|
|
end else
|
|
begin
|
|
node^.pLeft :=root^.pLeft;
|
|
node^.pRight:=root;
|
|
root^.pLeft :=nil;
|
|
end;
|
|
|
|
root:=node;
|
|
end;
|
|
|
|
procedure vm_track_delete_instance(var root:p_vm_track_object_instance;node:p_vm_track_object_instance);
|
|
var
|
|
pLeft :p_vm_track_object_instance;
|
|
pRight:p_vm_track_object_instance;
|
|
pMax :p_vm_track_object_instance;
|
|
begin
|
|
_vm_track_splay_instance(root,node^.obj);
|
|
|
|
if (root=node) then
|
|
begin
|
|
pLeft :=root^.pLeft;
|
|
pRight:=root^.pRight;
|
|
|
|
if (pLeft<>nil) then
|
|
begin
|
|
pMax:=pLeft;
|
|
while (pMax^.pRight<>nil) do
|
|
begin
|
|
pMax:=pMax^.pRight;
|
|
end;
|
|
|
|
root:=pLeft;
|
|
|
|
_vm_track_splay_instance(root,pMax^.obj);
|
|
|
|
root^.pRight:=pRight;
|
|
end else
|
|
begin
|
|
root:=pRight;
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
|
|
function vm_track_first_instance(root:p_vm_track_object_instance):p_vm_track_object_instance;
|
|
var
|
|
node:p_vm_track_object_instance;
|
|
begin
|
|
Result:=nil;
|
|
node:=root;
|
|
While (node<>nil) do
|
|
begin
|
|
Result:=node;
|
|
node:=node^.pLeft;
|
|
end;
|
|
end;
|
|
|
|
function vm_track_next_instance(root,node:p_vm_track_object_instance):p_vm_track_object_instance;
|
|
var
|
|
y,r:p_vm_track_object_instance;
|
|
begin
|
|
Result:=nil;
|
|
|
|
if (root=nil) or (node=nil) then Exit;
|
|
|
|
r:=root;
|
|
y:=nil;
|
|
|
|
if (node^.pRight<>nil) then
|
|
begin
|
|
y:=node^.pRight;
|
|
while (y^.pLeft<>nil) do y:=y^.pLeft;
|
|
Exit(y);
|
|
end;
|
|
|
|
while (r<>nil) do
|
|
begin
|
|
if (node^.obj=r^.obj) then
|
|
begin
|
|
Break;
|
|
end else
|
|
if (node^.obj<r^.obj) then
|
|
begin
|
|
y:=r;
|
|
r:=r^.pLeft;
|
|
end else
|
|
begin
|
|
r:=r^.pRight;
|
|
end;
|
|
end;
|
|
|
|
Exit(y);
|
|
end;
|
|
|
|
procedure _vm_track_entry_change_prot(pmap:Pointer;entry:p_vm_track_map_entry;add_prot,del_prot:Byte);
|
|
var
|
|
prot:Byte;
|
|
begin
|
|
//update prot
|
|
|
|
if (add_prot and PAGE_TRACK_R)<>0 then
|
|
begin
|
|
Inc(entry^.track_r);
|
|
end;
|
|
|
|
if (add_prot and PAGE_TRACK_W)<>0 then
|
|
begin
|
|
Inc(entry^.track_w);
|
|
end;
|
|
|
|
if (del_prot and PAGE_TRACK_R)<>0 then
|
|
begin
|
|
Dec(entry^.track_r);
|
|
end;
|
|
|
|
if (del_prot and PAGE_TRACK_W)<>0 then
|
|
begin
|
|
Dec(entry^.track_w);
|
|
end;
|
|
|
|
prot:=(ord(entry^.track_r<>0)*PAGE_TRACK_R) or
|
|
(ord(entry^.track_w<>0)*PAGE_TRACK_W);
|
|
|
|
if entry^.mark_cpu or
|
|
(prot<>entry^.prot) then
|
|
begin
|
|
entry^.prot:=prot;
|
|
|
|
if (pmap<>nil) then
|
|
begin
|
|
entry^.mark_cpu:=False;
|
|
|
|
pmap_prot_track(pmap,entry^.start,entry^.__end,prot);
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure _vm_track_entry_add_obj(pmap:Pointer;entry:p_vm_track_map_entry;obj:p_vm_track_object;source:vm_offset_t);
|
|
var
|
|
node:p_vm_track_object_instance;
|
|
begin
|
|
node:=AllocMem(SizeOf(t_vm_track_object_instance));
|
|
|
|
node^.entry :=entry;
|
|
node^.obj :=obj;
|
|
node^.source:=source;
|
|
|
|
vm_track_insert_instance(entry^.instances,node);
|
|
Inc(entry^.instcount);
|
|
|
|
TAILQ_INSERT_TAIL(@obj^.instances,node,@node^.obj_link);
|
|
|
|
vm_track_object_reference(obj);
|
|
|
|
//update prot
|
|
if (pmap<>nil) then //if not copy_obj_list
|
|
begin
|
|
_vm_track_entry_change_prot(pmap,entry,obj^.prot,0);
|
|
end;
|
|
//
|
|
end;
|
|
|
|
procedure vm_track_entry_add_obj(pmap:Pointer;entry:p_vm_track_map_entry;obj:p_vm_track_object;source:vm_offset_t);
|
|
var
|
|
root:p_vm_track_object_instance;
|
|
begin
|
|
_vm_track_splay_instance(entry^.instances,obj);
|
|
root:=entry^.instances;
|
|
|
|
if (root<>nil) then
|
|
if (root^.obj=obj) then
|
|
begin
|
|
Exit;
|
|
end;
|
|
|
|
_vm_track_entry_add_obj(pmap,entry,obj,source);
|
|
end;
|
|
|
|
function _vm_track_entry_del_node(pmap:Pointer;entry:p_vm_track_map_entry;node:p_vm_track_object_instance):Boolean;
|
|
var
|
|
obj:p_vm_track_object;
|
|
begin
|
|
obj:=node^.obj;
|
|
|
|
//update prot
|
|
if (pmap<>nil) then //if not vm_track_map_simplify_entry -> vm_track_entry_dispose -> vm_track_entry_del_obj_all
|
|
begin
|
|
_vm_track_entry_change_prot(pmap,entry,0,obj^.prot);
|
|
end;
|
|
//
|
|
|
|
Dec(entry^.instcount);
|
|
vm_track_delete_instance(entry^.instances,node);
|
|
|
|
TAILQ_REMOVE(@obj^.instances,node,@node^.obj_link);
|
|
|
|
vm_track_object_deallocate(obj);
|
|
|
|
FreeMem(node);
|
|
|
|
Result:=(entry^.instances=nil);
|
|
end;
|
|
|
|
function vm_track_entry_del_obj(pmap:Pointer;entry:p_vm_track_map_entry;obj:p_vm_track_object):Boolean;
|
|
var
|
|
root:p_vm_track_object_instance;
|
|
begin
|
|
Result:=False;
|
|
|
|
_vm_track_splay_instance(entry^.instances,obj);
|
|
root:=entry^.instances;
|
|
|
|
if (root=nil) then
|
|
begin
|
|
Exit;
|
|
end;
|
|
|
|
if (root^.obj<>obj) then
|
|
begin
|
|
Exit;
|
|
end;
|
|
|
|
Result:=_vm_track_entry_del_node(pmap,entry,root);
|
|
end;
|
|
|
|
procedure vm_track_entry_del_obj_all(pmap:Pointer;entry:p_vm_track_map_entry);
|
|
var
|
|
node,next:p_vm_track_object_instance;
|
|
begin
|
|
node:=vm_track_first_instance(entry^.instances);
|
|
|
|
while (node<>nil) do
|
|
begin
|
|
next:=vm_track_next_instance(entry^.instances,node);
|
|
|
|
_vm_track_entry_del_node(pmap,entry,node);
|
|
|
|
node:=next;
|
|
end;
|
|
end;
|
|
|
|
//
|
|
|
|
function in_obj_list(b:p_vm_track_map_entry;obj:p_vm_track_object;source:vm_offset_t):Boolean;
|
|
var
|
|
root:p_vm_track_object_instance;
|
|
begin
|
|
Result:=False;
|
|
|
|
_vm_track_splay_instance(b^.instances,obj);
|
|
root:=b^.instances;
|
|
|
|
if (root=nil) then
|
|
begin
|
|
Exit;
|
|
end;
|
|
|
|
Result:=(root^.obj=obj) and (root^.source=source);
|
|
end;
|
|
|
|
function compare_obj_list(a:p_vm_track_map_entry;offset:vm_offset_t;b:p_vm_track_map_entry):Boolean;
|
|
var
|
|
node:p_vm_track_object_instance;
|
|
begin
|
|
if (a^.instcount<>b^.instcount) then
|
|
begin
|
|
Exit(False);
|
|
end;
|
|
|
|
node:=vm_track_first_instance(a^.instances);
|
|
|
|
while (node<>nil) do
|
|
begin
|
|
|
|
if not in_obj_list(b,node^.obj,node^.source+offset) then
|
|
begin
|
|
Exit(False);
|
|
end;
|
|
|
|
node:=vm_track_next_instance(a^.instances,node);
|
|
end;
|
|
|
|
Result:=True;
|
|
end;
|
|
|
|
procedure inc_obj_list(src:p_vm_track_map_entry;offset:vm_offset_t);
|
|
var
|
|
node:p_vm_track_object_instance;
|
|
begin
|
|
node:=vm_track_first_instance(src^.instances);
|
|
|
|
while (node<>nil) do
|
|
begin
|
|
node^.source:=node^.source+offset;
|
|
|
|
node:=vm_track_next_instance(src^.instances,node);
|
|
end;
|
|
end;
|
|
|
|
procedure dec_obj_list(src:p_vm_track_map_entry;offset:vm_offset_t);
|
|
var
|
|
node:p_vm_track_object_instance;
|
|
begin
|
|
node:=vm_track_first_instance(src^.instances);
|
|
|
|
while (node<>nil) do
|
|
begin
|
|
node^.source:=node^.source-offset;
|
|
|
|
node:=vm_track_next_instance(src^.instances,node);
|
|
end;
|
|
end;
|
|
|
|
procedure copy_obj_list(src,dst:p_vm_track_map_entry;offset:vm_offset_t);
|
|
var
|
|
node:p_vm_track_object_instance;
|
|
begin
|
|
dst^.instances:=nil; //init
|
|
dst^.instcount:=0;
|
|
|
|
node:=vm_track_first_instance(src^.instances);
|
|
|
|
while (node<>nil) do
|
|
begin
|
|
_vm_track_entry_add_obj(nil,dst,node^.obj,node^.source+offset);
|
|
|
|
node:=vm_track_next_instance(src^.instances,node);
|
|
end;
|
|
end;
|
|
|
|
//
|
|
|
|
procedure vm_track_map_RANGE_CHECK(map:p_vm_track_map;var start,__end:vm_offset_t); inline;
|
|
begin
|
|
start:=start and (not PMAPP_MASK);
|
|
__end:=(__end+PMAPP_MASK) and (not PMAPP_MASK);
|
|
|
|
if (start<map^.min_offset) then
|
|
begin
|
|
start:=map^.min_offset;
|
|
end;
|
|
if (__end>map^.max_offset) then
|
|
begin
|
|
__end:=map^.max_offset;
|
|
end;
|
|
if (start>__end) then
|
|
begin
|
|
start:=__end;
|
|
end;
|
|
end;
|
|
|
|
function vm_map_lock_range (map:Pointer;start,__end:off_t;mode:Integer):Pointer; external;
|
|
procedure vm_map_unlock_range(map:Pointer;cookie:Pointer); external;
|
|
function vm_map_locked (map:Pointer):Boolean; external;
|
|
|
|
procedure vm_track_map_lock(map:p_vm_track_map); inline;
|
|
begin
|
|
//mtx_lock(map^.lock);
|
|
vm_map_lock_range(map^.vm_map,0,High(Int64),RL_LOCK_WRITE);
|
|
end;
|
|
|
|
procedure _vm_track_map_process_deferred(map:p_vm_track_map); forward;
|
|
|
|
procedure vm_track_map_unlock(map:p_vm_track_map;def:Boolean=True);
|
|
begin
|
|
if def then
|
|
begin
|
|
_vm_track_map_process_deferred(map);
|
|
end;
|
|
//mtx_unlock(map^.lock);
|
|
vm_map_unlock_range(map^.vm_map,map^.vm_map);
|
|
end;
|
|
|
|
function vm_track_locked(map:p_vm_track_map):Boolean; inline;
|
|
begin
|
|
//Result:=mtx_owned(map^.lock);
|
|
Result:=vm_map_locked(map^.vm_map);
|
|
end;
|
|
|
|
procedure VM_MAP_ASSERT_LOCKED(map:p_vm_track_map); inline;
|
|
begin
|
|
Assert(vm_track_locked(map));
|
|
end;
|
|
|
|
procedure vm_track_map_init(map:p_vm_track_map;min,max:vm_offset_t;vm_map:Pointer);
|
|
var
|
|
i:Integer;
|
|
begin
|
|
map^.header.next:=@map^.header;
|
|
map^.header.prev:=@map^.header;
|
|
map^.min_offset:=min;
|
|
map^.max_offset:=max;
|
|
map^.root:=nil;
|
|
|
|
//
|
|
TAILQ_INIT(@map^.insert_deferred.free);
|
|
For i:=Low(map^.insert_deferred.stub) to High(map^.insert_deferred.stub) do
|
|
begin
|
|
TAILQ_INSERT_TAIL(@map^.insert_deferred.free,
|
|
@map^.insert_deferred.stub[i],
|
|
@map^.insert_deferred.stub[i].entry);
|
|
end;
|
|
|
|
TAILQ_INIT(@map^.insert_deferred.list);
|
|
|
|
TAILQ_INIT(@map^.delete_deferred);
|
|
|
|
//
|
|
//mtx_init(map^.lock,'vm_track_map');
|
|
map^.vm_map:=vm_map;
|
|
end;
|
|
|
|
procedure vm_track_entry_dispose(map:p_vm_track_map;pmap:Pointer;entry:p_vm_track_map_entry); inline;
|
|
begin
|
|
vm_track_entry_del_obj_all(pmap,entry);
|
|
//
|
|
FreeMem(entry);
|
|
end;
|
|
|
|
function vm_track_entry_create(map:p_vm_track_map):p_vm_track_map_entry;
|
|
var
|
|
new_entry:p_vm_track_map_entry;
|
|
begin
|
|
new_entry:=AllocMem(SizeOf(t_vm_track_map_entry));
|
|
Assert((new_entry<>nil),'vm_track_map_entry_create: kernel resources exhausted');
|
|
|
|
new_entry^.instances:=nil;
|
|
|
|
Result:=new_entry;
|
|
end;
|
|
|
|
function vm_track_entry_splay(addr:vm_offset_t;root:p_vm_track_map_entry):p_vm_track_map_entry;
|
|
var
|
|
llist,rlist:p_vm_track_map_entry;
|
|
ltree,rtree:p_vm_track_map_entry;
|
|
y :p_vm_track_map_entry;
|
|
begin
|
|
{ Special case of empty tree. }
|
|
if (root=nil) then Exit(root);
|
|
|
|
llist:=nil;
|
|
rlist:=nil;
|
|
repeat
|
|
{ root is never nil in here. }
|
|
if (addr<root^.start) then
|
|
begin
|
|
y:=root^.left;
|
|
if (y=nil) then break;
|
|
if (addr<y^.start) and (y^.left<>nil) then
|
|
begin
|
|
{ Rotate right and put y on rlist. }
|
|
root^.left:=y^.right;
|
|
y^.right:=root;
|
|
root:=y^.left;
|
|
y^.left:=rlist;
|
|
rlist:=y;
|
|
end else
|
|
begin
|
|
{ Put root on rlist. }
|
|
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
|
|
{ Rotate left and put y on llist. }
|
|
root^.right:=y^.left;
|
|
y^.left:=root;
|
|
root:=y^.right;
|
|
y^.right:=llist;
|
|
llist:=y;
|
|
end else
|
|
begin
|
|
{ Put root on llist. }
|
|
root^.right:=llist;
|
|
llist:=root;
|
|
root:=y;
|
|
end;
|
|
end else
|
|
begin
|
|
break;
|
|
end;
|
|
until false;
|
|
|
|
{
|
|
* Pass Two: Walk back up the two spines, flip the pointers
|
|
* and set max_free. The subtrees of the root go at the
|
|
* bottom of llist and rlist.
|
|
}
|
|
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;
|
|
|
|
{
|
|
* Final assembly: add ltree and rtree as subtrees of root.
|
|
}
|
|
root^.left:=ltree;
|
|
root^.right:=rtree;
|
|
|
|
Result:=(root);
|
|
end;
|
|
|
|
procedure vm_track_map_entry_link(
|
|
map :p_vm_track_map;
|
|
after_where:p_vm_track_map_entry;
|
|
entry :p_vm_track_map_entry);
|
|
begin
|
|
VM_MAP_ASSERT_LOCKED(map);
|
|
|
|
Inc(map^.nentries);
|
|
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_track_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_track_map_entry_unlink(
|
|
map :p_vm_track_map;
|
|
entry:p_vm_track_map_entry);
|
|
var
|
|
next,prev,root:p_vm_track_map_entry;
|
|
begin
|
|
VM_MAP_ASSERT_LOCKED(map);
|
|
|
|
if (entry<>map^.root) then
|
|
begin
|
|
vm_track_entry_splay(entry^.start, map^.root);
|
|
end;
|
|
if (entry^.left=nil) then
|
|
begin
|
|
root:=entry^.right;
|
|
end else
|
|
begin
|
|
root:=vm_track_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;
|
|
Dec(map^.nentries);
|
|
end;
|
|
|
|
function vm_track_map_lookup_entry(
|
|
map :p_vm_track_map;
|
|
address:vm_offset_t;
|
|
entry :pp_vm_track_map_entry):Boolean;
|
|
var
|
|
cur:p_vm_track_map_entry;
|
|
begin
|
|
VM_MAP_ASSERT_LOCKED(map);
|
|
|
|
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_track_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_track_map_insert_internal(
|
|
map :p_vm_track_map;
|
|
after :p_vm_track_map_entry;
|
|
start :vm_offset_t;
|
|
__end :vm_offset_t):p_vm_track_map_entry;
|
|
var
|
|
new_entry:p_vm_track_map_entry;
|
|
begin
|
|
VM_MAP_ASSERT_LOCKED(map);
|
|
|
|
if (after<>@map^.header) and
|
|
(start<after^.__end) then
|
|
begin
|
|
start:=after^.__end;
|
|
end;
|
|
|
|
if (after^.next<>@map^.header) and
|
|
(after^.next^.start<__end) then
|
|
begin
|
|
__end:=after^.next^.start;
|
|
end;
|
|
|
|
if (start>=__end) then
|
|
begin
|
|
Exit(after);
|
|
end;
|
|
|
|
{
|
|
* Create a new after
|
|
}
|
|
new_entry:=vm_track_entry_create(map);
|
|
new_entry^.start :=start;
|
|
new_entry^.__end :=__end;
|
|
|
|
{
|
|
* Insert the new after into the list
|
|
}
|
|
vm_track_map_entry_link(map, after, new_entry);
|
|
|
|
//vm_track_entry_simplify_entry(map, new_entry);
|
|
|
|
Result:=new_entry;
|
|
end;
|
|
|
|
procedure vm_track_map_simplify_entry(map:p_vm_track_map;entry:p_vm_track_map_entry);
|
|
var
|
|
next,prev:p_vm_track_map_entry;
|
|
prevsize,esize:vm_size_t;
|
|
begin
|
|
prev:=entry^.prev;
|
|
if (prev<>@map^.header) then
|
|
begin
|
|
prevsize:=prev^.__end - prev^.start;
|
|
if (prev^.__end=entry^.start) and
|
|
compare_obj_list(prev,prevsize,entry) then
|
|
begin
|
|
vm_track_map_entry_unlink(map, prev);
|
|
entry^.start :=prev^.start;
|
|
|
|
dec_obj_list(entry,prevsize);
|
|
|
|
vm_track_entry_dispose(map, nil, prev);
|
|
end;
|
|
end;
|
|
|
|
next:=entry^.next;
|
|
if (next<>@map^.header) then
|
|
begin
|
|
esize:=entry^.__end - entry^.start;
|
|
if (entry^.__end=next^.start) and
|
|
compare_obj_list(entry,esize,next) then
|
|
begin
|
|
vm_track_map_entry_unlink(map, next);
|
|
entry^.__end:=next^.__end;
|
|
|
|
vm_track_entry_dispose(map, nil, next);
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure _vm_track_map_clip_start(map:p_vm_track_map;entry:p_vm_track_map_entry;start:vm_offset_t);
|
|
var
|
|
new_entry:p_vm_track_map_entry;
|
|
begin
|
|
VM_MAP_ASSERT_LOCKED(map);
|
|
|
|
vm_track_map_simplify_entry(map, entry);
|
|
|
|
new_entry:=vm_track_entry_create(map);
|
|
new_entry^:=entry^;
|
|
|
|
new_entry^.__end:=start;
|
|
|
|
copy_obj_list(entry,new_entry,0);
|
|
|
|
inc_obj_list(entry,(start - entry^.start));
|
|
|
|
entry^.start:=start;
|
|
|
|
vm_track_map_entry_link(map, entry^.prev, new_entry);
|
|
end;
|
|
|
|
procedure vm_track_map_clip_start(map:p_vm_track_map;entry:p_vm_track_map_entry;start:vm_offset_t); inline;
|
|
begin
|
|
if (start>entry^.start) then
|
|
begin
|
|
_vm_track_map_clip_start(map,entry,start);
|
|
end;
|
|
end;
|
|
|
|
procedure _vm_track_map_clip_end(map:p_vm_track_map;entry:p_vm_track_map_entry;__end:vm_offset_t);
|
|
var
|
|
new_entry:p_vm_track_map_entry;
|
|
begin
|
|
VM_MAP_ASSERT_LOCKED(map);
|
|
|
|
new_entry:=vm_track_entry_create(map);
|
|
new_entry^:=entry^;
|
|
|
|
new_entry^.start:=__end;
|
|
|
|
entry^.__end:=__end;
|
|
|
|
copy_obj_list(entry,new_entry,(__end - entry^.start));
|
|
|
|
vm_track_map_entry_link(map, entry, new_entry);
|
|
end;
|
|
|
|
procedure vm_track_map_clip_end(map:p_vm_track_map;entry:p_vm_track_map_entry;__end:vm_offset_t); inline;
|
|
begin
|
|
if (__end<entry^.__end) then
|
|
begin
|
|
_vm_track_map_clip_end(map,entry,__end);
|
|
end;
|
|
end;
|
|
|
|
function _vm_track_map_insert(map:p_vm_track_map;start,__end,source:vm_offset_t;obj:p_vm_track_object):Integer;
|
|
var
|
|
entry:p_vm_track_map_entry;
|
|
begin
|
|
if (start>=__end) then
|
|
begin
|
|
Exit(KERN_SUCCESS);
|
|
end;
|
|
|
|
VM_MAP_ASSERT_LOCKED(map);
|
|
|
|
if (obj^.mark_del<>0) then Exit(KERN_SUCCESS);
|
|
|
|
vm_track_map_RANGE_CHECK(map, start, __end);
|
|
source:=source and (not PMAPP_MASK);
|
|
|
|
if (vm_track_map_lookup_entry(map, start, @entry)) then
|
|
begin
|
|
vm_track_map_clip_start(map, entry, start);
|
|
end else
|
|
begin
|
|
entry:=vm_track_map_insert_internal(map,entry,start,__end);
|
|
end;
|
|
|
|
while (entry<>@map^.header) and (entry^.start<__end) do
|
|
begin
|
|
vm_track_map_clip_end(map, entry, __end);
|
|
|
|
entry:=vm_track_map_insert_internal(map,entry,
|
|
entry^.__end, //start
|
|
__end //__end
|
|
);
|
|
|
|
vm_track_entry_add_obj(map^.pmap,entry,obj,source+(entry^.start-start));
|
|
|
|
entry:=entry^.next;
|
|
end;
|
|
|
|
Result:=(KERN_SUCCESS);
|
|
end;
|
|
|
|
procedure vm_track_map_entry_delete(map:p_vm_track_map;entry:p_vm_track_map_entry);
|
|
begin
|
|
vm_track_map_entry_unlink(map, entry);
|
|
|
|
vm_track_entry_dispose(map, map^.pmap, entry);
|
|
end;
|
|
|
|
procedure vm_track_map_delete_object(map:p_vm_track_map;obj:p_vm_track_object);
|
|
var
|
|
node,next:p_vm_track_object_instance;
|
|
entry:p_vm_track_map_entry;
|
|
begin
|
|
VM_MAP_ASSERT_LOCKED(map);
|
|
|
|
obj^.mark_del:=1;
|
|
|
|
node:=TAILQ_FIRST(@obj^.instances);
|
|
|
|
while (node<>nil) do
|
|
begin
|
|
next:=TAILQ_NEXT(node,@node^.obj_link);
|
|
|
|
entry:=node^.entry;
|
|
|
|
if _vm_track_entry_del_node(map^.pmap,entry,node) then
|
|
begin
|
|
//zero
|
|
vm_track_map_entry_delete(map, entry);
|
|
end else
|
|
begin
|
|
//exclude one
|
|
vm_track_map_simplify_entry(map,entry);
|
|
end;
|
|
|
|
node:=next;
|
|
end;
|
|
end;
|
|
|
|
function vm_track_map_remove_object(map:p_vm_track_map;obj:p_vm_track_object):Integer;
|
|
begin
|
|
if (map=nil) or (obj=nil) then
|
|
begin
|
|
Exit(KERN_INVALID_ARGUMENT);
|
|
end;
|
|
|
|
obj^.mark_del:=1;
|
|
|
|
vm_track_map_lock(map);
|
|
vm_track_map_delete_object(map, obj);
|
|
vm_track_map_unlock(map);
|
|
|
|
Result:=KERN_SUCCESS;
|
|
end;
|
|
|
|
function vm_track_map_delete_main(map:p_vm_track_map;entry:p_vm_track_map_entry;start,__end:vm_offset_t):Boolean;
|
|
var
|
|
node,next:p_vm_track_object_instance;
|
|
obj:p_vm_track_object;
|
|
begin
|
|
Result:=False;
|
|
|
|
VM_MAP_ASSERT_LOCKED(map);
|
|
|
|
node:=vm_track_first_instance(entry^.instances);
|
|
|
|
while (node<>nil) do
|
|
begin
|
|
next:=vm_track_next_instance(entry^.instances,node);
|
|
|
|
obj:=node^.obj;
|
|
|
|
//cross with main
|
|
if (obj^.align.__end>start) and (obj^.align.start<__end) then
|
|
begin
|
|
//delete full object
|
|
_vm_track_map_delete_deferred(map,obj);
|
|
|
|
Result:=True;
|
|
end;
|
|
|
|
node:=next;
|
|
end;
|
|
end;
|
|
|
|
function vm_track_map_delete_memory(map:p_vm_track_map;start,__end:vm_offset_t):Integer;
|
|
var
|
|
entry :p_vm_track_map_entry;
|
|
first_entry:p_vm_track_map_entry;
|
|
next :p_vm_track_map_entry;
|
|
begin
|
|
vm_track_map_RANGE_CHECK(map,start,__end);
|
|
|
|
VM_MAP_ASSERT_LOCKED(map);
|
|
|
|
if (start>=__end) then
|
|
begin
|
|
Exit(KERN_SUCCESS);
|
|
end;
|
|
|
|
if (not vm_track_map_lookup_entry(map, start, @first_entry)) then
|
|
begin
|
|
entry:=first_entry^.next;
|
|
end else
|
|
begin
|
|
entry:=first_entry;
|
|
|
|
vm_track_map_clip_start(map, entry, start);
|
|
end;
|
|
|
|
while (entry<>@map^.header) and (entry^.start<__end) do
|
|
begin
|
|
vm_track_map_clip_end(map, entry, __end);
|
|
|
|
next:=entry^.next;
|
|
|
|
if vm_track_map_delete_main(map,entry,start,__end) then
|
|
begin
|
|
//delete intervals is deferred
|
|
end else
|
|
begin
|
|
//delete entry
|
|
vm_track_map_entry_delete(map, entry);
|
|
end;
|
|
|
|
entry:=next;
|
|
end;
|
|
|
|
Result:=(KERN_SUCCESS);
|
|
end;
|
|
|
|
function vm_track_map_remove_memory(map:p_vm_track_map;start,__end:vm_offset_t):Integer;
|
|
begin
|
|
if (map=nil) then
|
|
begin
|
|
Exit(KERN_INVALID_ARGUMENT);
|
|
end;
|
|
|
|
vm_track_map_lock(map);
|
|
Result:=vm_track_map_delete_memory(map, start, __end);
|
|
vm_track_map_unlock(map);
|
|
end;
|
|
|
|
function _new_deferred(map:p_vm_track_map):p_vm_track_deferred;
|
|
begin
|
|
Result:=TAILQ_FIRST(@map^.insert_deferred.free);
|
|
|
|
if (Result<>nil) then
|
|
begin
|
|
TAILQ_REMOVE(@map^.insert_deferred.free,Result,@Result^.entry);
|
|
end else
|
|
begin
|
|
Result:=GetMem(SizeOf(t_vm_track_deferred));
|
|
end;
|
|
end;
|
|
|
|
procedure _free_deferred(map:p_vm_track_map;node:p_vm_track_deferred);
|
|
begin
|
|
|
|
if (Ptruint(node)>=Ptruint(@map^.insert_deferred.stub)) and
|
|
(Ptruint(node)< (Ptruint(@map^.insert_deferred.stub)+SizeOf(map^.insert_deferred.stub))) then
|
|
begin
|
|
TAILQ_INSERT_TAIL(@map^.insert_deferred.free,node,@node^.entry);
|
|
end else
|
|
begin
|
|
FreeMem(node);
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure _vm_track_map_insert_deferred(map:p_vm_track_map;start,__end,source:vm_offset_t;obj:p_vm_track_object);
|
|
var
|
|
new:p_vm_track_deferred;
|
|
begin
|
|
vm_track_map_RANGE_CHECK(map,start,__end);
|
|
|
|
VM_MAP_ASSERT_LOCKED(map);
|
|
|
|
if (obj^.mark_del<>0) then Exit;
|
|
|
|
new:=_new_deferred(map);
|
|
new^:=Default(t_vm_track_deferred);
|
|
|
|
new^.start :=start;
|
|
new^.__end :=__end;
|
|
new^.source:=source;
|
|
new^.obj :=obj;
|
|
|
|
TAILQ_INSERT_TAIL(@map^.insert_deferred.list,new,@new^.entry);
|
|
end;
|
|
|
|
function _vm_track_map_delete_deferred(map:p_vm_track_map;obj:p_vm_track_object):Boolean;
|
|
begin
|
|
Result:=False;
|
|
|
|
VM_MAP_ASSERT_LOCKED(map);
|
|
|
|
if (obj=nil) then Exit;
|
|
|
|
obj^.mark_del:=1;
|
|
|
|
if (obj^.del_link.tqe_prev<>nil) then Exit;
|
|
|
|
TAILQ_INSERT_TAIL(@map^.delete_deferred,obj,@obj^.del_link);
|
|
|
|
Result:=True;
|
|
end;
|
|
|
|
procedure _vm_track_map_process_deferred(map:p_vm_track_map);
|
|
var
|
|
inode,inext:p_vm_track_deferred;
|
|
|
|
dnode,dnext:p_vm_track_object;
|
|
begin
|
|
|
|
inode:=TAILQ_FIRST(@map^.insert_deferred.list);
|
|
|
|
while (inode<>nil) do
|
|
begin
|
|
inext:=TAILQ_NEXT(inode,@inode^.entry);
|
|
|
|
TAILQ_REMOVE(@map^.insert_deferred.list,inode,@inode^.entry);
|
|
|
|
_vm_track_map_insert(map,inode^.start,inode^.__end,inode^.source,inode^.obj);
|
|
|
|
_free_deferred(map,inode);
|
|
|
|
inode:=inext;
|
|
end;
|
|
|
|
//
|
|
|
|
dnode:=TAILQ_FIRST(@map^.delete_deferred);
|
|
|
|
while (dnode<>nil) do
|
|
begin
|
|
dnext:=TAILQ_NEXT(dnode,@dnode^.del_link);
|
|
|
|
TAILQ_REMOVE(@map^.delete_deferred,dnode,@dnode^.del_link);
|
|
|
|
dnode^.del_link:=Default(TAILQ_ENTRY);
|
|
|
|
vm_track_map_delete_object(map,dnode);
|
|
|
|
dnode:=dnext;
|
|
end;
|
|
end;
|
|
|
|
function _vm_track_map_insert_mirror(map:p_vm_track_map;start,__end,dst:vm_offset_t):Integer;
|
|
var
|
|
e_start:vm_offset_t;
|
|
e___end:vm_offset_t;
|
|
d_start:vm_offset_t;
|
|
d___end:vm_offset_t;
|
|
entry:p_vm_track_map_entry;
|
|
node,next:p_vm_track_object_instance;
|
|
obj:p_vm_track_object;
|
|
begin
|
|
VM_MAP_ASSERT_LOCKED(map);
|
|
|
|
if (start>=__end) then
|
|
begin
|
|
Exit;
|
|
end;
|
|
|
|
if (vm_track_map_lookup_entry(map, start, @entry)) then
|
|
begin
|
|
//
|
|
end else
|
|
begin
|
|
entry:=entry^.next;
|
|
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
|
|
d_start:=dst +(e_start-start);
|
|
d___end:=d_start+(e___end-e_start);
|
|
|
|
node:=vm_track_first_instance(entry^.instances);
|
|
|
|
while (node<>nil) do
|
|
begin
|
|
next:=vm_track_next_instance(entry^.instances,node);
|
|
|
|
obj:=node^.obj;
|
|
|
|
//Don't try to add mirroring for mirroring
|
|
if (obj^.align.__end>e_start) and (obj^.align.start<e___end) then
|
|
begin
|
|
_vm_track_map_insert_deferred(map,d_start,d___end,e_start,obj);
|
|
end;
|
|
|
|
node:=next;
|
|
end;
|
|
|
|
end;
|
|
|
|
entry:=entry^.next;
|
|
end;
|
|
|
|
Result:=(KERN_SUCCESS);
|
|
end;
|
|
|
|
function vm_track_map_trigger(map:p_vm_track_map;start,__end:vm_offset_t;exclude:Pointer;mode:T_TRIGGER_MODE):Integer;
|
|
begin
|
|
Result:=vm_track_map_trigger2(map,start,__end,exclude,mode);
|
|
end;
|
|
|
|
function vm_track_map_trigger2(map:p_vm_track_map;var start,__end:vm_offset_t;exclude:Pointer;mode:T_TRIGGER_MODE):Integer;
|
|
var
|
|
entry:p_vm_track_map_entry;
|
|
node:p_vm_track_object_instance;
|
|
|
|
o_start:vm_offset_t;
|
|
o___end:vm_offset_t;
|
|
|
|
diff:vm_offset_t;
|
|
size:vm_offset_t;
|
|
|
|
s_start:vm_offset_t;
|
|
s___end:vm_offset_t;
|
|
|
|
ret:Integer;
|
|
|
|
//list:TAILQ_HEAD;
|
|
//onode,onext:p_vm_track_object;
|
|
begin
|
|
Result:=0; //count
|
|
|
|
if (start>=__end) or (map=nil) then
|
|
begin
|
|
Exit;
|
|
end;
|
|
|
|
//save orig
|
|
o_start:=start;
|
|
o___end:=__end;
|
|
|
|
size:=(o___end-o_start);
|
|
|
|
//TAILQ_INIT(@list);
|
|
|
|
vm_track_map_lock(map);
|
|
|
|
//vm_track_map_RANGE_CHECK(map, o_start, o___end);
|
|
|
|
if (vm_track_map_lookup_entry(map, o_start, @entry)) then
|
|
begin
|
|
//
|
|
end else
|
|
begin
|
|
entry:=entry^.next;
|
|
end;
|
|
|
|
while (entry<>@map^.header) and (entry^.start<o___end) do
|
|
begin
|
|
|
|
//expand lo result
|
|
if (start>entry^.start) then
|
|
begin
|
|
start:=entry^.start;
|
|
end;
|
|
|
|
//expand hi result
|
|
if (__end<entry^.__end) then
|
|
begin
|
|
__end:=entry^.__end;
|
|
end;
|
|
|
|
node:=vm_track_first_instance(entry^.instances);
|
|
|
|
while (node<>nil) do
|
|
begin
|
|
//vm_track_list_add_obj(list,node^.obj); //deferred
|
|
|
|
//remap with source
|
|
if (node^.obj<>exclude) then
|
|
begin
|
|
|
|
//remap with source
|
|
diff:=entry^.start-o_start;
|
|
//
|
|
s_start:=node^.source-diff;
|
|
s___end:=s_start+size;
|
|
|
|
ret:=vm_track_object_trigger(node^.obj,s_start,s___end,mode);
|
|
|
|
if ((ret and DO_DELETE)<>0) then
|
|
begin
|
|
//delete full object
|
|
_vm_track_map_delete_deferred(map,node^.obj);
|
|
end else
|
|
if (mode=M_CPU_WRITE) then
|
|
begin
|
|
entry^.mark_cpu:=True;
|
|
end;
|
|
|
|
if ((ret and DO_INCREMENT)<>0) then
|
|
begin
|
|
Inc(Result);
|
|
end;
|
|
end;
|
|
|
|
node:=vm_track_next_instance(entry^.instances,node);
|
|
end;
|
|
|
|
entry:=entry^.next;
|
|
end;
|
|
|
|
//iterate
|
|
|
|
{
|
|
onode:=TAILQ_FIRST(@list);
|
|
|
|
while (onode<>nil) do
|
|
begin
|
|
onext:=TAILQ_NEXT(onode,@onode^.iter_link);
|
|
|
|
TAILQ_REMOVE(@list,onode,@onode^.iter_link);
|
|
|
|
onode^.iter_link:=Default(TAILQ_ENTRY);
|
|
|
|
ret:=vm_track_object_trigger(map,onode,start,__end);
|
|
|
|
if ((ret and DO_DELETE)<>0) then
|
|
begin
|
|
//delete full object
|
|
_vm_track_map_delete_deferred(map,onode);
|
|
end;
|
|
|
|
if ((ret and DO_INCREMENT)<>0) then
|
|
begin
|
|
Inc(Result);
|
|
end;
|
|
|
|
onode:=onext;
|
|
end;
|
|
}
|
|
|
|
//iterate
|
|
|
|
vm_track_map_unlock(map);
|
|
end;
|
|
|
|
function vm_track_map_next_object(map:p_vm_track_map;start:vm_offset_t;obj:p_vm_track_object;htype:T_THANDLE_TYPE):p_vm_track_object;
|
|
var
|
|
entry:p_vm_track_map_entry;
|
|
node:p_vm_track_object_instance;
|
|
begin
|
|
Result:=nil;
|
|
|
|
if (map=nil) then Exit;
|
|
|
|
vm_track_map_lock(map);
|
|
|
|
vm_track_map_lookup_entry(map, start, @entry);
|
|
|
|
if (entry<>@map^.header) then
|
|
begin
|
|
_vm_track_splay_instance(entry^.instances,obj);
|
|
node:=entry^.instances;
|
|
|
|
//find greater than
|
|
if (node<>nil) then
|
|
if (node^.obj<=obj) then
|
|
begin
|
|
node:=vm_track_next_instance(entry^.instances,node);
|
|
end;
|
|
|
|
while (node<>nil) do
|
|
begin
|
|
|
|
if (node^.obj^.htype=htype) then
|
|
begin
|
|
Result:=node^.obj;
|
|
Break;
|
|
end;
|
|
|
|
node:=vm_track_next_instance(entry^.instances,node);
|
|
end;
|
|
|
|
end;
|
|
|
|
//inc ref
|
|
if (Result<>nil) then
|
|
begin
|
|
vm_track_object_reference(Result);
|
|
end;
|
|
|
|
vm_track_map_unlock(map);
|
|
end;
|
|
|
|
procedure vm_track_map_restore_object(map:p_vm_track_map;obj:p_vm_track_object);
|
|
var
|
|
node:p_vm_track_object_instance;
|
|
entry:p_vm_track_map_entry;
|
|
begin
|
|
if (map=nil) or (obj=nil) then Exit;
|
|
|
|
vm_track_map_lock(map);
|
|
|
|
node:=TAILQ_FIRST(@obj^.instances);
|
|
|
|
while (node<>nil) do
|
|
begin
|
|
entry:=node^.entry;
|
|
|
|
if entry^.mark_cpu then
|
|
begin
|
|
entry^.mark_cpu:=False;
|
|
|
|
pmap_prot_track(map^.pmap,entry^.start,entry^.__end,entry^.prot);
|
|
end;
|
|
|
|
node:=TAILQ_NEXT(node,@node^.obj_link);
|
|
end;
|
|
|
|
vm_track_map_unlock(map);
|
|
end;
|
|
|
|
procedure vm_track_map_set_prot(map:p_vm_track_map;obj:p_vm_track_object;prot:Byte);
|
|
var
|
|
node:p_vm_track_object_instance;
|
|
entry:p_vm_track_map_entry;
|
|
begin
|
|
if (map=nil) or (obj=nil) then Exit;
|
|
|
|
if (obj^.prot=prot) then Exit;
|
|
|
|
vm_track_map_lock(map);
|
|
|
|
node:=TAILQ_FIRST(@obj^.instances);
|
|
|
|
while (node<>nil) do
|
|
begin
|
|
entry:=node^.entry;
|
|
|
|
if entry^.mark_cpu then
|
|
begin
|
|
//dont change mark_cpu
|
|
_vm_track_entry_change_prot(nil,entry,prot,obj^.prot);
|
|
end else
|
|
begin
|
|
_vm_track_entry_change_prot(map^.pmap,entry,prot,obj^.prot);
|
|
end;
|
|
|
|
node:=TAILQ_NEXT(node,@node^.obj_link);
|
|
end;
|
|
|
|
obj^.prot:=prot;
|
|
|
|
vm_track_map_unlock(map);
|
|
end;
|
|
|
|
function _vm_track_entry_overlap(entry:p_vm_track_map_entry;exclude,data:Pointer):Integer;
|
|
var
|
|
node:p_vm_track_object_instance;
|
|
obj :p_vm_track_object;
|
|
begin
|
|
Result:=0;
|
|
|
|
node:=vm_track_first_instance(entry^.instances);
|
|
|
|
while (node<>nil) do
|
|
begin
|
|
obj:=node^.obj;
|
|
|
|
if (obj<>exclude) then
|
|
if (obj^.on_overlap<>nil) then
|
|
begin
|
|
Result:=Result+obj^.on_overlap(obj^.handle,data);
|
|
end;
|
|
|
|
node:=vm_track_next_instance(entry^.instances,node);
|
|
end;
|
|
end;
|
|
|
|
function vm_track_map_overlap(map:p_vm_track_map;obj:p_vm_track_object;data:Pointer):Integer;
|
|
var
|
|
node:p_vm_track_object_instance;
|
|
begin
|
|
Result:=0;
|
|
if (map=nil) or (obj=nil) then Exit;
|
|
|
|
vm_track_map_lock(map);
|
|
|
|
node:=TAILQ_FIRST(@obj^.instances);
|
|
|
|
while (node<>nil) do
|
|
begin
|
|
Result:=Result+_vm_track_entry_overlap(node^.entry,obj,data);
|
|
|
|
node:=TAILQ_NEXT(node,@node^.obj_link);
|
|
end;
|
|
|
|
vm_track_map_unlock(map);
|
|
end;
|
|
|
|
end.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|