unit mmap; {$mode ObjFPC}{$H+} interface uses Windows; const // CPU SCE_KERNEL_PROT_CPU_READ =$01; SCE_KERNEL_PROT_CPU_WRITE=$02; SCE_KERNEL_PROT_CPU_RW =(SCE_KERNEL_PROT_CPU_READ or SCE_KERNEL_PROT_CPU_WRITE); SCE_KERNEL_PROT_CPU_EXEC =$04; SCE_KERNEL_PROT_CPU_ALL =(SCE_KERNEL_PROT_CPU_RW or SCE_KERNEL_PROT_CPU_EXEC); // GPU SCE_KERNEL_PROT_GPU_READ =$10; SCE_KERNEL_PROT_GPU_WRITE=$20; SCE_KERNEL_PROT_GPU_RW =(SCE_KERNEL_PROT_GPU_READ or SCE_KERNEL_PROT_GPU_WRITE); SCE_KERNEL_PROT_GPU_ALL =SCE_KERNEL_PROT_GPU_RW; SCE_KERNEL_MAP_FIXED =$0010; SCE_KERNEL_MAP_NO_OVERWRITE=$0080; SCE_KERNEL_MAP_DMEM_COMPAT =$0400; SCE_KERNEL_MAP_NO_COALESCE =$400000; SCE_KERNEL_WB_ONION = 0; SCE_KERNEL_WC_GARLIC = 3; SCE_KERNEL_WB_GARLIC =10; //deprecated SCE_KERNEL_WB_ONION_NONVOLATILE = 1; SCE_KERNEL_WC_GARLIC_VOLATILE = 2; SCE_KERNEL_WC_GARLIC_NONVOLATILE = 3; SCE_KERNEL_WT_ONION_VOLATILE = 4; SCE_KERNEL_WT_ONION_NONVOLATILE = 5; SCE_KERNEL_WP_ONION_VOLATILE = 6; SCE_KERNEL_WP_ONION_NONVOLATILE = 7; SCE_KERNEL_UC_GARLIC_VOLATILE = 8; SCE_KERNEL_UC_GARLIC_NONVOLATILE = 9; //mmap PROT_NONE =$00; // no permissions PROT_READ =$01; // pages can be read PROT_WRITE =$02; // pages can be written PROT_EXEC =$04; // pages can be executed PROT_CPU_READ =PROT_READ; PROT_CPU_WRITE =PROT_WRITE; PROT_CPU_ALL =$07; PROT_GPU_READ =$10; PROT_GPU_WRITE =$20; PROT_GPU_ALL =$30; MAP_SHARED =$0001; // share changes MAP_PRIVATE =$0002; // changes are private MAP_FIXED =$0010; // map addr must be exactly as requested MAP_NO_OVERWRITE=$0080; MAP_VOID =$0100; // reserve MAP_RENAME =$0020; // Sun: rename private pages to file MAP_NORESERVE =$0040; // Sun: don't reserve needed swap area MAP_HASSEMAPHORE=$0200; // region may contain semaphores MAP_STACK =$0400; // region grows down, like a stack MAP_NOSYNC =$0800; // page to but do not sync underlying file MAP_FILE =$0000; // map from file (default) MAP_ANON =$1000; // allocated from memory, swap space MAP_ANONYMOUS =MAP_ANON; // For compatibility. MAP_SYSTEM =$2000; MAP_ALLAVAILABLE=$4000; MAP_SELF =$00080000; // map decryped SELF file MAP_ALIGNMENT_BIT =24; MAP_ALIGNMENT_MASK=$1f000000; MAP_ALIGNMENT_MUL =$01000000; //1 shl 24 MCL_CURRENT=$0001; // Lock only current memory MCL_FUTURE =$0002; // Lock all future memory as well MAP_FAILED =Pointer(-1); MS_SYNC =$0000; // msync synchronously MS_ASYNC =$0001; // return immediately MS_INVALIDATE=$0002; // invalidate all cached data function _isgpu(prot:Integer):Boolean; inline; function _iswrite(prot:Integer):Boolean; inline; function __map_prot_page(prot:Integer):DWORD; function __win_prot_page(prot:DWORD):Integer; function __map_prot_file(prot:Integer):DWORD; function _VirtualAlloc (Addr:Pointer;dwSize:PTRUINT;prot:Integer):Integer; function _VirtualReserve (Addr:Pointer;dwSize:PTRUINT;prot:Integer):Integer; function _VirtualCommit (Addr:Pointer;dwSize:PTRUINT;prot:Integer):Integer; function _VirtualDecommit(Addr:Pointer;dwSize:PTRUINT):Integer; function _VirtualFree (Addr:Pointer):Integer; function _VirtualMmap (Addr:Pointer;len:size_t;prot,fd:Integer;offst:size_t):Integer; function _VirtualUnmap (addr:Pointer):Integer; function _VirtualProtect (addr:Pointer;len:size_t;prot:Integer):Integer; function _VirtualQuery (addr:Pointer;paddr:PPointer;psize:Pptruint;pprots,pflags:PInteger):Integer; implementation uses sys_fd, sys_kernel; const FILE_MAP_EXECUTE=$0020; function _isgpu(prot:Integer):Boolean; inline; begin Result:=prot and (PROT_GPU_READ or PROT_GPU_WRITE)<>0; end; function _iswrite(prot:Integer):Boolean; inline; begin Result:=prot and (PROT_WRITE or PROT_GPU_WRITE)<>0; end; function __map_prot_page(prot:Integer):DWORD; begin Result:=0; if (prot=PROT_NONE) then Exit(PAGE_NOACCESS); if (prot and PROT_EXEC)<>0 then begin if (prot and (PROT_WRITE or PROT_GPU_WRITE))<>0 then begin Result:=PAGE_EXECUTE_READWRITE; end else if (prot and (PROT_READ or PROT_GPU_READ))<>0 then begin Result:=PAGE_EXECUTE_READ; end else begin Result:=PAGE_EXECUTE; end; end else if (prot and (PROT_WRITE or PROT_GPU_WRITE))<>0 then begin Result:=PAGE_READWRITE; end else begin Result:=PAGE_READONLY; end; end; function __win_prot_page(prot:DWORD):Integer; begin Result:=0; prot:=prot and ( PAGE_NOACCESS or PAGE_READONLY or PAGE_READWRITE or PAGE_EXECUTE or PAGE_EXECUTE_READ or PAGE_EXECUTE_READWRITE); Case prot of 0, PAGE_NOACCESS :Result:=0; PAGE_READONLY :Result:=PROT_READ; PAGE_READWRITE :Result:=PROT_READ or PROT_WRITE; PAGE_EXECUTE :Result:=PROT_EXEC; PAGE_EXECUTE_READ :Result:=PROT_EXEC or PROT_READ; PAGE_EXECUTE_READWRITE:Result:=PROT_EXEC or PROT_READ or PROT_WRITE; else; end; end; function __map_prot_file(prot:Integer):DWORD; begin Result:= 0; if (prot=PROT_NONE) then Exit; if (prot and PROT_READ) <>0 then Result:=Result or FILE_MAP_READ; if (prot and PROT_WRITE)<>0 then Result:=Result or FILE_MAP_WRITE; if (prot and PROT_EXEC) <>0 then Result:=Result or FILE_MAP_EXECUTE; end; function _VirtualAlloc(Addr:Pointer;dwSize:PTRUINT;prot:Integer):Integer; begin Result:=0; if (Addr=nil) then Exit(-1); Addr:=VirtualAlloc(Addr,dwSize,MEM_COMMIT or MEM_RESERVE,__map_prot_page(prot)); if (Addr<>nil) then Exit; Result:=GetLastError; end; function _VirtualReserve(Addr:Pointer;dwSize:PTRUINT;prot:Integer):Integer; begin Result:=0; if (Addr=nil) then Exit(-1); Addr:=VirtualAlloc(Addr,dwSize,MEM_RESERVE,PAGE_NOACCESS); if (Addr<>nil) then Exit; Result:=GetLastError; end; function _VirtualCommit(Addr:Pointer;dwSize:PTRUINT;prot:Integer):Integer; var new:Pointer; begin Result:=0; if (Addr=nil) then Exit(-1); new:=VirtualAlloc(Addr,dwSize,MEM_COMMIT,__map_prot_page(prot)); if (new<>nil) then begin Assert(new=Addr); Exit; end; Result:=GetLastError; end; function _VirtualDecommit(Addr:Pointer;dwSize:PTRUINT):Integer; begin Result:=0; if (Addr=nil) then Exit(-1); if (dwSize=0) then Exit; if not VirtualFree(Addr,dwSize,MEM_DECOMMIT) then begin Result:=GetLastError; end; end; function _VirtualFree(Addr:Pointer):Integer; begin Result:=0; if (Addr=nil) then Exit(-1); if not VirtualFree(Addr,0,MEM_RELEASE) then begin Result:=GetLastError; end; end; function _VirtualMmap(Addr:Pointer;len:size_t;prot,fd:Integer;offst:size_t):Integer; Var fm,h:THandle; dwFileOffsetLow, dwFileOffsetHigh, protect, desiredAccess, dwMaxSizeLow, dwMaxSizeHigh:DWORD; fileSize:size_t; maxSize:size_t; //info:BY_HANDLE_FILE_INFORMATION; begin Result:=0; if (Addr=nil) then Exit(-1); h:=_sys_get_osfhandle(fd); if (h=INVALID_HANDLE_VALUE) then begin Exit(GetLastError); end; fileSize:=0; if not GetFileSizeEx(h,@fileSize) then begin Exit(GetLastError); end; //info:=Default(BY_HANDLE_FILE_INFORMATION); //Result:=SwGetFileInformationByHandle(h,@info); //if (Result<>0) then Exit; //fileSize:=info.nFileSizeLow or (QWORD(info.nFileSizeHigh) shl 32); maxSize:=offst+len; if (maxSize>fileSize) then begin maxSize:=fileSize; len:=maxSize-offst; end; dwFileOffsetLow :=DWORD(offst and $FFFFFFFF); dwFileOffsetHigh:=DWORD(offst shr 32); dwMaxSizeLow :=DWORD(maxSize and $FFFFFFFF); dwMaxSizeHigh :=DWORD(maxSize shr 32); protect :=__map_prot_page(prot); desiredAccess:=__map_prot_file(prot); fm:=CreateFileMapping(h,nil,protect,dwMaxSizeHigh,dwMaxSizeLow,nil); if (fm=0) then begin Exit(GetLastError); end; addr:=MapViewOfFileEx(fm,desiredAccess,dwFileOffsetHigh,dwFileOffsetLow,len,addr); CloseHandle(fm); if (addr=nil) then begin Exit(GetLastError); end; end; function _VirtualUnmap(addr:Pointer):Integer; begin if (Addr=nil) then Exit(-1); if UnmapViewOfFile(addr) then begin Result:=0; end else begin Result:=GetLastError; end; end; function _VirtualProtect(addr:Pointer;len:size_t;prot:Integer):Integer; Var old:DWORD; begin Result:=0; old:=0; if not VirtualProtect(addr,len,__map_prot_page(prot),old) then begin Result:=GetLastError; end; end; function _win_state(state:DWORD):Integer; inline; begin Case state of MEM_COMMIT :Result:=MAP_FIXED; MEM_RESERVE:Result:=MAP_VOID; else Result:=0; end; end; function _win_mtype(mtype:DWORD):Integer; inline; begin Case mtype of MEM_PRIVATE:Result:=MAP_ANON; else Result:=MAP_SHARED; end; end; function _VirtualQuery(addr:Pointer;paddr:PPointer;psize:Pptruint;pprots,pflags:PInteger):Integer; var Info:TMemoryBasicInformation; begin Result:=0; Info:=Default(TMemoryBasicInformation); Result:=VirtualQuery(addr,Info,SizeOf(TMemoryBasicInformation)); if (Result=0) then begin Result:=GetLastError; end else begin Result:=0; if (paddr<>nil) then begin Case Info.State of MEM_FREE :paddr^:=Info.BaseAddress; else paddr^:=Info.AllocationBase; end; end; if (psize<>nil) then begin Case Info.State of MEM_FREE :psize^:=Info.RegionSize; else psize^:=Info.RegionSize+(ptruint(Info.BaseAddress)-ptruint(Info.AllocationBase)); end; end; if (pprots<>nil) then begin pprots^:=__win_prot_page(Info.Protect); end; if (pflags<>nil) then begin pflags^:=_win_state(Info.State) or _win_mtype(Info._Type) end; end; end; end.