add ntfs.sys standalone driver target, change default usb vhd layout formatting to ntfs, implement Fat32CreateDir for directory creation support in the fat32 file system driver, add a dedicated HAL serial output endpoint for COM1 writes in hal_serial.c and subscribe serial to HAL text streams, introduce waitable kernel timers with KeTimerCreate, KeTimerSet, and KeTimerCancel alongside spinlock-protected global timer list initialization and scheduler tick tracking, implement SyscallWriteFileAsync system call for asynchronous non-blocking file writes, refactor NetSocketConnect and NetSocketSendTo to use generic SYS_SOCKET_ADDRESS_K structures instead of being hardcoded to IPv4, update gethostbyname and DNS name resolution to support IPv6 parsing via ResolveNameFamily, update tcpserve.exe with -4 and -6 command-line flags to accept and display IPv6 addresses, append size and version headers to all kernel telemetry and statistics structures including SYS_PMM_STATS, SYS_CPU_STATS, and SYS_SCHEDULER_STATS, update winmm timeGetTime to look up high-resolution hardware frequencies via SysGetTickFrequency, integrate 14 native smoke test applications.
This commit is contained in:
1 parent
2c4a68a75f
commit
ed3d065abd
156 files changed
+10509
-2643
No files matched your search
@@ -54,7 +54,6 @@ typedef struct tagBITMAPINFO {
|
||||
RGBQUAD bmiColors[1];
|
||||
} BITMAPINFO;
|
||||
|
||||
|
||||
// GDI Exports.
|
||||
|
||||
// Static buffers to persist between function calls.
|
||||
|
||||
@@ -13,11 +13,8 @@
|
||||
// multiple heaps, and NULL is a legal (no-op) heap argument under Win32.
|
||||
// - Win32 per-thread state lives behind SYS_TEB::SubsystemData so the native
|
||||
// TEB ABI stays subsystem-neutral.
|
||||
// - File I/O uses SYS_OPEN_FILE / SYS_READ_FILE / SYS_SEEK_FILE /
|
||||
// SYS_GET_FILE_SIZE / SYS_CLOSE_HANDLE (unified close path - no separate
|
||||
// SysCloseFile).
|
||||
// - WriteFile / CreateFileA in write-mode / SetEndOfFile are stubs because
|
||||
// the VFS has no write path yet.
|
||||
// - File I/O uses the flags-based SYS_OPEN_FILE request plus the common
|
||||
// read/write/seek/query/close syscalls.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
@@ -221,19 +218,19 @@ static void TranslatePath(const char* input, char* output) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Implements the k32 Open File Native operation.
|
||||
static uint32_t K32OpenFileNative(const char* path, uint32_t* handleOut) {
|
||||
SYS_PATH_HANDLE_REQUEST req = { SysSvFromCstr(path), handleOut };
|
||||
static uint32_t K32OpenFileNative(const char* path,
|
||||
uint32_t access,
|
||||
uint32_t disposition,
|
||||
uint32_t* handleOut) {
|
||||
SYS_OPEN_FILE_REQUEST req = SysMakeOpenFileRequest(SysSvFromCstr(path),
|
||||
access,
|
||||
disposition,
|
||||
SYS_FILE_FLAG_NONE,
|
||||
handleOut);
|
||||
return SysOpenFile(&req);
|
||||
}
|
||||
|
||||
// Implements the k32 Create File Native operation.
|
||||
static uint32_t K32CreateFileNative(const char* path, uint32_t* handleOut) {
|
||||
SYS_PATH_HANDLE_REQUEST req = { SysSvFromCstr(path), handleOut };
|
||||
return SysCreateFile(&req);
|
||||
}
|
||||
|
||||
// Implements the k32 Delete File Native operation.
|
||||
static uint32_t K32DeleteFileNative(const char* path) {
|
||||
SYS_PATH_REQUEST req = { SysSvFromCstr(path) };
|
||||
@@ -254,13 +251,14 @@ static uint32_t K32SetCwdNative(const char* path) {
|
||||
|
||||
// Implements the k32 Get Cwd Native operation.
|
||||
static uint32_t K32GetCwdNative(char* buffer, size_t capacity, size_t* lengthOut) {
|
||||
size_t len = 0;
|
||||
size_t writable = (buffer && capacity) ? capacity - 1 : 0;
|
||||
SYS_GET_CWD_REQUEST req = { buffer, writable, &len };
|
||||
uint32_t s = SysGetCwd(&req);
|
||||
if (lengthOut) *lengthOut = len;
|
||||
if (s == 0 && buffer && capacity) buffer[len] = '\0';
|
||||
return s;
|
||||
SYS_STRING_VIEW cwd = SysGetCurrentDirectoryView();
|
||||
if ((cwd.Length && !cwd.Data) || cwd.Length > SYS_CWD_MAX) return STATUS_INVALID_PARAMETER;
|
||||
if (lengthOut) *lengthOut = cwd.Length;
|
||||
if (!buffer || cwd.Length + 1 > capacity) return STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
if (cwd.Length) memcpy(buffer, cwd.Data, cwd.Length);
|
||||
buffer[cwd.Length] = '\0';
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Implements the k32 Create Process Native operation.
|
||||
@@ -323,7 +321,10 @@ static BOOL KiFileExistsA(const char* path) {
|
||||
char native[MAX_PATH];
|
||||
TranslatePath(path, native);
|
||||
uint32_t h = 0;
|
||||
if (K32OpenFileNative(native, &h) != 0) return FALSE;
|
||||
if (K32OpenFileNative(native,
|
||||
SYS_FILE_ACCESS_READ | SYS_FILE_ACCESS_QUERY,
|
||||
SYS_FILE_OPEN_EXISTING,
|
||||
&h) != 0) return FALSE;
|
||||
SysCloseHandle(h);
|
||||
return TRUE;
|
||||
}
|
||||
@@ -396,7 +397,7 @@ __declspec(dllexport) DWORD SearchPathA(const char* lpPath, const char* lpFileNa
|
||||
return 0;
|
||||
}
|
||||
|
||||
// GetLastError / SetLastError (single-threaded stub).
|
||||
// GetLastError / SetLastError (single-threaded stub).
|
||||
static SYS_PEB* gProcessPeb = NULL;
|
||||
|
||||
// Implements the peb operation.
|
||||
@@ -416,7 +417,7 @@ __declspec(dllexport) void SetLastError(DWORD err) {
|
||||
|
||||
// Process termination.
|
||||
__declspec(dllexport) _Noreturn void ExitProcess(unsigned int code) {
|
||||
SysExitProcess((int)code);
|
||||
SysExitProcess((int32_t)code);
|
||||
while (true) ; // unreachable
|
||||
}
|
||||
|
||||
@@ -425,17 +426,31 @@ __declspec(dllexport) void OutputDebugStringA(const char* str) {
|
||||
if (str) K32DebugPrintA(str);
|
||||
}
|
||||
|
||||
// Queries the native monotonic tick frequency.
|
||||
static uint64_t K32TickFrequency(void) {
|
||||
uint64_t frequency = 0;
|
||||
if (SysGetTickFrequency(&frequency) != STATUS_SUCCESS) return 0;
|
||||
return frequency;
|
||||
}
|
||||
|
||||
// Returns monotonic milliseconds since boot.
|
||||
static uint64_t K32TickMilliseconds(void) {
|
||||
uint64_t frequency = K32TickFrequency();
|
||||
if (!frequency) return 0;
|
||||
return SysTicksToMilliseconds(SysGetTick(), frequency);
|
||||
}
|
||||
|
||||
// Timer.
|
||||
__declspec(dllexport) DWORD GetTickCount(void) {
|
||||
return (DWORD)(SysGetTick() / 1000);
|
||||
return (DWORD)K32TickMilliseconds();
|
||||
}
|
||||
|
||||
// Returns tick Count64.
|
||||
__declspec(dllexport) uint64_t GetTickCount64(void) {
|
||||
return SysGetTick() / 1000;
|
||||
return K32TickMilliseconds();
|
||||
}
|
||||
|
||||
// Memory (heap argument is ignored - single user-mode heap).
|
||||
// Memory (heap argument is ignored - single user-mode heap).
|
||||
#define HEAP_ZERO_MEMORY 0x00000008UL
|
||||
#define HEAP_REALLOC_IN_PLACE_ONLY 0x00000010UL
|
||||
|
||||
@@ -511,8 +526,8 @@ __declspec(dllexport) void* VirtualAlloc(void* lpAddress, size_t dwSize,
|
||||
void* base = NULL;
|
||||
uint32_t flags = lpAddress ? SYS_VM_FLAG_FIXED : SYS_VM_FLAG_NONE;
|
||||
uint32_t s = SysAllocVm(lpAddress, pages, WinProtectToSysVm(flProtect), flags, &base);
|
||||
if (s != SYS_STATUS_SUCCESS) {
|
||||
gLastError = (s == SYS_STATUS_NOT_FOUND || s == SYS_STATUS_INVALID_PARAMETER) ? 87 : 8;
|
||||
if (s != STATUS_SUCCESS) {
|
||||
gLastError = (s == STATUS_NOT_FOUND || s == STATUS_INVALID_PARAMETER) ? 87 : 8;
|
||||
return NULL;
|
||||
}
|
||||
return base;
|
||||
@@ -523,7 +538,7 @@ __declspec(dllexport) BOOL VirtualFree(void* lpAddress, size_t dwSize, DWORD dwF
|
||||
(void)dwSize; (void)dwFreeType;
|
||||
if (!lpAddress) return TRUE;
|
||||
uint32_t s = SysFreeVm(lpAddress);
|
||||
if (s != SYS_STATUS_SUCCESS) { gLastError = 87; return FALSE; }
|
||||
if (s != STATUS_SUCCESS) { gLastError = 87; return FALSE; }
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -534,7 +549,7 @@ __declspec(dllexport) BOOL VirtualProtect(void* lpAddress, size_t dwSize,
|
||||
uint32_t oldSysProtect = 0;
|
||||
uint32_t s = SysProtectVm(lpAddress, pages, WinProtectToSysVm(flNewProtect),
|
||||
lpflOldProtect ? &oldSysProtect : NULL);
|
||||
if (s != SYS_STATUS_SUCCESS) { gLastError = 87; return FALSE; }
|
||||
if (s != STATUS_SUCCESS) { gLastError = 87; return FALSE; }
|
||||
if (lpflOldProtect) *lpflOldProtect = SysProtectVmToWin(oldSysProtect);
|
||||
return TRUE;
|
||||
}
|
||||
@@ -549,7 +564,7 @@ __declspec(dllexport) size_t VirtualQuery(const void* lpAddress,
|
||||
|
||||
SYS_VM_REGION_INFO info;
|
||||
uint32_t s = SysQueryVm((void*)lpAddress, &info);
|
||||
if (s != SYS_STATUS_SUCCESS) {
|
||||
if (s != STATUS_SUCCESS) {
|
||||
gLastError = 87;
|
||||
return 0;
|
||||
}
|
||||
@@ -585,8 +600,8 @@ __declspec(dllexport) HANDLE CreateFileMappingA(HANDLE hFile,
|
||||
SYS_MAP_FLAG_NONE,
|
||||
maximumSize,
|
||||
&kh);
|
||||
if (s != SYS_STATUS_SUCCESS) {
|
||||
gLastError = (s == SYS_STATUS_NOT_SUPPORTED) ? 120 : ((s == SYS_STATUS_NO_MEMORY) ? 8 : 87);
|
||||
if (s != STATUS_SUCCESS) {
|
||||
gLastError = (s == STATUS_NOT_SUPPORTED) ? 120 : ((s == STATUS_NO_MEMORY) ? 8 : 87);
|
||||
return NULL;
|
||||
}
|
||||
return KH_TO_HANDLE(kh);
|
||||
@@ -621,8 +636,8 @@ __declspec(dllexport) void* MapViewOfFile(HANDLE hFileMappingObject,
|
||||
WinFileMapAccessToSys(dwDesiredAccess),
|
||||
SYS_MAP_FLAG_NONE,
|
||||
&base);
|
||||
if (s != SYS_STATUS_SUCCESS) {
|
||||
gLastError = (s == SYS_STATUS_NOT_SUPPORTED) ? 120 : ((s == SYS_STATUS_NO_MEMORY) ? 8 : 87);
|
||||
if (s != STATUS_SUCCESS) {
|
||||
gLastError = (s == STATUS_NOT_SUPPORTED) ? 120 : ((s == STATUS_NO_MEMORY) ? 8 : 87);
|
||||
return NULL;
|
||||
}
|
||||
return base;
|
||||
@@ -631,7 +646,7 @@ __declspec(dllexport) void* MapViewOfFile(HANDLE hFileMappingObject,
|
||||
__declspec(dllexport) BOOL UnmapViewOfFile(const void* lpBaseAddress) {
|
||||
if (!lpBaseAddress) { gLastError = 87; return FALSE; }
|
||||
uint32_t s = SysFreeVm((void*)lpBaseAddress);
|
||||
if (s != SYS_STATUS_SUCCESS) { gLastError = 87; return FALSE; }
|
||||
if (s != STATUS_SUCCESS) { gLastError = 87; return FALSE; }
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -645,16 +660,22 @@ __declspec(dllexport) BOOL FlushViewOfFile(const void* lpBaseAddress, size_t dwN
|
||||
|
||||
// --- Win32 API ---.
|
||||
|
||||
// Returns whether one input key is currently held for Win32 adapters.
|
||||
static bool Win32IsInputKeyDown(INPUT_KEY key) {
|
||||
bool down = false;
|
||||
return SysIsKeyDown(key, &down) == STATUS_SUCCESS && down;
|
||||
}
|
||||
|
||||
// GetAsyncKeyState implementation over the canonical input key namespace.
|
||||
__declspec(dllexport) SHORT GetAsyncKeyState(int vKey) {
|
||||
if (vKey == 0x11) { // VK_CONTROL
|
||||
return (SysIsKeyDown(INPUT_KEY_LEFT_CTRL) || SysIsKeyDown(INPUT_KEY_RIGHT_CTRL)) ? (SHORT)0x8000 : 0;
|
||||
return (Win32IsInputKeyDown(INPUT_KEY_LEFT_CTRL) || Win32IsInputKeyDown(INPUT_KEY_RIGHT_CTRL)) ? (SHORT)0x8000 : 0;
|
||||
}
|
||||
if (vKey == 0x10) { // VK_SHIFT
|
||||
return (SysIsKeyDown(INPUT_KEY_LEFT_SHIFT) || SysIsKeyDown(INPUT_KEY_RIGHT_SHIFT)) ? (SHORT)0x8000 : 0;
|
||||
return (Win32IsInputKeyDown(INPUT_KEY_LEFT_SHIFT) || Win32IsInputKeyDown(INPUT_KEY_RIGHT_SHIFT)) ? (SHORT)0x8000 : 0;
|
||||
}
|
||||
if (vKey == 0x12) { // VK_MENU / ALT
|
||||
return (SysIsKeyDown(INPUT_KEY_LEFT_ALT) || SysIsKeyDown(INPUT_KEY_RIGHT_ALT)) ? (SHORT)0x8000 : 0;
|
||||
return (Win32IsInputKeyDown(INPUT_KEY_LEFT_ALT) || Win32IsInputKeyDown(INPUT_KEY_RIGHT_ALT)) ? (SHORT)0x8000 : 0;
|
||||
}
|
||||
|
||||
static const struct { int vk; INPUT_KEY key; } vk_to_key[] = {
|
||||
@@ -697,7 +718,7 @@ __declspec(dllexport) SHORT GetAsyncKeyState(int vKey) {
|
||||
|
||||
for (size_t i = 0; i < sizeof(vk_to_key) / sizeof(vk_to_key[0]); ++i) {
|
||||
if (vk_to_key[i].vk == vKey) {
|
||||
if (SysIsKeyDown(vk_to_key[i].key))
|
||||
if (Win32IsInputKeyDown(vk_to_key[i].key))
|
||||
return (SHORT)0x8000;
|
||||
break;
|
||||
}
|
||||
@@ -709,8 +730,10 @@ __declspec(dllexport) SHORT GetAsyncKeyState(int vKey) {
|
||||
__declspec(dllexport) BOOL FlushConsoleInputBuffer(HANDLE hConsoleInput) {
|
||||
(void)hConsoleInput;
|
||||
// Drain the keyboard buffer by reading until empty.
|
||||
while (SysPollKeyboard()) {
|
||||
(void)SysReadKeyboardChar();
|
||||
INPUT_KEY key;
|
||||
while (SysPollKeyboard(&key) == STATUS_SUCCESS) {
|
||||
char ignored;
|
||||
(void)SysReadKeyboardChar(&ignored);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
@@ -788,71 +811,42 @@ __declspec(dllexport) HANDLE CreateFileA(const char* name,
|
||||
char translatedName[260];
|
||||
TranslatePath(name, translatedName);
|
||||
|
||||
int wantWrite = (access & GENERIC_WRITE) != 0;
|
||||
uint32_t sysAccess = SYS_FILE_ACCESS_QUERY;
|
||||
if (access & GENERIC_READ)
|
||||
sysAccess |= SYS_FILE_ACCESS_READ;
|
||||
if (access & GENERIC_WRITE)
|
||||
sysAccess |= SYS_FILE_ACCESS_WRITE;
|
||||
|
||||
if (disposition == OPEN_EXISTING || disposition == TRUNCATE_EXISTING) {
|
||||
// Open the file via the read path (it must already exist).
|
||||
uint32_t kh = 0;
|
||||
uint32_t s = K32OpenFileNative(translatedName, &kh);
|
||||
if (s != 0) { gLastError = 2; return INVALID_HANDLE_VALUE; }
|
||||
|
||||
if (disposition == TRUNCATE_EXISTING && wantWrite) {
|
||||
// Immediately truncate to zero.
|
||||
uint32_t ts = SysTruncateFile(kh, 0);
|
||||
if (ts != 0) {
|
||||
SysCloseHandle(kh);
|
||||
gLastError = 5;
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
}
|
||||
return KH_TO_HANDLE(kh);
|
||||
uint32_t sysDisposition;
|
||||
switch (disposition) {
|
||||
case OPEN_EXISTING: sysDisposition = SYS_FILE_OPEN_EXISTING; break;
|
||||
case OPEN_ALWAYS: sysDisposition = SYS_FILE_OPEN_ALWAYS; break;
|
||||
case CREATE_ALWAYS: sysDisposition = SYS_FILE_CREATE_ALWAYS; break;
|
||||
case CREATE_NEW: sysDisposition = SYS_FILE_CREATE_NEW; break;
|
||||
case TRUNCATE_EXISTING: sysDisposition = SYS_FILE_TRUNCATE_EXISTING; break;
|
||||
default:
|
||||
gLastError = 87;
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
if (disposition == CREATE_ALWAYS && wantWrite) {
|
||||
// Create-or-replace: try to create; if the file already exists,
|
||||
// open it and truncate it to zero instead.
|
||||
uint32_t kh = 0;
|
||||
uint32_t s = K32CreateFileNative(translatedName, &kh);
|
||||
if (s != 0) {
|
||||
// File may already exist - open and truncate.
|
||||
s = K32OpenFileNative(translatedName, &kh);
|
||||
if (s != 0) { gLastError = 5; return INVALID_HANDLE_VALUE; }
|
||||
SysTruncateFile(kh, 0);
|
||||
}
|
||||
return KH_TO_HANDLE(kh);
|
||||
uint32_t kh = 0;
|
||||
uint32_t s = K32OpenFileNative(translatedName, sysAccess, sysDisposition, &kh);
|
||||
if (s != 0) {
|
||||
gLastError = (s == STATUS_OBJECT_NAME_COLLISION) ? 80 :
|
||||
(s == STATUS_NOT_FOUND) ? 2 : 5;
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
if (disposition == OPEN_ALWAYS && wantWrite) {
|
||||
// Open if exists, create if not.
|
||||
uint32_t kh = 0;
|
||||
if (K32OpenFileNative(translatedName, &kh) != 0) {
|
||||
if (K32CreateFileNative(translatedName, &kh) != 0) {
|
||||
gLastError = 5;
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
}
|
||||
return KH_TO_HANDLE(kh);
|
||||
}
|
||||
|
||||
if (disposition == CREATE_NEW && wantWrite) {
|
||||
// Fail if the file already exists (we can't check atomically,
|
||||
// but SysCreateFile returns NAME_COLLISION for existing files).
|
||||
uint32_t kh = 0;
|
||||
uint32_t s = K32CreateFileNative(translatedName, &kh);
|
||||
if (s != 0) { gLastError = 80; return INVALID_HANDLE_VALUE; } // ERROR_FILE_EXISTS
|
||||
return KH_TO_HANDLE(kh);
|
||||
}
|
||||
|
||||
// Any other combination (e.g. read-only CREATE_ALWAYS) is not supported.
|
||||
gLastError = 87; // ERROR_INVALID_PARAMETER
|
||||
return INVALID_HANDLE_VALUE;
|
||||
return KH_TO_HANDLE(kh);
|
||||
}
|
||||
|
||||
// GetFileSize - fills optional high-DWORD pointer, returns low DWORD.
|
||||
// Returns 0xFFFFFFFF on error, matching Win32 behaviour.
|
||||
__declspec(dllexport) DWORD GetFileSize(HANDLE hFile, DWORD* fileSizeHigh) {
|
||||
if (!hFile || hFile == INVALID_HANDLE_VALUE) { gLastError = 6; return 0xFFFFFFFFUL; }
|
||||
uint64_t sz = SysGetFileSize(HANDLE_TO_KH(hFile));
|
||||
uint64_t sz = 0;
|
||||
uint32_t s = SysGetFileSize(HANDLE_TO_KH(hFile), &sz);
|
||||
if (s != 0) { gLastError = 6; return 0xFFFFFFFFUL; }
|
||||
if (fileSizeHigh) *fileSizeHigh = (DWORD)(sz >> 32);
|
||||
return (DWORD)(sz & 0xFFFFFFFFULL);
|
||||
}
|
||||
@@ -922,12 +916,14 @@ __declspec(dllexport) DWORD SetFilePointer(HANDLE hFile, long dist,
|
||||
if (method == FILE_BEGIN) {
|
||||
target = delta;
|
||||
} else if (method == FILE_CURRENT) {
|
||||
uint64_t cur = SysGetFilePos(kh);
|
||||
if (cur == (uint64_t)-1 || cur > 0x7FFFFFFFFFFFFFFFULL) { gLastError = 6; return 0xFFFFFFFFUL; }
|
||||
uint64_t cur = 0;
|
||||
uint32_t s = SysGetFilePos(kh, &cur);
|
||||
if (s != 0 || cur > 0x7FFFFFFFFFFFFFFFULL) { gLastError = 6; return 0xFFFFFFFFUL; }
|
||||
target = (int64_t)cur + delta;
|
||||
} else if (method == FILE_END) {
|
||||
uint64_t sz = SysGetFileSize(kh);
|
||||
if (sz > 0x7FFFFFFFFFFFFFFFULL) { gLastError = 6; return 0xFFFFFFFFUL; }
|
||||
uint64_t sz = 0;
|
||||
uint32_t s = SysGetFileSize(kh, &sz);
|
||||
if (s != 0 || sz > 0x7FFFFFFFFFFFFFFFULL) { gLastError = 6; return 0xFFFFFFFFUL; }
|
||||
target = (int64_t)sz + delta;
|
||||
} else {
|
||||
gLastError = 87; return 0xFFFFFFFFUL;
|
||||
@@ -949,9 +945,10 @@ __declspec(dllexport) DWORD SetFilePointer(HANDLE hFile, long dist,
|
||||
__declspec(dllexport) BOOL SetEndOfFile(HANDLE hFile) {
|
||||
if (!hFile || hFile == INVALID_HANDLE_VALUE) { gLastError = 6; return FALSE; }
|
||||
uint32_t kh = HANDLE_TO_KH(hFile);
|
||||
uint64_t pos = SysGetFilePos(kh);
|
||||
if (pos == (uint64_t)-1) { gLastError = 6; return FALSE; }
|
||||
uint32_t s = SysTruncateFile(kh, pos);
|
||||
uint64_t pos = 0;
|
||||
uint32_t s = SysGetFilePos(kh, &pos);
|
||||
if (s != 0) { gLastError = 6; return FALSE; }
|
||||
s = SysTruncateFile(kh, pos);
|
||||
if (s != 0) { gLastError = 1; return FALSE; }
|
||||
return TRUE;
|
||||
}
|
||||
@@ -1184,7 +1181,7 @@ __declspec(dllexport) DWORD GetModuleFileNameA(HANDLE hModule,
|
||||
// Implements the terminate Process operation.
|
||||
__declspec(dllexport) BOOL TerminateProcess(HANDLE hProcess, unsigned int uExitCode) {
|
||||
if (hProcess == GetCurrentProcess()) {
|
||||
SysExitProcess((int)uExitCode);
|
||||
SysExitProcess((int32_t)uExitCode);
|
||||
while (true) ;
|
||||
}
|
||||
|
||||
@@ -1193,16 +1190,9 @@ __declspec(dllexport) BOOL TerminateProcess(HANDLE hProcess, unsigned int uExitC
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
uint32_t pid = 0;
|
||||
uint32_t s = SysGetProcessPid(HANDLE_TO_KH(hProcess), &pid);
|
||||
if (s != 0 || pid == 0) {
|
||||
gLastError = 6; // ERROR_INVALID_HANDLE
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
s = SysKillProcess(pid, (int)uExitCode);
|
||||
uint32_t s = SysKillProcess(HANDLE_TO_KH(hProcess), (int32_t)uExitCode);
|
||||
if (s != 0) {
|
||||
gLastError = 5; // ERROR_ACCESS_DENIED / generic failure for now
|
||||
gLastError = (s == STATUS_INVALID_HANDLE) ? 6 : 5;
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
@@ -1290,7 +1280,6 @@ __declspec(dllexport) DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMillisec
|
||||
return 0xFFFFFFFFUL;
|
||||
}
|
||||
|
||||
|
||||
// Implements the extract Application Path A operation.
|
||||
static BOOL ExtractApplicationPathA(const char* commandLine, char* out, size_t outSize) {
|
||||
if (!commandLine || !out || outSize == 0) return FALSE;
|
||||
@@ -1411,7 +1400,7 @@ __declspec(dllexport) BOOL GetExitCodeProcess(HANDLE hProcess, DWORD* lpExitCode
|
||||
if (!lpExitCode) { gLastError = 87; return FALSE; }
|
||||
uint32_t kh = HANDLE_TO_KH(hProcess);
|
||||
if (!kh) { gLastError = 6; return FALSE; } // ERROR_INVALID_HANDLE
|
||||
int code = 0;
|
||||
int32_t code = 0;
|
||||
uint32_t s = SysGetProcessExitCode(kh, &code);
|
||||
if (s != 0) { gLastError = 6; return FALSE; }
|
||||
*lpExitCode = (DWORD)code;
|
||||
@@ -1471,13 +1460,13 @@ static BOOL K32IsConsoleOutputHandle(HANDLE h) {
|
||||
// Implements the k32 Set Console Last Error operation.
|
||||
static void K32SetConsoleLastError(uint32_t status) {
|
||||
switch (status) {
|
||||
case SYS_STATUS_SUCCESS:
|
||||
case STATUS_SUCCESS:
|
||||
gLastError = 0;
|
||||
break;
|
||||
case SYS_STATUS_INVALID_PARAMETER:
|
||||
case STATUS_INVALID_PARAMETER:
|
||||
gLastError = 87;
|
||||
break;
|
||||
case SYS_STATUS_NO_MEMORY:
|
||||
case STATUS_NO_MEMORY:
|
||||
gLastError = 8;
|
||||
break;
|
||||
default:
|
||||
@@ -1506,7 +1495,8 @@ __declspec(dllexport) BOOL ReadConsoleA(HANDLE hConsoleInput,
|
||||
DWORD i = 0; // Notice we switched to a while loop
|
||||
|
||||
while (i < nNumberOfCharsToRead) {
|
||||
char c = SysReadKeyboardChar();
|
||||
char c = 0;
|
||||
if (SysReadKeyboardChar(&c) != STATUS_SUCCESS) continue;
|
||||
|
||||
// Ignore unmapped keys (Shift, Ctrl, etc.).
|
||||
if (c == 0) continue;
|
||||
@@ -1518,7 +1508,7 @@ __declspec(dllexport) BOOL ReadConsoleA(HANDLE hConsoleInput,
|
||||
// Stop reading when the user presses Enter.
|
||||
if (c == '\n' || c == '\r') {
|
||||
// If your shell expects strings to be \n terminated, leave this.
|
||||
// If your shell expects \0 termination without a newline,
|
||||
// If your shell expects \0 termination without a newline,
|
||||
// you might want to replace buf[i-1] with \0 here!
|
||||
break;
|
||||
}
|
||||
@@ -1558,7 +1548,7 @@ __declspec(dllexport) BOOL GetConsoleScreenBufferInfo(HANDLE hConsoleOutput,
|
||||
|
||||
SYS_CONSOLE_INFO info;
|
||||
uint32_t s = SysGetConsoleInfo(&info);
|
||||
if (s != SYS_STATUS_SUCCESS) {
|
||||
if (s != STATUS_SUCCESS) {
|
||||
K32SetConsoleLastError(s);
|
||||
return FALSE;
|
||||
}
|
||||
@@ -1589,7 +1579,7 @@ __declspec(dllexport) BOOL SetConsoleCursorPosition(HANDLE hConsoleOutput,
|
||||
}
|
||||
|
||||
uint32_t s = SysSetConsoleCursor((int)dwCursorPosition.X, (int)dwCursorPosition.Y);
|
||||
if (s != SYS_STATUS_SUCCESS) {
|
||||
if (s != STATUS_SUCCESS) {
|
||||
K32SetConsoleLastError(s);
|
||||
return FALSE;
|
||||
}
|
||||
@@ -1618,7 +1608,7 @@ __declspec(dllexport) BOOL FillConsoleOutputCharacterA(HANDLE hConsoleOutput,
|
||||
(int)dwWriteCoord.Y, (size_t)nLength,
|
||||
&written);
|
||||
if (lpNumberOfCharsWritten) *lpNumberOfCharsWritten = (DWORD)written;
|
||||
if (s != SYS_STATUS_SUCCESS) {
|
||||
if (s != STATUS_SUCCESS) {
|
||||
K32SetConsoleLastError(s);
|
||||
return FALSE;
|
||||
}
|
||||
@@ -1647,18 +1637,17 @@ __declspec(dllexport) BOOL FillConsoleOutputAttribute(HANDLE hConsoleOutput,
|
||||
(int)dwWriteCoord.Y, (size_t)nLength,
|
||||
&written);
|
||||
if (lpNumberOfAttrsWritten) *lpNumberOfAttrsWritten = (DWORD)written;
|
||||
if (s != SYS_STATUS_SUCCESS) {
|
||||
if (s != STATUS_SUCCESS) {
|
||||
K32SetConsoleLastError(s);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Directory enumeration (FindFirstFileA / FindNextFileA / FindClose).
|
||||
// Directory enumeration (FindFirstFileA / FindNextFileA / FindClose).
|
||||
|
||||
typedef SYS_DIR_ENTRY KDIR_ENTRY;
|
||||
|
||||
|
||||
// FIND_HANDLE is a user-side wrapper: it stores the kernel dir handle and
|
||||
// the wildcard pattern so FindNextFileA can filter subsequent entries.
|
||||
// We return a pointer to this struct cast to HANDLE; it is NOT a kernel
|
||||
@@ -1912,16 +1901,16 @@ __declspec(dllexport) BOOL SetCurrentDirectoryA(const char* lpPathName) {
|
||||
// Returns current Directory A.
|
||||
__declspec(dllexport) DWORD GetCurrentDirectoryA(DWORD nBufferLength, char* lpBuffer) {
|
||||
if (!lpBuffer || nBufferLength == 0) {
|
||||
// Return required size (including NUL). Max CWD is 512 bytes + "C:\\".
|
||||
return 515;
|
||||
// Return a conservative required size including NUL.
|
||||
return SYS_CWD_MAX + 1;
|
||||
}
|
||||
|
||||
// Kernel returns native "N:/path". Present it as a Win32 drive letter.
|
||||
char raw[512];
|
||||
char raw[SYS_CWD_MAX + 1];
|
||||
uint32_t s = K32GetCwdNative(raw, sizeof(raw), NULL);
|
||||
if (s != 0) { gLastError = 1; return 0; }
|
||||
|
||||
char full[515];
|
||||
char full[SYS_CWD_MAX + 1];
|
||||
char drive = 'C';
|
||||
const char* rel = raw;
|
||||
if (raw[0] >= '0' && raw[0] <= '7' && raw[1] == ':' &&
|
||||
@@ -1948,7 +1937,6 @@ __declspec(dllexport) DWORD GetCurrentDirectoryA(DWORD nBufferLength, char* lpBu
|
||||
return (DWORD)(needed - 1); // length without NUL, matching Win32
|
||||
}
|
||||
|
||||
|
||||
__declspec(dllexport) HANDLE CreateMutexA(void* lpMutexAttributes, BOOL bInitialOwner,
|
||||
const char* lpName) {
|
||||
(void)lpMutexAttributes; (void)lpName;
|
||||
@@ -2108,26 +2096,28 @@ static long long TscFreqFromCpuid(void) {
|
||||
return (long long)crystal_hz * numer / denom;
|
||||
}
|
||||
|
||||
// Calibrate TSC against SysGetTick (1 unit = 1 microsecond).
|
||||
// Calibrates TSC against the native monotonic tick source.
|
||||
static long long TscFreqCalibrate(void) {
|
||||
// We'll wait for 100ms (100,000 microseconds) to get a stable sample.
|
||||
const uint64_t CALIBRATION_US = 100000;
|
||||
uint64_t frequency = K32TickFrequency();
|
||||
if (!frequency) return 0;
|
||||
|
||||
uint64_t calibrationTicks = frequency / 10ull;
|
||||
if (!calibrationTicks) calibrationTicks = 1;
|
||||
|
||||
uint64_t t0 = SysGetTick();
|
||||
uint64_t tsc0 = __rdtsc();
|
||||
|
||||
// Simple busy wait for the duration.
|
||||
while ((SysGetTick() - t0) < CALIBRATION_US) {
|
||||
_mm_pause();
|
||||
while ((SysGetTick() - t0) < calibrationTicks) {
|
||||
_mm_pause();
|
||||
}
|
||||
|
||||
uint64_t t1 = SysGetTick();
|
||||
uint64_t tsc1 = __rdtsc();
|
||||
|
||||
uint64_t delta_tsc = tsc1 - tsc0;
|
||||
uint64_t delta_us = t1 - t0;
|
||||
uint64_t delta_us = SysTicksToMicroseconds(t1 - t0, frequency);
|
||||
if (!delta_us) return 0;
|
||||
|
||||
// Hz = (Delta TSC / Delta Microseconds) * 1,000,000.
|
||||
return (long long)(delta_tsc * 1000000ULL / delta_us);
|
||||
}
|
||||
|
||||
@@ -2199,7 +2189,7 @@ __declspec(dllexport) void GetSystemTime(SYSTEMTIME* lpSystemTime) {
|
||||
if (!lpSystemTime) return;
|
||||
|
||||
SYS_SYSTEM_TIME st;
|
||||
if (SysGetSystemTime(&st) != SYS_STATUS_SUCCESS) {
|
||||
if (SysGetSystemTime(&st) != STATUS_SUCCESS) {
|
||||
memset(lpSystemTime, 0, sizeof(*lpSystemTime));
|
||||
return;
|
||||
}
|
||||
@@ -2237,11 +2227,12 @@ __declspec(dllexport) void GetSystemTimeAsFileTime(void* lpSystemTimeAsFileTime)
|
||||
|
||||
SYS_SYSTEM_TIME st;
|
||||
uint64_t ft;
|
||||
if (SysGetSystemTime(&st) == SYS_STATUS_SUCCESS) {
|
||||
if (SysGetSystemTime(&st) == STATUS_SUCCESS) {
|
||||
ft = K32EpochToFileTime(st.EpochSeconds, st.Nanosecond);
|
||||
} else {
|
||||
uint64_t frequency = K32TickFrequency();
|
||||
const uint64_t FALLBACK_2024_01_01_FT = 133485408000000000ULL;
|
||||
ft = FALLBACK_2024_01_01_FT + (SysGetTick() * 10ULL);
|
||||
ft = FALLBACK_2024_01_01_FT + SysTicksToMicroseconds(SysGetTick(), frequency) * 10ULL;
|
||||
}
|
||||
memcpy(lpSystemTimeAsFileTime, &ft, sizeof(ft));
|
||||
}
|
||||
@@ -2461,7 +2452,7 @@ __declspec(dllexport) BOOL IsDebuggerPresent(void) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// RTL Exception / Unwind (SEH infrastructure - all stubs).
|
||||
// RTL Exception / Unwind (SEH infrastructure - all stubs).
|
||||
|
||||
typedef struct _RUNTIME_FUNCTION {
|
||||
unsigned int BeginAddress;
|
||||
@@ -2635,7 +2626,7 @@ __declspec(dllexport) BOOL FlsFree(DWORD dwFlsIndex) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Pointer encoding (security cookie obfuscation)
|
||||
// Pointer encoding (security cookie obfuscation)
|
||||
// We have no security cookie; return the pointer unchanged.
|
||||
|
||||
__declspec(dllexport) void* EncodePointer(void* Ptr) { return Ptr; }
|
||||
|
||||
@@ -14,7 +14,6 @@ typedef struct tagPAINTSTRUCT {
|
||||
HDC hdc; BOOL fErase; RECT rcPaint; BOOL fRestore; BOOL fIncUpdate; char res[32];
|
||||
} PAINTSTRUCT;
|
||||
|
||||
|
||||
// Implements the user32 Debug Print A operation.
|
||||
static void User32DebugPrintA(const char* s) {
|
||||
if (!s) return;
|
||||
|
||||
@@ -49,7 +49,9 @@ typedef struct {
|
||||
// Timer.
|
||||
|
||||
__declspec(dllexport) unsigned long timeGetTime(void) {
|
||||
return (unsigned long)(SysGetTick() / 1000u);
|
||||
uint64_t frequency = 0;
|
||||
if (SysGetTickFrequency(&frequency) != STATUS_SUCCESS || !frequency) return 0;
|
||||
return (unsigned long)SysTicksToMilliseconds(SysGetTick(), frequency);
|
||||
}
|
||||
|
||||
// Waveform audio (stubs - no audio hardware at this stage).
|
||||
|
||||
Reference in new issue
Block a user