FPPS4/sys/vm/vm_tracking_map.pas

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.