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.