introduce a stable NTL_DDK driver ABI to replace direct HAL_API and kernel-header access in drivers, add code/kernel/io_ddk.c and code/public/ntlite/ddk/ headers, change DriverEntry to take (const NTL_DDK*, NTL_DRIVER_INIT*), update kmain to build the DDK once via IoInitializeDdk/IoGetDdk and hand it to both boot and runtime drivers, downgrade code/public/ntlite/ddi/io_driver.h to a legacy I/O model header pulling from ntlite/ddk instead of kernel internals, move code/third_party/lwip into code/drivers/net/lwip/third_party, fix up lwip_sources.txt and build.c include paths to match, split build.c's single CFLAGS macro into COMMON/KERNEL/USER/BOOT/DRIVER cflags.
This commit is contained in:
1 parent
08329516ba
commit
485a6bbfe7
385 files changed
+1822
-1079
No files matched your search
@@ -3,61 +3,11 @@
|
||||
#pragma once
|
||||
// io_async.h - waitable asynchronous I/O request objects.
|
||||
// Async request objects own the common completion, APC, wait, query, and
|
||||
// cancellation surface used by file and socket I/O.
|
||||
// cancellation surface used by file and socket I/O. The shared request layout is
|
||||
// currently DDK-visible for legacy kernel-mode drivers; this private header owns
|
||||
// only the kernel implementation entry points.
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <kernel/ke_list.h>
|
||||
#include <kernel/ob_object.h>
|
||||
#include <ntlite/status.h>
|
||||
|
||||
struct EVENT;
|
||||
struct KAPC;
|
||||
struct IRP;
|
||||
typedef struct MM_LOCKED_USER_BUFFER MM_LOCKED_USER_BUFFER;
|
||||
|
||||
// Completion status visible to async callers.
|
||||
typedef struct IO_STATUS_BLOCK {
|
||||
volatile KSTATUS Status;
|
||||
volatile size_t Information;
|
||||
} IO_STATUS_BLOCK;
|
||||
|
||||
typedef enum IO_ASYNC_REQUEST_STATE {
|
||||
IoAsyncRequestQueued = 0,
|
||||
IoAsyncRequestRunning = 1,
|
||||
IoAsyncRequestCompleted = 2,
|
||||
IoAsyncRequestCancelled = 3,
|
||||
} IO_ASYNC_REQUEST_STATE;
|
||||
|
||||
typedef struct IO_ASYNC_REQUEST_OBJECT IO_ASYNC_REQUEST_OBJECT;
|
||||
|
||||
typedef void (*IO_ASYNC_REQUEST_CLEANUP_ROUTINE)(IO_ASYNC_REQUEST_OBJECT* request,
|
||||
void* context);
|
||||
typedef KSTATUS (*IO_ASYNC_REQUEST_CANCEL_ROUTINE)(IO_ASYNC_REQUEST_OBJECT* request,
|
||||
void* context);
|
||||
|
||||
// Common waitable async I/O request object.
|
||||
struct IO_ASYNC_REQUEST_OBJECT {
|
||||
OBJECT Header;
|
||||
LIST_ENTRY Link;
|
||||
|
||||
IO_ASYNC_REQUEST_STATE State;
|
||||
uint8_t CancelRequested;
|
||||
|
||||
struct EVENT* WaitEvent;
|
||||
struct EVENT* CompletionEvent;
|
||||
struct KAPC* CompletionApc;
|
||||
IO_STATUS_BLOCK* Iosb;
|
||||
IO_STATUS_BLOCK IosbSnapshot;
|
||||
MM_LOCKED_USER_BUFFER* LockedBuffer;
|
||||
MM_LOCKED_USER_BUFFER* LockedIosb;
|
||||
struct IRP* Irp;
|
||||
|
||||
IO_ASYNC_REQUEST_CLEANUP_ROUTINE CleanupRoutine;
|
||||
void* CleanupContext;
|
||||
IO_ASYNC_REQUEST_CANCEL_ROUTINE CancelRoutine;
|
||||
void* CancelContext;
|
||||
};
|
||||
#include <ntlite/ddk/async.h>
|
||||
|
||||
__declspec(dllexport) KSTATUS IoCreateAsyncRequest(size_t objectSize,
|
||||
IO_ASYNC_REQUEST_CLEANUP_ROUTINE cleanupRoutine,
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
// Kernel DDK-table provider declarations.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ntlite/ddk/ddk.h>
|
||||
|
||||
struct HAL_API;
|
||||
typedef struct HAL_API HAL_API;
|
||||
|
||||
// Initializes the kernel-owned DDK table from platform services.
|
||||
void IoInitializeDdk(const HAL_API* hal);
|
||||
|
||||
// Returns the kernel-owned DDK table passed to driver entrypoints.
|
||||
const NTL_DDK* IoGetDdk(void);
|
||||
@@ -1,240 +1,53 @@
|
||||
// Kernel io file declarations shared by implementation files and kernel clients.
|
||||
// Kernel I/O file declarations shared by filesystem, cache, and syscall code.
|
||||
|
||||
#pragma once
|
||||
// io_file.h - VFS layer
|
||||
// Filesystem drivers register an IO_FILESYSTEM vtable via IoRegisterFilesystem.
|
||||
// Kernel and user code open files through IoOpenFile.
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <ntlite/status.h>
|
||||
#include <kernel/ob_object.h>
|
||||
#include <kernel/ke_spinlock.h>
|
||||
// io_file.h - VFS and filesystem provider interface.
|
||||
// Current kernel-mode filesystem drivers still use the legacy file-provider
|
||||
// layout. The shared declarations live in the DDK while the real provider split
|
||||
// is being designed; this private header adds kernel-only async and lock entry
|
||||
// points without redefining the shared types.
|
||||
|
||||
#include <ntlite/ddk/file.h>
|
||||
#include <kernel/io_async.h>
|
||||
#include <ntlite/string_view.h>
|
||||
#include <ntlite/dirent.h>
|
||||
#include <ntlite/file_stat.h>
|
||||
|
||||
// Kernel/filesystem code uses the public directory-entry ABI directly.
|
||||
typedef SYS_DIR_ENTRY KDIR_ENTRY;
|
||||
#define KDIR_NAME_MAX SYS_DIR_NAME_MAX
|
||||
struct PROCESS;
|
||||
|
||||
// Native asynchronous filesystem completion. Filesystems that provide
|
||||
// ReadAsync/WriteAsync accept the operation, return NTLSTATUS_PENDING, and later
|
||||
// call Complete(CompleteContext, status, information). Filesystems without
|
||||
// these callbacks fall back to the generic VFS async worker.
|
||||
typedef void (*IO_FS_ASYNC_COMPLETE)(void* completeContext,
|
||||
KSTATUS status,
|
||||
size_t information);
|
||||
|
||||
// Filesystem-level cache and traversal statistics.
|
||||
// Drivers map private metadata work onto these generic counters.
|
||||
typedef struct IO_FILESYSTEM_STATS {
|
||||
uint64_t PathLookups;
|
||||
uint64_t PathCacheHits;
|
||||
uint64_t PathCacheMisses;
|
||||
uint64_t PathCacheStores;
|
||||
uint64_t PathCacheInvalidations;
|
||||
uint64_t PathCacheGeneration;
|
||||
uint64_t DirectorySearches;
|
||||
uint64_t DirectoryBlocksRead;
|
||||
uint64_t DirectoryEntriesScanned;
|
||||
uint64_t DataReadRuns;
|
||||
uint64_t DataReadSectors;
|
||||
uint64_t DataReadRunMerges;
|
||||
uint64_t MaxDataReadSpanSectors;
|
||||
} IO_FILESYSTEM_STATS;
|
||||
|
||||
// Stable identity for a file on a mounted filesystem.
|
||||
// Filesystems that can provide this let higher layers cache file-backed
|
||||
// objects by file identity instead of by one FILE_OBJECT instance.
|
||||
typedef struct IO_FILE_IDENTITY {
|
||||
uint64_t VolumeId;
|
||||
uint64_t FileId;
|
||||
uint64_t Generation;
|
||||
uint64_t Size;
|
||||
} IO_FILE_IDENTITY;
|
||||
|
||||
// Filesystem driver vtable - filled in by a filesystem driver.
|
||||
typedef struct IO_FILESYSTEM {
|
||||
// Open a file by absolute path (e.g. "apps\\shell.exe").
|
||||
// Returns an opaque per-file driver cookie in* fileCtx.
|
||||
KSTATUS (*Open)(struct IO_FILESYSTEM* fs,
|
||||
SYS_STRING_VIEW path, void **fileCtx);
|
||||
|
||||
// Read up to 'size' bytes at 'offset' into 'buf'.
|
||||
// Sets* bytesRead to actual bytes copied.
|
||||
KSTATUS (*Read)(struct IO_FILESYSTEM* fs, void* fileCtx,
|
||||
uint64_t offset, void* buf,
|
||||
size_t size, size_t* bytesRead);
|
||||
|
||||
KSTATUS (*Write)(struct IO_FILESYSTEM* fs, void* fileCtx,
|
||||
uint64_t offset, const void* buf,
|
||||
size_t size, size_t* bytesWritten);
|
||||
|
||||
KSTATUS (*ReadAsync)(struct IO_FILESYSTEM* fs, void* fileCtx,
|
||||
uint64_t offset, void* buf, size_t size,
|
||||
IO_FS_ASYNC_COMPLETE complete,
|
||||
void* completeContext);
|
||||
|
||||
KSTATUS (*WriteAsync)(struct IO_FILESYSTEM* fs, void* fileCtx,
|
||||
uint64_t offset, const void* buf, size_t size,
|
||||
IO_FS_ASYNC_COMPLETE complete,
|
||||
void* completeContext);
|
||||
|
||||
// Create a new file at 'path'; returns an open fileCtx on success.
|
||||
KSTATUS (*Create)(struct IO_FILESYSTEM* fs, SYS_STRING_VIEW path,
|
||||
void** fileCtx);
|
||||
|
||||
// Delete the file at 'path'.
|
||||
KSTATUS (*Delete)(struct IO_FILESYSTEM* fs, SYS_STRING_VIEW path);
|
||||
|
||||
// Rename or move a file/directory within the same filesystem.
|
||||
KSTATUS (*Rename)(struct IO_FILESYSTEM* fs,
|
||||
SYS_STRING_VIEW oldPath, SYS_STRING_VIEW newPath);
|
||||
|
||||
// Create or remove directories.
|
||||
KSTATUS (*CreateDir)(struct IO_FILESYSTEM* fs, SYS_STRING_VIEW path);
|
||||
KSTATUS (*RemoveDir)(struct IO_FILESYSTEM* fs, SYS_STRING_VIEW path);
|
||||
|
||||
// Truncate or extend the file to exactly 'newSize' bytes.
|
||||
KSTATUS (*Truncate)(struct IO_FILESYSTEM* fs, void* fileCtx,
|
||||
uint64_t newSize, uint32_t fileFlags);
|
||||
|
||||
// Return the file size in bytes.
|
||||
uint64_t (*GetSize)(struct IO_FILESYSTEM* fs, void* fileCtx);
|
||||
|
||||
// Query metadata for an open file or path.
|
||||
KSTATUS (*QueryInfo)(struct IO_FILESYSTEM* fs, void* fileCtx,
|
||||
SYS_FILE_STAT* out);
|
||||
KSTATUS (*Stat)(struct IO_FILESYSTEM* fs, SYS_STRING_VIEW path,
|
||||
SYS_FILE_STAT* out);
|
||||
|
||||
// Return a stable file identity for caches that outlive one open handle.
|
||||
KSTATUS (*QueryIdentity)(struct IO_FILESYSTEM* fs, void* fileCtx,
|
||||
IO_FILE_IDENTITY* out);
|
||||
|
||||
// Release any resources the driver allocated for fileCtx.
|
||||
void (*Close)(struct IO_FILESYSTEM* fs, void* fileCtx);
|
||||
|
||||
// Query cache and traversal statistics exposed through kernel stats.
|
||||
void (*QueryStats)(struct IO_FILESYSTEM* fs, IO_FILESYSTEM_STATS* out);
|
||||
|
||||
// Optional driver-private data.
|
||||
void* DriverCtx;
|
||||
|
||||
// Open a directory iterator for 'dirPath' (relative or drive-prefixed).
|
||||
// Returns an opaque per-iteration driver cookie in *dirCtx.
|
||||
KSTATUS (*OpenDir)(struct IO_FILESYSTEM* fs,
|
||||
SYS_STRING_VIEW dirPath, void** dirCtx);
|
||||
|
||||
// Advance to the next entry.
|
||||
// Fills 'out' with name, attributes, and size.
|
||||
// Returns NTLSTATUS_NO_MORE_FILES when the directory is exhausted.
|
||||
KSTATUS (*ReadDir)(struct IO_FILESYSTEM* fs, void* dirCtx,
|
||||
KDIR_ENTRY* out);
|
||||
|
||||
// Release resources allocated by OpenDir.
|
||||
void (*CloseDir)(struct IO_FILESYSTEM* fs, void* dirCtx);
|
||||
} IO_FILESYSTEM;
|
||||
|
||||
struct EVENT;
|
||||
struct KAPC;
|
||||
typedef struct MM_LOCKED_USER_BUFFER MM_LOCKED_USER_BUFFER;
|
||||
typedef struct IO_ASYNC_FILE_REQUEST_OBJECT IO_ASYNC_FILE_REQUEST_OBJECT;
|
||||
|
||||
// FILE_OBJECT - the kernel object returned to callers.
|
||||
#define IO_FILE_FLAG_NO_CACHE 0x00000001u
|
||||
#define IO_FILE_FLAG_SKIP_ZERO_EXTEND 0x00000002u
|
||||
#define IO_FILE_FLAG_APPEND 0x00000004u
|
||||
|
||||
typedef struct FILE_OBJECT {
|
||||
OBJECT Header; // must be first
|
||||
IO_FILESYSTEM* Fs;
|
||||
void* FileCtx; // driver cookie
|
||||
SPINLOCK Lock; // protects cached Size/Offset updates
|
||||
uint64_t Size;
|
||||
uint64_t Offset; // current position for sequential reads
|
||||
uint32_t Flags; // IO_FILE_FLAG_*
|
||||
uint32_t ReadaheadScore;
|
||||
uint64_t ReadaheadNextOffset;
|
||||
uint64_t ReadaheadIssuedUntil;
|
||||
uint64_t ReadaheadSuppressedUntil;
|
||||
} FILE_OBJECT;
|
||||
|
||||
// DIR_OBJECT - kernel object for an open directory iterator.
|
||||
typedef struct DIR_OBJECT {
|
||||
OBJECT Header; // must be first
|
||||
IO_FILESYSTEM* Fs;
|
||||
void* DirCtx; // driver cookie (opaque iteration state)
|
||||
} DIR_OBJECT;
|
||||
|
||||
typedef struct IO_VOLUME_PARAMS {
|
||||
uint8_t DiskIndex; // registered disk DEVICE_OBJECT index
|
||||
uint64_t PartitionLba; // starting LBA of this partition
|
||||
uint64_t PartitionSize; // sectors, for bounds checking
|
||||
} IO_VOLUME_PARAMS;
|
||||
|
||||
// Registration - called by fat32.sys from DriverEntry
|
||||
// driveIndex matches the index passed to IoRegisterDiskDevice.
|
||||
__declspec(dllexport) KSTATUS IoRegisterFilesystem(uint8_t driveIndex, IO_FILESYSTEM* fs, const IO_VOLUME_PARAMS *vol);
|
||||
__declspec(dllexport) KSTATUS IoUnregisterFilesystem(uint8_t driveIndex);
|
||||
__declspec(dllexport) KSTATUS IoUnregisterFilesystemsForDisk(uint8_t diskIndex);
|
||||
__declspec(dllexport) bool IoFilesystemPresent(uint8_t driveIndex);
|
||||
__declspec(dllexport) void IoQueryFilesystemStats(IO_FILESYSTEM_STATS* out);
|
||||
|
||||
// Kernel-side API.
|
||||
__declspec(dllexport) KSTATUS IoOpenFile(SYS_STRING_VIEW path, FILE_OBJECT **out);
|
||||
__declspec(dllexport) KSTATUS IoReadFile(FILE_OBJECT* file, void* buf,
|
||||
size_t size, size_t* bytesRead);
|
||||
__declspec(dllexport) KSTATUS IoReadFileAt(FILE_OBJECT* file, uint64_t offset,
|
||||
void* buf, size_t size, size_t* bytesRead);
|
||||
__declspec(dllexport) KSTATUS IoWriteFile (FILE_OBJECT* file, const void* buf,
|
||||
size_t size, size_t* bytesWritten);
|
||||
__declspec(dllexport) KSTATUS IoWriteFileAt(FILE_OBJECT* file, uint64_t offset,
|
||||
const void* buf, size_t size,
|
||||
size_t* bytesWritten);
|
||||
__declspec(dllexport) KSTATUS IoFlushFile(FILE_OBJECT* file);
|
||||
__declspec(dllexport) KSTATUS IoReadFileAsyncKernel(FILE_OBJECT* file, void* buf,
|
||||
size_t size, uint64_t offset, IO_STATUS_BLOCK* iosb,
|
||||
struct EVENT* completionEvent, struct KAPC* completionApc,
|
||||
MM_LOCKED_USER_BUFFER* lockedBuffer,
|
||||
MM_LOCKED_USER_BUFFER* lockedIosb,
|
||||
IO_ASYNC_FILE_REQUEST_OBJECT** requestOut);
|
||||
__declspec(dllexport) KSTATUS IoWriteFileAsyncKernel(FILE_OBJECT* file, const void* buf,
|
||||
size_t size, uint64_t offset, IO_STATUS_BLOCK* iosb,
|
||||
struct EVENT* completionEvent, struct KAPC* completionApc,
|
||||
MM_LOCKED_USER_BUFFER* lockedBuffer,
|
||||
MM_LOCKED_USER_BUFFER* lockedIosb,
|
||||
IO_ASYNC_FILE_REQUEST_OBJECT** requestOut);
|
||||
__declspec(dllexport) OBJECT* IoAsyncFileRequestObject(IO_ASYNC_FILE_REQUEST_OBJECT* request);
|
||||
__declspec(dllexport) KSTATUS IoWaitAsyncFileRequest(IO_ASYNC_FILE_REQUEST_OBJECT* request,
|
||||
uint32_t flags);
|
||||
__declspec(dllexport) KSTATUS IoReadFileAsyncKernel(FILE_OBJECT* file,
|
||||
void* buf,
|
||||
size_t size,
|
||||
uint64_t offset,
|
||||
IO_STATUS_BLOCK* iosb,
|
||||
struct EVENT* completionEvent,
|
||||
struct KAPC* completionApc,
|
||||
MM_LOCKED_USER_BUFFER* lockedBuffer,
|
||||
MM_LOCKED_USER_BUFFER* lockedIosb,
|
||||
IO_ASYNC_FILE_REQUEST_OBJECT** requestOut);
|
||||
__declspec(dllexport) KSTATUS IoWriteFileAsyncKernel(FILE_OBJECT* file,
|
||||
const void* buf,
|
||||
size_t size,
|
||||
uint64_t offset,
|
||||
IO_STATUS_BLOCK* iosb,
|
||||
struct EVENT* completionEvent,
|
||||
struct KAPC* completionApc,
|
||||
MM_LOCKED_USER_BUFFER* lockedBuffer,
|
||||
MM_LOCKED_USER_BUFFER* lockedIosb,
|
||||
IO_ASYNC_FILE_REQUEST_OBJECT** requestOut);
|
||||
__declspec(dllexport) OBJECT* IoAsyncFileRequestObject(IO_ASYNC_FILE_REQUEST_OBJECT* request);
|
||||
__declspec(dllexport) KSTATUS IoWaitAsyncFileRequest(IO_ASYNC_FILE_REQUEST_OBJECT* request,
|
||||
uint32_t flags);
|
||||
__declspec(dllexport) struct EVENT* IoGetAsyncFileRequestWaitEvent(IO_ASYNC_FILE_REQUEST_OBJECT* request);
|
||||
__declspec(dllexport) KSTATUS IoCancelAsyncFileRequest(IO_ASYNC_FILE_REQUEST_OBJECT* request);
|
||||
__declspec(dllexport) KSTATUS IoQueryAsyncFileRequest(IO_ASYNC_FILE_REQUEST_OBJECT* request,
|
||||
IO_STATUS_BLOCK* iosbOut);
|
||||
__declspec(dllexport) KSTATUS IoCreateFile (SYS_STRING_VIEW path, FILE_OBJECT** out);
|
||||
__declspec(dllexport) KSTATUS IoDeleteFile (SYS_STRING_VIEW path);
|
||||
__declspec(dllexport) KSTATUS IoRenameFile (SYS_STRING_VIEW oldPath, SYS_STRING_VIEW newPath);
|
||||
__declspec(dllexport) KSTATUS IoCreateDir (SYS_STRING_VIEW path);
|
||||
__declspec(dllexport) KSTATUS IoRemoveDir (SYS_STRING_VIEW path);
|
||||
__declspec(dllexport) KSTATUS IoTruncateFile(FILE_OBJECT* file, uint64_t newSize);
|
||||
__declspec(dllexport) KSTATUS IoSeekFile(FILE_OBJECT* file, uint64_t offset);
|
||||
__declspec(dllexport) uint64_t IoGetFileSize(FILE_OBJECT* file);
|
||||
__declspec(dllexport) KSTATUS IoGetFileStat(FILE_OBJECT* file, SYS_FILE_STAT* out);
|
||||
__declspec(dllexport) KSTATUS IoStatFile(SYS_STRING_VIEW path, SYS_FILE_STAT* out);
|
||||
__declspec(dllexport) KSTATUS IoQueryFileIdentity(FILE_OBJECT* file, IO_FILE_IDENTITY* out);
|
||||
__declspec(dllexport) KSTATUS IoLockFile(FILE_OBJECT* file, struct PROCESS* owner, uint32_t mode, uint64_t offset, uint64_t length, uint64_t timeoutMilliseconds);
|
||||
__declspec(dllexport) KSTATUS IoUnlockFile(FILE_OBJECT* file, struct PROCESS* owner, uint64_t offset, uint64_t length);
|
||||
__declspec(dllexport) void IoReleaseFileLocksForProcess(struct PROCESS* owner);
|
||||
__declspec(dllexport) void IoCloseFile(FILE_OBJECT* file);
|
||||
__declspec(dllexport) KSTATUS IoCancelAsyncFileRequest(IO_ASYNC_FILE_REQUEST_OBJECT* request);
|
||||
__declspec(dllexport) KSTATUS IoQueryAsyncFileRequest(IO_ASYNC_FILE_REQUEST_OBJECT* request,
|
||||
IO_STATUS_BLOCK* iosbOut);
|
||||
|
||||
// Directory enumeration API.
|
||||
__declspec(dllexport) KSTATUS IoOpenDir (SYS_STRING_VIEW dirPath, DIR_OBJECT** out);
|
||||
__declspec(dllexport) KSTATUS IoReadDir (DIR_OBJECT* dir, KDIR_ENTRY* entryOut);
|
||||
__declspec(dllexport) void IoCloseDir(DIR_OBJECT* dir);
|
||||
|
||||
// Current Working Directory.
|
||||
__declspec(dllexport) KSTATUS IoSetCwd(SYS_STRING_VIEW path);
|
||||
__declspec(dllexport) KSTATUS IoRealPath(SYS_STRING_VIEW path, char* buffer, size_t bufferSize, size_t* requiredSizeOut);
|
||||
__declspec(dllexport) KSTATUS IoLockFile(FILE_OBJECT* file,
|
||||
struct PROCESS* owner,
|
||||
uint32_t mode,
|
||||
uint64_t offset,
|
||||
uint64_t length,
|
||||
uint64_t timeoutMilliseconds);
|
||||
__declspec(dllexport) KSTATUS IoUnlockFile(FILE_OBJECT* file,
|
||||
struct PROCESS* owner,
|
||||
uint64_t offset,
|
||||
uint64_t length);
|
||||
__declspec(dllexport) void IoReleaseFileLocksForProcess(struct PROCESS* owner);
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <ntlite/status.h>
|
||||
#include <ntlite/string_view.h>
|
||||
#include <ntlite/ddi/hal_api.h>
|
||||
#include <ntlite/ddk/debug.h>
|
||||
|
||||
#define KE_DEBUG_CONSOLE 0x00000001u
|
||||
#define KE_DEBUG_SELFTEST 0x00000002u
|
||||
@@ -29,17 +30,6 @@ __declspec(dllexport) void DbgPrint(const char* fmt, ...);
|
||||
__declspec(dllexport) void KePrintConsole(const char* buf, size_t len);
|
||||
__declspec(dllexport) KSTATUS KeFlushDebugLogToFile(SYS_STRING_VIEW path);
|
||||
|
||||
typedef enum KE_PANIC_CODE {
|
||||
KE_PANIC_CODE_GENERIC = 0,
|
||||
KE_PANIC_CODE_FAULT = 1,
|
||||
KE_PANIC_CODE_IRQL = 2,
|
||||
KE_PANIC_CODE_SELFTEST = 3,
|
||||
KE_PANIC_CODE_TRAP = 4,
|
||||
KE_PANIC_CODE_DRIVER = 5,
|
||||
KE_PANIC_CODE_INIT = 6,
|
||||
KE_PANIC_CODE_SCHEDULER= 7,
|
||||
} KE_PANIC_CODE;
|
||||
|
||||
__declspec(dllexport) _Noreturn void KePanic(int code, const char* fmt, ...);
|
||||
__declspec(dllexport) int KeHandleNmiIpi(void);
|
||||
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
// Kernel ke display declarations shared by implementation files and kernel clients.
|
||||
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <ntlite/status.h>
|
||||
#include <ntlite/ddi/hal_api.h>
|
||||
|
||||
#ifndef DISPLAY_API
|
||||
@@ -14,50 +10,7 @@
|
||||
#define DISPLAY_API __declspec(dllimport)
|
||||
#endif
|
||||
#endif
|
||||
#include <ntlite/ddi/display.h>
|
||||
|
||||
typedef struct KE_CONSOLE_INFO {
|
||||
uint32_t Columns;
|
||||
uint32_t Rows;
|
||||
uint32_t CursorX;
|
||||
uint32_t CursorY;
|
||||
uint16_t Attribute;
|
||||
} KE_CONSOLE_INFO;
|
||||
|
||||
typedef struct KE_DISPLAY_INFO {
|
||||
char PrimaryName[32];
|
||||
DISPLAY_MODE Mode;
|
||||
uint32_t Caps;
|
||||
uint32_t DeviceCount;
|
||||
DISPLAY_STATS ManagerStats;
|
||||
DISPLAY_STATS DeviceStats;
|
||||
} KE_DISPLAY_INFO;
|
||||
#include <ntlite/ddk/display.h>
|
||||
|
||||
void KeDisplayInitialize(const HAL_API* hal);
|
||||
|
||||
DISPLAY_API KSTATUS KeDisplayRegisterDevice(DISPLAY_DEVICE* device);
|
||||
DISPLAY_API KSTATUS KeDisplaySetPrimary(DISPLAY_DEVICE* device);
|
||||
DISPLAY_API void KeDisplaySuspendConsole(bool suspend);
|
||||
|
||||
DISPLAY_API KSTATUS KeDisplayGetMode(DISPLAY_MODE* outMode);
|
||||
DISPLAY_API KSTATUS KeDisplayGetSize(int* outWidth, int* outHeight);
|
||||
typedef KSTATUS (*KE_DISPLAY_ROW_SOURCE)(void* context, int rowIndex, uint32_t* scratch, size_t pixelCount);
|
||||
DISPLAY_API KSTATUS KeDisplayBlit(int x, int y, int w, int h, const uint32_t* pixels);
|
||||
DISPLAY_API KSTATUS KeDisplayBlitRows(int x, int y, int w, int h, KE_DISPLAY_ROW_SOURCE source, void* context, uint32_t* scratch);
|
||||
DISPLAY_API KSTATUS KeDisplayFillRect(int x, int y, int w, int h, uint32_t color);
|
||||
DISPLAY_API KSTATUS KeDisplayClear(uint32_t color);
|
||||
DISPLAY_API KSTATUS KeDisplayCopyRect(int dstX, int dstY, int srcX, int srcY, int w, int h);
|
||||
DISPLAY_API KSTATUS KeDisplayScroll(int lines);
|
||||
DISPLAY_API KSTATUS KeDisplayPutChar(char c, int x, int y, uint32_t fg, uint32_t bg);
|
||||
DISPLAY_API KSTATUS KeDisplayPrintChar(char c, uint32_t fg, uint32_t bg);
|
||||
DISPLAY_API KSTATUS KeDisplayGetConsoleInfo(KE_CONSOLE_INFO* outInfo);
|
||||
DISPLAY_API KSTATUS KeDisplaySetConsoleCursor(int col, int row);
|
||||
DISPLAY_API KSTATUS KeDisplayFillConsoleChars(char c, int col, int row, size_t length, size_t* writtenOut);
|
||||
DISPLAY_API KSTATUS KeDisplayFillConsoleAttrs(uint16_t attr, int col, int row, size_t length, size_t* writtenOut);
|
||||
DISPLAY_API KSTATUS KeDisplayPresent(const DISPLAY_RECT* rects, size_t rectCount);
|
||||
DISPLAY_API KSTATUS KeDisplaySync(void);
|
||||
DISPLAY_API KSTATUS KeDisplayQueryInfo(KE_DISPLAY_INFO* outInfo);
|
||||
|
||||
DISPLAY_API KSTATUS KeDisplaySetCursorImage(int width, int height, int hotX, int hotY, const uint32_t* argbPixels);
|
||||
DISPLAY_API KSTATUS KeDisplaySetCursorPosition(int x, int y);
|
||||
DISPLAY_API KSTATUS KeDisplayShowCursor(bool show);
|
||||
@@ -1,46 +1,16 @@
|
||||
// Kernel ke dpc declarations shared by implementation files and kernel clients.
|
||||
|
||||
#pragma once
|
||||
// ke_dpc.h - deferred procedure calls
|
||||
|
||||
// ke_dpc.h - deferred procedure calls.
|
||||
// DPCs are the kernel's bottom-half mechanism. Hardware ISRs can queue a DPC
|
||||
// after acknowledging/capturing device state; the DPC then runs later at
|
||||
// DISPATCH_LEVEL from the common interrupt-exit path. DPC routines must not
|
||||
// wait, block, or call PASSIVE_LEVEL-only code.
|
||||
// DISPATCH_LEVEL from the common interrupt-exit path. The legacy storage layout
|
||||
// is DDK-visible while kernel-mode drivers are being moved behind the real DDK.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <kernel/ke_list.h>
|
||||
#include <kernel/ke_spinlock.h>
|
||||
|
||||
typedef struct KDPC KDPC;
|
||||
|
||||
typedef void (*KDEFERRED_ROUTINE)(KDPC* dpc,
|
||||
void* context,
|
||||
void* systemArgument1,
|
||||
void* systemArgument2);
|
||||
|
||||
struct KDPC {
|
||||
LIST_ENTRY Link;
|
||||
KDEFERRED_ROUTINE Routine;
|
||||
void* Context;
|
||||
void* SystemArgument1;
|
||||
void* SystemArgument2;
|
||||
volatile long Inserted;
|
||||
};
|
||||
#include <ntlite/ddk/dpc.h>
|
||||
|
||||
// Called during kernel bring-up before interrupts are enabled.
|
||||
void KeInitializeDpcSystem(void);
|
||||
|
||||
__declspec(dllexport) void KeInitializeDpc(KDPC* dpc,
|
||||
KDEFERRED_ROUTINE routine,
|
||||
void* context);
|
||||
|
||||
// Queue a DPC if it is not already queued. Returns false if the DPC was
|
||||
// already pending or the arguments are invalid.
|
||||
__declspec(dllexport) bool KeInsertQueueDpc(KDPC* dpc,
|
||||
void* systemArgument1,
|
||||
void* systemArgument2);
|
||||
|
||||
// Internal: drain queued DPCs at DISPATCH_LEVEL. Called from interrupt exit.
|
||||
void KiDrainDpcQueue(void);
|
||||
@@ -2,26 +2,7 @@
|
||||
|
||||
#pragma once
|
||||
// ke_event.h - auto-reset and manual-reset events.
|
||||
#include <stdint.h>
|
||||
#include <kernel/ob_object.h>
|
||||
#include <kernel/ke_spinlock.h>
|
||||
#include <kernel/ke_list.h>
|
||||
#include <ntlite/status.h>
|
||||
// Event layout is DDK-visible during the legacy driver cleanup. This private
|
||||
// header intentionally reuses the shared declaration instead of redefining it.
|
||||
|
||||
typedef enum EVENT_TYPE { EventAutoReset, EventManualReset } EVENT_TYPE;
|
||||
|
||||
typedef struct EVENT {
|
||||
OBJECT Header;
|
||||
SPINLOCK Lock;
|
||||
EVENT_TYPE Type;
|
||||
uint32_t Signaled;
|
||||
LIST_ENTRY WaitList;
|
||||
LIST_ENTRY MultiWaitList;
|
||||
} EVENT;
|
||||
|
||||
__declspec(dllexport) KSTATUS KeEventCreate(EVENT_TYPE type, uint32_t initialState, EVENT **out);
|
||||
__declspec(dllexport) void KeSignalEvent(EVENT* event);
|
||||
__declspec(dllexport) void KeClearEvent(EVENT* event);
|
||||
__declspec(dllexport) KSTATUS KeWaitForEvent(EVENT* event, uint8_t alertable);
|
||||
__declspec(dllexport) KSTATUS KeTryWaitEvent(EVENT* event);
|
||||
__declspec(dllexport) KSTATUS KeWaitForMultipleEvents(EVENT** events, uint32_t count, uint8_t alertable, uint64_t timeoutMs, uint32_t* signaledIndexOut);
|
||||
#include <ntlite/ddk/event.h>
|
||||
@@ -1,200 +1,8 @@
|
||||
// Kernel ke irp declarations shared by implementation files and kernel clients.
|
||||
|
||||
#pragma once
|
||||
// ke_irp.h - I/O Request Packet and remove-lock primitives
|
||||
|
||||
// IRPs are stack-based. A caller builds an IRP with one or more
|
||||
// IO_STACK_LOCATION entries, submits it to a DEVICE_OBJECT, and the I/O
|
||||
// manager/driver stack advances CurrentLocation as the IRP is forwarded.
|
||||
// ke_irp.h - kernel-private include path for the current IRP API.
|
||||
// The legacy layout is DDK-visible until the opaque IRP accessor work lands.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <kernel/ke_list.h>
|
||||
#include <kernel/ke_spinlock.h>
|
||||
#include <kernel/ke_irql.h>
|
||||
#include <ntlite/status.h>
|
||||
|
||||
struct EVENT;
|
||||
struct SEMAPHORE;
|
||||
struct KAPC;
|
||||
typedef struct DEVICE_OBJECT DEVICE_OBJECT;
|
||||
|
||||
// IRP major/minor functions.
|
||||
|
||||
typedef enum IO_MAJOR_FUNCTION {
|
||||
IRP_MJ_CREATE = 0,
|
||||
IRP_MJ_CLOSE = 1,
|
||||
IRP_MJ_READ = 2,
|
||||
IRP_MJ_WRITE = 3,
|
||||
IRP_MJ_DEVICE_CONTROL = 4,
|
||||
IRP_MJ_INTERNAL_DEVICE_CONTROL = 5,
|
||||
IRP_MJ_PNP = 6,
|
||||
IRP_MJ_POWER = 7,
|
||||
IRP_MJ_MAXIMUM_FUNCTION = 8,
|
||||
} IO_MAJOR_FUNCTION;
|
||||
|
||||
typedef enum IO_PNP_MINOR_FUNCTION {
|
||||
IRP_MN_START_DEVICE = 0,
|
||||
IRP_MN_QUERY_REMOVE_DEVICE = 1,
|
||||
IRP_MN_CANCEL_REMOVE_DEVICE = 2,
|
||||
IRP_MN_SURPRISE_REMOVAL = 3,
|
||||
IRP_MN_REMOVE_DEVICE = 4,
|
||||
IRP_MN_QUERY_DEVICE_RELATIONS = 5,
|
||||
IRP_MN_QUERY_ID = 6,
|
||||
IRP_MN_QUERY_CAPABILITIES = 7,
|
||||
} IO_PNP_MINOR_FUNCTION;
|
||||
|
||||
typedef enum IO_DEVICE_RELATION_TYPE {
|
||||
IoBusRelations = 0,
|
||||
IoRemovalRelations = 1,
|
||||
} IO_DEVICE_RELATION_TYPE;
|
||||
|
||||
// IRP flags.
|
||||
|
||||
#define IRP_FLAG_PRIORITY (1u << 0) // insert at head of a driver queue
|
||||
#define IRP_FLAG_CANCELLED (1u << 1)
|
||||
#define IRP_FLAG_COMPLETED (1u << 2)
|
||||
|
||||
// IRP stack parameters.
|
||||
|
||||
typedef struct IO_STACK_LOCATION {
|
||||
IO_MAJOR_FUNCTION MajorFunction;
|
||||
uint8_t MinorFunction;
|
||||
DEVICE_OBJECT* DeviceObject;
|
||||
|
||||
union {
|
||||
struct {
|
||||
uint64_t ByteOffset;
|
||||
uint32_t Length;
|
||||
} ReadWrite;
|
||||
|
||||
struct {
|
||||
uint32_t IoControlCode;
|
||||
void* InputBuffer;
|
||||
uint32_t InputLength;
|
||||
void* OutputBuffer;
|
||||
uint32_t OutputLength;
|
||||
} DeviceIoControl;
|
||||
|
||||
struct {
|
||||
IO_DEVICE_RELATION_TYPE RelationType;
|
||||
} QueryDeviceRelations;
|
||||
|
||||
struct {
|
||||
uint32_t IdType;
|
||||
} QueryId;
|
||||
} Parameters;
|
||||
} IO_STACK_LOCATION;
|
||||
|
||||
// Forward declaration / callbacks.
|
||||
|
||||
typedef struct IRP IRP;
|
||||
|
||||
typedef void (*IRP_COMPLETION_FN)(IRP* irp, void* ctx);
|
||||
typedef void (*IRP_CANCEL_ROUTINE)(DEVICE_OBJECT* device, IRP* irp);
|
||||
|
||||
// I/O Request Packet.
|
||||
|
||||
typedef struct IRP {
|
||||
LIST_ENTRY Link;
|
||||
|
||||
volatile KSTATUS Status;
|
||||
volatile size_t Information;
|
||||
|
||||
uint32_t Flags;
|
||||
volatile bool Cancel;
|
||||
SPINLOCK CancelLock;
|
||||
KIRQL CancelIrql;
|
||||
IRP_CANCEL_ROUTINE CancelRoutine;
|
||||
|
||||
struct EVENT* CompletionEvent;
|
||||
struct KAPC* CompletionApc;
|
||||
IRP_COMPLETION_FN CompletionFn;
|
||||
void* CompletionCtx;
|
||||
|
||||
void* UserBuffer;
|
||||
void* SystemBuffer;
|
||||
|
||||
uint8_t StackCount;
|
||||
uint8_t CurrentLocation;
|
||||
|
||||
// Driver-owned scratch fields. They are deliberately not interpreted by
|
||||
// the I/O manager and are preserved across queueing/completion.
|
||||
uint8_t HwSlot;
|
||||
void* DriverCtx;
|
||||
|
||||
IO_STACK_LOCATION Stack[1];
|
||||
} IRP;
|
||||
|
||||
// Remove lock.
|
||||
|
||||
typedef struct IO_REMOVE_LOCK {
|
||||
SPINLOCK Lock;
|
||||
volatile long IoCount;
|
||||
bool Removing;
|
||||
struct EVENT* RemovedEvent;
|
||||
} IO_REMOVE_LOCK;
|
||||
|
||||
__declspec(dllexport) KSTATUS IoInitializeRemoveLock(IO_REMOVE_LOCK* lock);
|
||||
__declspec(dllexport) void IoDestroyRemoveLock(IO_REMOVE_LOCK* lock);
|
||||
__declspec(dllexport) KSTATUS IoAcquireRemoveLock(IO_REMOVE_LOCK* lock, IRP* irp);
|
||||
__declspec(dllexport) void IoReleaseRemoveLock(IO_REMOVE_LOCK* lock, IRP* irp);
|
||||
__declspec(dllexport) void IoReleaseRemoveLockAndWait(IO_REMOVE_LOCK* lock, IRP* removeIrp);
|
||||
|
||||
// IRP_QUEUE (per-device, driver-internal).
|
||||
|
||||
typedef struct IRP_QUEUE {
|
||||
SPINLOCK Lock;
|
||||
LIST_ENTRY Head;
|
||||
struct SEMAPHORE* Semaphore;
|
||||
} IRP_QUEUE;
|
||||
|
||||
__declspec(dllexport) void IrpQueueInit (IRP_QUEUE* q, struct SEMAPHORE* sem);
|
||||
__declspec(dllexport) void IrpQueueEnqueue (IRP_QUEUE* q, IRP* irp);
|
||||
__declspec(dllexport) IRP* IrpQueueDequeue (IRP_QUEUE* q);
|
||||
typedef void (*IRP_QUEUE_CANCEL_CALLBACK)(IRP* irp, void* context);
|
||||
__declspec(dllexport) void IrpQueueCancelAllEx(IRP_QUEUE* q,
|
||||
KSTATUS status,
|
||||
IRP_QUEUE_CANCEL_CALLBACK callback,
|
||||
void* context);
|
||||
__declspec(dllexport) void IrpQueueCancelAll(IRP_QUEUE* q, KSTATUS status);
|
||||
|
||||
// IRP allocation / stack helpers.
|
||||
|
||||
__declspec(dllexport) KSTATUS IoAllocateIrp(uint8_t stackCount, IRP** outIrp);
|
||||
__declspec(dllexport) void IoFreeIrp(IRP* irp);
|
||||
__declspec(dllexport) void IoInitializeIrp(IRP* irp, uint8_t stackCount);
|
||||
|
||||
__declspec(dllexport) IO_STACK_LOCATION* IoGetCurrentIrpStackLocation(IRP* irp);
|
||||
__declspec(dllexport) IO_STACK_LOCATION* IoGetNextIrpStackLocation(IRP* irp);
|
||||
__declspec(dllexport) void IoSkipCurrentIrpStackLocation(IRP* irp);
|
||||
__declspec(dllexport) void IoCopyCurrentIrpStackLocationToNext(IRP* irp);
|
||||
__declspec(dllexport) void IoSetCompletionRoutine(IRP* irp, IRP_COMPLETION_FN fn, void* ctx);
|
||||
__declspec(dllexport) IRP_CANCEL_ROUTINE IoSetCancelRoutine(IRP* irp, IRP_CANCEL_ROUTINE routine);
|
||||
__declspec(dllexport) void IoCancelIrp(IRP* irp);
|
||||
|
||||
__declspec(dllexport) void IoBuildReadWriteIrp(IRP* irp,
|
||||
IO_MAJOR_FUNCTION major,
|
||||
uint64_t byteOffset,
|
||||
uint32_t length,
|
||||
void* buffer);
|
||||
__declspec(dllexport) void IoBuildPnpIrp(IRP* irp,
|
||||
IO_PNP_MINOR_FUNCTION minor);
|
||||
__declspec(dllexport) void IoBuildDeviceIoControlIrp(IRP* irp,
|
||||
IO_MAJOR_FUNCTION major,
|
||||
uint32_t ioControlCode,
|
||||
void* inputBuffer,
|
||||
uint32_t inputLength,
|
||||
void* outputBuffer,
|
||||
uint32_t outputLength);
|
||||
|
||||
// Complete an IRP exactly once: publish status/information, signal the
|
||||
// optional completion event, queue the optional APC, then invoke the optional
|
||||
// completion callback.
|
||||
__declspec(dllexport) KSTATUS IoCompleteRequest(IRP* irp, KSTATUS status, size_t information);
|
||||
|
||||
// Submit to a specific top-of-stack device object. The current stack location
|
||||
// is stamped with the target device before dispatch.
|
||||
__declspec(dllexport) KSTATUS IoSubmitIrp(DEVICE_OBJECT* device, IRP* irp);
|
||||
__declspec(dllexport) KSTATUS IoSubmitIrpSync(DEVICE_OBJECT* device, IRP* irp);
|
||||
#include <ntlite/ddk/irp.h>
|
||||
@@ -1,36 +1,30 @@
|
||||
// Kernel ke irql declarations shared by implementation files and kernel clients.
|
||||
|
||||
#pragma once
|
||||
// ke_irql.h - software IRQL skeleton
|
||||
|
||||
// This is intentionally small for the first IRQL/APC bring-up step. It does
|
||||
// not yet program interrupt hardware or replace the spinlock interrupt-disable
|
||||
// path. It gives the kernel one authoritative execution-level state plus
|
||||
// assertions so blocking code can reject illegal callers early.
|
||||
// ke_irql.h - software IRQL skeleton.
|
||||
// The level constants are DDK-visible because current synchronization and IRP
|
||||
// layouts expose KIRQL. Kernel routines remain declared here.
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef uint8_t KIRQL;
|
||||
|
||||
#define PASSIVE_LEVEL ((KIRQL)0)
|
||||
#define APC_LEVEL ((KIRQL)1)
|
||||
#define DISPATCH_LEVEL ((KIRQL)2)
|
||||
#define DIRQL_BASE ((KIRQL)16)
|
||||
#define HIGH_LEVEL ((KIRQL)31)
|
||||
#include <ntlite/ddk/irql.h>
|
||||
|
||||
// Return the current processor's software IRQL.
|
||||
__declspec(dllexport) KIRQL KeGetCurrentIrql(void);
|
||||
|
||||
// Raise to newIrql and return the previous level. Raising to a lower level is
|
||||
// a kernel bug and will panic in checked/debug-style builds.
|
||||
// Raise to newIrql and return the previous level.
|
||||
__declspec(dllexport) KIRQL KeRaiseIrql(KIRQL newIrql);
|
||||
|
||||
// Restore a previously returned level. Lowering to a higher level is a kernel
|
||||
// bug and will panic.
|
||||
// Restore a previously returned level.
|
||||
__declspec(dllexport) void KeLowerIrql(KIRQL oldIrql);
|
||||
|
||||
// Assert that the current IRQL exactly matches expected.
|
||||
__declspec(dllexport) void KeAssertIrql(KIRQL expected);
|
||||
__declspec(dllexport) void KeAssertIrqlAtOrBelow(KIRQL maxIrql);
|
||||
__declspec(dllexport) int KeCanWait(void);
|
||||
|
||||
// Internal/debug helper used by diagnostics and panic messages.
|
||||
// Assert that the current IRQL is at or below maxIrql.
|
||||
__declspec(dllexport) void KeAssertIrqlAtOrBelow(KIRQL maxIrql);
|
||||
|
||||
// Return nonzero when the current context may block.
|
||||
__declspec(dllexport) int KeCanWait(void);
|
||||
|
||||
// Return a diagnostic name for an IRQL.
|
||||
__declspec(dllexport) const char* KeIrqlName(KIRQL irql);
|
||||
@@ -1,49 +1,9 @@
|
||||
// Kernel ke list declarations shared by implementation files and kernel clients.
|
||||
|
||||
#pragma once
|
||||
// ke_list.h - intrusive doubly-linked list
|
||||
// Used throughout the kernel for run queues, wait lists, thread lists, etc.
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct LIST_ENTRY {
|
||||
struct LIST_ENTRY* Fwd;
|
||||
struct LIST_ENTRY* Bwd;
|
||||
} LIST_ENTRY;
|
||||
// ke_list.h - kernel-private include path for the shared intrusive list type.
|
||||
// The type currently remains DDK-visible because legacy driver objects still
|
||||
// expose embedded lists and IRPs. Opaque request/device work removes that need.
|
||||
|
||||
#define LIST_INIT(head) ((head)->Fwd = (head)->Bwd = (head))
|
||||
#define LIST_IS_EMPTY(head) ((head)->Fwd == (head))
|
||||
|
||||
// Recover the containing struct pointer from an embedded LIST_ENTRY.
|
||||
#define CONTAINING_RECORD(ptr, type, member) \
|
||||
((type *)((char *)(ptr) - offsetof(type, member)))
|
||||
|
||||
// Implements the list Insert Tail operation.
|
||||
static inline void ListInsertTail(LIST_ENTRY* head, LIST_ENTRY* node) {
|
||||
node->Bwd = head->Bwd;
|
||||
node->Fwd = head;
|
||||
head->Bwd->Fwd = node;
|
||||
head->Bwd = node;
|
||||
}
|
||||
|
||||
// Implements the list Insert Head operation.
|
||||
static inline void ListInsertHead(LIST_ENTRY* head, LIST_ENTRY* node) {
|
||||
node->Fwd = head->Fwd;
|
||||
node->Bwd = head;
|
||||
head->Fwd->Bwd = node;
|
||||
head->Fwd = node;
|
||||
}
|
||||
|
||||
// Implements the list Remove operation.
|
||||
static inline void ListRemove(LIST_ENTRY* node) {
|
||||
node->Bwd->Fwd = node->Fwd;
|
||||
node->Fwd->Bwd = node->Bwd;
|
||||
node->Fwd = node->Bwd = node; // self-loop: poison against double-remove
|
||||
}
|
||||
|
||||
// Pop the first entry off the list, or NULL if empty.
|
||||
static inline LIST_ENTRY* ListPopHead(LIST_ENTRY* head) {
|
||||
if (LIST_IS_EMPTY(head)) return (LIST_ENTRY *)0;
|
||||
LIST_ENTRY* node = head->Fwd;
|
||||
ListRemove(node);
|
||||
return node;
|
||||
}
|
||||
#include <ntlite/ddk/list.h>
|
||||
@@ -1,95 +1,8 @@
|
||||
// Kernel ke spinlock declarations shared by implementation files and kernel clients.
|
||||
|
||||
#pragma once
|
||||
// ke_spinlock.h - spinlock for short, non-sleeping critical sections
|
||||
|
||||
// Step 3 IRQL bring-up:
|
||||
// * Acquiring a spinlock disables maskable interrupts and raises the software
|
||||
// IRQL to at least DISPATCH_LEVEL.
|
||||
// * Releasing restores both the previous IRQL and the previous RFLAGS.IF
|
||||
// state through the returned cookie.
|
||||
|
||||
// The public type remains uintptr_t so existing callers do not need to change.
|
||||
// Never hold a spinlock across a wait/blocking operation.
|
||||
#include <stdint.h>
|
||||
#include <intrin.h>
|
||||
#include <kernel/ke_irql.h>
|
||||
#include <ntlite/ddi/hal_api.h>
|
||||
|
||||
typedef struct SPINLOCK {
|
||||
volatile long Locked;
|
||||
} SPINLOCK;
|
||||
|
||||
#define SPINLOCK_INIT { 0 }
|
||||
|
||||
#define KI_SPINLOCK_IRQL_SHIFT ((unsigned)(sizeof(uintptr_t) * 8u - 8u))
|
||||
#define KI_SPINLOCK_FLAGS_MASK (~(((uintptr_t)0xFFu) << KI_SPINLOCK_IRQL_SHIFT))
|
||||
|
||||
// Implements the pack Spinlock Cookie operation.
|
||||
static __forceinline uintptr_t KiPackSpinlockCookie(uintptr_t flags, KIRQL oldIrql) {
|
||||
return (flags & KI_SPINLOCK_FLAGS_MASK) |
|
||||
(((uintptr_t)oldIrql) << KI_SPINLOCK_IRQL_SHIFT);
|
||||
}
|
||||
|
||||
// Implements the spinlock Cookie Flags operation.
|
||||
static __forceinline uintptr_t KiSpinlockCookieFlags(uintptr_t cookie) {
|
||||
return cookie & KI_SPINLOCK_FLAGS_MASK;
|
||||
}
|
||||
|
||||
// Implements the spinlock Cookie Irql operation.
|
||||
static __forceinline KIRQL KiSpinlockCookieIrql(uintptr_t cookie) {
|
||||
return (KIRQL)(cookie >> KI_SPINLOCK_IRQL_SHIFT);
|
||||
}
|
||||
|
||||
// Save RFLAGS, mask interrupts, raise to DISPATCH_LEVEL if needed, acquire.
|
||||
// If already running at DIRQL, the higher IRQL is preserved.
|
||||
static __forceinline uintptr_t KeAcquireSpinlock(SPINLOCK* sl) {
|
||||
uintptr_t flags = HalDisableInterrupts();
|
||||
|
||||
KIRQL oldIrql = KeGetCurrentIrql();
|
||||
if (oldIrql < DISPATCH_LEVEL)
|
||||
KeRaiseIrql(DISPATCH_LEVEL);
|
||||
|
||||
while (_InterlockedCompareExchange(&sl->Locked, 1, 0) != 0)
|
||||
_mm_pause();
|
||||
|
||||
return KiPackSpinlockCookie(flags, oldIrql);
|
||||
}
|
||||
|
||||
// Release and restore the caller's previous software IRQL/RFLAGS state.
|
||||
static __forceinline void KeReleaseSpinlock(SPINLOCK* sl, uintptr_t cookie) {
|
||||
uintptr_t flags = KiSpinlockCookieFlags(cookie);
|
||||
KIRQL oldIrql = KiSpinlockCookieIrql(cookie);
|
||||
|
||||
_InterlockedExchange(&sl->Locked, 0);
|
||||
KeLowerIrql(oldIrql);
|
||||
HalRestoreInterrupts(flags);
|
||||
}
|
||||
|
||||
// Implements the try Acquire Spinlock operation.
|
||||
static __forceinline int KeTryAcquireSpinlock(SPINLOCK* sl, uintptr_t* outCookie) {
|
||||
uintptr_t flags = HalDisableInterrupts();
|
||||
|
||||
KIRQL oldIrql = KeGetCurrentIrql();
|
||||
if (oldIrql < DISPATCH_LEVEL)
|
||||
KeRaiseIrql(DISPATCH_LEVEL);
|
||||
|
||||
if (_InterlockedCompareExchange(&sl->Locked, 1, 0) == 0) {
|
||||
*outCookie = KiPackSpinlockCookie(flags, oldIrql);
|
||||
return 1;
|
||||
}
|
||||
|
||||
KeLowerIrql(oldIrql);
|
||||
HalRestoreInterrupts(flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Transitional names for the IRQL-aware driver model work that follows.
|
||||
static __forceinline uintptr_t KeAcquireSpinlockRaiseToDpc(SPINLOCK* sl) {
|
||||
return KeAcquireSpinlock(sl);
|
||||
}
|
||||
|
||||
// Releases spinlock From Dpc.
|
||||
static __forceinline void KeReleaseSpinlockFromDpc(SPINLOCK* sl, uintptr_t cookie) {
|
||||
KeReleaseSpinlock(sl, cookie);
|
||||
}
|
||||
// The current spinlock layout and inline operations are DDK-visible while
|
||||
// driver objects still embed spinlocks. The kernel-private header remains as a
|
||||
// compatibility include for kernel implementation files only.
|
||||
#include <ntlite/ddk/sync.h>
|
||||
@@ -1,6 +1,8 @@
|
||||
// Kernel ke thread declarations shared by implementation files and kernel clients.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ntlite/ddk/thread.h>
|
||||
// ke_thread.h - thread model
|
||||
// A THREAD is the unit of scheduling. Every thread belongs to exactly one process.
|
||||
#include <stdint.h>
|
||||
@@ -17,12 +19,15 @@
|
||||
|
||||
typedef struct THREAD THREAD;
|
||||
|
||||
#ifndef NTL_THREAD_PRIORITY_DEFINED
|
||||
typedef enum THREAD_PRIORITY {
|
||||
PriorityLow = 0,
|
||||
PriorityNormal = 1,
|
||||
PriorityHigh = 2,
|
||||
PriorityCount = 3,
|
||||
} THREAD_PRIORITY;
|
||||
#define NTL_THREAD_PRIORITY_DEFINED 1
|
||||
#endif
|
||||
|
||||
typedef enum THREAD_STATE {
|
||||
ThreadReady = 0,
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ntlite/ddk/memory.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <ntlite/status.h>
|
||||
@@ -12,6 +14,7 @@
|
||||
|
||||
#define MM_PFN_INVALID_INDEX ((size_t)-1)
|
||||
|
||||
#ifndef NTL_MM_PFN_TYPES_DEFINED
|
||||
typedef enum MM_PFN_STATE {
|
||||
MmPfnStateInvalid = 0,
|
||||
MmPfnStateReserved,
|
||||
@@ -51,6 +54,9 @@ typedef struct MM_PFN {
|
||||
uint64_t BackingPage;
|
||||
} MM_PFN;
|
||||
|
||||
#define NTL_MM_PFN_TYPES_DEFINED 1
|
||||
#endif
|
||||
|
||||
typedef struct MM_PFN_STATS {
|
||||
uint64_t TotalFrames;
|
||||
uint64_t FreeFrames;
|
||||
|
||||
@@ -4,15 +4,24 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ntlite/ddk/memory.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <ntlite/memory_map.h>
|
||||
|
||||
#ifndef PAGE_SIZE
|
||||
#define PAGE_SIZE 4096ULL
|
||||
#endif
|
||||
#ifndef PAGE_MASK
|
||||
#define PAGE_MASK (~(PAGE_SIZE - 1))
|
||||
#endif
|
||||
|
||||
#ifndef NTL_PHYSICAL_ADDRESS_DEFINED
|
||||
typedef uint64_t PHYSICAL_ADDRESS;
|
||||
#define NTL_PHYSICAL_ADDRESS_DEFINED 1
|
||||
#endif
|
||||
|
||||
typedef struct MM_PHYSICAL_STATS {
|
||||
uint64_t TotalFrames;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// Kernel page-table manager declarations shared by the VMM and low-level kernel clients.
|
||||
#pragma once
|
||||
|
||||
#include <ntlite/ddk/memory.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <kernel/mm_phys.h>
|
||||
@@ -10,7 +12,9 @@
|
||||
#define PAGE_PRESENT (1ULL << 0)
|
||||
#define PAGE_WRITE (1ULL << 1)
|
||||
#define PAGE_USER (1ULL << 2)
|
||||
#ifndef PAGE_WRITETHROUGH
|
||||
#define PAGE_WRITETHROUGH (1ULL << 3)
|
||||
#endif
|
||||
#define PAGE_NOCACHE (1ULL << 4)
|
||||
#define PAGE_ACCESSED (1ULL << 5)
|
||||
#define PAGE_DIRTY (1ULL << 6)
|
||||
@@ -57,10 +61,13 @@ typedef struct MM_PTE_STATS {
|
||||
uint64_t CurrentLeafMappings;
|
||||
} MM_PTE_STATS;
|
||||
|
||||
#ifndef NTL_MM_PTE_MAP_MODE_DEFINED
|
||||
typedef enum MM_PTE_MAP_MODE {
|
||||
MmPteMapFailIfPresent = 0,
|
||||
MmPteMapReplaceExisting = 1,
|
||||
} MM_PTE_MAP_MODE;
|
||||
#define NTL_MM_PTE_MAP_MODE_DEFINED 1
|
||||
#endif
|
||||
|
||||
// Initializes the page-table manager around the bootloader-created PML4.
|
||||
void MmPteInitialize(PHYSICAL_ADDRESS bootPml4Phys);
|
||||
|
||||
@@ -1,48 +1,21 @@
|
||||
// Kernel ob object declarations shared by implementation files and kernel clients.
|
||||
|
||||
#pragma once
|
||||
// ob_object.h - executive object model
|
||||
// Every resource the kernel tracks is a typed, reference-counted OBJECT.
|
||||
// The OBJECT header must be the first member of any derived struct.
|
||||
#include <stdint.h>
|
||||
|
||||
// ob_object.h - executive object model.
|
||||
// Every resource the kernel tracks is a typed, reference-counted OBJECT. The
|
||||
// legacy OBJECT layout lives in the DDK while driver/device objects are still
|
||||
// public; object-manager routines remain kernel-private.
|
||||
|
||||
#include <stddef.h>
|
||||
#include <ntlite/status.h>
|
||||
|
||||
typedef enum OBJECT_TYPE {
|
||||
ObjectTypeProcess = 1,
|
||||
ObjectTypeThread = 2,
|
||||
ObjectTypeMutex = 3,
|
||||
ObjectTypeSemaphore = 4,
|
||||
ObjectTypeEvent = 5,
|
||||
ObjectTypeQueue = 6,
|
||||
ObjectTypeFile = 7,
|
||||
ObjectTypeDir = 8,
|
||||
ObjectTypeAsyncIo = 9,
|
||||
ObjectTypeSocket = 10,
|
||||
ObjectTypeDevice = 11,
|
||||
ObjectTypeDriver = 12,
|
||||
ObjectTypeUsbDevice = 13,
|
||||
ObjectTypeUsbPipe = 14,
|
||||
ObjectTypeFileMapping = 15,
|
||||
ObjectTypeSurface = 16,
|
||||
ObjectTypeInputQueue = 17,
|
||||
ObjectTypeImageSection = 18,
|
||||
ObjectTypeTimer = 19,
|
||||
ObjectTypeModule = 20,
|
||||
} OBJECT_TYPE;
|
||||
|
||||
typedef struct OBJECT {
|
||||
OBJECT_TYPE Type;
|
||||
volatile long RefCount; // interlocked
|
||||
void (*Destroy)(struct OBJECT* self);
|
||||
} OBJECT;
|
||||
#include <ntlite/ddk/object.h>
|
||||
|
||||
// Increment the reference count. Call whenever ownership is shared.
|
||||
__declspec(dllexport) void ObReferenceObject(OBJECT* object);
|
||||
__declspec(dllexport) void ObReferenceObject(OBJECT* object);
|
||||
|
||||
// Decrement. Calls Destroy() and frees the object when count reaches zero.
|
||||
__declspec(dllexport) void ObDereferenceObject(OBJECT* object);
|
||||
// Decrement the reference count and destroy the object when it reaches zero.
|
||||
__declspec(dllexport) void ObDereferenceObject(OBJECT* object);
|
||||
|
||||
// Allocate a zeroed object of the given size from kernel pool.
|
||||
// Caller must fill Type and Destroy before publishing the pointer.
|
||||
__declspec(dllexport) OBJECT* ObAllocateObject(OBJECT_TYPE type, size_t size);
|
||||
@@ -0,0 +1,119 @@
|
||||
// Kernel DDK-table provider implementation.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <ntlite/ddk/ddk.h>
|
||||
#include <ntlite/ddi/hal_api.h>
|
||||
#include <kernel/hal/hal_apic.h>
|
||||
#include <kernel/io_ddk.h>
|
||||
#include <kernel/ke_irq.h>
|
||||
#include <kernel/ke_sched.h>
|
||||
|
||||
static const HAL_API* gIoDdkHal;
|
||||
|
||||
// Returns the kernel direct-map alias for a physical address.
|
||||
static void* IoDdkPhysToVirt(uint64_t physicalAddress) {
|
||||
if (!gIoDdkHal || !gIoDdkHal->PhysToVirt)
|
||||
return (void*)0;
|
||||
return gIoDdkHal->PhysToVirt(physicalAddress);
|
||||
}
|
||||
|
||||
// Maps one kernel page through the DDK memory surface.
|
||||
static KSTATUS IoDdkMapPage(uintptr_t virtualAddress,
|
||||
uint64_t physicalAddress,
|
||||
uint64_t pageFlags,
|
||||
NTL_DDK_MAP_MODE mode) {
|
||||
MM_PTE_MAP_MODE kernelMode = MmPteMapFailIfPresent;
|
||||
if (mode == NtlDdkMapReplaceExisting)
|
||||
kernelMode = MmPteMapReplaceExisting;
|
||||
return MmPteMapPage(virtualAddress, physicalAddress, pageFlags, kernelMode);
|
||||
}
|
||||
|
||||
// Reads one aligned PCI configuration DWORD through the platform HAL.
|
||||
static uint32_t IoDdkPciRead32(uint16_t segment,
|
||||
uint8_t bus,
|
||||
uint8_t device,
|
||||
uint8_t function,
|
||||
uint16_t offset) {
|
||||
if (!gIoDdkHal || !gIoDdkHal->Pci.Read32)
|
||||
return 0xFFFFFFFFu;
|
||||
return gIoDdkHal->Pci.Read32(segment, bus, device, function, offset);
|
||||
}
|
||||
|
||||
// Writes one aligned PCI configuration DWORD through the platform HAL.
|
||||
static void IoDdkPciWrite32(uint16_t segment,
|
||||
uint8_t bus,
|
||||
uint8_t device,
|
||||
uint8_t function,
|
||||
uint16_t offset,
|
||||
uint32_t value) {
|
||||
if (!gIoDdkHal || !gIoDdkHal->Pci.Write32)
|
||||
return;
|
||||
gIoDdkHal->Pci.Write32(segment, bus, device, function, offset, value);
|
||||
}
|
||||
|
||||
// Returns the BSP local APIC identifier.
|
||||
static uint32_t IoDdkGetBspLapicId(void) {
|
||||
return HalGetBspLapicId();
|
||||
}
|
||||
|
||||
// Returns whether the platform interrupt controller is using x2APIC mode.
|
||||
static uint8_t IoDdkIsX2ApicEnabled(void) {
|
||||
return HalApicUsingX2Apic();
|
||||
}
|
||||
|
||||
// Allocates one kernel IRQ slot for MSI delivery.
|
||||
static KSTATUS IoDdkAllocateMsiVector(uint8_t* outIrq) {
|
||||
return KeIrqAllocateMsiVector(outIrq);
|
||||
}
|
||||
|
||||
static const NTL_DDK_DEBUG gIoDdkDebug = {
|
||||
.Print = DbgPrint,
|
||||
};
|
||||
|
||||
static const NTL_DDK_INTERRUPT gIoDdkInterrupt = {
|
||||
.AllocateMsiVector = IoDdkAllocateMsiVector,
|
||||
};
|
||||
|
||||
static const NTL_DDK_MEMORY gIoDdkMemory = {
|
||||
.PhysToVirt = IoDdkPhysToVirt,
|
||||
.MapPage = IoDdkMapPage,
|
||||
};
|
||||
|
||||
static const NTL_DDK_PLATFORM gIoDdkPlatform = {
|
||||
.PciRead32 = IoDdkPciRead32,
|
||||
.PciWrite32 = IoDdkPciWrite32,
|
||||
.GetBspLapicId = IoDdkGetBspLapicId,
|
||||
.IsX2ApicEnabled = IoDdkIsX2ApicEnabled,
|
||||
};
|
||||
|
||||
static const NTL_DDK_SCHEDULER gIoDdkScheduler = {
|
||||
.DelayThread = KeDelayThread,
|
||||
.Yield = KeYield,
|
||||
};
|
||||
|
||||
static NTL_DDK_TIMER gIoDdkTimer = {
|
||||
.QueryTicks = 0,
|
||||
.Stall = 0,
|
||||
};
|
||||
|
||||
static NTL_DDK gIoDdk = {
|
||||
.Version = NTL_DDK_VERSION,
|
||||
.Debug = &gIoDdkDebug,
|
||||
.Interrupt = &gIoDdkInterrupt,
|
||||
.Memory = &gIoDdkMemory,
|
||||
.Platform = &gIoDdkPlatform,
|
||||
.Scheduler = &gIoDdkScheduler,
|
||||
.Timer = &gIoDdkTimer,
|
||||
};
|
||||
|
||||
// Initializes the kernel-owned DDK table from platform services.
|
||||
void IoInitializeDdk(const HAL_API* hal) {
|
||||
gIoDdkHal = hal;
|
||||
gIoDdkTimer.QueryTicks = hal ? hal->Timer.QueryTicks : 0;
|
||||
gIoDdkTimer.Stall = hal ? hal->Timer.Stall : 0;
|
||||
}
|
||||
|
||||
// Returns the kernel-owned DDK table passed to driver entrypoints.
|
||||
const NTL_DDK* IoGetDdk(void) {
|
||||
return &gIoDdk;
|
||||
}
|
||||
+9
-3
@@ -23,6 +23,7 @@
|
||||
#include <kernel/ldr_image.h>
|
||||
#include <ntlite/ddi/hal_api.h>
|
||||
#include <kernel/io_file.h>
|
||||
#include <kernel/io_ddk.h>
|
||||
#include <kernel/ke_selftest.h>
|
||||
#include <kernel/ke_smp.h>
|
||||
#include <kernel/ke_input.h>
|
||||
@@ -122,7 +123,7 @@ static void KiInitializeSwapFromSettings(void) {
|
||||
}
|
||||
}
|
||||
|
||||
typedef KSTATUS (*DRIVER_ENTRY_FN)(const HAL_API *);
|
||||
typedef KSTATUS (*DRIVER_ENTRY_FN)(const NTL_DDK* ddk, NTL_DRIVER_INIT* init);
|
||||
|
||||
// HAL pointer cached at boot for subsystems that still need platform services.
|
||||
static const HAL_API* gKmainHal;
|
||||
@@ -190,6 +191,8 @@ static void KiDriversIniCb(const char* section, const char* key,
|
||||
|
||||
// Initializes drivers.
|
||||
static void KiInitializeDrivers(BOOT_INFO* bootInfo, const HAL_API* hal) {
|
||||
(void)hal;
|
||||
const NTL_DDK* ddk = IoGetDdk();
|
||||
DbgPrint("KiInitializeDrivers: Initializing drivers...\n");
|
||||
|
||||
// boot drivers (provided by the bootloader).
|
||||
@@ -230,7 +233,8 @@ static void KiInitializeDrivers(BOOT_INFO* bootInfo, const HAL_API* hal) {
|
||||
// Execute Entry Point.
|
||||
DRIVER_ENTRY_FN entry = (DRIVER_ENTRY_FN)LdrGetEntryPoint(mappedBase);
|
||||
if (entry) {
|
||||
KSTATUS ds = entry(hal);
|
||||
NTL_DRIVER_INIT init = {0};
|
||||
KSTATUS ds = entry(ddk, &init);
|
||||
if (!KSUCCESS(ds)) {
|
||||
DbgPrint("WARNING: Driver %s returned failure status 0x%X\n", mod->Name, ds);
|
||||
}
|
||||
@@ -326,7 +330,8 @@ static void KiInitializeDrivers(BOOT_INFO* bootInfo, const HAL_API* hal) {
|
||||
|
||||
DRIVER_ENTRY_FN entry = (DRIVER_ENTRY_FN)(LdrGetEntryPoint(mappedBase));
|
||||
|
||||
KSTATUS ds = entry(hal);
|
||||
NTL_DRIVER_INIT init = {0};
|
||||
KSTATUS ds = entry(ddk, &init);
|
||||
if (!KSUCCESS(ds)) {
|
||||
DbgPrint("KiInitializeDrivers: Driver %s failed to init!\n", runtimeKeys[i]);
|
||||
}
|
||||
@@ -523,6 +528,7 @@ extern void KernelMain(BOOT_INFO* bootInfo) {
|
||||
HalStopProcessor();
|
||||
|
||||
const HAL_API* hal = HalGetApi();
|
||||
IoInitializeDdk(hal);
|
||||
gKmainHal = hal;
|
||||
|
||||
KeInitDebug(hal, bootInfo->Debug);
|
||||
|
||||
Reference in new issue
Block a user