refactor syscall ABI and FAT32 driver to use request structs and string views natively, enforce handle access rights on object lookup, add scheduler statistics tracking, fix KiSchedule to prevent 50% idle throttling on CPU-bound threads, better document x64 initial user stack alignment, fix process teardown to properly signal exit events and manage thread counts, optimize doom file I/O with a custom handle struct to internally track position and size, add SubsystemData to TEB for generic thread-local state, apply PAGE_NX to non-executable PE sections in the loader, update native apps, tests, and shells to match new APIs, update kernel32 directory retrieval.
This commit is contained in:
1 parent
603fbdfab1
commit
e1248f4afe
43 files changed
+2892
-1857
No files matched your search
+114
-33
@@ -11,8 +11,8 @@
|
||||
// - HeapAlloc / HeapFree / HeapReAlloc ignore the HANDLE heap argument and
|
||||
// always use the single kernel user-heap. This is fine: we don't expose
|
||||
// multiple heaps, and NULL is a legal (no-op) heap argument under Win32.
|
||||
// - GetLastError / SetLastError are per-thread on Windows. We keep a single
|
||||
// global for now; enough for Bink and similar single-threaded guests.
|
||||
// - Win32 per-thread state lives behind SYS_TEB::SubsystemData so the native
|
||||
// TEB ABI stays subsystem-neutral.
|
||||
// - File I/O uses SYS_OPEN_FILE / SYS_READ_FILE / SYS_SEEK_FILE /
|
||||
// SYS_GET_FILE_SIZE / SYS_CLOSE_HANDLE (unified close path - no separate
|
||||
// SysCloseFile).
|
||||
@@ -160,14 +160,94 @@ static void TranslatePath(const char* input, char* output) {
|
||||
}
|
||||
}
|
||||
|
||||
static DWORD gLastError = 0;
|
||||
|
||||
static uint32_t K32OpenFileNative(const char* path, uint32_t* handleOut) {
|
||||
SYS_PATH_HANDLE_REQUEST req = { SysSvFromCstr(path), handleOut };
|
||||
return SysOpenFile(&req);
|
||||
}
|
||||
|
||||
static uint32_t K32CreateFileNative(const char* path, uint32_t* handleOut) {
|
||||
SYS_PATH_HANDLE_REQUEST req = { SysSvFromCstr(path), handleOut };
|
||||
return SysCreateFile(&req);
|
||||
}
|
||||
|
||||
static uint32_t K32DeleteFileNative(const char* path) {
|
||||
SYS_PATH_REQUEST req = { SysSvFromCstr(path) };
|
||||
return SysDeleteFile(&req);
|
||||
}
|
||||
|
||||
static uint32_t K32OpenDirNative(const char* path, uint32_t* handleOut) {
|
||||
SYS_PATH_HANDLE_REQUEST req = { SysSvFromCstr(path), handleOut };
|
||||
return SysOpenDir(&req);
|
||||
}
|
||||
|
||||
static uint32_t K32SetCwdNative(const char* path) {
|
||||
SYS_PATH_REQUEST req = { SysSvFromCstr(path) };
|
||||
return SysSetCwd(&req);
|
||||
}
|
||||
|
||||
static uint32_t K32GetCwdNative(char* buffer, size_t capacity, size_t* lengthOut) {
|
||||
size_t len = 0;
|
||||
size_t writable = (buffer && capacity) ? capacity - 1 : 0;
|
||||
SYS_GET_CWD_REQUEST req = { buffer, writable, &len };
|
||||
uint32_t s = SysGetCwd(&req);
|
||||
if (lengthOut) *lengthOut = len;
|
||||
if (s == 0 && buffer && capacity) buffer[len] = '\0';
|
||||
return s;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static void K32WriteConsoleSpan(const char* data, size_t length) {
|
||||
SYS_WRITE_CONSOLE_REQUEST req = { SysSvFromParts(data, length) };
|
||||
SysWriteConsole(&req);
|
||||
}
|
||||
|
||||
static void K32DebugPrintA(const char* s) {
|
||||
if (!s) return;
|
||||
SYS_DEBUG_PRINT_REQUEST req = { SysSvFromCstr(s) };
|
||||
SysDebugPrint(&req);
|
||||
}
|
||||
|
||||
#define WIN32_TLS_SLOTS 64
|
||||
|
||||
typedef struct WIN32_THREAD_ENV {
|
||||
DWORD LastError;
|
||||
DWORD Reserved0;
|
||||
void* TlsSlots[WIN32_TLS_SLOTS];
|
||||
} WIN32_THREAD_ENV;
|
||||
|
||||
static WIN32_THREAD_ENV gFallbackThreadEnv;
|
||||
|
||||
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*)SysAlloc(sizeof(WIN32_THREAD_ENV));
|
||||
if (!env) return &gFallbackThreadEnv;
|
||||
memset(env, 0, sizeof(*env));
|
||||
teb->SubsystemData = env;
|
||||
}
|
||||
return env;
|
||||
}
|
||||
|
||||
static DWORD* K32LastErrorSlot(void) {
|
||||
return &K32ThreadEnv()->LastError;
|
||||
}
|
||||
|
||||
#define gLastError (*K32LastErrorSlot())
|
||||
|
||||
static BOOL KiFileExistsA(const char* path) {
|
||||
if (!path || !*path) return FALSE;
|
||||
char native[MAX_PATH];
|
||||
TranslatePath(path, native);
|
||||
uint32_t h = 0;
|
||||
if (SysOpenFile(native, &h) != 0) return FALSE;
|
||||
if (K32OpenFileNative(native, &h) != 0) return FALSE;
|
||||
SysCloseHandle(h);
|
||||
return TRUE;
|
||||
}
|
||||
@@ -268,7 +348,7 @@ __declspec(dllexport) _Noreturn void ExitProcess(unsigned int code) {
|
||||
// Debug output
|
||||
// ---------------------------------------------------------------------------
|
||||
__declspec(dllexport) void OutputDebugStringA(const char* str) {
|
||||
if (str) SysDebugPrint(str);
|
||||
if (str) K32DebugPrintA(str);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -510,7 +590,7 @@ __declspec(dllexport) HANDLE CreateFileA(const char* name,
|
||||
if (disposition == OPEN_EXISTING || disposition == TRUNCATE_EXISTING) {
|
||||
// Open the file via the read path (it must already exist).
|
||||
uint32_t kh = 0;
|
||||
uint32_t s = SysOpenFile(translatedName, &kh);
|
||||
uint32_t s = K32OpenFileNative(translatedName, &kh);
|
||||
if (s != 0) { gLastError = 2; return INVALID_HANDLE_VALUE; }
|
||||
|
||||
if (disposition == TRUNCATE_EXISTING && wantWrite) {
|
||||
@@ -529,10 +609,10 @@ __declspec(dllexport) HANDLE CreateFileA(const char* name,
|
||||
// Create-or-replace: try to create; if the file already exists,
|
||||
// open it and truncate it to zero instead.
|
||||
uint32_t kh = 0;
|
||||
uint32_t s = SysCreateFile(translatedName, &kh);
|
||||
uint32_t s = K32CreateFileNative(translatedName, &kh);
|
||||
if (s != 0) {
|
||||
// File may already exist - open and truncate.
|
||||
s = SysOpenFile(translatedName, &kh);
|
||||
s = K32OpenFileNative(translatedName, &kh);
|
||||
if (s != 0) { gLastError = 5; return INVALID_HANDLE_VALUE; }
|
||||
SysTruncateFile(kh, 0);
|
||||
}
|
||||
@@ -542,8 +622,8 @@ __declspec(dllexport) HANDLE CreateFileA(const char* name,
|
||||
if (disposition == OPEN_ALWAYS && wantWrite) {
|
||||
// Open if exists, create if not.
|
||||
uint32_t kh = 0;
|
||||
if (SysOpenFile(translatedName, &kh) != 0) {
|
||||
if (SysCreateFile(translatedName, &kh) != 0) {
|
||||
if (K32OpenFileNative(translatedName, &kh) != 0) {
|
||||
if (K32CreateFileNative(translatedName, &kh) != 0) {
|
||||
gLastError = 5;
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
@@ -555,7 +635,7 @@ __declspec(dllexport) HANDLE CreateFileA(const char* name,
|
||||
// Fail if the file already exists (we can't check atomically,
|
||||
// but SysCreateFile returns NAME_COLLISION for existing files).
|
||||
uint32_t kh = 0;
|
||||
uint32_t s = SysCreateFile(translatedName, &kh);
|
||||
uint32_t s = K32CreateFileNative(translatedName, &kh);
|
||||
if (s != 0) { gLastError = 80; return INVALID_HANDLE_VALUE; } // ERROR_FILE_EXISTS
|
||||
return KH_TO_HANDLE(kh);
|
||||
}
|
||||
@@ -677,7 +757,7 @@ __declspec(dllexport) BOOL DeleteFileA(const char* lpFileName) {
|
||||
char translatedPath[MAX_PATH];
|
||||
TranslatePath(lpFileName, translatedPath);
|
||||
|
||||
uint32_t s = SysDeleteFile(translatedPath);
|
||||
uint32_t s = K32DeleteFileNative(translatedPath);
|
||||
if (s != 0) { gLastError = 2; return FALSE; }
|
||||
return TRUE;
|
||||
}
|
||||
@@ -747,15 +827,13 @@ __declspec(dllexport) HANDLE GetCurrentThread(void) {
|
||||
__declspec(dllexport) DWORD GetCurrentThreadId(void) { return (DWORD)SysGetCurrentTid(); }
|
||||
__declspec(dllexport) DWORD GetCurrentProcessId(void) { return (DWORD)SysGetCurrentPid(); }
|
||||
|
||||
// Tiny TLS table; enough for MSVCRT/TCC compatibility paths that probe TLS.
|
||||
#define WIN32_TLS_SLOTS 64
|
||||
static void* gTlsSlots[WIN32_TLS_SLOTS];
|
||||
// Tiny TLS index allocator; slot values are stored per thread in WIN32_THREAD_ENV.
|
||||
static uint64_t gTlsBitmap = 1; // reserve slot 0
|
||||
|
||||
__declspec(dllexport) DWORD TlsAlloc(void) {
|
||||
for (DWORD i = 1; i < WIN32_TLS_SLOTS; i++) {
|
||||
uint64_t bit = 1ULL << i;
|
||||
if (!(gTlsBitmap & bit)) { gTlsBitmap |= bit; gTlsSlots[i] = NULL; return i; }
|
||||
if (!(gTlsBitmap & bit)) { gTlsBitmap |= bit; return i; }
|
||||
}
|
||||
gLastError = 8;
|
||||
return 0xFFFFFFFFUL;
|
||||
@@ -763,20 +841,23 @@ __declspec(dllexport) DWORD TlsAlloc(void) {
|
||||
|
||||
__declspec(dllexport) BOOL TlsFree(DWORD dwTlsIndex) {
|
||||
if (dwTlsIndex >= WIN32_TLS_SLOTS || !(gTlsBitmap & (1ULL << dwTlsIndex))) { gLastError = 87; return FALSE; }
|
||||
gTlsSlots[dwTlsIndex] = NULL;
|
||||
WIN32_THREAD_ENV* env = K32ThreadEnv();
|
||||
if (env) env->TlsSlots[dwTlsIndex] = NULL;
|
||||
gTlsBitmap &= ~(1ULL << dwTlsIndex);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
__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 gTlsSlots[dwTlsIndex];
|
||||
return env->TlsSlots[dwTlsIndex];
|
||||
}
|
||||
|
||||
__declspec(dllexport) BOOL TlsSetValue(DWORD dwTlsIndex, void* lpTlsValue) {
|
||||
if (dwTlsIndex >= WIN32_TLS_SLOTS || !(gTlsBitmap & (1ULL << dwTlsIndex))) { gLastError = 87; return FALSE; }
|
||||
gTlsSlots[dwTlsIndex] = lpTlsValue;
|
||||
WIN32_THREAD_ENV* env = K32ThreadEnv();
|
||||
env->TlsSlots[dwTlsIndex] = lpTlsValue;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -797,7 +878,7 @@ static BOOL KiIsWin32DllNameA(const char* name) {
|
||||
}
|
||||
|
||||
static void KiDbgWriteA(const char* s) {
|
||||
if (s) SysWriteConsole(s, strlen(s));
|
||||
if (s) K32WriteConsoleSpan(s, strlen(s));
|
||||
}
|
||||
|
||||
__declspec(dllexport) HANDLE GetModuleHandleA(const char* lpModuleName) {
|
||||
@@ -856,8 +937,8 @@ __declspec(dllexport) DWORD GetModuleFileNameA(HANDLE hModule,
|
||||
if (!lpFilename || !nSize) return 0;
|
||||
|
||||
SYS_PEB* peb = Win32Peb();
|
||||
const char* src = (peb && peb->Magic == SYS_PEB_MAGIC && peb->ImagePath)
|
||||
? peb->ImagePath
|
||||
const char* src = (peb && peb->Magic == SYS_PEB_MAGIC && peb->ImagePath.Data)
|
||||
? peb->ImagePath.Data
|
||||
: "";
|
||||
|
||||
DWORD len = (DWORD)strlen(src);
|
||||
@@ -898,8 +979,8 @@ __declspec(dllexport) void GetStartupInfoA(STARTUPINFOA* lpStartupInfo) {
|
||||
|
||||
__declspec(dllexport) char* GetCommandLineA(void) {
|
||||
SYS_PEB* peb = Win32Peb();
|
||||
if (!peb || peb->Magic != SYS_PEB_MAGIC || !peb->CommandLine) return "";
|
||||
return (char*)peb->CommandLine;
|
||||
if (!peb || peb->Magic != SYS_PEB_MAGIC || !peb->CommandLine.Data) return "";
|
||||
return (char*)peb->CommandLine.Data;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -1025,11 +1106,11 @@ __declspec(dllexport) BOOL CreateProcessA(
|
||||
|
||||
if (lpCurrentDirectory && lpCurrentDirectory[0]) {
|
||||
char translatedCwd[MAX_PATH];
|
||||
uint32_t gs = SysGetCwd(savedCwd, sizeof(savedCwd));
|
||||
uint32_t gs = K32GetCwdNative(savedCwd, sizeof(savedCwd), NULL);
|
||||
if (gs != 0) { gLastError = 3; return FALSE; }
|
||||
|
||||
TranslatePath(lpCurrentDirectory, translatedCwd);
|
||||
gs = SysSetCwd(translatedCwd);
|
||||
gs = K32SetCwdNative(translatedCwd);
|
||||
if (gs != 0) { gLastError = 3; return FALSE; }
|
||||
changedCwd = true;
|
||||
}
|
||||
@@ -1038,7 +1119,7 @@ __declspec(dllexport) BOOL CreateProcessA(
|
||||
// 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 = SysCreateProcess(translatedPath, &kh, cmdline);
|
||||
uint32_t s = K32CreateProcessNative(translatedPath, &kh, cmdline);
|
||||
|
||||
if (changedCwd) {
|
||||
if (savedCwd[0]) {
|
||||
@@ -1048,9 +1129,9 @@ __declspec(dllexport) BOOL CreateProcessA(
|
||||
if (rlen + 4 > sizeof(restoreCwd)) rlen = sizeof(restoreCwd) - 4;
|
||||
memcpy(restoreCwd + 3, savedCwd, rlen);
|
||||
restoreCwd[3 + rlen] = '\0';
|
||||
SysSetCwd(restoreCwd);
|
||||
K32SetCwdNative(restoreCwd);
|
||||
} else {
|
||||
SysSetCwd("0:/");
|
||||
K32SetCwdNative("0:/");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1166,7 +1247,7 @@ __declspec(dllexport) BOOL WriteConsoleA(HANDLE hConsoleOutput,
|
||||
if (lpNumberOfCharsWritten) *lpNumberOfCharsWritten = 0;
|
||||
return TRUE;
|
||||
}
|
||||
SysWriteConsole((const char*)lpBuffer, (size_t)nNumberOfCharsToWrite);
|
||||
K32WriteConsoleSpan((const char*)lpBuffer, (size_t)nNumberOfCharsToWrite);
|
||||
if (lpNumberOfCharsWritten) *lpNumberOfCharsWritten = nNumberOfCharsToWrite;
|
||||
return TRUE;
|
||||
}
|
||||
@@ -1306,7 +1387,7 @@ __declspec(dllexport) HANDLE FindFirstFileA(const char* lpFileName,
|
||||
|
||||
// Open the kernel directory iterator
|
||||
uint32_t kh = 0;
|
||||
uint32_t s = SysOpenDir(dir[0] ? dir : NULL, &kh);
|
||||
uint32_t s = K32OpenDirNative(dir[0] ? dir : NULL, &kh);
|
||||
if (s != 0 || kh == 0) {
|
||||
gLastError = 2; // ERROR_FILE_NOT_FOUND
|
||||
return INVALID_HANDLE_VALUE;
|
||||
@@ -1387,7 +1468,7 @@ __declspec(dllexport) BOOL SetCurrentDirectoryA(const char* lpPathName) {
|
||||
char translatedPath[MAX_PATH];
|
||||
TranslatePath(lpPathName, translatedPath);
|
||||
|
||||
uint32_t s = SysSetCwd(translatedPath);
|
||||
uint32_t s = K32SetCwdNative(translatedPath);
|
||||
if (s != 0) { gLastError = 2; return FALSE; }
|
||||
return TRUE;
|
||||
}
|
||||
@@ -1400,7 +1481,7 @@ __declspec(dllexport) DWORD GetCurrentDirectoryA(DWORD nBufferLength, char* lpBu
|
||||
|
||||
// Kernel returns native "N:/path". Present it as a Win32 drive letter.
|
||||
char raw[512];
|
||||
uint32_t s = SysGetCwd(raw, sizeof(raw));
|
||||
uint32_t s = K32GetCwdNative(raw, sizeof(raw), NULL);
|
||||
if (s != 0) { gLastError = 1; return 0; }
|
||||
|
||||
char full[515];
|
||||
|
||||
Reference in new issue
Block a user