mirror of https://github.com/red-prig/fpPS4.git
228 lines
4.2 KiB
Plaintext
228 lines
4.2 KiB
Plaintext
unit device_pager;
|
|
|
|
{$mode ObjFPC}{$H+}
|
|
{$CALLING SysV_ABI_CDecl}
|
|
|
|
interface
|
|
|
|
uses
|
|
vm,
|
|
sys_vm_object;
|
|
|
|
function dev_pager_alloc(
|
|
handle:Pointer;
|
|
size :vm_ooffset_t;
|
|
prot :vm_prot_t;
|
|
foff :vm_ooffset_t):vm_object_t;
|
|
|
|
procedure dev_pager_dealloc(obj:vm_object_t);
|
|
|
|
implementation
|
|
|
|
uses
|
|
errno,
|
|
vmparam,
|
|
vm_pmap,
|
|
sys_conf;
|
|
|
|
function OFF_TO_IDX(x:QWORD):QWORD; inline;
|
|
begin
|
|
Result:=QWORD(x) shr PAGE_SHIFT;
|
|
end;
|
|
|
|
function old_dev_pager_ctor(
|
|
handle:Pointer;
|
|
size :vm_ooffset_t;
|
|
prot :vm_prot_t;
|
|
foff :vm_ooffset_t;
|
|
color :pword):Integer;
|
|
var
|
|
dev:p_cdev;
|
|
csw:p_cdevsw;
|
|
dummy:vm_memattr_t;
|
|
off:vm_ooffset_t;
|
|
paddr:vm_paddr_t;
|
|
npages:DWORD;
|
|
ref:Integer;
|
|
begin
|
|
{
|
|
* Make sure this device can be mapped.
|
|
}
|
|
dev:=handle;
|
|
csw:=dev_refthread(dev, @ref);
|
|
if (csw=nil) then
|
|
begin
|
|
Exit(ENXIO);
|
|
end;
|
|
|
|
{
|
|
* Check that the specified range of the device allows the desired
|
|
* protection.
|
|
*
|
|
* XXX assumes VM_PROT_*=PROT_*
|
|
}
|
|
npages:=OFF_TO_IDX(size);
|
|
paddr:=0; { Make paddr initialized for the case of size=0. }
|
|
|
|
off:=foff;
|
|
while (npages<>0) do
|
|
begin
|
|
if (csw^.d_mmap(dev, off, @paddr, prot, @dummy)<>0) then
|
|
begin
|
|
dev_relthread(dev, ref);
|
|
Exit(EINVAL);
|
|
end;
|
|
//
|
|
Dec(npages);
|
|
Inc(off,PAGE_SIZE);
|
|
end;
|
|
|
|
dev_ref(dev);
|
|
dev_relthread(dev, ref);
|
|
|
|
color^:=atop(paddr) - OFF_TO_IDX(off - PAGE_SIZE);
|
|
Exit(0);
|
|
end;
|
|
|
|
procedure old_dev_pager_dtor(handle:Pointer);
|
|
begin
|
|
dev_rel(handle);
|
|
end;
|
|
|
|
function cdev_pager_allocate(
|
|
handle:Pointer;
|
|
tp :obj_type;
|
|
size :vm_ooffset_t;
|
|
prot :vm_prot_t;
|
|
foff :vm_ooffset_t):vm_object_t;
|
|
var
|
|
obj,obj1:vm_object_t;
|
|
pindex:vm_pindex_t;
|
|
color:word;
|
|
begin
|
|
if (tp<>OBJT_DEVICE) then
|
|
begin
|
|
Exit(nil);
|
|
end;
|
|
|
|
{
|
|
* Offset should be page aligned.
|
|
}
|
|
if ((foff and PAGE_MASK)<>0) then
|
|
begin
|
|
Exit(nil);
|
|
end;
|
|
|
|
size:=round_page(size);
|
|
pindex:=OFF_TO_IDX(foff + size);
|
|
|
|
if (old_dev_pager_ctor(handle, size, prot, foff, @color)<>0) then
|
|
begin
|
|
Exit(nil);
|
|
end;
|
|
|
|
//mtx_lock(@dev_pager_mtx);
|
|
|
|
{
|
|
* Look up pager, creating as necessary.
|
|
}
|
|
obj1:=nil;
|
|
obj:=nil;
|
|
//obj:=vm_pager_object_lookup(@dev_pager_object_list, handle);
|
|
if (obj=nil) then
|
|
begin
|
|
{
|
|
* Allocate obj and associate it with the pager. Initialize
|
|
* the obj's pg_color based upon the physical address of the
|
|
* device's memory.
|
|
}
|
|
//mtx_unlock(@dev_pager_mtx);
|
|
|
|
obj1:=vm_object_allocate(tp, pindex);
|
|
obj1^.flags:=obj1^.flags or OBJ_COLORED;
|
|
obj1^.pg_color:=color;
|
|
obj1^.handle:=handle;
|
|
//obj1^.un_pager.devp.ops:=ops;
|
|
//TAILQ_INIT(@obj1^.un_pager.devp.devp_pglist);
|
|
//mtx_lock(@dev_pager_mtx);
|
|
|
|
obj:=nil;
|
|
//obj:=vm_pager_object_lookup(@dev_pager_object_list, handle);
|
|
if (obj<>nil) then
|
|
begin
|
|
{
|
|
* We raced with other thread while allocating obj.
|
|
}
|
|
if (pindex > obj^.size) then
|
|
begin
|
|
obj^.size:=pindex;
|
|
end;
|
|
end else
|
|
begin
|
|
obj:=obj1;
|
|
obj1:=nil;
|
|
obj^.handle:=handle;
|
|
//TAILQ_INSERT_TAIL(@dev_pager_object_list, obj, pager_object_list);
|
|
Assert(obj^.otype=tp,'Inconsistent device pager otype');
|
|
end;
|
|
end else
|
|
begin
|
|
if (pindex > obj^.size) then
|
|
begin
|
|
obj^.size:=pindex;
|
|
end;
|
|
end;
|
|
|
|
//mtx_unlock(@dev_pager_mtx);
|
|
|
|
if (obj1<>nil) then
|
|
begin
|
|
obj1^.handle:=obj1;
|
|
//mtx_lock(@dev_pager_mtx);
|
|
//TAILQ_INSERT_TAIL(@dev_pager_object_list, obj1, pager_object_list);
|
|
//mtx_unlock(@dev_pager_mtx);
|
|
vm_object_deallocate(obj1);
|
|
end;
|
|
Exit(obj);
|
|
end;
|
|
|
|
function dev_pager_alloc(
|
|
handle:Pointer;
|
|
size :vm_ooffset_t;
|
|
prot :vm_prot_t;
|
|
foff :vm_ooffset_t):vm_object_t;
|
|
begin
|
|
Exit(cdev_pager_allocate(handle, OBJT_DEVICE, size, prot, foff));
|
|
end;
|
|
|
|
procedure dev_pager_dealloc(obj:vm_object_t);
|
|
begin
|
|
//vm_page_t m;
|
|
|
|
VM_OBJECT_UNLOCK(obj);
|
|
old_dev_pager_dtor(obj^.handle);
|
|
|
|
//mtx_lock(@dev_pager_mtx);
|
|
//TAILQ_REMOVE(@dev_pager_object_list, obj, pager_object_list);
|
|
//mtx_unlock(@dev_pager_mtx);
|
|
VM_OBJECT_LOCK(obj);
|
|
|
|
if (obj^.otype=OBJT_DEVICE) then
|
|
begin
|
|
{
|
|
* Free up our fake pages.
|
|
}
|
|
//while ((m:=TAILQ_FIRST(@obj^.un_pager.devp.devp_pglist))<>nil) do
|
|
//begin
|
|
// dev_pager_free_page(obj, m);
|
|
//end;
|
|
end;
|
|
obj^.handle:=nil;
|
|
obj^.otype:=OBJT_DEAD;
|
|
end;
|
|
|
|
|
|
|
|
end.
|
|
|