// Win32 kernel32 compatibility layer. This file maps common Win32 process, file, console, heap, and timing APIs onto native syscalls. // Thin wrappers around syscall.dll stubs that expose a familiar Win32 API // surface to user-mode code originally written for Windows. // Design notes: // - HANDLE is void*; we store the uint32_t kernel handle as a pointer value // so Win32 code can pass it around opaquely without knowing its size. // HANDLE_TO_KH / KH_TO_HANDLE do that conversion in one place. // - INVALID_HANDLE_VALUE maps to kernel handle 0 (the always-invalid slot). // - HeapAlloc / HeapFree / HeapReAlloc ignore the HANDLE heap argument and // always use the single user-mode heap. This is fine: we don't expose // 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 the flags-based SYS_OPEN_FILE request plus the common // read/write/seek/query/close syscalls. #include #include #include #include #include #include #include #include extern size_t _malloc_usable_size(const void* ptr); // Types. typedef void* HANDLE; typedef unsigned long DWORD; typedef unsigned long long DWORD64; typedef unsigned short WORD; typedef int BOOL; typedef unsigned char BYTE; typedef short SHORT; typedef long LONG; typedef struct { LONG x; LONG y; } POINT; typedef struct { SHORT X; SHORT Y; } COORD; typedef struct { SHORT Left; SHORT Top; SHORT Right; SHORT Bottom; } SMALL_RECT; typedef struct { uintptr_t _opaque[5]; } CRITICAL_SECTION; typedef struct { void* _ptr; } CONDITION_VARIABLE; // Forward declarations used by the process-local GetProcAddress surface. __declspec(dllexport) HANDLE CreateEventA(void*, BOOL, BOOL, const char*); __declspec(dllexport) HANDLE CreateEventW(void*, BOOL, BOOL, const unsigned short*); __declspec(dllexport) BOOL SetEvent(HANDLE); __declspec(dllexport) BOOL ResetEvent(HANDLE); __declspec(dllexport) _Noreturn void ExitThread(DWORD); __declspec(dllexport) HANDLE CreateThread(void*, size_t, void*, void*, DWORD, DWORD*); __declspec(dllexport) DWORD WaitForSingleObject(HANDLE, DWORD); __declspec(dllexport) HANDLE CreateMutexA(void*, BOOL, const char*); __declspec(dllexport) HANDLE CreateMutexW(void*, BOOL, const unsigned short*); __declspec(dllexport) BOOL ReleaseMutex(HANDLE); __declspec(dllexport) BOOL CloseHandle(HANDLE); __declspec(dllexport) void InitializeCriticalSection(CRITICAL_SECTION*); __declspec(dllexport) BOOL InitializeCriticalSectionAndSpinCount(CRITICAL_SECTION*, DWORD); __declspec(dllexport) void DeleteCriticalSection(CRITICAL_SECTION*); __declspec(dllexport) void EnterCriticalSection(CRITICAL_SECTION*); __declspec(dllexport) void LeaveCriticalSection(CRITICAL_SECTION*); __declspec(dllexport) BOOL TryEnterCriticalSection(CRITICAL_SECTION*); __declspec(dllexport) void InitializeConditionVariable(CONDITION_VARIABLE*); __declspec(dllexport) BOOL SleepConditionVariableCS(CONDITION_VARIABLE*, CRITICAL_SECTION*, DWORD); __declspec(dllexport) void WakeConditionVariable(CONDITION_VARIABLE*); __declspec(dllexport) void WakeAllConditionVariable(CONDITION_VARIABLE*); __declspec(dllexport) BOOL IsDebuggerPresent(void); extern void waveOutGetNumDevs(void); extern void waveOutOpen(void); extern void waveOutClose(void); extern void waveOutPrepareHeader(void); extern void waveOutUnprepareHeader(void); extern void waveOutWrite(void); extern void waveOutPause(void); extern void waveOutRestart(void); extern void waveOutReset(void); extern void waveOutSetVolume(void); extern void waveOutGetVolume(void); extern void waveOutGetPosition(void); extern void waveOutGetID(void); extern void waveOutGetDevCapsA(void); extern void waveOutGetDevCapsW(void); extern void waveOutGetErrorTextA(void); extern void waveOutGetErrorTextW(void); extern void waveOutBreakLoop(void); extern void waveOutMessage(void); extern void timeGetTime(void); extern void timeBeginPeriod(void); extern void timeEndPeriod(void); typedef struct _CONSOLE_SCREEN_BUFFER_INFO { COORD dwSize; COORD dwCursorPosition; WORD wAttributes; SMALL_RECT srWindow; COORD dwMaximumWindowSize; } CONSOLE_SCREEN_BUFFER_INFO; #define MAX_PATH 260 #define TRUE 1 #define FALSE 0 #define INVALID_HANDLE_VALUE ((HANDLE)(intptr_t)-1) #define MEM_COMMIT 0x00001000UL #define MEM_RESERVE 0x00002000UL #define MEM_RELEASE 0x00008000UL #define MEM_FREE 0x00010000UL #define MEM_PRIVATE 0x00020000UL #define MEM_MAPPED 0x00040000UL #define PAGE_NOACCESS 0x01UL #define PAGE_READONLY 0x02UL #define PAGE_READWRITE 0x04UL #define PAGE_WRITECOPY 0x08UL #define PAGE_EXECUTE 0x10UL #define PAGE_EXECUTE_READ 0x20UL #define PAGE_EXECUTE_READWRITE 0x40UL #define SEC_COMMIT 0x08000000UL #define FILE_MAP_COPY 0x00000001UL #define FILE_MAP_WRITE 0x00000002UL #define FILE_MAP_READ 0x00000004UL #define FILE_MAP_EXECUTE 0x00000020UL #define FILE_MAP_ALL_ACCESS 0x000F001FUL typedef struct _MEMORY_BASIC_INFORMATION { void* BaseAddress; void* AllocationBase; DWORD AllocationProtect; size_t RegionSize; DWORD State; DWORD Protect; DWORD Type; } MEMORY_BASIC_INFORMATION; // Implements the win Protect To Sys Vm operation. static uint32_t WinProtectToSysVm(DWORD protect) { switch (protect) { case PAGE_NOACCESS: return SYS_VM_NOACCESS; case PAGE_READONLY: return SYS_VM_READ; case PAGE_READWRITE: case PAGE_WRITECOPY: return SYS_VM_READWRITE; case PAGE_EXECUTE: return SYS_VM_EXECUTE; case PAGE_EXECUTE_READ: return SYS_VM_EXECUTE_READ; case PAGE_EXECUTE_READWRITE: return SYS_VM_EXECUTE_READWRITE; default: return SYS_VM_READWRITE; } } static uint32_t WinFileMappingProtectToSysVm(DWORD protect) { // Strip section attributes; the low byte carries PAGE_* protection. DWORD pageProtect = protect & 0xFFu; if (pageProtect == PAGE_WRITECOPY) return SYS_VM_READ; // MapViewOfFile(FILE_MAP_COPY) asks for the private writable view. return WinProtectToSysVm(pageProtect ? pageProtect : PAGE_READONLY); } static uint32_t WinFileMapAccessToSys(DWORD desiredAccess) { uint32_t access = 0; if (desiredAccess & FILE_MAP_EXECUTE) access |= SYS_MAP_ACCESS_EXECUTE; if (desiredAccess & FILE_MAP_COPY) access |= SYS_MAP_ACCESS_COPY; if (desiredAccess & FILE_MAP_WRITE) access |= SYS_MAP_ACCESS_WRITE; if (desiredAccess & FILE_MAP_READ) access |= SYS_MAP_ACCESS_READ; if ((desiredAccess & FILE_MAP_ALL_ACCESS) == FILE_MAP_ALL_ACCESS) access |= SYS_MAP_ACCESS_READ | SYS_MAP_ACCESS_COPY; if (!access) access = SYS_MAP_ACCESS_READ; return access; } // Implements the protect Vm To Win operation. static DWORD SysProtectVmToWin(uint32_t protect) { switch (protect) { case SYS_VM_NOACCESS: return PAGE_NOACCESS; case SYS_VM_READ: return PAGE_READONLY; case SYS_VM_READWRITE: return PAGE_READWRITE; case SYS_VM_EXECUTE: return PAGE_EXECUTE; case SYS_VM_EXECUTE_READ: return PAGE_EXECUTE_READ; case SYS_VM_EXECUTE_READWRITE: return PAGE_EXECUTE_READWRITE; default: return PAGE_NOACCESS; } } // File-find structures. typedef struct _FILETIME { DWORD dwLowDateTime; DWORD dwHighDateTime; } FILETIME; typedef struct _SYSTEMTIME { unsigned short wYear; unsigned short wMonth; unsigned short wDayOfWeek; unsigned short wDay; unsigned short wHour; unsigned short wMinute; unsigned short wSecond; unsigned short wMilliseconds; } SYSTEMTIME; typedef struct _WIN32_FIND_DATAA { DWORD dwFileAttributes; FILETIME ftCreationTime; FILETIME ftLastAccessTime; FILETIME ftLastWriteTime; DWORD nFileSizeHigh; DWORD nFileSizeLow; DWORD dwReserved0; DWORD dwReserved1; char cFileName[260]; // MAX_PATH char cAlternateFileName[14]; } WIN32_FIND_DATAA; // CreateFileA disposition / access flags (subset used by Bink and similar). #define GENERIC_READ 0x80000000UL #define GENERIC_WRITE 0x40000000UL #define GENERIC_READ 0x80000000UL #define GENERIC_WRITE 0x40000000UL #define OPEN_EXISTING 3 #define OPEN_ALWAYS 4 #define CREATE_ALWAYS 2 #define CREATE_NEW 1 #define TRUNCATE_EXISTING 5 #define FILE_BEGIN 0 #define FILE_CURRENT 1 #define FILE_END 2 // Handle conversion helpers // uint32_t kernel handle <-> opaque Win32 HANDLE // Kernel handle 0 == invalid; we map that to INVALID_HANDLE_VALUE (NULL). static inline HANDLE KH_TO_HANDLE(uint32_t kh) { return (HANDLE)(uintptr_t)kh; } static inline uint32_t HANDLE_TO_KH(HANDLE h) { return (uint32_t)(uintptr_t)h; } static inline BOOL IS_VALID_KERNEL_HANDLE(HANDLE h) { uintptr_t v = (uintptr_t)h; return v != 0 && v != (uintptr_t)INVALID_HANDLE_VALUE; } // Path translator. static void TranslatePath(const char* input, char* output) { if (!output) return; if (!input) { output[0] = '\0'; return; } if (input[0] != '\0' && input[1] == ':' && (input[2] == '\\' || input[2] == '/')) { // Translate "C:\" -> "0:/". Native nt-lite paths such as // "0:/system/foo.dll" are already drive-indexed and pass through. char drive = input[0]; if (drive >= 'a' && drive <= 'z') drive -= ('a' - 'A'); // To uppercase output[0] = (drive >= '0' && drive <= '7') ? drive : (char)('0' + (drive - 'C')); output[1] = ':'; output[2] = '/'; // Copy the rest, swapping backslashes to forward slashes. const char* src = input + 3; char* dst = output + 3; while (*src) { *dst = (*src == '\\') ? '/' : *src; src++; dst++; } *dst = '\0'; } else { // Fallback for relative paths: just swap slashes. while (*input) { *output = (*input == '\\') ? '/' : *input; input++; output++; } *output = '\0'; } } // Implements the k32 Open File Native operation. 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 Delete File Native operation. static uint32_t K32DeleteFileNative(const char* path) { SYS_PATH_REQUEST req = { SysSvFromCstr(path) }; return SysDeleteFile(&req); } // Implements the k32 Open Dir Native operation. static uint32_t K32OpenDirNative(const char* path, uint32_t* handleOut) { SYS_PATH_HANDLE_REQUEST req = { SysSvFromCstr(path), handleOut }; return SysOpenDir(&req); } // Implements the k32 Set Cwd Native operation. static uint32_t K32SetCwdNative(const char* path) { SYS_PATH_REQUEST req = { SysSvFromCstr(path) }; return SysSetCwd(&req); } // Implements the k32 Get Cwd Native operation. static uint32_t K32GetCwdNative(char* buffer, size_t capacity, size_t* lengthOut) { SYS_STRING_VIEW cwd = SysGetCurrentDirectoryView(); if ((cwd.Length && !cwd.Data) || cwd.Length > SYS_CWD_MAX) return NTLSTATUS_INVALID_PARAMETER; if (lengthOut) *lengthOut = cwd.Length; if (!buffer || cwd.Length + 1 > capacity) return NTLSTATUS_BUFFER_TOO_SMALL; if (cwd.Length) memcpy(buffer, cwd.Data, cwd.Length); buffer[cwd.Length] = '\0'; return NTLSTATUS_SUCCESS; } // Implements the k32 Create Process Native operation. static uint32_t K32CreateProcessNative(const char* path, uint32_t* handleOut, const char* commandLine) { SYS_CREATE_PROCESS_REQUEST req = { SysSvFromCstr(path), SysSvFromCstr(commandLine), handleOut }; return SysCreateProcess(&req); } // Implements the k32 Write Console Span operation. static void K32WriteConsoleSpan(const char* data, size_t length) { SYS_WRITE_CONSOLE_REQUEST req = { SysSvFromParts(data, length) }; SysWriteConsole(&req); } // Implements the k32 Debug Print A operation. static void K32DebugPrintA(const char* s) { if (!s) return; SYS_PRINT_DEBUG_REQUEST req = { SysSvFromCstr(s) }; SysPrintDebug(&req); } #define WIN32_TLS_SLOTS 64 #define FLS_MAX_SLOTS 64 #define FLS_OUT_OF_INDEXES 0xFFFFFFFFUL typedef struct WIN32_THREAD_ENV { DWORD LastError; DWORD Reserved0; void* TlsSlots[WIN32_TLS_SLOTS]; void* FlsSlots[FLS_MAX_SLOTS]; void* ExceptionFrameHead; } WIN32_THREAD_ENV; static WIN32_THREAD_ENV gFallbackThreadEnv; // Implements the k32 Thread Env operation. static WIN32_THREAD_ENV* K32ThreadEnv(void) { SYS_TEB* teb = SysGetTeb(); if (!teb || teb->Magic != SYS_TEB_MAGIC) return &gFallbackThreadEnv; WIN32_THREAD_ENV* env = (WIN32_THREAD_ENV*)teb->SubsystemData; if (!env) { env = (WIN32_THREAD_ENV*)malloc(sizeof(WIN32_THREAD_ENV)); if (!env) return &gFallbackThreadEnv; memset(env, 0, sizeof(*env)); teb->SubsystemData = env; } return env; } // Implements the k32 Last Error Slot operation. static DWORD* K32LastErrorSlot(void) { return &K32ThreadEnv()->LastError; } #define gLastError (*K32LastErrorSlot()) // Returns a stable nonzero identifier for the calling thread. static DWORD K32CurrentTidOrOne(void); // Implements the file Exists A operation. static BOOL KiFileExistsA(const char* path) { if (!path || !*path) return FALSE; char native[MAX_PATH]; TranslatePath(path, native); uint32_t h = 0; if (K32OpenFileNative(native, SYS_FILE_ACCESS_READ | SYS_FILE_ACCESS_QUERY, SYS_FILE_OPEN_EXISTING, &h) != 0) return FALSE; SysCloseHandle(h); return TRUE; } // Copies search Path Result. static DWORD KiCopySearchPathResult(char* out, DWORD outChars, const char* text, char** filePart) { DWORD len = (DWORD)strlen(text); if (out && outChars) { DWORD copy = (len < outChars - 1) ? len : outChars - 1; memcpy(out, text, copy); out[copy] = '\0'; if (filePart) { char* slash1 = strrchr(out, '/'); char* slash2 = strrchr(out, '\\'); char* slash = slash1 > slash2 ? slash1 : slash2; *filePart = slash ? slash + 1 : out; } } return len; } __declspec(dllexport) DWORD SearchPathA(const char* lpPath, const char* lpFileName, const char* lpExtension, DWORD nBufferLength, char* lpBuffer, char** lpFilePart) { if (!lpFileName || !*lpFileName) { gLastError = 87; return 0; } char candidate[MAX_PATH]; size_t nameLen = strlen(lpFileName); bool hasExt = (strrchr(lpFileName, '.') != NULL); bool rooted = (lpFileName[0] == '/' || lpFileName[0] == '\\' || (lpFileName[0] && lpFileName[1] == ':')); if (rooted || strchr(lpFileName, '/') || strchr(lpFileName, '\\')) { strncpy(candidate, lpFileName, sizeof(candidate) - 1); candidate[sizeof(candidate) - 1] = '\0'; if (!hasExt && lpExtension && nameLen + strlen(lpExtension) + 1 < sizeof(candidate)) strcat(candidate, lpExtension); if (KiFileExistsA(candidate)) return KiCopySearchPathResult(lpBuffer, nBufferLength, candidate, lpFilePart); } const char* paths = lpPath && *lpPath ? lpPath : "."; const char* p = paths; while (*p) { char dir[MAX_PATH]; size_t di = 0; while (*p && *p != ';' && di + 1 < sizeof(dir)) dir[di++] = *p++; while (*p == ';') p++; dir[di] = '\0'; size_t pos = 0; if (strcmp(dir, ".") != 0) { while (dir[pos] && pos + 1 < sizeof(candidate)) { candidate[pos] = dir[pos]; pos++; } if (pos && candidate[pos - 1] != '/' && candidate[pos - 1] != '\\' && pos + 1 < sizeof(candidate)) candidate[pos++] = '/'; } for (size_t i = 0; lpFileName[i] && pos + 1 < sizeof(candidate); i++) candidate[pos++] = lpFileName[i]; if (!hasExt && lpExtension) { for (size_t i = 0; lpExtension[i] && pos + 1 < sizeof(candidate); i++) candidate[pos++] = lpExtension[i]; } candidate[pos] = '\0'; if (KiFileExistsA(candidate)) return KiCopySearchPathResult(lpBuffer, nBufferLength, candidate, lpFilePart); } gLastError = 2; // ERROR_FILE_NOT_FOUND if (lpBuffer && nBufferLength) lpBuffer[0] = '\0'; if (lpFilePart) *lpFilePart = NULL; return 0; } // GetLastError / SetLastError (single-threaded stub). static SYS_PEB* gProcessPeb = NULL; // Implements the peb operation. static SYS_PEB* Win32Peb(void) { if (!gProcessPeb) gProcessPeb = SysGetPeb(); return gProcessPeb; } // Returns last Error. __declspec(dllexport) DWORD GetLastError(void) { return gLastError; } // Updates last Error. __declspec(dllexport) void SetLastError(DWORD err) { gLastError = err; } // Process termination. __declspec(dllexport) _Noreturn void ExitProcess(unsigned int code) { SysExitProcess((int32_t)code); while (true) ; // unreachable } // Debug output. __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) != NTLSTATUS_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)K32TickMilliseconds(); } // Returns tick Count64. __declspec(dllexport) uint64_t GetTickCount64(void) { return K32TickMilliseconds(); } // Memory (heap argument is ignored - single user-mode heap). #define HEAP_ZERO_MEMORY 0x00000008UL #define HEAP_REALLOC_IN_PLACE_ONLY 0x00000010UL __declspec(dllexport) void* HeapAlloc(void* heap, DWORD flags, size_t size) { (void)heap; if (!size) return NULL; void* ptr = malloc(size); if (!ptr) { gLastError = 8; // ERROR_NOT_ENOUGH_MEMORY return NULL; } // Bink and the Microsoft CRT routinely allocate internal state with // HEAP_ZERO_MEMORY. Ignoring this flag only works accidentally while the // heap keeps receiving fresh demand-zero pages; under low memory / swap the // allocator reuses dirty freed blocks and stale pitch/pointer fields can // corrupt the decoder. if (flags & HEAP_ZERO_MEMORY) memset(ptr, 0, size); return ptr; } // Implements the heap Free operation. __declspec(dllexport) BOOL HeapFree(void* heap, DWORD flags, void* ptr) { (void)heap; (void)flags; // Win32's HeapFree doesn't need the size; we pass 0 and the user-mode heap carries the block size. if (ptr) free(ptr); return TRUE; } __declspec(dllexport) void* HeapReAlloc(void* heap, DWORD flags, void* ptr, size_t size) { (void)heap; if (flags & HEAP_REALLOC_IN_PLACE_ONLY) { // The user heap does not expose an in-place grow primitive. Preserve // Windows semantics by failing instead of silently moving the block. size_t oldSize = _malloc_usable_size(ptr); if (oldSize != (size_t)-1 && oldSize >= size) return ptr; gLastError = 8; // ERROR_NOT_ENOUGH_MEMORY return NULL; } size_t oldSize = ptr ? _malloc_usable_size(ptr) : 0; void* newptr = realloc(ptr, size); if (!newptr && size) { gLastError = 8; return NULL; } if (newptr && (flags & HEAP_ZERO_MEMORY) && oldSize != (size_t)-1 && size > oldSize) memset((unsigned char*)newptr + oldSize, 0, size - oldSize); return newptr; } // GetProcessHeap - return a sentinel non-NULL value so callers can pass it // back into HeapAlloc/HeapFree without crashing (we ignore it anyway). __declspec(dllexport) void* GetProcessHeap(void) { return (void*)1; } // Virtual memory compatibility. __declspec(dllexport) void* VirtualAlloc(void* lpAddress, size_t dwSize, DWORD flAllocationType, DWORD flProtect) { (void)flAllocationType; if (!dwSize) return NULL; size_t pages = (dwSize + 4095u) / 4096u; void* base = NULL; uint32_t flags = lpAddress ? SYS_VM_FLAG_FIXED : SYS_VM_FLAG_NONE; SYS_ALLOC_VM_REQUEST req; memset(&req, 0, sizeof(req)); req.Size = sizeof(req); req.PreferredBase = lpAddress; req.PageCount = pages; req.Protect = WinProtectToSysVm(flProtect); req.Flags = flags; req.BaseOut = &base; KSTATUS s = SysAllocVm(&req); if (s != NTLSTATUS_SUCCESS) { gLastError = (s == NTLSTATUS_NOT_FOUND || s == NTLSTATUS_INVALID_PARAMETER) ? 87 : 8; return NULL; } return base; } // Implements the virtual Free operation. __declspec(dllexport) BOOL VirtualFree(void* lpAddress, size_t dwSize, DWORD dwFreeType) { (void)dwSize; (void)dwFreeType; if (!lpAddress) return TRUE; uint32_t s = SysFreeVm(lpAddress); if (s != NTLSTATUS_SUCCESS) { gLastError = 87; return FALSE; } return TRUE; } __declspec(dllexport) BOOL VirtualProtect(void* lpAddress, size_t dwSize, DWORD flNewProtect, DWORD* lpflOldProtect) { if (!lpAddress || !dwSize) { gLastError = 87; return FALSE; } size_t pages = (dwSize + 4095u) / 4096u; uint32_t oldSysProtect = 0; uint32_t s = SysProtectVm(lpAddress, pages, WinProtectToSysVm(flNewProtect), lpflOldProtect ? &oldSysProtect : NULL); if (s != NTLSTATUS_SUCCESS) { gLastError = 87; return FALSE; } if (lpflOldProtect) *lpflOldProtect = SysProtectVmToWin(oldSysProtect); return TRUE; } __declspec(dllexport) size_t VirtualQuery(const void* lpAddress, MEMORY_BASIC_INFORMATION* lpBuffer, size_t dwLength) { if (!lpAddress || !lpBuffer || dwLength < sizeof(MEMORY_BASIC_INFORMATION)) { gLastError = 87; // ERROR_INVALID_PARAMETER return 0; } SYS_VM_REGION_INFO info; uint32_t s = SysQueryVm((void*)lpAddress, &info); if (s != NTLSTATUS_SUCCESS) { gLastError = 87; return 0; } DWORD protect = SysProtectVmToWin(info.Protect); lpBuffer->BaseAddress = info.Base; lpBuffer->AllocationBase = info.Base; lpBuffer->AllocationProtect = protect; lpBuffer->RegionSize = info.PageCount * 4096u; lpBuffer->State = MEM_COMMIT; lpBuffer->Protect = protect; lpBuffer->Type = (info.Type == 7u) ? MEM_MAPPED : MEM_PRIVATE; // 7 == MmVadMappedFile return sizeof(MEMORY_BASIC_INFORMATION); } __declspec(dllexport) HANDLE CreateFileMappingA(HANDLE hFile, void* lpFileMappingAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, const char* lpName) { (void)lpFileMappingAttributes; (void)lpName; if (!hFile || hFile == INVALID_HANDLE_VALUE) { gLastError = 6; // ERROR_INVALID_HANDLE return NULL; } uint64_t maximumSize = ((uint64_t)dwMaximumSizeHigh << 32) | (uint64_t)dwMaximumSizeLow; uint32_t kh = 0; uint32_t s = SysCreateFileMapping(HANDLE_TO_KH(hFile), WinFileMappingProtectToSysVm(flProtect), SYS_MAP_FLAG_NONE, maximumSize, &kh); if (s != NTLSTATUS_SUCCESS) { gLastError = (s == NTLSTATUS_NOT_SUPPORTED) ? 120 : ((s == NTLSTATUS_NO_MEMORY) ? 8 : 87); return NULL; } return KH_TO_HANDLE(kh); } __declspec(dllexport) HANDLE CreateFileMappingW(HANDLE hFile, void* lpFileMappingAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, const unsigned short* lpName) { (void)lpName; return CreateFileMappingA(hFile, lpFileMappingAttributes, flProtect, dwMaximumSizeHigh, dwMaximumSizeLow, NULL); } __declspec(dllexport) void* MapViewOfFile(HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, size_t dwNumberOfBytesToMap) { if (!hFileMappingObject || hFileMappingObject == INVALID_HANDLE_VALUE) { gLastError = 6; return NULL; } uint64_t offset = ((uint64_t)dwFileOffsetHigh << 32) | (uint64_t)dwFileOffsetLow; void* base = NULL; uint32_t s = SysMapFile(HANDLE_TO_KH(hFileMappingObject), offset, dwNumberOfBytesToMap, WinFileMapAccessToSys(dwDesiredAccess), SYS_MAP_FLAG_NONE, &base); if (s != NTLSTATUS_SUCCESS) { gLastError = (s == NTLSTATUS_NOT_SUPPORTED) ? 120 : ((s == NTLSTATUS_NO_MEMORY) ? 8 : 87); return NULL; } return base; } __declspec(dllexport) BOOL UnmapViewOfFile(const void* lpBaseAddress) { if (!lpBaseAddress) { gLastError = 87; return FALSE; } uint32_t s = SysFreeVm((void*)lpBaseAddress); if (s != NTLSTATUS_SUCCESS) { gLastError = 87; return FALSE; } return TRUE; } __declspec(dllexport) BOOL FlushViewOfFile(const void* lpBaseAddress, size_t dwNumberOfBytesToFlush) { (void)dwNumberOfBytesToFlush; if (!lpBaseAddress) { gLastError = 87; return FALSE; } // Native flush is file-handle based for now; unmap/close also harvests dirty // PTEs, so FlushViewOfFile remains a successful cache-coherency hint. return TRUE; } // --- 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) == NTLSTATUS_SUCCESS && down; } // GetAsyncKeyState implementation over the canonical input key namespace. __declspec(dllexport) SHORT GetAsyncKeyState(int vKey) { if (vKey == 0x11) { // VK_CONTROL return (Win32IsInputKeyDown(INPUT_KEY_LEFT_CTRL) || Win32IsInputKeyDown(INPUT_KEY_RIGHT_CTRL)) ? (SHORT)0x8000 : 0; } if (vKey == 0x10) { // VK_SHIFT return (Win32IsInputKeyDown(INPUT_KEY_LEFT_SHIFT) || Win32IsInputKeyDown(INPUT_KEY_RIGHT_SHIFT)) ? (SHORT)0x8000 : 0; } if (vKey == 0x12) { // VK_MENU / ALT 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[] = { // Letters. { 0x41, INPUT_KEY_A }, { 0x42, INPUT_KEY_B }, { 0x43, INPUT_KEY_C }, { 0x44, INPUT_KEY_D }, { 0x45, INPUT_KEY_E }, { 0x46, INPUT_KEY_F }, { 0x47, INPUT_KEY_G }, { 0x48, INPUT_KEY_H }, { 0x49, INPUT_KEY_I }, { 0x4A, INPUT_KEY_J }, { 0x4B, INPUT_KEY_K }, { 0x4C, INPUT_KEY_L }, { 0x4D, INPUT_KEY_M }, { 0x4E, INPUT_KEY_N }, { 0x4F, INPUT_KEY_O }, { 0x50, INPUT_KEY_P }, { 0x51, INPUT_KEY_Q }, { 0x52, INPUT_KEY_R }, { 0x53, INPUT_KEY_S }, { 0x54, INPUT_KEY_T }, { 0x55, INPUT_KEY_U }, { 0x56, INPUT_KEY_V }, { 0x57, INPUT_KEY_W }, { 0x58, INPUT_KEY_X }, { 0x59, INPUT_KEY_Y }, { 0x5A, INPUT_KEY_Z }, // Numbers. { 0x31, INPUT_KEY_1 }, { 0x32, INPUT_KEY_2 }, { 0x33, INPUT_KEY_3 }, { 0x34, INPUT_KEY_4 }, { 0x35, INPUT_KEY_5 }, { 0x36, INPUT_KEY_6 }, { 0x37, INPUT_KEY_7 }, { 0x38, INPUT_KEY_8 }, { 0x39, INPUT_KEY_9 }, { 0x30, INPUT_KEY_0 }, // Arrows. { 0x26, INPUT_KEY_UP }, { 0x28, INPUT_KEY_DOWN }, { 0x25, INPUT_KEY_LEFT }, { 0x27, INPUT_KEY_RIGHT }, // Controls. { 0x1B, INPUT_KEY_ESCAPE }, { 0x0D, INPUT_KEY_ENTER }, { 0x20, INPUT_KEY_SPACE }, { 0x08, INPUT_KEY_BACKSPACE }, { 0x09, INPUT_KEY_TAB }, // Function Keys. { 0x70, INPUT_KEY_F1 }, { 0x71, INPUT_KEY_F2 }, { 0x72, INPUT_KEY_F3 }, { 0x73, INPUT_KEY_F4 }, { 0x74, INPUT_KEY_F5 }, { 0x75, INPUT_KEY_F6 }, { 0x76, INPUT_KEY_F7 }, { 0x77, INPUT_KEY_F8 }, { 0x78, INPUT_KEY_F9 }, { 0x79, INPUT_KEY_F10 }, { 0x7A, INPUT_KEY_F11 }, { 0x7B, INPUT_KEY_F12 }, // Symbols. { 0xBD, INPUT_KEY_MINUS }, { 0xBB, INPUT_KEY_EQUAL }, { 0xBC, INPUT_KEY_COMMA }, { 0xBE, INPUT_KEY_PERIOD }, }; for (size_t i = 0; i < sizeof(vk_to_key) / sizeof(vk_to_key[0]); ++i) { if (vk_to_key[i].vk == vKey) { if (Win32IsInputKeyDown(vk_to_key[i].key)) return (SHORT)0x8000; break; } } return 0; } // FlushConsoleInputBuffer: clear the keyboard input buffer. __declspec(dllexport) BOOL FlushConsoleInputBuffer(HANDLE hConsoleInput) { (void)hConsoleInput; // Drain the keyboard buffer by reading until empty. INPUT_KEY key; while (SysPollKeyboard(&key) == NTLSTATUS_SUCCESS) { char ignored; (void)SysReadKeyboardChar(&ignored); } return TRUE; } // !Made-up! clear console api. __declspec(dllexport) BOOL ClearConsoleScreenBuffer(HANDLE hConsole) { SysClearScreen(0x012456); return TRUE; } // Locale / code-page stubs. __declspec(dllexport) int MultiByteToWideChar(unsigned int cp, DWORD flags, const char* src, int srcLen, unsigned short* dst, int dstLen) { (void)cp; (void)flags; // Trivial ASCII -> UTF-16LE expansion, good enough for English strings. if (!src || !dstLen) return 0; if (srcLen < 0) srcLen = (int)strlen(src) + 1; int out = 0; while (out < dstLen && out < srcLen) { if (dst) dst[out] = (unsigned short)(unsigned char)src[out]; out++; } return out; } __declspec(dllexport) int WideCharToMultiByte(unsigned int cp, DWORD flags, const unsigned short* src, int srcLen, char* dst, int dstLen, const char* defChar, int* usedDefault) { (void)cp; (void)flags; (void)defChar; if (usedDefault) *usedDefault = FALSE; if (!src || !dstLen) return 0; if (srcLen < 0) { srcLen = 0; while (src[srcLen]) srcLen++; srcLen++; } int out = 0; while (out < dstLen && out < srcLen) { if (dst) dst[out] = (char)(src[out] < 128 ? src[out] : '?'); out++; } return out; } // Returns aCP. __declspec(dllexport) DWORD GetACP(void) { return 1252; } // Windows-1252 // Returns oEMCP. __declspec(dllexport) DWORD GetOEMCP(void) { return 437; } // DOS Latin US // Checks whether dBCS Lead Byte Ex. __declspec(dllexport) BOOL IsDBCSLeadByteEx(unsigned int CodePage, BYTE TestChar) { (void)CodePage; (void)TestChar; return FALSE; } // File I/O. // CreateFileA - opens or creates a file. // Supported modes: // OPEN_EXISTING + GENERIC_READ -> open existing, read-only // OPEN_EXISTING + GENERIC_WRITE -> open existing, read-write // OPEN_EXISTING + GENERIC_READ|GENERIC_WRITE -> open existing, read-write // CREATE_ALWAYS + GENERIC_WRITE -> create/truncate, write // OPEN_ALWAYS + GENERIC_WRITE -> create if absent, write // TRUNCATE_EXISTING + GENERIC_WRITE -> open & truncate to zero. __declspec(dllexport) HANDLE CreateFileA(const char* name, DWORD access, DWORD share, void* sa, DWORD disposition, DWORD flags, void* templ) { (void)share; (void)sa; (void)flags; (void)templ; // Translate the path from Windows format to custom 0:/ format. char translatedName[260]; TranslatePath(name, translatedName); 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; 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; } uint32_t kh = 0; uint32_t s = K32OpenFileNative(translatedName, sysAccess, sysDisposition, &kh); if (s != 0) { gLastError = (s == NTLSTATUS_OBJECT_NAME_COLLISION) ? 80 : (s == NTLSTATUS_NOT_FOUND) ? 2 : 5; 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 = 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); } // ReadFile - sequential read at the file's current position. __declspec(dllexport) BOOL ReadFile(HANDLE hFile, void* buf, DWORD toRead, DWORD* bytesRead, void* overlapped) { (void)overlapped; if (bytesRead) *bytesRead = 0; if (!hFile || hFile == INVALID_HANDLE_VALUE || !buf) { gLastError = 6; return FALSE; } size_t got = 0; SYS_FILE_IO_REQUEST req = SysMakeFileIoRequest(HANDLE_TO_KH(hFile), buf, (size_t)toRead, &got); uint32_t s = SysReadFile(&req); if (bytesRead) *bytesRead = (DWORD)got; if (s != 0) { gLastError = 1; return FALSE; } // Harden callers that accidentally look past *bytesRead. EOF/short reads // are legal for files, but do not touch the caller's remaining buffer after // a failed read because that can fault in megabytes under low memory. if (got < (size_t)toRead) memset((unsigned char*)buf + got, 0, (size_t)toRead - got); return TRUE; } // WriteFile - sequential write at the file's current position. // Extends the file if writing past EOF. Overlapped I/O is not supported. __declspec(dllexport) BOOL WriteFile(HANDLE hFile, const void* buf, DWORD toWrite, DWORD* bytesWritten, void* overlapped) { (void)overlapped; if (!hFile || hFile == INVALID_HANDLE_VALUE || !buf) { gLastError = 6; return FALSE; } size_t written = 0; SYS_FILE_IO_REQUEST req = SysMakeFileIoRequest(HANDLE_TO_KH(hFile), buf, (size_t)toWrite, &written); uint32_t s = SysWriteFile(&req); if (bytesWritten) *bytesWritten = (DWORD)written; if (s != 0) { gLastError = 29; return FALSE; } // ERROR_WRITE_FAULT return TRUE; } // SetFilePointer - seek to an absolute, relative, or end-relative position. // Returns new position low DWORD, or 0xFFFFFFFF on error. __declspec(dllexport) DWORD SetFilePointer(HANDLE hFile, long dist, long* distHigh, DWORD method) { if (!hFile || hFile == INVALID_HANDLE_VALUE) { gLastError = 6; return 0xFFFFFFFFUL; } uint32_t kh = HANDLE_TO_KH(hFile); int64_t delta; if (distHigh) { uint64_t combined = ((uint64_t)(uint32_t)(*distHigh) << 32) | (uint32_t)dist; delta = (int64_t)combined; } else { delta = (int64_t)dist; } int64_t target = 0; if (method == FILE_BEGIN) { target = delta; } else if (method == FILE_CURRENT) { 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 = 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; } if (target < 0) { gLastError = 131; // ERROR_NEGATIVE_SEEK return 0xFFFFFFFFUL; } uint64_t offset = (uint64_t)target; uint32_t s = SysSeekFile(kh, offset); if (s != 0) { gLastError = 1; return 0xFFFFFFFFUL; } if (distHigh) *distHigh = (long)(int32_t)(offset >> 32); return (DWORD)(offset & 0xFFFFFFFFULL); } // SetEndOfFile - truncate or extend the file to the current seek position. __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 = 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; } // DeleteFileA - delete a file by name; no open handle required. __declspec(dllexport) BOOL DeleteFileA(const char* lpFileName) { if (!lpFileName) { gLastError = 87; return FALSE; } char translatedPath[MAX_PATH]; TranslatePath(lpFileName, translatedPath); uint32_t s = K32DeleteFileNative(translatedPath); if (s != 0) { gLastError = 2; return FALSE; } return TRUE; } #define K32_MUTEX_MAGIC 0x58544D4Bu typedef struct K32_MUTEX_HANDLE { struct K32_MUTEX_HANDLE* Next; uint32_t Magic; volatile long StateLock; volatile long ApiUsers; uint32_t NativeHandle; DWORD OwnerTid; uint32_t Recursion; uint32_t Waiters; volatile long Closing; } K32_MUTEX_HANDLE; static K32_MUTEX_HANDLE* gK32MutexRegistry; static volatile long gK32MutexRegistryLock; // Acquires one short process-local mutex registry lock. static void K32MutexRegistryLock(void) { while (_InterlockedCompareExchange(&gK32MutexRegistryLock, 1, 0) != 0) (void)SysYield(); } // Releases the process-local mutex registry lock. static void K32MutexRegistryUnlock(void) { _InterlockedExchange(&gK32MutexRegistryLock, 0); } // Acquires one short mutex-wrapper state lock. static void K32MutexStateLock(K32_MUTEX_HANDLE* mutex) { while (_InterlockedCompareExchange(&mutex->StateLock, 1, 0) != 0) (void)SysYield(); } // Releases one mutex-wrapper state lock. static void K32MutexStateUnlock(K32_MUTEX_HANDLE* mutex) { _InterlockedExchange(&mutex->StateLock, 0); } // Registers one process-local Win32 mutex wrapper. static void K32RegisterMutex(K32_MUTEX_HANDLE* mutex) { K32MutexRegistryLock(); mutex->Next = gK32MutexRegistry; gK32MutexRegistry = mutex; K32MutexRegistryUnlock(); } // References one registered Win32 mutex without dereferencing unknown handles. static K32_MUTEX_HANDLE* K32ReferenceMutex(HANDLE handle) { K32_MUTEX_HANDLE* found = NULL; K32MutexRegistryLock(); for (K32_MUTEX_HANDLE* current = gK32MutexRegistry; current; current = current->Next) { if ((HANDLE)current == handle && current->Magic == K32_MUTEX_MAGIC && _InterlockedCompareExchange(¤t->Closing, 0, 0) == 0) { _InterlockedIncrement(¤t->ApiUsers); found = current; break; } } K32MutexRegistryUnlock(); return found; } // Releases one mutex-wrapper API reference. static void K32DereferenceMutex(K32_MUTEX_HANDLE* mutex) { if (mutex) _InterlockedDecrement(&mutex->ApiUsers); } // Removes one mutex wrapper so no new API references can be acquired. static BOOL K32RemoveMutex(K32_MUTEX_HANDLE* mutex) { BOOL removed = FALSE; K32MutexRegistryLock(); K32_MUTEX_HANDLE** link = &gK32MutexRegistry; while (*link) { if (*link == mutex) { *link = mutex->Next; mutex->Next = NULL; removed = TRUE; break; } link = &(*link)->Next; } K32MutexRegistryUnlock(); return removed; } // Waits on one recursive Win32 mutex wrapper. static DWORD K32WaitMutex(K32_MUTEX_HANDLE* mutex, DWORD milliseconds) { DWORD tid = K32CurrentTidOrOne(); K32MutexStateLock(mutex); if (_InterlockedCompareExchange(&mutex->Closing, 0, 0) != 0) { K32MutexStateUnlock(mutex); gLastError = 6; return 0xFFFFFFFFUL; } if (mutex->OwnerTid == tid) { if (mutex->Recursion == UINT32_MAX) { K32MutexStateUnlock(mutex); gLastError = 8; return 0xFFFFFFFFUL; } mutex->Recursion++; K32MutexStateUnlock(mutex); return 0; } mutex->Waiters++; K32MutexStateUnlock(mutex); uint64_t timeout = milliseconds == 0xFFFFFFFFUL ? SYS_WAIT_TIMEOUT_INFINITE : (uint64_t)milliseconds; uint32_t status = SysWaitSingle(mutex->NativeHandle, SYS_WAIT_FLAG_NONE, timeout); K32MutexStateLock(mutex); if (mutex->Waiters) mutex->Waiters--; if (status == NTLSTATUS_SUCCESS || status == NTLSTATUS_ABANDONED) { mutex->OwnerTid = tid; mutex->Recursion = 1; } K32MutexStateUnlock(mutex); if (status == NTLSTATUS_SUCCESS) return 0; if (status == NTLSTATUS_ABANDONED) return 0x00000080UL; if (status == NTLSTATUS_TIMEOUT) return 0x00000102UL; gLastError = 6; return 0xFFFFFFFFUL; } // Closes one idle Win32 mutex wrapper. static BOOL K32CloseMutex(K32_MUTEX_HANDLE* mutex) { K32MutexStateLock(mutex); BOOL busy = mutex->OwnerTid != 0 || mutex->Waiters != 0; if (!busy && _InterlockedCompareExchange(&mutex->Closing, 1, 0) != 0) busy = TRUE; K32MutexStateUnlock(mutex); if (busy) { gLastError = 170; K32DereferenceMutex(mutex); return FALSE; } if (!K32RemoveMutex(mutex)) { gLastError = 6; K32DereferenceMutex(mutex); return FALSE; } while (mutex->ApiUsers > 1) (void)SysYield(); uint32_t status = SysCloseHandle(mutex->NativeHandle); mutex->Magic = 0; K32DereferenceMutex(mutex); free(mutex); if (status != NTLSTATUS_SUCCESS) { gLastError = 6; return FALSE; } return TRUE; } // Closes one Win32 or native kernel handle. __declspec(dllexport) BOOL CloseHandle(HANDLE hObject) { if (!hObject || hObject == INVALID_HANDLE_VALUE) { gLastError = 6; return FALSE; } K32_MUTEX_HANDLE* mutex = K32ReferenceMutex(hObject); if (mutex) return K32CloseMutex(mutex); uint32_t status = SysCloseHandle(HANDLE_TO_KH(hObject)); if (status != NTLSTATUS_SUCCESS) { gLastError = 6; return FALSE; } return TRUE; } // Extended shims - funcs.txt additions // All functions here return plausible values; no real implementation exists // unless a matching syscall stub is available. // Additional Heap APIs // We have one kernel heap; the HANDLE is always ignored. typedef int HEAP_INFORMATION_CLASS; // opaque __declspec(dllexport) HANDLE HeapCreate(DWORD flOptions, size_t dwInitialSize, size_t dwMaximumSize) { (void)flOptions; (void)dwInitialSize; (void)dwMaximumSize; return (HANDLE)(uintptr_t)1; // non-NULL sentinel } // Implements the heap Destroy operation. __declspec(dllexport) BOOL HeapDestroy(HANDLE hHeap) { (void)hHeap; return TRUE; } // Implements the heap Size operation. __declspec(dllexport) size_t HeapSize(HANDLE heap, DWORD flags, const void* ptr) { (void)heap; (void)flags; size_t size = _malloc_usable_size(ptr); if (size == (size_t)-1) gLastError = 87; // ERROR_INVALID_PARAMETER return size; } __declspec(dllexport) BOOL HeapSetInformation(HANDLE HeapHandle, HEAP_INFORMATION_CLASS cls, void* info, size_t infoLen) { (void)HeapHandle; (void)cls; (void)info; (void)infoLen; return TRUE; } // Process & Module pseudo-handles / queries. // Pseudo-handles matching Windows convention: -1 = process, -2 = thread. __declspec(dllexport) HANDLE GetCurrentProcess(void) { return (HANDLE)(uintptr_t)(~(uintptr_t)0); } // Returns current Thread. __declspec(dllexport) HANDLE GetCurrentThread(void) { return (HANDLE)(uintptr_t)(~(uintptr_t)1); } // Returns current Thread Id. __declspec(dllexport) DWORD GetCurrentThreadId(void) { return (DWORD)SysGetCurrentTid(); } // Returns current Process Id. __declspec(dllexport) DWORD GetCurrentProcessId(void) { return (DWORD)SysGetCurrentPid(); } // Tiny TLS index allocator; slot values are stored per thread in WIN32_THREAD_ENV. static uint64_t gTlsBitmap = 1; // reserve slot 0 // Implements the tls Alloc operation. __declspec(dllexport) DWORD TlsAlloc(void) { for (DWORD i = 1; i < WIN32_TLS_SLOTS; i++) { uint64_t bit = 1ULL << i; if (!(gTlsBitmap & bit)) { gTlsBitmap |= bit; return i; } } gLastError = 8; return 0xFFFFFFFFUL; } // Implements the tls Free operation. __declspec(dllexport) BOOL TlsFree(DWORD dwTlsIndex) { if (dwTlsIndex >= WIN32_TLS_SLOTS || !(gTlsBitmap & (1ULL << dwTlsIndex))) { gLastError = 87; return FALSE; } WIN32_THREAD_ENV* env = K32ThreadEnv(); if (env) env->TlsSlots[dwTlsIndex] = NULL; gTlsBitmap &= ~(1ULL << dwTlsIndex); return TRUE; } // Implements the tls Get Value operation. __declspec(dllexport) void* TlsGetValue(DWORD dwTlsIndex) { if (dwTlsIndex >= WIN32_TLS_SLOTS || !(gTlsBitmap & (1ULL << dwTlsIndex))) { gLastError = 87; return NULL; } WIN32_THREAD_ENV* env = K32ThreadEnv(); gLastError = 0; return env->TlsSlots[dwTlsIndex]; } // Implements the tls Set Value operation. __declspec(dllexport) BOOL TlsSetValue(DWORD dwTlsIndex, void* lpTlsValue) { if (dwTlsIndex >= WIN32_TLS_SLOTS || !(gTlsBitmap & (1ULL << dwTlsIndex))) { gLastError = 87; return FALSE; } WIN32_THREAD_ENV* env = K32ThreadEnv(); env->TlsSlots[dwTlsIndex] = lpTlsValue; return TRUE; } // Pseudo HMODULEs for callers that probe already-linked personality DLLs. #define WIN32_HMODULE_EXE ((HANDLE)(uintptr_t)0x00400000UL) #define WIN32_HMODULE_WIN32 ((HANDLE)(uintptr_t)0x57333232UL) // W322 // Implements the stricmp A operation. static int KiStricmpA(const char* a, const char* b) { while (*a && (((unsigned char)*a | 0x20) == ((unsigned char)*b | 0x20))) { a++; b++; } return ((unsigned char)*a | 0x20) - ((unsigned char)*b | 0x20); } // Matches one Win32 module basename with its optional DLL suffix. static BOOL KiMatchesWin32DllNameA(const char* name, const char* baseName) { if (!name || !baseName) return FALSE; while (*name && *baseName && (((unsigned char)*name | 0x20u) == ((unsigned char)*baseName | 0x20u))) { name++; baseName++; } if (*baseName) return FALSE; if (!*name) return TRUE; return KiStricmpA(name, ".dll") == 0; } // Checks whether one name identifies a process-local Win32 personality module. static BOOL KiIsWin32DllNameA(const char* name) { return KiMatchesWin32DllNameA(name, "kernel32") || KiMatchesWin32DllNameA(name, "user32") || KiMatchesWin32DllNameA(name, "gdi32") || KiMatchesWin32DllNameA(name, "ole32") || KiMatchesWin32DllNameA(name, "winmm") || KiMatchesWin32DllNameA(name, "win32"); } // Implements the dbg Write A operation. static void KiDbgWriteA(const char* s) { if (s) K32WriteConsoleSpan(s, strlen(s)); } // Returns the process-local module handle for one ANSI module name. __declspec(dllexport) HANDLE GetModuleHandleA(const char* lpModuleName) { if (!lpModuleName) return WIN32_HMODULE_EXE; if (KiIsWin32DllNameA(lpModuleName)) return WIN32_HMODULE_WIN32; gLastError = 126; // ERROR_MOD_NOT_FOUND. return NULL; } // Returns module Handle W. __declspec(dllexport) HANDLE GetModuleHandleW(const unsigned short* lpModuleName) { return lpModuleName ? NULL : WIN32_HMODULE_EXE; } // Loads a user-mode DLL through the native module loader. __declspec(dllexport) HANDLE LoadLibraryA(const char* lpLibFileName) { if (KiIsWin32DllNameA(lpLibFileName)) return WIN32_HMODULE_WIN32; if (!lpLibFileName) { gLastError = 87; return NULL; } uint32_t handle = 0; SYS_LOAD_MODULE_REQUEST req; memset(&req, 0, sizeof(req)); req.Size = sizeof(req); req.Path = SysSvFromCstr(lpLibFileName); req.ModuleHandleOut = &handle; uint32_t status = SysLoadModule(&req); if (status != NTLSTATUS_SUCCESS) { gLastError = 126; return NULL; } return (HANDLE)(uintptr_t)handle; } // GetProcAddress handles both built-in win32 exports and native module handles. __declspec(dllexport) BOOL FreeLibrary(HANDLE hLibModule); __declspec(dllexport) void Sleep(DWORD dwMilliseconds); __declspec(dllexport) BOOL GetConsoleScreenBufferInfo(HANDLE hConsoleOutput, CONSOLE_SCREEN_BUFFER_INFO* lpConsoleScreenBufferInfo); __declspec(dllexport) BOOL FillConsoleOutputCharacterA(HANDLE hConsoleOutput, char cCharacter, DWORD nLength, COORD dwWriteCoord, DWORD* lpNumberOfCharsWritten); __declspec(dllexport) BOOL FillConsoleOutputAttribute(HANDLE hConsoleOutput, WORD wAttribute, DWORD nLength, COORD dwWriteCoord, DWORD* lpNumberOfAttrsWritten); __declspec(dllexport) BOOL SetConsoleCursorPosition(HANDLE hConsoleOutput, COORD dwCursorPosition); // Returns proc Address. __declspec(dllexport) void* GetProcAddress(HANDLE hModule, const char* lpProcName) { if (!hModule || !lpProcName) { gLastError = 127; return NULL; } // Ordinal probes are represented as small integer pointers. Do not treat // them as strings while debugging misses. if ((uintptr_t)lpProcName < 0x10000) { KiDbgWriteA("GetProcAddress ordinal miss\n"); gLastError = 127; return NULL; } if (hModule != WIN32_HMODULE_WIN32) { uintptr_t address = 0; SYS_GET_MODULE_EXPORT_REQUEST req; memset(&req, 0, sizeof(req)); req.Size = sizeof(req); req.ModuleHandle = (uint32_t)(uintptr_t)hModule; req.Name = SysSvFromCstr(lpProcName); req.AddressOut = &address; uint32_t status = SysGetModuleExport(&req); if (status != NTLSTATUS_SUCCESS || !address) { gLastError = 127; return NULL; } return (void*)address; } #define GP(name) do { \ if (strcmp(lpProcName, #name) == 0) return (void*)&name; \ } while (0) GP(GetLastError); GP(SetLastError); GP(LoadLibraryA); GP(GetProcAddress); GP(IsDebuggerPresent); GP(FreeLibrary); GP(VirtualAlloc); GP(VirtualFree); GP(VirtualProtect); GP(VirtualQuery); GP(GetTickCount); GP(GetTickCount64); GP(Sleep); GP(CreateEventA); GP(CreateEventW); GP(SetEvent); GP(ResetEvent); GP(CreateThread); GP(ExitThread); GP(WaitForSingleObject); GP(CreateMutexA); GP(CreateMutexW); GP(ReleaseMutex); GP(CloseHandle); GP(InitializeCriticalSection); GP(InitializeCriticalSectionAndSpinCount); GP(DeleteCriticalSection); GP(EnterCriticalSection); GP(LeaveCriticalSection); GP(TryEnterCriticalSection); GP(InitializeConditionVariable); GP(SleepConditionVariableCS); GP(WakeConditionVariable); GP(WakeAllConditionVariable); GP(TlsAlloc); GP(TlsFree); GP(TlsGetValue); GP(TlsSetValue); GP(GetConsoleScreenBufferInfo); GP(FillConsoleOutputCharacterA); GP(FillConsoleOutputAttribute); GP(SetConsoleCursorPosition); GP(waveOutGetNumDevs); GP(waveOutOpen); GP(waveOutClose); GP(waveOutPrepareHeader); GP(waveOutUnprepareHeader); GP(waveOutWrite); GP(waveOutPause); GP(waveOutRestart); GP(waveOutReset); GP(waveOutSetVolume); GP(waveOutGetVolume); GP(waveOutGetPosition); GP(waveOutGetID); GP(waveOutGetDevCapsA); GP(waveOutGetDevCapsW); GP(waveOutGetErrorTextA); GP(waveOutGetErrorTextW); GP(waveOutBreakLoop); GP(waveOutMessage); GP(timeGetTime); GP(timeBeginPeriod); GP(timeEndPeriod); #undef GP KiDbgWriteA("GetProcAddress miss: "); KiDbgWriteA(lpProcName); KiDbgWriteA("\n"); gLastError = 127; // ERROR_PROC_NOT_FOUND return NULL; } // Releases one native module handle returned by LoadLibraryA. __declspec(dllexport) BOOL FreeLibrary(HANDLE hLibModule) { if (!hLibModule || hLibModule == WIN32_HMODULE_WIN32 || hLibModule == WIN32_HMODULE_EXE) return TRUE; uint32_t status = SysUnloadModule((uint32_t)(uintptr_t)hLibModule); if (status != NTLSTATUS_SUCCESS) { gLastError = 126; return FALSE; } return TRUE; } __declspec(dllexport) DWORD GetModuleFileNameA(HANDLE hModule, char* lpFilename, DWORD nSize) { (void)hModule; if (!lpFilename || !nSize) return 0; SYS_PEB* peb = Win32Peb(); const char* src = (peb && peb->Magic == SYS_PEB_MAGIC && peb->ImagePath.Data) ? peb->ImagePath.Data : ""; DWORD len = (DWORD)strlen(src); DWORD copy = (len < nSize - 1) ? len : nSize - 1; memcpy(lpFilename, src, copy); lpFilename[copy] = '\0'; if (copy < len) gLastError = 122; // ERROR_INSUFFICIENT_BUFFER return copy; } // Implements the terminate Process operation. __declspec(dllexport) BOOL TerminateProcess(HANDLE hProcess, unsigned int uExitCode) { if (hProcess == GetCurrentProcess()) { SysExitProcess((int32_t)uExitCode); while (true) ; } if (!hProcess) { gLastError = 6; // ERROR_INVALID_HANDLE return FALSE; } uint32_t s = SysKillProcess(HANDLE_TO_KH(hProcess), (int32_t)uExitCode); if (s != 0) { gLastError = (s == NTLSTATUS_INVALID_HANDLE) ? 6 : 5; return FALSE; } return TRUE; } // STARTUPINFOA - only cb matters for our stub. typedef struct { DWORD cb; char* lpReserved; char* lpDesktop; char* lpTitle; DWORD dwX, dwY, dwXSize, dwYSize; DWORD dwXCountChars, dwYCountChars; DWORD dwFillAttribute, dwFlags; unsigned short wShowWindow, cbReserved2; unsigned char* lpReserved2; HANDLE hStdInput, hStdOutput, hStdError; } STARTUPINFOA; // Returns startup Info A. __declspec(dllexport) void GetStartupInfoA(STARTUPINFOA* lpStartupInfo) { if (!lpStartupInfo) return; // Zero every field, then set the mandatory cb. unsigned char* p = (unsigned char*)lpStartupInfo; for (size_t i = 0; i < sizeof(*lpStartupInfo); i++) p[i] = 0; lpStartupInfo->cb = (DWORD)sizeof(*lpStartupInfo); } // Returns command Line A. __declspec(dllexport) char* GetCommandLineA(void) { SYS_PEB* peb = Win32Peb(); if (!peb || peb->Magic != SYS_PEB_MAGIC || !peb->CommandLine.Data) return ""; return (char*)peb->CommandLine.Data; } // Threading. #define WAIT_OBJECT_0 0x00000000UL #define WAIT_TIMEOUT 0x00000102UL #define INFINITE 0xFFFFFFFFUL #define CREATE_SUSPENDED 0x00000004UL typedef DWORD (__stdcall *K32_THREAD_START_ROUTINE)(void* parameter); typedef struct K32_THREAD_START_CONTEXT { K32_THREAD_START_ROUTINE StartRoutine; void* Parameter; } K32_THREAD_START_CONTEXT; // Invokes one Win32 thread procedure and terminates the native thread on return. static void K32ThreadStart(uintptr_t argument) { K32_THREAD_START_CONTEXT* context = (K32_THREAD_START_CONTEXT*)argument; K32_THREAD_START_ROUTINE startRoutine = context->StartRoutine; void* parameter = context->Parameter; free(context); DWORD exitCode = startRoutine(parameter); SysExitThread((int32_t)exitCode); while (true) { (void)SysYield(); } } // Creates one Win32 thread with return-to-ExitThread semantics. __declspec(dllexport) HANDLE CreateThread(void* lpThreadAttributes, size_t dwStackSize, void* lpStartAddress, void* lpParameter, DWORD dwCreationFlags, DWORD* lpThreadId) { (void)lpThreadAttributes; (void)dwStackSize; if (!lpStartAddress || (dwCreationFlags & ~CREATE_SUSPENDED)) { gLastError = 87; return NULL; } K32_THREAD_START_CONTEXT* context = (K32_THREAD_START_CONTEXT*)malloc(sizeof(*context)); if (!context) { gLastError = 8; return NULL; } context->StartRoutine = (K32_THREAD_START_ROUTINE)lpStartAddress; context->Parameter = lpParameter; uint32_t tid = 0; uint32_t kh = 0; SYS_CREATE_THREAD_REQUEST req = { (uintptr_t)K32ThreadStart, (uintptr_t)context, 0, (dwCreationFlags & CREATE_SUSPENDED) ? SYS_CREATE_THREAD_FLAG_SUSPENDED : SYS_CREATE_THREAD_FLAG_NONE, &kh, &tid }; uint32_t status = SysCreateThread(&req); if (status != NTLSTATUS_SUCCESS) { free(context); gLastError = status == NTLSTATUS_NO_MEMORY ? 8 : 11; return NULL; } if (lpThreadId) *lpThreadId = (DWORD)tid; return KH_TO_HANDLE(kh); } // Terminates the calling Win32 thread with the supplied exit code. __declspec(dllexport) _Noreturn void ExitThread(DWORD exitCode) { SysExitThread((int32_t)exitCode); while (true) { (void)SysYield(); } } // Waits for one Win32 mutex wrapper or native waitable handle. __declspec(dllexport) DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) { if (!hHandle || hHandle == INVALID_HANDLE_VALUE) { gLastError = 6; return 0xFFFFFFFFUL; } K32_MUTEX_HANDLE* mutex = K32ReferenceMutex(hHandle); if (mutex) { DWORD result = K32WaitMutex(mutex, dwMilliseconds); K32DereferenceMutex(mutex); return result; } if (!IS_VALID_KERNEL_HANDLE(hHandle)) { gLastError = 6; return 0xFFFFFFFFUL; } uint64_t timeout = dwMilliseconds == INFINITE ? SYS_WAIT_TIMEOUT_INFINITE : (uint64_t)dwMilliseconds; uint32_t s = SysWaitSingle(HANDLE_TO_KH(hHandle), SYS_WAIT_FLAG_NONE, timeout); if (s == NTLSTATUS_SUCCESS) return WAIT_OBJECT_0; if (s == NTLSTATUS_ABANDONED) return 0x00000080UL; if (s == NTLSTATUS_TIMEOUT) return WAIT_TIMEOUT; gLastError = 6; return 0xFFFFFFFFUL; } // Creates one unnamed native event with Win32 reset semantics. __declspec(dllexport) HANDLE CreateEventA(void* lpEventAttributes, BOOL bManualReset, BOOL bInitialState, const char* lpName) { (void)lpEventAttributes; if (lpName && lpName[0]) { gLastError = 120; return NULL; } uint32_t handle = 0; uint32_t status = SysCreateEvent(bManualReset ? 1u : 0u, bInitialState ? 1u : 0u, &handle); if (status != NTLSTATUS_SUCCESS) { gLastError = status == NTLSTATUS_NO_MEMORY ? 8 : 87; return NULL; } return KH_TO_HANDLE(handle); } // Creates one unnamed native event from the wide Win32 entry point. __declspec(dllexport) HANDLE CreateEventW(void* lpEventAttributes, BOOL bManualReset, BOOL bInitialState, const unsigned short* lpName) { if (lpName && lpName[0]) { gLastError = 120; return NULL; } return CreateEventA(lpEventAttributes, bManualReset, bInitialState, NULL); } // Signals one native event. __declspec(dllexport) BOOL SetEvent(HANDLE hEvent) { if (!IS_VALID_KERNEL_HANDLE(hEvent)) { gLastError = 6; return FALSE; } uint32_t status = SysSignalEvent(HANDLE_TO_KH(hEvent)); if (status != NTLSTATUS_SUCCESS) { gLastError = 6; return FALSE; } return TRUE; } // Clears one native event. __declspec(dllexport) BOOL ResetEvent(HANDLE hEvent) { if (!IS_VALID_KERNEL_HANDLE(hEvent)) { gLastError = 6; return FALSE; } uint32_t status = SysClearEvent(HANDLE_TO_KH(hEvent)); if (status != NTLSTATUS_SUCCESS) { gLastError = 6; return FALSE; } return TRUE; } // 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; while (*commandLine == ' ' || *commandLine == '\t') commandLine++; if (*commandLine == '\0') return FALSE; size_t pos = 0; if (*commandLine == '"') { commandLine++; while (*commandLine && *commandLine != '"' && pos + 1 < outSize) out[pos++] = *commandLine++; } else { while (*commandLine && *commandLine != ' ' && *commandLine != '\t' && pos + 1 < outSize) out[pos++] = *commandLine++; } out[pos] = '\0'; return pos != 0; } // Process creation. typedef struct { HANDLE hProcess; HANDLE hThread; DWORD dwProcessId; DWORD dwThreadId; } PROCESS_INFORMATION; #define STILL_ACTIVE 259UL __declspec(dllexport) BOOL CreateProcessA( const char* lpApplicationName, char* lpCommandLine, void* lpProcessAttributes, void* lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, void* lpEnvironment, const char* lpCurrentDirectory, STARTUPINFOA* lpStartupInfo, PROCESS_INFORMATION* lpProcessInformation) { (void)lpProcessAttributes; (void)lpThreadAttributes; (void)bInheritHandles; (void)dwCreationFlags; (void)lpEnvironment; (void)lpStartupInfo; // lpProcessInformation is mandatory. if (!lpProcessInformation) { gLastError = 87; // ERROR_INVALID_PARAMETER return FALSE; } char appPath[MAX_PATH]; const char* targetPath = lpApplicationName; if (!targetPath) { if (!ExtractApplicationPathA(lpCommandLine, appPath, sizeof(appPath))) { gLastError = 87; return FALSE; } targetPath = appPath; } const char* cmdline = (lpCommandLine && lpCommandLine[0]) ? lpCommandLine : targetPath; char translatedPath[MAX_PATH]; TranslatePath(targetPath, translatedPath); char savedCwd[SYS_CWD_MAX]; bool changedCwd = false; savedCwd[0] = '\0'; if (lpCurrentDirectory && lpCurrentDirectory[0]) { char translatedCwd[MAX_PATH]; uint32_t gs = K32GetCwdNative(savedCwd, sizeof(savedCwd), NULL); if (gs != 0) { gLastError = 3; return FALSE; } TranslatePath(lpCurrentDirectory, translatedCwd); gs = K32SetCwdNative(translatedCwd); if (gs != 0) { gLastError = 3; return FALSE; } changedCwd = true; } uint32_t kh = 0; // Call the syscall.dll stub. The kernel snapshots the current CWD into // the child process, so the temporary lpCurrentDirectory switch can be // restored immediately after creation. uint32_t s = K32CreateProcessNative(translatedPath, &kh, cmdline); if (changedCwd) { if (savedCwd[0]) { char restoreCwd[SYS_CWD_MAX + 3]; restoreCwd[0] = '0'; restoreCwd[1] = ':'; restoreCwd[2] = '/'; size_t rlen = strlen(savedCwd); if (rlen + 4 > sizeof(restoreCwd)) rlen = sizeof(restoreCwd) - 4; memcpy(restoreCwd + 3, savedCwd, rlen); restoreCwd[3 + rlen] = '\0'; K32SetCwdNative(restoreCwd); } else { K32SetCwdNative("0:/"); } } if (s != 0 || kh == 0) { gLastError = 2; // ERROR_FILE_NOT_FOUND return FALSE; } lpProcessInformation->hProcess = KH_TO_HANDLE(kh); lpProcessInformation->hThread = INVALID_HANDLE_VALUE; lpProcessInformation->dwProcessId = 0; lpProcessInformation->dwThreadId = 0; return TRUE; } // Returns exit Code Process. __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 int32_t code = 0; uint32_t s = SysGetProcessExitCode(kh, &code); if (s != 0) { gLastError = 6; return FALSE; } *lpExitCode = (DWORD)code; return TRUE; } // Decrements a thread's suspend count and makes it runnable at zero. __declspec(dllexport) DWORD ResumeThread(HANDLE hThread) { if (!hThread || hThread == INVALID_HANDLE_VALUE) { gLastError = 6; return 0xFFFFFFFFu; } uint32_t previousSuspendCount = 0; uint32_t status = SysResumeThread(HANDLE_TO_KH(hThread), &previousSuspendCount); if (status != NTLSTATUS_SUCCESS) { gLastError = status == NTLSTATUS_ACCESS_DENIED ? 5 : 6; return 0xFFFFFFFFu; } return previousSuspendCount; } #define THREAD_PRIORITY_NORMAL 0 // Updates thread Priority. __declspec(dllexport) BOOL SetThreadPriority(HANDLE hThread, int nPriority) { (void)hThread; (void)nPriority; return TRUE; } // Returns thread Priority. __declspec(dllexport) int GetThreadPriority(HANDLE hThread) { (void)hThread; return THREAD_PRIORITY_NORMAL; } __declspec(dllexport) uintptr_t SetThreadAffinityMask(HANDLE hThread, uintptr_t dwThreadAffinityMask) { (void)hThread; (void)dwThreadAffinityMask; return 1; // previous mask: CPU 0 only } // Implements the sleep operation. __declspec(dllexport) void Sleep(DWORD dwMilliseconds) { SysSleep(dwMilliseconds); } // Console I/O. #define STD_INPUT_HANDLE ((DWORD)-10) #define STD_OUTPUT_HANDLE ((DWORD)-11) #define STD_ERROR_HANDLE ((DWORD)-12) // Implements the k32 Is Std Handle Value operation. static BOOL K32IsStdHandleValue(HANDLE h, DWORD stdHandle) { uintptr_t value = (uintptr_t)h; return value == (uintptr_t)stdHandle || value == (uintptr_t)(intptr_t)(int32_t)stdHandle; } // Implements the k32 Is Console Output Handle operation. static BOOL K32IsConsoleOutputHandle(HANDLE h) { return h && h != INVALID_HANDLE_VALUE && (K32IsStdHandleValue(h, STD_OUTPUT_HANDLE) || K32IsStdHandleValue(h, STD_ERROR_HANDLE)); } // Implements the k32 Set Console Last Error operation. static void K32SetConsoleLastError(uint32_t status) { switch (status) { case NTLSTATUS_SUCCESS: gLastError = 0; break; case NTLSTATUS_INVALID_PARAMETER: gLastError = 87; break; case NTLSTATUS_NO_MEMORY: gLastError = 8; break; default: gLastError = 1; break; } } // We have no real console handles; return a sentinel the other APIs recognise. __declspec(dllexport) HANDLE GetStdHandle(DWORD nStdHandle) { return (HANDLE)(uintptr_t)nStdHandle; } // ReadConsoleA: blocking read of up to nNumberOfCharsToRead characters. // Each character is read individually via SysReadKeyboardChar so the caller can // do its own line-editing (echo, backspace, etc.) one char at a time. __declspec(dllexport) BOOL ReadConsoleA(HANDLE hConsoleInput, void* lpBuffer, DWORD nNumberOfCharsToRead, DWORD* lpNumberOfCharsRead, void* pInputControl) { (void)hConsoleInput; (void)pInputControl; if (!lpBuffer || nNumberOfCharsToRead == 0) return FALSE; char* buf = (char*)lpBuffer; DWORD i = 0; // Notice we switched to a while loop while (i < nNumberOfCharsToRead) { char c = 0; if (SysReadKeyboardChar(&c) != NTLSTATUS_SUCCESS) continue; // Ignore unmapped keys (Shift, Ctrl, etc.). if (c == 0) continue; // Deliver the raw character; the caller handles echo and line editing. buf[i] = c; i++; // 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, // you might want to replace buf[i-1] with \0 here! break; } } if (lpNumberOfCharsRead) *lpNumberOfCharsRead = i; return TRUE; } // WriteConsoleA: write nNumberOfCharsToWrite characters from lpBuffer to the // console as white-on-black text via SYS_WRITE_CONSOLE. __declspec(dllexport) BOOL WriteConsoleA(HANDLE hConsoleOutput, const void* lpBuffer, DWORD nNumberOfCharsToWrite, DWORD* lpNumberOfCharsWritten, void* lpReserved) { (void)hConsoleOutput; (void)lpReserved; if (!lpBuffer || nNumberOfCharsToWrite == 0) { if (lpNumberOfCharsWritten) *lpNumberOfCharsWritten = 0; return TRUE; } K32WriteConsoleSpan((const char*)lpBuffer, (size_t)nNumberOfCharsToWrite); if (lpNumberOfCharsWritten) *lpNumberOfCharsWritten = nNumberOfCharsToWrite; return TRUE; } __declspec(dllexport) BOOL GetConsoleScreenBufferInfo(HANDLE hConsoleOutput, CONSOLE_SCREEN_BUFFER_INFO* lpConsoleScreenBufferInfo) { if (!K32IsConsoleOutputHandle(hConsoleOutput)) { gLastError = 6; return FALSE; } if (!lpConsoleScreenBufferInfo) { gLastError = 87; return FALSE; } SYS_CONSOLE_INFO info; uint32_t s = SysGetConsoleInfo(&info); if (s != NTLSTATUS_SUCCESS) { K32SetConsoleLastError(s); return FALSE; } memset(lpConsoleScreenBufferInfo, 0, sizeof(*lpConsoleScreenBufferInfo)); lpConsoleScreenBufferInfo->dwSize.X = (SHORT)info.Columns; lpConsoleScreenBufferInfo->dwSize.Y = (SHORT)info.Rows; lpConsoleScreenBufferInfo->dwCursorPosition.X = (SHORT)info.CursorX; lpConsoleScreenBufferInfo->dwCursorPosition.Y = (SHORT)info.CursorY; lpConsoleScreenBufferInfo->wAttributes = (WORD)info.Attribute; lpConsoleScreenBufferInfo->srWindow.Left = 0; lpConsoleScreenBufferInfo->srWindow.Top = 0; lpConsoleScreenBufferInfo->srWindow.Right = info.Columns ? (SHORT)(info.Columns - 1u) : 0; lpConsoleScreenBufferInfo->srWindow.Bottom = info.Rows ? (SHORT)(info.Rows - 1u) : 0; lpConsoleScreenBufferInfo->dwMaximumWindowSize = lpConsoleScreenBufferInfo->dwSize; return TRUE; } __declspec(dllexport) BOOL SetConsoleCursorPosition(HANDLE hConsoleOutput, COORD dwCursorPosition) { if (!K32IsConsoleOutputHandle(hConsoleOutput)) { gLastError = 6; return FALSE; } if (dwCursorPosition.X < 0 || dwCursorPosition.Y < 0) { gLastError = 87; return FALSE; } uint32_t s = SysSetConsoleCursor((int)dwCursorPosition.X, (int)dwCursorPosition.Y); if (s != NTLSTATUS_SUCCESS) { K32SetConsoleLastError(s); return FALSE; } return TRUE; } __declspec(dllexport) BOOL FillConsoleOutputCharacterA(HANDLE hConsoleOutput, char cCharacter, DWORD nLength, COORD dwWriteCoord, DWORD* lpNumberOfCharsWritten) { if (lpNumberOfCharsWritten) *lpNumberOfCharsWritten = 0; if (!K32IsConsoleOutputHandle(hConsoleOutput)) { gLastError = 6; return FALSE; } if (dwWriteCoord.X < 0 || dwWriteCoord.Y < 0) { gLastError = 87; return FALSE; } if (nLength == 0) return TRUE; size_t written = 0; uint32_t s = SysFillConsoleCharacter(cCharacter, (int)dwWriteCoord.X, (int)dwWriteCoord.Y, (size_t)nLength, &written); if (lpNumberOfCharsWritten) *lpNumberOfCharsWritten = (DWORD)written; if (s != NTLSTATUS_SUCCESS) { K32SetConsoleLastError(s); return FALSE; } return TRUE; } __declspec(dllexport) BOOL FillConsoleOutputAttribute(HANDLE hConsoleOutput, WORD wAttribute, DWORD nLength, COORD dwWriteCoord, DWORD* lpNumberOfAttrsWritten) { if (lpNumberOfAttrsWritten) *lpNumberOfAttrsWritten = 0; if (!K32IsConsoleOutputHandle(hConsoleOutput)) { gLastError = 6; return FALSE; } if (dwWriteCoord.X < 0 || dwWriteCoord.Y < 0) { gLastError = 87; return FALSE; } if (nLength == 0) return TRUE; size_t written = 0; uint32_t s = SysFillConsoleAttribute(wAttribute, (int)dwWriteCoord.X, (int)dwWriteCoord.Y, (size_t)nLength, &written); if (lpNumberOfAttrsWritten) *lpNumberOfAttrsWritten = (DWORD)written; if (s != NTLSTATUS_SUCCESS) { K32SetConsoleLastError(s); return FALSE; } return TRUE; } // 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 // handle, so FindClose must NOT go through CloseHandle/SysCloseHandle. typedef struct { uint32_t kh; // kernel DIR_OBJECT handle (raw pointer) char pattern[MAX_PATH]; // wildcard pattern, e.g. "*" or "*.txt" } FIND_HANDLE; // Minimal wildcard match: supports '*' (any sequence) and '?' (any char). // Case-insensitive to match FAT32/Windows behaviour. static int WildMatch(const char* pat, const char* name) { while (*pat && *name) { if (*pat == '*') { // Skip consecutive stars. while (*pat == '*') pat++; if (!*pat) return 1; // trailing * matches everything // Try matching the rest of the pattern at every position. while (*name) { if (WildMatch(pat, name)) return 1; name++; } return 0; } char p = (*pat >= 'A' && *pat <= 'Z') ? *pat + 32 : *pat; char n = (*name >= 'A' && *name <= 'Z') ? *name + 32 : *name; if (*pat != '?' && p != n) return 0; pat++; name++; } // Consume trailing stars in the pattern. while (*pat == '*') pat++; return (*pat == '\0' && *name == '\0'); } // Split a FindFirstFileA-style search path into directory and pattern parts. // "apps\\*" -> dir="apps" pat="*" // "*.txt" -> dir="" pat="*.txt" // "*" -> dir="" pat="*" // "apps\\" -> dir="apps" pat="*". static void SplitFindPath(const char* searchPath, char* dirOut, size_t dirSize, char* patOut, size_t patSize) { // Find last backslash or forward-slash. const char* last = NULL; for (const char* p = searchPath; *p; p++) if (*p == '\\' || *p == '/') last = p; if (!last) { // No separator: whole string is the pattern, dir is CWD. if (dirOut && dirSize) dirOut[0] = '\0'; if (patOut && patSize) { size_t len = strlen(searchPath); if (len + 1 > patSize) len = patSize - 1; memcpy(patOut, searchPath, len); patOut[len] = '\0'; } } else { // Everything before the last separator is the directory. if (dirOut) { size_t len = (size_t)(last - searchPath); if (len + 1 > dirSize) len = dirSize - 1; memcpy(dirOut, searchPath, len); dirOut[len] = '\0'; } // Everything after the last separator is the pattern. if (patOut) { const char* p = last + 1; size_t len = strlen(p); if (len + 1 > patSize) len = patSize - 1; memcpy(patOut, p, len); patOut[len] = '\0'; } } // Empty pattern defaults to "*". if (patOut && patOut[0] == '\0') { patOut[0] = '*'; patOut[1] = '\0'; } } // Fill a WIN32_FIND_DATAA from a KDIR_ENTRY. #define FILE_ATTRIBUTE_DIRECTORY 0x00000010UL #define FILE_ATTRIBUTE_ARCHIVE 0x00000020UL #define FILE_ATTRIBUTE_NORMAL 0x00000080UL // Implements the k32 Dir Is Leap Year operation. static int K32DirIsLeapYear(unsigned int year) { return ((year % 4u) == 0u && (year % 100u) != 0u) || ((year % 400u) == 0u); } // Implements the k32 Dir Days In Month operation. static unsigned int K32DirDaysInMonth(unsigned int year, unsigned int month) { static const unsigned char days[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 }; if (month < 1u || month > 12u) return 31u; if (month == 2u && K32DirIsLeapYear(year)) return 29u; return days[month - 1u]; } // Implements the k32 Dir Calendar To Epoch Seconds operation. static uint64_t K32DirCalendarToEpochSeconds(const SYS_SYSTEM_TIME* st) { uint64_t days = 0; for (unsigned int y = 1970u; y < st->Year; y++) days += K32DirIsLeapYear(y) ? 366u : 365u; for (unsigned int m = 1u; m < st->Month; m++) days += K32DirDaysInMonth(st->Year, m); days += (uint64_t)(st->Day - 1u); return (((days * 24u) + st->Hour) * 60u + st->Minute) * 60u + st->Second; } // Implements the k32 Dir Store File Time operation. static void K32DirStoreFileTime(FILETIME* ft, const SYS_SYSTEM_TIME* st) { if (!ft || !st || !(st->Flags & SYS_TIME_FLAG_VALID) || st->Year < 1970u) { if (ft) { ft->dwLowDateTime = 0; ft->dwHighDateTime = 0; } return; } const uint64_t WINDOWS_EPOCH_BIAS_SECONDS = 11644473600ULL; uint64_t epoch = st->EpochSeconds ? st->EpochSeconds : K32DirCalendarToEpochSeconds(st); uint64_t value = (epoch + WINDOWS_EPOCH_BIAS_SECONDS) * 10000000ULL + ((uint64_t)st->Millisecond * 10000ULL) + ((uint64_t)st->Nanosecond / 100ULL); ft->dwLowDateTime = (DWORD)(value & 0xFFFFFFFFULL); ft->dwHighDateTime = (DWORD)(value >> 32); } // Implements the kdir To Find Data operation. static void KdirToFindData(const KDIR_ENTRY* ke, WIN32_FIND_DATAA* fd) { // Zero the entire struct (covers all FILETIME and reserved fields). unsigned char* p = (unsigned char*)fd; for (size_t i = 0; i < sizeof(*fd); i++) p[i] = 0; fd->dwFileAttributes = ke->Attr; if (!(fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && !(fd->dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE)) fd->dwFileAttributes |= FILE_ATTRIBUTE_NORMAL; fd->nFileSizeLow = ke->FileSize; fd->nFileSizeHigh = 0; K32DirStoreFileTime(&fd->ftCreationTime, &ke->CreateTime); K32DirStoreFileTime(&fd->ftLastAccessTime, &ke->LastAccessTime); K32DirStoreFileTime(&fd->ftLastWriteTime, &ke->LastWriteTime); size_t nameLen = strlen(ke->Name); if (nameLen >= MAX_PATH) nameLen = MAX_PATH - 1; memcpy(fd->cFileName, ke->Name, nameLen); fd->cFileName[nameLen] = '\0'; } __declspec(dllexport) HANDLE FindFirstFileA(const char* lpFileName, WIN32_FIND_DATAA* lpFindFileData) { if (!lpFileName || !lpFindFileData) { gLastError = 87; // ERROR_INVALID_PARAMETER return INVALID_HANDLE_VALUE; } // Translate the path. char translatedInput[MAX_PATH]; TranslatePath(lpFileName, translatedInput); // Split path into directory and wildcard pattern. char dir[MAX_PATH]; char pat[MAX_PATH]; SplitFindPath(translatedInput, dir, sizeof(dir), pat, sizeof(pat)); // Open the kernel directory iterator. uint32_t kh = 0; uint32_t s = K32OpenDirNative(dir[0] ? dir : NULL, &kh); if (s != 0 || kh == 0) { gLastError = 2; // ERROR_FILE_NOT_FOUND return INVALID_HANDLE_VALUE; } // Allocate our user-side FIND_HANDLE wrapper. FIND_HANDLE* fh = (FIND_HANDLE*)HeapAlloc(NULL, 0, sizeof(FIND_HANDLE)); if (!fh) { SysCloseHandle(kh); gLastError = 8; // ERROR_NOT_ENOUGH_MEMORY return INVALID_HANDLE_VALUE; } fh->kh = kh; size_t patLen = strlen(pat); if (patLen >= MAX_PATH) patLen = MAX_PATH - 1; memcpy(fh->pattern, pat, patLen); fh->pattern[patLen] = '\0'; // Read the first entry that matches the pattern. KDIR_ENTRY ke; while (true) { uint32_t rs = SysReadDir(kh, &ke); if (rs != 0) { // Directory exhausted or error. SysCloseHandle(kh); HeapFree(NULL, 0, fh); gLastError = 18; // ERROR_NO_MORE_FILES return INVALID_HANDLE_VALUE; } if (WildMatch(fh->pattern, ke.Name)) { KdirToFindData(&ke, lpFindFileData); return (HANDLE)fh; } } } __declspec(dllexport) BOOL FindNextFileA(HANDLE hFindFile, WIN32_FIND_DATAA* lpFindFileData) { if (hFindFile == INVALID_HANDLE_VALUE || !lpFindFileData) { gLastError = 6; // ERROR_INVALID_HANDLE return FALSE; } FIND_HANDLE* fh = (FIND_HANDLE*)hFindFile; KDIR_ENTRY ke; while (true) { uint32_t rs = SysReadDir(fh->kh, &ke); if (rs != 0) { gLastError = 18; // ERROR_NO_MORE_FILES return FALSE; } if (WildMatch(fh->pattern, ke.Name)) { KdirToFindData(&ke, lpFindFileData); return TRUE; } } } // Returns close. __declspec(dllexport) BOOL FindClose(HANDLE hFindFile) { if (hFindFile == INVALID_HANDLE_VALUE) { gLastError = 6; return FALSE; } FIND_HANDLE* fh = (FIND_HANDLE*)hFindFile; SysCloseHandle(fh->kh); HeapFree(NULL, 0, fh); return TRUE; } // Current Working Directory. __declspec(dllexport) BOOL SetCurrentDirectoryA(const char* lpPathName) { if (!lpPathName) { gLastError = 87; return FALSE; } char translatedPath[MAX_PATH]; TranslatePath(lpPathName, translatedPath); uint32_t s = K32SetCwdNative(translatedPath); if (s != 0) { gLastError = 2; return FALSE; } return TRUE; } // Returns current Directory A. __declspec(dllexport) DWORD GetCurrentDirectoryA(DWORD nBufferLength, char* lpBuffer) { if (!lpBuffer || nBufferLength == 0) { // 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[SYS_CWD_MAX + 1]; uint32_t s = K32GetCwdNative(raw, sizeof(raw), NULL); if (s != 0) { gLastError = 1; return 0; } char full[SYS_CWD_MAX + 1]; char drive = 'C'; const char* rel = raw; if (raw[0] >= '0' && raw[0] <= '7' && raw[1] == ':' && (raw[2] == '\\' || raw[2] == '/')) { drive = (char)('C' + (raw[0] - '0')); rel = raw + 3; } full[0] = drive; full[1] = ':'; full[2] = '\\'; size_t rawLen = strlen(rel); if (rawLen + 4 > sizeof(full)) rawLen = sizeof(full) - 4; memcpy(full + 3, rel, rawLen); full[3 + rawLen] = '\0'; for (char* p = full + 3; *p; p++) if (*p == '/') *p = '\\'; size_t needed = strlen(full) + 1; if ((DWORD)needed > nBufferLength) { gLastError = 122; // ERROR_INSUFFICIENT_BUFFER return (DWORD)needed; } memcpy(lpBuffer, full, needed); return (DWORD)(needed - 1); // length without NUL, matching Win32 } // Creates one unnamed recursive Win32 mutex over a native kernel mutex. __declspec(dllexport) HANDLE CreateMutexA(void* lpMutexAttributes, BOOL bInitialOwner, const char* lpName) { (void)lpMutexAttributes; if (lpName && lpName[0]) { gLastError = 120; return NULL; } K32_MUTEX_HANDLE* mutex = (K32_MUTEX_HANDLE*)calloc(1, sizeof(*mutex)); if (!mutex) { gLastError = 8; return NULL; } uint32_t status = SysCreateMutex(&mutex->NativeHandle); if (status != NTLSTATUS_SUCCESS || !mutex->NativeHandle) { free(mutex); gLastError = status == NTLSTATUS_NO_MEMORY ? 8 : 1; return NULL; } mutex->Magic = K32_MUTEX_MAGIC; if (bInitialOwner) { status = SysWait(mutex->NativeHandle, SYS_WAIT_FLAG_NONE); if (status != NTLSTATUS_SUCCESS && status != NTLSTATUS_ABANDONED) { (void)SysCloseHandle(mutex->NativeHandle); free(mutex); gLastError = 1; return NULL; } mutex->OwnerTid = K32CurrentTidOrOne(); mutex->Recursion = 1; } K32RegisterMutex(mutex); return (HANDLE)mutex; } // Creates one unnamed recursive Win32 mutex from a wide-name request. __declspec(dllexport) HANDLE CreateMutexW(void* lpMutexAttributes, BOOL bInitialOwner, const unsigned short* lpName) { if (lpName && lpName[0]) { gLastError = 120; return NULL; } return CreateMutexA(lpMutexAttributes, bInitialOwner, NULL); } // Releases one recursion level from a Win32 mutex wrapper. __declspec(dllexport) BOOL ReleaseMutex(HANDLE hMutex) { K32_MUTEX_HANDLE* mutex = K32ReferenceMutex(hMutex); if (!mutex) { gLastError = 6; return FALSE; } DWORD tid = K32CurrentTidOrOne(); K32MutexStateLock(mutex); if (mutex->OwnerTid != tid || mutex->Recursion == 0) { K32MutexStateUnlock(mutex); K32DereferenceMutex(mutex); gLastError = 288; return FALSE; } mutex->Recursion--; if (mutex->Recursion != 0) { K32MutexStateUnlock(mutex); K32DereferenceMutex(mutex); return TRUE; } mutex->OwnerTid = 0; K32MutexStateUnlock(mutex); uint32_t status = SysReleaseMutex(mutex->NativeHandle); if (status != NTLSTATUS_SUCCESS) { K32MutexStateLock(mutex); mutex->OwnerTid = tid; mutex->Recursion = 1; K32MutexStateUnlock(mutex); K32DereferenceMutex(mutex); gLastError = 288; return FALSE; } K32DereferenceMutex(mutex); return TRUE; } __declspec(dllexport) HANDLE CreateSemaphoreA(void* lpSemaphoreAttributes, long lInitialCount, long lMaximumCount, const char* lpName) { (void)lpSemaphoreAttributes; (void)lpName; uint32_t kh = 0; uint32_t s = SysCreateSem((int32_t)lInitialCount, (int32_t)lMaximumCount, &kh); if (s != 0 || !kh) { gLastError = 8; return NULL; } return KH_TO_HANDLE(kh); } __declspec(dllexport) BOOL ReleaseSemaphore(HANDLE hSemaphore, long lReleaseCount, long* lpPreviousCount) { if (!IS_VALID_KERNEL_HANDLE(hSemaphore) || lReleaseCount < 0) { gLastError = 6; return FALSE; } if (lpPreviousCount) *lpPreviousCount = 0; for (long i = 0; i < lReleaseCount; ++i) { uint32_t s = SysSignalSem(HANDLE_TO_KH(hSemaphore)); if (s != 0) { gLastError = 6; return FALSE; } } return TRUE; } // Critical Sections & Condition Variables. // Match the size of Win64 RTL_CRITICAL_SECTION (5 pointer-sized fields) while // using the storage as a small recursive spin lock. Bink uses these from its // worker/copy paths, so the old no-op implementation allowed internal state // races as soon as CreateThread started working. typedef struct K32_CONDITION_WAITER K32_CONDITION_WAITER; typedef struct K32_CONDITION_STATE { volatile long Lock; K32_CONDITION_WAITER* Head; K32_CONDITION_WAITER* Tail; } K32_CONDITION_STATE; struct K32_CONDITION_WAITER { K32_CONDITION_WAITER* Previous; K32_CONDITION_WAITER* Next; uint32_t Event; BOOL Queued; }; #define K32_CS_LOCK 0 #define K32_CS_OWNER 1 #define K32_CS_RECURSION 2 static volatile long* K32CsLockWord(CRITICAL_SECTION* cs) { return (volatile long*)&cs->_opaque[K32_CS_LOCK]; } static DWORD K32CurrentTidOrOne(void) { DWORD tid = (DWORD)SysGetCurrentTid(); return tid ? tid : 1; } // Initializes critical Section. __declspec(dllexport) void InitializeCriticalSection(CRITICAL_SECTION* lpCS) { if (!lpCS) return; memset(lpCS, 0, sizeof(*lpCS)); } __declspec(dllexport) BOOL InitializeCriticalSectionAndSpinCount(CRITICAL_SECTION* lpCS, DWORD dwSpinCount) { (void)dwSpinCount; InitializeCriticalSection(lpCS); return TRUE; } // Releases critical Section. __declspec(dllexport) void DeleteCriticalSection(CRITICAL_SECTION* lpCS) { (void)lpCS; } // Implements the enter Critical Section operation. __declspec(dllexport) void EnterCriticalSection(CRITICAL_SECTION* lpCS) { if (!lpCS) return; DWORD tid = K32CurrentTidOrOne(); if ((DWORD)lpCS->_opaque[K32_CS_OWNER] == tid) { lpCS->_opaque[K32_CS_RECURSION]++; return; } uint32_t spins = 0; while (_InterlockedCompareExchange(K32CsLockWord(lpCS), 1, 0) != 0) { _mm_pause(); if ((++spins & 0xFFFu) == 0) (void)SysYield(); } lpCS->_opaque[K32_CS_OWNER] = tid; lpCS->_opaque[K32_CS_RECURSION] = 1; } // Implements the leave Critical Section operation. __declspec(dllexport) void LeaveCriticalSection(CRITICAL_SECTION* lpCS) { if (!lpCS) return; DWORD tid = K32CurrentTidOrOne(); if ((DWORD)lpCS->_opaque[K32_CS_OWNER] != tid || lpCS->_opaque[K32_CS_RECURSION] == 0) return; lpCS->_opaque[K32_CS_RECURSION]--; if (lpCS->_opaque[K32_CS_RECURSION] == 0) { lpCS->_opaque[K32_CS_OWNER] = 0; _ReadWriteBarrier(); _InterlockedExchange(K32CsLockWord(lpCS), 0); } } // Implements the try Enter Critical Section operation. __declspec(dllexport) BOOL TryEnterCriticalSection(CRITICAL_SECTION* lpCS) { if (!lpCS) return FALSE; DWORD tid = K32CurrentTidOrOne(); if ((DWORD)lpCS->_opaque[K32_CS_OWNER] == tid) { lpCS->_opaque[K32_CS_RECURSION]++; return TRUE; } if (_InterlockedCompareExchange(K32CsLockWord(lpCS), 1, 0) != 0) return FALSE; lpCS->_opaque[K32_CS_OWNER] = tid; lpCS->_opaque[K32_CS_RECURSION] = 1; return TRUE; } // Acquires one condition-variable queue lock. static void K32ConditionLock(K32_CONDITION_STATE* state) { uint32_t spins = 0; while (_InterlockedCompareExchange(&state->Lock, 1, 0) != 0) { _mm_pause(); if ((++spins & 0xFFFu) == 0) (void)SysYield(); } } // Releases one condition-variable queue lock. static void K32ConditionUnlock(K32_CONDITION_STATE* state) { _ReadWriteBarrier(); _InterlockedExchange(&state->Lock, 0); } // Returns the lazily allocated process-local condition-variable state. static K32_CONDITION_STATE* K32ConditionState(CONDITION_VARIABLE* cv, BOOL create) { if (!cv) return NULL; K32_CONDITION_STATE* state = (K32_CONDITION_STATE*)cv->_ptr; if (state || !create) return state; K32_CONDITION_STATE* allocated = (K32_CONDITION_STATE*)calloc(1, sizeof(*allocated)); if (!allocated) return NULL; void* previous = _InterlockedCompareExchangePointer((void* volatile*)&cv->_ptr, allocated, NULL); if (previous) { free(allocated); state = (K32_CONDITION_STATE*)previous; } else { state = allocated; } return state; } // Removes one waiter while the condition-variable queue lock is held. static void K32ConditionRemoveWaiter(K32_CONDITION_STATE* state, K32_CONDITION_WAITER* waiter) { if (!waiter->Queued) return; if (waiter->Previous) waiter->Previous->Next = waiter->Next; else state->Head = waiter->Next; if (waiter->Next) waiter->Next->Previous = waiter->Previous; else state->Tail = waiter->Previous; waiter->Previous = NULL; waiter->Next = NULL; waiter->Queued = FALSE; } // Initializes one process-local condition variable. __declspec(dllexport) void InitializeConditionVariable(CONDITION_VARIABLE* cv) { if (cv) cv->_ptr = NULL; } // Atomically releases a critical section and waits for one condition wake. __declspec(dllexport) BOOL SleepConditionVariableCS(CONDITION_VARIABLE* cv, CRITICAL_SECTION* cs, DWORD dwMilliseconds) { if (!cv || !cs) { gLastError = 87; return FALSE; } DWORD tid = K32CurrentTidOrOne(); uintptr_t recursion = cs->_opaque[K32_CS_RECURSION]; if ((DWORD)cs->_opaque[K32_CS_OWNER] != tid || recursion == 0) { gLastError = 87; return FALSE; } K32_CONDITION_STATE* state = K32ConditionState(cv, TRUE); if (!state) { gLastError = 8; return FALSE; } uint32_t event = 0; KSTATUS status = SysCreateEvent(0, 0, &event); if (status != NTLSTATUS_SUCCESS) { gLastError = status == NTLSTATUS_NO_MEMORY ? 8 : 87; return FALSE; } // The waiter is heap-backed because process termination can stop a user // thread at syscall return before it can remove a stack-backed queue node. K32_CONDITION_WAITER* waiter = (K32_CONDITION_WAITER*)calloc(1, sizeof(*waiter)); if (!waiter) { (void)SysCloseHandle(event); gLastError = 8; return FALSE; } waiter->Event = event; waiter->Queued = TRUE; K32ConditionLock(state); waiter->Previous = state->Tail; if (state->Tail) state->Tail->Next = waiter; else state->Head = waiter; state->Tail = waiter; K32ConditionUnlock(state); // The waiter is visible before the lock is released, so a wake that races // this transition is retained by the private auto-reset event. cs->_opaque[K32_CS_RECURSION] = 0; cs->_opaque[K32_CS_OWNER] = 0; _ReadWriteBarrier(); _InterlockedExchange(K32CsLockWord(cs), 0); uint64_t timeout = dwMilliseconds == INFINITE ? SYS_WAIT_TIMEOUT_INFINITE : (uint64_t)dwMilliseconds; status = SysWaitSingle(event, SYS_WAIT_FLAG_NONE, timeout); K32ConditionLock(state); BOOL wakeWon = waiter->Queued ? FALSE : TRUE; K32ConditionRemoveWaiter(state, waiter); K32ConditionUnlock(state); EnterCriticalSection(cs); cs->_opaque[K32_CS_RECURSION] = recursion; (void)SysCloseHandle(event); free(waiter); if (status == NTLSTATUS_SUCCESS || wakeWon) return TRUE; if (status == NTLSTATUS_TIMEOUT) gLastError = 1460; else gLastError = 6; return FALSE; } // Wakes the oldest waiter on one condition variable. __declspec(dllexport) void WakeConditionVariable(CONDITION_VARIABLE* cv) { K32_CONDITION_STATE* state = K32ConditionState(cv, FALSE); if (!state) return; K32ConditionLock(state); K32_CONDITION_WAITER* waiter = state->Head; if (waiter) { K32ConditionRemoveWaiter(state, waiter); (void)SysSignalEvent(waiter->Event); } K32ConditionUnlock(state); } // Wakes every waiter currently queued on one condition variable. __declspec(dllexport) void WakeAllConditionVariable(CONDITION_VARIABLE* cv) { K32_CONDITION_STATE* state = K32ConditionState(cv, FALSE); if (!state) return; K32ConditionLock(state); while (state->Head) { K32_CONDITION_WAITER* waiter = state->Head; K32ConditionRemoveWaiter(state, waiter); (void)SysSignalEvent(waiter->Event); } K32ConditionUnlock(state); } // Timing & Performance Counters. typedef union { struct { DWORD LowPart; long HighPart; } u; long long QuadPart; } LARGE_INTEGER; static volatile long long gTscFreq = 0; // Attempt to read TSC frequency from CPUID leaf 0x15 (Modern Intel/AMD). static long long TscFreqFromCpuid(void) { int info[4]; __cpuid(info, 0); if ((unsigned)info[0] < 0x15) return 0; __cpuid(info, 0x15); unsigned denom = (unsigned)info[0]; unsigned numer = (unsigned)info[1]; unsigned crystal_hz = (unsigned)info[2]; if (!denom || !numer || !crystal_hz) return 0; return (long long)crystal_hz * numer / denom; } // Calibrates TSC against the native monotonic tick source. static long long TscFreqCalibrate(void) { 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(); while ((SysGetTick() - t0) < calibrationTicks) { _mm_pause(); } uint64_t t1 = SysGetTick(); uint64_t tsc1 = __rdtsc(); uint64_t delta_tsc = tsc1 - tsc0; uint64_t delta_us = SysTicksToMicroseconds(t1 - t0, frequency); if (!delta_us) return 0; return (long long)(delta_tsc * 1000000ULL / delta_us); } // Implements the tsc Freq Get operation. static long long TscFreqGet(void) { if (gTscFreq) return gTscFreq; long long f = TscFreqFromCpuid(); if (!f) f = TscFreqCalibrate(); gTscFreq = f; return f; } // Returns performance Frequency. __declspec(dllexport) BOOL QueryPerformanceFrequency(LARGE_INTEGER* lpFrequency) { if (lpFrequency) lpFrequency->QuadPart = TscFreqGet(); return TRUE; } // Returns performance Counter. __declspec(dllexport) BOOL QueryPerformanceCounter(LARGE_INTEGER* lpPerformanceCount) { // Ensure calibration happens before the first read. TscFreqGet(); if (lpPerformanceCount) lpPerformanceCount->QuadPart = (long long)__rdtsc(); return TRUE; } // Implements the k32 Is Leap Year operation. static BOOL K32IsLeapYear(unsigned int year) { return ((year % 4u) == 0u && (year % 100u) != 0u) || ((year % 400u) == 0u); } // Implements the k32 Days In Month operation. static unsigned int K32DaysInMonth(unsigned int year, unsigned int month) { static const unsigned char days[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 }; if (month == 2u && K32IsLeapYear(year)) return 29u; if (month < 1u || month > 12u) return 0u; return days[month - 1u]; } // Implements the k32 Calendar To Epoch Seconds operation. static uint64_t K32CalendarToEpochSeconds(const SYSTEMTIME* st) { uint64_t days = 0; for (unsigned int y = 1970u; y < st->wYear; y++) days += K32IsLeapYear(y) ? 366u : 365u; for (unsigned int m = 1u; m < st->wMonth; m++) days += K32DaysInMonth(st->wYear, m); days += (uint64_t)(st->wDay - 1u); return (((days * 24u) + st->wHour) * 60u + st->wMinute) * 60u + st->wSecond; } // Implements the k32 Epoch To File Time operation. static uint64_t K32EpochToFileTime(uint64_t epochSeconds, uint32_t nanosecond) { const uint64_t WINDOWS_EPOCH_BIAS_SECONDS = 11644473600ULL; return (epochSeconds + WINDOWS_EPOCH_BIAS_SECONDS) * 10000000ULL + ((uint64_t)nanosecond / 100ULL); } // Implements the k32 Store File Time operation. static void K32StoreFileTime(FILETIME* ft, uint64_t value) { ft->dwLowDateTime = (DWORD)(value & 0xFFFFFFFFULL); ft->dwHighDateTime = (DWORD)(value >> 32); } // Returns system Time. __declspec(dllexport) void GetSystemTime(SYSTEMTIME* lpSystemTime) { if (!lpSystemTime) return; SYS_SYSTEM_TIME st; if (SysGetSystemTime(&st) != NTLSTATUS_SUCCESS) { memset(lpSystemTime, 0, sizeof(*lpSystemTime)); return; } lpSystemTime->wYear = st.Year; lpSystemTime->wMonth = st.Month; lpSystemTime->wDayOfWeek = st.DayOfWeek; lpSystemTime->wDay = st.Day; lpSystemTime->wHour = st.Hour; lpSystemTime->wMinute = st.Minute; lpSystemTime->wSecond = st.Second; lpSystemTime->wMilliseconds = st.Millisecond; } __declspec(dllexport) BOOL SystemTimeToFileTime(const SYSTEMTIME* lpSystemTime, FILETIME* lpFileTime) { if (!lpSystemTime || !lpFileTime) return FALSE; if (lpSystemTime->wYear < 1970 || lpSystemTime->wMonth < 1 || lpSystemTime->wMonth > 12 || lpSystemTime->wDay < 1 || lpSystemTime->wDay > K32DaysInMonth(lpSystemTime->wYear, lpSystemTime->wMonth) || lpSystemTime->wHour > 23 || lpSystemTime->wMinute > 59 || lpSystemTime->wSecond > 59 || lpSystemTime->wMilliseconds > 999) { return FALSE; } uint64_t ft = K32EpochToFileTime(K32CalendarToEpochSeconds(lpSystemTime), (uint32_t)lpSystemTime->wMilliseconds * 1000000u); K32StoreFileTime(lpFileTime, ft); return TRUE; } // Returns system Time As File Time. __declspec(dllexport) void GetSystemTimeAsFileTime(void* lpSystemTimeAsFileTime) { if (!lpSystemTimeAsFileTime) return; SYS_SYSTEM_TIME st; uint64_t ft; if (SysGetSystemTime(&st) == NTLSTATUS_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 + SysTicksToMicroseconds(SysGetTick(), frequency) * 10ULL; } memcpy(lpSystemTimeAsFileTime, &ft, sizeof(ft)); } // System Information. typedef struct { union { DWORD dwOemId; struct { unsigned short wProcessorArchitecture; unsigned short wReserved; }; }; DWORD dwPageSize; void* lpMinimumApplicationAddress; void* lpMaximumApplicationAddress; uintptr_t dwActiveProcessorMask; DWORD dwNumberOfProcessors; DWORD dwProcessorType; DWORD dwAllocationGranularity; unsigned short wProcessorLevel; unsigned short wProcessorRevision; } SYSTEM_INFO; // Returns system Info. __declspec(dllexport) void GetSystemInfo(SYSTEM_INFO* lpSystemInfo) { if (!lpSystemInfo) return; unsigned char* p = (unsigned char*)lpSystemInfo; for (size_t i = 0; i < sizeof(*lpSystemInfo); i++) p[i] = 0; lpSystemInfo->wProcessorArchitecture = 9; // PROCESSOR_ARCHITECTURE_AMD64 lpSystemInfo->dwPageSize = 4096; lpSystemInfo->lpMinimumApplicationAddress = (void*)0x10000; lpSystemInfo->lpMaximumApplicationAddress = (void*)0x7FFFFFFEFFFFull; lpSystemInfo->dwActiveProcessorMask = 1; lpSystemInfo->dwNumberOfProcessors = 1; lpSystemInfo->dwProcessorType = 8664; // PROCESSOR_AMD_X8664 lpSystemInfo->dwAllocationGranularity= 65536; lpSystemInfo->wProcessorLevel = 6; lpSystemInfo->wProcessorRevision = 0; } typedef struct { DWORD dwLength; DWORD dwMemoryLoad; unsigned long long ullTotalPhys; unsigned long long ullAvailPhys; unsigned long long ullTotalPageFile; unsigned long long ullAvailPageFile; unsigned long long ullTotalVirtual; unsigned long long ullAvailVirtual; unsigned long long ullAvailExtendedVirtual; } MEMORYSTATUSEX; __declspec(dllexport) BOOL GetLogicalProcessorInformation(void* Buffer, DWORD* ReturnedLength) { (void)Buffer; // Signal that the buffer is too small so callers know to handle failure. if (ReturnedLength) *ReturnedLength = 0; gLastError = 122; // ERROR_INSUFFICIENT_BUFFER return FALSE; } #define MAX_PATH 260 // Returns system Directory A. __declspec(dllexport) unsigned int GetSystemDirectoryA(char* lpBuffer, unsigned int uSize) { static const char sysdir[] = "C:\\Windows\\System32"; unsigned int needed = sizeof(sysdir); // includes NUL if (lpBuffer && uSize >= needed) { for (unsigned int i = 0; i < needed; i++) lpBuffer[i] = sysdir[i]; } return needed - 1; // return length without NUL, matching Win32 } // Returns windows Directory A. __declspec(dllexport) unsigned int GetWindowsDirectoryA(char* lpBuffer, unsigned int uSize) { static const char windir[] = "C:\\Windows"; unsigned int needed = sizeof(windir); if (lpBuffer && uSize >= needed) { for (unsigned int i = 0; i < needed; i++) lpBuffer[i] = windir[i]; } return needed - 1; } // Returns static Env A. static const char* LookupStaticEnvA(const char* name) { if (!name) return NULL; if (strcmp(name, "HOME") == 0) return "."; if (strcmp(name, "USERPROFILE") == 0) return "."; if (strcmp(name, "HOMEDRIVE") == 0) return "C:"; if (strcmp(name, "HOMEPATH") == 0) return "\\"; return NULL; } __declspec(dllexport) DWORD GetEnvironmentVariableA(const char* lpName, char* lpBuffer, DWORD nSize) { const char* value = LookupStaticEnvA(lpName); if (!value) { if (lpBuffer && nSize) lpBuffer[0] = '\0'; gLastError = 203; // ERROR_ENVVAR_NOT_FOUND return 0; } DWORD len = (DWORD)strlen(value); if (!lpBuffer || nSize == 0) return len; if (len + 1 > nSize) { if (nSize) lpBuffer[0] = '\0'; gLastError = 122; // ERROR_INSUFFICIENT_BUFFER return len + 1; } memcpy(lpBuffer, value, len + 1); return len; } // Returns environment Strings. __declspec(dllexport) char* GetEnvironmentStrings(void) { // Double-NUL-terminated environment block. static char env[] = "HOME=.\0USERPROFILE=.\0HOMEDRIVE=C:\0HOMEPATH=\\\0\0"; return env; } // Releases environment Strings A. __declspec(dllexport) BOOL FreeEnvironmentStringsA(char* penv) { (void)penv; return TRUE; } // Returns environment Strings W. __declspec(dllexport) unsigned short* GetEnvironmentStringsW(void) { static unsigned short emptyEnvW[2] = { 0, 0 }; return emptyEnvW; } // Releases environment Strings W. __declspec(dllexport) BOOL FreeEnvironmentStringsW(unsigned short* penv) { (void)penv; return TRUE; } // Handle / Error helpers. __declspec(dllexport) unsigned int SetErrorMode(unsigned int uMode) { (void)uMode; return 0; // previous mode } // Updates handle Count. __declspec(dllexport) unsigned int SetHandleCount(unsigned int uNumber) { return uNumber < 256 ? 256 : uNumber; } // File helpers. #define FILE_TYPE_UNKNOWN 0x0000 #define FILE_TYPE_DISK 0x0001 #define FILE_TYPE_CHAR 0x0002 #define FILE_TYPE_PIPE 0x0003 #define STD_INPUT_HANDLE ((DWORD)-10) #define STD_OUTPUT_HANDLE ((DWORD)-11) #define STD_ERROR_HANDLE ((DWORD)-12) // Returns file Type. __declspec(dllexport) DWORD GetFileType(HANDLE hFile) { if (!hFile || hFile == INVALID_HANDLE_VALUE) return FILE_TYPE_UNKNOWN; if (K32IsStdHandleValue(hFile, STD_INPUT_HANDLE) || K32IsStdHandleValue(hFile, STD_OUTPUT_HANDLE) || K32IsStdHandleValue(hFile, STD_ERROR_HANDLE)) return FILE_TYPE_CHAR; return FILE_TYPE_DISK; } // Exception Handling & Debugging. #define EXCEPTION_CONTINUE_EXECUTION ((LONG)-1) #define EXCEPTION_CONTINUE_SEARCH 0 #define EXCEPTION_EXECUTE_HANDLER 1 #define EXCEPTION_NONCONTINUABLE 0x1UL #define EXCEPTION_MAXIMUM_PARAMETERS SYS_EXCEPTION_MAXIMUM_PARAMETERS #define WIN_VECTORED_MAX_HANDLERS 16u #define WIN_SEH_MAX_FRAMES 16u typedef struct _EXCEPTION_RECORD { DWORD ExceptionCode; DWORD ExceptionFlags; struct _EXCEPTION_RECORD* ExceptionRecord; void* ExceptionAddress; DWORD NumberParameters; uintptr_t ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; } EXCEPTION_RECORD; typedef struct _CONTEXT { DWORD64 P1Home; DWORD64 P2Home; DWORD64 P3Home; DWORD64 P4Home; DWORD64 P5Home; DWORD64 P6Home; DWORD ContextFlags; DWORD MxCsr; WORD SegCs; WORD SegDs; WORD SegEs; WORD SegFs; WORD SegGs; WORD SegSs; DWORD EFlags; DWORD64 Dr0; DWORD64 Dr1; DWORD64 Dr2; DWORD64 Dr3; DWORD64 Dr6; DWORD64 Dr7; DWORD64 Rax; DWORD64 Rcx; DWORD64 Rdx; DWORD64 Rbx; DWORD64 Rsp; DWORD64 Rbp; DWORD64 Rsi; DWORD64 Rdi; DWORD64 R8; DWORD64 R9; DWORD64 R10; DWORD64 R11; DWORD64 R12; DWORD64 R13; DWORD64 R14; DWORD64 R15; DWORD64 Rip; } CONTEXT; typedef struct _EXCEPTION_POINTERS { EXCEPTION_RECORD* ExceptionRecord; CONTEXT* ContextRecord; } EXCEPTION_POINTERS; typedef LONG (*PVECTORED_EXCEPTION_HANDLER)(EXCEPTION_POINTERS* ExceptionInfo); typedef LONG (*PRTL_EXCEPTION_FRAME_HANDLER)(EXCEPTION_POINTERS* ExceptionInfo, void* UserContext); typedef struct _RTL_EXCEPTION_FRAME { DWORD Size; DWORD Flags; struct _RTL_EXCEPTION_FRAME* Previous; PRTL_EXCEPTION_FRAME_HANDLER Handler; void* UserContext; } RTL_EXCEPTION_FRAME; typedef struct WIN_VECTORED_HANDLER_ENTRY { uint32_t Active; uint32_t IsContinue; uint32_t Previous; uint32_t Next; PVECTORED_EXCEPTION_HANDLER Handler; } WIN_VECTORED_HANDLER_ENTRY; typedef struct WIN_VECTORED_HANDLER_SNAPSHOT { PVECTORED_EXCEPTION_HANDLER Handler; } WIN_VECTORED_HANDLER_SNAPSHOT; typedef struct WIN_SEH_FRAME_SNAPSHOT { PRTL_EXCEPTION_FRAME_HANDLER Handler; void* UserContext; } WIN_SEH_FRAME_SNAPSHOT; static volatile long gWinVectoredLock; static uint32_t gWinVectoredExceptionHead = UINT32_MAX; static uint32_t gWinVectoredExceptionTail = UINT32_MAX; static uint32_t gWinVectoredContinueHead = UINT32_MAX; static uint32_t gWinVectoredContinueTail = UINT32_MAX; static WIN_VECTORED_HANDLER_ENTRY gWinVectoredHandlers[WIN_VECTORED_MAX_HANDLERS]; static void* gWinExceptionNativeHandle; // Acquires the Win32 vectored-handler list lock. static void WinpVectoredLock(void) { while (_InterlockedCompareExchange(&gWinVectoredLock, 1, 0) != 0) _mm_pause(); _ReadWriteBarrier(); } // Releases the Win32 vectored-handler list lock. static void WinpVectoredUnlock(void) { _ReadWriteBarrier(); _InterlockedExchange(&gWinVectoredLock, 0); } // Returns the list head slot for one vectored-handler kind. static uint32_t* WinpVectoredHeadSlot(uint32_t isContinue) { return isContinue ? &gWinVectoredContinueHead : &gWinVectoredExceptionHead; } // Returns the list tail slot for one vectored-handler kind. static uint32_t* WinpVectoredTailSlot(uint32_t isContinue) { return isContinue ? &gWinVectoredContinueTail : &gWinVectoredExceptionTail; } // Copies native exception state into the Win32-facing exception record. static void WinpBuildExceptionRecord(const SYS_EXCEPTION_RECORD* source, EXCEPTION_RECORD* target) { memset(target, 0, sizeof(*target)); target->ExceptionCode = source->Code; if (source->Flags & SYS_EXCEPTION_FLAG_NONCONTINUABLE) target->ExceptionFlags |= EXCEPTION_NONCONTINUABLE; target->ExceptionAddress = (void*)(uintptr_t)source->ExceptionAddress; target->NumberParameters = source->ParameterCount; if (target->NumberParameters > EXCEPTION_MAXIMUM_PARAMETERS) target->NumberParameters = EXCEPTION_MAXIMUM_PARAMETERS; for (DWORD i = 0; i < target->NumberParameters; i++) target->ExceptionInformation[i] = (uintptr_t)source->Parameters[i]; } // Copies native user context into the subset of x64 CONTEXT currently exposed by Win32. static void WinpBuildContext(const SYS_USER_CONTEXT* source, CONTEXT* target) { memset(target, 0, sizeof(*target)); target->SegCs = (WORD)source->SegCs; target->SegSs = (WORD)source->SegSs; target->EFlags = (DWORD)source->Rflags; target->Rax = source->Rax; target->Rcx = source->Rcx; target->Rdx = source->Rdx; target->Rbx = source->Rbx; target->Rsp = source->Rsp; target->Rbp = source->Rbp; target->Rsi = source->Rsi; target->Rdi = source->Rdi; target->R8 = source->R8; target->R9 = source->R9; target->R10 = source->R10; target->R11 = source->R11; target->R12 = source->R12; target->R13 = source->R13; target->R14 = source->R14; target->R15 = source->R15; target->Rip = source->Rip; } // Copies handler-edited Win32 context back to the native resume context. static void WinpStoreContext(SYS_USER_CONTEXT* target, const CONTEXT* source) { target->Rflags = source->EFlags; target->Rax = source->Rax; target->Rcx = source->Rcx; target->Rdx = source->Rdx; target->Rbx = source->Rbx; target->Rsp = source->Rsp; target->Rbp = source->Rbp; target->Rsi = source->Rsi; target->Rdi = source->Rdi; target->R8 = source->R8; target->R9 = source->R9; target->R10 = source->R10; target->R11 = source->R11; target->R12 = source->R12; target->R13 = source->R13; target->R14 = source->R14; target->R15 = source->R15; target->Rip = source->Rip; } // Copies one vectored-handler list so callbacks can run without the list lock. static size_t WinpSnapshotVectoredHandlers(uint32_t isContinue, WIN_VECTORED_HANDLER_SNAPSHOT* snapshot, size_t capacity) { size_t count = 0; WinpVectoredLock(); uint32_t head = *WinpVectoredHeadSlot(isContinue); for (uint32_t index = head; index != UINT32_MAX && count < capacity; index = gWinVectoredHandlers[index].Next) { WIN_VECTORED_HANDLER_ENTRY* entry = &gWinVectoredHandlers[index]; if (!entry->Active || entry->IsContinue != isContinue || !entry->Handler) continue; snapshot[count++].Handler = entry->Handler; } WinpVectoredUnlock(); return count; } // Runs one Win32 vectored-handler list against the current exception state. static int WinpRunVectoredList(uint32_t isContinue, EXCEPTION_POINTERS* pointers, SYS_USER_CONTEXT* nativeContext) { WIN_VECTORED_HANDLER_SNAPSHOT snapshot[WIN_VECTORED_MAX_HANDLERS]; size_t count = WinpSnapshotVectoredHandlers(isContinue, snapshot, WIN_VECTORED_MAX_HANDLERS); for (size_t i = 0; i < count; i++) { LONG disposition = snapshot[i].Handler(pointers); if (disposition == EXCEPTION_CONTINUE_SEARCH) continue; if (disposition == EXCEPTION_CONTINUE_EXECUTION) { if (pointers->ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE) return NTL_EXCEPTION_TERMINATE_PROCESS; WinpStoreContext(nativeContext, pointers->ContextRecord); return NTL_EXCEPTION_CONTINUE_EXECUTION; } } return NTL_EXCEPTION_CONTINUE_SEARCH; } // Returns the current thread's top runtime-registered SEH frame. static RTL_EXCEPTION_FRAME* WinpSehFrameHead(void) { return (RTL_EXCEPTION_FRAME*)K32ThreadEnv()->ExceptionFrameHead; } // Updates the current thread's top runtime-registered SEH frame. static void WinpSetSehFrameHead(RTL_EXCEPTION_FRAME* frame) { K32ThreadEnv()->ExceptionFrameHead = frame; } // Copies the current SEH frame chain so callbacks can mutate registration safely. static size_t WinpSnapshotSehFrames(WIN_SEH_FRAME_SNAPSHOT* snapshot, size_t capacity) { size_t count = 0; for (RTL_EXCEPTION_FRAME* frame = WinpSehFrameHead(); frame && count < capacity; frame = frame->Previous) { if (frame->Size != sizeof(*frame) || !frame->Handler) break; snapshot[count].Handler = frame->Handler; snapshot[count].UserContext = frame->UserContext; count++; } return count; } // Runs runtime-registered SEH frames after VEH has declined the exception. static int WinpRunSehFrames(EXCEPTION_POINTERS* pointers, SYS_USER_CONTEXT* nativeContext) { WIN_SEH_FRAME_SNAPSHOT snapshot[WIN_SEH_MAX_FRAMES]; size_t count = WinpSnapshotSehFrames(snapshot, WIN_SEH_MAX_FRAMES); for (size_t i = 0; i < count; i++) { LONG disposition = snapshot[i].Handler(pointers, snapshot[i].UserContext); if (disposition == EXCEPTION_CONTINUE_SEARCH) continue; if (disposition == EXCEPTION_CONTINUE_EXECUTION) { if (pointers->ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE) return NTL_EXCEPTION_TERMINATE_PROCESS; WinpStoreContext(nativeContext, pointers->ContextRecord); return NTL_EXCEPTION_CONTINUE_EXECUTION; } if (disposition == EXCEPTION_EXECUTE_HANDLER) { // Runtime frames do not have a compiler-generated landing pad yet. return NTL_EXCEPTION_TERMINATE_PROCESS; } return NTL_EXCEPTION_TERMINATE_PROCESS; } return NTL_EXCEPTION_CONTINUE_SEARCH; } // Bridges the native exception runtime into Win32 exception policy. static int WinpExceptionNativeDispatch(SYS_EXCEPTION_RECORD* record, SYS_USER_CONTEXT* context, void* userContext) { (void)userContext; EXCEPTION_RECORD winRecord; CONTEXT winContext; EXCEPTION_POINTERS pointers; WinpBuildExceptionRecord(record, &winRecord); WinpBuildContext(context, &winContext); pointers.ExceptionRecord = &winRecord; pointers.ContextRecord = &winContext; int disposition = WinpRunVectoredList(0, &pointers, context); if (disposition != NTL_EXCEPTION_CONTINUE_SEARCH) return disposition; disposition = WinpRunSehFrames(&pointers, context); if (disposition != NTL_EXCEPTION_CONTINUE_SEARCH) return disposition; return WinpRunVectoredList(1, &pointers, context); } // Ensures the Win32 exception bridge is registered with the native exception runtime. static BOOL WinpEnsureExceptionBridge(void) { if (gWinExceptionNativeHandle) return TRUE; WinpVectoredLock(); if (gWinExceptionNativeHandle) { WinpVectoredUnlock(); return TRUE; } void* handle = NtlAddExceptionHandler(1, WinpExceptionNativeDispatch, NULL); if (!handle) { WinpVectoredUnlock(); gLastError = 8; return FALSE; } gWinExceptionNativeHandle = handle; WinpVectoredUnlock(); return TRUE; } // Adds one Win32 vectored exception or continue handler. static void* WinpAddVectoredHandler(uint32_t isContinue, unsigned long first, void* handler) { if (!handler) { gLastError = 87; return NULL; } if (!WinpEnsureExceptionBridge()) return NULL; WinpVectoredLock(); uint32_t slot = UINT32_MAX; for (uint32_t i = 0; i < WIN_VECTORED_MAX_HANDLERS; i++) { if (!gWinVectoredHandlers[i].Active) { slot = i; break; } } if (slot == UINT32_MAX) { WinpVectoredUnlock(); gLastError = 8; return NULL; } uint32_t* head = WinpVectoredHeadSlot(isContinue); uint32_t* tail = WinpVectoredTailSlot(isContinue); WIN_VECTORED_HANDLER_ENTRY* entry = &gWinVectoredHandlers[slot]; entry->Active = 1; entry->IsContinue = isContinue; entry->Handler = (PVECTORED_EXCEPTION_HANDLER)handler; entry->Previous = UINT32_MAX; entry->Next = UINT32_MAX; if (*head == UINT32_MAX) { *head = slot; *tail = slot; } else if (first) { entry->Next = *head; gWinVectoredHandlers[*head].Previous = slot; *head = slot; } else { entry->Previous = *tail; gWinVectoredHandlers[*tail].Next = slot; *tail = slot; } WinpVectoredUnlock(); return entry; } // Removes one Win32 vectored exception or continue handler. static unsigned long WinpRemoveVectoredHandler(uint32_t isContinue, void* handle) { if (!handle) { gLastError = 6; return 0; } WinpVectoredLock(); uint32_t slot = UINT32_MAX; for (uint32_t i = 0; i < WIN_VECTORED_MAX_HANDLERS; i++) { if (handle == &gWinVectoredHandlers[i]) { slot = i; break; } } if (slot == UINT32_MAX || !gWinVectoredHandlers[slot].Active || gWinVectoredHandlers[slot].IsContinue != isContinue) { WinpVectoredUnlock(); gLastError = 6; return 0; } uint32_t* head = WinpVectoredHeadSlot(isContinue); uint32_t* tail = WinpVectoredTailSlot(isContinue); WIN_VECTORED_HANDLER_ENTRY* entry = &gWinVectoredHandlers[slot]; if (entry->Previous != UINT32_MAX) gWinVectoredHandlers[entry->Previous].Next = entry->Next; else *head = entry->Next; if (entry->Next != UINT32_MAX) gWinVectoredHandlers[entry->Next].Previous = entry->Previous; else *tail = entry->Previous; memset(entry, 0, sizeof(*entry)); entry->Previous = UINT32_MAX; entry->Next = UINT32_MAX; WinpVectoredUnlock(); return 1; } // Registers one Win32 vectored exception handler. __declspec(dllexport) void* AddVectoredExceptionHandler(unsigned long First, void* Handler) { return WinpAddVectoredHandler(0, First, Handler); } // Removes one Win32 vectored exception handler. __declspec(dllexport) unsigned long RemoveVectoredExceptionHandler(void* Handle) { return WinpRemoveVectoredHandler(0, Handle); } // Registers one Win32 vectored continue handler. __declspec(dllexport) void* AddVectoredContinueHandler(unsigned long First, void* Handler) { return WinpAddVectoredHandler(1, First, Handler); } // Removes one Win32 vectored continue handler. __declspec(dllexport) unsigned long RemoveVectoredContinueHandler(void* Handle) { return WinpRemoveVectoredHandler(1, Handle); } // Pushes one explicit runtime SEH frame for tests and hand-written personality code. __declspec(dllexport) void* RtlPushExceptionFrame(RTL_EXCEPTION_FRAME* Frame, PRTL_EXCEPTION_FRAME_HANDLER Handler, void* UserContext) { if (!Frame || !Handler) { gLastError = 87; return NULL; } if (!WinpEnsureExceptionBridge()) return NULL; memset(Frame, 0, sizeof(*Frame)); Frame->Size = sizeof(*Frame); Frame->Previous = WinpSehFrameHead(); Frame->Handler = Handler; Frame->UserContext = UserContext; WinpSetSehFrameHead(Frame); return Frame; } // Pops the current explicit runtime SEH frame and enforces stack discipline. __declspec(dllexport) BOOL RtlPopExceptionFrame(RTL_EXCEPTION_FRAME* Frame) { if (!Frame || WinpSehFrameHead() != Frame) { gLastError = 87; return FALSE; } WinpSetSehFrameHead(Frame->Previous); memset(Frame, 0, sizeof(*Frame)); return TRUE; } __declspec(dllexport) void RaiseException(DWORD dwExceptionCode, DWORD dwExceptionFlags, DWORD nNumberOfArguments, const uintptr_t* lpArguments) { uint64_t arguments[EXCEPTION_MAXIMUM_PARAMETERS]; DWORD count = nNumberOfArguments; if (count > EXCEPTION_MAXIMUM_PARAMETERS) count = EXCEPTION_MAXIMUM_PARAMETERS; for (DWORD i = 0; i < count; i++) arguments[i] = lpArguments ? (uint64_t)lpArguments[i] : 0; SYS_RAISE_EXCEPTION_REQUEST request; memset(&request, 0, sizeof(request)); request.Size = sizeof(request); request.Code = dwExceptionCode; request.Flags = (dwExceptionFlags & EXCEPTION_NONCONTINUABLE) ? SYS_RAISE_EXCEPTION_FLAG_NONCONTINUABLE : SYS_RAISE_EXCEPTION_FLAG_NONE; request.ParameterCount = count; request.Parameters = count ? arguments : NULL; uint32_t status = SysRaiseException(&request); if (status != NTLSTATUS_SUCCESS) SysExitProcess((int32_t)status); } // Implements the unhandled Exception Filter operation. __declspec(dllexport) long UnhandledExceptionFilter(EXCEPTION_POINTERS* ExceptionInfo) { (void)ExceptionInfo; return EXCEPTION_CONTINUE_SEARCH; } typedef long (*LPTOP_LEVEL_EXCEPTION_FILTER)(EXCEPTION_POINTERS*); __declspec(dllexport) LPTOP_LEVEL_EXCEPTION_FILTER // Updates unhandled Exception Filter. SetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpFilter) { (void)lpFilter; return NULL; // previous filter: none } // Reports that no user-mode debugger is attached. __declspec(dllexport) BOOL IsDebuggerPresent(void) { return FALSE; } // RTL Exception / Unwind metadata helpers. typedef struct _RUNTIME_FUNCTION { unsigned int BeginAddress; unsigned int EndAddress; unsigned int UnwindInfoAddress; } RUNTIME_FUNCTION; __declspec(dllexport) BOOL RtlAddFunctionTable(RUNTIME_FUNCTION* FunctionTable, DWORD EntryCount, unsigned long long BaseAddress) { (void)FunctionTable; (void)EntryCount; (void)BaseAddress; return TRUE; } // Implements the rtl Delete Function Table operation. __declspec(dllexport) BOOL RtlDeleteFunctionTable(RUNTIME_FUNCTION* FunctionTable) { (void)FunctionTable; return TRUE; } // We have no runtime function table, so RtlLookupFunctionEntry always fails. __declspec(dllexport) RUNTIME_FUNCTION* RtlLookupFunctionEntry(unsigned long long ControlPc, unsigned long long* ImageBase, void* HistoryTable) { (void)ControlPc; (void)HistoryTable; if (ImageBase) *ImageBase = 0; return NULL; } __declspec(dllexport) void* RtlVirtualUnwind(unsigned long HandlerType, unsigned long long ImageBase, unsigned long long ControlPc, RUNTIME_FUNCTION* FunctionEntry, void* ContextRecord, void** HandlerData, unsigned long long* EstablisherFrame, void* ContextPointers) { (void)HandlerType; (void)ImageBase; (void)ControlPc; (void)FunctionEntry; (void)ContextRecord; (void)ContextPointers; if (HandlerData) *HandlerData = NULL; if (EstablisherFrame)*EstablisherFrame = 0; return NULL; } // Implements the rtl Capture Context operation. __declspec(dllexport) void RtlCaptureContext(void* ContextRecord) { // Zero out the context record so callers don't read garbage. if (!ContextRecord) return; // CONTEXT is ~1232 bytes on x64; zero a conservative upper bound. unsigned char* p = (unsigned char*)ContextRecord; for (int i = 0; i < 1232; i++) p[i] = 0; } __declspec(dllexport) void RtlUnwindEx(void* TargetFrame, void* TargetIp, void* ExceptionRecord, void* ReturnValue, void* ContextRecord, void* HistoryTable) { (void)TargetFrame; (void)TargetIp; (void)ExceptionRecord; (void)ReturnValue; (void)ContextRecord; (void)HistoryTable; // No real unwind possible; halt rather than corrupt the stack silently. while (true) ; } // Code Pages & Locale helpers. typedef struct { unsigned int MaxCharSize; unsigned char DefaultChar[2]; unsigned char LeadByte[12]; } CPINFO; // Returns cP Info. __declspec(dllexport) BOOL GetCPInfo(unsigned int CodePage, CPINFO* lpCPInfo) { (void)CodePage; if (lpCPInfo) { lpCPInfo->MaxCharSize = 1; lpCPInfo->DefaultChar[0] = '?'; lpCPInfo->DefaultChar[1] = 0; for (int i = 0; i < 12; i++) lpCPInfo->LeadByte[i] = 0; } return TRUE; } // Checks whether valid Code Page. __declspec(dllexport) BOOL IsValidCodePage(unsigned int CodePage) { // Acknowledge the two code pages we claim to support. return (CodePage == 1252 || CodePage == 437) ? TRUE : FALSE; } __declspec(dllexport) int LCMapStringA(unsigned int Locale, DWORD dwMapFlags, const char* lpSrcStr, int cchSrc, char* lpDestStr, int cchDest) { (void)Locale; (void)dwMapFlags; (void)lpSrcStr; (void)cchSrc; (void)lpDestStr; (void)cchDest; return 0; } __declspec(dllexport) int LCMapStringW(unsigned int Locale, DWORD dwMapFlags, const unsigned short* lpSrcStr, int cchSrc, unsigned short* lpDestStr, int cchDest) { (void)Locale; (void)dwMapFlags; (void)lpSrcStr; (void)cchSrc; (void)lpDestStr; (void)cchDest; return 0; } __declspec(dllexport) BOOL GetStringTypeA(unsigned int Locale, DWORD dwInfoType, const char* lpSrcStr, int cchSrc, unsigned short* lpCharType) { (void)Locale; (void)dwInfoType; (void)lpSrcStr; (void)cchSrc; (void)lpCharType; return FALSE; } __declspec(dllexport) BOOL GetStringTypeW(DWORD dwInfoType, const unsigned short* lpSrcStr, int cchSrc, unsigned short* lpCharType) { (void)dwInfoType; (void)lpSrcStr; (void)cchSrc; (void)lpCharType; return FALSE; } __declspec(dllexport) int GetLocaleInfoA(unsigned int Locale, DWORD LCType, char* lpLCData, int cchData) { (void)Locale; (void)LCType; (void)lpLCData; (void)cchData; return 0; } // Fiber Local Storage (FLS). // Allocation state is process-global, but the values themselves are per-thread, // matching the contract that Bink and the CRT expect when worker threads are // enabled. The old single global value array let unrelated threads overwrite // each other's decoder-local state. static int gFlsUsed[FLS_MAX_SLOTS]; // 0 = free, 1 = allocated // Implements the fls Alloc operation. __declspec(dllexport) DWORD FlsAlloc(void* lpCallback) { (void)lpCallback; for (int i = 0; i < FLS_MAX_SLOTS; i++) { if (!gFlsUsed[i]) { gFlsUsed[i] = 1; K32ThreadEnv()->FlsSlots[i] = NULL; return (DWORD)i; } } gLastError = 8; // ERROR_NOT_ENOUGH_MEMORY return (DWORD)FLS_OUT_OF_INDEXES; } // Implements the fls Get Value operation. __declspec(dllexport) void* FlsGetValue(DWORD dwFlsIndex) { if (dwFlsIndex >= FLS_MAX_SLOTS || !gFlsUsed[dwFlsIndex]) { gLastError = 87; // ERROR_INVALID_PARAMETER return NULL; } return K32ThreadEnv()->FlsSlots[dwFlsIndex]; } // Implements the fls Set Value operation. __declspec(dllexport) BOOL FlsSetValue(DWORD dwFlsIndex, void* lpFlsData) { if (dwFlsIndex >= FLS_MAX_SLOTS || !gFlsUsed[dwFlsIndex]) { gLastError = 87; return FALSE; } K32ThreadEnv()->FlsSlots[dwFlsIndex] = lpFlsData; return TRUE; } // Implements the fls Free operation. __declspec(dllexport) BOOL FlsFree(DWORD dwFlsIndex) { if (dwFlsIndex >= FLS_MAX_SLOTS || !gFlsUsed[dwFlsIndex]) { gLastError = 87; return FALSE; } gFlsUsed[dwFlsIndex] = 0; K32ThreadEnv()->FlsSlots[dwFlsIndex] = NULL; return TRUE; } // Pointer encoding (security cookie obfuscation) // We have no security cookie; return the pointer unchanged. __declspec(dllexport) void* EncodePointer(void* Ptr) { return Ptr; } // Implements the decode Pointer operation. __declspec(dllexport) void* DecodePointer(void* Ptr) { return Ptr; }