implement user mode catchable exceptions, refactor system status codes to use NTLSTATUS_ prefix, update build scripts to use shared literal macros for linker arguments, update named queue lifetime cleanup to include KeNamedQueueUnpublishHandle.
This commit is contained in:
1 parent
1f5477cf66
commit
b7fcfce6f7
140 files changed
+7649
-3943
No files matched your search
@@ -173,7 +173,7 @@ static int doom_eof_wrapper(void* handle)
|
||||
static void doom_gettime_wrapper(int* sec, int* usec)
|
||||
{
|
||||
uint64_t frequency = 0;
|
||||
if (SysGetTickFrequency(&frequency) != STATUS_SUCCESS || !frequency) {
|
||||
if (SysGetTickFrequency(&frequency) != NTLSTATUS_SUCCESS || !frequency) {
|
||||
*sec = 0;
|
||||
*usec = 0;
|
||||
return;
|
||||
@@ -278,7 +278,7 @@ static bool g_prev_key[KEYMAP_COUNT];
|
||||
static bool ntlite_key_down(INPUT_KEY key)
|
||||
{
|
||||
bool down = false;
|
||||
return SysIsKeyDown(key, &down) == STATUS_SUCCESS && down;
|
||||
return SysIsKeyDown(key, &down) == NTLSTATUS_SUCCESS && down;
|
||||
}
|
||||
|
||||
static void poll_input(void)
|
||||
@@ -309,9 +309,16 @@ static uint32_t g_surface_pitch_pixels;
|
||||
|
||||
static void init_surface(void)
|
||||
{
|
||||
uint32_t s = SysCreateSurface(DISP_W, DISP_H, SYS_SURFACE_FORMAT_XRGB8888,
|
||||
SYS_SURFACE_FLAG_NONE, &g_surface_handle);
|
||||
if (s != STATUS_SUCCESS || !g_surface_handle) {
|
||||
SYS_CREATE_SURFACE_REQUEST req;
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.Size = sizeof(req);
|
||||
req.Width = DISP_W;
|
||||
req.Height = DISP_H;
|
||||
req.Format = SYS_SURFACE_FORMAT_XRGB8888;
|
||||
req.Flags = SYS_SURFACE_FLAG_NONE;
|
||||
req.HandleOut = &g_surface_handle;
|
||||
uint32_t s = SysCreateSurface(&req);
|
||||
if (s != NTLSTATUS_SUCCESS || !g_surface_handle) {
|
||||
doom_print_wrapper("doom: SysCreateSurface failed\n");
|
||||
SysExitProcess(1);
|
||||
}
|
||||
@@ -319,7 +326,7 @@ static void init_surface(void)
|
||||
void* base = 0;
|
||||
uint32_t pitchBytes = 0;
|
||||
s = SysMapSurface(g_surface_handle, &base, &pitchBytes);
|
||||
if (s != STATUS_SUCCESS || !base || pitchBytes < DISP_W * sizeof(uint32_t)) {
|
||||
if (s != NTLSTATUS_SUCCESS || !base || pitchBytes < DISP_W * sizeof(uint32_t)) {
|
||||
doom_print_wrapper("doom: SysMapSurface failed\n");
|
||||
SysExitProcess(1);
|
||||
}
|
||||
@@ -359,7 +366,7 @@ static void render_frame(const uint8_t* rgba)
|
||||
|
||||
DISPLAY_RECT rect = { 0, 0, DISP_W, DISP_H };
|
||||
uint32_t code = SysPresentSurface(g_surface_handle, &rect, 1);
|
||||
if (code != STATUS_SUCCESS) {
|
||||
if (code != NTLSTATUS_SUCCESS) {
|
||||
SysExitProcess(code);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -508,7 +508,7 @@ static void editor_loop(void) {
|
||||
render();
|
||||
|
||||
INPUT_KEY key = INPUT_KEY_NONE;
|
||||
if (SysReadKey(&key) != STATUS_SUCCESS) continue;
|
||||
if (SysReadKey(&key) != NTLSTATUS_SUCCESS) continue;
|
||||
uint32_t mods = SysGetKeyModifiers();
|
||||
bool ctrl = (mods & INPUT_MOD_CTRL) != 0;
|
||||
|
||||
|
||||
@@ -160,7 +160,7 @@ static uint32_t resolve_host(const char* host, SYS_SOCKET_ADDRESS* address) {
|
||||
address->Size = sizeof(*address);
|
||||
address->Family = SYS_AF_INET;
|
||||
memcpy(address->Address, ip, 4);
|
||||
return STATUS_SUCCESS;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
size_t resolvedSize = sizeof(*address);
|
||||
@@ -173,8 +173,8 @@ static uint32_t resolve_host(const char* host, SYS_SOCKET_ADDRESS* address) {
|
||||
req.AddressSizeInOut = &resolvedSize;
|
||||
|
||||
uint32_t st = SysResolveHost(&req);
|
||||
if (st == STATUS_SUCCESS)
|
||||
return STATUS_SUCCESS;
|
||||
if (st == NTLSTATUS_SUCCESS)
|
||||
return NTLSTATUS_SUCCESS;
|
||||
|
||||
resolvedSize = sizeof(*address);
|
||||
memset(address, 0, sizeof(*address));
|
||||
@@ -224,7 +224,7 @@ int main(void) {
|
||||
}
|
||||
|
||||
uint32_t st = resolve_host(host, &addr);
|
||||
if (st != STATUS_SUCCESS) {
|
||||
if (st != NTLSTATUS_SUCCESS) {
|
||||
print("httpget: resolve failed "); print_u64(st); print(" for "); print(host); print("\n");
|
||||
usage();
|
||||
SysExitProcess(1);
|
||||
@@ -242,7 +242,7 @@ int main(void) {
|
||||
|
||||
uint32_t sock = 0;
|
||||
st = SysCreateSocket(addr.Family, SYS_SOCK_STREAM, SYS_IPPROTO_TCP, &sock);
|
||||
if (st != STATUS_SUCCESS) {
|
||||
if (st != NTLSTATUS_SUCCESS) {
|
||||
print("httpget: SysCreateSocket failed "); print_u64(st); print("\n");
|
||||
SysExitProcess(1);
|
||||
}
|
||||
@@ -250,7 +250,7 @@ int main(void) {
|
||||
addr.Port = 80;
|
||||
|
||||
st = SysConnectSocket(sock, &addr, sizeof(addr));
|
||||
if (st != STATUS_SUCCESS) {
|
||||
if (st != NTLSTATUS_SUCCESS) {
|
||||
print("httpget: SysConnectSocket failed "); print_u64(st); print("\n");
|
||||
SysCloseHandle(sock);
|
||||
SysExitProcess(1);
|
||||
@@ -269,7 +269,7 @@ int main(void) {
|
||||
while (totalSent < off) {
|
||||
size_t sent = 0;
|
||||
st = SysSendSocket(sock, request + totalSent, off - totalSent, 0, &sent);
|
||||
if (st != STATUS_SUCCESS || sent == 0) {
|
||||
if (st != NTLSTATUS_SUCCESS || sent == 0) {
|
||||
print("httpget: SysSendSocket failed "); print_u64(st); print(" sent="); print_u64(sent); print("\n");
|
||||
SysCloseHandle(sock);
|
||||
SysExitProcess(1);
|
||||
@@ -282,7 +282,7 @@ int main(void) {
|
||||
for (;;) {
|
||||
size_t got = 0;
|
||||
st = SysRecvSocket(sock, buf, sizeof(buf) - 1, 0, &got);
|
||||
if (st != STATUS_SUCCESS) {
|
||||
if (st != NTLSTATUS_SUCCESS) {
|
||||
print("\nhttpget: SysRecvSocket failed "); print_u64(st); print(" after "); print_u64(total); print(" bytes\n");
|
||||
SysCloseHandle(sock);
|
||||
SysExitProcess(1);
|
||||
|
||||
@@ -30,8 +30,8 @@ int main(void) {
|
||||
char metricsBuf[128];
|
||||
|
||||
while (true) {
|
||||
if (SysGetConsoleInfo(&console) == STATUS_SUCCESS &&
|
||||
SysGetMemoryStatus(&mem) == STATUS_SUCCESS) {
|
||||
if (SysGetConsoleInfo(&console) == NTLSTATUS_SUCCESS &&
|
||||
SysGetMemoryStatus(&mem) == NTLSTATUS_SUCCESS) {
|
||||
|
||||
// If the system isn't reporting columns correctly, default to a safe standard width
|
||||
int columns = (console.Columns > 0) ? (int)console.Columns : 80;
|
||||
|
||||
+10
-10
@@ -133,7 +133,7 @@ static bool parse_u32(const char* s, uint32_t* out) {
|
||||
// Implements the resolve host operation.
|
||||
static uint32_t resolve_host(const char* host, uint8_t ip[4]) {
|
||||
if (parse_ipv4(host, ip))
|
||||
return STATUS_SUCCESS;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
|
||||
SYS_SOCKET_ADDRESS resolved;
|
||||
size_t resolvedSize = sizeof(resolved);
|
||||
@@ -146,16 +146,16 @@ static uint32_t resolve_host(const char* host, uint8_t ip[4]) {
|
||||
req.AddressSizeInOut = &resolvedSize;
|
||||
|
||||
uint32_t st = SysResolveHost(&req);
|
||||
if (st != STATUS_SUCCESS)
|
||||
if (st != NTLSTATUS_SUCCESS)
|
||||
return st;
|
||||
if (resolved.Family != SYS_AF_INET)
|
||||
return STATUS_NOT_FOUND;
|
||||
return NTLSTATUS_NOT_FOUND;
|
||||
|
||||
ip[0] = resolved.Address[0];
|
||||
ip[1] = resolved.Address[1];
|
||||
ip[2] = resolved.Address[2];
|
||||
ip[3] = resolved.Address[3];
|
||||
return STATUS_SUCCESS;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Implements the icmp checksum operation.
|
||||
@@ -258,7 +258,7 @@ int main(void) {
|
||||
|
||||
uint8_t ip[4];
|
||||
uint32_t st = resolve_host(host, ip);
|
||||
if (st != STATUS_SUCCESS) {
|
||||
if (st != NTLSTATUS_SUCCESS) {
|
||||
print("ping: resolve failed "); print_u64(st); print(" for "); print(host); print("\n");
|
||||
SysExitProcess(1);
|
||||
}
|
||||
@@ -268,7 +268,7 @@ int main(void) {
|
||||
|
||||
uint32_t sock = 0;
|
||||
st = SysCreateSocket(SYS_AF_INET, SYS_SOCK_RAW, SYS_IPPROTO_ICMP, &sock);
|
||||
if (st != STATUS_SUCCESS) {
|
||||
if (st != NTLSTATUS_SUCCESS) {
|
||||
print("ping: SysCreateSocket(raw icmp) failed "); print_u64(st); print("\n");
|
||||
SysExitProcess(1);
|
||||
}
|
||||
@@ -283,7 +283,7 @@ int main(void) {
|
||||
|
||||
uint64_t tickFrequency = 0;
|
||||
st = SysGetTickFrequency(&tickFrequency);
|
||||
if (st != STATUS_SUCCESS || !tickFrequency) {
|
||||
if (st != NTLSTATUS_SUCCESS || !tickFrequency) {
|
||||
print("ping: SysGetTickFrequency failed "); print_u64(st); print("\n");
|
||||
SysCloseHandle(sock);
|
||||
SysExitProcess(1);
|
||||
@@ -323,7 +323,7 @@ int main(void) {
|
||||
|
||||
uint64_t start = SysGetTick();
|
||||
st = SysSendToSocket(sock, &sendReq);
|
||||
if (st != STATUS_SUCCESS) {
|
||||
if (st != NTLSTATUS_SUCCESS) {
|
||||
print("ping: send failed seq="); print_u64(seq); print(" status="); print_u64(st); print("\n");
|
||||
if (i + 1 < count) SysSleep(1000);
|
||||
continue;
|
||||
@@ -346,9 +346,9 @@ int main(void) {
|
||||
recvReq.ReceivedOut = &got;
|
||||
|
||||
st = SysRecvFromSocket(sock, &recvReq);
|
||||
if (st == STATUS_TIMEOUT)
|
||||
if (st == NTLSTATUS_TIMEOUT)
|
||||
break;
|
||||
if (st != STATUS_SUCCESS) {
|
||||
if (st != NTLSTATUS_SUCCESS) {
|
||||
print("ping: recv failed status="); print_u64(st); print("\n");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -109,12 +109,12 @@ int main(void) {
|
||||
req.AddressSizeInOut = &addrSize;
|
||||
|
||||
uint32_t st = SysResolveHost(&req);
|
||||
if (st != STATUS_SUCCESS && family == 0) {
|
||||
if (st != NTLSTATUS_SUCCESS && family == 0) {
|
||||
req.Family = SYS_AF_INET;
|
||||
addrSize = sizeof(addr);
|
||||
st = SysResolveHost(&req);
|
||||
}
|
||||
if (st != STATUS_SUCCESS) {
|
||||
if (st != NTLSTATUS_SUCCESS) {
|
||||
print("resolve: SysResolveHost failed "); print_u64(st); print("\n");
|
||||
SysExitProcess(1);
|
||||
}
|
||||
|
||||
@@ -138,14 +138,14 @@ static void printUInt64Width(uint64_t n, size_t width) {
|
||||
// Names nt-lite process-abort exit statuses.
|
||||
static const char* processExitStatusName(uint32_t code) {
|
||||
switch (code) {
|
||||
case STATUS_PROCESS_KILLED: return "killed";
|
||||
case STATUS_PROCESS_PAGE_FAULT: return "page-fault";
|
||||
case STATUS_PROCESS_GENERAL_PROTECTION: return "general-protection";
|
||||
case STATUS_PROCESS_ILLEGAL_OPCODE: return "illegal-opcode";
|
||||
case STATUS_PROCESS_DIVIDE_BY_ZERO: return "divide-by-zero";
|
||||
case STATUS_PROCESS_BREAKPOINT: return "breakpoint";
|
||||
case STATUS_PROCESS_ALIGNMENT_FAULT: return "alignment-fault";
|
||||
case STATUS_PROCESS_UNKNOWN_FAULT: return "unknown-fault";
|
||||
case NTLSTATUS_PROCESS_KILLED: return "killed";
|
||||
case NTLSTATUS_PROCESS_PAGE_FAULT: return "page-fault";
|
||||
case NTLSTATUS_PROCESS_GENERAL_PROTECTION: return "general-protection";
|
||||
case NTLSTATUS_PROCESS_ILLEGAL_OPCODE: return "illegal-opcode";
|
||||
case NTLSTATUS_PROCESS_DIVIDE_BY_ZERO: return "divide-by-zero";
|
||||
case NTLSTATUS_PROCESS_BREAKPOINT: return "breakpoint";
|
||||
case NTLSTATUS_PROCESS_ALIGNMENT_FAULT: return "alignment-fault";
|
||||
case NTLSTATUS_PROCESS_UNKNOWN_FAULT: return "unknown-fault";
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
@@ -527,7 +527,7 @@ static bool readLine(char* buf, int len) {
|
||||
inputReq.Flags = SYS_INPUT_EVENT_FLAG_NONE;
|
||||
inputReq.TimeoutMilliseconds = SYS_WAIT_TIMEOUT_INFINITE;
|
||||
inputReq.RecordOut = &input;
|
||||
if (SysReadInputEvent(&inputReq) != STATUS_SUCCESS) { SysYield(); continue; }
|
||||
if (SysReadInputEvent(&inputReq) != NTLSTATUS_SUCCESS) { SysYield(); continue; }
|
||||
|
||||
INPUT_KEY key = input.Key;
|
||||
if (key == INPUT_KEY_NONE) { SysYield(); continue; }
|
||||
@@ -653,6 +653,7 @@ static void cmd_stats(void) {
|
||||
SYS_DISK_STATS disk;
|
||||
SYS_PTE_STATS pte;
|
||||
SYS_SURFACE_STATS surface;
|
||||
SYS_EXCEPTION_STATS exceptionStats;
|
||||
uint32_t status;
|
||||
|
||||
status = SysQueryKernelStats(SYS_KERNEL_STATS_SCHEDULER, &sched, sizeof(sched), NULL);
|
||||
@@ -682,7 +683,14 @@ static void cmd_stats(void) {
|
||||
|
||||
size_t cpuPages = (cpuSize + 4095u) / 4096u;
|
||||
if (cpuPages == 0) cpuPages = 1;
|
||||
status = SysAllocVm(0, cpuPages, SYS_VM_READWRITE, SYS_VM_FLAG_NONE, &cpuBuffer);
|
||||
SYS_ALLOC_VM_REQUEST allocReq;
|
||||
memset(&allocReq, 0, sizeof(allocReq));
|
||||
allocReq.Size = sizeof(allocReq);
|
||||
allocReq.PageCount = cpuPages;
|
||||
allocReq.Protect = SYS_VM_READWRITE;
|
||||
allocReq.Flags = SYS_VM_FLAG_NONE;
|
||||
allocReq.BaseOut = &cpuBuffer;
|
||||
status = SysAllocVm(&allocReq);
|
||||
if (status != 0 || !cpuBuffer) {
|
||||
print("stats: cpu buffer allocation failed: ");
|
||||
printUInt(status);
|
||||
@@ -772,6 +780,15 @@ static void cmd_stats(void) {
|
||||
return;
|
||||
}
|
||||
|
||||
status = SysQueryKernelStats(SYS_KERNEL_STATS_EXCEPTION, &exceptionStats, sizeof(exceptionStats), NULL);
|
||||
if (status != 0) {
|
||||
print("stats: exception query failed: ");
|
||||
printUInt(status);
|
||||
print("\n");
|
||||
SysFreeVm(cpuBuffer);
|
||||
return;
|
||||
}
|
||||
|
||||
print("Scheduler:\n");
|
||||
print(" ticks: "); printUInt64(sched.Ticks); print("\n");
|
||||
print(" context switches: "); printUInt64(sched.ContextSwitches); print("\n");
|
||||
@@ -785,6 +802,15 @@ static void cmd_stats(void) {
|
||||
print(" SMT deferrals: "); printUInt64(sched.SmtSiblingDeferrals); print("\n");
|
||||
print(" SMT primary pokes: "); printUInt64(sched.SmtPrimaryPokes); print("\n");
|
||||
|
||||
print("Exceptions:\n");
|
||||
print(" delivered: "); printUInt64(exceptionStats.Delivered); print("\n");
|
||||
print(" user-raised: "); printUInt64(exceptionStats.UserRaised); print("\n");
|
||||
print(" continued: "); printUInt64(exceptionStats.Continued); print("\n");
|
||||
print(" unhandled: "); printUInt64(exceptionStats.Unhandled); print("\n");
|
||||
print(" invalid continue: "); printUInt64(exceptionStats.InvalidContinue); print("\n");
|
||||
print(" max nesting: "); printUInt(exceptionStats.MaxNestedDispatch); print("\n");
|
||||
print(" last code: "); printUInt(exceptionStats.LastCode); print("\n");
|
||||
|
||||
print("CPUs:\n");
|
||||
const SYS_CPU_STAT* cpuRecords = SYS_CPU_STATS_CONST_RECORDS(cpu);
|
||||
uint32_t n = cpu->RecordCount;
|
||||
@@ -1352,11 +1378,11 @@ static void cmd_kill(const char* args) {
|
||||
uint32_t hProc = 0;
|
||||
uint32_t status = SysOpenProcess(pid, &hProc);
|
||||
if (status == 0) {
|
||||
status = SysKillProcess(hProc, (int32_t)STATUS_PROCESS_KILLED);
|
||||
status = SysKillProcess(hProc, (int32_t)NTLSTATUS_PROCESS_KILLED);
|
||||
SysCloseHandle(hProc);
|
||||
}
|
||||
|
||||
if (status == STATUS_ACCESS_DENIED) {
|
||||
if (status == NTLSTATUS_ACCESS_DENIED) {
|
||||
print("kill: process ");
|
||||
printUInt(pid);
|
||||
print(" is termination-protected.\n");
|
||||
@@ -1466,7 +1492,7 @@ static bool shellConsumeQueuedCtrlC(void) {
|
||||
inputReq.Flags = SYS_INPUT_EVENT_FLAG_NONE;
|
||||
inputReq.TimeoutMilliseconds = 0;
|
||||
inputReq.RecordOut = &input;
|
||||
if (SysPeekInputEvent(&inputReq) != STATUS_SUCCESS) return false;
|
||||
if (SysPeekInputEvent(&inputReq) != NTLSTATUS_SUCCESS) return false;
|
||||
|
||||
if ((input.Modifiers & INPUT_MOD_CTRL) && input.Key == INPUT_KEY_C) {
|
||||
(void)SysReadInputEvent(&inputReq);
|
||||
@@ -1487,7 +1513,7 @@ static bool shellConsumeQueuedCtrlC(void) {
|
||||
// Returns whether one input key is currently held.
|
||||
static bool shellIsKeyDown(INPUT_KEY key) {
|
||||
bool down = false;
|
||||
return SysIsKeyDown(key, &down) == STATUS_SUCCESS && down;
|
||||
return SysIsKeyDown(key, &down) == NTLSTATUS_SUCCESS && down;
|
||||
}
|
||||
|
||||
// Waits for a foreground process while watching Ctrl-C without stealing ordinary stdin.
|
||||
@@ -1511,7 +1537,7 @@ static uint32_t waitForegroundProcess(uint32_t hProc) {
|
||||
for (;;) {
|
||||
index = 0;
|
||||
uint32_t status = SysWaitMany(&waitReq);
|
||||
if (status != STATUS_SUCCESS) {
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
SysCloseHandle(inputQueue);
|
||||
return status;
|
||||
}
|
||||
@@ -1525,7 +1551,7 @@ static uint32_t waitForegroundProcess(uint32_t hProc) {
|
||||
if (((modifiers & INPUT_MOD_CTRL) && shellIsKeyDown(INPUT_KEY_C)) || shellConsumeQueuedCtrlC()) {
|
||||
if (!sentBreak) {
|
||||
print("^C\n");
|
||||
(void)SysKillProcess(hProc, (int32_t)STATUS_PROCESS_KILLED);
|
||||
(void)SysKillProcess(hProc, (int32_t)NTLSTATUS_PROCESS_KILLED);
|
||||
sentBreak = true;
|
||||
}
|
||||
}
|
||||
@@ -1624,7 +1650,7 @@ static int runCommand(const char* cmd) {
|
||||
} else {
|
||||
// Foreground mode: Wait for completion and flush standard keyboard stream.
|
||||
uint32_t waitStatus = waitForegroundProcess(hProc);
|
||||
if (waitStatus != STATUS_SUCCESS) {
|
||||
if (waitStatus != NTLSTATUS_SUCCESS) {
|
||||
print("shell: wait failed: ");
|
||||
printUInt(waitStatus);
|
||||
print("\n");
|
||||
@@ -1644,7 +1670,7 @@ static int runCommand(const char* cmd) {
|
||||
print("\n");
|
||||
SysCloseHandle(hProc);
|
||||
INPUT_KEY drainedKey;
|
||||
while (SysPollKeyboard(&drainedKey) == STATUS_SUCCESS) (void)SysReadKey(&drainedKey);
|
||||
while (SysPollKeyboard(&drainedKey) == NTLSTATUS_SUCCESS) (void)SysReadKey(&drainedKey);
|
||||
}
|
||||
} else {
|
||||
print("shell: launch failed\n");
|
||||
|
||||
@@ -131,7 +131,7 @@ int main(void) {
|
||||
|
||||
uint32_t listener = 0;
|
||||
uint32_t st = SysCreateSocket(family, SYS_SOCK_STREAM, SYS_IPPROTO_TCP, &listener);
|
||||
if (st != STATUS_SUCCESS) {
|
||||
if (st != NTLSTATUS_SUCCESS) {
|
||||
print("tcpserve: SysCreateSocket failed "); print_u64(st); print("\n");
|
||||
SysExitProcess(1);
|
||||
}
|
||||
@@ -143,14 +143,14 @@ int main(void) {
|
||||
bindAddr.Port = port;
|
||||
|
||||
st = SysBindSocket(listener, &bindAddr, sizeof(bindAddr));
|
||||
if (st != STATUS_SUCCESS) {
|
||||
if (st != NTLSTATUS_SUCCESS) {
|
||||
print("tcpserve: SysBindSocket failed "); print_u64(st); print("\n");
|
||||
SysCloseHandle(listener);
|
||||
SysExitProcess(1);
|
||||
}
|
||||
|
||||
st = SysListenSocket(listener, 4);
|
||||
if (st != STATUS_SUCCESS) {
|
||||
if (st != NTLSTATUS_SUCCESS) {
|
||||
print("tcpserve: SysListenSocket failed "); print_u64(st); print("\n");
|
||||
SysCloseHandle(listener);
|
||||
SysExitProcess(1);
|
||||
@@ -165,7 +165,7 @@ int main(void) {
|
||||
size_t remoteSize = sizeof(remote);
|
||||
uint32_t client = 0;
|
||||
st = SysAcceptSocket(listener, &remote, &remoteSize, &client);
|
||||
if (st != STATUS_SUCCESS) {
|
||||
if (st != NTLSTATUS_SUCCESS) {
|
||||
print("tcpserve: SysAcceptSocket failed "); print_u64(st); print("\n");
|
||||
SysCloseHandle(listener);
|
||||
SysExitProcess(1);
|
||||
@@ -178,7 +178,7 @@ int main(void) {
|
||||
char request[1025];
|
||||
size_t got = 0;
|
||||
st = SysRecvSocket(client, request, sizeof(request) - 1, 0, &got);
|
||||
if (st != STATUS_SUCCESS) {
|
||||
if (st != NTLSTATUS_SUCCESS) {
|
||||
print("tcpserve: SysRecvSocket failed "); print_u64(st); print("\n");
|
||||
SysCloseHandle(client);
|
||||
SysCloseHandle(listener);
|
||||
@@ -217,9 +217,9 @@ int main(void) {
|
||||
|
||||
size_t sent = 0;
|
||||
st = SysSendSocket(client, response, off, 0, &sent);
|
||||
if (st == STATUS_SUCCESS)
|
||||
if (st == NTLSTATUS_SUCCESS)
|
||||
st = SysSendSocket(client, body, sizeof(body) - 1, 0, &sent);
|
||||
if (st != STATUS_SUCCESS)
|
||||
if (st != NTLSTATUS_SUCCESS)
|
||||
print("tcpserve: SysSendSocket failed "), print_u64(st), print("\n");
|
||||
|
||||
SysShutdownSocket(client, SYS_SHUTDOWN_BOTH);
|
||||
|
||||
@@ -148,7 +148,7 @@ static uint32_t resolve_address(const char* text, SYS_SOCKET_ADDRESS* out) {
|
||||
out->Size = sizeof(*out);
|
||||
out->Family = SYS_AF_INET;
|
||||
memcpy(out->Address, ip, 4);
|
||||
return STATUS_SUCCESS;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
SYS_RESOLVE_HOST_REQUEST req;
|
||||
@@ -161,8 +161,8 @@ static uint32_t resolve_address(const char* text, SYS_SOCKET_ADDRESS* out) {
|
||||
req.AddressSizeInOut = &addressSize;
|
||||
|
||||
uint32_t status = SysResolveHost(&req);
|
||||
if (status == STATUS_SUCCESS)
|
||||
return STATUS_SUCCESS;
|
||||
if (status == NTLSTATUS_SUCCESS)
|
||||
return NTLSTATUS_SUCCESS;
|
||||
|
||||
addressSize = sizeof(*out);
|
||||
memset(out, 0, sizeof(*out));
|
||||
@@ -179,7 +179,7 @@ static int run_send(const char* cmd) {
|
||||
cmd = next_token(cmd, tok, sizeof(tok));
|
||||
if (!tok[0]) { usage(); return 1; }
|
||||
uint32_t status = resolve_address(tok, &remote);
|
||||
if (status != STATUS_SUCCESS) { print("udp: resolve failed "); print_u64(status); print("\n"); return 1; }
|
||||
if (status != NTLSTATUS_SUCCESS) { print("udp: resolve failed "); print_u64(status); print("\n"); return 1; }
|
||||
cmd = next_token(cmd, tok, sizeof(tok));
|
||||
if (!tok[0] || !parse_port(tok, &port)) { usage(); return 1; }
|
||||
|
||||
@@ -197,7 +197,7 @@ static int run_send(const char* cmd) {
|
||||
|
||||
uint32_t sock = 0;
|
||||
uint32_t st = SysCreateSocket(remote.Family, SYS_SOCK_DGRAM, SYS_IPPROTO_UDP, &sock);
|
||||
if (st != STATUS_SUCCESS) {
|
||||
if (st != NTLSTATUS_SUCCESS) {
|
||||
print("udp: SysCreateSocket failed "); print_u64(st); print("\n");
|
||||
return 1;
|
||||
}
|
||||
@@ -215,7 +215,7 @@ static int run_send(const char* cmd) {
|
||||
|
||||
st = SysSendToSocket(sock, &req);
|
||||
SysCloseHandle(sock);
|
||||
if (st != STATUS_SUCCESS) {
|
||||
if (st != NTLSTATUS_SUCCESS) {
|
||||
print("udp: SysSendToSocket failed "); print_u64(st); print("\n");
|
||||
return 1;
|
||||
}
|
||||
@@ -242,7 +242,7 @@ static int run_listen(const char* cmd) {
|
||||
|
||||
uint32_t sock = 0;
|
||||
uint32_t st = SysCreateSocket(family, SYS_SOCK_DGRAM, SYS_IPPROTO_UDP, &sock);
|
||||
if (st != STATUS_SUCCESS) {
|
||||
if (st != NTLSTATUS_SUCCESS) {
|
||||
print("udp: SysCreateSocket failed "); print_u64(st); print("\n");
|
||||
return 1;
|
||||
}
|
||||
@@ -254,7 +254,7 @@ static int run_listen(const char* cmd) {
|
||||
bindAddr.Port = port;
|
||||
|
||||
st = SysBindSocket(sock, &bindAddr, sizeof(bindAddr));
|
||||
if (st != STATUS_SUCCESS) {
|
||||
if (st != NTLSTATUS_SUCCESS) {
|
||||
print("udp: SysBindSocket failed "); print_u64(st); print("\n");
|
||||
SysCloseHandle(sock);
|
||||
return 1;
|
||||
@@ -278,7 +278,7 @@ static int run_listen(const char* cmd) {
|
||||
|
||||
st = SysRecvFromSocket(sock, &req);
|
||||
SysCloseHandle(sock);
|
||||
if (st != STATUS_SUCCESS) {
|
||||
if (st != NTLSTATUS_SUCCESS) {
|
||||
print("udp: SysRecvFromSocket failed "); print_u64(st); print("\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ int main(void) {
|
||||
|
||||
uint32_t file = 0;
|
||||
uint32_t status = open_file_view(pathView, &file);
|
||||
if (status != STATUS_SUCCESS) {
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
char pathBuf[260];
|
||||
print("video: failed to open input file: ");
|
||||
print(path_to_cstr(pathView, pathBuf, sizeof(pathBuf)));
|
||||
@@ -160,7 +160,7 @@ int main(void) {
|
||||
|
||||
uint64_t fileSize = 0;
|
||||
status = SysGetFileSize(file, &fileSize);
|
||||
if (status != STATUS_SUCCESS) {
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
SysCloseHandle(file);
|
||||
fail_status("SysGetFileSize", status);
|
||||
}
|
||||
@@ -172,7 +172,7 @@ int main(void) {
|
||||
|
||||
uint32_t mapping = 0;
|
||||
status = SysCreateFileMapping(file, SYS_VM_READ, SYS_MAP_FLAG_NONE, fileSize, &mapping);
|
||||
if (status != STATUS_SUCCESS || !mapping) {
|
||||
if (status != NTLSTATUS_SUCCESS || !mapping) {
|
||||
SysCloseHandle(file);
|
||||
fail_status("SysCreateFileMapping", status);
|
||||
}
|
||||
@@ -180,7 +180,7 @@ int main(void) {
|
||||
void* buf = 0;
|
||||
status = SysMapFile(mapping, 0, (size_t)fileSize,
|
||||
SYS_MAP_ACCESS_READ, SYS_MAP_FLAG_NONE, &buf);
|
||||
if (status != STATUS_SUCCESS || !buf) {
|
||||
if (status != NTLSTATUS_SUCCESS || !buf) {
|
||||
SysCloseHandle(mapping);
|
||||
SysCloseHandle(file);
|
||||
fail_status("SysMapFile", status);
|
||||
@@ -214,9 +214,16 @@ int main(void) {
|
||||
}
|
||||
|
||||
uint32_t surface = 0;
|
||||
status = SysCreateSurface(width, height, SYS_SURFACE_FORMAT_XRGB8888,
|
||||
SYS_SURFACE_FLAG_NONE, &surface);
|
||||
if (status != STATUS_SUCCESS || !surface) {
|
||||
SYS_CREATE_SURFACE_REQUEST surfaceReq;
|
||||
memset(&surfaceReq, 0, sizeof(surfaceReq));
|
||||
surfaceReq.Size = sizeof(surfaceReq);
|
||||
surfaceReq.Width = width;
|
||||
surfaceReq.Height = height;
|
||||
surfaceReq.Format = SYS_SURFACE_FORMAT_XRGB8888;
|
||||
surfaceReq.Flags = SYS_SURFACE_FLAG_NONE;
|
||||
surfaceReq.HandleOut = &surface;
|
||||
status = SysCreateSurface(&surfaceReq);
|
||||
if (status != NTLSTATUS_SUCCESS || !surface) {
|
||||
BinkClose(b);
|
||||
SysFreeVm(buf);
|
||||
fail_status("SysCreateSurface", status);
|
||||
@@ -225,7 +232,7 @@ int main(void) {
|
||||
void* surfaceBase = 0;
|
||||
uint32_t pitchBytes = 0;
|
||||
status = SysMapSurface(surface, &surfaceBase, &pitchBytes);
|
||||
if (status != STATUS_SUCCESS || !surfaceBase || pitchBytes < width * sizeof(uint32_t)) {
|
||||
if (status != NTLSTATUS_SUCCESS || !surfaceBase || pitchBytes < width * sizeof(uint32_t)) {
|
||||
SysCloseHandle(surface);
|
||||
BinkClose(b);
|
||||
SysFreeVm(buf);
|
||||
@@ -253,7 +260,7 @@ int main(void) {
|
||||
BinkCopyToBuffer(b, surfaceBase, pitchBytes, height, 0, 0, BINKSURFACE32);
|
||||
|
||||
status = SysPresentSurface(surface, &fullFrame, 1);
|
||||
if (status != STATUS_SUCCESS) {
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
SysCloseHandle(surface);
|
||||
BinkClose(b);
|
||||
SysFreeVm(buf);
|
||||
|
||||
@@ -82,7 +82,7 @@ __declspec(dllexport) char* realpath(const char* path, char* resolved_path) {
|
||||
&required,
|
||||
};
|
||||
uint32_t status = SysRealPath(&query);
|
||||
if (status != STATUS_SUCCESS) { errno = PosixStatusToErrno(status); return (char*)0; }
|
||||
if (status != NTLSTATUS_SUCCESS) { errno = PosixStatusToErrno(status); return (char*)0; }
|
||||
if (required == 0 || required > SYS_CWD_MAX) { errno = ERANGE; return (char*)0; }
|
||||
|
||||
char nativeResolved[SYS_CWD_MAX];
|
||||
@@ -95,7 +95,7 @@ __declspec(dllexport) char* realpath(const char* path, char* resolved_path) {
|
||||
&required,
|
||||
};
|
||||
status = SysRealPath(&request);
|
||||
if (status != STATUS_SUCCESS) { errno = PosixStatusToErrno(status); return (char*)0; }
|
||||
if (status != NTLSTATUS_SUCCESS) { errno = PosixStatusToErrno(status); return (char*)0; }
|
||||
|
||||
char posix[SYS_CWD_MAX];
|
||||
NativeToPosix(nativeResolved, posix, sizeof(posix));
|
||||
|
||||
@@ -58,7 +58,7 @@ __declspec(dllexport) void* dlopen(const char* filename, int flags) {
|
||||
req.ModuleHandleOut = &handle;
|
||||
|
||||
uint32_t status = SysLoadModule(&req);
|
||||
if (status != STATUS_SUCCESS || handle == 0) {
|
||||
if (status != NTLSTATUS_SUCCESS || handle == 0) {
|
||||
DlSetStatusError("dlopen failed", status);
|
||||
return 0;
|
||||
}
|
||||
@@ -84,7 +84,7 @@ __declspec(dllexport) void* dlsym(void* handle, const char* symbol) {
|
||||
req.AddressOut = &address;
|
||||
|
||||
uint32_t status = SysGetModuleExport(&req);
|
||||
if (status != STATUS_SUCCESS || address == 0) {
|
||||
if (status != NTLSTATUS_SUCCESS || address == 0) {
|
||||
DlSetStatusError("dlsym failed", status);
|
||||
return 0;
|
||||
}
|
||||
@@ -102,7 +102,7 @@ __declspec(dllexport) int dlclose(void* handle) {
|
||||
}
|
||||
|
||||
uint32_t status = SysUnloadModule((uint32_t)(uintptr_t)handle);
|
||||
if (status != STATUS_SUCCESS) {
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
DlSetStatusError("dlclose failed", status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -9,23 +9,23 @@ int errno = 0;
|
||||
// Implements the status To Errno operation.
|
||||
int PosixStatusToErrno(uint32_t s) {
|
||||
switch (s) {
|
||||
case STATUS_SUCCESS: return 0;
|
||||
case STATUS_NOT_SUPPORTED: return ENOSYS;
|
||||
case STATUS_TIMEOUT: return EAGAIN;
|
||||
case STATUS_WOULD_BLOCK: return EAGAIN;
|
||||
case STATUS_INVALID_PARAMETER: return EINVAL;
|
||||
case STATUS_INVALID_HANDLE: return EBADF;
|
||||
case STATUS_BUFFER_TOO_SMALL: return ERANGE;
|
||||
case STATUS_NO_MEMORY: return ENOMEM;
|
||||
case STATUS_ACCESS_DENIED: return EACCES;
|
||||
case STATUS_NOT_FOUND: return ENOENT;
|
||||
case STATUS_ALREADY_EXISTS: return EEXIST;
|
||||
case STATUS_OBJECT_NAME_COLLISION: return EEXIST;
|
||||
case STATUS_OBJECT_DEAD: return ECONNRESET;
|
||||
case STATUS_QUEUE_FULL: return EAGAIN;
|
||||
case STATUS_QUEUE_EMPTY: return EAGAIN;
|
||||
case STATUS_CANCELLED: return ECANCELED;
|
||||
case STATUS_NO_MORE_FILES: return ENOENT;
|
||||
case NTLSTATUS_SUCCESS: return 0;
|
||||
case NTLSTATUS_NOT_SUPPORTED: return ENOSYS;
|
||||
case NTLSTATUS_TIMEOUT: return EAGAIN;
|
||||
case NTLSTATUS_WOULD_BLOCK: return EAGAIN;
|
||||
case NTLSTATUS_INVALID_PARAMETER: return EINVAL;
|
||||
case NTLSTATUS_INVALID_HANDLE: return EBADF;
|
||||
case NTLSTATUS_BUFFER_TOO_SMALL: return ERANGE;
|
||||
case NTLSTATUS_NO_MEMORY: return ENOMEM;
|
||||
case NTLSTATUS_ACCESS_DENIED: return EACCES;
|
||||
case NTLSTATUS_NOT_FOUND: return ENOENT;
|
||||
case NTLSTATUS_ALREADY_EXISTS: return EEXIST;
|
||||
case NTLSTATUS_OBJECT_NAME_COLLISION: return EEXIST;
|
||||
case NTLSTATUS_OBJECT_DEAD: return ECONNRESET;
|
||||
case NTLSTATUS_QUEUE_FULL: return EAGAIN;
|
||||
case NTLSTATUS_QUEUE_EMPTY: return EAGAIN;
|
||||
case NTLSTATUS_CANCELLED: return ECANCELED;
|
||||
case NTLSTATUS_NO_MORE_FILES: return ENOENT;
|
||||
default: return EIO;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ __declspec(dllexport) void clearscreen(void) {
|
||||
// Implements the clearkeyboard operation.
|
||||
__declspec(dllexport) void clearkeyboard(void) {
|
||||
INPUT_KEY key;
|
||||
while (SysPollKeyboard(&key) == STATUS_SUCCESS) {
|
||||
while (SysPollKeyboard(&key) == NTLSTATUS_SUCCESS) {
|
||||
char ignored;
|
||||
(void)SysReadKeyboardChar(&ignored);
|
||||
}
|
||||
@@ -90,7 +90,7 @@ __declspec(dllexport) ssize_t read(int fd, void* buf, size_t count) {
|
||||
char* dst = (char*)buf;
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
uint32_t s = SysReadKeyboardChar(&dst[i]);
|
||||
if (s != STATUS_SUCCESS) { errno = PosixStatusToErrno(s); return -1; }
|
||||
if (s != NTLSTATUS_SUCCESS) { errno = PosixStatusToErrno(s); return -1; }
|
||||
if (dst[i] == '\n' || dst[i] == '\r') return (ssize_t)(i + 1);
|
||||
}
|
||||
return (ssize_t)count;
|
||||
|
||||
@@ -52,7 +52,7 @@ __declspec(dllexport) void* mmap(void* addr, size_t length, int prot,
|
||||
uint32_t mapping = 0;
|
||||
uint32_t s = SysCreateFileMapping(e->KHandle, protect, SYS_MAP_FLAG_NONE,
|
||||
maxSize, &mapping);
|
||||
if (s != STATUS_SUCCESS) {
|
||||
if (s != NTLSTATUS_SUCCESS) {
|
||||
errno = PosixStatusToErrno(s);
|
||||
return MAP_FAILED;
|
||||
}
|
||||
@@ -62,7 +62,7 @@ __declspec(dllexport) void* mmap(void* addr, size_t length, int prot,
|
||||
PosixProtToSysMapAccess(prot, flags),
|
||||
SYS_MAP_FLAG_NONE, &base);
|
||||
SysCloseHandle(mapping);
|
||||
if (s != STATUS_SUCCESS) {
|
||||
if (s != NTLSTATUS_SUCCESS) {
|
||||
errno = PosixStatusToErrno(s);
|
||||
return MAP_FAILED;
|
||||
}
|
||||
@@ -73,7 +73,7 @@ __declspec(dllexport) int munmap(void* addr, size_t length) {
|
||||
(void)length;
|
||||
if (!addr) { errno = EINVAL; return -1; }
|
||||
uint32_t s = SysFreeVm(addr);
|
||||
if (s != STATUS_SUCCESS) { errno = PosixStatusToErrno(s); return -1; }
|
||||
if (s != NTLSTATUS_SUCCESS) { errno = PosixStatusToErrno(s); return -1; }
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -535,7 +535,14 @@ __declspec(dllexport) int poll(struct pollfd* fds, nfds_t nfds, int timeout) {
|
||||
|
||||
size_t ready = 0;
|
||||
uint32_t timeoutMs = timeout < 0 ? SYS_POLL_TIMEOUT_INFINITE : (uint32_t)timeout;
|
||||
uint32_t s = SysPoll(kfds, nfds, timeoutMs, &ready);
|
||||
SYS_POLL_REQUEST req;
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.Size = sizeof(req);
|
||||
req.TimeoutMs = timeoutMs;
|
||||
req.Fds = kfds;
|
||||
req.Count = nfds;
|
||||
req.ReadyOut = &ready;
|
||||
KSTATUS s = SysPoll(&req);
|
||||
if (s != 0) {
|
||||
free(kfds);
|
||||
errno = PosixStatusToErrno(s);
|
||||
|
||||
@@ -23,12 +23,14 @@
|
||||
#include <string.h>
|
||||
#include <intrin.h>
|
||||
#include <ntlite/syscall.h>
|
||||
#include <ntlite/exception.h>
|
||||
|
||||
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;
|
||||
@@ -252,13 +254,13 @@ static uint32_t K32SetCwdNative(const char* path) {
|
||||
// Implements the k32 Get Cwd Native operation.
|
||||
static uint32_t K32GetCwdNative(char* buffer, size_t capacity, size_t* lengthOut) {
|
||||
SYS_STRING_VIEW cwd = SysGetCurrentDirectoryView();
|
||||
if ((cwd.Length && !cwd.Data) || cwd.Length > SYS_CWD_MAX) return STATUS_INVALID_PARAMETER;
|
||||
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 STATUS_BUFFER_TOO_SMALL;
|
||||
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 STATUS_SUCCESS;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Implements the k32 Create Process Native operation.
|
||||
@@ -289,6 +291,7 @@ typedef struct WIN32_THREAD_ENV {
|
||||
DWORD Reserved0;
|
||||
void* TlsSlots[WIN32_TLS_SLOTS];
|
||||
void* FlsSlots[FLS_MAX_SLOTS];
|
||||
void* ExceptionFrameHead;
|
||||
} WIN32_THREAD_ENV;
|
||||
|
||||
static WIN32_THREAD_ENV gFallbackThreadEnv;
|
||||
@@ -429,7 +432,7 @@ __declspec(dllexport) void OutputDebugStringA(const char* str) {
|
||||
// Queries the native monotonic tick frequency.
|
||||
static uint64_t K32TickFrequency(void) {
|
||||
uint64_t frequency = 0;
|
||||
if (SysGetTickFrequency(&frequency) != STATUS_SUCCESS) return 0;
|
||||
if (SysGetTickFrequency(&frequency) != NTLSTATUS_SUCCESS) return 0;
|
||||
return frequency;
|
||||
}
|
||||
|
||||
@@ -525,9 +528,17 @@ __declspec(dllexport) void* VirtualAlloc(void* lpAddress, size_t dwSize,
|
||||
size_t pages = (dwSize + 4095u) / 4096u;
|
||||
void* base = NULL;
|
||||
uint32_t flags = lpAddress ? SYS_VM_FLAG_FIXED : SYS_VM_FLAG_NONE;
|
||||
uint32_t s = SysAllocVm(lpAddress, pages, WinProtectToSysVm(flProtect), flags, &base);
|
||||
if (s != STATUS_SUCCESS) {
|
||||
gLastError = (s == STATUS_NOT_FOUND || s == STATUS_INVALID_PARAMETER) ? 87 : 8;
|
||||
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;
|
||||
@@ -538,7 +549,7 @@ __declspec(dllexport) BOOL VirtualFree(void* lpAddress, size_t dwSize, DWORD dwF
|
||||
(void)dwSize; (void)dwFreeType;
|
||||
if (!lpAddress) return TRUE;
|
||||
uint32_t s = SysFreeVm(lpAddress);
|
||||
if (s != STATUS_SUCCESS) { gLastError = 87; return FALSE; }
|
||||
if (s != NTLSTATUS_SUCCESS) { gLastError = 87; return FALSE; }
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -549,7 +560,7 @@ __declspec(dllexport) BOOL VirtualProtect(void* lpAddress, size_t dwSize,
|
||||
uint32_t oldSysProtect = 0;
|
||||
uint32_t s = SysProtectVm(lpAddress, pages, WinProtectToSysVm(flNewProtect),
|
||||
lpflOldProtect ? &oldSysProtect : NULL);
|
||||
if (s != STATUS_SUCCESS) { gLastError = 87; return FALSE; }
|
||||
if (s != NTLSTATUS_SUCCESS) { gLastError = 87; return FALSE; }
|
||||
if (lpflOldProtect) *lpflOldProtect = SysProtectVmToWin(oldSysProtect);
|
||||
return TRUE;
|
||||
}
|
||||
@@ -564,7 +575,7 @@ __declspec(dllexport) size_t VirtualQuery(const void* lpAddress,
|
||||
|
||||
SYS_VM_REGION_INFO info;
|
||||
uint32_t s = SysQueryVm((void*)lpAddress, &info);
|
||||
if (s != STATUS_SUCCESS) {
|
||||
if (s != NTLSTATUS_SUCCESS) {
|
||||
gLastError = 87;
|
||||
return 0;
|
||||
}
|
||||
@@ -600,8 +611,8 @@ __declspec(dllexport) HANDLE CreateFileMappingA(HANDLE hFile,
|
||||
SYS_MAP_FLAG_NONE,
|
||||
maximumSize,
|
||||
&kh);
|
||||
if (s != STATUS_SUCCESS) {
|
||||
gLastError = (s == STATUS_NOT_SUPPORTED) ? 120 : ((s == STATUS_NO_MEMORY) ? 8 : 87);
|
||||
if (s != NTLSTATUS_SUCCESS) {
|
||||
gLastError = (s == NTLSTATUS_NOT_SUPPORTED) ? 120 : ((s == NTLSTATUS_NO_MEMORY) ? 8 : 87);
|
||||
return NULL;
|
||||
}
|
||||
return KH_TO_HANDLE(kh);
|
||||
@@ -636,8 +647,8 @@ __declspec(dllexport) void* MapViewOfFile(HANDLE hFileMappingObject,
|
||||
WinFileMapAccessToSys(dwDesiredAccess),
|
||||
SYS_MAP_FLAG_NONE,
|
||||
&base);
|
||||
if (s != STATUS_SUCCESS) {
|
||||
gLastError = (s == STATUS_NOT_SUPPORTED) ? 120 : ((s == STATUS_NO_MEMORY) ? 8 : 87);
|
||||
if (s != NTLSTATUS_SUCCESS) {
|
||||
gLastError = (s == NTLSTATUS_NOT_SUPPORTED) ? 120 : ((s == NTLSTATUS_NO_MEMORY) ? 8 : 87);
|
||||
return NULL;
|
||||
}
|
||||
return base;
|
||||
@@ -646,7 +657,7 @@ __declspec(dllexport) void* MapViewOfFile(HANDLE hFileMappingObject,
|
||||
__declspec(dllexport) BOOL UnmapViewOfFile(const void* lpBaseAddress) {
|
||||
if (!lpBaseAddress) { gLastError = 87; return FALSE; }
|
||||
uint32_t s = SysFreeVm((void*)lpBaseAddress);
|
||||
if (s != STATUS_SUCCESS) { gLastError = 87; return FALSE; }
|
||||
if (s != NTLSTATUS_SUCCESS) { gLastError = 87; return FALSE; }
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -663,7 +674,7 @@ __declspec(dllexport) BOOL FlushViewOfFile(const void* lpBaseAddress, size_t dwN
|
||||
// Returns whether one input key is currently held for Win32 adapters.
|
||||
static bool Win32IsInputKeyDown(INPUT_KEY key) {
|
||||
bool down = false;
|
||||
return SysIsKeyDown(key, &down) == STATUS_SUCCESS && down;
|
||||
return SysIsKeyDown(key, &down) == NTLSTATUS_SUCCESS && down;
|
||||
}
|
||||
|
||||
// GetAsyncKeyState implementation over the canonical input key namespace.
|
||||
@@ -731,7 +742,7 @@ __declspec(dllexport) BOOL FlushConsoleInputBuffer(HANDLE hConsoleInput) {
|
||||
(void)hConsoleInput;
|
||||
// Drain the keyboard buffer by reading until empty.
|
||||
INPUT_KEY key;
|
||||
while (SysPollKeyboard(&key) == STATUS_SUCCESS) {
|
||||
while (SysPollKeyboard(&key) == NTLSTATUS_SUCCESS) {
|
||||
char ignored;
|
||||
(void)SysReadKeyboardChar(&ignored);
|
||||
}
|
||||
@@ -832,8 +843,8 @@ __declspec(dllexport) HANDLE CreateFileA(const char* name,
|
||||
uint32_t kh = 0;
|
||||
uint32_t s = K32OpenFileNative(translatedName, sysAccess, sysDisposition, &kh);
|
||||
if (s != 0) {
|
||||
gLastError = (s == STATUS_OBJECT_NAME_COLLISION) ? 80 :
|
||||
(s == STATUS_NOT_FOUND) ? 2 : 5;
|
||||
gLastError = (s == NTLSTATUS_OBJECT_NAME_COLLISION) ? 80 :
|
||||
(s == NTLSTATUS_NOT_FOUND) ? 2 : 5;
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
@@ -1115,7 +1126,7 @@ __declspec(dllexport) HANDLE LoadLibraryA(const char* lpLibFileName) {
|
||||
req.ModuleHandleOut = &handle;
|
||||
|
||||
uint32_t status = SysLoadModule(&req);
|
||||
if (status != STATUS_SUCCESS) {
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
gLastError = 126;
|
||||
return NULL;
|
||||
}
|
||||
@@ -1160,7 +1171,7 @@ __declspec(dllexport) void* GetProcAddress(HANDLE hModule, const char* lpProcNam
|
||||
req.Name = SysSvFromCstr(lpProcName);
|
||||
req.AddressOut = &address;
|
||||
uint32_t status = SysGetModuleExport(&req);
|
||||
if (status != STATUS_SUCCESS || !address) { gLastError = 127; return NULL; }
|
||||
if (status != NTLSTATUS_SUCCESS || !address) { gLastError = 127; return NULL; }
|
||||
return (void*)address;
|
||||
}
|
||||
|
||||
@@ -1184,7 +1195,7 @@ __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 != STATUS_SUCCESS) {
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
gLastError = 126;
|
||||
return FALSE;
|
||||
}
|
||||
@@ -1223,7 +1234,7 @@ __declspec(dllexport) BOOL TerminateProcess(HANDLE hProcess, unsigned int uExitC
|
||||
|
||||
uint32_t s = SysKillProcess(HANDLE_TO_KH(hProcess), (int32_t)uExitCode);
|
||||
if (s != 0) {
|
||||
gLastError = (s == STATUS_INVALID_HANDLE) ? 6 : 5;
|
||||
gLastError = (s == NTLSTATUS_INVALID_HANDLE) ? 6 : 5;
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
@@ -1491,13 +1502,13 @@ static BOOL K32IsConsoleOutputHandle(HANDLE h) {
|
||||
// Implements the k32 Set Console Last Error operation.
|
||||
static void K32SetConsoleLastError(uint32_t status) {
|
||||
switch (status) {
|
||||
case STATUS_SUCCESS:
|
||||
case NTLSTATUS_SUCCESS:
|
||||
gLastError = 0;
|
||||
break;
|
||||
case STATUS_INVALID_PARAMETER:
|
||||
case NTLSTATUS_INVALID_PARAMETER:
|
||||
gLastError = 87;
|
||||
break;
|
||||
case STATUS_NO_MEMORY:
|
||||
case NTLSTATUS_NO_MEMORY:
|
||||
gLastError = 8;
|
||||
break;
|
||||
default:
|
||||
@@ -1527,7 +1538,7 @@ __declspec(dllexport) BOOL ReadConsoleA(HANDLE hConsoleInput,
|
||||
|
||||
while (i < nNumberOfCharsToRead) {
|
||||
char c = 0;
|
||||
if (SysReadKeyboardChar(&c) != STATUS_SUCCESS) continue;
|
||||
if (SysReadKeyboardChar(&c) != NTLSTATUS_SUCCESS) continue;
|
||||
|
||||
// Ignore unmapped keys (Shift, Ctrl, etc.).
|
||||
if (c == 0) continue;
|
||||
@@ -1579,7 +1590,7 @@ __declspec(dllexport) BOOL GetConsoleScreenBufferInfo(HANDLE hConsoleOutput,
|
||||
|
||||
SYS_CONSOLE_INFO info;
|
||||
uint32_t s = SysGetConsoleInfo(&info);
|
||||
if (s != STATUS_SUCCESS) {
|
||||
if (s != NTLSTATUS_SUCCESS) {
|
||||
K32SetConsoleLastError(s);
|
||||
return FALSE;
|
||||
}
|
||||
@@ -1610,7 +1621,7 @@ __declspec(dllexport) BOOL SetConsoleCursorPosition(HANDLE hConsoleOutput,
|
||||
}
|
||||
|
||||
uint32_t s = SysSetConsoleCursor((int)dwCursorPosition.X, (int)dwCursorPosition.Y);
|
||||
if (s != STATUS_SUCCESS) {
|
||||
if (s != NTLSTATUS_SUCCESS) {
|
||||
K32SetConsoleLastError(s);
|
||||
return FALSE;
|
||||
}
|
||||
@@ -1639,7 +1650,7 @@ __declspec(dllexport) BOOL FillConsoleOutputCharacterA(HANDLE hConsoleOutput,
|
||||
(int)dwWriteCoord.Y, (size_t)nLength,
|
||||
&written);
|
||||
if (lpNumberOfCharsWritten) *lpNumberOfCharsWritten = (DWORD)written;
|
||||
if (s != STATUS_SUCCESS) {
|
||||
if (s != NTLSTATUS_SUCCESS) {
|
||||
K32SetConsoleLastError(s);
|
||||
return FALSE;
|
||||
}
|
||||
@@ -1668,7 +1679,7 @@ __declspec(dllexport) BOOL FillConsoleOutputAttribute(HANDLE hConsoleOutput,
|
||||
(int)dwWriteCoord.Y, (size_t)nLength,
|
||||
&written);
|
||||
if (lpNumberOfAttrsWritten) *lpNumberOfAttrsWritten = (DWORD)written;
|
||||
if (s != STATUS_SUCCESS) {
|
||||
if (s != NTLSTATUS_SUCCESS) {
|
||||
K32SetConsoleLastError(s);
|
||||
return FALSE;
|
||||
}
|
||||
@@ -2220,7 +2231,7 @@ __declspec(dllexport) void GetSystemTime(SYSTEMTIME* lpSystemTime) {
|
||||
if (!lpSystemTime) return;
|
||||
|
||||
SYS_SYSTEM_TIME st;
|
||||
if (SysGetSystemTime(&st) != STATUS_SUCCESS) {
|
||||
if (SysGetSystemTime(&st) != NTLSTATUS_SUCCESS) {
|
||||
memset(lpSystemTime, 0, sizeof(*lpSystemTime));
|
||||
return;
|
||||
}
|
||||
@@ -2258,7 +2269,7 @@ __declspec(dllexport) void GetSystemTimeAsFileTime(void* lpSystemTimeAsFileTime)
|
||||
|
||||
SYS_SYSTEM_TIME st;
|
||||
uint64_t ft;
|
||||
if (SysGetSystemTime(&st) == STATUS_SUCCESS) {
|
||||
if (SysGetSystemTime(&st) == NTLSTATUS_SUCCESS) {
|
||||
ft = K32EpochToFileTime(st.EpochSeconds, st.Nanosecond);
|
||||
} else {
|
||||
uint64_t frequency = K32TickFrequency();
|
||||
@@ -2436,32 +2447,504 @@ __declspec(dllexport) DWORD GetFileType(HANDLE hFile) {
|
||||
|
||||
// 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
|
||||
|
||||
// Implements the add Vectored Exception Handler operation.
|
||||
__declspec(dllexport) void* AddVectoredExceptionHandler(unsigned long First, void* Handler) {
|
||||
(void)First; (void)Handler;
|
||||
// Return a non-NULL sentinel so callers can pass it to RemoveVectoredExceptionHandler.
|
||||
return (void*)(uintptr_t)0x56455843UL; // 'VEXC'
|
||||
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 vectored Exception Handler.
|
||||
// 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) {
|
||||
(void)Handle;
|
||||
return 1; // success
|
||||
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) {
|
||||
(void)dwExceptionCode; (void)dwExceptionFlags;
|
||||
(void)nNumberOfArguments; (void)lpArguments;
|
||||
// Best-effort: nothing to unwind; just halt.
|
||||
while (true) ;
|
||||
}
|
||||
uint64_t arguments[EXCEPTION_MAXIMUM_PARAMETERS];
|
||||
DWORD count = nNumberOfArguments;
|
||||
if (count > EXCEPTION_MAXIMUM_PARAMETERS)
|
||||
count = EXCEPTION_MAXIMUM_PARAMETERS;
|
||||
|
||||
typedef struct _EXCEPTION_POINTERS { void* ExceptionRecord; void* ContextRecord; } EXCEPTION_POINTERS;
|
||||
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) {
|
||||
@@ -2483,7 +2966,7 @@ __declspec(dllexport) BOOL IsDebuggerPresent(void) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// RTL Exception / Unwind (SEH infrastructure - all stubs).
|
||||
// RTL Exception / Unwind metadata helpers.
|
||||
|
||||
typedef struct _RUNTIME_FUNCTION {
|
||||
unsigned int BeginAddress;
|
||||
|
||||
@@ -50,7 +50,7 @@ typedef struct {
|
||||
|
||||
__declspec(dllexport) unsigned long timeGetTime(void) {
|
||||
uint64_t frequency = 0;
|
||||
if (SysGetTickFrequency(&frequency) != STATUS_SUCCESS || !frequency) return 0;
|
||||
if (SysGetTickFrequency(&frequency) != NTLSTATUS_SUCCESS || !frequency) return 0;
|
||||
return (unsigned long)SysTicksToMilliseconds(SysGetTick(), frequency);
|
||||
}
|
||||
|
||||
|
||||
@@ -116,8 +116,15 @@ static HEAP_SEGMENT* AddSegment(size_t payloadSize) {
|
||||
if (pages < USER_HEAP_MIN_PAGES) pages = USER_HEAP_MIN_PAGES;
|
||||
|
||||
void* base = 0;
|
||||
uint32_t s = SysAllocVm(0, pages, SYS_VM_READWRITE, SYS_VM_FLAG_NONE, &base);
|
||||
if (s != STATUS_SUCCESS || !base)
|
||||
SYS_ALLOC_VM_REQUEST req;
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.Size = sizeof(req);
|
||||
req.PageCount = pages;
|
||||
req.Protect = SYS_VM_READWRITE;
|
||||
req.Flags = SYS_VM_FLAG_NONE;
|
||||
req.BaseOut = &base;
|
||||
KSTATUS s = SysAllocVm(&req);
|
||||
if (s != NTLSTATUS_SUCCESS || !base)
|
||||
return (HEAP_SEGMENT*)0;
|
||||
|
||||
HEAP_SEGMENT* seg = (HEAP_SEGMENT*)base;
|
||||
|
||||
@@ -0,0 +1,256 @@
|
||||
// Native user-mode exception runtime. This file owns process-local native handler dispatch.
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <intrin.h>
|
||||
#include <ntlite/exception.h>
|
||||
#include <ntlite/syscall.h>
|
||||
|
||||
#define NTL_EXCEPTION_MAX_HANDLERS 16u
|
||||
|
||||
typedef struct NTL_EXCEPTION_HANDLER_ENTRY {
|
||||
uint32_t Active;
|
||||
uint32_t Previous;
|
||||
uint32_t Next;
|
||||
NTL_EXCEPTION_HANDLER Handler;
|
||||
void* Context;
|
||||
} NTL_EXCEPTION_HANDLER_ENTRY;
|
||||
|
||||
typedef struct NTL_EXCEPTION_HANDLER_SNAPSHOT {
|
||||
NTL_EXCEPTION_HANDLER Handler;
|
||||
void* Context;
|
||||
} NTL_EXCEPTION_HANDLER_SNAPSHOT;
|
||||
|
||||
static volatile long gNtlExceptionLock;
|
||||
static uint32_t gNtlExceptionListHead = UINT32_MAX;
|
||||
static uint32_t gNtlExceptionListTail = UINT32_MAX;
|
||||
static NTL_EXCEPTION_HANDLER_ENTRY gNtlExceptionHandlers[NTL_EXCEPTION_MAX_HANDLERS];
|
||||
|
||||
// Acquires the process-local exception handler lock.
|
||||
static void NtlpExceptionLock(void) {
|
||||
while (_InterlockedCompareExchange(&gNtlExceptionLock, 1, 0) != 0)
|
||||
_mm_pause();
|
||||
_ReadWriteBarrier();
|
||||
}
|
||||
|
||||
// Releases the process-local exception handler lock.
|
||||
static void NtlpExceptionUnlock(void) {
|
||||
_ReadWriteBarrier();
|
||||
_InterlockedExchange(&gNtlExceptionLock, 0);
|
||||
}
|
||||
|
||||
// Returns a generic status after a failed exception-continue syscall.
|
||||
static uint32_t NtlpStatusOrFailure(uint32_t status) {
|
||||
return status == NTLSTATUS_SUCCESS ? NTLSTATUS_FAILURE : status;
|
||||
}
|
||||
|
||||
// Asks the kernel to terminate the active exception dispatch.
|
||||
static void NtlpTerminateExceptionDispatch(void) {
|
||||
SYS_CONTINUE_EXCEPTION_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.Disposition = SYS_EXCEPTION_DISPOSITION_TERMINATE_PROCESS;
|
||||
|
||||
uint32_t status = SysContinueException(&request);
|
||||
for (;;) SysExitProcess((int32_t)NtlpStatusOrFailure(status));
|
||||
}
|
||||
|
||||
// Asks the kernel to continue searching from the top-level native dispatcher.
|
||||
static void NtlpContinueExceptionSearch(void) {
|
||||
SYS_CONTINUE_EXCEPTION_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.Disposition = SYS_EXCEPTION_DISPOSITION_CONTINUE_SEARCH;
|
||||
|
||||
uint32_t status = SysContinueException(&request);
|
||||
for (;;) SysExitProcess((int32_t)NtlpStatusOrFailure(status));
|
||||
}
|
||||
|
||||
// Asks the kernel to resume execution with a handler-edited user context.
|
||||
static void NtlpContinueExecution(SYS_USER_CONTEXT* context) {
|
||||
SYS_CONTINUE_EXCEPTION_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.Disposition = SYS_EXCEPTION_DISPOSITION_CONTINUE_EXECUTION;
|
||||
request.Context = context;
|
||||
|
||||
uint32_t status = SysContinueException(&request);
|
||||
for (;;) SysExitProcess((int32_t)NtlpStatusOrFailure(status));
|
||||
}
|
||||
|
||||
// Returns whether one kernel-provided exception frame has the expected ABI shape.
|
||||
static int NtlpFrameIsValid(SYS_EXCEPTION_FRAME* frame) {
|
||||
if (!frame)
|
||||
return 0;
|
||||
if (frame->Size != sizeof(*frame) || frame->Version != SYS_EXCEPTION_ABI_VERSION)
|
||||
return 0;
|
||||
if (frame->ExceptionRecord.Size != sizeof(frame->ExceptionRecord) ||
|
||||
frame->ExceptionRecord.Version != SYS_EXCEPTION_ABI_VERSION)
|
||||
return 0;
|
||||
if (frame->ContextRecord.Size != sizeof(frame->ContextRecord) ||
|
||||
frame->ContextRecord.Version != SYS_EXCEPTION_ABI_VERSION)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Copies the current handler list so callbacks can run without holding the list lock.
|
||||
static size_t NtlpSnapshotExceptionHandlers(NTL_EXCEPTION_HANDLER_SNAPSHOT* snapshot, size_t capacity) {
|
||||
size_t count = 0;
|
||||
|
||||
NtlpExceptionLock();
|
||||
for (uint32_t index = gNtlExceptionListHead;
|
||||
index != UINT32_MAX && count < capacity;
|
||||
index = gNtlExceptionHandlers[index].Next) {
|
||||
NTL_EXCEPTION_HANDLER_ENTRY* entry = &gNtlExceptionHandlers[index];
|
||||
if (!entry->Active || !entry->Handler)
|
||||
continue;
|
||||
snapshot[count].Handler = entry->Handler;
|
||||
snapshot[count].Context = entry->Context;
|
||||
count++;
|
||||
}
|
||||
NtlpExceptionUnlock();
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
// Dispatches one kernel-delivered exception through the native handler list.
|
||||
static void NtlpUserExceptionDispatcher(SYS_EXCEPTION_FRAME* frame) {
|
||||
if (!NtlpFrameIsValid(frame))
|
||||
NtlpTerminateExceptionDispatch();
|
||||
|
||||
NTL_EXCEPTION_HANDLER_SNAPSHOT snapshot[NTL_EXCEPTION_MAX_HANDLERS];
|
||||
size_t count = NtlpSnapshotExceptionHandlers(snapshot, NTL_EXCEPTION_MAX_HANDLERS);
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
int disposition = snapshot[i].Handler(&frame->ExceptionRecord,
|
||||
&frame->ContextRecord,
|
||||
snapshot[i].Context);
|
||||
if (disposition == NTL_EXCEPTION_CONTINUE_SEARCH)
|
||||
continue;
|
||||
if (disposition == NTL_EXCEPTION_CONTINUE_EXECUTION)
|
||||
NtlpContinueExecution(&frame->ContextRecord);
|
||||
if (disposition == NTL_EXCEPTION_TERMINATE_PROCESS)
|
||||
NtlpTerminateExceptionDispatch();
|
||||
NtlpTerminateExceptionDispatch();
|
||||
}
|
||||
|
||||
NtlpContinueExceptionSearch();
|
||||
}
|
||||
|
||||
// Registers the native dispatcher for the current process when no other dispatcher owns the process.
|
||||
NTL_EXCEPTION_API uint32_t NtlInitializeExceptionRuntime(void) {
|
||||
NtlpExceptionLock();
|
||||
|
||||
SYS_EXCEPTION_DISPATCHER_REQUEST current;
|
||||
memset(¤t, 0, sizeof(current));
|
||||
current.Size = sizeof(current);
|
||||
uint32_t status = SysGetExceptionDispatcher(¤t);
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
NtlpExceptionUnlock();
|
||||
return status;
|
||||
}
|
||||
|
||||
if (current.DispatcherRoutine == NtlpUserExceptionDispatcher) {
|
||||
NtlpExceptionUnlock();
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
if (current.DispatcherRoutine) {
|
||||
NtlpExceptionUnlock();
|
||||
return NTLSTATUS_ALREADY_EXISTS;
|
||||
}
|
||||
|
||||
SYS_EXCEPTION_DISPATCHER_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.DispatcherRoutine = NtlpUserExceptionDispatcher;
|
||||
|
||||
status = SysSetExceptionDispatcher(&request);
|
||||
NtlpExceptionUnlock();
|
||||
return status;
|
||||
}
|
||||
|
||||
// Adds one process-local native exception handler.
|
||||
NTL_EXCEPTION_API void* NtlAddExceptionHandler(int first, NTL_EXCEPTION_HANDLER handler, void* context) {
|
||||
if (!handler)
|
||||
return 0;
|
||||
if (NtlInitializeExceptionRuntime() != NTLSTATUS_SUCCESS)
|
||||
return 0;
|
||||
|
||||
NtlpExceptionLock();
|
||||
|
||||
uint32_t slot = UINT32_MAX;
|
||||
for (uint32_t i = 0; i < NTL_EXCEPTION_MAX_HANDLERS; i++) {
|
||||
if (!gNtlExceptionHandlers[i].Active) {
|
||||
slot = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (slot == UINT32_MAX) {
|
||||
NtlpExceptionUnlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
NTL_EXCEPTION_HANDLER_ENTRY* entry = &gNtlExceptionHandlers[slot];
|
||||
entry->Active = 1;
|
||||
entry->Handler = handler;
|
||||
entry->Context = context;
|
||||
entry->Previous = UINT32_MAX;
|
||||
entry->Next = UINT32_MAX;
|
||||
|
||||
if (gNtlExceptionListHead == UINT32_MAX) {
|
||||
gNtlExceptionListHead = slot;
|
||||
gNtlExceptionListTail = slot;
|
||||
} else if (first) {
|
||||
entry->Next = gNtlExceptionListHead;
|
||||
gNtlExceptionHandlers[gNtlExceptionListHead].Previous = slot;
|
||||
gNtlExceptionListHead = slot;
|
||||
} else {
|
||||
entry->Previous = gNtlExceptionListTail;
|
||||
gNtlExceptionHandlers[gNtlExceptionListTail].Next = slot;
|
||||
gNtlExceptionListTail = slot;
|
||||
}
|
||||
|
||||
NtlpExceptionUnlock();
|
||||
return entry;
|
||||
}
|
||||
|
||||
// Removes one process-local native exception handler.
|
||||
NTL_EXCEPTION_API uint32_t NtlRemoveExceptionHandler(void* handle) {
|
||||
if (!handle)
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
NtlpExceptionLock();
|
||||
|
||||
uint32_t slot = UINT32_MAX;
|
||||
for (uint32_t i = 0; i < NTL_EXCEPTION_MAX_HANDLERS; i++) {
|
||||
if (handle == &gNtlExceptionHandlers[i]) {
|
||||
slot = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (slot == UINT32_MAX || !gNtlExceptionHandlers[slot].Active) {
|
||||
NtlpExceptionUnlock();
|
||||
return NTLSTATUS_NOT_FOUND;
|
||||
}
|
||||
|
||||
NTL_EXCEPTION_HANDLER_ENTRY* entry = &gNtlExceptionHandlers[slot];
|
||||
if (entry->Previous != UINT32_MAX)
|
||||
gNtlExceptionHandlers[entry->Previous].Next = entry->Next;
|
||||
else
|
||||
gNtlExceptionListHead = entry->Next;
|
||||
|
||||
if (entry->Next != UINT32_MAX)
|
||||
gNtlExceptionHandlers[entry->Next].Previous = entry->Previous;
|
||||
else
|
||||
gNtlExceptionListTail = entry->Previous;
|
||||
|
||||
memset(entry, 0, sizeof(*entry));
|
||||
entry->Previous = UINT32_MAX;
|
||||
entry->Next = UINT32_MAX;
|
||||
|
||||
NtlpExceptionUnlock();
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// Native process startup. This file owns process-local native runtime initialization before main runs.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <ntlite/exception.h>
|
||||
#include <ntlite/syscall.h>
|
||||
|
||||
extern int main(void);
|
||||
|
||||
// Initializes native process state and exits with main's return value.
|
||||
void NtlNativeStart(void) {
|
||||
uint32_t status = NtlInitializeExceptionRuntime();
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
for (;;) SysExitProcess((int32_t)status);
|
||||
}
|
||||
|
||||
int exitCode = main();
|
||||
for (;;) SysExitProcess(exitCode);
|
||||
}
|
||||
@@ -1,13 +1,22 @@
|
||||
// POSIX process startup. This file owns process-local POSIX personality initialization before main runs.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <ntlite/exception.h>
|
||||
#include <ntlite/syscall.h>
|
||||
|
||||
extern int main(void);
|
||||
extern void exit(int status);
|
||||
extern void PosixFdInit(void);
|
||||
|
||||
// Initializes POSIX process state and exits with main's return value.
|
||||
void PosixStart(void) {
|
||||
uint32_t status = NtlInitializeExceptionRuntime();
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
for (;;) SysExitProcess((int32_t)status);
|
||||
}
|
||||
|
||||
PosixFdInit();
|
||||
int status = main();
|
||||
exit(status);
|
||||
int exitCode = main();
|
||||
exit(exitCode);
|
||||
for (;;) {}
|
||||
}
|
||||
+126
-121
@@ -1,140 +1,145 @@
|
||||
; Syscall numbers shared by MASM user-mode stubs.
|
||||
|
||||
; Process, threads, modules, waits, and APC.
|
||||
SYS_EXIT_PROCESS EQU 0
|
||||
SYS_EXIT_THREAD EQU 1
|
||||
SYS_CREATE_PROCESS EQU 2
|
||||
SYS_OPEN_PROCESS EQU 3
|
||||
SYS_GET_PROCESS_EXIT_CODE EQU 4
|
||||
SYS_KILL_PROCESS EQU 5
|
||||
SYS_GET_PROCESS_LIST EQU 6
|
||||
SYS_GET_PROCESS_PID EQU 7
|
||||
SYS_CREATE_THREAD EQU 8
|
||||
SYS_GET_THREAD_LIST EQU 9
|
||||
SYS_LOAD_MODULE EQU 10
|
||||
SYS_UNLOAD_MODULE EQU 11
|
||||
SYS_GET_MODULE_INFO EQU 12
|
||||
SYS_GET_MODULE_EXPORT EQU 13
|
||||
SYS_GET_MODULE_LIST EQU 14
|
||||
SYS_GET_CURRENT_TID EQU 15
|
||||
SYS_GET_CURRENT_PID EQU 16
|
||||
SYS_SET_THREAD_PRIORITY EQU 17
|
||||
SYS_YIELD EQU 18
|
||||
SYS_SLEEP EQU 19
|
||||
SYS_WAIT_SINGLE EQU 20
|
||||
SYS_WAIT_MANY EQU 21
|
||||
SYS_SET_USER_APC_DISPATCHER EQU 22
|
||||
SYS_APC_RETURN EQU 23
|
||||
; Process, threads, modules, waits, APC, and exceptions.
|
||||
SYS_EXIT_PROCESS EQU 0
|
||||
SYS_EXIT_THREAD EQU 1
|
||||
SYS_CREATE_PROCESS EQU 2
|
||||
SYS_OPEN_PROCESS EQU 3
|
||||
SYS_GET_PROCESS_EXIT_CODE EQU 4
|
||||
SYS_KILL_PROCESS EQU 5
|
||||
SYS_GET_PROCESS_LIST EQU 6
|
||||
SYS_GET_PROCESS_PID EQU 7
|
||||
SYS_CREATE_THREAD EQU 8
|
||||
SYS_GET_THREAD_LIST EQU 9
|
||||
SYS_LOAD_MODULE EQU 10
|
||||
SYS_UNLOAD_MODULE EQU 11
|
||||
SYS_GET_MODULE_INFO EQU 12
|
||||
SYS_GET_MODULE_EXPORT EQU 13
|
||||
SYS_GET_MODULE_LIST EQU 14
|
||||
SYS_GET_CURRENT_TID EQU 15
|
||||
SYS_GET_CURRENT_PID EQU 16
|
||||
SYS_SET_THREAD_PRIORITY EQU 17
|
||||
SYS_YIELD EQU 18
|
||||
SYS_SLEEP EQU 19
|
||||
SYS_WAIT_SINGLE EQU 20
|
||||
SYS_WAIT_MANY EQU 21
|
||||
SYS_SET_USER_APC_DISPATCHER EQU 22
|
||||
SYS_APC_RETURN EQU 23
|
||||
SYS_SET_EXCEPTION_DISPATCHER EQU 24
|
||||
SYS_GET_EXCEPTION_DISPATCHER EQU 25
|
||||
SYS_CONTINUE_EXCEPTION EQU 26
|
||||
SYS_RAISE_EXCEPTION EQU 27
|
||||
|
||||
; Virtual memory, mappings, and handles.
|
||||
SYS_ALLOC_VM EQU 24
|
||||
SYS_FREE_VM EQU 25
|
||||
SYS_PROTECT_VM EQU 26
|
||||
SYS_QUERY_VM EQU 27
|
||||
SYS_CLOSE_HANDLE EQU 28
|
||||
SYS_DUPLICATE_HANDLE EQU 29
|
||||
SYS_CREATE_FILE_MAPPING EQU 30
|
||||
SYS_MAP_FILE EQU 31
|
||||
SYS_ALLOC_VM EQU 28
|
||||
SYS_FREE_VM EQU 29
|
||||
SYS_PROTECT_VM EQU 30
|
||||
SYS_QUERY_VM EQU 31
|
||||
SYS_CLOSE_HANDLE EQU 32
|
||||
SYS_DUPLICATE_HANDLE EQU 33
|
||||
SYS_CREATE_FILE_MAPPING EQU 34
|
||||
SYS_MAP_FILE EQU 35
|
||||
|
||||
; Synchronization objects.
|
||||
SYS_CREATE_MUTEX EQU 32
|
||||
SYS_TRY_ACQUIRE_MUTEX EQU 33
|
||||
SYS_RELEASE_MUTEX EQU 34
|
||||
SYS_CREATE_SEM EQU 35
|
||||
SYS_TRY_WAIT_SEM EQU 36
|
||||
SYS_SIGNAL_SEM EQU 37
|
||||
SYS_CREATE_EVENT EQU 38
|
||||
SYS_SIGNAL_EVENT EQU 39
|
||||
SYS_CLEAR_EVENT EQU 40
|
||||
SYS_CREATE_MUTEX EQU 36
|
||||
SYS_TRY_ACQUIRE_MUTEX EQU 37
|
||||
SYS_RELEASE_MUTEX EQU 38
|
||||
SYS_CREATE_SEM EQU 39
|
||||
SYS_TRY_WAIT_SEM EQU 40
|
||||
SYS_SIGNAL_SEM EQU 41
|
||||
SYS_CREATE_EVENT EQU 42
|
||||
SYS_SIGNAL_EVENT EQU 43
|
||||
SYS_CLEAR_EVENT EQU 44
|
||||
|
||||
; Queues and named queues.
|
||||
SYS_CREATE_QUEUE EQU 41
|
||||
SYS_SEND_QUEUE EQU 42
|
||||
SYS_RECV_QUEUE EQU 43
|
||||
SYS_PUBLISH_QUEUE EQU 44
|
||||
SYS_OPEN_NAMED_QUEUE EQU 45
|
||||
SYS_OPEN_NAMED_QUEUE_OWNER_PROCESS EQU 46
|
||||
SYS_CREATE_QUEUE EQU 45
|
||||
SYS_SEND_QUEUE EQU 46
|
||||
SYS_RECV_QUEUE EQU 47
|
||||
SYS_PUBLISH_QUEUE EQU 48
|
||||
SYS_OPEN_NAMED_QUEUE EQU 49
|
||||
SYS_OPEN_NAMED_QUEUE_OWNER_PROCESS EQU 50
|
||||
|
||||
; Files, directories, and current directory.
|
||||
SYS_OPEN_FILE EQU 47
|
||||
SYS_READ_FILE EQU 48
|
||||
SYS_WRITE_FILE EQU 49
|
||||
SYS_READ_FILE_ASYNC EQU 50
|
||||
SYS_WRITE_FILE_ASYNC EQU 51
|
||||
SYS_CANCEL_IO EQU 52
|
||||
SYS_SEEK_FILE EQU 53
|
||||
SYS_GET_FILE_POS EQU 54
|
||||
SYS_GET_FILE_SIZE EQU 55
|
||||
SYS_GET_FILE_STAT EQU 56
|
||||
SYS_STAT_FILE EQU 57
|
||||
SYS_TRUNCATE_FILE EQU 58
|
||||
SYS_FLUSH_FILE EQU 59
|
||||
SYS_DELETE_FILE EQU 60
|
||||
SYS_RENAME_FILE EQU 61
|
||||
SYS_LOCK_FILE EQU 62
|
||||
SYS_UNLOCK_FILE EQU 63
|
||||
SYS_OPEN_DIR EQU 64
|
||||
SYS_READ_DIR EQU 65
|
||||
SYS_CREATE_DIR EQU 66
|
||||
SYS_REMOVE_DIR EQU 67
|
||||
SYS_SET_CWD EQU 68
|
||||
SYS_REAL_PATH EQU 69
|
||||
SYS_OPEN_FILE EQU 51
|
||||
SYS_READ_FILE EQU 52
|
||||
SYS_WRITE_FILE EQU 53
|
||||
SYS_READ_FILE_ASYNC EQU 54
|
||||
SYS_WRITE_FILE_ASYNC EQU 55
|
||||
SYS_CANCEL_IO EQU 56
|
||||
SYS_SEEK_FILE EQU 57
|
||||
SYS_GET_FILE_POS EQU 58
|
||||
SYS_GET_FILE_SIZE EQU 59
|
||||
SYS_GET_FILE_STAT EQU 60
|
||||
SYS_STAT_FILE EQU 61
|
||||
SYS_TRUNCATE_FILE EQU 62
|
||||
SYS_FLUSH_FILE EQU 63
|
||||
SYS_DELETE_FILE EQU 64
|
||||
SYS_RENAME_FILE EQU 65
|
||||
SYS_LOCK_FILE EQU 66
|
||||
SYS_UNLOCK_FILE EQU 67
|
||||
SYS_OPEN_DIR EQU 68
|
||||
SYS_READ_DIR EQU 69
|
||||
SYS_CREATE_DIR EQU 70
|
||||
SYS_REMOVE_DIR EQU 71
|
||||
SYS_SET_CWD EQU 72
|
||||
SYS_REAL_PATH EQU 73
|
||||
|
||||
; Console, display, and surfaces.
|
||||
SYS_WRITE_CONSOLE EQU 70
|
||||
SYS_GET_CONSOLE_INFO EQU 71
|
||||
SYS_SET_CONSOLE_CURSOR EQU 72
|
||||
SYS_FILL_CONSOLE_CHARACTER EQU 73
|
||||
SYS_FILL_CONSOLE_ATTRIBUTE EQU 74
|
||||
SYS_PUT_SCREEN_CHAR EQU 75
|
||||
SYS_CLEAR_SCREEN EQU 76
|
||||
SYS_GET_SCREEN_SIZE EQU 77
|
||||
SYS_QUERY_DISPLAY_INFO EQU 78
|
||||
SYS_CREATE_SURFACE EQU 79
|
||||
SYS_MAP_SURFACE EQU 80
|
||||
SYS_QUERY_SURFACE EQU 81
|
||||
SYS_PRESENT_SURFACE EQU 82
|
||||
SYS_WRITE_CONSOLE EQU 74
|
||||
SYS_GET_CONSOLE_INFO EQU 75
|
||||
SYS_SET_CONSOLE_CURSOR EQU 76
|
||||
SYS_FILL_CONSOLE_CHARACTER EQU 77
|
||||
SYS_FILL_CONSOLE_ATTRIBUTE EQU 78
|
||||
SYS_PUT_SCREEN_CHAR EQU 79
|
||||
SYS_CLEAR_SCREEN EQU 80
|
||||
SYS_GET_SCREEN_SIZE EQU 81
|
||||
SYS_QUERY_DISPLAY_INFO EQU 82
|
||||
SYS_CREATE_SURFACE EQU 83
|
||||
SYS_MAP_SURFACE EQU 84
|
||||
SYS_QUERY_SURFACE EQU 85
|
||||
SYS_PRESENT_SURFACE EQU 86
|
||||
|
||||
; Input.
|
||||
SYS_POLL_KEYBOARD EQU 83
|
||||
SYS_IS_KEY_DOWN EQU 84
|
||||
SYS_READ_KEYBOARD_CHAR EQU 85
|
||||
SYS_READ_KEY EQU 86
|
||||
SYS_GET_KEY_MODIFIERS EQU 87
|
||||
SYS_OPEN_INPUT_QUEUE EQU 88
|
||||
SYS_READ_INPUT_EVENT EQU 89
|
||||
SYS_PEEK_INPUT_EVENT EQU 90
|
||||
SYS_PEEK_MOUSE EQU 91
|
||||
SYS_READ_MOUSE EQU 92
|
||||
SYS_GET_MOUSE_POS EQU 93
|
||||
SYS_POLL_KEYBOARD EQU 87
|
||||
SYS_IS_KEY_DOWN EQU 88
|
||||
SYS_READ_KEYBOARD_CHAR EQU 89
|
||||
SYS_READ_KEY EQU 90
|
||||
SYS_GET_KEY_MODIFIERS EQU 91
|
||||
SYS_OPEN_INPUT_QUEUE EQU 92
|
||||
SYS_READ_INPUT_EVENT EQU 93
|
||||
SYS_PEEK_INPUT_EVENT EQU 94
|
||||
SYS_PEEK_MOUSE EQU 95
|
||||
SYS_READ_MOUSE EQU 96
|
||||
SYS_GET_MOUSE_POS EQU 97
|
||||
|
||||
; Time, debug, and system information.
|
||||
SYS_CREATE_TIMER EQU 94
|
||||
SYS_SET_TIMER EQU 95
|
||||
SYS_CANCEL_TIMER EQU 96
|
||||
SYS_GET_TICK EQU 97
|
||||
SYS_GET_TICK_FREQUENCY EQU 98
|
||||
SYS_GET_SYSTEM_TIME EQU 99
|
||||
SYS_PRINT_DEBUG EQU 100
|
||||
SYS_QUERY_TRAP_FRAME EQU 101
|
||||
SYS_GET_MEMORY_STATUS EQU 102
|
||||
SYS_QUERY_KERNEL_STATS EQU 103
|
||||
SYS_CREATE_TIMER EQU 98
|
||||
SYS_SET_TIMER EQU 99
|
||||
SYS_CANCEL_TIMER EQU 100
|
||||
SYS_GET_TICK EQU 101
|
||||
SYS_GET_TICK_FREQUENCY EQU 102
|
||||
SYS_GET_SYSTEM_TIME EQU 103
|
||||
SYS_PRINT_DEBUG EQU 104
|
||||
SYS_QUERY_TRAP_FRAME EQU 105
|
||||
SYS_GET_MEMORY_STATUS EQU 106
|
||||
SYS_QUERY_KERNEL_STATS EQU 107
|
||||
|
||||
; Native sockets and polling.
|
||||
SYS_CREATE_SOCKET EQU 104
|
||||
SYS_SOCKET_IO_ASYNC EQU 105
|
||||
SYS_BIND_SOCKET EQU 106
|
||||
SYS_LISTEN_SOCKET EQU 107
|
||||
SYS_ACCEPT_SOCKET EQU 108
|
||||
SYS_CONNECT_SOCKET EQU 109
|
||||
SYS_SEND_SOCKET EQU 110
|
||||
SYS_RECV_SOCKET EQU 111
|
||||
SYS_SHUTDOWN_SOCKET EQU 112
|
||||
SYS_SEND_TO_SOCKET EQU 113
|
||||
SYS_RECV_FROM_SOCKET EQU 114
|
||||
SYS_RESOLVE_HOST EQU 115
|
||||
SYS_SET_SOCKET_OPTION EQU 116
|
||||
SYS_GET_SOCKET_OPTION EQU 117
|
||||
SYS_POLL EQU 118
|
||||
SYS_CREATE_SOCKET EQU 108
|
||||
SYS_SOCKET_IO_ASYNC EQU 109
|
||||
SYS_BIND_SOCKET EQU 110
|
||||
SYS_LISTEN_SOCKET EQU 111
|
||||
SYS_ACCEPT_SOCKET EQU 112
|
||||
SYS_CONNECT_SOCKET EQU 113
|
||||
SYS_SEND_SOCKET EQU 114
|
||||
SYS_RECV_SOCKET EQU 115
|
||||
SYS_SHUTDOWN_SOCKET EQU 116
|
||||
SYS_SEND_TO_SOCKET EQU 117
|
||||
SYS_RECV_FROM_SOCKET EQU 118
|
||||
SYS_RESOLVE_HOST EQU 119
|
||||
SYS_SET_SOCKET_OPTION EQU 120
|
||||
SYS_GET_SOCKET_OPTION EQU 121
|
||||
SYS_POLL EQU 122
|
||||
SYS_UNPUBLISH_QUEUE EQU 123
|
||||
|
||||
SYS_MAX EQU 119
|
||||
SYS_MAX EQU 124
|
||||
@@ -104,6 +104,10 @@ SYSCALL_STUB2 Yield, SYS_YIELD
|
||||
SYSCALL_STUB2 Sleep, SYS_SLEEP
|
||||
SYSCALL_STUB2 SetUserApcDispatcher, SYS_SET_USER_APC_DISPATCHER
|
||||
SYSCALL_STUB2 ApcReturn, SYS_APC_RETURN
|
||||
SYSCALL_STUB2 SetExceptionDispatcher, SYS_SET_EXCEPTION_DISPATCHER
|
||||
SYSCALL_STUB2 GetExceptionDispatcher, SYS_GET_EXCEPTION_DISPATCHER
|
||||
SYSCALL_STUB2 ContinueException, SYS_CONTINUE_EXCEPTION
|
||||
SYSCALL_STUB2 RaiseException, SYS_RAISE_EXCEPTION
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; User APC dispatcher
|
||||
@@ -137,7 +141,7 @@ SysUserApcDispatcher ENDP
|
||||
; ---------------------------------------------------------------------------
|
||||
; Virtual memory and handles
|
||||
; ---------------------------------------------------------------------------
|
||||
SYSCALL_STUB6 AllocVm, SYS_ALLOC_VM
|
||||
SYSCALL_STUB2 AllocVm, SYS_ALLOC_VM
|
||||
SYSCALL_STUB2 FreeVm, SYS_FREE_VM
|
||||
SYSCALL_STUB2 ProtectVm, SYS_PROTECT_VM
|
||||
SYSCALL_STUB2 QueryVm, SYS_QUERY_VM
|
||||
@@ -166,6 +170,7 @@ SYSCALL_STUB2 CreateQueue, SYS_CREATE_QUEUE
|
||||
SYSCALL_STUB2 SendQueue, SYS_SEND_QUEUE
|
||||
SYSCALL_STUB2 RecvQueue, SYS_RECV_QUEUE
|
||||
SYSCALL_STUB2 PublishQueue, SYS_PUBLISH_QUEUE
|
||||
SYSCALL_STUB2 UnpublishQueue, SYS_UNPUBLISH_QUEUE
|
||||
SYSCALL_STUB2 OpenNamedQueue, SYS_OPEN_NAMED_QUEUE
|
||||
SYSCALL_STUB2 OpenNamedQueueOwnerProcess, SYS_OPEN_NAMED_QUEUE_OWNER_PROCESS
|
||||
|
||||
@@ -206,7 +211,7 @@ SYSCALL_STUB2 SetConsoleCursor, SYS_SET_CONSOLE_CURSOR
|
||||
SYSCALL_STUB6 FillConsoleCharacter, SYS_FILL_CONSOLE_CHARACTER
|
||||
SYSCALL_STUB6 FillConsoleAttribute, SYS_FILL_CONSOLE_ATTRIBUTE
|
||||
SYSCALL_STUB6 PutScreenChar, SYS_PUT_SCREEN_CHAR
|
||||
SYSCALL_STUB5 CreateSurface, SYS_CREATE_SURFACE
|
||||
SYSCALL_STUB2 CreateSurface, SYS_CREATE_SURFACE
|
||||
SYSCALL_STUB2 MapSurface, SYS_MAP_SURFACE
|
||||
SYSCALL_STUB2 QuerySurface, SYS_QUERY_SURFACE
|
||||
SYSCALL_STUB2 PresentSurface, SYS_PRESENT_SURFACE
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <ntlite/exception.h>
|
||||
#include <ntlite/syscall.h>
|
||||
|
||||
// Implements the itoa operation.
|
||||
@@ -54,8 +55,13 @@ static void debug_print(const char* s) {
|
||||
(void)SysPrintDebug(&req);
|
||||
}
|
||||
|
||||
// Initializes init process state and supervises the configured child process.
|
||||
void _start(void)
|
||||
{
|
||||
uint32_t runtimeStatus = NtlInitializeExceptionRuntime();
|
||||
if (runtimeStatus != NTLSTATUS_SUCCESS)
|
||||
SysExitProcess((int32_t)runtimeStatus);
|
||||
|
||||
SYS_STRING_VIEW args = SysGetPeb()->CommandLine;
|
||||
uint32_t h = 0;
|
||||
uint32_t s = 0;
|
||||
@@ -64,7 +70,7 @@ void _start(void)
|
||||
debug_print("[init] starting\n");
|
||||
SYS_CREATE_PROCESS_REQUEST cp = { args, SysSvFromParts(0, 0), &h };
|
||||
s = SysCreateProcess(&cp);
|
||||
if (s != STATUS_SUCCESS) {
|
||||
if (s != NTLSTATUS_SUCCESS) {
|
||||
debug_print("[init] FATAL: failed to start!\n");
|
||||
char buffer[12];
|
||||
itoa(s, buffer);
|
||||
@@ -75,11 +81,11 @@ void _start(void)
|
||||
|
||||
debug_print("[init] waiting\n");
|
||||
s = SysWait(h, SYS_WAIT_FLAG_NONE);
|
||||
if (s != STATUS_SUCCESS)
|
||||
if (s != NTLSTATUS_SUCCESS)
|
||||
debug_print("[init] WARNING: SysWait returned error\n");
|
||||
|
||||
int32_t exitCode = 0;
|
||||
if (SysGetProcessExitCode(h, &exitCode) != STATUS_SUCCESS) {
|
||||
if (SysGetProcessExitCode(h, &exitCode) != NTLSTATUS_SUCCESS) {
|
||||
debug_print("[init] WARNING: failed to read exit code\n");
|
||||
exitCode = 1;
|
||||
}
|
||||
|
||||
@@ -57,13 +57,13 @@ static uint32_t open_test_file(uint32_t* handleOut) {
|
||||
SYS_FILE_FLAG_NONE,
|
||||
&handle);
|
||||
uint32_t status = SysOpenFile(&request);
|
||||
if (status == STATUS_SUCCESS) {
|
||||
if (status == NTLSTATUS_SUCCESS) {
|
||||
*handleOut = handle;
|
||||
return STATUS_SUCCESS;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return STATUS_NOT_FOUND;
|
||||
return NTLSTATUS_NOT_FOUND;
|
||||
}
|
||||
|
||||
typedef struct APC_RETURN_STATE {
|
||||
@@ -75,7 +75,7 @@ typedef struct APC_RETURN_STATE {
|
||||
// Records that the user APC callback ran and observed the I/O status block.
|
||||
static void file_apc(void* context, SYS_IO_STATUS_BLOCK* iosb, uint64_t information) {
|
||||
APC_RETURN_STATE* state = (APC_RETURN_STATE*)context;
|
||||
state->Status = iosb ? iosb->Status : STATUS_FAILURE;
|
||||
state->Status = iosb ? iosb->Status : NTLSTATUS_FAILURE;
|
||||
state->Information = information;
|
||||
state->Delivered++;
|
||||
}
|
||||
@@ -97,29 +97,29 @@ int main(void) {
|
||||
print("apc_return_smoke: start\n");
|
||||
|
||||
uint32_t status = SysApcReturn((const SYS_USER_APC_FRAME*)0);
|
||||
if (status != STATUS_INVALID_PARAMETER)
|
||||
fail_status("inactive null return", status, STATUS_INVALID_PARAMETER);
|
||||
if (status != NTLSTATUS_INVALID_PARAMETER)
|
||||
fail_status("inactive null return", status, NTLSTATUS_INVALID_PARAMETER);
|
||||
|
||||
SYS_USER_APC_FRAME fakeFrame;
|
||||
memset(&fakeFrame, 0, sizeof(fakeFrame));
|
||||
fakeFrame.Magic = SYS_USER_APC_FRAME_MAGIC;
|
||||
status = SysApcReturn(&fakeFrame);
|
||||
if (status != STATUS_INVALID_PARAMETER)
|
||||
fail_status("inactive forged return", status, STATUS_INVALID_PARAMETER);
|
||||
if (status != NTLSTATUS_INVALID_PARAMETER)
|
||||
fail_status("inactive forged return", status, NTLSTATUS_INVALID_PARAMETER);
|
||||
|
||||
status = SysSetUserApcDispatcher((void*)SysUserApcDispatcher);
|
||||
if (status != STATUS_SUCCESS)
|
||||
fail_status("set dispatcher", status, STATUS_SUCCESS);
|
||||
if (status != NTLSTATUS_SUCCESS)
|
||||
fail_status("set dispatcher", status, NTLSTATUS_SUCCESS);
|
||||
|
||||
uint32_t file = 0;
|
||||
status = open_test_file(&file);
|
||||
if (status != STATUS_SUCCESS)
|
||||
fail_status("open", status, STATUS_SUCCESS);
|
||||
if (status != NTLSTATUS_SUCCESS)
|
||||
fail_status("open", status, NTLSTATUS_SUCCESS);
|
||||
|
||||
uint32_t event = 0;
|
||||
status = SysCreateEvent(EVENT_AUTO_RESET, 0, &event);
|
||||
if (status != STATUS_SUCCESS)
|
||||
fail_status("create event", status, STATUS_SUCCESS);
|
||||
if (status != NTLSTATUS_SUCCESS)
|
||||
fail_status("create event", status, NTLSTATUS_SUCCESS);
|
||||
|
||||
uint8_t* buffer = (uint8_t*)malloc(512);
|
||||
if (!buffer) {
|
||||
@@ -146,16 +146,16 @@ int main(void) {
|
||||
request.ApcContext = &state;
|
||||
|
||||
status = SysReadFileAsync(&request);
|
||||
if (status != STATUS_PENDING)
|
||||
fail_status("submit", status, STATUS_PENDING);
|
||||
if (status != NTLSTATUS_PENDING)
|
||||
fail_status("submit", status, NTLSTATUS_PENDING);
|
||||
|
||||
while (!state.Delivered) {
|
||||
status = SysWait(event, SYS_WAIT_FLAG_ALERTABLE);
|
||||
if (status != STATUS_USER_APC && status != STATUS_SUCCESS && status != STATUS_PENDING)
|
||||
fail_status("alertable wait", status, STATUS_USER_APC);
|
||||
if (status != NTLSTATUS_USER_APC && status != NTLSTATUS_SUCCESS && status != NTLSTATUS_PENDING)
|
||||
fail_status("alertable wait", status, NTLSTATUS_USER_APC);
|
||||
}
|
||||
|
||||
uint32_t ok = state.Delivered == 1 && state.Status == STATUS_SUCCESS && state.Information == 512;
|
||||
uint32_t ok = state.Delivered == 1 && state.Status == NTLSTATUS_SUCCESS && state.Information == 512;
|
||||
|
||||
SysCloseHandle(event);
|
||||
SysCloseHandle(file);
|
||||
|
||||
@@ -39,15 +39,15 @@ static uint32_t open_test_file(uint32_t* handleOut, const char** pathOut) {
|
||||
SYS_FILE_FLAG_NONE,
|
||||
&h);
|
||||
uint32_t s = SysOpenFile(&req);
|
||||
if (s == STATUS_SUCCESS) {
|
||||
if (s == NTLSTATUS_SUCCESS) {
|
||||
*handleOut = h;
|
||||
if (pathOut)
|
||||
*pathOut = paths[i];
|
||||
return STATUS_SUCCESS;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return STATUS_NOT_FOUND;
|
||||
return NTLSTATUS_NOT_FOUND;
|
||||
}
|
||||
|
||||
// Prints hex8.
|
||||
@@ -95,7 +95,7 @@ int main(void) {
|
||||
print("async_apc: start\n");
|
||||
|
||||
uint32_t s = SysSetUserApcDispatcher((void*)SysUserApcDispatcher);
|
||||
if (s != STATUS_SUCCESS) {
|
||||
if (s != NTLSTATUS_SUCCESS) {
|
||||
print("async_apc: dispatcher registration failed status=");
|
||||
print_u64(s);
|
||||
print("\n");
|
||||
@@ -105,7 +105,7 @@ int main(void) {
|
||||
uint32_t file = 0;
|
||||
const char* openedPath = 0;
|
||||
s = open_test_file(&file, &openedPath);
|
||||
if (s != STATUS_SUCCESS) {
|
||||
if (s != NTLSTATUS_SUCCESS) {
|
||||
print("async_apc: open failed status=");
|
||||
print_u64(s);
|
||||
print("\n");
|
||||
@@ -118,7 +118,7 @@ int main(void) {
|
||||
|
||||
uint32_t event = 0;
|
||||
s = SysCreateEvent(EVENT_AUTO_RESET, 0, &event);
|
||||
if (s != STATUS_SUCCESS) {
|
||||
if (s != NTLSTATUS_SUCCESS) {
|
||||
print("async_apc: event create failed status=");
|
||||
print_u64(s);
|
||||
print("\n");
|
||||
@@ -151,7 +151,7 @@ int main(void) {
|
||||
req.ApcContext = &state;
|
||||
|
||||
s = SysReadFileAsync(&req);
|
||||
if (s != STATUS_PENDING) {
|
||||
if (s != NTLSTATUS_PENDING) {
|
||||
print("async_apc: submit failed status=");
|
||||
print_u64(s);
|
||||
print("\n");
|
||||
@@ -163,7 +163,7 @@ int main(void) {
|
||||
print("async_apc: alertable wait returned ");
|
||||
print_u64(s);
|
||||
print("\n");
|
||||
if (s != STATUS_USER_APC && s != STATUS_SUCCESS && s != STATUS_PENDING)
|
||||
if (s != NTLSTATUS_USER_APC && s != NTLSTATUS_SUCCESS && s != NTLSTATUS_PENDING)
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -179,7 +179,7 @@ int main(void) {
|
||||
print_hex8(buffer[2]); print(" ");
|
||||
print_hex8(buffer[3]); print("\n");
|
||||
|
||||
uint32_t ok = (state.Delivered == 1 && state.Status == STATUS_SUCCESS &&
|
||||
uint32_t ok = (state.Delivered == 1 && state.Status == NTLSTATUS_SUCCESS &&
|
||||
state.Information == 512 && buffer[0] == 'M' && buffer[1] == 'Z');
|
||||
|
||||
SysCloseHandle(event);
|
||||
|
||||
@@ -38,15 +38,15 @@ static uint32_t open_test_file(uint32_t* handleOut, const char** pathOut) {
|
||||
SYS_FILE_FLAG_NONE,
|
||||
&h);
|
||||
uint32_t s = SysOpenFile(&req);
|
||||
if (s == STATUS_SUCCESS) {
|
||||
if (s == NTLSTATUS_SUCCESS) {
|
||||
*handleOut = h;
|
||||
if (pathOut)
|
||||
*pathOut = paths[i];
|
||||
return STATUS_SUCCESS;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return STATUS_NOT_FOUND;
|
||||
return NTLSTATUS_NOT_FOUND;
|
||||
}
|
||||
|
||||
// Prints u64.
|
||||
@@ -77,7 +77,7 @@ int main(void) {
|
||||
|
||||
const char* openedPath = 0;
|
||||
uint32_t s = open_test_file(&file, &openedPath);
|
||||
if (s != STATUS_SUCCESS) {
|
||||
if (s != NTLSTATUS_SUCCESS) {
|
||||
print("async_cancel: open failed status="); print_u64(s); print("\n");
|
||||
SysExitProcess(1);
|
||||
}
|
||||
@@ -87,7 +87,7 @@ int main(void) {
|
||||
print("\n");
|
||||
|
||||
s = SysCreateEvent(EVENT_AUTO_RESET, 0, &event);
|
||||
if (s != STATUS_SUCCESS) {
|
||||
if (s != NTLSTATUS_SUCCESS) {
|
||||
print("async_cancel: event create failed status="); print_u64(s); print("\n");
|
||||
SysExitProcess(1);
|
||||
}
|
||||
@@ -114,7 +114,7 @@ int main(void) {
|
||||
req.RequestHandleOut = &request;
|
||||
|
||||
s = SysReadFileAsync(&req);
|
||||
if (s != STATUS_PENDING || request == 0) {
|
||||
if (s != NTLSTATUS_PENDING || request == 0) {
|
||||
print("async_cancel: submit failed status="); print_u64(s);
|
||||
print(" request="); print_u64(request); print("\n");
|
||||
SysExitProcess(1);
|
||||
@@ -123,10 +123,10 @@ int main(void) {
|
||||
uint32_t cs = SysCancelIo(request);
|
||||
print("async_cancel: cancel returned "); print_u64(cs); print("\n");
|
||||
|
||||
while (iosb.Status == STATUS_PENDING) {
|
||||
while (iosb.Status == NTLSTATUS_PENDING) {
|
||||
s = SysWait(event, SYS_WAIT_FLAG_ALERTABLE);
|
||||
print("async_cancel: wait returned "); print_u64(s); print("\n");
|
||||
if (s != STATUS_SUCCESS && s != STATUS_KERNEL_APC && s != STATUS_USER_APC && s != STATUS_ALERTED)
|
||||
if (s != NTLSTATUS_SUCCESS && s != NTLSTATUS_KERNEL_APC && s != NTLSTATUS_USER_APC && s != NTLSTATUS_ALERTED)
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -135,9 +135,9 @@ int main(void) {
|
||||
|
||||
// If the worker had already started, cancellation is best-effort and the
|
||||
// request may complete successfully. If it was still queued, it must report
|
||||
// STATUS_CANCELLED. Both outcomes are valid; STATUS_PENDING is not.
|
||||
uint32_t ok = (iosb.Status == STATUS_CANCELLED) ||
|
||||
(iosb.Status == STATUS_SUCCESS && iosb.Information == 512);
|
||||
// NTLSTATUS_CANCELLED. Both outcomes are valid; NTLSTATUS_PENDING is not.
|
||||
uint32_t ok = (iosb.Status == NTLSTATUS_CANCELLED) ||
|
||||
(iosb.Status == NTLSTATUS_SUCCESS && iosb.Information == 512);
|
||||
|
||||
SysCloseHandle(request);
|
||||
SysCloseHandle(event);
|
||||
|
||||
@@ -58,7 +58,7 @@ static void fail(const char* what) {
|
||||
static void set_cwd_or_fail(const char* path, const char* what) {
|
||||
SYS_PATH_REQUEST req = { SysSvFromCstr(path) };
|
||||
uint32_t status = SysSetCwd(&req);
|
||||
if (status != STATUS_SUCCESS) fail_status(what, status);
|
||||
if (status != NTLSTATUS_SUCCESS) fail_status(what, status);
|
||||
}
|
||||
|
||||
// Verifies the current-directory PEB view against one native path.
|
||||
@@ -87,11 +87,11 @@ int main(void) {
|
||||
|
||||
SYS_PATH_REQUEST dirReq = { SysSvFromCstr(tempDir) };
|
||||
uint32_t status = SysRemoveDir(&dirReq);
|
||||
if (status != STATUS_SUCCESS && status != STATUS_NOT_FOUND)
|
||||
if (status != NTLSTATUS_SUCCESS && status != NTLSTATUS_NOT_FOUND)
|
||||
fail_status("remove stale temp dir", status);
|
||||
|
||||
status = SysCreateDir(&dirReq);
|
||||
if (status != STATUS_SUCCESS) fail_status("create temp dir", status);
|
||||
if (status != NTLSTATUS_SUCCESS) fail_status("create temp dir", status);
|
||||
|
||||
set_cwd_or_fail(tempDir, "set temp cwd");
|
||||
expect_cwd(tempDir);
|
||||
@@ -100,7 +100,7 @@ int main(void) {
|
||||
expect_cwd(rootPath);
|
||||
|
||||
status = SysRemoveDir(&dirReq);
|
||||
if (status != STATUS_SUCCESS) fail_status("remove temp dir", status);
|
||||
if (status != NTLSTATUS_SUCCESS) fail_status("remove temp dir", status);
|
||||
|
||||
print("cwd_peb_smoke: PASS\n");
|
||||
exit_now(0);
|
||||
|
||||
@@ -79,19 +79,19 @@ static uint32_t create_temp(uint32_t* fileOut, const char** pathOut) {
|
||||
uint32_t h = 0;
|
||||
delete_path(paths[i]);
|
||||
SYS_OPEN_FILE_REQUEST req = SysMakeOpenFileRequest(SysSvFromCstr(paths[i]),
|
||||
SYS_FILE_ACCESS_WRITE | SYS_FILE_ACCESS_QUERY,
|
||||
SYS_FILE_ACCESS_READ | SYS_FILE_ACCESS_WRITE | SYS_FILE_ACCESS_QUERY,
|
||||
SYS_FILE_CREATE_NEW,
|
||||
SYS_FILE_FLAG_NONE,
|
||||
&h);
|
||||
uint32_t s = SysOpenFile(&req);
|
||||
if (s == STATUS_SUCCESS) {
|
||||
if (s == NTLSTATUS_SUCCESS) {
|
||||
*fileOut = h;
|
||||
if (pathOut) *pathOut = paths[i];
|
||||
return STATUS_SUCCESS;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return STATUS_NOT_FOUND;
|
||||
return NTLSTATUS_NOT_FOUND;
|
||||
}
|
||||
|
||||
static uint32_t open_path(const char* path, uint32_t* fileOut) {
|
||||
@@ -102,7 +102,7 @@ static uint32_t open_path(const char* path, uint32_t* fileOut) {
|
||||
SYS_FILE_FLAG_NONE,
|
||||
&h);
|
||||
uint32_t s = SysOpenFile(&req);
|
||||
if (s == STATUS_SUCCESS)
|
||||
if (s == NTLSTATUS_SUCCESS)
|
||||
*fileOut = h;
|
||||
return s;
|
||||
}
|
||||
@@ -118,7 +118,7 @@ static void checked_write(uint32_t file, const void* buffer, size_t size, const
|
||||
size_t done = 0;
|
||||
SYS_FILE_IO_REQUEST req = SysMakeFileIoRequest(file, buffer, size, &done);
|
||||
uint32_t s = SysWriteFile(&req);
|
||||
if (s != STATUS_SUCCESS) fail_status(what, s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status(what, s);
|
||||
if (done != size) fail("short write");
|
||||
}
|
||||
|
||||
@@ -127,13 +127,13 @@ static void checked_read(uint32_t file, void* buffer, size_t size, size_t* gotOu
|
||||
memset(buffer, 0xCC, size);
|
||||
SYS_FILE_IO_REQUEST req = SysMakeFileIoRequest(file, buffer, size, &got);
|
||||
uint32_t s = SysReadFile(&req);
|
||||
if (s != STATUS_SUCCESS) fail_status(what, s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status(what, s);
|
||||
if (gotOut) *gotOut = got;
|
||||
}
|
||||
|
||||
static void checked_seek(uint32_t file, uint64_t offset, const char* what) {
|
||||
uint32_t s = SysSeekFile(file, offset);
|
||||
if (s != STATUS_SUCCESS) fail_status(what, s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status(what, s);
|
||||
}
|
||||
|
||||
static void expect_writeback_progress(const SYS_FILE_CACHE_STATS* before,
|
||||
@@ -158,7 +158,7 @@ int main(void) {
|
||||
uint32_t file = 0;
|
||||
const char* path = 0;
|
||||
uint32_t s = create_temp(&file, &path);
|
||||
if (s != STATUS_SUCCESS) fail_status("create temp", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("create temp", s);
|
||||
|
||||
print("dirty_writeback: using ");
|
||||
print(path ? path : "<unknown>");
|
||||
@@ -170,11 +170,11 @@ int main(void) {
|
||||
SYS_FILE_CACHE_STATS beforeClose;
|
||||
SYS_FILE_CACHE_STATS afterClose;
|
||||
|
||||
if (query_cache(&before) != STATUS_SUCCESS) fail("initial stats query failed");
|
||||
if (query_cache(&before) != NTLSTATUS_SUCCESS) fail("initial stats query failed");
|
||||
|
||||
checked_write(file, gPatternA, sizeof(gPatternA), "write pattern A");
|
||||
|
||||
if (query_cache(&afterWrite) != STATUS_SUCCESS) fail("post-write stats query failed");
|
||||
if (query_cache(&afterWrite) != NTLSTATUS_SUCCESS) fail("post-write stats query failed");
|
||||
if (afterWrite.DirtyMarks <= before.DirtyMarks) fail("write did not mark dirty cache pages");
|
||||
if (afterWrite.DirtyPages <= before.DirtyPages) fail("write did not leave dirty pages resident");
|
||||
|
||||
@@ -185,9 +185,9 @@ int main(void) {
|
||||
if (memcmp(gReadback, gPatternA, sizeof(gPatternA)) != 0) fail("cached read before flush mismatch");
|
||||
|
||||
s = SysFlushFile(file);
|
||||
if (s != STATUS_SUCCESS) fail_status("explicit flush", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("explicit flush", s);
|
||||
|
||||
if (query_cache(&afterFlush) != STATUS_SUCCESS) fail("post-flush stats query failed");
|
||||
if (query_cache(&afterFlush) != NTLSTATUS_SUCCESS) fail("post-flush stats query failed");
|
||||
if (afterFlush.FlushFileCalls <= afterWrite.FlushFileCalls) fail("flush call counter did not increase");
|
||||
expect_writeback_progress(&afterWrite, &afterFlush, "explicit flush");
|
||||
|
||||
@@ -196,19 +196,19 @@ int main(void) {
|
||||
checked_seek(file, REWRITE_SIZE, "seek close-tail");
|
||||
checked_write(file, gPatternA + REWRITE_SIZE, CLOSE_SIZE - REWRITE_SIZE, "write close tail");
|
||||
|
||||
if (query_cache(&beforeClose) != STATUS_SUCCESS) fail("pre-close stats query failed");
|
||||
if (query_cache(&beforeClose) != NTLSTATUS_SUCCESS) fail("pre-close stats query failed");
|
||||
if (beforeClose.DirtyMarks <= afterFlush.DirtyMarks) fail("rewrite did not mark dirty pages");
|
||||
|
||||
s = SysCloseHandle(file);
|
||||
file = 0;
|
||||
if (s != STATUS_SUCCESS) fail_status("close", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("close", s);
|
||||
|
||||
if (query_cache(&afterClose) != STATUS_SUCCESS) fail("post-close stats query failed");
|
||||
if (query_cache(&afterClose) != NTLSTATUS_SUCCESS) fail("post-close stats query failed");
|
||||
if (afterClose.FlushFileCalls <= beforeClose.FlushFileCalls) fail("close did not flush file");
|
||||
expect_writeback_progress(&beforeClose, &afterClose, "close flush");
|
||||
|
||||
s = open_path(path, &file);
|
||||
if (s != STATUS_SUCCESS) fail_status("reopen", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("reopen", s);
|
||||
|
||||
checked_read(file, gReadback, CLOSE_SIZE, &got, "read after reopen");
|
||||
if (got != CLOSE_SIZE) fail("read after reopen size mismatch");
|
||||
@@ -218,7 +218,7 @@ int main(void) {
|
||||
|
||||
s = SysCloseHandle(file);
|
||||
file = 0;
|
||||
if (s != STATUS_SUCCESS) fail_status("close reopened", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("close reopened", s);
|
||||
delete_path(path);
|
||||
|
||||
print("dirty_writeback: dirty-marks+=");
|
||||
|
||||
@@ -0,0 +1,197 @@
|
||||
// User-mode smoke test for native exception dispatcher registration.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <intrin.h>
|
||||
#include <ntlite/syscall.h>
|
||||
|
||||
// Prints one NUL-terminated string to the kernel console.
|
||||
static void print(const char* s) {
|
||||
SYS_WRITE_CONSOLE_REQUEST req = { SysSvFromCstr(s) };
|
||||
SysWriteConsole(&req);
|
||||
}
|
||||
|
||||
// Prints one unsigned integer.
|
||||
static void print_u64(uint64_t v) {
|
||||
char buf[32];
|
||||
int i = 0;
|
||||
if (v == 0) {
|
||||
print("0");
|
||||
return;
|
||||
}
|
||||
while (v && i < (int)sizeof(buf)) {
|
||||
buf[i++] = (char)('0' + (v % 10));
|
||||
v /= 10;
|
||||
}
|
||||
while (i--) {
|
||||
char c = buf[i];
|
||||
SYS_WRITE_CONSOLE_REQUEST req = { SysSvFromParts(&c, 1) };
|
||||
SysWriteConsole(&req);
|
||||
}
|
||||
}
|
||||
|
||||
// Terminates the current process.
|
||||
static void exit_now(int32_t code) {
|
||||
for (;;) SysExitProcess(code);
|
||||
}
|
||||
|
||||
// Fails the test with one message.
|
||||
static void fail(const char* message) {
|
||||
print("exception_dispatcher_smoke: ");
|
||||
print(message);
|
||||
print("\n");
|
||||
exit_now(1);
|
||||
}
|
||||
|
||||
// Fails the test with one status value.
|
||||
static void fail_status(const char* what, uint32_t status) {
|
||||
print("exception_dispatcher_smoke: ");
|
||||
print(what);
|
||||
print(" status=");
|
||||
print_u64(status);
|
||||
print("\n");
|
||||
exit_now(1);
|
||||
}
|
||||
|
||||
// Dummy dispatcher used only as a validated user-mode code pointer.
|
||||
static void smoke_dispatcher(SYS_EXCEPTION_FRAME* frame) {
|
||||
(void)frame;
|
||||
}
|
||||
|
||||
// Dispatcher hit count used by the delivery/continue stage.
|
||||
static volatile uint32_t gBreakpointDispatchCount;
|
||||
|
||||
// Continues from a breakpoint exception using the kernel-provided context.
|
||||
static void smoke_continue_dispatcher(SYS_EXCEPTION_FRAME* frame) {
|
||||
if (!frame)
|
||||
fail("dispatcher received null frame");
|
||||
if (frame->Size != sizeof(*frame) || frame->Version != SYS_EXCEPTION_ABI_VERSION)
|
||||
fail("dispatcher frame ABI mismatch");
|
||||
if (frame->ExceptionRecord.Code != SYS_EXCEPTION_CODE_BREAKPOINT)
|
||||
fail("dispatcher received unexpected exception code");
|
||||
if (frame->DispatcherContext != (void*)(uintptr_t)0xBEEF)
|
||||
fail("dispatcher context mismatch during delivery");
|
||||
|
||||
gBreakpointDispatchCount++;
|
||||
|
||||
SYS_CONTINUE_EXCEPTION_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.Disposition = SYS_EXCEPTION_DISPOSITION_CONTINUE_EXECUTION;
|
||||
request.Context = &frame->ContextRecord;
|
||||
|
||||
uint32_t status = SysContinueException(&request);
|
||||
fail_status("continue exception returned", status);
|
||||
}
|
||||
|
||||
// Requires one syscall to return the expected status.
|
||||
static void expect_status(const char* what, uint32_t got, uint32_t expected) {
|
||||
if (got != expected) {
|
||||
print("exception_dispatcher_smoke: ");
|
||||
print(what);
|
||||
print(" expected=");
|
||||
print_u64(expected);
|
||||
print(" got=");
|
||||
print_u64(got);
|
||||
print("\n");
|
||||
exit_now(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Reads the current dispatcher registration.
|
||||
static SYS_EXCEPTION_DISPATCHER_REQUEST get_registration(void) {
|
||||
SYS_EXCEPTION_DISPATCHER_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
uint32_t status = SysGetExceptionDispatcher(&request);
|
||||
if (status != NTLSTATUS_SUCCESS)
|
||||
fail_status("get dispatcher", status);
|
||||
if (request.Size != sizeof(request))
|
||||
fail("get dispatcher size mismatch");
|
||||
return request;
|
||||
}
|
||||
|
||||
// Runs the native dispatcher registration smoke test.
|
||||
int main(void) {
|
||||
print("exception_dispatcher_smoke: start\n");
|
||||
|
||||
expect_status("null get", SysGetExceptionDispatcher(0), NTLSTATUS_INVALID_PARAMETER);
|
||||
expect_status("null set", SysSetExceptionDispatcher(0), NTLSTATUS_INVALID_PARAMETER);
|
||||
|
||||
SYS_EXCEPTION_DISPATCHER_REQUEST initial = get_registration();
|
||||
SYS_EXCEPTION_DISPATCHER_REQUEST request;
|
||||
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request) - 1;
|
||||
request.DispatcherRoutine = smoke_dispatcher;
|
||||
expect_status("bad size", SysSetExceptionDispatcher(&request), NTLSTATUS_INVALID_PARAMETER);
|
||||
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.Flags = 1;
|
||||
request.DispatcherRoutine = smoke_dispatcher;
|
||||
expect_status("bad flags", SysSetExceptionDispatcher(&request), NTLSTATUS_INVALID_PARAMETER);
|
||||
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.DispatcherRoutine = (SYS_USER_EXCEPTION_DISPATCHER)(uintptr_t)0xFFFF800000000000ull;
|
||||
expect_status("kernel dispatcher", SysSetExceptionDispatcher(&request), NTLSTATUS_ACCESS_DENIED);
|
||||
|
||||
char tinyStack[32];
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.DispatcherRoutine = smoke_dispatcher;
|
||||
request.ExceptionStackBase = tinyStack;
|
||||
request.ExceptionStackSize = sizeof(tinyStack);
|
||||
expect_status("tiny exception stack", SysSetExceptionDispatcher(&request), NTLSTATUS_BUFFER_TOO_SMALL);
|
||||
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.DispatcherRoutine = smoke_dispatcher;
|
||||
request.DispatcherContext = (void*)(uintptr_t)0x1234;
|
||||
uint32_t status = SysSetExceptionDispatcher(&request);
|
||||
if (status != NTLSTATUS_SUCCESS)
|
||||
fail_status("set dispatcher", status);
|
||||
|
||||
SYS_EXCEPTION_DISPATCHER_REQUEST snapshot = get_registration();
|
||||
if (snapshot.DispatcherRoutine != smoke_dispatcher)
|
||||
fail("dispatcher routine mismatch");
|
||||
if (snapshot.DispatcherContext != (void*)(uintptr_t)0x1234)
|
||||
fail("dispatcher context mismatch");
|
||||
if (snapshot.ExceptionStackBase || snapshot.ExceptionStackSize)
|
||||
fail("unexpected exception stack registration");
|
||||
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.DispatcherRoutine = smoke_continue_dispatcher;
|
||||
request.DispatcherContext = (void*)(uintptr_t)0xBEEF;
|
||||
status = SysSetExceptionDispatcher(&request);
|
||||
if (status != NTLSTATUS_SUCCESS)
|
||||
fail_status("set continue dispatcher", status);
|
||||
|
||||
__debugbreak();
|
||||
if (gBreakpointDispatchCount != 1)
|
||||
fail("breakpoint was not delivered exactly once");
|
||||
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
status = SysSetExceptionDispatcher(&request);
|
||||
if (status != NTLSTATUS_SUCCESS)
|
||||
fail_status("clear dispatcher", status);
|
||||
|
||||
snapshot = get_registration();
|
||||
if (snapshot.DispatcherRoutine || snapshot.DispatcherContext ||
|
||||
snapshot.ExceptionStackBase || snapshot.ExceptionStackSize)
|
||||
fail("dispatcher did not clear");
|
||||
|
||||
if (initial.DispatcherRoutine) {
|
||||
status = SysSetExceptionDispatcher(&initial);
|
||||
if (status != NTLSTATUS_SUCCESS)
|
||||
fail_status("restore initial dispatcher", status);
|
||||
}
|
||||
|
||||
print("exception_dispatcher_smoke: PASS\n");
|
||||
exit_now(0);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,256 @@
|
||||
// Native exception pipeline integration smoke test.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <intrin.h>
|
||||
#include <ntlite/exception.h>
|
||||
#include <ntlite/syscall.h>
|
||||
|
||||
#define CHILD_DIVIDE_BY_ZERO "child-divide-by-zero"
|
||||
#define CHILD_ACCESS_VIOLATION "child-access-violation"
|
||||
#define CHILD_INVALID_RESUME "child-invalid-resume"
|
||||
#define CHILD_NONCONTINUABLE "child-noncontinuable"
|
||||
#define SMOKE_NONCONTINUABLE_CODE 0xE1111003u
|
||||
|
||||
// Prints one NUL-terminated string to the kernel console.
|
||||
static void print(const char* s) {
|
||||
SYS_WRITE_CONSOLE_REQUEST req = { SysSvFromCstr(s) };
|
||||
SysWriteConsole(&req);
|
||||
}
|
||||
|
||||
// Prints one unsigned integer.
|
||||
static void print_u64(uint64_t v) {
|
||||
char buf[32];
|
||||
int i = 0;
|
||||
if (v == 0) {
|
||||
print("0");
|
||||
return;
|
||||
}
|
||||
while (v && i < (int)sizeof(buf)) {
|
||||
buf[i++] = (char)('0' + (v % 10));
|
||||
v /= 10;
|
||||
}
|
||||
while (i--) {
|
||||
char c = buf[i];
|
||||
SYS_WRITE_CONSOLE_REQUEST req = { SysSvFromParts(&c, 1) };
|
||||
SysWriteConsole(&req);
|
||||
}
|
||||
}
|
||||
|
||||
// Terminates the current process.
|
||||
static void exit_now(int32_t code) {
|
||||
for (;;) SysExitProcess(code);
|
||||
}
|
||||
|
||||
// Fails the test with one message.
|
||||
static void fail(const char* message) {
|
||||
print("exception_smoke: ");
|
||||
print(message);
|
||||
print("\n");
|
||||
exit_now(1);
|
||||
}
|
||||
|
||||
// Fails the test with one status value.
|
||||
static void fail_status(const char* what, uint32_t status) {
|
||||
print("exception_smoke: ");
|
||||
print(what);
|
||||
print(" status=");
|
||||
print_u64(status);
|
||||
print("\n");
|
||||
exit_now(1);
|
||||
}
|
||||
|
||||
// Returns whether a string view exactly matches a literal string.
|
||||
static int sv_equals_cstr(SYS_STRING_VIEW sv, const char* literal) {
|
||||
size_t len = strlen(literal);
|
||||
return sv.Length == len && sv.Data && memcmp(sv.Data, literal, len) == 0;
|
||||
}
|
||||
|
||||
// Returns the current process command line.
|
||||
static SYS_STRING_VIEW current_command_line(void) {
|
||||
SYS_PEB* peb = SysGetPeb();
|
||||
if (!peb)
|
||||
return SysSvFromParts(NULL, 0);
|
||||
return peb->CommandLine;
|
||||
}
|
||||
|
||||
// Requires one syscall to return the expected status.
|
||||
static void expect_status(const char* what, uint32_t got, uint32_t expected) {
|
||||
if (got != expected) {
|
||||
print("exception_smoke: ");
|
||||
print(what);
|
||||
print(" expected=");
|
||||
print_u64(expected);
|
||||
print(" got=");
|
||||
print_u64(got);
|
||||
print("\n");
|
||||
exit_now(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Runs this image as a child and requires the expected exit code.
|
||||
static void run_child_expect_exit(const char* mode, uint32_t expectedExit) {
|
||||
SYS_PEB* peb = SysGetPeb();
|
||||
if (!peb || !peb->ImagePath.Data || peb->ImagePath.Length == 0)
|
||||
fail("missing image path");
|
||||
|
||||
uint32_t child = 0;
|
||||
SYS_CREATE_PROCESS_REQUEST request = {
|
||||
peb->ImagePath,
|
||||
SysSvFromCstr(mode),
|
||||
&child,
|
||||
};
|
||||
uint32_t status = SysCreateProcess(&request);
|
||||
if (status != NTLSTATUS_SUCCESS)
|
||||
fail_status("create child", status);
|
||||
|
||||
status = SysWait(child, SYS_WAIT_FLAG_NONE);
|
||||
if (status != NTLSTATUS_SUCCESS)
|
||||
fail_status("wait child", status);
|
||||
|
||||
int32_t exitCode = 0;
|
||||
status = SysGetProcessExitCode(child, &exitCode);
|
||||
if (status != NTLSTATUS_SUCCESS)
|
||||
fail_status("query child", status);
|
||||
SysCloseHandle(child);
|
||||
|
||||
if ((uint32_t)exitCode != expectedExit) {
|
||||
print("exception_smoke: child ");
|
||||
print(mode);
|
||||
print(" expected exit=");
|
||||
print_u64(expectedExit);
|
||||
print(" got=");
|
||||
print_u64((uint32_t)exitCode);
|
||||
print("\n");
|
||||
exit_now(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Triggers a divide-by-zero with no registered native handlers.
|
||||
static void child_divide_by_zero(void) {
|
||||
volatile int one = 1;
|
||||
volatile int zero = 0;
|
||||
volatile int sink = one / zero;
|
||||
(void)sink;
|
||||
exit_now(2);
|
||||
}
|
||||
|
||||
// Observes an access violation and exits from inside the native handler.
|
||||
static int access_violation_handler(SYS_EXCEPTION_RECORD* record,
|
||||
SYS_USER_CONTEXT* context,
|
||||
void* userContext) {
|
||||
(void)context;
|
||||
if (userContext != (void*)(uintptr_t)0xA11C)
|
||||
exit_now(10);
|
||||
if (!record || record->Code != SYS_EXCEPTION_CODE_ACCESS_VIOLATION)
|
||||
exit_now(11);
|
||||
if (record->FaultAddress != 0)
|
||||
exit_now(12);
|
||||
if (record->ParameterCount != 2 || record->Parameters[1] != 0)
|
||||
exit_now(13);
|
||||
exit_now(0);
|
||||
return NTL_EXCEPTION_TERMINATE_PROCESS;
|
||||
}
|
||||
|
||||
// Triggers a null read so the handler can inspect the fault address.
|
||||
static void child_access_violation(void) {
|
||||
void* handle = NtlAddExceptionHandler(1, access_violation_handler, (void*)(uintptr_t)0xA11C);
|
||||
if (!handle)
|
||||
exit_now(20);
|
||||
|
||||
volatile uint8_t* p = (volatile uint8_t*)0;
|
||||
volatile uint8_t value = *p;
|
||||
(void)value;
|
||||
exit_now(21);
|
||||
}
|
||||
|
||||
// Returns a resume context with an invalid user RIP.
|
||||
static int invalid_resume_handler(SYS_EXCEPTION_RECORD* record,
|
||||
SYS_USER_CONTEXT* context,
|
||||
void* userContext) {
|
||||
(void)userContext;
|
||||
if (!record || !context || record->Code != SYS_EXCEPTION_CODE_BREAKPOINT)
|
||||
exit_now(30);
|
||||
context->Rip = 0;
|
||||
return NTL_EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
|
||||
// Triggers a breakpoint whose handler asks the kernel to resume at RIP zero.
|
||||
static void child_invalid_resume(void) {
|
||||
void* handle = NtlAddExceptionHandler(1, invalid_resume_handler, NULL);
|
||||
if (!handle)
|
||||
exit_now(31);
|
||||
__debugbreak();
|
||||
exit_now(32);
|
||||
}
|
||||
|
||||
// Attempts to continue a noncontinuable user-raised exception.
|
||||
static int noncontinuable_handler(SYS_EXCEPTION_RECORD* record,
|
||||
SYS_USER_CONTEXT* context,
|
||||
void* userContext) {
|
||||
(void)context;
|
||||
(void)userContext;
|
||||
if (!record || record->Code != SMOKE_NONCONTINUABLE_CODE)
|
||||
exit_now(40);
|
||||
if ((record->Flags & SYS_EXCEPTION_FLAG_NONCONTINUABLE) == 0)
|
||||
exit_now(41);
|
||||
return NTL_EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
|
||||
// Raises a noncontinuable exception that a handler must not resume.
|
||||
static void child_noncontinuable(void) {
|
||||
void* handle = NtlAddExceptionHandler(1, noncontinuable_handler, NULL);
|
||||
if (!handle)
|
||||
exit_now(42);
|
||||
|
||||
SYS_RAISE_EXCEPTION_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.Flags = SYS_RAISE_EXCEPTION_FLAG_NONCONTINUABLE;
|
||||
request.Code = SMOKE_NONCONTINUABLE_CODE;
|
||||
|
||||
uint32_t status = SysRaiseException(&request);
|
||||
exit_now((int32_t)status);
|
||||
}
|
||||
|
||||
// Dispatches the child process mode selected by the command line.
|
||||
static void run_child_if_requested(void) {
|
||||
SYS_STRING_VIEW command = current_command_line();
|
||||
if (sv_equals_cstr(command, CHILD_DIVIDE_BY_ZERO))
|
||||
child_divide_by_zero();
|
||||
if (sv_equals_cstr(command, CHILD_ACCESS_VIOLATION))
|
||||
child_access_violation();
|
||||
if (sv_equals_cstr(command, CHILD_INVALID_RESUME))
|
||||
child_invalid_resume();
|
||||
if (sv_equals_cstr(command, CHILD_NONCONTINUABLE))
|
||||
child_noncontinuable();
|
||||
}
|
||||
|
||||
// Runs validation that does not intentionally fault this process.
|
||||
static void verify_continue_validation(void) {
|
||||
expect_status("null continue", SysContinueException(NULL), NTLSTATUS_INVALID_PARAMETER);
|
||||
|
||||
SYS_CONTINUE_EXCEPTION_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.Disposition = SYS_EXCEPTION_DISPOSITION_CONTINUE_EXECUTION;
|
||||
expect_status("inactive continue", SysContinueException(&request), NTLSTATUS_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
// Runs the native exception integration smoke test.
|
||||
int main(void) {
|
||||
run_child_if_requested();
|
||||
|
||||
print("exception_smoke: start\n");
|
||||
|
||||
verify_continue_validation();
|
||||
run_child_expect_exit(CHILD_DIVIDE_BY_ZERO, NTLSTATUS_PROCESS_DIVIDE_BY_ZERO);
|
||||
run_child_expect_exit(CHILD_ACCESS_VIOLATION, NTLSTATUS_SUCCESS);
|
||||
run_child_expect_exit(CHILD_INVALID_RESUME, NTLSTATUS_ACCESS_DENIED);
|
||||
run_child_expect_exit(CHILD_NONCONTINUABLE, NTLSTATUS_PROCESS_UNKNOWN_FAULT);
|
||||
|
||||
print("exception_smoke: PASS\n");
|
||||
exit_now(0);
|
||||
return 0;
|
||||
}
|
||||
@@ -75,7 +75,7 @@ static uint32_t open_existing_lockable(const char* path, uint32_t* fileOut) {
|
||||
SYS_FILE_FLAG_NONE,
|
||||
&h);
|
||||
uint32_t s = SysOpenFile(&req);
|
||||
if (s == STATUS_SUCCESS)
|
||||
if (s == NTLSTATUS_SUCCESS)
|
||||
*fileOut = h;
|
||||
return s;
|
||||
}
|
||||
@@ -98,13 +98,13 @@ static uint32_t create_temp_file(uint32_t* fileOut, const char** pathOut) {
|
||||
SYS_FILE_FLAG_NONE,
|
||||
&h);
|
||||
uint32_t s = SysOpenFile(&req);
|
||||
if (s == STATUS_SUCCESS) {
|
||||
if (s == NTLSTATUS_SUCCESS) {
|
||||
*fileOut = h;
|
||||
*pathOut = paths[i];
|
||||
return STATUS_SUCCESS;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
return STATUS_NOT_FOUND;
|
||||
return NTLSTATUS_NOT_FOUND;
|
||||
}
|
||||
|
||||
// Locks a range through the public request ABI.
|
||||
@@ -175,49 +175,49 @@ static void run_child(SYS_STRING_VIEW commandLine) {
|
||||
|
||||
uint32_t file = 0;
|
||||
uint32_t s = open_existing_lockable(path, &file);
|
||||
if (s != STATUS_SUCCESS)
|
||||
if (s != NTLSTATUS_SUCCESS)
|
||||
exit_now(3);
|
||||
|
||||
if (str_eq(mode, "excl-blocked")) {
|
||||
s = lock_range(file, SYS_FILE_LOCK_EXCLUSIVE, LOCK_OFFSET, LOCK_LENGTH, 0);
|
||||
SysCloseHandle(file);
|
||||
exit_now(s == STATUS_WOULD_BLOCK ? 0 : 4);
|
||||
exit_now(s == NTLSTATUS_WOULD_BLOCK ? 0 : 4);
|
||||
}
|
||||
|
||||
if (str_eq(mode, "excl-timeout")) {
|
||||
s = lock_range(file, SYS_FILE_LOCK_EXCLUSIVE, LOCK_OFFSET, LOCK_LENGTH, 20);
|
||||
SysCloseHandle(file);
|
||||
exit_now(s == STATUS_TIMEOUT ? 0 : 5);
|
||||
exit_now(s == NTLSTATUS_TIMEOUT ? 0 : 5);
|
||||
}
|
||||
|
||||
if (str_eq(mode, "excl-wait")) {
|
||||
s = lock_range(file, SYS_FILE_LOCK_EXCLUSIVE, LOCK_OFFSET, LOCK_LENGTH, SYS_WAIT_TIMEOUT_INFINITE);
|
||||
if (s == STATUS_SUCCESS)
|
||||
if (s == NTLSTATUS_SUCCESS)
|
||||
(void)unlock_range(file, LOCK_OFFSET, LOCK_LENGTH);
|
||||
SysCloseHandle(file);
|
||||
exit_now(s == STATUS_SUCCESS ? 0 : 6);
|
||||
exit_now(s == NTLSTATUS_SUCCESS ? 0 : 6);
|
||||
}
|
||||
|
||||
if (str_eq(mode, "shared-ok")) {
|
||||
s = lock_range(file, SYS_FILE_LOCK_SHARED, LOCK_OFFSET, LOCK_LENGTH, 0);
|
||||
if (s == STATUS_SUCCESS)
|
||||
if (s == NTLSTATUS_SUCCESS)
|
||||
(void)unlock_range(file, LOCK_OFFSET, LOCK_LENGTH);
|
||||
SysCloseHandle(file);
|
||||
exit_now(s == STATUS_SUCCESS ? 0 : 7);
|
||||
exit_now(s == NTLSTATUS_SUCCESS ? 0 : 7);
|
||||
}
|
||||
|
||||
if (str_eq(mode, "excl-nonoverlap")) {
|
||||
s = lock_range(file, SYS_FILE_LOCK_EXCLUSIVE, NONOVERLAP_OFFSET, LOCK_LENGTH, 0);
|
||||
if (s == STATUS_SUCCESS)
|
||||
if (s == NTLSTATUS_SUCCESS)
|
||||
(void)unlock_range(file, NONOVERLAP_OFFSET, LOCK_LENGTH);
|
||||
SysCloseHandle(file);
|
||||
exit_now(s == STATUS_SUCCESS ? 0 : 8);
|
||||
exit_now(s == NTLSTATUS_SUCCESS ? 0 : 8);
|
||||
}
|
||||
|
||||
if (str_eq(mode, "hold-exit")) {
|
||||
s = lock_range(file, SYS_FILE_LOCK_EXCLUSIVE, LOCK_OFFSET, LOCK_LENGTH, 0);
|
||||
SysCloseHandle(file);
|
||||
exit_now(s == STATUS_SUCCESS ? 0 : 9);
|
||||
exit_now(s == NTLSTATUS_SUCCESS ? 0 : 9);
|
||||
}
|
||||
|
||||
SysCloseHandle(file);
|
||||
@@ -251,14 +251,14 @@ static void run_child_expect_success(const char* mode, const char* path) {
|
||||
&child,
|
||||
};
|
||||
uint32_t s = SysCreateProcess(&req);
|
||||
if (s != STATUS_SUCCESS) fail_status("create child", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("create child", s);
|
||||
|
||||
s = SysWait(child, SYS_WAIT_FLAG_NONE);
|
||||
if (s != STATUS_SUCCESS) fail_status("wait child", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("wait child", s);
|
||||
|
||||
int32_t exitCode = 0;
|
||||
s = SysGetProcessExitCode(child, &exitCode);
|
||||
if (s != STATUS_SUCCESS) fail_status("query child", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("query child", s);
|
||||
SysCloseHandle(child);
|
||||
if (exitCode != 0) {
|
||||
print("file_lock_smoke: child ");
|
||||
@@ -282,12 +282,12 @@ static void test_validation(uint32_t file) {
|
||||
0,
|
||||
};
|
||||
uint32_t s = SysLockFile(&lockReq);
|
||||
if (s != STATUS_INVALID_PARAMETER) fail_status("bad lock size", s);
|
||||
if (s != NTLSTATUS_INVALID_PARAMETER) fail_status("bad lock size", s);
|
||||
|
||||
lockReq.Size = sizeof(lockReq);
|
||||
lockReq.Length = 0;
|
||||
s = SysLockFile(&lockReq);
|
||||
if (s != STATUS_INVALID_PARAMETER) fail_status("zero lock length", s);
|
||||
if (s != NTLSTATUS_INVALID_PARAMETER) fail_status("zero lock length", s);
|
||||
|
||||
SYS_UNLOCK_FILE_REQUEST unlockReq = {
|
||||
sizeof(unlockReq),
|
||||
@@ -297,12 +297,12 @@ static void test_validation(uint32_t file) {
|
||||
LOCK_LENGTH,
|
||||
};
|
||||
s = SysUnlockFile(&unlockReq);
|
||||
if (s != STATUS_NOT_FOUND) fail_status("unlock missing range", s);
|
||||
if (s != NTLSTATUS_NOT_FOUND) fail_status("unlock missing range", s);
|
||||
|
||||
lockReq.Length = LOCK_LENGTH;
|
||||
lockReq.FileHandle = 0xeeeeeeeeu;
|
||||
s = SysLockFile(&lockReq);
|
||||
if (s != STATUS_INVALID_HANDLE) fail_status("bad lock handle", s);
|
||||
if (s != NTLSTATUS_INVALID_HANDLE) fail_status("bad lock handle", s);
|
||||
}
|
||||
|
||||
// Program entry point.
|
||||
@@ -322,27 +322,27 @@ int main(void) {
|
||||
uint32_t file = 0;
|
||||
const char* path = 0;
|
||||
uint32_t s = create_temp_file(&file, &path);
|
||||
if (s != STATUS_SUCCESS) fail_status("create temp", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("create temp", s);
|
||||
|
||||
test_validation(file);
|
||||
|
||||
s = lock_range(file, SYS_FILE_LOCK_EXCLUSIVE, LOCK_OFFSET, LOCK_LENGTH, 0);
|
||||
if (s != STATUS_SUCCESS) fail_status("exclusive parent lock", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("exclusive parent lock", s);
|
||||
run_child_expect_success("excl-blocked", path);
|
||||
run_child_expect_success("excl-timeout", path);
|
||||
run_child_expect_success("excl-nonoverlap", path);
|
||||
s = unlock_range(file, LOCK_OFFSET, LOCK_LENGTH);
|
||||
if (s != STATUS_SUCCESS) fail_status("exclusive parent unlock", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("exclusive parent unlock", s);
|
||||
|
||||
s = lock_range(file, SYS_FILE_LOCK_SHARED, LOCK_OFFSET, LOCK_LENGTH, 0);
|
||||
if (s != STATUS_SUCCESS) fail_status("shared parent lock", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("shared parent lock", s);
|
||||
run_child_expect_success("shared-ok", path);
|
||||
run_child_expect_success("excl-blocked", path);
|
||||
s = unlock_range(file, LOCK_OFFSET, LOCK_LENGTH);
|
||||
if (s != STATUS_SUCCESS) fail_status("shared parent unlock", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("shared parent unlock", s);
|
||||
|
||||
s = lock_range(file, SYS_FILE_LOCK_EXCLUSIVE, LOCK_OFFSET, LOCK_LENGTH, 0);
|
||||
if (s != STATUS_SUCCESS) fail_status("blocking setup lock", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("blocking setup lock", s);
|
||||
SYS_PEB* selfPeb = SysGetPeb();
|
||||
if (!selfPeb || !selfPeb->ImagePath.Data || selfPeb->ImagePath.Length == 0) fail("missing self image");
|
||||
char command[CHILD_PREFIX_MAX + CHILD_PATH_MAX];
|
||||
@@ -350,23 +350,23 @@ int main(void) {
|
||||
uint32_t child = 0;
|
||||
SYS_CREATE_PROCESS_REQUEST createReq = { selfPeb->ImagePath, SysSvFromCstr(command), &child };
|
||||
s = SysCreateProcess(&createReq);
|
||||
if (s != STATUS_SUCCESS) fail_status("create blocking child", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("create blocking child", s);
|
||||
SysSleep(30);
|
||||
s = unlock_range(file, LOCK_OFFSET, LOCK_LENGTH);
|
||||
if (s != STATUS_SUCCESS) fail_status("wake unlock", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("wake unlock", s);
|
||||
s = SysWait(child, SYS_WAIT_FLAG_NONE);
|
||||
if (s != STATUS_SUCCESS) fail_status("wait blocking child", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("wait blocking child", s);
|
||||
int32_t exitCode = 0;
|
||||
s = SysGetProcessExitCode(child, &exitCode);
|
||||
if (s != STATUS_SUCCESS) fail_status("query blocking child", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("query blocking child", s);
|
||||
SysCloseHandle(child);
|
||||
if (exitCode != 0) fail("blocking child failed");
|
||||
|
||||
run_child_expect_success("hold-exit", path);
|
||||
s = lock_range(file, SYS_FILE_LOCK_EXCLUSIVE, LOCK_OFFSET, LOCK_LENGTH, 0);
|
||||
if (s != STATUS_SUCCESS) fail_status("exit released lock", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("exit released lock", s);
|
||||
s = unlock_range(file, LOCK_OFFSET, LOCK_LENGTH);
|
||||
if (s != STATUS_SUCCESS) fail_status("exit release cleanup unlock", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("exit release cleanup unlock", s);
|
||||
|
||||
SysCloseHandle(file);
|
||||
delete_path(path);
|
||||
|
||||
@@ -88,14 +88,14 @@ static uint32_t create_temp_file(uint32_t* fileOut, const char** pathOut) {
|
||||
SYS_FILE_FLAG_NONE,
|
||||
&h);
|
||||
uint32_t s = SysOpenFile(&req);
|
||||
if (s == STATUS_SUCCESS) {
|
||||
if (s == NTLSTATUS_SUCCESS) {
|
||||
*fileOut = h;
|
||||
*pathOut = paths[i];
|
||||
return STATUS_SUCCESS;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return STATUS_NOT_FOUND;
|
||||
return NTLSTATUS_NOT_FOUND;
|
||||
}
|
||||
|
||||
// Creates a temporary directory on the first writable path that works.
|
||||
@@ -111,13 +111,13 @@ static uint32_t create_temp_dir(const char** pathOut) {
|
||||
remove_dir_path(paths[i]);
|
||||
SYS_PATH_REQUEST req = { SysSvFromCstr(paths[i]) };
|
||||
uint32_t s = SysCreateDir(&req);
|
||||
if (s == STATUS_SUCCESS) {
|
||||
if (s == NTLSTATUS_SUCCESS) {
|
||||
*pathOut = paths[i];
|
||||
return STATUS_SUCCESS;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return STATUS_NOT_FOUND;
|
||||
return NTLSTATUS_NOT_FOUND;
|
||||
}
|
||||
|
||||
// Fills the write pattern used by the test file.
|
||||
@@ -131,11 +131,11 @@ static void write_test_file(uint32_t file) {
|
||||
size_t done = 0;
|
||||
SYS_FILE_IO_REQUEST writeReq = SysMakeFileIoRequest(file, gPattern, sizeof(gPattern), &done);
|
||||
uint32_t s = SysWriteFile(&writeReq);
|
||||
if (s != STATUS_SUCCESS) fail_status("write test file", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("write test file", s);
|
||||
if (done != sizeof(gPattern)) fail("short write");
|
||||
|
||||
s = SysFlushFile(file);
|
||||
if (s != STATUS_SUCCESS) fail_status("flush test file", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("flush test file", s);
|
||||
}
|
||||
|
||||
// Checks one regular-file metadata result.
|
||||
@@ -176,19 +176,19 @@ static void test_file_stat(uint32_t file, const char* path) {
|
||||
SYS_FILE_STAT byHandle;
|
||||
memset(&byHandle, 0xA5, sizeof(byHandle));
|
||||
uint32_t s = SysGetFileStat(file, &byHandle);
|
||||
if (s != STATUS_SUCCESS) fail_status("get file stat", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("get file stat", s);
|
||||
check_regular_stat(&byHandle, sizeof(gPattern), "handle stat");
|
||||
|
||||
uint64_t size = 0;
|
||||
s = SysGetFileSize(file, &size);
|
||||
if (s != STATUS_SUCCESS) fail_status("get file size", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("get file size", s);
|
||||
if (size != byHandle.FileSize) fail("file size and file stat disagree");
|
||||
|
||||
SYS_FILE_STAT byPath;
|
||||
memset(&byPath, 0x5A, sizeof(byPath));
|
||||
SYS_STAT_FILE_REQUEST statReq = { SysSvFromCstr(path), &byPath };
|
||||
s = SysStatFile(&statReq);
|
||||
if (s != STATUS_SUCCESS) fail_status("path stat", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("path stat", s);
|
||||
check_regular_stat(&byPath, sizeof(gPattern), "path stat");
|
||||
|
||||
if (byHandle.VolumeId != 0 && byPath.VolumeId != 0 && byHandle.VolumeId != byPath.VolumeId)
|
||||
@@ -203,7 +203,7 @@ static void test_directory_stat(const char* path) {
|
||||
memset(&stat, 0xCC, sizeof(stat));
|
||||
SYS_STAT_FILE_REQUEST statReq = { SysSvFromCstr(path), &stat };
|
||||
uint32_t s = SysStatFile(&statReq);
|
||||
if (s != STATUS_SUCCESS) fail_status("directory stat", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("directory stat", s);
|
||||
check_directory_stat(&stat);
|
||||
}
|
||||
|
||||
@@ -212,14 +212,14 @@ static void test_failure_paths(void) {
|
||||
SYS_FILE_STAT stat;
|
||||
SYS_STAT_FILE_REQUEST missingReq = { SysSvFromCstr("file_stat_smoke_missing.nope"), &stat };
|
||||
uint32_t s = SysStatFile(&missingReq);
|
||||
if (s != STATUS_NOT_FOUND) fail_status("missing path status", s);
|
||||
if (s != NTLSTATUS_NOT_FOUND) fail_status("missing path status", s);
|
||||
|
||||
s = SysGetFileStat(0xFFFFFFFFu, &stat);
|
||||
if (s != STATUS_INVALID_HANDLE) fail_status("invalid handle status", s);
|
||||
if (s != NTLSTATUS_INVALID_HANDLE) fail_status("invalid handle status", s);
|
||||
|
||||
SYS_STAT_FILE_REQUEST badReq = { SysSvFromCstr("file_stat_smoke_missing.nope"), 0 };
|
||||
s = SysStatFile(&badReq);
|
||||
if (s != STATUS_INVALID_PARAMETER) fail_status("null stat output status", s);
|
||||
if (s != NTLSTATUS_INVALID_PARAMETER) fail_status("null stat output status", s);
|
||||
}
|
||||
|
||||
// Runs the native file metadata smoke test.
|
||||
@@ -231,7 +231,7 @@ int main(void) {
|
||||
uint32_t file = 0;
|
||||
const char* filePath = 0;
|
||||
uint32_t s = create_temp_file(&file, &filePath);
|
||||
if (s != STATUS_SUCCESS) fail_status("create temp file", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("create temp file", s);
|
||||
|
||||
write_test_file(file);
|
||||
test_file_stat(file, filePath);
|
||||
@@ -240,13 +240,13 @@ int main(void) {
|
||||
|
||||
const char* dirPath = 0;
|
||||
s = create_temp_dir(&dirPath);
|
||||
if (s != STATUS_SUCCESS) fail_status("create temp dir", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("create temp dir", s);
|
||||
test_directory_stat(dirPath);
|
||||
remove_dir_path(dirPath);
|
||||
|
||||
SYS_PATH_REQUEST dirReq = { SysSvFromCstr(dirPath) };
|
||||
s = SysCreateDir(&dirReq);
|
||||
if (s != STATUS_SUCCESS) fail_status("recreate temp dir", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("recreate temp dir", s);
|
||||
test_directory_stat(dirPath);
|
||||
remove_dir_path(dirPath);
|
||||
|
||||
|
||||
@@ -127,61 +127,61 @@ int main(void) {
|
||||
uint32_t currentPid = SysGetCurrentPid();
|
||||
uint32_t process = 0;
|
||||
uint32_t s = SysOpenProcess(currentPid, &process);
|
||||
if (s != STATUS_SUCCESS) fail_status("open current process", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("open current process", s);
|
||||
|
||||
uint32_t queue = 0;
|
||||
s = SysCreateQueue(&queue);
|
||||
if (s != STATUS_SUCCESS) fail_status("create queue", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("create queue", s);
|
||||
|
||||
uint32_t readOnly = 0;
|
||||
s = duplicate_handle(queue, process, SYS_HANDLE_RIGHT_READ, SYS_DUPLICATE_HANDLE_FLAG_NONE, &readOnly);
|
||||
if (s != STATUS_SUCCESS) fail_status("duplicate read-only", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("duplicate read-only", s);
|
||||
|
||||
uint32_t writeOnly = 0;
|
||||
s = duplicate_handle(queue, process, SYS_HANDLE_RIGHT_WRITE, SYS_DUPLICATE_HANDLE_FLAG_NONE, &writeOnly);
|
||||
if (s != STATUS_SUCCESS) fail_status("duplicate write-only", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("duplicate write-only", s);
|
||||
|
||||
uint32_t sameRights = 0;
|
||||
s = duplicate_handle(queue, process, 0, SYS_DUPLICATE_HANDLE_FLAG_SAME_RIGHTS, &sameRights);
|
||||
if (s != STATUS_SUCCESS) fail_status("duplicate same rights", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("duplicate same rights", s);
|
||||
|
||||
s = send_message(readOnly, 10, 100);
|
||||
if (s == STATUS_SUCCESS) fail("read-only duplicate allowed send");
|
||||
if (s == NTLSTATUS_SUCCESS) fail("read-only duplicate allowed send");
|
||||
|
||||
TEST_QUEUE_MESSAGE msg;
|
||||
s = recv_message(writeOnly, &msg);
|
||||
if (s == STATUS_SUCCESS) fail("write-only duplicate allowed receive");
|
||||
if (s == NTLSTATUS_SUCCESS) fail("write-only duplicate allowed receive");
|
||||
|
||||
s = send_message(queue, 11, 101);
|
||||
if (s != STATUS_SUCCESS) fail_status("send original", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("send original", s);
|
||||
s = recv_message(readOnly, &msg);
|
||||
if (s != STATUS_SUCCESS) fail_status("receive read-only", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("receive read-only", s);
|
||||
check_message(&msg, 11, 101);
|
||||
|
||||
s = send_message(writeOnly, 12, 102);
|
||||
if (s != STATUS_SUCCESS) fail_status("send write-only", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("send write-only", s);
|
||||
s = recv_message(queue, &msg);
|
||||
if (s != STATUS_SUCCESS) fail_status("receive original", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("receive original", s);
|
||||
check_message(&msg, 12, 102);
|
||||
|
||||
s = send_message(sameRights, 13, 103);
|
||||
if (s != STATUS_SUCCESS) fail_status("send same-rights", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("send same-rights", s);
|
||||
s = recv_message(sameRights, &msg);
|
||||
if (s != STATUS_SUCCESS) fail_status("receive same-rights", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("receive same-rights", s);
|
||||
check_message(&msg, 13, 103);
|
||||
|
||||
uint32_t ignored = 0;
|
||||
s = duplicate_handle(readOnly, process, SYS_HANDLE_RIGHT_READ, SYS_DUPLICATE_HANDLE_FLAG_NONE, &ignored);
|
||||
expect_status("duplicate non-duplicable handle", s, STATUS_ACCESS_DENIED);
|
||||
expect_status("duplicate non-duplicable handle", s, NTLSTATUS_ACCESS_DENIED);
|
||||
|
||||
s = duplicate_handle(queue, process, SYS_HANDLE_RIGHT_READ | 0x80000000u, SYS_DUPLICATE_HANDLE_FLAG_NONE, &ignored);
|
||||
expect_status("duplicate unknown rights", s, STATUS_INVALID_PARAMETER);
|
||||
expect_status("duplicate unknown rights", s, NTLSTATUS_INVALID_PARAMETER);
|
||||
|
||||
s = duplicate_handle(queue, process, SYS_HANDLE_RIGHT_READ, SYS_DUPLICATE_HANDLE_FLAG_SAME_RIGHTS, &ignored);
|
||||
expect_status("duplicate same-rights with desired rights", s, STATUS_INVALID_PARAMETER);
|
||||
expect_status("duplicate same-rights with desired rights", s, NTLSTATUS_INVALID_PARAMETER);
|
||||
|
||||
s = duplicate_handle(queue, process, 0, SYS_DUPLICATE_HANDLE_FLAG_NONE, &ignored);
|
||||
expect_status("duplicate zero rights", s, STATUS_INVALID_PARAMETER);
|
||||
expect_status("duplicate zero rights", s, NTLSTATUS_INVALID_PARAMETER);
|
||||
|
||||
SYS_DUPLICATE_HANDLE_REQUEST badOut = {
|
||||
queue,
|
||||
@@ -191,7 +191,7 @@ int main(void) {
|
||||
0,
|
||||
};
|
||||
s = SysDuplicateHandle(&badOut);
|
||||
expect_status("duplicate null output", s, STATUS_INVALID_PARAMETER);
|
||||
expect_status("duplicate null output", s, NTLSTATUS_INVALID_PARAMETER);
|
||||
|
||||
SysCloseHandle(sameRights);
|
||||
SysCloseHandle(writeOnly);
|
||||
|
||||
@@ -62,21 +62,21 @@ static void expect_status(const char* what, uint32_t got, uint32_t expected) {
|
||||
int main(void) {
|
||||
print("input_api_smoke: start\n");
|
||||
|
||||
expect_status("poll keyboard null", SysPollKeyboard((INPUT_KEY*)0), STATUS_INVALID_PARAMETER);
|
||||
expect_status("is key down null", SysIsKeyDown(INPUT_KEY_A, (bool*)0), STATUS_INVALID_PARAMETER);
|
||||
expect_status("read key null", SysReadKey((INPUT_KEY*)0), STATUS_INVALID_PARAMETER);
|
||||
expect_status("read char null", SysReadKeyboardChar((char*)0), STATUS_INVALID_PARAMETER);
|
||||
expect_status("poll keyboard null", SysPollKeyboard((INPUT_KEY*)0), NTLSTATUS_INVALID_PARAMETER);
|
||||
expect_status("is key down null", SysIsKeyDown(INPUT_KEY_A, (bool*)0), NTLSTATUS_INVALID_PARAMETER);
|
||||
expect_status("read key null", SysReadKey((INPUT_KEY*)0), NTLSTATUS_INVALID_PARAMETER);
|
||||
expect_status("read char null", SysReadKeyboardChar((char*)0), NTLSTATUS_INVALID_PARAMETER);
|
||||
|
||||
bool down = true;
|
||||
uint32_t status = SysIsKeyDown(INPUT_KEY_A, &down);
|
||||
if (status != STATUS_SUCCESS)
|
||||
if (status != NTLSTATUS_SUCCESS)
|
||||
fail_status("is key down", status);
|
||||
|
||||
INPUT_KEY key = INPUT_KEY_A;
|
||||
status = SysPollKeyboard(&key);
|
||||
if (status != STATUS_SUCCESS && status != STATUS_WOULD_BLOCK)
|
||||
if (status != NTLSTATUS_SUCCESS && status != NTLSTATUS_WOULD_BLOCK)
|
||||
fail_status("poll keyboard", status);
|
||||
if (status == STATUS_WOULD_BLOCK && key != INPUT_KEY_NONE)
|
||||
if (status == NTLSTATUS_WOULD_BLOCK && key != INPUT_KEY_NONE)
|
||||
fail_status("poll keyboard would-block key", key);
|
||||
|
||||
INPUT_KEY_RECORD input;
|
||||
@@ -87,33 +87,33 @@ int main(void) {
|
||||
inputReq.TimeoutMilliseconds = 0;
|
||||
inputReq.RecordOut = &input;
|
||||
|
||||
expect_status("peek input null", SysPeekInputEvent((const SYS_INPUT_EVENT_REQUEST*)0), STATUS_INVALID_PARAMETER);
|
||||
expect_status("peek input null", SysPeekInputEvent((const SYS_INPUT_EVENT_REQUEST*)0), NTLSTATUS_INVALID_PARAMETER);
|
||||
status = SysPeekInputEvent(&inputReq);
|
||||
if (status != STATUS_SUCCESS && status != STATUS_WOULD_BLOCK)
|
||||
if (status != NTLSTATUS_SUCCESS && status != NTLSTATUS_WOULD_BLOCK)
|
||||
fail_status("peek input", status);
|
||||
|
||||
INPUT_MOUSE_EVENT mouse;
|
||||
expect_status("peek mouse null", SysPeekMouse((INPUT_MOUSE_EVENT*)0), STATUS_INVALID_PARAMETER);
|
||||
expect_status("read mouse null", SysReadMouse((INPUT_MOUSE_EVENT*)0), STATUS_INVALID_PARAMETER);
|
||||
expect_status("peek mouse null", SysPeekMouse((INPUT_MOUSE_EVENT*)0), NTLSTATUS_INVALID_PARAMETER);
|
||||
expect_status("read mouse null", SysReadMouse((INPUT_MOUSE_EVENT*)0), NTLSTATUS_INVALID_PARAMETER);
|
||||
|
||||
status = SysPeekMouse(&mouse);
|
||||
if (status != STATUS_SUCCESS && status != STATUS_WOULD_BLOCK)
|
||||
if (status != NTLSTATUS_SUCCESS && status != NTLSTATUS_WOULD_BLOCK)
|
||||
fail_status("peek mouse", status);
|
||||
|
||||
uint32_t readStatus = SysReadMouse(&mouse);
|
||||
if (status == STATUS_SUCCESS) {
|
||||
if (readStatus != STATUS_SUCCESS)
|
||||
if (status == NTLSTATUS_SUCCESS) {
|
||||
if (readStatus != NTLSTATUS_SUCCESS)
|
||||
fail_status("read mouse after peek", readStatus);
|
||||
} else if (readStatus != STATUS_WOULD_BLOCK) {
|
||||
} else if (readStatus != NTLSTATUS_WOULD_BLOCK) {
|
||||
fail_status("read mouse would-block", readStatus);
|
||||
}
|
||||
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
expect_status("get mouse pos null x", SysGetMousePos((int*)0, &y), STATUS_INVALID_PARAMETER);
|
||||
expect_status("get mouse pos null y", SysGetMousePos(&x, (int*)0), STATUS_INVALID_PARAMETER);
|
||||
expect_status("get mouse pos null x", SysGetMousePos((int*)0, &y), NTLSTATUS_INVALID_PARAMETER);
|
||||
expect_status("get mouse pos null y", SysGetMousePos(&x, (int*)0), NTLSTATUS_INVALID_PARAMETER);
|
||||
status = SysGetMousePos(&x, &y);
|
||||
if (status != STATUS_SUCCESS)
|
||||
if (status != NTLSTATUS_SUCCESS)
|
||||
fail_status("get mouse pos", status);
|
||||
|
||||
print("input_api_smoke: PASS\n");
|
||||
|
||||
@@ -62,11 +62,11 @@ int main(void) {
|
||||
print("input_model_smoke: start\n");
|
||||
|
||||
uint32_t inputQueue = 0;
|
||||
expect_status("open input queue null", SysOpenInputQueue(SYS_INPUT_QUEUE_FLAG_NONE, (uint32_t*)0), STATUS_INVALID_PARAMETER);
|
||||
expect_status("open input queue bad flags", SysOpenInputQueue(1, &inputQueue), STATUS_INVALID_PARAMETER);
|
||||
expect_status("open input queue null", SysOpenInputQueue(SYS_INPUT_QUEUE_FLAG_NONE, (uint32_t*)0), NTLSTATUS_INVALID_PARAMETER);
|
||||
expect_status("open input queue bad flags", SysOpenInputQueue(1, &inputQueue), NTLSTATUS_INVALID_PARAMETER);
|
||||
|
||||
uint32_t status = SysOpenInputQueue(SYS_INPUT_QUEUE_FLAG_NONE, &inputQueue);
|
||||
if (status != STATUS_SUCCESS)
|
||||
if (status != NTLSTATUS_SUCCESS)
|
||||
fail_status("open input queue", status);
|
||||
|
||||
INPUT_KEY_RECORD record;
|
||||
@@ -79,31 +79,31 @@ int main(void) {
|
||||
|
||||
SYS_INPUT_EVENT_REQUEST badReq = req;
|
||||
badReq.Size = 0;
|
||||
expect_status("read input bad size", SysReadInputEvent(&badReq), STATUS_INVALID_PARAMETER);
|
||||
expect_status("read input bad size", SysReadInputEvent(&badReq), NTLSTATUS_INVALID_PARAMETER);
|
||||
|
||||
badReq = req;
|
||||
badReq.RecordOut = (INPUT_KEY_RECORD*)0;
|
||||
expect_status("peek input null out", SysPeekInputEvent(&badReq), STATUS_INVALID_PARAMETER);
|
||||
expect_status("peek input null out", SysPeekInputEvent(&badReq), NTLSTATUS_INVALID_PARAMETER);
|
||||
|
||||
badReq = req;
|
||||
badReq.QueueHandle = 0xdeadbeefu;
|
||||
expect_status("read input bad handle", SysReadInputEvent(&badReq), STATUS_INVALID_HANDLE);
|
||||
expect_status("read input bad handle", SysReadInputEvent(&badReq), NTLSTATUS_INVALID_HANDLE);
|
||||
|
||||
status = SysPeekInputEvent(&req);
|
||||
if (status != STATUS_SUCCESS && status != STATUS_WOULD_BLOCK)
|
||||
if (status != NTLSTATUS_SUCCESS && status != NTLSTATUS_WOULD_BLOCK)
|
||||
fail_status("peek input immediate", status);
|
||||
|
||||
uint32_t waitStatus = SysWaitSingle(inputQueue, SYS_WAIT_FLAG_NONE, 0);
|
||||
if (status == STATUS_SUCCESS) {
|
||||
if (waitStatus != STATUS_SUCCESS)
|
||||
if (status == NTLSTATUS_SUCCESS) {
|
||||
if (waitStatus != NTLSTATUS_SUCCESS)
|
||||
fail_status("wait input after readable peek", waitStatus);
|
||||
} else if (waitStatus != STATUS_TIMEOUT) {
|
||||
} else if (waitStatus != NTLSTATUS_TIMEOUT) {
|
||||
fail_status("wait empty input immediate", waitStatus);
|
||||
}
|
||||
|
||||
req.TimeoutMilliseconds = 1;
|
||||
status = SysReadInputEvent(&req);
|
||||
if (status != STATUS_SUCCESS && status != STATUS_TIMEOUT)
|
||||
if (status != NTLSTATUS_SUCCESS && status != NTLSTATUS_TIMEOUT)
|
||||
fail_status("read input finite timeout", status);
|
||||
|
||||
SysCloseHandle(inputQueue);
|
||||
|
||||
@@ -76,15 +76,15 @@ static uint32_t open_first_existing(uint32_t* fileOut, const char** pathOut) {
|
||||
SYS_FILE_FLAG_NONE,
|
||||
&file);
|
||||
uint32_t s = SysOpenFile(&openReq);
|
||||
if (s == STATUS_SUCCESS) {
|
||||
if (s == NTLSTATUS_SUCCESS) {
|
||||
*fileOut = file;
|
||||
if (pathOut)
|
||||
*pathOut = candidates[i];
|
||||
return STATUS_SUCCESS;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return STATUS_NOT_FOUND;
|
||||
return NTLSTATUS_NOT_FOUND;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
@@ -93,7 +93,7 @@ int main(void) {
|
||||
uint32_t file = 0;
|
||||
const char* openedPath = 0;
|
||||
uint32_t s = open_first_existing(&file, &openedPath);
|
||||
if (s != STATUS_SUCCESS)
|
||||
if (s != NTLSTATUS_SUCCESS)
|
||||
fail_status("open test file", s);
|
||||
|
||||
print("mmap_smoke: using ");
|
||||
@@ -105,7 +105,7 @@ int main(void) {
|
||||
|
||||
SYS_FILE_IO_REQUEST ioReq = SysMakeFileIoRequest(file, gExpected, sizeof(gExpected), &got);
|
||||
s = SysReadFile(&ioReq);
|
||||
if (s != STATUS_SUCCESS)
|
||||
if (s != NTLSTATUS_SUCCESS)
|
||||
fail_status("read baseline", s);
|
||||
if (got < 64)
|
||||
fail_msg("baseline read was unexpectedly short");
|
||||
@@ -118,7 +118,7 @@ int main(void) {
|
||||
SYS_MAP_FLAG_NONE,
|
||||
sizeof(gExpected),
|
||||
&mapping);
|
||||
if (s != STATUS_SUCCESS)
|
||||
if (s != NTLSTATUS_SUCCESS)
|
||||
fail_status("create file mapping", s);
|
||||
|
||||
print("mmap_smoke: mapping created\n");
|
||||
@@ -141,7 +141,7 @@ int main(void) {
|
||||
SysCloseHandle(mapping);
|
||||
mapping = 0;
|
||||
|
||||
if (s != STATUS_SUCCESS)
|
||||
if (s != NTLSTATUS_SUCCESS)
|
||||
fail_status("map file view", s);
|
||||
if (!base)
|
||||
fail_msg("map returned null base");
|
||||
@@ -191,7 +191,7 @@ int main(void) {
|
||||
print("mmap_smoke: EOF fill OK\n");
|
||||
|
||||
s = SysFreeVm(base);
|
||||
if (s != STATUS_SUCCESS)
|
||||
if (s != NTLSTATUS_SUCCESS)
|
||||
fail_status("unmap", s);
|
||||
|
||||
print("mmap_smoke: PASS\n");
|
||||
|
||||
@@ -68,14 +68,14 @@ static void check_module_info(const SYS_MODULE_INFO* info) {
|
||||
static int module_list_contains(uintptr_t base) {
|
||||
size_t count = 0;
|
||||
uint32_t status = SysGetModuleList(0, 0, &count);
|
||||
if (status != STATUS_SUCCESS) fail_status("query module count", status);
|
||||
if (status != NTLSTATUS_SUCCESS) fail_status("query module count", status);
|
||||
if (count == 0) return 0;
|
||||
if (count > 32) fail("module count unexpectedly large");
|
||||
|
||||
SYS_MODULE_INFO modules[32];
|
||||
memset(modules, 0, sizeof(modules));
|
||||
status = SysGetModuleList(modules, count, &count);
|
||||
if (status != STATUS_SUCCESS) fail_status("query module list", status);
|
||||
if (status != NTLSTATUS_SUCCESS) fail_status("query module list", status);
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
if (modules[i].Base == base)
|
||||
@@ -95,7 +95,7 @@ static void check_export_lookup(void) {
|
||||
req.ModuleHandleOut = &handle;
|
||||
|
||||
uint32_t status = SysLoadModule(&req);
|
||||
if (status != STATUS_SUCCESS) fail_status("load syscall.dll", status);
|
||||
if (status != NTLSTATUS_SUCCESS) fail_status("load syscall.dll", status);
|
||||
if (handle == 0) fail("syscall load returned null handle");
|
||||
|
||||
uintptr_t address = 0;
|
||||
@@ -107,11 +107,11 @@ static void check_export_lookup(void) {
|
||||
exportReq.AddressOut = &address;
|
||||
|
||||
status = SysGetModuleExport(&exportReq);
|
||||
if (status != STATUS_SUCCESS) fail_status("lookup SysGetCurrentPid", status);
|
||||
if (status != NTLSTATUS_SUCCESS) fail_status("lookup SysGetCurrentPid", status);
|
||||
if (address == 0) fail("export address is zero");
|
||||
|
||||
status = SysUnloadModule(handle);
|
||||
if (status != STATUS_SUCCESS) fail_status("unload syscall.dll handle", status);
|
||||
if (status != NTLSTATUS_SUCCESS) fail_status("unload syscall.dll handle", status);
|
||||
}
|
||||
|
||||
// Runs the public dynamic module loader smoke test.
|
||||
@@ -131,7 +131,7 @@ int main(void) {
|
||||
req.InfoOut = &info;
|
||||
|
||||
uint32_t status = SysLoadModule(&req);
|
||||
if (status != STATUS_SUCCESS) fail_status("load posix.dll", status);
|
||||
if (status != NTLSTATUS_SUCCESS) fail_status("load posix.dll", status);
|
||||
if (handle == 0) fail("load returned null handle");
|
||||
check_module_info(&info);
|
||||
if (!module_list_contains(info.Base)) fail("loaded module absent from list");
|
||||
@@ -139,16 +139,16 @@ int main(void) {
|
||||
SYS_MODULE_INFO byHandle;
|
||||
memset(&byHandle, 0, sizeof(byHandle));
|
||||
status = SysGetModuleInfo(handle, &byHandle);
|
||||
if (status != STATUS_SUCCESS) fail_status("get module info", status);
|
||||
if (status != NTLSTATUS_SUCCESS) fail_status("get module info", status);
|
||||
check_module_info(&byHandle);
|
||||
if (byHandle.Base != info.Base) fail("module handle base mismatch");
|
||||
|
||||
status = SysUnloadModule(handle);
|
||||
if (status != STATUS_SUCCESS) fail_status("unload module", status);
|
||||
if (status != NTLSTATUS_SUCCESS) fail_status("unload module", status);
|
||||
|
||||
memset(&byHandle, 0, sizeof(byHandle));
|
||||
status = SysGetModuleInfo(handle, &byHandle);
|
||||
if (status != STATUS_INVALID_HANDLE) fail_status("query unloaded handle", status);
|
||||
if (status != NTLSTATUS_INVALID_HANDLE) fail_status("query unloaded handle", status);
|
||||
|
||||
print("module_load_smoke: PASS\n");
|
||||
exit_now(0);
|
||||
|
||||
@@ -0,0 +1,194 @@
|
||||
// Native named queue lifetime smoke test.
|
||||
// Verifies explicit name withdrawal and automatic withdrawal on owner handle close.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <ntlite/syscall.h>
|
||||
|
||||
#define TEST_MESSAGE_TYPE 0x71756575u
|
||||
#define TEST_MESSAGE_VALUE 0x123456789abcdef0ull
|
||||
|
||||
typedef struct TEST_QUEUE_MESSAGE {
|
||||
uint32_t Type;
|
||||
uint32_t Flags;
|
||||
uint64_t Param[6];
|
||||
} TEST_QUEUE_MESSAGE;
|
||||
|
||||
typedef char TEST_QUEUE_MESSAGE_SIZE_CHECK[
|
||||
(sizeof(TEST_QUEUE_MESSAGE) == SYS_QUEUE_MESSAGE_SIZE) ? 1 : -1
|
||||
];
|
||||
|
||||
// Prints one NUL-terminated string to the kernel console.
|
||||
static void print(const char* s) {
|
||||
SYS_WRITE_CONSOLE_REQUEST req = { SysSvFromCstr(s) };
|
||||
SysWriteConsole(&req);
|
||||
}
|
||||
|
||||
// Prints one unsigned integer to the kernel console.
|
||||
static void print_u64(uint64_t v) {
|
||||
char buf[32];
|
||||
int i = 0;
|
||||
if (v == 0) {
|
||||
print("0");
|
||||
return;
|
||||
}
|
||||
while (v && i < (int)sizeof(buf)) {
|
||||
buf[i++] = (char)('0' + (v % 10));
|
||||
v /= 10;
|
||||
}
|
||||
while (i--) {
|
||||
char c = buf[i];
|
||||
SYS_WRITE_CONSOLE_REQUEST req = { SysSvFromParts(&c, 1) };
|
||||
SysWriteConsole(&req);
|
||||
}
|
||||
}
|
||||
|
||||
// Terminates the current test process.
|
||||
static void exit_now(int code) {
|
||||
for (;;) SysExitProcess(code);
|
||||
}
|
||||
|
||||
// Fails the test with one plain message.
|
||||
static void fail(const char* msg) {
|
||||
print("named_queue_lifetime_smoke: ");
|
||||
print(msg);
|
||||
print("\n");
|
||||
exit_now(1);
|
||||
}
|
||||
|
||||
// Fails the test with one status value.
|
||||
static void fail_status(const char* what, uint32_t status) {
|
||||
print("named_queue_lifetime_smoke: ");
|
||||
print(what);
|
||||
print(" status=");
|
||||
print_u64(status);
|
||||
print("\n");
|
||||
exit_now(1);
|
||||
}
|
||||
|
||||
// Requires one exact status value.
|
||||
static void expect_status(const char* what, uint32_t got, uint32_t expected) {
|
||||
if (got == expected) return;
|
||||
print("named_queue_lifetime_smoke: ");
|
||||
print(what);
|
||||
print(" got=");
|
||||
print_u64(got);
|
||||
print(" expected=");
|
||||
print_u64(expected);
|
||||
print("\n");
|
||||
exit_now(1);
|
||||
}
|
||||
|
||||
// Publishes one queue under a short test name.
|
||||
static uint32_t publish_queue(const char* name, uint32_t queue) {
|
||||
SYS_PUBLISH_QUEUE_REQUEST req;
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.Name = SysSvFromCstr(name);
|
||||
req.QueueHandle = queue;
|
||||
return SysPublishQueue(&req);
|
||||
}
|
||||
|
||||
// Withdraws one named queue publication.
|
||||
static uint32_t unpublish_queue(const char* name) {
|
||||
SYS_UNPUBLISH_QUEUE_REQUEST req;
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.Name = SysSvFromCstr(name);
|
||||
return SysUnpublishQueue(&req);
|
||||
}
|
||||
|
||||
// Opens one named queue publication.
|
||||
static uint32_t open_named_queue(const char* name, uint32_t* out) {
|
||||
SYS_OPEN_NAMED_QUEUE_REQUEST req;
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.Name = SysSvFromCstr(name);
|
||||
req.HandleOut = out;
|
||||
return SysOpenNamedQueue(&req);
|
||||
}
|
||||
|
||||
// Sends one fixed-size queue message.
|
||||
static uint32_t send_message(uint32_t queue, const TEST_QUEUE_MESSAGE* message) {
|
||||
SYS_QUEUE_SEND_REQUEST req;
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.Size = sizeof(req);
|
||||
req.QueueHandle = queue;
|
||||
req.Flags = SYS_QUEUE_FLAG_NONE;
|
||||
req.TimeoutMilliseconds = 0;
|
||||
req.Message = message;
|
||||
return SysSendQueue(&req);
|
||||
}
|
||||
|
||||
// Receives one fixed-size queue message.
|
||||
static uint32_t recv_message(uint32_t queue, TEST_QUEUE_MESSAGE* message) {
|
||||
SYS_QUEUE_RECV_REQUEST req;
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.Size = sizeof(req);
|
||||
req.QueueHandle = queue;
|
||||
req.Flags = SYS_QUEUE_FLAG_NONE;
|
||||
req.TimeoutMilliseconds = 0;
|
||||
req.MessageOut = message;
|
||||
return SysRecvQueue(&req);
|
||||
}
|
||||
|
||||
// Verifies explicit unpublish removes only the name, not existing handles.
|
||||
static void check_explicit_unpublish(void) {
|
||||
uint32_t queue = 0;
|
||||
uint32_t opened = 0;
|
||||
uint32_t status = SysCreateQueue(&queue);
|
||||
if (status != NTLSTATUS_SUCCESS) fail_status("create queue", status);
|
||||
|
||||
status = publish_queue("ntl.queue.explicit", queue);
|
||||
if (status != NTLSTATUS_SUCCESS) fail_status("publish queue", status);
|
||||
|
||||
status = open_named_queue("ntl.queue.explicit", &opened);
|
||||
if (status != NTLSTATUS_SUCCESS) fail_status("open published queue", status);
|
||||
if (!opened) fail("opened handle is zero");
|
||||
|
||||
status = unpublish_queue("ntl.queue.explicit");
|
||||
if (status != NTLSTATUS_SUCCESS) fail_status("unpublish queue", status);
|
||||
|
||||
uint32_t missing = 0;
|
||||
status = open_named_queue("ntl.queue.explicit", &missing);
|
||||
expect_status("open withdrawn name", status, NTLSTATUS_NOT_FOUND);
|
||||
|
||||
TEST_QUEUE_MESSAGE out;
|
||||
TEST_QUEUE_MESSAGE in;
|
||||
memset(&out, 0, sizeof(out));
|
||||
memset(&in, 0, sizeof(in));
|
||||
out.Type = TEST_MESSAGE_TYPE;
|
||||
out.Param[0] = TEST_MESSAGE_VALUE;
|
||||
status = send_message(queue, &out);
|
||||
if (status != NTLSTATUS_SUCCESS) fail_status("send after unpublish", status);
|
||||
status = recv_message(opened, &in);
|
||||
if (status != NTLSTATUS_SUCCESS) fail_status("recv after unpublish", status);
|
||||
if (in.Type != TEST_MESSAGE_TYPE || in.Param[0] != TEST_MESSAGE_VALUE)
|
||||
fail("message mismatch after unpublish");
|
||||
|
||||
SysCloseHandle(opened);
|
||||
SysCloseHandle(queue);
|
||||
}
|
||||
|
||||
// Verifies closing the publishing handle withdraws its names.
|
||||
static void check_close_withdraws_name(void) {
|
||||
uint32_t queue = 0;
|
||||
uint32_t status = SysCreateQueue(&queue);
|
||||
if (status != NTLSTATUS_SUCCESS) fail_status("create close queue", status);
|
||||
|
||||
status = publish_queue("ntl.queue.close", queue);
|
||||
if (status != NTLSTATUS_SUCCESS) fail_status("publish close queue", status);
|
||||
|
||||
SysCloseHandle(queue);
|
||||
|
||||
uint32_t opened = 0;
|
||||
status = open_named_queue("ntl.queue.close", &opened);
|
||||
expect_status("open close-withdrawn name", status, NTLSTATUS_NOT_FOUND);
|
||||
}
|
||||
|
||||
// Runs the named queue lifetime smoke test.
|
||||
int main(void) {
|
||||
print("named_queue_lifetime_smoke: start\n");
|
||||
check_explicit_unpublish();
|
||||
check_close_withdraws_name();
|
||||
print("named_queue_lifetime_smoke: PASS\n");
|
||||
exit_now(0);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
// Native exception runtime smoke test. This file verifies process-start registration and handler dispatch.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <ntlite/exception.h>
|
||||
#include <ntlite/syscall.h>
|
||||
|
||||
static volatile uint32_t gSearchHits;
|
||||
static volatile uint32_t gContinueHits;
|
||||
|
||||
// Prints one NUL-terminated string to the kernel console.
|
||||
static void print(const char* s) {
|
||||
SYS_WRITE_CONSOLE_REQUEST req = { SysSvFromCstr(s) };
|
||||
SysWriteConsole(&req);
|
||||
}
|
||||
|
||||
// Prints one unsigned integer.
|
||||
static void print_u64(uint64_t v) {
|
||||
char buf[32];
|
||||
int i = 0;
|
||||
if (v == 0) {
|
||||
print("0");
|
||||
return;
|
||||
}
|
||||
while (v && i < (int)sizeof(buf)) {
|
||||
buf[i++] = (char)('0' + (v % 10));
|
||||
v /= 10;
|
||||
}
|
||||
while (i--) {
|
||||
char c = buf[i];
|
||||
SYS_WRITE_CONSOLE_REQUEST req = { SysSvFromParts(&c, 1) };
|
||||
SysWriteConsole(&req);
|
||||
}
|
||||
}
|
||||
|
||||
// Terminates the current process.
|
||||
static void exit_now(int32_t code) {
|
||||
for (;;) SysExitProcess(code);
|
||||
}
|
||||
|
||||
// Fails the test with one message.
|
||||
static void fail(const char* message) {
|
||||
print("native_exception_runtime_smoke: ");
|
||||
print(message);
|
||||
print("\n");
|
||||
exit_now(1);
|
||||
}
|
||||
|
||||
// Fails the test with one status value.
|
||||
static void fail_status(const char* what, uint32_t status) {
|
||||
print("native_exception_runtime_smoke: ");
|
||||
print(what);
|
||||
print(" status=");
|
||||
print_u64(status);
|
||||
print("\n");
|
||||
exit_now(1);
|
||||
}
|
||||
|
||||
// Requires one syscall to return the expected status.
|
||||
static void expect_status(const char* what, uint32_t got, uint32_t expected) {
|
||||
if (got != expected) {
|
||||
print("native_exception_runtime_smoke: ");
|
||||
print(what);
|
||||
print(" expected=");
|
||||
print_u64(expected);
|
||||
print(" got=");
|
||||
print_u64(got);
|
||||
print("\n");
|
||||
exit_now(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Verifies the native runtime installed the process dispatcher during startup.
|
||||
static void verify_startup_registration(void) {
|
||||
SYS_EXCEPTION_DISPATCHER_REQUEST request;
|
||||
for (size_t i = 0; i < sizeof(request); i++)
|
||||
((char*)&request)[i] = 0;
|
||||
request.Size = sizeof(request);
|
||||
|
||||
uint32_t status = SysGetExceptionDispatcher(&request);
|
||||
if (status != NTLSTATUS_SUCCESS)
|
||||
fail_status("get dispatcher", status);
|
||||
if (!request.DispatcherRoutine)
|
||||
fail("runtime dispatcher was not registered");
|
||||
}
|
||||
|
||||
// Verifies one breakpoint exception record has the expected native shape.
|
||||
static void verify_breakpoint_record(SYS_EXCEPTION_RECORD* record, SYS_USER_CONTEXT* context) {
|
||||
if (!record || !context)
|
||||
fail("handler received null state");
|
||||
if (record->Size != sizeof(*record) || record->Version != SYS_EXCEPTION_ABI_VERSION)
|
||||
fail("record ABI mismatch");
|
||||
if (context->Size != sizeof(*context) || context->Version != SYS_EXCEPTION_ABI_VERSION)
|
||||
fail("context ABI mismatch");
|
||||
if (record->Code != SYS_EXCEPTION_CODE_BREAKPOINT)
|
||||
fail("unexpected exception code");
|
||||
}
|
||||
|
||||
// Records a first-chance exception and asks the dispatcher to continue searching.
|
||||
static int search_handler(SYS_EXCEPTION_RECORD* record, SYS_USER_CONTEXT* context, void* userContext) {
|
||||
if (userContext != (void*)(uintptr_t)0x1111)
|
||||
fail("search handler context mismatch");
|
||||
verify_breakpoint_record(record, context);
|
||||
gSearchHits++;
|
||||
return NTL_EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
// Records a first-chance exception and asks the kernel to resume the saved context.
|
||||
static int continue_handler(SYS_EXCEPTION_RECORD* record, SYS_USER_CONTEXT* context, void* userContext) {
|
||||
if (userContext != (void*)(uintptr_t)0x2222)
|
||||
fail("continue handler context mismatch");
|
||||
verify_breakpoint_record(record, context);
|
||||
gContinueHits++;
|
||||
return NTL_EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
|
||||
// Verifies the process-local handler list can dispatch and remove handlers.
|
||||
static void verify_handler_dispatch(void) {
|
||||
expect_status("remove null", NtlRemoveExceptionHandler(0), NTLSTATUS_INVALID_PARAMETER);
|
||||
if (NtlAddExceptionHandler(0, 0, 0))
|
||||
fail("null handler was accepted");
|
||||
|
||||
void* search = NtlAddExceptionHandler(0, search_handler, (void*)(uintptr_t)0x1111);
|
||||
void* cont = NtlAddExceptionHandler(0, continue_handler, (void*)(uintptr_t)0x2222);
|
||||
if (!search || !cont)
|
||||
fail("handler registration failed");
|
||||
|
||||
__debugbreak();
|
||||
if (gSearchHits != 1 || gContinueHits != 1)
|
||||
fail("breakpoint did not visit both handlers");
|
||||
|
||||
expect_status("remove search", NtlRemoveExceptionHandler(search), NTLSTATUS_SUCCESS);
|
||||
__debugbreak();
|
||||
if (gSearchHits != 1 || gContinueHits != 2)
|
||||
fail("removed handler still participated");
|
||||
|
||||
expect_status("remove continue", NtlRemoveExceptionHandler(cont), NTLSTATUS_SUCCESS);
|
||||
expect_status("remove continue twice", NtlRemoveExceptionHandler(cont), NTLSTATUS_NOT_FOUND);
|
||||
}
|
||||
|
||||
// Runs the native exception runtime smoke test.
|
||||
int main(void) {
|
||||
print("native_exception_runtime_smoke: start\n");
|
||||
|
||||
verify_startup_registration();
|
||||
verify_handler_dispatch();
|
||||
|
||||
print("native_exception_runtime_smoke: PASS\n");
|
||||
exit_now(0);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
// Native user-raised exception smoke test.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <ntlite/exception.h>
|
||||
#include <ntlite/syscall.h>
|
||||
|
||||
#define SMOKE_EXCEPTION_CODE 0xE1111001u
|
||||
|
||||
static volatile uint32_t gHandlerHits;
|
||||
|
||||
// Prints one NUL-terminated string to the kernel console.
|
||||
static void print(const char* s) {
|
||||
SYS_WRITE_CONSOLE_REQUEST req = { SysSvFromCstr(s) };
|
||||
SysWriteConsole(&req);
|
||||
}
|
||||
|
||||
// Prints one unsigned integer.
|
||||
static void print_u64(uint64_t v) {
|
||||
char buf[32];
|
||||
int i = 0;
|
||||
if (v == 0) {
|
||||
print("0");
|
||||
return;
|
||||
}
|
||||
while (v && i < (int)sizeof(buf)) {
|
||||
buf[i++] = (char)('0' + (v % 10));
|
||||
v /= 10;
|
||||
}
|
||||
while (i--) {
|
||||
char c = buf[i];
|
||||
SYS_WRITE_CONSOLE_REQUEST req = { SysSvFromParts(&c, 1) };
|
||||
SysWriteConsole(&req);
|
||||
}
|
||||
}
|
||||
|
||||
// Terminates the current process.
|
||||
static void exit_now(int32_t code) {
|
||||
for (;;) SysExitProcess(code);
|
||||
}
|
||||
|
||||
// Fails the test with one message.
|
||||
static void fail(const char* message) {
|
||||
print("native_raise_exception_smoke: ");
|
||||
print(message);
|
||||
print("\n");
|
||||
exit_now(1);
|
||||
}
|
||||
|
||||
// Fails the test with one status value.
|
||||
static void fail_status(const char* what, uint32_t status) {
|
||||
print("native_raise_exception_smoke: ");
|
||||
print(what);
|
||||
print(" status=");
|
||||
print_u64(status);
|
||||
print("\n");
|
||||
exit_now(1);
|
||||
}
|
||||
|
||||
// Requires one syscall to return the expected status.
|
||||
static void expect_status(const char* what, uint32_t got, uint32_t expected) {
|
||||
if (got != expected) {
|
||||
print("native_raise_exception_smoke: ");
|
||||
print(what);
|
||||
print(" expected=");
|
||||
print_u64(expected);
|
||||
print(" got=");
|
||||
print_u64(got);
|
||||
print("\n");
|
||||
exit_now(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Reads aggregate exception counters.
|
||||
static void query_exception_stats(SYS_EXCEPTION_STATS* out) {
|
||||
uint32_t status = SysQueryKernelStats(SYS_KERNEL_STATS_EXCEPTION, out, sizeof(*out), 0);
|
||||
expect_status("query exception stats", status, NTLSTATUS_SUCCESS);
|
||||
if (out->Size != sizeof(*out) || out->Version != SYS_STATS_VERSION)
|
||||
fail("exception stats ABI mismatch");
|
||||
}
|
||||
|
||||
// Handles the user-raised exception and verifies its native record payload.
|
||||
static int smoke_handler(SYS_EXCEPTION_RECORD* record, SYS_USER_CONTEXT* context, void* userContext) {
|
||||
if (userContext != (void*)(uintptr_t)0x111E)
|
||||
fail("handler context mismatch");
|
||||
if (!record || !context)
|
||||
fail("handler received null records");
|
||||
if (record->Code != SMOKE_EXCEPTION_CODE)
|
||||
fail("handler received wrong exception code");
|
||||
if ((record->Flags & SYS_EXCEPTION_FLAG_FIRST_CHANCE) == 0)
|
||||
fail("handler missing first-chance flag");
|
||||
if (record->Flags & SYS_EXCEPTION_FLAG_NONCONTINUABLE)
|
||||
fail("handler received unexpected noncontinuable flag");
|
||||
if (record->ParameterCount != 2)
|
||||
fail("handler received wrong parameter count");
|
||||
if (record->Parameters[0] != 0x12345678u || record->Parameters[1] != 0xABCDEF00u)
|
||||
fail("handler received wrong parameters");
|
||||
if (!context->Rip || !context->Rsp)
|
||||
fail("handler received empty context");
|
||||
|
||||
gHandlerHits++;
|
||||
return NTL_EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
print("native_raise_exception_smoke: start\n");
|
||||
|
||||
SYS_EXCEPTION_STATS before;
|
||||
SYS_EXCEPTION_STATS after;
|
||||
query_exception_stats(&before);
|
||||
|
||||
void* handle = NtlAddExceptionHandler(1, smoke_handler, (void*)(uintptr_t)0x111E);
|
||||
if (!handle)
|
||||
fail("failed to add native exception handler");
|
||||
|
||||
uint64_t args[2] = { 0x12345678u, 0xABCDEF00u };
|
||||
SYS_RAISE_EXCEPTION_REQUEST request;
|
||||
request.Size = sizeof(request);
|
||||
request.Flags = SYS_RAISE_EXCEPTION_FLAG_NONE;
|
||||
request.Code = SMOKE_EXCEPTION_CODE;
|
||||
request.ParameterCount = 2;
|
||||
request.Parameters = args;
|
||||
|
||||
uint32_t status = SysRaiseException(&request);
|
||||
expect_status("raise exception", status, NTLSTATUS_SUCCESS);
|
||||
if (gHandlerHits != 1)
|
||||
fail("handler was not called exactly once");
|
||||
|
||||
status = NtlRemoveExceptionHandler(handle);
|
||||
expect_status("remove native exception handler", status, NTLSTATUS_SUCCESS);
|
||||
|
||||
query_exception_stats(&after);
|
||||
if (after.Delivered < before.Delivered + 1 ||
|
||||
after.UserRaised < before.UserRaised + 1 ||
|
||||
after.Continued < before.Continued + 1)
|
||||
fail("exception counters did not advance");
|
||||
if (after.LastCode != SMOKE_EXCEPTION_CODE)
|
||||
fail("last exception code was not updated");
|
||||
|
||||
print("native_raise_exception_smoke: PASS\n");
|
||||
exit_now(0);
|
||||
return 0;
|
||||
}
|
||||
@@ -62,7 +62,7 @@ static SYS_NET_IRP_STATS query_stats(void) {
|
||||
SYS_NET_IRP_STATS stats;
|
||||
memset(&stats, 0, sizeof(stats));
|
||||
uint32_t status = SysQueryKernelStats(SYS_KERNEL_STATS_NET_IRP, &stats, sizeof(stats), 0);
|
||||
if (status != STATUS_SUCCESS)
|
||||
if (status != NTLSTATUS_SUCCESS)
|
||||
fail_status("query net irp stats", status);
|
||||
if (stats.Size != sizeof(stats))
|
||||
fail("net irp stats size mismatch");
|
||||
@@ -93,20 +93,20 @@ static void set_u32_option(uint32_t socket, uint32_t option, uint32_t value) {
|
||||
req.Value = &value;
|
||||
req.ValueSize = sizeof(value);
|
||||
uint32_t status = SysSetSocketOption(socket, &req);
|
||||
if (status != STATUS_SUCCESS)
|
||||
if (status != NTLSTATUS_SUCCESS)
|
||||
fail_status("set socket option", status);
|
||||
}
|
||||
|
||||
// Waits for an async socket request to publish a terminal IOSB status.
|
||||
static void wait_for_async(uint32_t event, SYS_IO_STATUS_BLOCK* iosb, const char* what) {
|
||||
for (uint32_t i = 0; i < 200u && iosb->Status == STATUS_PENDING; ++i) {
|
||||
for (uint32_t i = 0; i < 200u && iosb->Status == NTLSTATUS_PENDING; ++i) {
|
||||
uint32_t status = SysWait(event, 0);
|
||||
if (status != STATUS_SUCCESS && status != STATUS_ALERTED &&
|
||||
status != STATUS_KERNEL_APC && status != STATUS_USER_APC) {
|
||||
if (status != NTLSTATUS_SUCCESS && status != NTLSTATUS_ALERTED &&
|
||||
status != NTLSTATUS_KERNEL_APC && status != NTLSTATUS_USER_APC) {
|
||||
fail_status(what, status);
|
||||
}
|
||||
}
|
||||
if (iosb->Status == STATUS_PENDING)
|
||||
if (iosb->Status == NTLSTATUS_PENDING)
|
||||
fail("async request stayed pending");
|
||||
}
|
||||
|
||||
@@ -114,12 +114,12 @@ static void wait_for_async(uint32_t event, SYS_IO_STATUS_BLOCK* iosb, const char
|
||||
static void check_nonblocking_receive(void) {
|
||||
uint32_t udp = 0;
|
||||
uint32_t status = SysCreateSocket(SYS_AF_INET, SYS_SOCK_DGRAM, SYS_IPPROTO_UDP, &udp);
|
||||
if (status != STATUS_SUCCESS)
|
||||
if (status != NTLSTATUS_SUCCESS)
|
||||
fail_status("create udp socket", status);
|
||||
|
||||
SYS_SOCKET_ADDRESS bindAddress = make_ipv4(0, 0, 0, 0, NET_IRP_SMOKE_UDP_PORT);
|
||||
status = SysBindSocket(udp, &bindAddress, sizeof(bindAddress));
|
||||
if (status != STATUS_SUCCESS) {
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
SysCloseHandle(udp);
|
||||
fail_status("bind udp socket", status);
|
||||
}
|
||||
@@ -143,7 +143,7 @@ static void check_nonblocking_receive(void) {
|
||||
|
||||
status = SysRecvFromSocket(udp, &req);
|
||||
SysCloseHandle(udp);
|
||||
if (status != STATUS_WOULD_BLOCK)
|
||||
if (status != NTLSTATUS_WOULD_BLOCK)
|
||||
fail_status("nonblocking udp recvfrom", status);
|
||||
}
|
||||
|
||||
@@ -151,19 +151,19 @@ static void check_nonblocking_receive(void) {
|
||||
static void check_async_receive_cancel(void) {
|
||||
uint32_t udp = 0;
|
||||
uint32_t status = SysCreateSocket(SYS_AF_INET, SYS_SOCK_DGRAM, SYS_IPPROTO_UDP, &udp);
|
||||
if (status != STATUS_SUCCESS)
|
||||
if (status != NTLSTATUS_SUCCESS)
|
||||
fail_status("create cancel udp socket", status);
|
||||
|
||||
SYS_SOCKET_ADDRESS bindAddress = make_ipv4(0, 0, 0, 0, NET_IRP_SMOKE_UDP_PORT + 1u);
|
||||
status = SysBindSocket(udp, &bindAddress, sizeof(bindAddress));
|
||||
if (status != STATUS_SUCCESS) {
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
SysCloseHandle(udp);
|
||||
fail_status("bind cancel udp socket", status);
|
||||
}
|
||||
|
||||
uint32_t event = 0;
|
||||
status = SysCreateEvent(EVENT_AUTO_RESET, 0, &event);
|
||||
if (status != STATUS_SUCCESS) {
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
SysCloseHandle(udp);
|
||||
fail_status("create event", status);
|
||||
}
|
||||
@@ -193,7 +193,7 @@ static void check_async_receive_cancel(void) {
|
||||
|
||||
SYS_NET_IRP_STATS beforeSubmit = query_stats();
|
||||
status = SysSocketIoAsync(&req);
|
||||
if (status != STATUS_PENDING || requestHandle == 0) {
|
||||
if (status != NTLSTATUS_PENDING || requestHandle == 0) {
|
||||
SysCloseHandle(event);
|
||||
SysCloseHandle(udp);
|
||||
fail_status("submit async recvfrom", status);
|
||||
@@ -213,17 +213,17 @@ static void check_async_receive_cancel(void) {
|
||||
fail("async recvfrom did not enter the IRP path");
|
||||
|
||||
uint32_t cancelStatus = SysCancelIo(requestHandle);
|
||||
if (cancelStatus != STATUS_SUCCESS && cancelStatus != STATUS_PENDING)
|
||||
if (cancelStatus != NTLSTATUS_SUCCESS && cancelStatus != NTLSTATUS_PENDING)
|
||||
fail_status("cancel async recvfrom", cancelStatus);
|
||||
|
||||
wait_for_async(event, &iosb, "wait async recvfrom cancel");
|
||||
if (iosb.Status != STATUS_CANCELLED)
|
||||
if (iosb.Status != NTLSTATUS_CANCELLED)
|
||||
fail_status("async recvfrom iosb", iosb.Status);
|
||||
if (iosb.Information != 0)
|
||||
fail("async recvfrom cancel transferred bytes");
|
||||
|
||||
status = SysWaitSingle(requestHandle, 0, 0);
|
||||
if (status != STATUS_SUCCESS)
|
||||
if (status != NTLSTATUS_SUCCESS)
|
||||
fail_status("wait cancelled request handle", status);
|
||||
|
||||
SysCloseHandle(requestHandle);
|
||||
@@ -235,7 +235,7 @@ static void check_async_receive_cancel(void) {
|
||||
static void try_http_async_success(void) {
|
||||
uint32_t tcp = 0;
|
||||
uint32_t status = SysCreateSocket(SYS_AF_INET, SYS_SOCK_STREAM, SYS_IPPROTO_TCP, &tcp);
|
||||
if (status != STATUS_SUCCESS) {
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
print("net_irp_smoke: http success path skipped create status=");
|
||||
print_u64(status);
|
||||
print("\n");
|
||||
@@ -244,7 +244,7 @@ static void try_http_async_success(void) {
|
||||
|
||||
SYS_SOCKET_ADDRESS address = make_ipv4(10, 0, 2, 2, NET_IRP_SMOKE_HTTP_PORT);
|
||||
status = SysConnectSocket(tcp, &address, sizeof(address));
|
||||
if (status != STATUS_SUCCESS) {
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
print("net_irp_smoke: http success path skipped connect status=");
|
||||
print_u64(status);
|
||||
print("\n");
|
||||
@@ -254,7 +254,7 @@ static void try_http_async_success(void) {
|
||||
|
||||
uint32_t event = 0;
|
||||
status = SysCreateEvent(EVENT_AUTO_RESET, 0, &event);
|
||||
if (status != STATUS_SUCCESS) {
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
SysCloseHandle(tcp);
|
||||
fail_status("create http event", status);
|
||||
}
|
||||
@@ -276,10 +276,10 @@ static void try_http_async_success(void) {
|
||||
sendReq.RequestHandleOut = &sendRequest;
|
||||
|
||||
status = SysSocketIoAsync(&sendReq);
|
||||
if (status != STATUS_PENDING || sendRequest == 0)
|
||||
if (status != NTLSTATUS_PENDING || sendRequest == 0)
|
||||
fail_status("submit async send", status);
|
||||
wait_for_async(event, &sendIosb, "wait async send");
|
||||
if (sendIosb.Status != STATUS_SUCCESS)
|
||||
if (sendIosb.Status != NTLSTATUS_SUCCESS)
|
||||
fail_status("async send iosb", sendIosb.Status);
|
||||
if (sendIosb.Information != sizeof(requestText) - 1u)
|
||||
fail("async send byte count mismatch");
|
||||
@@ -303,10 +303,10 @@ static void try_http_async_success(void) {
|
||||
recvReq.RequestHandleOut = &recvRequest;
|
||||
|
||||
status = SysSocketIoAsync(&recvReq);
|
||||
if (status != STATUS_PENDING || recvRequest == 0)
|
||||
if (status != NTLSTATUS_PENDING || recvRequest == 0)
|
||||
fail_status("submit async recv", status);
|
||||
wait_for_async(event, &recvIosb, "wait async recv");
|
||||
if (recvIosb.Status != STATUS_SUCCESS)
|
||||
if (recvIosb.Status != NTLSTATUS_SUCCESS)
|
||||
fail_status("async recv iosb", recvIosb.Status);
|
||||
if (recvIosb.Information == 0)
|
||||
fail("async recv returned no bytes");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Page-cache write/truncate invalidation regression test.
|
||||
// Verifies cached clean pages are not reused after file write or truncate.
|
||||
// Page-cache write/truncate coherency regression test.
|
||||
// Verifies cached pages stay coherent after file write and cached tails are dropped after truncate.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
@@ -79,14 +79,14 @@ static uint32_t create_temp(uint32_t* fileOut, const char** pathOut) {
|
||||
SYS_FILE_FLAG_NONE,
|
||||
&h);
|
||||
uint32_t s = SysOpenFile(&req);
|
||||
if (s == STATUS_SUCCESS) {
|
||||
if (s == NTLSTATUS_SUCCESS) {
|
||||
*fileOut = h;
|
||||
if (pathOut) *pathOut = paths[i];
|
||||
return STATUS_SUCCESS;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return STATUS_NOT_FOUND;
|
||||
return NTLSTATUS_NOT_FOUND;
|
||||
}
|
||||
|
||||
static void fill_patterns(void) {
|
||||
@@ -100,7 +100,7 @@ static void checked_write(uint32_t file, const void* buffer, size_t size, const
|
||||
size_t done = 0;
|
||||
SYS_FILE_IO_REQUEST req = SysMakeFileIoRequest(file, buffer, size, &done);
|
||||
uint32_t s = SysWriteFile(&req);
|
||||
if (s != STATUS_SUCCESS) fail_status(what, s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status(what, s);
|
||||
if (done != size) fail("short write");
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ static void checked_read(uint32_t file, void* buffer, size_t size, size_t* gotOu
|
||||
memset(buffer, 0xCC, size);
|
||||
SYS_FILE_IO_REQUEST req = SysMakeFileIoRequest(file, buffer, size, &got);
|
||||
uint32_t s = SysReadFile(&req);
|
||||
if (s != STATUS_SUCCESS) fail_status(what, s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status(what, s);
|
||||
if (gotOut) *gotOut = got;
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ int main(void) {
|
||||
uint32_t file = 0;
|
||||
const char* path = 0;
|
||||
uint32_t s = create_temp(&file, &path);
|
||||
if (s != STATUS_SUCCESS) fail_status("create temp", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("create temp", s);
|
||||
|
||||
print("pcache_invalidate: using ");
|
||||
print(path ? path : "<unknown>");
|
||||
@@ -129,7 +129,7 @@ int main(void) {
|
||||
checked_write(file, gOriginal, sizeof(gOriginal), "write original");
|
||||
|
||||
s = SysSeekFile(file, 0);
|
||||
if (s != STATUS_SUCCESS) fail_status("seek fill", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("seek fill", s);
|
||||
|
||||
SYS_FILE_CACHE_STATS before;
|
||||
SYS_FILE_CACHE_STATS afterFill;
|
||||
@@ -137,23 +137,24 @@ int main(void) {
|
||||
SYS_FILE_CACHE_STATS afterWrite;
|
||||
SYS_FILE_CACHE_STATS afterRewriteRead;
|
||||
SYS_FILE_CACHE_STATS afterTruncate;
|
||||
if (query_cache(&before) != STATUS_SUCCESS) fail("initial stats query failed");
|
||||
if (query_cache(&before) != NTLSTATUS_SUCCESS) fail("initial stats query failed");
|
||||
|
||||
size_t got = 0;
|
||||
checked_read(file, gReadback, sizeof(gReadback), &got, "first read");
|
||||
if (got != sizeof(gOriginal)) fail("first read size mismatch");
|
||||
if (memcmp(gReadback, gOriginal, sizeof(gOriginal)) != 0) fail("first read data mismatch");
|
||||
|
||||
if (query_cache(&afterFill) != STATUS_SUCCESS) fail("fill stats query failed");
|
||||
if (afterFill.Loads <= before.Loads) fail("initial read did not populate cache");
|
||||
if (query_cache(&afterFill) != NTLSTATUS_SUCCESS) fail("fill stats query failed");
|
||||
if (afterFill.Loads <= before.Loads && afterFill.Hits <= before.Hits)
|
||||
fail("initial read did not touch cache");
|
||||
|
||||
s = SysSeekFile(file, 0);
|
||||
if (s != STATUS_SUCCESS) fail_status("seek second", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("seek second", s);
|
||||
checked_read(file, gReadback, sizeof(gReadback), &got, "second read");
|
||||
if (got != sizeof(gOriginal)) fail("second read size mismatch");
|
||||
if (memcmp(gReadback, gOriginal, sizeof(gOriginal)) != 0) fail("second read data mismatch");
|
||||
|
||||
if (query_cache(&afterSecond) != STATUS_SUCCESS) fail("second stats query failed");
|
||||
if (query_cache(&afterSecond) != NTLSTATUS_SUCCESS) fail("second stats query failed");
|
||||
// Do not require this second read to hit: the cache is intentionally
|
||||
// bounded and pcache_pressure.exe may have left it at the soft limit, so
|
||||
// the newly-populated temp pages are eligible for immediate pressure
|
||||
@@ -161,20 +162,20 @@ int main(void) {
|
||||
// is covered by pcache_mmap_read_reuse.exe.
|
||||
|
||||
s = SysSeekFile(file, 0);
|
||||
if (s != STATUS_SUCCESS) fail_status("seek rewrite", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("seek rewrite", s);
|
||||
checked_write(file, gReplacement, sizeof(gReplacement), "rewrite first page");
|
||||
|
||||
if (query_cache(&afterWrite) != STATUS_SUCCESS) fail("post-write stats query failed");
|
||||
if (afterWrite.Invalidations <= afterSecond.Invalidations) fail("write did not invalidate cached page");
|
||||
if (query_cache(&afterWrite) != NTLSTATUS_SUCCESS) fail("post-write stats query failed");
|
||||
if (afterWrite.DirtyMarks <= afterSecond.DirtyMarks) fail("rewrite did not dirty cached page");
|
||||
|
||||
uint32_t mapping = 0;
|
||||
s = SysCreateFileMapping(file, SYS_VM_READ, SYS_MAP_FLAG_NONE, sizeof(gReplacement), &mapping);
|
||||
if (s != STATUS_SUCCESS) fail_status("create mapping after rewrite", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("create mapping after rewrite", s);
|
||||
|
||||
void* mappedBase = 0;
|
||||
s = SysMapFile(mapping, 0, sizeof(gReplacement), SYS_MAP_ACCESS_READ, SYS_MAP_FLAG_NONE, &mappedBase);
|
||||
SysCloseHandle(mapping);
|
||||
if (s != STATUS_SUCCESS) fail_status("map after rewrite", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("map after rewrite", s);
|
||||
if (!mappedBase) fail("map after rewrite returned null");
|
||||
|
||||
volatile uint8_t* mappedView = (volatile uint8_t*)mappedBase;
|
||||
@@ -185,30 +186,30 @@ int main(void) {
|
||||
fail("stale mmap data after write invalidation");
|
||||
}
|
||||
s = SysFreeVm(mappedBase);
|
||||
if (s != STATUS_SUCCESS) fail_status("unmap after rewrite", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("unmap after rewrite", s);
|
||||
|
||||
s = SysSeekFile(file, 0);
|
||||
if (s != STATUS_SUCCESS) fail_status("seek verify rewrite", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("seek verify rewrite", s);
|
||||
checked_read(file, gReadback, sizeof(gReadback), &got, "read after rewrite");
|
||||
if (got != sizeof(gOriginal)) fail("rewrite read size mismatch");
|
||||
if (memcmp(gReadback, gReplacement, sizeof(gReplacement)) != 0) fail("stale data after write invalidation");
|
||||
if (memcmp(gReadback + sizeof(gReplacement), gOriginal + sizeof(gReplacement),
|
||||
sizeof(gOriginal) - sizeof(gReplacement)) != 0) fail("unwritten page changed after rewrite");
|
||||
|
||||
if (query_cache(&afterRewriteRead) != STATUS_SUCCESS) fail("rewrite-read stats query failed");
|
||||
if (query_cache(&afterRewriteRead) != NTLSTATUS_SUCCESS) fail("rewrite-read stats query failed");
|
||||
|
||||
s = SysTruncateFile(file, TRUNC_SIZE);
|
||||
if (s != STATUS_SUCCESS) fail_status("truncate", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("truncate", s);
|
||||
uint64_t truncatedSize = 0;
|
||||
s = SysGetFileSize(file, &truncatedSize);
|
||||
if (s != STATUS_SUCCESS) fail_status("get truncated size", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("get truncated size", s);
|
||||
if (truncatedSize != TRUNC_SIZE) fail("truncate size mismatch");
|
||||
|
||||
if (query_cache(&afterTruncate) != STATUS_SUCCESS) fail("truncate stats query failed");
|
||||
if (query_cache(&afterTruncate) != NTLSTATUS_SUCCESS) fail("truncate stats query failed");
|
||||
if (afterTruncate.Invalidations <= afterRewriteRead.Invalidations) fail("truncate did not invalidate cached tail");
|
||||
|
||||
s = SysSeekFile(file, 0);
|
||||
if (s != STATUS_SUCCESS) fail_status("seek truncated", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("seek truncated", s);
|
||||
checked_read(file, gReadback, sizeof(gReadback), &got, "read truncated");
|
||||
if (got != TRUNC_SIZE) fail("truncated read length mismatch");
|
||||
if (memcmp(gReadback, gReplacement, TRUNC_SIZE) != 0) fail("truncated data mismatch");
|
||||
|
||||
@@ -78,13 +78,13 @@ static uint32_t open_test_file(uint32_t* out, const char** pathOut) {
|
||||
SYS_FILE_FLAG_NONE,
|
||||
&h);
|
||||
uint32_t s = SysOpenFile(&req);
|
||||
if (s == STATUS_SUCCESS) {
|
||||
if (s == NTLSTATUS_SUCCESS) {
|
||||
*out = h;
|
||||
if (pathOut) *pathOut = paths[i];
|
||||
return STATUS_SUCCESS;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
return STATUS_NOT_FOUND;
|
||||
return NTLSTATUS_NOT_FOUND;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
@@ -94,16 +94,16 @@ int main(void) {
|
||||
SYS_FILE_CACHE_STATS afterFault;
|
||||
SYS_FILE_CACHE_STATS afterRead;
|
||||
uint32_t s = query_cache(&before);
|
||||
if (s != STATUS_SUCCESS) fail_status("query initial stats", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("query initial stats", s);
|
||||
|
||||
uint32_t file = 0;
|
||||
const char* path = 0;
|
||||
s = open_test_file(&file, &path);
|
||||
if (s != STATUS_SUCCESS) fail_status("open test file", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("open test file", s);
|
||||
|
||||
uint64_t fileSize = 0;
|
||||
s = SysGetFileSize(file, &fileSize);
|
||||
if (s != STATUS_SUCCESS) fail_status("get file size", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("get file size", s);
|
||||
if (fileSize < 4096) fail("test file too small");
|
||||
size_t mapSize = (fileSize < TEST_SIZE) ? (size_t)fileSize : TEST_SIZE;
|
||||
|
||||
@@ -115,12 +115,12 @@ int main(void) {
|
||||
|
||||
uint32_t mapping = 0;
|
||||
s = SysCreateFileMapping(file, SYS_VM_READ, SYS_MAP_FLAG_NONE, mapSize, &mapping);
|
||||
if (s != STATUS_SUCCESS) fail_status("create mapping", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("create mapping", s);
|
||||
|
||||
void* base = 0;
|
||||
s = SysMapFile(mapping, 0, mapSize, SYS_MAP_ACCESS_READ, SYS_MAP_FLAG_NONE, &base);
|
||||
SysCloseHandle(mapping);
|
||||
if (s != STATUS_SUCCESS) fail_status("map file", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("map file", s);
|
||||
if (!base) fail("map returned null");
|
||||
|
||||
volatile uint8_t* view = (volatile uint8_t*)base;
|
||||
@@ -129,14 +129,14 @@ int main(void) {
|
||||
(void)view[mapSize - 1];
|
||||
|
||||
s = query_cache(&afterFault);
|
||||
if (s != STATUS_SUCCESS) fail_status("query after mmap faults", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("query after mmap faults", s);
|
||||
if (afterFault.Loads <= before.Loads) {
|
||||
SysFreeVm(base);
|
||||
fail("mmap faults did not populate file cache");
|
||||
}
|
||||
|
||||
s = SysSeekFile(file, 0);
|
||||
if (s != STATUS_SUCCESS) {
|
||||
if (s != NTLSTATUS_SUCCESS) {
|
||||
SysFreeVm(base);
|
||||
fail_status("seek", s);
|
||||
}
|
||||
@@ -145,7 +145,7 @@ int main(void) {
|
||||
memset(gReadback, 0xCC, sizeof(gReadback));
|
||||
SYS_FILE_IO_REQUEST readReq = SysMakeFileIoRequest(file, gReadback, mapSize, &got);
|
||||
s = SysReadFile(&readReq);
|
||||
if (s != STATUS_SUCCESS) {
|
||||
if (s != NTLSTATUS_SUCCESS) {
|
||||
SysFreeVm(base);
|
||||
fail_status("read", s);
|
||||
}
|
||||
@@ -159,7 +159,7 @@ int main(void) {
|
||||
}
|
||||
|
||||
s = query_cache(&afterRead);
|
||||
if (s != STATUS_SUCCESS) {
|
||||
if (s != NTLSTATUS_SUCCESS) {
|
||||
SysFreeVm(base);
|
||||
fail_status("query after read", s);
|
||||
}
|
||||
|
||||
@@ -87,14 +87,14 @@ static uint32_t create_temp(uint32_t* fileOut, const char** pathOut) {
|
||||
SYS_FILE_FLAG_NONE,
|
||||
&h);
|
||||
uint32_t s = SysOpenFile(&req);
|
||||
if (s == STATUS_SUCCESS) {
|
||||
if (s == NTLSTATUS_SUCCESS) {
|
||||
*fileOut = h;
|
||||
if (pathOut) *pathOut = paths[i];
|
||||
return STATUS_SUCCESS;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return STATUS_NOT_FOUND;
|
||||
return NTLSTATUS_NOT_FOUND;
|
||||
}
|
||||
|
||||
static void fill_pattern(void) {
|
||||
@@ -107,7 +107,7 @@ static uint32_t validate_mapping(const uint8_t* base) {
|
||||
if (base[i] != gPattern[i])
|
||||
return 0x10000000u | (uint32_t)(i & 0x0FFFFFFFu);
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void thread_main(uintptr_t arg) {
|
||||
@@ -118,8 +118,8 @@ static void thread_main(uintptr_t arg) {
|
||||
void* base = 0;
|
||||
uint32_t s = SysMapFile(ctx->Mapping, 0, TEST_SIZE,
|
||||
SYS_MAP_ACCESS_READ, SYS_MAP_FLAG_NONE, &base);
|
||||
if (s != STATUS_SUCCESS || !base) {
|
||||
ctx->Status = s ? s : STATUS_INVALID_PARAMETER;
|
||||
if (s != NTLSTATUS_SUCCESS || !base) {
|
||||
ctx->Status = s ? s : NTLSTATUS_INVALID_PARAMETER;
|
||||
SysExitThread(1);
|
||||
}
|
||||
|
||||
@@ -130,18 +130,18 @@ static void thread_main(uintptr_t arg) {
|
||||
|
||||
s = validate_mapping((const uint8_t*)base);
|
||||
uint32_t fs = SysFreeVm(base);
|
||||
if (s != STATUS_SUCCESS) {
|
||||
if (s != NTLSTATUS_SUCCESS) {
|
||||
ctx->Status = s;
|
||||
SysExitThread(1);
|
||||
}
|
||||
if (fs != STATUS_SUCCESS) {
|
||||
if (fs != NTLSTATUS_SUCCESS) {
|
||||
ctx->Status = fs;
|
||||
SysExitThread(1);
|
||||
}
|
||||
ctx->IterationsDone++;
|
||||
}
|
||||
|
||||
ctx->Status = STATUS_SUCCESS;
|
||||
ctx->Status = NTLSTATUS_SUCCESS;
|
||||
SysExitThread(0);
|
||||
}
|
||||
|
||||
@@ -152,21 +152,21 @@ int main(void) {
|
||||
uint32_t file = 0;
|
||||
const char* path = 0;
|
||||
uint32_t s = create_temp(&file, &path);
|
||||
if (s != STATUS_SUCCESS) fail_status("create temp", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("create temp", s);
|
||||
|
||||
size_t written = 0;
|
||||
SYS_FILE_IO_REQUEST writeReq = SysMakeFileIoRequest(file, gPattern, sizeof(gPattern), &written);
|
||||
s = SysWriteFile(&writeReq);
|
||||
if (s != STATUS_SUCCESS) fail_status("write pattern", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("write pattern", s);
|
||||
if (written != sizeof(gPattern)) fail("short write");
|
||||
|
||||
uint32_t mapping = 0;
|
||||
s = SysCreateFileMapping(file, SYS_VM_READ, SYS_MAP_FLAG_NONE, TEST_SIZE, &mapping);
|
||||
if (s != STATUS_SUCCESS) fail_status("create mapping", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("create mapping", s);
|
||||
|
||||
SYS_FILE_CACHE_STATS before;
|
||||
SYS_FILE_CACHE_STATS after;
|
||||
if (query_cache(&before) != STATUS_SUCCESS) fail("initial stats query failed");
|
||||
if (query_cache(&before) != NTLSTATUS_SUCCESS) fail("initial stats query failed");
|
||||
|
||||
uint32_t handles[THREAD_COUNT];
|
||||
uint32_t tids[THREAD_COUNT];
|
||||
@@ -177,7 +177,7 @@ int main(void) {
|
||||
for (uint32_t i = 0; i < THREAD_COUNT; ++i) {
|
||||
gThreads[i].Index = i;
|
||||
gThreads[i].Mapping = mapping;
|
||||
gThreads[i].Status = STATUS_PENDING;
|
||||
gThreads[i].Status = NTLSTATUS_PENDING;
|
||||
SYS_CREATE_THREAD_REQUEST req = {
|
||||
(uintptr_t)thread_main,
|
||||
(uintptr_t)&gThreads[i],
|
||||
@@ -187,17 +187,17 @@ int main(void) {
|
||||
&tids[i]
|
||||
};
|
||||
s = SysCreateThread(&req);
|
||||
if (s != STATUS_SUCCESS) fail_status("create thread", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("create thread", s);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < THREAD_COUNT; ++i) {
|
||||
s = SysWait(handles[i], SYS_WAIT_FLAG_NONE);
|
||||
if (s != STATUS_SUCCESS) fail_status("wait thread", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("wait thread", s);
|
||||
SysCloseHandle(handles[i]);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < THREAD_COUNT; ++i) {
|
||||
if (gThreads[i].Status != STATUS_SUCCESS) {
|
||||
if (gThreads[i].Status != NTLSTATUS_SUCCESS) {
|
||||
print("pcache_multithread: worker ");
|
||||
print_u64(i);
|
||||
print(" status=");
|
||||
@@ -210,8 +210,9 @@ int main(void) {
|
||||
if (gThreads[i].IterationsDone != ITERATIONS) fail("worker iteration count mismatch");
|
||||
}
|
||||
|
||||
if (query_cache(&after) != STATUS_SUCCESS) fail("final stats query failed");
|
||||
if (after.Loads <= before.Loads) fail("concurrent mmap did not load cache pages");
|
||||
if (query_cache(&after) != NTLSTATUS_SUCCESS) fail("final stats query failed");
|
||||
if (after.Loads <= before.Loads && after.Hits <= before.Hits)
|
||||
fail("concurrent mmap did not touch cache pages");
|
||||
if (after.Hits <= before.Hits) fail("concurrent mmap did not reuse cache pages");
|
||||
|
||||
SysCloseHandle(mapping);
|
||||
|
||||
@@ -77,12 +77,12 @@ static uint32_t open_first_large(uint32_t* fileOut, const char** pathOut, uint64
|
||||
SYS_FILE_FLAG_NONE,
|
||||
&h);
|
||||
uint32_t s = SysOpenFile(&req);
|
||||
if (s != STATUS_SUCCESS)
|
||||
if (s != NTLSTATUS_SUCCESS)
|
||||
continue;
|
||||
|
||||
uint64_t size = 0;
|
||||
s = SysGetFileSize(h, &size);
|
||||
if (s != STATUS_SUCCESS) {
|
||||
if (s != NTLSTATUS_SUCCESS) {
|
||||
SysCloseHandle(h);
|
||||
continue;
|
||||
}
|
||||
@@ -90,13 +90,13 @@ static uint32_t open_first_large(uint32_t* fileOut, const char** pathOut, uint64
|
||||
*fileOut = h;
|
||||
*pathOut = candidates[i];
|
||||
*sizeOut = size;
|
||||
return STATUS_SUCCESS;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
SysCloseHandle(h);
|
||||
}
|
||||
|
||||
return STATUS_NOT_FOUND;
|
||||
return NTLSTATUS_NOT_FOUND;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
@@ -104,14 +104,14 @@ int main(void) {
|
||||
|
||||
SYS_FILE_CACHE_STATS before;
|
||||
SYS_FILE_CACHE_STATS after;
|
||||
if (query_cache(&before) != STATUS_SUCCESS)
|
||||
if (query_cache(&before) != NTLSTATUS_SUCCESS)
|
||||
fail("initial cache stats query failed");
|
||||
|
||||
uint32_t file = 0;
|
||||
const char* path = 0;
|
||||
uint64_t size = 0;
|
||||
uint32_t s = open_first_large(&file, &path, &size);
|
||||
if (s != STATUS_SUCCESS)
|
||||
if (s != NTLSTATUS_SUCCESS)
|
||||
fail_status("open large asset", s);
|
||||
|
||||
print("pcache_pressure: using ");
|
||||
@@ -126,7 +126,7 @@ int main(void) {
|
||||
size_t got = 0;
|
||||
SYS_FILE_IO_REQUEST readReq = SysMakeFileIoRequest(file, gBuf, sizeof(gBuf), &got);
|
||||
s = SysReadFile(&readReq);
|
||||
if (s != STATUS_SUCCESS)
|
||||
if (s != NTLSTATUS_SUCCESS)
|
||||
fail_status("read", s);
|
||||
if (got == 0)
|
||||
break;
|
||||
@@ -138,7 +138,7 @@ int main(void) {
|
||||
if (total < MIN_PRESSURE_BYTES)
|
||||
fail("asset read was too short to pressure the cache");
|
||||
|
||||
if (query_cache(&after) != STATUS_SUCCESS)
|
||||
if (query_cache(&after) != NTLSTATUS_SUCCESS)
|
||||
fail("final cache stats query failed");
|
||||
|
||||
uint64_t loads = after.Loads - before.Loads;
|
||||
|
||||
@@ -72,13 +72,13 @@ static uint32_t open_self(uint32_t* out) {
|
||||
SYS_FILE_FLAG_NONE,
|
||||
&h);
|
||||
uint32_t s = SysOpenFile(&req);
|
||||
if (s == STATUS_SUCCESS) {
|
||||
if (s == NTLSTATUS_SUCCESS) {
|
||||
*out = h;
|
||||
print("pcache_smoke: using "); print(paths[i]); print("\n");
|
||||
return STATUS_SUCCESS;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
return STATUS_NOT_FOUND;
|
||||
return NTLSTATUS_NOT_FOUND;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
@@ -86,52 +86,52 @@ int main(void) {
|
||||
|
||||
SYS_FILE_CACHE_STATS before, afterFirst, afterSecond, afterMap;
|
||||
uint32_t s = query_cache(&before);
|
||||
if (s != STATUS_SUCCESS) fail_status("query initial stats", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("query initial stats", s);
|
||||
|
||||
uint32_t file = 0;
|
||||
s = open_self(&file);
|
||||
if (s != STATUS_SUCCESS) fail_status("open test file", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("open test file", s);
|
||||
|
||||
size_t gotA = 0;
|
||||
memset(gA, 0xA5, sizeof(gA));
|
||||
SYS_FILE_IO_REQUEST readReqA = SysMakeFileIoRequest(file, gA, sizeof(gA), &gotA);
|
||||
s = SysReadFile(&readReqA);
|
||||
if (s != STATUS_SUCCESS) fail_status("first read", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("first read", s);
|
||||
if (gotA < 4096) fail("first read too short");
|
||||
print("pcache_smoke: first read OK\n");
|
||||
|
||||
s = query_cache(&afterFirst);
|
||||
if (s != STATUS_SUCCESS) fail_status("query after first read", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("query after first read", s);
|
||||
if (afterFirst.Loads <= before.Loads)
|
||||
fail("first read did not load file-cache pages");
|
||||
|
||||
s = SysSeekFile(file, 0);
|
||||
if (s != STATUS_SUCCESS) fail_status("seek", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("seek", s);
|
||||
|
||||
size_t gotB = 0;
|
||||
memset(gB, 0x5A, sizeof(gB));
|
||||
SYS_FILE_IO_REQUEST readReqB = SysMakeFileIoRequest(file, gB, sizeof(gB), &gotB);
|
||||
s = SysReadFile(&readReqB);
|
||||
if (s != STATUS_SUCCESS) fail_status("second read", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("second read", s);
|
||||
if (gotB != gotA) fail("second read length mismatch");
|
||||
if (memcmp(gA, gB, gotA) != 0) fail("second read data mismatch");
|
||||
print("pcache_smoke: second read OK\n");
|
||||
|
||||
s = query_cache(&afterSecond);
|
||||
if (s != STATUS_SUCCESS) fail_status("query after second read", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("query after second read", s);
|
||||
if (afterSecond.Hits <= afterFirst.Hits)
|
||||
fail("second read did not hit file cache");
|
||||
|
||||
uint32_t mapping = 0;
|
||||
s = SysCreateFileMapping(file, SYS_VM_READ, SYS_MAP_FLAG_NONE, sizeof(gA), &mapping);
|
||||
if (s != STATUS_SUCCESS) fail_status("create mapping", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("create mapping", s);
|
||||
SysCloseHandle(file);
|
||||
file = 0;
|
||||
|
||||
void* base = 0;
|
||||
s = SysMapFile(mapping, 0, sizeof(gA), SYS_MAP_ACCESS_READ, SYS_MAP_FLAG_NONE, &base);
|
||||
SysCloseHandle(mapping);
|
||||
if (s != STATUS_SUCCESS) fail_status("map file", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("map file", s);
|
||||
if (!base) fail("map returned null");
|
||||
|
||||
volatile uint8_t* view = (volatile uint8_t*)base;
|
||||
@@ -145,7 +145,7 @@ int main(void) {
|
||||
}
|
||||
|
||||
s = query_cache(&afterMap);
|
||||
if (s != STATUS_SUCCESS) fail_status("query after map", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("query after map", s);
|
||||
if (afterMap.Hits <= afterSecond.Hits)
|
||||
fail("mmap faults did not hit already cached pages");
|
||||
|
||||
|
||||
@@ -54,18 +54,18 @@ static void fail_status(const char* operation, uint32_t status) {
|
||||
static void verify_protected_process(const SYS_PROCESS_INFO* process) {
|
||||
uint32_t handle = 0;
|
||||
uint32_t status = SysOpenProcess(process->ProcessId, &handle);
|
||||
if (status != STATUS_SUCCESS)
|
||||
if (status != NTLSTATUS_SUCCESS)
|
||||
fail_status("open protected process", status);
|
||||
|
||||
status = SysKillProcess(handle, (int32_t)STATUS_PROCESS_KILLED);
|
||||
if (status != STATUS_ACCESS_DENIED) {
|
||||
status = SysKillProcess(handle, (int32_t)NTLSTATUS_PROCESS_KILLED);
|
||||
if (status != NTLSTATUS_ACCESS_DENIED) {
|
||||
SysCloseHandle(handle);
|
||||
fail_status("kill protected process", status);
|
||||
}
|
||||
|
||||
status = SysWaitSingle(handle, SYS_WAIT_FLAG_NONE, 0);
|
||||
SysCloseHandle(handle);
|
||||
if (status != STATUS_TIMEOUT)
|
||||
if (status != NTLSTATUS_TIMEOUT)
|
||||
fail_status("protected process remained signaled", status);
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ void main(void) {
|
||||
SYS_PROCESS_INFO processes[MAX_PROCESSES];
|
||||
size_t count = 0;
|
||||
uint32_t status = SysGetProcessList(processes, MAX_PROCESSES, &count);
|
||||
if (status != STATUS_SUCCESS)
|
||||
if (status != NTLSTATUS_SUCCESS)
|
||||
fail_status("query process list", status);
|
||||
|
||||
int sawIdle = 0;
|
||||
|
||||
@@ -75,7 +75,7 @@ static void get_current_drive_root(char* out, size_t cap) {
|
||||
&required,
|
||||
};
|
||||
uint32_t status = SysRealPath(&req);
|
||||
if (status != STATUS_SUCCESS) fail_status("query current path", status);
|
||||
if (status != NTLSTATUS_SUCCESS) fail_status("query current path", status);
|
||||
if (required < 4 || current[0] < '0' || current[0] > '7' || current[1] != ':' || current[2] != '/')
|
||||
fail("current path is not native drive-rooted");
|
||||
if (cap < 4) fail("drive root output too small");
|
||||
@@ -98,7 +98,7 @@ static void expect_realpath(const char* input, const char* expected) {
|
||||
&required,
|
||||
};
|
||||
uint32_t status = SysRealPath(&req);
|
||||
if (status != STATUS_SUCCESS) fail_status("realpath", status);
|
||||
if (status != NTLSTATUS_SUCCESS) fail_status("realpath", status);
|
||||
if (required != strlen(expected) + 1) fail("required size mismatch");
|
||||
if (strcmp(out, expected) != 0) fail("resolved path mismatch");
|
||||
}
|
||||
@@ -115,7 +115,7 @@ static void check_size_reporting(const char* input, const char* expected) {
|
||||
&required,
|
||||
};
|
||||
uint32_t status = SysRealPath(&query);
|
||||
if (status != STATUS_SUCCESS) fail_status("size query", status);
|
||||
if (status != NTLSTATUS_SUCCESS) fail_status("size query", status);
|
||||
if (required != strlen(expected) + 1) fail("size query required mismatch");
|
||||
|
||||
char small[4];
|
||||
@@ -129,7 +129,7 @@ static void check_size_reporting(const char* input, const char* expected) {
|
||||
&smallRequired,
|
||||
};
|
||||
status = SysRealPath(&smallReq);
|
||||
if (status != STATUS_BUFFER_TOO_SMALL) fail_status("small buffer", status);
|
||||
if (status != NTLSTATUS_BUFFER_TOO_SMALL) fail_status("small buffer", status);
|
||||
if (smallRequired != required) fail("small required mismatch");
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ int main(void) {
|
||||
(size_t*)0,
|
||||
};
|
||||
uint32_t status = SysRealPath(¤tReq);
|
||||
if (status != STATUS_SUCCESS) fail_status("current realpath", status);
|
||||
if (status != NTLSTATUS_SUCCESS) fail_status("current realpath", status);
|
||||
|
||||
memcpy(input, "missing_realpath_dir/../missing_file", sizeof("missing_realpath_dir/../missing_file"));
|
||||
append(expected, sizeof(expected), expected[strlen(expected) - 1] == '/' ? "missing_file" : "/missing_file");
|
||||
|
||||
@@ -79,13 +79,13 @@ static uint32_t create_temp(uint32_t* fileOut, const char** pathOut) {
|
||||
SYS_FILE_FLAG_NONE,
|
||||
&h);
|
||||
uint32_t s = SysOpenFile(&req);
|
||||
if (s == STATUS_SUCCESS) {
|
||||
if (s == NTLSTATUS_SUCCESS) {
|
||||
*fileOut = h;
|
||||
if (pathOut) *pathOut = paths[i];
|
||||
return STATUS_SUCCESS;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
return STATUS_NOT_FOUND;
|
||||
return NTLSTATUS_NOT_FOUND;
|
||||
}
|
||||
|
||||
static uint32_t open_path(const char* path, uint32_t* fileOut) {
|
||||
@@ -96,21 +96,21 @@ static uint32_t open_path(const char* path, uint32_t* fileOut) {
|
||||
SYS_FILE_FLAG_NONE,
|
||||
&h);
|
||||
uint32_t s = SysOpenFile(&req);
|
||||
if (s == STATUS_SUCCESS)
|
||||
if (s == NTLSTATUS_SUCCESS)
|
||||
*fileOut = h;
|
||||
return s;
|
||||
}
|
||||
|
||||
static void checked_seek(uint32_t file, uint64_t offset, const char* what) {
|
||||
uint32_t s = SysSeekFile(file, offset);
|
||||
if (s != STATUS_SUCCESS) fail_status(what, s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status(what, s);
|
||||
}
|
||||
|
||||
static void checked_write(uint32_t file, const void* buffer, size_t size, const char* what) {
|
||||
size_t done = 0;
|
||||
SYS_FILE_IO_REQUEST req = SysMakeFileIoRequest(file, buffer, size, &done);
|
||||
uint32_t s = SysWriteFile(&req);
|
||||
if (s != STATUS_SUCCESS) fail_status(what, s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status(what, s);
|
||||
if (done != size) fail("short write");
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ static void checked_read(uint32_t file, void* buffer, size_t size, size_t* gotOu
|
||||
memset(buffer, 0xCC, size);
|
||||
SYS_FILE_IO_REQUEST req = SysMakeFileIoRequest(file, buffer, size, &got);
|
||||
uint32_t s = SysReadFile(&req);
|
||||
if (s != STATUS_SUCCESS) fail_status(what, s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status(what, s);
|
||||
if (gotOut) *gotOut = got;
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ int main(void) {
|
||||
uint32_t file = 0;
|
||||
const char* path = 0;
|
||||
uint32_t s = create_temp(&file, &path);
|
||||
if (s != STATUS_SUCCESS) fail_status("create temp", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("create temp", s);
|
||||
|
||||
print("shared_mmap: creating temporary file ");
|
||||
print(path ? path : "<unknown>");
|
||||
@@ -145,16 +145,16 @@ int main(void) {
|
||||
|
||||
checked_write(file, gInitial, TEST_SIZE, "initial write");
|
||||
s = SysFlushFile(file);
|
||||
if (s != STATUS_SUCCESS) fail_status("initial flush", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("initial flush", s);
|
||||
|
||||
uint32_t mapping = 0;
|
||||
s = SysCreateFileMapping(file, SYS_VM_READWRITE, SYS_MAP_FLAG_NONE, TEST_SIZE, &mapping);
|
||||
if (s != STATUS_SUCCESS) fail_status("create mapping", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("create mapping", s);
|
||||
|
||||
uint8_t* view = 0;
|
||||
s = SysMapFile(mapping, 0, TEST_SIZE, SYS_MAP_ACCESS_READ | SYS_MAP_ACCESS_WRITE,
|
||||
SYS_MAP_FLAG_NONE, (void**)&view);
|
||||
if (s != STATUS_SUCCESS) fail_status("map shared write", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("map shared write", s);
|
||||
|
||||
for (size_t i = 128; i < 128 + 3000; ++i) {
|
||||
view[i] = (uint8_t)(0xA0u + (uint8_t)i);
|
||||
@@ -167,12 +167,12 @@ int main(void) {
|
||||
|
||||
SYS_FILE_CACHE_STATS beforeFlush;
|
||||
SYS_FILE_CACHE_STATS afterFlush;
|
||||
if (query_cache(&beforeFlush) != STATUS_SUCCESS) fail("pre-flush stats failed");
|
||||
if (query_cache(&beforeFlush) != NTLSTATUS_SUCCESS) fail("pre-flush stats failed");
|
||||
|
||||
s = SysFlushFile(file);
|
||||
if (s != STATUS_SUCCESS) fail_status("flush mapped writes", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("flush mapped writes", s);
|
||||
|
||||
if (query_cache(&afterFlush) != STATUS_SUCCESS) fail("post-flush stats failed");
|
||||
if (query_cache(&afterFlush) != NTLSTATUS_SUCCESS) fail("post-flush stats failed");
|
||||
if (afterFlush.MappedDirtyPages <= beforeFlush.MappedDirtyPages)
|
||||
fail("mapped dirty pages were not harvested");
|
||||
if (afterFlush.WritebackBytes <= beforeFlush.WritebackBytes)
|
||||
@@ -191,18 +191,18 @@ int main(void) {
|
||||
|
||||
s = SysFreeVm(view);
|
||||
view = 0;
|
||||
if (s != STATUS_SUCCESS) fail_status("unmap", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("unmap", s);
|
||||
|
||||
s = SysCloseHandle(mapping);
|
||||
mapping = 0;
|
||||
if (s != STATUS_SUCCESS) fail_status("close mapping", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("close mapping", s);
|
||||
|
||||
s = SysCloseHandle(file);
|
||||
file = 0;
|
||||
if (s != STATUS_SUCCESS) fail_status("close file", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("close file", s);
|
||||
|
||||
s = open_path(path, &file);
|
||||
if (s != STATUS_SUCCESS) fail_status("reopen", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("reopen", s);
|
||||
|
||||
checked_read(file, gReadback, TEST_SIZE, &got, "read after close");
|
||||
if (got != TEST_SIZE) fail("read after close size mismatch");
|
||||
@@ -210,7 +210,7 @@ int main(void) {
|
||||
|
||||
s = SysCloseHandle(file);
|
||||
file = 0;
|
||||
if (s != STATUS_SUCCESS) fail_status("close reopened", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("close reopened", s);
|
||||
delete_path(path);
|
||||
|
||||
print("shared_mmap: mapped-dirty-pages+=");
|
||||
|
||||
@@ -73,7 +73,7 @@ static void check_ipv4_resolve(void) {
|
||||
req.AddressSizeInOut = &addressSize;
|
||||
|
||||
uint32_t status = SysResolveHost(&req);
|
||||
if (status != STATUS_SUCCESS) fail_status("resolve ipv4", status);
|
||||
if (status != NTLSTATUS_SUCCESS) fail_status("resolve ipv4", status);
|
||||
if (addressSize != sizeof(address)) fail("resolve ipv4 size mismatch");
|
||||
if (address.Family != SYS_AF_INET || address.Size != sizeof(address)) fail("resolve ipv4 tag mismatch");
|
||||
if (address.Address[0] != 127 || address.Address[1] != 0 || address.Address[2] != 0 || address.Address[3] != 1)
|
||||
@@ -93,7 +93,7 @@ static void check_ipv6_resolve(void) {
|
||||
req.AddressSizeInOut = &addressSize;
|
||||
|
||||
uint32_t status = SysResolveHost(&req);
|
||||
if (status != STATUS_SUCCESS) fail_status("resolve ipv6", status);
|
||||
if (status != NTLSTATUS_SUCCESS) fail_status("resolve ipv6", status);
|
||||
if (addressSize != sizeof(address)) fail("resolve ipv6 size mismatch");
|
||||
if (address.Family != SYS_AF_INET6 || address.Size != sizeof(address)) fail("resolve ipv6 tag mismatch");
|
||||
for (int i = 0; i < 15; i++) {
|
||||
@@ -107,10 +107,10 @@ static void check_socket_address_validation(void) {
|
||||
uint32_t ipv4 = 0;
|
||||
uint32_t ipv6 = 0;
|
||||
uint32_t status = SysCreateSocket(SYS_AF_INET, SYS_SOCK_DGRAM, SYS_IPPROTO_UDP, &ipv4);
|
||||
if (status != STATUS_SUCCESS) fail_status("create ipv4 udp", status);
|
||||
if (status != NTLSTATUS_SUCCESS) fail_status("create ipv4 udp", status);
|
||||
|
||||
status = SysCreateSocket(SYS_AF_INET6, SYS_SOCK_DGRAM, SYS_IPPROTO_UDP, &ipv6);
|
||||
if (status != STATUS_SUCCESS) fail_status("create ipv6 udp", status);
|
||||
if (status != NTLSTATUS_SUCCESS) fail_status("create ipv6 udp", status);
|
||||
|
||||
SYS_SOCKET_ADDRESS ipv4Address;
|
||||
memset(&ipv4Address, 0, sizeof(ipv4Address));
|
||||
@@ -128,10 +128,16 @@ static void check_socket_address_validation(void) {
|
||||
SYS_SOCKET_ADDRESS badSize = ipv6Address;
|
||||
badSize.Size = sizeof(badSize) - 1;
|
||||
status = SysBindSocket(ipv6, &badSize, sizeof(badSize));
|
||||
if (status == STATUS_SUCCESS) fail("bind accepted wrong ipv6 size");
|
||||
if (status != NTLSTATUS_INVALID_PARAMETER) fail_status("bind wrong struct size", status);
|
||||
|
||||
status = SysBindSocket(ipv6, &ipv6Address, sizeof(ipv6Address) - 1);
|
||||
if (status != NTLSTATUS_BUFFER_TOO_SMALL) fail_status("bind short buffer size", status);
|
||||
|
||||
status = SysBindSocket(ipv6, &ipv6Address, sizeof(ipv6Address) + 1);
|
||||
if (status != NTLSTATUS_INVALID_PARAMETER) fail_status("bind oversized buffer size", status);
|
||||
|
||||
status = SysConnectSocket(ipv4, &ipv6Address, sizeof(ipv6Address));
|
||||
if (status == STATUS_SUCCESS) fail("connect accepted wrong address family");
|
||||
if (status == NTLSTATUS_SUCCESS) fail("connect accepted wrong address family");
|
||||
|
||||
SysCloseHandle(ipv4);
|
||||
SysCloseHandle(ipv6);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <ntlite/syscall.h>
|
||||
|
||||
// Prints one NUL-terminated string to the kernel console.
|
||||
@@ -70,50 +71,63 @@ static void expect_status(const char* what, uint32_t got, uint32_t expected) {
|
||||
static void check_fixed_stats(void) {
|
||||
size_t required = 0;
|
||||
uint32_t status = SysQueryKernelStats(SYS_KERNEL_STATS_SCHEDULER, 0, 0, &required);
|
||||
if (status != STATUS_SUCCESS) fail_status("scheduler size", status);
|
||||
if (status != NTLSTATUS_SUCCESS) fail_status("scheduler size", status);
|
||||
if (required != sizeof(SYS_SCHEDULER_STATS)) fail("scheduler required size mismatch");
|
||||
|
||||
uint8_t small[sizeof(SYS_SCHEDULER_STATS) - 1u];
|
||||
size_t smallRequired = 0;
|
||||
status = SysQueryKernelStats(SYS_KERNEL_STATS_SCHEDULER, small, sizeof(small), &smallRequired);
|
||||
expect_status("scheduler small buffer", status, STATUS_BUFFER_TOO_SMALL);
|
||||
expect_status("scheduler small buffer", status, NTLSTATUS_BUFFER_TOO_SMALL);
|
||||
if (smallRequired != sizeof(SYS_SCHEDULER_STATS)) fail("scheduler small required mismatch");
|
||||
|
||||
SYS_SCHEDULER_STATS scheduler;
|
||||
status = SysQueryKernelStats(SYS_KERNEL_STATS_SCHEDULER, &scheduler, sizeof(scheduler), 0);
|
||||
if (status != STATUS_SUCCESS) fail_status("scheduler exact", status);
|
||||
if (status != NTLSTATUS_SUCCESS) fail_status("scheduler exact", status);
|
||||
if (scheduler.Size != sizeof(scheduler)) fail("scheduler size field mismatch");
|
||||
if (scheduler.Version != SYS_STATS_VERSION) fail("scheduler version mismatch");
|
||||
|
||||
SYS_FILESYSTEM_STATS filesystem;
|
||||
status = SysQueryKernelStats(SYS_KERNEL_STATS_FILESYSTEM, &filesystem, sizeof(filesystem), 0);
|
||||
if (status != STATUS_SUCCESS) fail_status("filesystem exact", status);
|
||||
if (status != NTLSTATUS_SUCCESS) fail_status("filesystem exact", status);
|
||||
if (filesystem.Size != sizeof(filesystem)) fail("filesystem size field mismatch");
|
||||
if (filesystem.Version != SYS_STATS_VERSION) fail("filesystem version mismatch");
|
||||
|
||||
SYS_EXCEPTION_STATS exceptionStats;
|
||||
status = SysQueryKernelStats(SYS_KERNEL_STATS_EXCEPTION, &exceptionStats, sizeof(exceptionStats), 0);
|
||||
if (status != NTLSTATUS_SUCCESS) fail_status("exception exact", status);
|
||||
if (exceptionStats.Size != sizeof(exceptionStats)) fail("exception size field mismatch");
|
||||
if (exceptionStats.Version != SYS_STATS_VERSION) fail("exception version mismatch");
|
||||
}
|
||||
|
||||
// Verifies CPU stats use a size-reported trailing-record layout.
|
||||
static void check_cpu_stats(void) {
|
||||
size_t required = 0;
|
||||
uint32_t status = SysQueryKernelStats(SYS_KERNEL_STATS_CPU, 0, 0, &required);
|
||||
if (status != STATUS_SUCCESS) fail_status("cpu size", status);
|
||||
if (status != NTLSTATUS_SUCCESS) fail_status("cpu size", status);
|
||||
if (required < sizeof(SYS_CPU_STATS) + sizeof(SYS_CPU_STAT)) fail("cpu required size too small");
|
||||
|
||||
SYS_CPU_STATS headerOnly;
|
||||
size_t smallRequired = 0;
|
||||
status = SysQueryKernelStats(SYS_KERNEL_STATS_CPU, &headerOnly, sizeof(headerOnly), &smallRequired);
|
||||
expect_status("cpu header-only buffer", status, STATUS_BUFFER_TOO_SMALL);
|
||||
expect_status("cpu header-only buffer", status, NTLSTATUS_BUFFER_TOO_SMALL);
|
||||
if (smallRequired != required) fail("cpu small required mismatch");
|
||||
|
||||
void* buffer = 0;
|
||||
size_t pages = (required + 4095u) / 4096u;
|
||||
if (pages == 0) pages = 1;
|
||||
status = SysAllocVm(0, pages, SYS_VM_READWRITE, SYS_VM_FLAG_NONE, &buffer);
|
||||
if (status != STATUS_SUCCESS || !buffer) fail_status("cpu buffer alloc", status);
|
||||
SYS_ALLOC_VM_REQUEST allocReq;
|
||||
memset(&allocReq, 0, sizeof(allocReq));
|
||||
allocReq.Size = sizeof(allocReq);
|
||||
allocReq.PageCount = pages;
|
||||
allocReq.Protect = SYS_VM_READWRITE;
|
||||
allocReq.Flags = SYS_VM_FLAG_NONE;
|
||||
allocReq.BaseOut = &buffer;
|
||||
status = SysAllocVm(&allocReq);
|
||||
if (status != NTLSTATUS_SUCCESS || !buffer) fail_status("cpu buffer alloc", status);
|
||||
|
||||
SYS_CPU_STATS* cpu = (SYS_CPU_STATS*)buffer;
|
||||
status = SysQueryKernelStats(SYS_KERNEL_STATS_CPU, cpu, pages * 4096u, 0);
|
||||
if (status != STATUS_SUCCESS) {
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
SysFreeVm(buffer);
|
||||
fail_status("cpu exact", status);
|
||||
}
|
||||
|
||||
@@ -65,38 +65,49 @@ int main(void) {
|
||||
print("surface_invalid_rect: start\n");
|
||||
|
||||
uint32_t bad = 0;
|
||||
uint32_t s = SysCreateSurface(0, SURFACE_H, SYS_SURFACE_FORMAT_XRGB8888, SYS_SURFACE_FLAG_NONE, &bad);
|
||||
expect_status("zero width", s, STATUS_INVALID_PARAMETER);
|
||||
SYS_CREATE_SURFACE_REQUEST req;
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.Size = sizeof(req);
|
||||
req.Width = 0;
|
||||
req.Height = SURFACE_H;
|
||||
req.Format = SYS_SURFACE_FORMAT_XRGB8888;
|
||||
req.Flags = SYS_SURFACE_FLAG_NONE;
|
||||
req.HandleOut = &bad;
|
||||
uint32_t s = SysCreateSurface(&req);
|
||||
expect_status("zero width", s, NTLSTATUS_INVALID_PARAMETER);
|
||||
|
||||
s = SysCreateSurface(SURFACE_W, SURFACE_H, 0x9999u, SYS_SURFACE_FLAG_NONE, &bad);
|
||||
expect_status("bad format", s, STATUS_NOT_SUPPORTED);
|
||||
req.Width = SURFACE_W;
|
||||
req.Format = 0x9999u;
|
||||
s = SysCreateSurface(&req);
|
||||
expect_status("bad format", s, NTLSTATUS_NOT_SUPPORTED);
|
||||
|
||||
uint32_t surface = 0;
|
||||
s = SysCreateSurface(SURFACE_W, SURFACE_H, SYS_SURFACE_FORMAT_XRGB8888,
|
||||
SYS_SURFACE_FLAG_NONE, &surface);
|
||||
if (s != STATUS_SUCCESS) fail_status("create surface", s);
|
||||
req.Format = SYS_SURFACE_FORMAT_XRGB8888;
|
||||
req.HandleOut = &surface;
|
||||
s = SysCreateSurface(&req);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("create surface", s);
|
||||
|
||||
void* base = 0;
|
||||
uint32_t pitch = 0;
|
||||
s = SysMapSurface(surface, &base, &pitch);
|
||||
if (s != STATUS_SUCCESS) fail_status("map surface", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("map surface", s);
|
||||
if (!base || pitch < SURFACE_W * sizeof(uint32_t)) fail("invalid mapping");
|
||||
|
||||
s = SysPresentSurface(surface, 0, 1);
|
||||
expect_status("null rect array with nonzero count", s, STATUS_INVALID_PARAMETER);
|
||||
expect_status("null rect array with nonzero count", s, NTLSTATUS_INVALID_PARAMETER);
|
||||
|
||||
DISPLAY_RECT rects[SYS_SURFACE_MAX_RECTS + 1];
|
||||
memset(rects, 0, sizeof(rects));
|
||||
s = SysPresentSurface(surface, rects, SYS_SURFACE_MAX_RECTS + 1);
|
||||
expect_status("too many rects", s, STATUS_INVALID_PARAMETER);
|
||||
expect_status("too many rects", s, NTLSTATUS_INVALID_PARAMETER);
|
||||
|
||||
DISPLAY_RECT clipped = { -8, -8, 24, 24 };
|
||||
s = SysPresentSurface(surface, &clipped, 1);
|
||||
if (s != STATUS_SUCCESS) fail_status("present clipped rect", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("present clipped rect", s);
|
||||
|
||||
DISPLAY_RECT empty = { 10000, 10000, 16, 16 };
|
||||
s = SysPresentSurface(surface, &empty, 1);
|
||||
if (s != STATUS_SUCCESS) fail_status("present empty clipped rect", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("present empty clipped rect", s);
|
||||
|
||||
SysCloseHandle(surface);
|
||||
print("surface_invalid_rect: PASS\n");
|
||||
|
||||
@@ -80,7 +80,7 @@ static void worker_main(uintptr_t arg) {
|
||||
|
||||
DISPLAY_RECT rect = { 0, (int32_t)y0, (int32_t)SURFACE_W, (int32_t)h };
|
||||
uint32_t s = SysPresentSurface(st->Surface, &rect, 1);
|
||||
if (s != STATUS_SUCCESS) {
|
||||
if (s != NTLSTATUS_SUCCESS) {
|
||||
st->Status = s;
|
||||
SysExitThread(1);
|
||||
}
|
||||
@@ -88,7 +88,7 @@ static void worker_main(uintptr_t arg) {
|
||||
SysYield();
|
||||
}
|
||||
|
||||
st->Status = STATUS_SUCCESS;
|
||||
st->Status = NTLSTATUS_SUCCESS;
|
||||
SysExitThread(0);
|
||||
}
|
||||
|
||||
@@ -96,14 +96,21 @@ int main(void) {
|
||||
print("surface_multithread_present: start\n");
|
||||
|
||||
uint32_t surface = 0;
|
||||
uint32_t s = SysCreateSurface(SURFACE_W, SURFACE_H, SYS_SURFACE_FORMAT_XRGB8888,
|
||||
SYS_SURFACE_FLAG_NONE, &surface);
|
||||
if (s != STATUS_SUCCESS) fail_status("create surface", s);
|
||||
SYS_CREATE_SURFACE_REQUEST req;
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.Size = sizeof(req);
|
||||
req.Width = SURFACE_W;
|
||||
req.Height = SURFACE_H;
|
||||
req.Format = SYS_SURFACE_FORMAT_XRGB8888;
|
||||
req.Flags = SYS_SURFACE_FLAG_NONE;
|
||||
req.HandleOut = &surface;
|
||||
uint32_t s = SysCreateSurface(&req);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("create surface", s);
|
||||
|
||||
void* base = 0;
|
||||
uint32_t pitch = 0;
|
||||
s = SysMapSurface(surface, &base, &pitch);
|
||||
if (s != STATUS_SUCCESS) fail_status("map surface", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("map surface", s);
|
||||
if (!base || pitch < SURFACE_W * sizeof(uint32_t)) fail("invalid mapping");
|
||||
|
||||
uint32_t handles[THREAD_COUNT];
|
||||
@@ -117,7 +124,7 @@ int main(void) {
|
||||
gWorkers[i].Surface = surface;
|
||||
gWorkers[i].Base = (uint8_t*)base;
|
||||
gWorkers[i].Pitch = pitch;
|
||||
gWorkers[i].Status = STATUS_PENDING;
|
||||
gWorkers[i].Status = NTLSTATUS_PENDING;
|
||||
SYS_CREATE_THREAD_REQUEST req = {
|
||||
(uintptr_t)worker_main,
|
||||
(uintptr_t)&gWorkers[i],
|
||||
@@ -127,17 +134,17 @@ int main(void) {
|
||||
&tids[i]
|
||||
};
|
||||
s = SysCreateThread(&req);
|
||||
if (s != STATUS_SUCCESS) fail_status("create thread", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("create thread", s);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < THREAD_COUNT; ++i) {
|
||||
s = SysWait(handles[i], SYS_WAIT_FLAG_NONE);
|
||||
if (s != STATUS_SUCCESS) fail_status("wait thread", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("wait thread", s);
|
||||
SysCloseHandle(handles[i]);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < THREAD_COUNT; ++i) {
|
||||
if (gWorkers[i].Status != STATUS_SUCCESS) {
|
||||
if (gWorkers[i].Status != NTLSTATUS_SUCCESS) {
|
||||
print("surface_multithread_present: worker ");
|
||||
print_u64(i);
|
||||
print(" status=");
|
||||
|
||||
@@ -53,21 +53,28 @@ int main(void) {
|
||||
print("surface_smoke: start\n");
|
||||
|
||||
uint32_t surface = 0;
|
||||
uint32_t s = SysCreateSurface(SURFACE_W, SURFACE_H, SYS_SURFACE_FORMAT_XRGB8888,
|
||||
SYS_SURFACE_FLAG_NONE, &surface);
|
||||
if (s != STATUS_SUCCESS) fail_status("create surface", s);
|
||||
SYS_CREATE_SURFACE_REQUEST req;
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.Size = sizeof(req);
|
||||
req.Width = SURFACE_W;
|
||||
req.Height = SURFACE_H;
|
||||
req.Format = SYS_SURFACE_FORMAT_XRGB8888;
|
||||
req.Flags = SYS_SURFACE_FLAG_NONE;
|
||||
req.HandleOut = &surface;
|
||||
uint32_t s = SysCreateSurface(&req);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("create surface", s);
|
||||
if (!surface) fail("surface handle is zero");
|
||||
|
||||
void* base = 0;
|
||||
uint32_t pitch = 0;
|
||||
s = SysMapSurface(surface, &base, &pitch);
|
||||
if (s != STATUS_SUCCESS) fail_status("map surface", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("map surface", s);
|
||||
if (!base || pitch < SURFACE_W * sizeof(uint32_t)) fail("invalid mapping");
|
||||
|
||||
SYS_SURFACE_DESC desc;
|
||||
memset(&desc, 0, sizeof(desc));
|
||||
s = SysQuerySurface(surface, &desc);
|
||||
if (s != STATUS_SUCCESS) fail_status("query surface", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("query surface", s);
|
||||
if (desc.Width != SURFACE_W || desc.Height != SURFACE_H) fail("query dimensions mismatch");
|
||||
if (desc.PitchBytes != pitch || desc.Format != SYS_SURFACE_FORMAT_XRGB8888) fail("query metadata mismatch");
|
||||
if (desc.Base != base) fail("query base mismatch");
|
||||
@@ -81,10 +88,10 @@ int main(void) {
|
||||
|
||||
DISPLAY_RECT rect = { 0, 0, (int32_t)SURFACE_W, (int32_t)SURFACE_H };
|
||||
s = SysPresentSurface(surface, &rect, 1);
|
||||
if (s != STATUS_SUCCESS) fail_status("present surface", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("present surface", s);
|
||||
|
||||
s = SysPresentSurface(surface, 0, 0);
|
||||
if (s != STATUS_SUCCESS) fail_status("present full surface", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("present full surface", s);
|
||||
|
||||
SysCloseHandle(surface);
|
||||
print("surface_smoke: PASS\n");
|
||||
|
||||
@@ -70,12 +70,12 @@ static void fail_status(const char* what, uint32_t status) {
|
||||
static void check_tick_contract(void) {
|
||||
uint64_t frequency = 0;
|
||||
uint32_t s = SysGetTickFrequency(&frequency);
|
||||
if (s != STATUS_SUCCESS) fail_status("query tick frequency", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("query tick frequency", s);
|
||||
if (!frequency) fail("tick frequency was zero");
|
||||
|
||||
uint64_t t0 = SysGetTick();
|
||||
s = SysSleep(1);
|
||||
if (s != STATUS_SUCCESS) fail_status("sleep", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("sleep", s);
|
||||
|
||||
uint64_t t1 = SysGetTick();
|
||||
if (t1 < t0) fail("tick moved backwards across sleep");
|
||||
@@ -96,14 +96,14 @@ static void check_exit_code_contract(void) {
|
||||
};
|
||||
|
||||
uint32_t s = SysCreateProcess(&req);
|
||||
if (s != STATUS_SUCCESS) fail_status("create child", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("create child", s);
|
||||
|
||||
s = SysWait(child, SYS_WAIT_FLAG_NONE);
|
||||
if (s != STATUS_SUCCESS) fail_status("wait child", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("wait child", s);
|
||||
|
||||
int32_t exitCode = 0;
|
||||
s = SysGetProcessExitCode(child, &exitCode);
|
||||
if (s != STATUS_SUCCESS) fail_status("query child exit code", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("query child exit code", s);
|
||||
if (exitCode != CHILD_EXIT_CODE) fail("child exit code mismatch");
|
||||
|
||||
SysCloseHandle(child);
|
||||
|
||||
@@ -72,14 +72,14 @@ static uint32_t set_timer(uint32_t timer, uint64_t dueMs, uint64_t periodMs) {
|
||||
// Verifies timer request validation paths.
|
||||
static void test_validation(void) {
|
||||
uint32_t timer = 0;
|
||||
expect_status("create timer null", SysCreateTimer((uint32_t*)0), STATUS_INVALID_PARAMETER);
|
||||
expect_status("create timer null", SysCreateTimer((uint32_t*)0), NTLSTATUS_INVALID_PARAMETER);
|
||||
|
||||
uint32_t s = SysCreateTimer(&timer);
|
||||
if (s != STATUS_SUCCESS) fail_status("create validation timer", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("create validation timer", s);
|
||||
|
||||
expect_status("set timer null", SysSetTimer((const SYS_SET_TIMER_REQUEST*)0), STATUS_INVALID_PARAMETER);
|
||||
expect_status("cancel invalid", SysCancelTimer(0xdeadbeefu), STATUS_INVALID_HANDLE);
|
||||
expect_status("wait invalid", SysWaitSingle(0xdeadbeefu, SYS_WAIT_FLAG_NONE, 0), STATUS_INVALID_HANDLE);
|
||||
expect_status("set timer null", SysSetTimer((const SYS_SET_TIMER_REQUEST*)0), NTLSTATUS_INVALID_PARAMETER);
|
||||
expect_status("cancel invalid", SysCancelTimer(0xdeadbeefu), NTLSTATUS_INVALID_HANDLE);
|
||||
expect_status("wait invalid", SysWaitSingle(0xdeadbeefu, SYS_WAIT_FLAG_NONE, 0), NTLSTATUS_INVALID_HANDLE);
|
||||
|
||||
SYS_SET_TIMER_REQUEST req = {
|
||||
0,
|
||||
@@ -88,11 +88,11 @@ static void test_validation(void) {
|
||||
1,
|
||||
0,
|
||||
};
|
||||
expect_status("set bad size", SysSetTimer(&req), STATUS_INVALID_PARAMETER);
|
||||
expect_status("set bad size", SysSetTimer(&req), NTLSTATUS_INVALID_PARAMETER);
|
||||
|
||||
req.Size = sizeof(req);
|
||||
req.Flags = 1;
|
||||
expect_status("set bad flags", SysSetTimer(&req), STATUS_INVALID_PARAMETER);
|
||||
expect_status("set bad flags", SysSetTimer(&req), NTLSTATUS_INVALID_PARAMETER);
|
||||
|
||||
SysCloseHandle(timer);
|
||||
}
|
||||
@@ -101,16 +101,16 @@ static void test_validation(void) {
|
||||
static void test_one_shot(void) {
|
||||
uint32_t timer = 0;
|
||||
uint32_t s = SysCreateTimer(&timer);
|
||||
if (s != STATUS_SUCCESS) fail_status("create one-shot timer", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("create one-shot timer", s);
|
||||
|
||||
expect_status("unset immediate wait", SysWaitSingle(timer, SYS_WAIT_FLAG_NONE, 0), STATUS_TIMEOUT);
|
||||
expect_status("unset immediate wait", SysWaitSingle(timer, SYS_WAIT_FLAG_NONE, 0), NTLSTATUS_TIMEOUT);
|
||||
s = set_timer(timer, 20, 0);
|
||||
if (s != STATUS_SUCCESS) fail_status("set one-shot", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("set one-shot", s);
|
||||
|
||||
s = SysWaitSingle(timer, SYS_WAIT_FLAG_NONE, SYS_WAIT_TIMEOUT_INFINITE);
|
||||
if (s != STATUS_SUCCESS) fail_status("wait one-shot", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("wait one-shot", s);
|
||||
|
||||
expect_status("one-shot consumed", SysWaitSingle(timer, SYS_WAIT_FLAG_NONE, 0), STATUS_TIMEOUT);
|
||||
expect_status("one-shot consumed", SysWaitSingle(timer, SYS_WAIT_FLAG_NONE, 0), NTLSTATUS_TIMEOUT);
|
||||
SysCloseHandle(timer);
|
||||
}
|
||||
|
||||
@@ -118,24 +118,24 @@ static void test_one_shot(void) {
|
||||
static void test_cancel(void) {
|
||||
uint32_t timer = 0;
|
||||
uint32_t s = SysCreateTimer(&timer);
|
||||
if (s != STATUS_SUCCESS) fail_status("create cancel timer", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("create cancel timer", s);
|
||||
|
||||
s = set_timer(timer, 100, 0);
|
||||
if (s != STATUS_SUCCESS) fail_status("set cancel timer", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("set cancel timer", s);
|
||||
s = SysCancelTimer(timer);
|
||||
if (s != STATUS_SUCCESS) fail_status("cancel timer", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("cancel timer", s);
|
||||
|
||||
expect_status("cancelled timer wait", SysWaitSingle(timer, SYS_WAIT_FLAG_NONE, 30), STATUS_TIMEOUT);
|
||||
expect_status("cancelled timer wait", SysWaitSingle(timer, SYS_WAIT_FLAG_NONE, 30), NTLSTATUS_TIMEOUT);
|
||||
|
||||
s = set_timer(timer, 0, 0);
|
||||
if (s != STATUS_SUCCESS) fail_status("set immediate", s);
|
||||
expect_status("immediate timer wait", SysWaitSingle(timer, SYS_WAIT_FLAG_NONE, 0), STATUS_SUCCESS);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("set immediate", s);
|
||||
expect_status("immediate timer wait", SysWaitSingle(timer, SYS_WAIT_FLAG_NONE, 0), NTLSTATUS_SUCCESS);
|
||||
|
||||
s = set_timer(timer, 0, 0);
|
||||
if (s != STATUS_SUCCESS) fail_status("set immediate before cancel", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("set immediate before cancel", s);
|
||||
s = SysCancelTimer(timer);
|
||||
if (s != STATUS_SUCCESS) fail_status("cancel signaled", s);
|
||||
expect_status("cancel clears signal", SysWaitSingle(timer, SYS_WAIT_FLAG_NONE, 0), STATUS_TIMEOUT);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("cancel signaled", s);
|
||||
expect_status("cancel clears signal", SysWaitSingle(timer, SYS_WAIT_FLAG_NONE, 0), NTLSTATUS_TIMEOUT);
|
||||
|
||||
SysCloseHandle(timer);
|
||||
}
|
||||
@@ -144,15 +144,15 @@ static void test_cancel(void) {
|
||||
static void test_reset_changes_deadline(void) {
|
||||
uint32_t timer = 0;
|
||||
uint32_t s = SysCreateTimer(&timer);
|
||||
if (s != STATUS_SUCCESS) fail_status("create reset timer", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("create reset timer", s);
|
||||
|
||||
s = set_timer(timer, 100, 0);
|
||||
if (s != STATUS_SUCCESS) fail_status("set reset timer long", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("set reset timer long", s);
|
||||
s = set_timer(timer, 20, 0);
|
||||
if (s != STATUS_SUCCESS) fail_status("set reset timer short", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("set reset timer short", s);
|
||||
|
||||
s = SysWaitSingle(timer, SYS_WAIT_FLAG_NONE, 80);
|
||||
if (s != STATUS_SUCCESS) fail_status("wait reset timer", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("wait reset timer", s);
|
||||
|
||||
SysCloseHandle(timer);
|
||||
}
|
||||
@@ -161,18 +161,18 @@ static void test_reset_changes_deadline(void) {
|
||||
static void test_periodic(void) {
|
||||
uint32_t timer = 0;
|
||||
uint32_t s = SysCreateTimer(&timer);
|
||||
if (s != STATUS_SUCCESS) fail_status("create periodic timer", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("create periodic timer", s);
|
||||
|
||||
s = set_timer(timer, 10, 20);
|
||||
if (s != STATUS_SUCCESS) fail_status("set periodic timer", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("set periodic timer", s);
|
||||
s = SysWaitSingle(timer, SYS_WAIT_FLAG_NONE, 80);
|
||||
if (s != STATUS_SUCCESS) fail_status("wait periodic first", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("wait periodic first", s);
|
||||
s = SysWaitSingle(timer, SYS_WAIT_FLAG_NONE, 80);
|
||||
if (s != STATUS_SUCCESS) fail_status("wait periodic second", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("wait periodic second", s);
|
||||
|
||||
s = SysCancelTimer(timer);
|
||||
if (s != STATUS_SUCCESS) fail_status("cancel periodic", s);
|
||||
expect_status("periodic cancelled wait", SysWaitSingle(timer, SYS_WAIT_FLAG_NONE, 30), STATUS_TIMEOUT);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("cancel periodic", s);
|
||||
expect_status("periodic cancelled wait", SysWaitSingle(timer, SYS_WAIT_FLAG_NONE, 30), NTLSTATUS_TIMEOUT);
|
||||
|
||||
SysCloseHandle(timer);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
// Win32 vectored exception smoke test. This file verifies Win32 VEH policy over the native exception runtime.
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <intrin.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <ntlite/syscall.h>
|
||||
|
||||
static volatile uint32_t gFirstHits;
|
||||
|
||||
static volatile uint32_t gTailHits;
|
||||
static volatile uint32_t gContinueHits;
|
||||
static volatile uint32_t gOnlyHits;
|
||||
static volatile uint32_t gRaisedHits;
|
||||
|
||||
// Prints one NUL-terminated string to the kernel console.
|
||||
static void print(const char* s) {
|
||||
SYS_WRITE_CONSOLE_REQUEST req = { SysSvFromCstr(s) };
|
||||
SysWriteConsole(&req);
|
||||
}
|
||||
|
||||
// Prints one unsigned integer.
|
||||
static void print_u64(uint64_t v) {
|
||||
char buf[32];
|
||||
int i = 0;
|
||||
if (v == 0) {
|
||||
print("0");
|
||||
return;
|
||||
}
|
||||
while (v && i < (int)sizeof(buf)) {
|
||||
buf[i++] = (char)('0' + (v % 10));
|
||||
v /= 10;
|
||||
}
|
||||
while (i--) {
|
||||
char c = buf[i];
|
||||
SYS_WRITE_CONSOLE_REQUEST req = { SysSvFromParts(&c, 1) };
|
||||
SysWriteConsole(&req);
|
||||
}
|
||||
}
|
||||
|
||||
// Terminates the current process.
|
||||
static void exit_now(int32_t code) {
|
||||
for (;;) SysExitProcess(code);
|
||||
}
|
||||
|
||||
// Fails the test with one message.
|
||||
static void fail(const char* message) {
|
||||
print("win32_exception_smoke: ");
|
||||
print(message);
|
||||
print("\n");
|
||||
exit_now(1);
|
||||
}
|
||||
|
||||
// Fails the test with one integer value.
|
||||
static void fail_value(const char* message, uint64_t value) {
|
||||
print("win32_exception_smoke: ");
|
||||
print(message);
|
||||
print(" value=");
|
||||
print_u64(value);
|
||||
print("\n");
|
||||
exit_now(1);
|
||||
}
|
||||
|
||||
// Verifies the Win32 exception pointers contain a breakpoint and editable context.
|
||||
static void verify_breakpoint(EXCEPTION_POINTERS* info) {
|
||||
if (!info || !info->ExceptionRecord || !info->ContextRecord)
|
||||
fail("handler received null exception pointers");
|
||||
if (info->ExceptionRecord->ExceptionCode != EXCEPTION_BREAKPOINT)
|
||||
fail_value("handler received unexpected exception code", info->ExceptionRecord->ExceptionCode);
|
||||
if (!info->ExceptionRecord->ExceptionAddress)
|
||||
fail("handler received null exception address");
|
||||
if (!info->ContextRecord->Rip || !info->ContextRecord->Rsp)
|
||||
fail("handler received empty context");
|
||||
}
|
||||
|
||||
// Handles the first breakpoint before later exception handlers can observe it.
|
||||
static LONG first_continue_handler(EXCEPTION_POINTERS* info) {
|
||||
verify_breakpoint(info);
|
||||
gFirstHits++;
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
|
||||
// Records an exception pass and asks Win32 policy to keep searching.
|
||||
static LONG tail_search_handler(EXCEPTION_POINTERS* info) {
|
||||
verify_breakpoint(info);
|
||||
gTailHits++;
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
// Continues a breakpoint after the exception-handler list declines it.
|
||||
static LONG continue_handler(EXCEPTION_POINTERS* info) {
|
||||
verify_breakpoint(info);
|
||||
gContinueHits++;
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
|
||||
// Handles a breakpoint after earlier handlers have been removed.
|
||||
static LONG only_continue_handler(EXCEPTION_POINTERS* info) {
|
||||
verify_breakpoint(info);
|
||||
gOnlyHits++;
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
|
||||
|
||||
// Handles a user-raised Win32 exception and verifies parameter translation.
|
||||
static LONG raised_continue_handler(EXCEPTION_POINTERS* info) {
|
||||
if (!info || !info->ExceptionRecord || !info->ContextRecord)
|
||||
fail("raised handler received null exception pointers");
|
||||
if (info->ExceptionRecord->ExceptionCode != 0xE1111002u)
|
||||
fail_value("raised handler received unexpected exception code", info->ExceptionRecord->ExceptionCode);
|
||||
if (info->ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE)
|
||||
fail("raised handler received unexpected noncontinuable flag");
|
||||
if (info->ExceptionRecord->NumberParameters != 2)
|
||||
fail_value("raised handler received wrong parameter count", info->ExceptionRecord->NumberParameters);
|
||||
if (info->ExceptionRecord->ExceptionInformation[0] != 0x1122u ||
|
||||
info->ExceptionRecord->ExceptionInformation[1] != 0x3344u)
|
||||
fail("raised handler received wrong parameters");
|
||||
gRaisedHits++;
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
|
||||
// Verifies one successful remove operation.
|
||||
static void expect_remove(const char* what, unsigned long removed) {
|
||||
if (!removed)
|
||||
fail(what);
|
||||
}
|
||||
|
||||
// Runs the Win32 vectored exception smoke test.
|
||||
int main(void) {
|
||||
print("win32_exception_smoke: start\n");
|
||||
|
||||
if (AddVectoredExceptionHandler(0, 0))
|
||||
fail("null exception handler was accepted");
|
||||
if (GetLastError() != 87)
|
||||
fail_value("null handler did not set ERROR_INVALID_PARAMETER", GetLastError());
|
||||
|
||||
void* tail = AddVectoredExceptionHandler(0, tail_search_handler);
|
||||
void* first = AddVectoredExceptionHandler(1, first_continue_handler);
|
||||
if (!tail || !first)
|
||||
fail("exception handler registration failed");
|
||||
|
||||
__debugbreak();
|
||||
if (gFirstHits != 1 || gTailHits != 0)
|
||||
fail("first vectored handler did not run before tail handler");
|
||||
|
||||
expect_remove("remove first failed", RemoveVectoredExceptionHandler(first));
|
||||
|
||||
void* cont = AddVectoredContinueHandler(0, continue_handler);
|
||||
if (!cont)
|
||||
fail("continue handler registration failed");
|
||||
|
||||
__debugbreak();
|
||||
if (gTailHits != 1 || gContinueHits != 1)
|
||||
fail("continue handler did not run after exception search");
|
||||
|
||||
expect_remove("remove tail failed", RemoveVectoredExceptionHandler(tail));
|
||||
expect_remove("remove continue failed", RemoveVectoredContinueHandler(cont));
|
||||
if (RemoveVectoredContinueHandler(cont))
|
||||
fail("second continue-handler removal succeeded unexpectedly");
|
||||
if (GetLastError() != 6)
|
||||
fail_value("second removal did not set ERROR_INVALID_HANDLE", GetLastError());
|
||||
|
||||
void* only = AddVectoredExceptionHandler(0, only_continue_handler);
|
||||
if (!only)
|
||||
fail("single handler registration failed");
|
||||
|
||||
__debugbreak();
|
||||
if (gOnlyHits != 1)
|
||||
fail("single vectored exception handler did not continue execution");
|
||||
|
||||
expect_remove("remove single handler failed", RemoveVectoredExceptionHandler(only));
|
||||
|
||||
void* raised = AddVectoredExceptionHandler(1, raised_continue_handler);
|
||||
if (!raised)
|
||||
fail("raised handler registration failed");
|
||||
ULONG_PTR args[2] = { 0x1122u, 0x3344u };
|
||||
RaiseException(0xE1111002u, 0, 2, args);
|
||||
if (gRaisedHits != 1)
|
||||
fail("raised vectored handler did not continue execution");
|
||||
expect_remove("remove raised handler failed", RemoveVectoredExceptionHandler(raised));
|
||||
|
||||
print("win32_exception_smoke: PASS\n");
|
||||
exit_now(0);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
// Win32 runtime SEH smoke test. This file verifies explicit runtime frames before compiler SEH exists.
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <intrin.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <ntlite/syscall.h>
|
||||
|
||||
typedef LONG (*PRTL_EXCEPTION_FRAME_HANDLER)(EXCEPTION_POINTERS* ExceptionInfo, PVOID UserContext);
|
||||
|
||||
typedef struct _RTL_EXCEPTION_FRAME {
|
||||
DWORD Size;
|
||||
DWORD Flags;
|
||||
struct _RTL_EXCEPTION_FRAME* Previous;
|
||||
PRTL_EXCEPTION_FRAME_HANDLER Handler;
|
||||
PVOID UserContext;
|
||||
} RTL_EXCEPTION_FRAME;
|
||||
|
||||
PVOID RtlPushExceptionFrame(RTL_EXCEPTION_FRAME* Frame,
|
||||
PRTL_EXCEPTION_FRAME_HANDLER Handler,
|
||||
PVOID UserContext);
|
||||
BOOL RtlPopExceptionFrame(RTL_EXCEPTION_FRAME* Frame);
|
||||
|
||||
static volatile uint32_t gTopHits;
|
||||
|
||||
static volatile uint32_t gBottomHits;
|
||||
static volatile uint32_t gVehHits;
|
||||
|
||||
// Prints one NUL-terminated string to the kernel console.
|
||||
static void print(const char* s) {
|
||||
SYS_WRITE_CONSOLE_REQUEST req = { SysSvFromCstr(s) };
|
||||
SysWriteConsole(&req);
|
||||
}
|
||||
|
||||
// Prints one unsigned integer.
|
||||
static void print_u64(uint64_t v) {
|
||||
char buf[32];
|
||||
int i = 0;
|
||||
if (v == 0) {
|
||||
print("0");
|
||||
return;
|
||||
}
|
||||
while (v && i < (int)sizeof(buf)) {
|
||||
buf[i++] = (char)('0' + (v % 10));
|
||||
v /= 10;
|
||||
}
|
||||
while (i--) {
|
||||
char c = buf[i];
|
||||
SYS_WRITE_CONSOLE_REQUEST req = { SysSvFromParts(&c, 1) };
|
||||
SysWriteConsole(&req);
|
||||
}
|
||||
}
|
||||
|
||||
// Terminates the current process.
|
||||
static void exit_now(int32_t code) {
|
||||
for (;;) SysExitProcess(code);
|
||||
}
|
||||
|
||||
// Fails the test with one message.
|
||||
static void fail(const char* message) {
|
||||
print("win32_seh_smoke: ");
|
||||
print(message);
|
||||
print("\n");
|
||||
exit_now(1);
|
||||
}
|
||||
|
||||
// Fails the test with one integer value.
|
||||
static void fail_value(const char* message, uint64_t value) {
|
||||
print("win32_seh_smoke: ");
|
||||
print(message);
|
||||
print(" value=");
|
||||
print_u64(value);
|
||||
print("\n");
|
||||
exit_now(1);
|
||||
}
|
||||
|
||||
// Verifies a breakpoint exception and editable context.
|
||||
static void verify_breakpoint(EXCEPTION_POINTERS* info) {
|
||||
if (!info || !info->ExceptionRecord || !info->ContextRecord)
|
||||
fail("handler received null exception pointers");
|
||||
if (info->ExceptionRecord->ExceptionCode != EXCEPTION_BREAKPOINT)
|
||||
fail_value("handler received unexpected exception code", info->ExceptionRecord->ExceptionCode);
|
||||
if (!info->ContextRecord->Rip || !info->ContextRecord->Rsp)
|
||||
fail("handler received empty context");
|
||||
}
|
||||
|
||||
// Handles the first breakpoint from the newest runtime SEH frame.
|
||||
static LONG top_frame_handler(EXCEPTION_POINTERS* info, void* userContext) {
|
||||
verify_breakpoint(info);
|
||||
if (userContext != (void*)0x1111u)
|
||||
fail("top frame context was not preserved");
|
||||
gTopHits++;
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
|
||||
// Handles a breakpoint after the top frame is removed.
|
||||
static LONG bottom_frame_handler(EXCEPTION_POINTERS* info, void* userContext) {
|
||||
verify_breakpoint(info);
|
||||
if (userContext != (void*)0x2222u)
|
||||
fail("bottom frame context was not preserved");
|
||||
gBottomHits++;
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
|
||||
// Proves VEH still sees exceptions before the runtime SEH chain.
|
||||
static LONG veh_search_handler(EXCEPTION_POINTERS* info) {
|
||||
verify_breakpoint(info);
|
||||
gVehHits++;
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
// Runs the runtime-registered Win32 SEH smoke test.
|
||||
int main(void) {
|
||||
print("win32_seh_smoke: start\n");
|
||||
|
||||
if (RtlPushExceptionFrame(NULL, top_frame_handler, NULL))
|
||||
fail("null frame was accepted");
|
||||
if (GetLastError() != 87)
|
||||
fail_value("null frame did not set ERROR_INVALID_PARAMETER", GetLastError());
|
||||
|
||||
RTL_EXCEPTION_FRAME bottom;
|
||||
RTL_EXCEPTION_FRAME top;
|
||||
if (!RtlPushExceptionFrame(&bottom, bottom_frame_handler, (void*)0x2222u))
|
||||
fail("bottom SEH frame registration failed");
|
||||
if (!RtlPushExceptionFrame(&top, top_frame_handler, (void*)0x1111u))
|
||||
fail("top SEH frame registration failed");
|
||||
|
||||
if (RtlPopExceptionFrame(&bottom))
|
||||
fail("non-top SEH frame pop succeeded unexpectedly");
|
||||
if (GetLastError() != 87)
|
||||
fail_value("non-top pop did not set ERROR_INVALID_PARAMETER", GetLastError());
|
||||
|
||||
__debugbreak();
|
||||
if (gTopHits != 1 || gBottomHits != 0)
|
||||
fail("top SEH frame did not run before bottom frame");
|
||||
|
||||
if (!RtlPopExceptionFrame(&top))
|
||||
fail("top SEH frame pop failed");
|
||||
|
||||
void* veh = AddVectoredExceptionHandler(0, veh_search_handler);
|
||||
if (!veh)
|
||||
fail("VEH registration failed");
|
||||
|
||||
__debugbreak();
|
||||
if (gVehHits != 1 || gBottomHits != 1)
|
||||
fail("VEH did not search before SEH handled the exception");
|
||||
|
||||
if (!RemoveVectoredExceptionHandler(veh))
|
||||
fail("VEH removal failed");
|
||||
if (!RtlPopExceptionFrame(&bottom))
|
||||
fail("bottom SEH frame pop failed");
|
||||
|
||||
print("win32_seh_smoke: PASS\n");
|
||||
exit_now(0);
|
||||
return 0;
|
||||
}
|
||||
@@ -119,7 +119,7 @@ static void sender_thread(uintptr_t arg) {
|
||||
msg.Type = TEST_MESSAGE_WAKE;
|
||||
msg.Param[0] = TEST_WAKE_VALUE;
|
||||
ctx->Status = send_queue(ctx->Queue, &msg, SYS_WAIT_TIMEOUT_INFINITE);
|
||||
SysExitThread(ctx->Status == STATUS_SUCCESS ? 0 : 1);
|
||||
SysExitThread(ctx->Status == NTLSTATUS_SUCCESS ? 0 : 1);
|
||||
}
|
||||
|
||||
// Fills one queue with immediate sends until the queue reports would-block.
|
||||
@@ -131,9 +131,9 @@ static void fill_until_would_block(uint32_t queue) {
|
||||
for (; sends < TEST_FILL_LIMIT; sends++) {
|
||||
msg.Param[0] = sends;
|
||||
uint32_t s = send_queue(queue, &msg, 0);
|
||||
if (s == STATUS_WOULD_BLOCK)
|
||||
if (s == NTLSTATUS_WOULD_BLOCK)
|
||||
break;
|
||||
if (s != STATUS_SUCCESS)
|
||||
if (s != NTLSTATUS_SUCCESS)
|
||||
fail_status("fill send", s);
|
||||
}
|
||||
|
||||
@@ -145,20 +145,20 @@ static void fill_until_would_block(uint32_t queue) {
|
||||
static void test_queue_empty_and_full(void) {
|
||||
uint32_t queue = 0;
|
||||
uint32_t s = SysCreateQueue(&queue);
|
||||
if (s != STATUS_SUCCESS) fail_status("create empty queue", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("create empty queue", s);
|
||||
|
||||
TEST_QUEUE_MESSAGE msg = {0};
|
||||
expect_status("empty nonblocking receive", recv_queue(queue, &msg, 0), STATUS_WOULD_BLOCK);
|
||||
expect_status("empty finite receive", recv_queue(queue, &msg, 20), STATUS_TIMEOUT);
|
||||
expect_status("empty nonblocking receive", recv_queue(queue, &msg, 0), NTLSTATUS_WOULD_BLOCK);
|
||||
expect_status("empty finite receive", recv_queue(queue, &msg, 20), NTLSTATUS_TIMEOUT);
|
||||
SysCloseHandle(queue);
|
||||
|
||||
queue = 0;
|
||||
s = SysCreateQueue(&queue);
|
||||
if (s != STATUS_SUCCESS) fail_status("create full queue", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("create full queue", s);
|
||||
|
||||
fill_until_would_block(queue);
|
||||
expect_status("full nonblocking send", send_queue(queue, &msg, 0), STATUS_WOULD_BLOCK);
|
||||
expect_status("full finite send", send_queue(queue, &msg, 20), STATUS_TIMEOUT);
|
||||
expect_status("full nonblocking send", send_queue(queue, &msg, 0), NTLSTATUS_WOULD_BLOCK);
|
||||
expect_status("full finite send", send_queue(queue, &msg, 20), NTLSTATUS_TIMEOUT);
|
||||
SysCloseHandle(queue);
|
||||
}
|
||||
|
||||
@@ -166,9 +166,9 @@ static void test_queue_empty_and_full(void) {
|
||||
static void test_queue_infinite_receive_wakeup(void) {
|
||||
uint32_t queue = 0;
|
||||
uint32_t s = SysCreateQueue(&queue);
|
||||
if (s != STATUS_SUCCESS) fail_status("create wake queue", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("create wake queue", s);
|
||||
|
||||
TEST_SENDER_CONTEXT ctx = { queue, STATUS_PENDING };
|
||||
TEST_SENDER_CONTEXT ctx = { queue, NTLSTATUS_PENDING };
|
||||
uint32_t threadHandle = 0;
|
||||
uint32_t threadId = 0;
|
||||
SYS_CREATE_THREAD_REQUEST req = {
|
||||
@@ -180,17 +180,17 @@ static void test_queue_infinite_receive_wakeup(void) {
|
||||
&threadId
|
||||
};
|
||||
s = SysCreateThread(&req);
|
||||
if (s != STATUS_SUCCESS) fail_status("create sender", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("create sender", s);
|
||||
|
||||
TEST_QUEUE_MESSAGE msg = {0};
|
||||
s = recv_queue(queue, &msg, SYS_WAIT_TIMEOUT_INFINITE);
|
||||
if (s != STATUS_SUCCESS) fail_status("infinite receive", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("infinite receive", s);
|
||||
if (msg.Type != TEST_MESSAGE_WAKE || msg.Param[0] != TEST_WAKE_VALUE)
|
||||
fail("wake message payload mismatch");
|
||||
|
||||
s = SysWait(threadHandle, SYS_WAIT_FLAG_NONE);
|
||||
if (s != STATUS_SUCCESS) fail_status("wait sender", s);
|
||||
if (ctx.Status != STATUS_SUCCESS) fail_status("sender status", ctx.Status);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("wait sender", s);
|
||||
if (ctx.Status != NTLSTATUS_SUCCESS) fail_status("sender status", ctx.Status);
|
||||
|
||||
SysCloseHandle(threadHandle);
|
||||
SysCloseHandle(queue);
|
||||
@@ -200,11 +200,11 @@ static void test_queue_infinite_receive_wakeup(void) {
|
||||
static void test_queue_request_validation(void) {
|
||||
uint32_t queue = 0;
|
||||
uint32_t s = SysCreateQueue(&queue);
|
||||
if (s != STATUS_SUCCESS) fail_status("create validation queue", s);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("create validation queue", s);
|
||||
|
||||
TEST_QUEUE_MESSAGE msg = {0};
|
||||
expect_status("null send request", SysSendQueue((const SYS_QUEUE_SEND_REQUEST*)0), STATUS_INVALID_PARAMETER);
|
||||
expect_status("null recv request", SysRecvQueue((const SYS_QUEUE_RECV_REQUEST*)0), STATUS_INVALID_PARAMETER);
|
||||
expect_status("null send request", SysSendQueue((const SYS_QUEUE_SEND_REQUEST*)0), NTLSTATUS_INVALID_PARAMETER);
|
||||
expect_status("null recv request", SysRecvQueue((const SYS_QUEUE_RECV_REQUEST*)0), NTLSTATUS_INVALID_PARAMETER);
|
||||
|
||||
SYS_QUEUE_SEND_REQUEST sendReq = {
|
||||
0,
|
||||
@@ -213,15 +213,15 @@ static void test_queue_request_validation(void) {
|
||||
0,
|
||||
&msg,
|
||||
};
|
||||
expect_status("bad send size", SysSendQueue(&sendReq), STATUS_INVALID_PARAMETER);
|
||||
expect_status("bad send size", SysSendQueue(&sendReq), NTLSTATUS_INVALID_PARAMETER);
|
||||
|
||||
sendReq.Size = sizeof(sendReq);
|
||||
sendReq.Flags = 1;
|
||||
expect_status("bad send flags", SysSendQueue(&sendReq), STATUS_INVALID_PARAMETER);
|
||||
expect_status("bad send flags", SysSendQueue(&sendReq), NTLSTATUS_INVALID_PARAMETER);
|
||||
|
||||
sendReq.Flags = SYS_QUEUE_FLAG_NONE;
|
||||
sendReq.Message = (const void*)0;
|
||||
expect_status("bad send message", SysSendQueue(&sendReq), STATUS_INVALID_PARAMETER);
|
||||
expect_status("bad send message", SysSendQueue(&sendReq), NTLSTATUS_INVALID_PARAMETER);
|
||||
|
||||
SYS_QUEUE_RECV_REQUEST recvReq = {
|
||||
sizeof(recvReq),
|
||||
@@ -230,7 +230,7 @@ static void test_queue_request_validation(void) {
|
||||
0,
|
||||
(void*)0,
|
||||
};
|
||||
expect_status("bad recv message", SysRecvQueue(&recvReq), STATUS_INVALID_PARAMETER);
|
||||
expect_status("bad recv message", SysRecvQueue(&recvReq), NTLSTATUS_INVALID_PARAMETER);
|
||||
|
||||
SysCloseHandle(queue);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user