forked from amir/filehasher
286 lines
9.8 KiB
C
286 lines
9.8 KiB
C
#pragma once
|
||
#include <stdio.h>
|
||
#include <windows.h>
|
||
#include <winnt.h>
|
||
|
||
// Forward declarations
|
||
typedef struct IORING_HANDLE_REF IORING_HANDLE_REF;
|
||
typedef struct IORING_BUFFER_REF IORING_BUFFER_REF;
|
||
typedef void *HIORING;
|
||
|
||
/* --------------------- Types declaration --------------------- */
|
||
typedef enum IORING_CREATE_ADVISORY_FLAGS {
|
||
IORING_CREATE_ADVISORY_FLAGS_NONE,
|
||
IORING_CREATE_SKIP_BUILDER_PARAM_CHECKS
|
||
} IORING_CREATE_ADVISORY_FLAGS;
|
||
// Specifies advisory flags for creating an I/O ring with a call to
|
||
// CreateIoRing.
|
||
|
||
typedef enum IORING_CREATE_REQUIRED_FLAGS {
|
||
IORING_CREATE_REQUIRED_FLAGS_NONE
|
||
} IORING_CREATE_REQUIRED_FLAGS;
|
||
// Specifies required flags for creating an I/O ring with a call to
|
||
// CreateIoRing.
|
||
|
||
typedef enum IORING_REF_KIND {
|
||
IORING_REF_RAW = 0,
|
||
IORING_REF_REGISTERED = 1,
|
||
} IORING_REF_KIND;
|
||
// Specifies the type of an IORING_HANDLE_REF structure.
|
||
|
||
typedef enum IORING_SQE_FLAGS {
|
||
IOSQE_FLAGS_NONE,
|
||
IOSQE_FLAGS_DRAIN_PRECEDING_OPS
|
||
} IORING_SQE_FLAGS;
|
||
// Specifies kernel behavior options for I/O ring submission queue entries
|
||
|
||
// IORING_REGISTERED_BUFFER structure
|
||
typedef struct IORING_REGISTERED_BUFFER {
|
||
UINT32 Index;
|
||
UINT32 Offset;
|
||
} IORING_REGISTERED_BUFFER;
|
||
|
||
// IORING_HANDLE_REF
|
||
struct IORING_HANDLE_REF {
|
||
IORING_REF_KIND Kind;
|
||
union {
|
||
HANDLE Handle;
|
||
UINT32 Index;
|
||
} HandleUnion;
|
||
};
|
||
// Represents a reference to a file handle used in an I/O ring operation
|
||
|
||
// IORING_BUFFER_REF
|
||
struct IORING_BUFFER_REF {
|
||
IORING_REF_KIND Kind;
|
||
union {
|
||
void *Address;
|
||
IORING_REGISTERED_BUFFER IndexAndOffset;
|
||
} BufferUnion;
|
||
};
|
||
|
||
typedef struct IORING_BUFFER_INFO {
|
||
void *Address;
|
||
UINT32 Length;
|
||
} IORING_BUFFER_INFO;
|
||
|
||
// IORING_BUFFER_REF represents a reference to a buffer used in an I/O ring
|
||
// operation
|
||
|
||
// IORING_VERSION enumeration
|
||
typedef enum IORING_VERSION {
|
||
IORING_VERSION_INVALID = 0,
|
||
IORING_VERSION_1 = 1,
|
||
IORING_VERSION_2 = 2,
|
||
IORING_VERSION_3 = 3,
|
||
IORING_VERSION_4 = 4,
|
||
} IORING_VERSION;
|
||
|
||
typedef enum IORING_FEATURE_FLAGS {
|
||
IORING_FEATURE_FLAGS_NONE = 0,
|
||
IORING_FEATURE_UM_EMULATION = 1
|
||
} IORING_FEATURE_FLAGS;
|
||
|
||
// IORING_CAPABILITIES structure
|
||
typedef struct IORING_CAPABILITIES {
|
||
IORING_VERSION MaxVersion;
|
||
UINT32 MaxSubmissionQueueSize;
|
||
UINT32 MaxCompletionQueueSize;
|
||
IORING_FEATURE_FLAGS FeatureFlags;
|
||
} IORING_CAPABILITIES;
|
||
// Represents the IORING API capabilities.
|
||
|
||
// IORING_CQE structure
|
||
typedef struct IORING_CQE {
|
||
UINT_PTR UserData;
|
||
HRESULT ResultCode;
|
||
ULONG_PTR Information;
|
||
} IORING_CQE;
|
||
// Represents a completed I/O ring queue entry.
|
||
|
||
// IORING_CREATE_FLAGS structure
|
||
typedef struct IORING_CREATE_FLAGS {
|
||
IORING_CREATE_REQUIRED_FLAGS Required;
|
||
IORING_CREATE_ADVISORY_FLAGS Advisory;
|
||
} IORING_CREATE_FLAGS;
|
||
// Specifies flags for creating an I/O ring with a call to CreateIoRing.
|
||
|
||
// IORING_INFO structure
|
||
typedef struct IORING_INFO {
|
||
IORING_VERSION IoRingVersion;
|
||
IORING_CREATE_FLAGS Flags;
|
||
UINT32 SubmissionQueueSize;
|
||
UINT32 CompletionQueueSize;
|
||
} IORING_INFO;
|
||
// Represents the shape and version information for the specified I/O ring
|
||
|
||
// IORING_OP_CODE for IsIoRingOpSupported
|
||
typedef enum IORING_OP_CODE {
|
||
IORING_OP_NOP = 0,
|
||
IORING_OP_READ = 1,
|
||
IORING_OP_WRITE = 2,
|
||
IORING_OP_FLUSH = 3,
|
||
IORING_OP_REGISTER_BUFFERS = 4,
|
||
IORING_OP_REGISTER_FILES = 5,
|
||
IORING_OP_CANCEL = 6,
|
||
} IORING_OP_CODE;
|
||
|
||
/* --------------------- Dynamic loader --------------------- */
|
||
// Function pointer types
|
||
typedef BOOL(WINAPI *IsIoRingOpSupported_t)(HIORING, IORING_OP_CODE);
|
||
typedef HRESULT(WINAPI *QueryIoRingCapabilities_t)(IORING_CAPABILITIES *);
|
||
typedef HRESULT(WINAPI *GetIoRingInfo_t)(HIORING, IORING_INFO *);
|
||
typedef HRESULT(WINAPI *CreateIoRing_t)(IORING_VERSION, IORING_CREATE_FLAGS,
|
||
UINT32, UINT32, HIORING *);
|
||
typedef HRESULT(WINAPI *CloseIoRing_t)(HIORING);
|
||
typedef HRESULT(WINAPI *SubmitIoRing_t)(HIORING, UINT32, UINT32, UINT32 *);
|
||
typedef HRESULT(WINAPI *PopIoRingCompletion_t)(HIORING, IORING_CQE *);
|
||
typedef HRESULT(WINAPI *SetIoRingCompletionEvent_t)(HIORING, HANDLE);
|
||
typedef HRESULT(WINAPI *BuildIoRingCancelRequest_t)(HIORING, IORING_HANDLE_REF,
|
||
UINT_PTR, UINT_PTR);
|
||
typedef HRESULT(WINAPI *BuildIoRingReadFile_t)(HIORING, IORING_HANDLE_REF,
|
||
IORING_BUFFER_REF, UINT32,
|
||
UINT64, UINT_PTR,
|
||
IORING_SQE_FLAGS);
|
||
typedef HRESULT(WINAPI *BuildIoRingRegisterBuffers_t)(
|
||
HIORING, UINT32, IORING_BUFFER_INFO const[], UINT_PTR);
|
||
|
||
typedef HRESULT(WINAPI *BuildIoRingRegisterFileHandles_t)(HIORING, UINT32,
|
||
HANDLE const[],
|
||
UINT_PTR);
|
||
|
||
// Core:
|
||
// Queries the support of the specified operation for the specified I/O ring
|
||
static IsIoRingOpSupported_t IsIoRingOpSupported = NULL;
|
||
|
||
// Queries the OS for the supported capabilities for IORINGs
|
||
static QueryIoRingCapabilities_t QueryIoRingCapabilities = NULL;
|
||
|
||
// Gets information about the API version and queue sizes of an I/O ring
|
||
static GetIoRingInfo_t GetIoRingInfo = NULL;
|
||
|
||
// Creates a new instance of an I/O ring submission/completion queue pair and
|
||
// returns a handle for referencing the I/O ring
|
||
static CreateIoRing_t CreateIoRing = NULL;
|
||
|
||
// Closes an HIORING handle that was previously opened with a call to
|
||
// CreateIoRing
|
||
static CloseIoRing_t CloseIoRing = NULL;
|
||
|
||
// Submission / completion:
|
||
// Submits all constructed but not yet submitted entries to the kernel’s queue
|
||
// and optionally waits for a set of operations to complete
|
||
static SubmitIoRing_t SubmitIoRing = NULL;
|
||
|
||
// Pops a single entry from the completion queue, if one is available
|
||
static PopIoRingCompletion_t PopIoRingCompletion = NULL;
|
||
|
||
// Registers a completion queue event with an IORING
|
||
static SetIoRingCompletionEvent_t SetIoRingCompletionEvent = NULL;
|
||
|
||
// Operations:
|
||
// Performs an asynchronous read from a file using an I/O ring
|
||
static BuildIoRingReadFile_t BuildIoRingReadFile = NULL;
|
||
|
||
// Attempts to cancel a previously submitted I/O ring operation
|
||
static BuildIoRingCancelRequest_t BuildIoRingCancelRequest = NULL;
|
||
|
||
// Registers an array of buffers with the system for future I/O ring operations
|
||
static BuildIoRingRegisterBuffers_t BuildIoRingRegisterBuffers = NULL;
|
||
|
||
// Registers an array of file handles with the system for future I/O ring
|
||
// operations
|
||
static BuildIoRingRegisterFileHandles_t BuildIoRingRegisterFileHandles = NULL;
|
||
|
||
static int io_ring_loaded = 0;
|
||
|
||
static int io_ring_load_functions(void) {
|
||
if (io_ring_loaded)
|
||
return 1;
|
||
|
||
HMODULE hKernel = GetModuleHandleW(L"kernel32.dll");
|
||
if (!hKernel)
|
||
return 0;
|
||
|
||
IsIoRingOpSupported =
|
||
(IsIoRingOpSupported_t)GetProcAddress(hKernel, "IsIoRingOpSupported");
|
||
QueryIoRingCapabilities = (QueryIoRingCapabilities_t)GetProcAddress(
|
||
hKernel, "QueryIoRingCapabilities");
|
||
GetIoRingInfo = (GetIoRingInfo_t)GetProcAddress(hKernel, "GetIoRingInfo");
|
||
CreateIoRing = (CreateIoRing_t)GetProcAddress(hKernel, "CreateIoRing");
|
||
CloseIoRing = (CloseIoRing_t)GetProcAddress(hKernel, "CloseIoRing");
|
||
SubmitIoRing = (SubmitIoRing_t)GetProcAddress(hKernel, "SubmitIoRing");
|
||
PopIoRingCompletion =
|
||
(PopIoRingCompletion_t)GetProcAddress(hKernel, "PopIoRingCompletion");
|
||
SetIoRingCompletionEvent = (SetIoRingCompletionEvent_t)GetProcAddress(
|
||
hKernel, "SetIoRingCompletionEvent");
|
||
BuildIoRingReadFile =
|
||
(BuildIoRingReadFile_t)GetProcAddress(hKernel, "BuildIoRingReadFile");
|
||
BuildIoRingCancelRequest = (BuildIoRingCancelRequest_t)GetProcAddress(
|
||
hKernel, "BuildIoRingCancelRequest");
|
||
BuildIoRingRegisterBuffers = (BuildIoRingRegisterBuffers_t)GetProcAddress(
|
||
hKernel, "BuildIoRingRegisterBuffers");
|
||
BuildIoRingRegisterFileHandles =
|
||
(BuildIoRingRegisterFileHandles_t)GetProcAddress(
|
||
hKernel, "BuildIoRingRegisterFileHandles");
|
||
|
||
io_ring_loaded =
|
||
(IsIoRingOpSupported && QueryIoRingCapabilities && CreateIoRing &&
|
||
CloseIoRing && SubmitIoRing && PopIoRingCompletion &&
|
||
SetIoRingCompletionEvent && BuildIoRingReadFile &&
|
||
BuildIoRingCancelRequest && BuildIoRingRegisterBuffers &&
|
||
BuildIoRingRegisterFileHandles);
|
||
|
||
if (io_ring_loaded)
|
||
printf("[I/O Ring] Functions loaded\n");
|
||
else
|
||
printf("[I/O Ring] Some functions not available\n");
|
||
|
||
return io_ring_loaded;
|
||
}
|
||
|
||
/* ------------- Standard helper functions definition ------------- */
|
||
// Creates an instance of the IORING_BUFFER_REF structure with the provided
|
||
// buffer index and offset
|
||
static inline IORING_BUFFER_REF
|
||
IoRingBufferRefFromIndexAndOffset(UINT32 index, UINT32 offset) {
|
||
IORING_BUFFER_REF ref;
|
||
ref.Kind = IORING_REF_REGISTERED;
|
||
ref.BufferUnion.IndexAndOffset.Index = index;
|
||
ref.BufferUnion.IndexAndOffset.Offset = offset;
|
||
return ref;
|
||
}
|
||
|
||
// Creates an instance of the IORING_BUFFER_REF structure from the provided
|
||
// pointer
|
||
static IORING_BUFFER_REF IoRingBufferRefFromPointer(void *addr) {
|
||
IORING_BUFFER_REF ref;
|
||
ref.Kind = IORING_REF_RAW;
|
||
ref.BufferUnion.Address = addr;
|
||
return ref;
|
||
}
|
||
|
||
// Creates an instance of the IORING_HANDLE_REF structure from the provided file
|
||
// handle
|
||
static IORING_HANDLE_REF IoRingHandleRefFromHandle(HANDLE h) {
|
||
IORING_HANDLE_REF ref;
|
||
ref.Kind = IORING_REF_RAW;
|
||
ref.HandleUnion.Handle = h;
|
||
return ref;
|
||
}
|
||
|
||
// Creates an instance of the IORING_HANDLE_REF structure from the provided
|
||
// index
|
||
static inline IORING_HANDLE_REF IoRingHandleRefFromIndex(UINT32 index) {
|
||
IORING_HANDLE_REF ref;
|
||
ref.Kind = IORING_REF_REGISTERED; // MUST be registered
|
||
ref.HandleUnion.Index = index;
|
||
return ref;
|
||
}
|
||
|
||
// NOTE: If you are using index-based buffers or handles, make sure you have
|
||
// successfully called BuildIoRingRegisterBuffers or
|
||
// BuildIoRingRegisterFileHandles first so the kernel has a valid table to look
|
||
// into, otherwise the kernel will treat the index as an invalid memory
|
||
// address/handle.
|