mirror of https://github.com/red-prig/fpPS4.git
952 lines
20 KiB
Plaintext
952 lines
20 KiB
Plaintext
unit vm_pmap;
|
|
|
|
{$mode ObjFPC}{$H+}
|
|
{$CALLING SysV_ABI_CDecl}
|
|
|
|
interface
|
|
|
|
uses
|
|
vm,
|
|
vmparam,
|
|
sys_vm_object,
|
|
vm_file,
|
|
vnode,
|
|
vuio;
|
|
|
|
const
|
|
PMAPP_SHIFT=12;
|
|
PMAPP_SIZE =1 shl PMAPP_SHIFT;
|
|
PMAPP_MASK =PMAPP_SIZE-1;
|
|
|
|
PAGE_MAP_COUNT =(QWORD(VM_MAXUSER_ADDRESS) shr PMAPP_SHIFT);
|
|
PAGE_MAP_MASK =PAGE_MAP_COUNT-1;
|
|
|
|
PAGE_PROT_READ =VM_PROT_READ;
|
|
PAGE_PROT_WRITE =VM_PROT_WRITE;
|
|
PAGE_PROT_EXECUTE=VM_PROT_EXECUTE;
|
|
|
|
PAGE_PROT_RW =PAGE_PROT_READ or PAGE_PROT_WRITE;
|
|
|
|
PAGE_PROT_LIFT =$40;
|
|
|
|
//PAGE_BUSY_FLAG =DWORD($10000000);
|
|
//PAGE_PATCH_FLAG =DWORD($08000000);
|
|
|
|
var
|
|
PAGE_MAP :PInteger=nil;
|
|
PAGE_PROT :PBYTE =nil;
|
|
|
|
procedure pmap_mark (start,__end,__off:vm_offset_t;prots:Byte);
|
|
procedure pmap_unmark (start,__end:vm_offset_t);
|
|
function pmap_get_prot (addr:vm_offset_t):Byte;
|
|
function pmap_get_page (addr:vm_offset_t):DWORD;
|
|
function pmap_test_cross(addr:vm_offset_t;h:Integer):Boolean;
|
|
|
|
function uplift(addr:Pointer):Pointer;
|
|
procedure iov_uplift(iov:p_iovec);
|
|
|
|
type
|
|
p_pmap=^_pmap;
|
|
_pmap=packed object
|
|
//
|
|
end;
|
|
|
|
pmap_t=p_pmap;
|
|
|
|
function atop(x:QWORD):DWORD; inline;
|
|
function ptoa(x:DWORD):QWORD; inline;
|
|
|
|
function ctob(x:QWORD):QWORD; inline;
|
|
function btoc(x:QWORD):QWORD; inline;
|
|
|
|
procedure pmap_pinit(pmap:p_pmap);
|
|
|
|
procedure pmap_align_superpage(obj :vm_object_t;
|
|
offset:vm_ooffset_t;
|
|
addr :p_vm_offset_t;
|
|
size :vm_size_t);
|
|
|
|
procedure pmap_enter_object(pmap :pmap_t;
|
|
obj :vm_object_t;
|
|
offset :vm_ooffset_t;
|
|
start :vm_offset_t;
|
|
__end :vm_offset_t;
|
|
prot :vm_prot_t);
|
|
|
|
procedure pmap_protect(pmap :pmap_t;
|
|
obj :vm_object_t;
|
|
offset:vm_ooffset_t;
|
|
start :vm_offset_t;
|
|
__end :vm_offset_t;
|
|
prot :vm_prot_t);
|
|
|
|
procedure pmap_madv_free(pmap :pmap_t;
|
|
obj :vm_object_t;
|
|
offset:vm_ooffset_t;
|
|
start :vm_offset_t;
|
|
__end :vm_offset_t;
|
|
prot :vm_prot_t);
|
|
|
|
procedure pmap_remove(pmap :pmap_t;
|
|
obj :vm_object_t;
|
|
offset:vm_ooffset_t;
|
|
start :vm_offset_t;
|
|
__end :vm_offset_t;
|
|
prot :vm_prot_t);
|
|
|
|
implementation
|
|
|
|
uses
|
|
md_map;
|
|
|
|
function atop(x:QWORD):DWORD; inline;
|
|
begin
|
|
Result:=QWORD(x) shr PAGE_SHIFT;
|
|
end;
|
|
|
|
function ptoa(x:DWORD):QWORD; inline;
|
|
begin
|
|
Result:=QWORD(x) shl PAGE_SHIFT;
|
|
end;
|
|
|
|
function ctob(x:QWORD):QWORD; inline;
|
|
begin
|
|
Result:=QWORD(x) shl PAGE_SHIFT;
|
|
end;
|
|
|
|
function btoc(x:QWORD):QWORD; inline;
|
|
begin
|
|
Result:=((x+PAGE_MASK) shr PAGE_SHIFT);
|
|
end;
|
|
|
|
procedure pmap_pinit(pmap:p_pmap);
|
|
var
|
|
base:Pointer;
|
|
size:QWORD;
|
|
prot:QWORD;
|
|
i,r:Integer;
|
|
begin
|
|
|
|
if Length(pmap_mem)<>0 then
|
|
begin
|
|
For i:=0 to High(pmap_mem) do
|
|
begin
|
|
base:=Pointer(pmap_mem[i].start);
|
|
size:=pmap_mem[i].__end-pmap_mem[i].start;
|
|
|
|
r:=md_reserve(base,size);
|
|
|
|
if (r<>0) then
|
|
begin
|
|
Writeln('failed md_reserve(',HexStr(base),',',HexStr(base+size),'):0x',HexStr(r,8));
|
|
//STATUS_COMMITMENT_LIMIT = $C000012D
|
|
Assert(false,'pmap_init');
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
PAGE_MAP:=nil;
|
|
size:=PAGE_MAP_COUNT*SizeOf(DWORD);
|
|
|
|
prot:=size;
|
|
size:=size+PAGE_MAP_COUNT;
|
|
|
|
r:=md_mmap(PAGE_MAP,size,MD_PROT_RW);
|
|
|
|
if (r<>0) then
|
|
begin
|
|
Writeln('failed md_mmap(',HexStr(PAGE_MAP),',',HexStr(PAGE_MAP+size),'):0x',HexStr(r,8));
|
|
Assert(false,'pmap_init');
|
|
end;
|
|
|
|
PAGE_PROT:=Pointer(PAGE_MAP)+prot;
|
|
|
|
//init zero
|
|
pmap_unmark(0,VM_MAXUSER_ADDRESS);
|
|
|
|
//Mapping to internal memory, isolate TODO
|
|
if Length(exclude_mem)<>0 then
|
|
begin
|
|
For i:=0 to High(exclude_mem) do
|
|
begin
|
|
pmap_mark(exclude_mem[i].start,exclude_mem[i].__end,exclude_mem[i].start,0);
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
|
|
{
|
|
* Increase the starting virtual address of the given mapping if a
|
|
* different alignment might result in more superpage mappings.
|
|
}
|
|
procedure pmap_align_superpage(obj :vm_object_t;
|
|
offset:vm_ooffset_t;
|
|
addr :p_vm_offset_t;
|
|
size :vm_size_t);
|
|
var
|
|
superpage_offset:vm_offset_t;
|
|
begin
|
|
if (size < NBPDR) then Exit;
|
|
if (obj<>nil) then
|
|
if ((obj^.flags and OBJ_COLORED)<>0) then
|
|
begin
|
|
offset:=offset+ptoa(obj^.pg_color);
|
|
end;
|
|
superpage_offset:=offset and PDRMASK;
|
|
if (size - ((NBPDR - superpage_offset) and PDRMASK) < NBPDR) or
|
|
((addr^ and PDRMASK)=superpage_offset) then
|
|
begin
|
|
Exit;
|
|
end;
|
|
if ((addr^ and PDRMASK) < superpage_offset) then
|
|
begin
|
|
addr^:=(addr^ and (not PDRMASK)) + superpage_offset
|
|
end else
|
|
begin
|
|
addr^:=((addr^ + PDRMASK) and (not PDRMASK)) + superpage_offset;
|
|
end;
|
|
end;
|
|
|
|
//PAGE_MAP
|
|
|
|
function IDX_TO_OFF(x:DWORD):QWORD; inline;
|
|
begin
|
|
Result:=QWORD(x) shl PMAPP_SHIFT;
|
|
end;
|
|
|
|
function OFF_TO_IDX(x:QWORD):DWORD; inline;
|
|
begin
|
|
Result:=QWORD(x) shr PMAPP_SHIFT;
|
|
end;
|
|
|
|
function MAX_IDX(x:DWORD):DWORD; inline;
|
|
begin
|
|
if (x>PAGE_MAP_MASK) then
|
|
Result:=PAGE_MAP_MASK
|
|
else
|
|
Result:=x;
|
|
end;
|
|
|
|
procedure pmap_mark(start,__end,__off:vm_offset_t;prots:Byte);
|
|
var
|
|
d:Integer;
|
|
begin
|
|
start:=OFF_TO_IDX(start);
|
|
__end:=OFF_TO_IDX(__end);
|
|
__off:=OFF_TO_IDX(__off);
|
|
start:=MAX_IDX(start);
|
|
__end:=MAX_IDX(__end);
|
|
d:=Integer(__off-start);
|
|
prots:=prots or (ord(d<>0)*PAGE_PROT_LIFT);
|
|
while (start<__end) do
|
|
begin
|
|
PAGE_MAP [start]:=d;
|
|
PAGE_PROT[start]:=prots;
|
|
Inc(start);
|
|
end;
|
|
WriteBarrier;
|
|
end;
|
|
|
|
procedure pmap_unmark(start,__end:vm_offset_t);
|
|
begin
|
|
start:=OFF_TO_IDX(start);
|
|
__end:=OFF_TO_IDX(__end);
|
|
start:=MAX_IDX(start);
|
|
__end:=MAX_IDX(__end);
|
|
while (start<__end) do
|
|
begin
|
|
PAGE_MAP [start]:=Integer(0-start);
|
|
PAGE_PROT[start]:=0;
|
|
Inc(start);
|
|
end;
|
|
WriteBarrier;
|
|
end;
|
|
|
|
function pmap_get_prot(addr:vm_offset_t):Byte;
|
|
begin
|
|
addr:=OFF_TO_IDX(addr);
|
|
addr:=addr and PAGE_MAP_MASK;
|
|
Result:=PAGE_PROT[addr];
|
|
end;
|
|
|
|
function pmap_get_page(addr:vm_offset_t):DWORD;
|
|
begin
|
|
addr:=OFF_TO_IDX(addr);
|
|
addr:=addr and PAGE_MAP_MASK;
|
|
Result:=addr+PAGE_MAP[addr];
|
|
end;
|
|
|
|
function pmap_test_cross(addr:vm_offset_t;h:Integer):Boolean;
|
|
var
|
|
page1,page2:DWORD;
|
|
begin
|
|
page1:=OFF_TO_IDX(addr ) and PAGE_MAP_MASK;
|
|
page2:=OFF_TO_IDX(addr+h) and PAGE_MAP_MASK;
|
|
if (page1=page2) then
|
|
begin
|
|
Result:=False;
|
|
end else
|
|
begin
|
|
page1:=PAGE_MAP[page1];
|
|
page2:=PAGE_MAP[page2];
|
|
Result:=(page1<>page2);
|
|
end;
|
|
end;
|
|
|
|
//rax,rdi,rsi
|
|
function uplift(addr:Pointer):Pointer; assembler; nostackframe;
|
|
label
|
|
_exit;
|
|
asm
|
|
//orig addr (rsi)
|
|
mov %rdi,%rsi
|
|
//high addr (rdi)
|
|
shr PMAPP_SHIFT,%rdi
|
|
//test
|
|
cmp PAGE_MAP_COUNT,%rdi
|
|
ja _exit
|
|
//uplift (rdi)
|
|
mov PAGE_MAP(%rip),%rax
|
|
movslq (%rax,%rdi,4),%rdi //sign extend int32->int64
|
|
//high addr (rdi)
|
|
shl PMAPP_SHIFT,%rdi
|
|
//combine (rdi+rsi)
|
|
lea (%rsi,%rdi),%rdi
|
|
//test
|
|
cmp PMAPP_SIZE,%rdi
|
|
jna _exit
|
|
//result
|
|
mov %rdi,%rax
|
|
ret
|
|
_exit:
|
|
xor %eax,%eax
|
|
end;
|
|
|
|
procedure iov_uplift(iov:p_iovec);
|
|
var
|
|
base:Ptruint;
|
|
len:Ptruint;
|
|
i,p:DWORD;
|
|
v:Integer;
|
|
begin
|
|
base:=Ptruint(iov^.iov_base);
|
|
len:=iov^.iov_len;
|
|
|
|
p:=base shr PMAPP_SHIFT;
|
|
|
|
if (p>=PAGE_MAP_COUNT) then
|
|
begin
|
|
//error
|
|
iov^.iov_base:=nil;
|
|
Exit;
|
|
end;
|
|
|
|
i:=base and PMAPP_MASK;
|
|
i:=PMAPP_SIZE-i;
|
|
if (i>len) then i:=len;
|
|
Dec(len,i);
|
|
|
|
v:=PAGE_MAP[p];
|
|
|
|
while (len<>0) and (p<PAGE_MAP_COUNT) do
|
|
begin
|
|
Inc(p);
|
|
if (v<>PAGE_MAP[p]) then Break;
|
|
|
|
i:=PMAPP_SIZE;
|
|
if (i>len) then i:=len;
|
|
Dec(len,i);
|
|
end;
|
|
|
|
base:=base+(int64(v) shl PMAPP_SHIFT);
|
|
|
|
iov^.iov_base:=Pointer(base);
|
|
Dec(iov^.iov_len,len);
|
|
end;
|
|
|
|
const
|
|
VM_RWX=VM_PROT_READ or VM_PROT_WRITE or VM_PROT_EXECUTE;
|
|
|
|
wprots:array[0..7] of Byte=(
|
|
MD_PROT_NONE,//___
|
|
MD_PROT_R ,//__R
|
|
MD_PROT_W ,//_W_
|
|
MD_PROT_RW ,//_WR
|
|
MD_PROT_R ,//X__
|
|
MD_PROT_R ,//X_R
|
|
MD_PROT_RW ,//XW_
|
|
MD_PROT_RW //XWR
|
|
);
|
|
|
|
function get_vnode_handle(obj:vm_object_t):THandle;
|
|
var
|
|
vp:p_vnode;
|
|
begin
|
|
Result:=0;
|
|
|
|
vp:=obj^.handle;
|
|
|
|
if (vp<>nil) then
|
|
begin
|
|
VI_LOCK(vp);
|
|
|
|
Result:=THandle(vp^.v_un);
|
|
|
|
VI_UNLOCK(vp);
|
|
end;
|
|
end;
|
|
|
|
function vm_file_protect(start,__end:QWORD;base:Pointer;size:QWORD;prot:Integer):Integer;
|
|
var
|
|
paddi:QWORD;
|
|
delta:QWORD;
|
|
begin
|
|
Result:=md_protect(base,size,wprots[prot and VM_RWX]);
|
|
|
|
if (Result<>0) then
|
|
begin
|
|
Writeln('failed md_protect:0x',HexStr(Result,8));
|
|
Assert(false,'md_protect');
|
|
end;
|
|
|
|
//padding pages
|
|
paddi:=PAGE_SIZE-(size and PAGE_MASK);
|
|
|
|
if (paddi<>0) then
|
|
begin
|
|
delta:=__end-paddi;
|
|
//
|
|
//padding as private pages
|
|
Result:=md_protect(Pointer(VM_DEFAULT_MAP_BASE+delta),paddi,wprots[prot and VM_RWX]);
|
|
|
|
if (Result<>0) then
|
|
begin
|
|
Writeln('failed md_protect:0x',HexStr(Result,8));
|
|
Assert(false,'md_protect');
|
|
end;
|
|
end;
|
|
|
|
if (paddi<>0) then
|
|
begin
|
|
pmap_mark(start,delta,QWORD(base),prot and VM_RWX);
|
|
//
|
|
pmap_mark(delta,__end,VM_DEFAULT_MAP_BASE+delta,prot and VM_RWX);
|
|
end else
|
|
begin
|
|
pmap_mark(start,__end,QWORD(base),prot and VM_RWX);
|
|
end;
|
|
end;
|
|
|
|
function vm_file_remove(start,__end:QWORD;base:Pointer;size:QWORD):Integer;
|
|
var
|
|
paddi:QWORD;
|
|
delta:QWORD;
|
|
begin
|
|
Result:=0;
|
|
|
|
//padding pages
|
|
paddi:=PAGE_SIZE-(size and PAGE_MASK);
|
|
|
|
if (paddi<>0) then
|
|
begin
|
|
delta:=__end-paddi;
|
|
//
|
|
//padding as private pages
|
|
Result:=md_remove(Pointer(VM_DEFAULT_MAP_BASE+delta),paddi);
|
|
|
|
if (Result<>0) then
|
|
begin
|
|
Writeln('failed md_remove:0x',HexStr(Result,8));
|
|
Assert(false,'md_remove');
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function vm_file_unmap(base:Pointer;size:QWORD):Integer;
|
|
begin
|
|
Result:=md_file_unmap(base,size);
|
|
|
|
if (Result<>0) then
|
|
begin
|
|
Writeln('failed md_file_unmap:0x',HexStr(Result,8));
|
|
Assert(false,'md_file_unmap');
|
|
end;
|
|
end;
|
|
|
|
function vm_file_map_fixed(map :p_vm_file_map;
|
|
offset:vm_ooffset_t;
|
|
start :vm_offset_t;
|
|
__end :vm_offset_t;
|
|
base :Pointer;
|
|
size :QWORD):Integer;
|
|
var
|
|
obj:p_vm_file_obj;
|
|
begin
|
|
vm_file_map_delete(map,start,__end);
|
|
|
|
obj:=vm_file_obj_allocate(base,size);
|
|
|
|
obj^.protect:=@vm_file_protect;
|
|
obj^.remove :=@vm_file_remove;
|
|
obj^.unmap :=@vm_file_unmap;
|
|
|
|
Result:=vm_file_map_insert(map,obj,offset,start,__end);
|
|
end;
|
|
|
|
{
|
|
* Maps a sequence of resident pages belonging to the same object.
|
|
* The sequence begins with the given page m_start. This page is
|
|
* mapped at the given virtual address start. Each subsequent page is
|
|
* mapped at a virtual address that is offset from start by the same
|
|
* amount as the page is offset from m_start within the object. The
|
|
* last page in the sequence is the page with the largest offset from
|
|
* m_start that can be mapped at a virtual address less than the given
|
|
* virtual address end. Not every virtual page between start and end
|
|
* is mapped; only those for which a resident page exists with the
|
|
* corresponding offset from m_start are mapped.
|
|
}
|
|
procedure pmap_enter_object(pmap :pmap_t;
|
|
obj :vm_object_t;
|
|
offset :vm_ooffset_t;
|
|
start :vm_offset_t;
|
|
__end :vm_offset_t;
|
|
prot :vm_prot_t);
|
|
label
|
|
_default;
|
|
var
|
|
fd:THandle;
|
|
base:Pointer;
|
|
size:QWORD;
|
|
delta:QWORD;
|
|
paddi:QWORD;
|
|
r:Integer;
|
|
begin
|
|
Writeln('pmap_enter_object:',HexStr(start,11),':',HexStr(__end,11),':',HexStr(prot,2));
|
|
|
|
r:=0;
|
|
case vm_object_type(obj) of
|
|
OBJT_SELF , // same?
|
|
|
|
OBJT_DEFAULT:
|
|
begin
|
|
_default:
|
|
|
|
base:=Pointer(VM_DEFAULT_MAP_BASE+trunc_page(start));
|
|
size:=trunc_page(__end-start);
|
|
|
|
r:=md_enter(base,size,wprots[prot and VM_RWX]);
|
|
end;
|
|
OBJT_DEVICE:
|
|
begin
|
|
if (obj^.un_pager.map_base=nil) then
|
|
begin
|
|
goto _default;
|
|
end;
|
|
|
|
base:=obj^.un_pager.map_base+trunc_page(offset);
|
|
size:=trunc_page(__end-start);
|
|
|
|
if ((obj^.flags and OBJ_DMEM_EXT)<>0) then
|
|
begin
|
|
Writeln('pmap_enter_gpuobj:',HexStr(QWORD(base),11),':',HexStr(QWORD(base)+size,11),':',HexStr(prot,2));
|
|
|
|
r:=md_enter(base,size,MD_PROT_RWX);
|
|
end;
|
|
end;
|
|
OBJT_VNODE:
|
|
begin
|
|
base:=nil;
|
|
delta:=0;
|
|
paddi:=0;
|
|
|
|
VM_OBJECT_LOCK(obj);
|
|
|
|
fd:=get_vnode_handle(obj);
|
|
|
|
if (fd<>0) then
|
|
begin
|
|
|
|
delta :=offset and (MD_ALLOC_GRANULARITY-1);
|
|
offset:=offset and (not (MD_ALLOC_GRANULARITY-1));
|
|
|
|
size:=delta+offset+(__end-start);
|
|
|
|
if (size>obj^.un_pager.vnp.vnp_size) then
|
|
begin
|
|
size:=obj^.un_pager.vnp.vnp_size;
|
|
end;
|
|
size:=size-offset;
|
|
|
|
base:=nil;
|
|
r:=md_file_mmap(fd,base,offset,size,wprots[prot and VM_RWX]);
|
|
|
|
if (r<>0) then
|
|
begin
|
|
Writeln('failed md_file_mmap:0x',HexStr(r,8));
|
|
Assert(false,'md_file_mmap');
|
|
end;
|
|
|
|
if (r=0) and (delta<>0) then
|
|
begin
|
|
//protect head
|
|
md_protect(base,delta,MD_PROT_NONE);
|
|
end;
|
|
|
|
if (r=0) then
|
|
begin
|
|
//align host page
|
|
size:=(size+(MD_PAGE_SIZE-1)) and (not (MD_PAGE_SIZE-1));
|
|
|
|
//padding pages
|
|
paddi:=PAGE_SIZE-((size-delta) and PAGE_MASK);
|
|
|
|
if (paddi<>0) then
|
|
begin
|
|
//padding as private pages
|
|
r:=md_enter(Pointer(VM_DEFAULT_MAP_BASE+__end-paddi),paddi,wprots[prot and VM_RWX]);
|
|
|
|
if (r<>0) then
|
|
begin
|
|
Writeln('failed md_enter:0x',HexStr(r,8));
|
|
Assert(false,'md_enter');
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
if (r=0) then
|
|
begin
|
|
r:=vm_file_map_fixed(@obj^.un_pager.vnp.file_map,
|
|
delta,
|
|
start,
|
|
__end,
|
|
base,
|
|
size);
|
|
end;
|
|
|
|
end;
|
|
|
|
VM_OBJECT_UNLOCK(obj);
|
|
|
|
if (r<>0) then
|
|
begin
|
|
Writeln('failed vm_file_map_fixed:0x',HexStr(r,8));
|
|
Assert(false,'vm_file_map_fixed');
|
|
end;
|
|
|
|
if (r=0) then
|
|
begin
|
|
base:=base+delta;
|
|
|
|
if (paddi<>0) then
|
|
begin
|
|
delta:=__end-paddi;
|
|
//
|
|
pmap_mark(start,delta,QWORD(base),prot and VM_RWX);
|
|
//
|
|
pmap_mark(delta,__end,VM_DEFAULT_MAP_BASE+delta,prot and VM_RWX);
|
|
end else
|
|
begin
|
|
pmap_mark(start,__end,QWORD(base),prot and VM_RWX);
|
|
end;
|
|
end;
|
|
|
|
Exit;
|
|
end;
|
|
else
|
|
begin
|
|
Writeln('TODO:',vm_object_type(obj));
|
|
Assert(False);
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
if (r<>0) then
|
|
begin
|
|
Writeln('failed md_enter:0x',HexStr(r,8));
|
|
Assert(false,'pmap_enter_object');
|
|
end;
|
|
|
|
pmap_mark(start,__end,QWORD(base),prot and VM_RWX);
|
|
end;
|
|
|
|
procedure pmap_move(pmap :pmap_t;
|
|
start :vm_offset_t;
|
|
ofs_old :vm_offset_t;
|
|
ofs_new :vm_offset_t;
|
|
size :vm_offset_t;
|
|
new_prot:vm_prot_t);
|
|
var
|
|
r:Integer;
|
|
begin
|
|
//pmap_mark_flags(start,start+size,PAGE_BUSY_FLAG);
|
|
|
|
//set old to readonly
|
|
r:=md_protect(Pointer(ofs_old),size,MD_PROT_R);
|
|
|
|
if (r<>0) then
|
|
begin
|
|
Writeln('failed md_protect:0x',HexStr(r,8));
|
|
Assert(false,'pmap_move');
|
|
end;
|
|
|
|
//alloc new
|
|
r:=md_enter(Pointer(ofs_new),size,MD_PROT_RW);
|
|
|
|
if (r<>0) then
|
|
begin
|
|
Writeln('failed md_enter:0x',HexStr(r,8));
|
|
Assert(false,'pmap_move');
|
|
end;
|
|
|
|
//move data
|
|
Move(Pointer(ofs_old)^,Pointer(ofs_new)^,size);
|
|
|
|
//prot new
|
|
if (MD_PROT_RW<>wprots[new_prot and VM_RWX]) then
|
|
begin
|
|
r:=md_protect(Pointer(ofs_new),size,wprots[new_prot and VM_RWX]);
|
|
|
|
if (r<>0) then
|
|
begin
|
|
Writeln('failed md_protect:0x',HexStr(r,8));
|
|
Assert(false,'pmap_move');
|
|
end;
|
|
end;
|
|
|
|
pmap_mark(start,start+size,ofs_new,new_prot);
|
|
|
|
//free old
|
|
r:=md_remove(Pointer(ofs_old),size);
|
|
|
|
if (r<>0) then
|
|
begin
|
|
Writeln('failed md_remove:0x',HexStr(r,8));
|
|
Assert(false,'pmap_move');
|
|
end;
|
|
end;
|
|
|
|
procedure pmap_protect(pmap :pmap_t;
|
|
obj :vm_object_t;
|
|
offset:vm_ooffset_t;
|
|
start :vm_offset_t;
|
|
__end :vm_offset_t;
|
|
prot :vm_prot_t);
|
|
label
|
|
_default;
|
|
var
|
|
base:Pointer;
|
|
size:QWORD;
|
|
r:Integer;
|
|
begin
|
|
Writeln('pmap_protect:',HexStr(start,11),':',HexStr(__end,11),':prot:',HexStr(prot,2));
|
|
|
|
r:=0;
|
|
case vm_object_type(obj) of
|
|
OBJT_SELF , // same?
|
|
|
|
OBJT_DEFAULT:
|
|
begin
|
|
_default:
|
|
|
|
base:=Pointer(VM_DEFAULT_MAP_BASE+trunc_page(start));
|
|
size:=trunc_page(__end-start);
|
|
|
|
r:=md_protect(base,size,wprots[prot and VM_RWX]);
|
|
end;
|
|
OBJT_DEVICE:
|
|
begin
|
|
if (obj^.un_pager.map_base=nil) then
|
|
begin
|
|
goto _default;
|
|
end;
|
|
|
|
base:=obj^.un_pager.map_base+trunc_page(offset);
|
|
size:=trunc_page(__end-start);
|
|
|
|
if ((obj^.flags and OBJ_DMEM_EXT)<>0) then
|
|
begin
|
|
Writeln('pmap_protect_gpuobj:',HexStr(QWORD(base),11),':',HexStr(QWORD(base)+size,11),':',HexStr(prot,2));
|
|
|
|
r:=md_protect(base,size,MD_PROT_RWX);
|
|
end;
|
|
end;
|
|
OBJT_VNODE:
|
|
begin
|
|
VM_OBJECT_LOCK(obj);
|
|
|
|
r:=vm_file_map_protect(@obj^.un_pager.vnp.file_map,
|
|
start,
|
|
__end,
|
|
prot);
|
|
|
|
VM_OBJECT_UNLOCK(obj);
|
|
|
|
if (r<>0) then
|
|
begin
|
|
Writeln('failed vm_file_map_protect:0x',HexStr(r,8));
|
|
Assert(false,'vm_file_map_protect');
|
|
end;
|
|
|
|
Exit;
|
|
end;
|
|
else
|
|
begin
|
|
Writeln('TODO:',vm_object_type(obj));
|
|
Assert(False);
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
if (r<>0) then
|
|
begin
|
|
Writeln('failed md_protect:0x',HexStr(r,8));
|
|
Assert(false,'pmap_protect');
|
|
end;
|
|
|
|
pmap_mark(start,__end,QWORD(base),prot and VM_RWX);
|
|
end;
|
|
|
|
procedure pmap_madv_free(pmap :pmap_t;
|
|
obj :vm_object_t;
|
|
offset:vm_ooffset_t;
|
|
start :vm_offset_t;
|
|
__end :vm_offset_t;
|
|
prot :vm_prot_t);
|
|
label
|
|
_default;
|
|
var
|
|
base:Pointer;
|
|
size:QWORD;
|
|
r:Integer;
|
|
begin
|
|
Writeln('pmap_madv_free:',HexStr(start,11),':',HexStr(__end,11),':',HexStr(prot,2));
|
|
|
|
r:=0;
|
|
case vm_object_type(obj) of
|
|
OBJT_SELF , // same?
|
|
|
|
OBJT_DEFAULT:
|
|
begin
|
|
_default:
|
|
|
|
base:=Pointer(VM_DEFAULT_MAP_BASE+trunc_page(start));
|
|
size:=trunc_page(__end-start);
|
|
|
|
r:=md_reset(base,size,wprots[prot and VM_RWX]);
|
|
end;
|
|
OBJT_DEVICE:
|
|
begin
|
|
if (obj^.un_pager.map_base=nil) then
|
|
begin
|
|
goto _default;
|
|
end;
|
|
//ignore
|
|
end;
|
|
OBJT_PHYSHM:
|
|
begin
|
|
//ignore
|
|
end;
|
|
OBJT_VNODE:
|
|
begin
|
|
//ignore
|
|
end;
|
|
else
|
|
begin
|
|
Writeln('TODO:',vm_object_type(obj));
|
|
Assert(False);
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
if (r<>0) then
|
|
begin
|
|
Writeln('failed md_reset:0x',HexStr(r,8));
|
|
Assert(false,'pmap_madv_free');
|
|
end;
|
|
end;
|
|
|
|
procedure pmap_remove(pmap :pmap_t;
|
|
obj :vm_object_t;
|
|
offset:vm_ooffset_t;
|
|
start :vm_offset_t;
|
|
__end :vm_offset_t;
|
|
prot :vm_prot_t);
|
|
label
|
|
_default;
|
|
var
|
|
base:Pointer;
|
|
size:QWORD;
|
|
r:Integer;
|
|
begin
|
|
Writeln('pmap_remove:',HexStr(start,11),':',HexStr(__end,11),':',HexStr(prot,2));
|
|
|
|
pmap_unmark(start,__end);
|
|
|
|
r:=0;
|
|
case vm_object_type(obj) of
|
|
OBJT_SELF , // same?
|
|
|
|
OBJT_DEFAULT:
|
|
begin
|
|
_default:
|
|
|
|
base:=Pointer(VM_DEFAULT_MAP_BASE+trunc_page(start));
|
|
size:=trunc_page(__end-start);
|
|
|
|
r:=md_remove(base,size);
|
|
end;
|
|
OBJT_DEVICE:
|
|
begin
|
|
if (obj^.un_pager.map_base=nil) then
|
|
begin
|
|
goto _default;
|
|
end;
|
|
|
|
base:=obj^.un_pager.map_base+trunc_page(offset);
|
|
size:=trunc_page(__end-start);
|
|
|
|
if ((obj^.flags and OBJ_DMEM_EXT)<>0) then
|
|
begin
|
|
Writeln('pmap_remove_gpuobj:',HexStr(QWORD(base),11),':',HexStr(QWORD(base)+size,11),':',HexStr(prot,2));
|
|
|
|
r:=md_remove(base,size);
|
|
end;
|
|
end;
|
|
OBJT_VNODE:
|
|
begin
|
|
VM_OBJECT_LOCK(obj);
|
|
|
|
r:=vm_file_map_delete(@obj^.un_pager.vnp.file_map,
|
|
start,
|
|
__end);
|
|
|
|
VM_OBJECT_UNLOCK(obj);
|
|
|
|
if (r<>0) then
|
|
begin
|
|
Writeln('failed vm_file_map_delete:0x',HexStr(r,8));
|
|
Assert(false,'vm_file_map_delete');
|
|
end;
|
|
|
|
Exit;
|
|
end;
|
|
else
|
|
begin
|
|
Writeln('TODO:',vm_object_type(obj));
|
|
Assert(False);
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
if (r<>0) then
|
|
begin
|
|
Writeln('failed md_remove:0x',HexStr(r,8));
|
|
Assert(false,'pmap_remove');
|
|
end;
|
|
end;
|
|
|
|
|
|
end.
|
|
|