clean up and standardize types across the codebase, unify atomic operations, improve UTF-8 handling throughout the system, remove obsolete input and named queue interfaces, redesign process preparation and creation, tighten IPC and service boundaries, improve error handling and reliability, minor documentation cleanup, fix doom surfaces, fix panic in ini parsing.
This commit is contained in:
1 parent
899225f551
commit
c0ad63c27f
226 files changed
+6562
-4147
No files matched your search
+34
-563
@@ -24,6 +24,8 @@
|
||||
// call: the object model already handled it; the dedicated syscall was only
|
||||
// adding a footgun where callers could bypass the unified refcount path.
|
||||
|
||||
#include <ntlite/atomic.h>
|
||||
#include <intrin.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
@@ -43,7 +45,6 @@
|
||||
#include <kernel/ke_spinlock.h>
|
||||
#include <kernel/ke_debug.h>
|
||||
#include <kernel/ke_exception.h>
|
||||
#include <kernel/ke_named_queue.h>
|
||||
|
||||
#ifndef PROCESS_LAUNCH_DEBUG
|
||||
#define PROCESS_LAUNCH_DEBUG 0
|
||||
@@ -83,7 +84,7 @@ static const HAL_API* gHal;
|
||||
|
||||
|
||||
typedef struct SYS_IO_STATUS_BLOCK_K {
|
||||
volatile uint32_t Status;
|
||||
volatile KSTATUS Status;
|
||||
volatile uint64_t Information;
|
||||
} SYS_IO_STATUS_BLOCK_K;
|
||||
|
||||
@@ -259,7 +260,7 @@ static KSTATUS KiImportUserTextView(SYS_STRING_VIEW userView,
|
||||
bool nulTerminate) {
|
||||
KSTATUS s = KiImportUserStringView(userView, dst, dstSize, out, nulTerminate);
|
||||
if (!KSUCCESS(s)) return s;
|
||||
if (out && SysSvContainsByte(*out, '\0')) return NTLSTATUS_INVALID_PARAMETER;
|
||||
if (!out || !SysSvIsUtf8Text(*out)) return NTLSTATUS_INVALID_PARAMETER;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -300,11 +301,11 @@ static KSTATUS KiCopyInt32ToUser(int32_t* valueOut, int32_t value) {
|
||||
}
|
||||
|
||||
// Implements the mul Size operation.
|
||||
static int KiMulSize(size_t a, size_t b, size_t* out) {
|
||||
if (!out) return 0;
|
||||
if (a && b > ((size_t)-1) / a) return 0;
|
||||
static bool KiMulSize(size_t a, size_t b, size_t* out) {
|
||||
if (!out) return false;
|
||||
if (a && b > ((size_t)-1) / a) return false;
|
||||
*out = a * b;
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
static size_t KiAlignUpSize(size_t value, size_t alignment) {
|
||||
@@ -554,9 +555,6 @@ static KSTATUS KiHandleToWaitEvent(PROCESS* proc, SYS_HANDLE handle, EVENT** eve
|
||||
case ObjectTypeAsyncIo:
|
||||
event = IoGetAsyncRequestWaitEvent((IO_ASYNC_REQUEST_OBJECT*)obj);
|
||||
break;
|
||||
case ObjectTypeInputQueue:
|
||||
event = KeInputQueueWaitEvent(CONTAINING_RECORD(obj, INPUT_QUEUE, Header));
|
||||
break;
|
||||
case ObjectTypeTimer:
|
||||
event = KeTimerWaitEvent(CONTAINING_RECORD(obj, KTIMER, Header));
|
||||
break;
|
||||
@@ -698,29 +696,6 @@ static uint64_t SyscallWaitMany(const SYS_WAIT_MANY_REQUEST* request) {
|
||||
return s;
|
||||
}
|
||||
|
||||
// Implements SYS_OPEN_INPUT_QUEUE.
|
||||
static uint64_t SyscallOpenInputQueue(uint32_t flags, SYS_HANDLE* handleOut) {
|
||||
KSTATUS privilegeStatus = KiRequirePrivilege(SYS_PRIV_GLOBAL_INPUT);
|
||||
if (!KSUCCESS(privilegeStatus)) return privilegeStatus;
|
||||
if (flags != 0) return NTLSTATUS_INVALID_PARAMETER;
|
||||
if (!handleOut) return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
INPUT_QUEUE* queue = (INPUT_QUEUE*)0;
|
||||
KSTATUS s = KeInputOpenQueue(&queue);
|
||||
if (!KSUCCESS(s)) return s;
|
||||
|
||||
SYS_HANDLE handle = SYS_HANDLE_INVALID;
|
||||
s = KiAllocHandleForCurrentWithRights(&queue->Header, KeGetValidHandleRights(ObjectTypeInputQueue), &handle);
|
||||
if (!KSUCCESS(s)) return s;
|
||||
|
||||
s = KiCopyHandleToUser(handleOut, handle);
|
||||
if (!KSUCCESS(s)) {
|
||||
PROCESS* proc = KeGetCurrentProcess();
|
||||
if (proc) KeCloseHandle(proc, handle);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
// Returns the current thread ID.
|
||||
static uint64_t SyscallGetCurrentTid(void) {
|
||||
THREAD* t = KeGetCurrentThread();
|
||||
@@ -2503,7 +2478,7 @@ static KSTATUS KiConsoleQueryInfo(SYS_CONSOLE_INFO* infoOut) {
|
||||
}
|
||||
|
||||
// Updates the legacy text-console cursor after authorization.
|
||||
static KSTATUS KiConsoleSetCursor(int x, int y) {
|
||||
static KSTATUS KiConsoleSetCursor(int32_t x, int32_t y) {
|
||||
if (x < 0 || y < 0) return NTLSTATUS_INVALID_PARAMETER;
|
||||
return KeDisplaySetConsoleCursor(x, y);
|
||||
}
|
||||
@@ -2560,18 +2535,18 @@ static uint64_t SyscallClearScreen(uint32_t color) {
|
||||
}
|
||||
|
||||
// Implements SYS_GET_SCREEN_SIZE.
|
||||
static uint64_t SyscallGetScreenSize(int* widthOut, int* heightOut) {
|
||||
static uint64_t SyscallGetScreenSize(int32_t* widthOut, int32_t* heightOut) {
|
||||
KSTATUS privilegeStatus = KiRequirePrivilege(SYS_PRIV_CONSOLE_ACCESS);
|
||||
if (!KSUCCESS(privilegeStatus)) return privilegeStatus;
|
||||
int w = 0, h = 0;
|
||||
int32_t w = 0, h = 0;
|
||||
KSTATUS gs = KeDisplayGetSize(&w, &h);
|
||||
if (!KSUCCESS(gs)) return gs;
|
||||
if (widthOut) {
|
||||
KSTATUS s = KiCopyIntToUser(widthOut, w);
|
||||
KSTATUS s = KiCopyInt32ToUser(widthOut, w);
|
||||
if (!KSUCCESS(s)) return s;
|
||||
}
|
||||
if (heightOut) {
|
||||
KSTATUS s = KiCopyIntToUser(heightOut, h);
|
||||
KSTATUS s = KiCopyInt32ToUser(heightOut, h);
|
||||
if (!KSUCCESS(s)) return s;
|
||||
}
|
||||
return NTLSTATUS_SUCCESS;
|
||||
@@ -2592,7 +2567,7 @@ static uint64_t SyscallGetConsoleInfo(SYS_CONSOLE_INFO* infoOut) {
|
||||
}
|
||||
|
||||
// Implements SYS_SET_CONSOLE_CURSOR through the legacy ambient console privilege.
|
||||
static uint64_t SyscallSetConsoleCursor(int x, int y) {
|
||||
static uint64_t SyscallSetConsoleCursor(int32_t x, int32_t y) {
|
||||
KSTATUS privilegeStatus = KiRequirePrivilege(SYS_PRIV_CONSOLE_ACCESS);
|
||||
if (!KSUCCESS(privilegeStatus)) return privilegeStatus;
|
||||
return KiConsoleSetCursor(x, y);
|
||||
@@ -2612,19 +2587,6 @@ static uint64_t SyscallFillConsoleAttribute(const SYS_FILL_CONSOLE_ATTRIBUTE_REQ
|
||||
return KiConsoleFillAttribute(request);
|
||||
}
|
||||
|
||||
static KSTATUS KiReferenceInputQueueHandle(SYS_HANDLE handle, INPUT_QUEUE** queueOut) {
|
||||
if (!queueOut) return NTLSTATUS_INVALID_PARAMETER;
|
||||
*queueOut = (INPUT_QUEUE*)0;
|
||||
if (handle == 0) return NTLSTATUS_SUCCESS;
|
||||
|
||||
KSTATUS handleStatus = NTLSTATUS_SUCCESS;
|
||||
OBJECT* object = KiHandleToObject(handle, ObjectTypeInputQueue,
|
||||
SYS_INPUT_QUEUE_RIGHT_READ, &handleStatus);
|
||||
if (!object) return handleStatus;
|
||||
*queueOut = CONTAINING_RECORD(object, INPUT_QUEUE, Header);
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Implements the capability-scoped raw input-manager stream used by RSSRV.
|
||||
static uint64_t SyscallReadInputManagerEvent(const SYS_INPUT_MANAGER_READ_REQUEST* request) {
|
||||
SYS_INPUT_MANAGER_READ_REQUEST req;
|
||||
@@ -2645,209 +2607,6 @@ static uint64_t SyscallReadInputManagerEvent(const SYS_INPUT_MANAGER_READ_REQUES
|
||||
return CopyToUser(req.EventOut, &event, sizeof(event));
|
||||
}
|
||||
|
||||
// Copies one keyboard input record to user mode.
|
||||
static KSTATUS KiCopyInputRecordToUser(INPUT_KEY_RECORD* userRecord, const INPUT_KEY_RECORD* record) {
|
||||
if (!userRecord || !record) return NTLSTATUS_INVALID_PARAMETER;
|
||||
return CopyToUser(userRecord, record, sizeof(*record));
|
||||
}
|
||||
|
||||
// Imports and validates a keyboard input event request.
|
||||
static KSTATUS KiCopyInputEventRequest(const SYS_INPUT_EVENT_REQUEST* userRequest, SYS_INPUT_EVENT_REQUEST* req) {
|
||||
KSTATUS s = KiCopySizedUserRequest(userRequest, req, sizeof(*req));
|
||||
if (!KSUCCESS(s)) return s;
|
||||
if (req->Flags != SYS_INPUT_EVENT_FLAG_NONE) return NTLSTATUS_INVALID_PARAMETER;
|
||||
if (!req->RecordOut) return NTLSTATUS_INVALID_PARAMETER;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Implements SYS_POLL_KEYBOARD.
|
||||
static uint64_t SyscallKbPoll(INPUT_KEY* keyOut) {
|
||||
KSTATUS privilegeStatus = KiRequirePrivilege(SYS_PRIV_GLOBAL_INPUT);
|
||||
if (!KSUCCESS(privilegeStatus)) return privilegeStatus;
|
||||
if (!keyOut) return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
INPUT_KEY key = KeInputKbPoll();
|
||||
KSTATUS s = CopyToUser(keyOut, &key, sizeof(key));
|
||||
if (!KSUCCESS(s)) return s;
|
||||
return (key == INPUT_KEY_NONE) ? NTLSTATUS_WOULD_BLOCK : NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Implements SYS_IS_KEY_DOWN.
|
||||
static uint64_t SyscallKbIsKeyDown(INPUT_KEY key, bool* downOut) {
|
||||
KSTATUS privilegeStatus = KiRequirePrivilege(SYS_PRIV_GLOBAL_INPUT);
|
||||
if (!KSUCCESS(privilegeStatus)) return privilegeStatus;
|
||||
if (!downOut) return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
bool down = KeInputIsKeyDown((INPUT_KEY)key);
|
||||
return CopyToUser(downOut, &down, sizeof(down));
|
||||
}
|
||||
|
||||
// Implements SYS_READ_KEYBOARD_CHAR.
|
||||
static uint64_t SyscallKbReadChar(char* charOut) {
|
||||
KSTATUS privilegeStatus = KiRequirePrivilege(SYS_PRIV_GLOBAL_INPUT);
|
||||
if (!KSUCCESS(privilegeStatus)) return privilegeStatus;
|
||||
if (!charOut) return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
while (true) {
|
||||
char ch = KeInputReadChar();
|
||||
if (ch)
|
||||
return CopyToUser(charOut, &ch, sizeof(ch));
|
||||
|
||||
KSTATUS s = KeInputWaitKey(0, SYS_WAIT_TIMEOUT_INFINITE);
|
||||
if (!KSUCCESS(s))
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
// Implements SYS_READ_KEY.
|
||||
static uint64_t SyscallKbReadKey(INPUT_KEY* keyOut) {
|
||||
KSTATUS privilegeStatus = KiRequirePrivilege(SYS_PRIV_GLOBAL_INPUT);
|
||||
if (!KSUCCESS(privilegeStatus)) return privilegeStatus;
|
||||
if (!keyOut) return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
while (true) {
|
||||
INPUT_KEY key = KeInputReadKey();
|
||||
if (key != INPUT_KEY_NONE)
|
||||
return CopyToUser(keyOut, &key, sizeof(key));
|
||||
|
||||
KSTATUS s = KeInputWaitKey(0, SYS_WAIT_TIMEOUT_INFINITE);
|
||||
if (!KSUCCESS(s))
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
// SYS_GET_KEY_MODIFIERS -> uint32_t INPUT_MOD_* flags.
|
||||
static uint64_t SyscallKbGetModifiers(void) {
|
||||
KSTATUS privilegeStatus = KiRequirePrivilege(SYS_PRIV_GLOBAL_INPUT);
|
||||
if (!KSUCCESS(privilegeStatus)) return privilegeStatus;
|
||||
return (uint64_t)KeInputGetModifiers();
|
||||
}
|
||||
|
||||
// Implements SYS_QUERY_GLOBAL_INPUT_STATE.
|
||||
static uint64_t SyscallQueryGlobalInputState(SYS_GLOBAL_INPUT_STATE* stateOut) {
|
||||
KSTATUS privilegeStatus = KiRequirePrivilege(SYS_PRIV_GLOBAL_INPUT);
|
||||
if (!KSUCCESS(privilegeStatus)) return privilegeStatus;
|
||||
SYS_GLOBAL_INPUT_STATE state;
|
||||
KSTATUS s = KiCopySizedUserRequest(stateOut, &state, sizeof(state));
|
||||
if (!KSUCCESS(s)) return s;
|
||||
if (state.Flags != SYS_GLOBAL_INPUT_STATE_FLAG_NONE) return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
s = KeInputQueryGlobalState(&state);
|
||||
if (!KSUCCESS(s)) return s;
|
||||
return CopyToUser(stateOut, &state, sizeof(state));
|
||||
}
|
||||
|
||||
// Implements SYS_READ_INPUT_EVENT.
|
||||
static uint64_t SyscallKbReadInputEvent(const SYS_INPUT_EVENT_REQUEST* request) {
|
||||
SYS_INPUT_EVENT_REQUEST req;
|
||||
KSTATUS s = KiCopyInputEventRequest(request, &req);
|
||||
if (!KSUCCESS(s)) return s;
|
||||
if (req.QueueHandle == SYS_HANDLE_INVALID) {
|
||||
KSTATUS privilegeStatus = KiRequirePrivilege(SYS_PRIV_GLOBAL_INPUT);
|
||||
if (!KSUCCESS(privilegeStatus)) return privilegeStatus;
|
||||
}
|
||||
|
||||
INPUT_QUEUE* queue = (INPUT_QUEUE*)0;
|
||||
s = KiReferenceInputQueueHandle(req.QueueHandle, &queue);
|
||||
if (!KSUCCESS(s)) return s;
|
||||
|
||||
INPUT_KEY_RECORD record;
|
||||
while (true) {
|
||||
bool available = queue ? KeInputQueueReadEvent(queue, &record)
|
||||
: KeInputReadEvent(&record);
|
||||
if (available) {
|
||||
s = KiCopyInputRecordToUser(req.RecordOut, &record);
|
||||
break;
|
||||
}
|
||||
|
||||
if (req.TimeoutMilliseconds == 0) {
|
||||
s = NTLSTATUS_WOULD_BLOCK;
|
||||
break;
|
||||
}
|
||||
|
||||
s = queue ? KeInputQueueWaitKey(queue, 0, req.TimeoutMilliseconds)
|
||||
: KeInputWaitKey(0, req.TimeoutMilliseconds);
|
||||
if (!KSUCCESS(s))
|
||||
break;
|
||||
}
|
||||
|
||||
if (queue) ObDereferenceObject(&queue->Header);
|
||||
return s;
|
||||
}
|
||||
|
||||
// Implements SYS_PEEK_INPUT_EVENT.
|
||||
static uint64_t SyscallKbPeekInputEvent(const SYS_INPUT_EVENT_REQUEST* request) {
|
||||
SYS_INPUT_EVENT_REQUEST req;
|
||||
KSTATUS s = KiCopyInputEventRequest(request, &req);
|
||||
if (!KSUCCESS(s)) return s;
|
||||
if (req.QueueHandle == SYS_HANDLE_INVALID) {
|
||||
KSTATUS privilegeStatus = KiRequirePrivilege(SYS_PRIV_GLOBAL_INPUT);
|
||||
if (!KSUCCESS(privilegeStatus)) return privilegeStatus;
|
||||
}
|
||||
|
||||
INPUT_QUEUE* queue = (INPUT_QUEUE*)0;
|
||||
s = KiReferenceInputQueueHandle(req.QueueHandle, &queue);
|
||||
if (!KSUCCESS(s)) return s;
|
||||
|
||||
INPUT_KEY_RECORD record;
|
||||
while (true) {
|
||||
bool available = queue ? KeInputQueuePeekEvent(queue, &record)
|
||||
: KeInputPeekEvent(&record);
|
||||
if (available) {
|
||||
s = KiCopyInputRecordToUser(req.RecordOut, &record);
|
||||
break;
|
||||
}
|
||||
|
||||
if (req.TimeoutMilliseconds == 0) {
|
||||
s = NTLSTATUS_WOULD_BLOCK;
|
||||
break;
|
||||
}
|
||||
|
||||
s = queue ? KeInputQueueWaitKey(queue, 0, req.TimeoutMilliseconds)
|
||||
: KeInputWaitKey(0, req.TimeoutMilliseconds);
|
||||
if (!KSUCCESS(s))
|
||||
break;
|
||||
}
|
||||
|
||||
if (queue) ObDereferenceObject(&queue->Header);
|
||||
return s;
|
||||
}
|
||||
|
||||
// Implements SYS_PEEK_MOUSE.
|
||||
static uint64_t SyscallMousePeek(INPUT_MOUSE_EVENT* eventOut) {
|
||||
KSTATUS privilegeStatus = KiRequirePrivilege(SYS_PRIV_GLOBAL_INPUT);
|
||||
if (!KSUCCESS(privilegeStatus)) return privilegeStatus;
|
||||
if (!eventOut) return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
INPUT_MOUSE_EVENT event;
|
||||
if (!KeInputMousePeek(&event)) return NTLSTATUS_WOULD_BLOCK;
|
||||
return CopyToUser(eventOut, &event, sizeof(event));
|
||||
}
|
||||
|
||||
// Implements SYS_READ_MOUSE.
|
||||
static uint64_t SyscallMouseRead(INPUT_MOUSE_EVENT* eventOut) {
|
||||
KSTATUS privilegeStatus = KiRequirePrivilege(SYS_PRIV_GLOBAL_INPUT);
|
||||
if (!KSUCCESS(privilegeStatus)) return privilegeStatus;
|
||||
if (!eventOut) return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
INPUT_MOUSE_EVENT event;
|
||||
if (!KeInputMouseRead(&event)) return NTLSTATUS_WOULD_BLOCK;
|
||||
return CopyToUser(eventOut, &event, sizeof(event));
|
||||
}
|
||||
|
||||
// Implements SYS_GET_MOUSE_POS.
|
||||
static uint64_t SyscallMouseGetPos(int* xOut, int* yOut) {
|
||||
KSTATUS privilegeStatus = KiRequirePrivilege(SYS_PRIV_GLOBAL_INPUT);
|
||||
if (!KSUCCESS(privilegeStatus)) return privilegeStatus;
|
||||
if (!xOut || !yOut) return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
int x = 0, y = 0;
|
||||
KeInputMouseGetPosition(&x, &y);
|
||||
KSTATUS s = KiCopyIntToUser(xOut, x);
|
||||
if (!KSUCCESS(s)) return s;
|
||||
return KiCopyIntToUser(yOut, y);
|
||||
}
|
||||
|
||||
// Returns monotonic ticks since boot.
|
||||
static uint64_t SyscallGetTick(void) {
|
||||
return gHal ? gHal->Timer.QueryTicks() : 0;
|
||||
@@ -2919,19 +2678,19 @@ static uint64_t SyscallQueryTrapFrame(SYS_TRAP_FRAME_INFO* infoOut) {
|
||||
static KSTATUS KiBeginProcessBuildOperation(PROCESS* process) {
|
||||
if (!process) return NTLSTATUS_INVALID_PARAMETER;
|
||||
for (;;) {
|
||||
if (_InterlockedCompareExchange(&process->BuildState, 0, 0) != KE_PROCESS_BUILD_CONSTRUCTING)
|
||||
if (NtlAtomicLoad32(&process->BuildState) != KE_PROCESS_BUILD_CONSTRUCTING)
|
||||
return NTLSTATUS_ACCESS_DENIED;
|
||||
_InterlockedIncrement(&process->BuildOperations);
|
||||
if (_InterlockedCompareExchange(&process->BuildState, 0, 0) == KE_PROCESS_BUILD_CONSTRUCTING)
|
||||
NtlAtomicIncrement32(&process->BuildOperations);
|
||||
if (NtlAtomicLoad32(&process->BuildState) == KE_PROCESS_BUILD_CONSTRUCTING)
|
||||
return NTLSTATUS_SUCCESS;
|
||||
_InterlockedDecrement(&process->BuildOperations);
|
||||
NtlAtomicDecrement32(&process->BuildOperations);
|
||||
}
|
||||
}
|
||||
|
||||
// Ends one process-construction memory operation.
|
||||
static void KiEndProcessBuildOperation(PROCESS* process) {
|
||||
if (!process) return;
|
||||
long remaining = _InterlockedDecrement(&process->BuildOperations);
|
||||
int32_t remaining = NtlAtomicDecrement32(&process->BuildOperations);
|
||||
if (remaining == 0 && KeIsProcessTerminating(process))
|
||||
(void)KeTerminateProcess(process, process->ExitCode);
|
||||
}
|
||||
@@ -3094,20 +2853,20 @@ static uint64_t SyscallStartProcess(const SYS_START_PROCESS_REQUEST* request) {
|
||||
int buildActive = 0;
|
||||
status = KiBeginProcessBuildOperation(child);
|
||||
if (!KSUCCESS(status)) {
|
||||
int terminating = KeIsProcessTerminating(child);
|
||||
bool terminating = KeIsProcessTerminating(child);
|
||||
ObDereferenceObject(&child->Header);
|
||||
return terminating ? NTLSTATUS_OBJECT_DEAD : status;
|
||||
}
|
||||
buildActive = 1;
|
||||
THREAD* thread = (THREAD*)0;
|
||||
|
||||
if (_InterlockedCompareExchange(&child->BuildState, KE_PROCESS_BUILD_STARTING,
|
||||
if (NtlAtomicCompareExchange32(&child->BuildState, KE_PROCESS_BUILD_STARTING,
|
||||
KE_PROCESS_BUILD_CONSTRUCTING) != KE_PROCESS_BUILD_CONSTRUCTING) {
|
||||
status = KeIsProcessTerminating(child) ? NTLSTATUS_OBJECT_DEAD : NTLSTATUS_ACCESS_DENIED;
|
||||
goto done;
|
||||
}
|
||||
if (_InterlockedCompareExchange(&child->BuildOperations, 0, 0) != 1) {
|
||||
(void)_InterlockedCompareExchange(&child->BuildState, KE_PROCESS_BUILD_CONSTRUCTING,
|
||||
if (NtlAtomicLoad32(&child->BuildOperations) != 1) {
|
||||
(void)NtlAtomicCompareExchange32(&child->BuildState, KE_PROCESS_BUILD_CONSTRUCTING,
|
||||
KE_PROCESS_BUILD_STARTING);
|
||||
status = NTLSTATUS_WOULD_BLOCK;
|
||||
goto done;
|
||||
@@ -3169,7 +2928,7 @@ static uint64_t SyscallStartProcess(const SYS_START_PROCESS_REQUEST* request) {
|
||||
parameters.Flags = KE_THREAD_CREATE_FLAG_SUSPENDED;
|
||||
status = KeCreateThread(child, req.EntryPoint, 0, ¶meters, &thread);
|
||||
if (KSUCCESS(status)) {
|
||||
if (_InterlockedCompareExchange(&child->BuildState, KE_PROCESS_BUILD_STARTED,
|
||||
if (NtlAtomicCompareExchange32(&child->BuildState, KE_PROCESS_BUILD_STARTED,
|
||||
KE_PROCESS_BUILD_STARTING) != KE_PROCESS_BUILD_STARTING) {
|
||||
(void)KeCancelSuspendedThread(thread);
|
||||
status = NTLSTATUS_OBJECT_DEAD;
|
||||
@@ -3184,7 +2943,7 @@ static uint64_t SyscallStartProcess(const SYS_START_PROCESS_REQUEST* request) {
|
||||
child->ImageSize = 0;
|
||||
(void)KeSetProcessStartupCapabilities(child, (const SYS_STARTUP_CAPABILITY*)0, 0);
|
||||
(void)KeSetProcessLoaderData(child, (const void*)0);
|
||||
(void)_InterlockedCompareExchange(&child->BuildState, KE_PROCESS_BUILD_CONSTRUCTING,
|
||||
(void)NtlAtomicCompareExchange32(&child->BuildState, KE_PROCESS_BUILD_CONSTRUCTING,
|
||||
KE_PROCESS_BUILD_STARTING);
|
||||
goto done;
|
||||
}
|
||||
@@ -3841,221 +3600,6 @@ static uint64_t SyscallWaitVolumeChange(SYS_HANDLE managerHandle,
|
||||
return IoWaitForVolumeChange(observedGeneration, timeoutMilliseconds);
|
||||
}
|
||||
|
||||
// Named Queue Registry
|
||||
|
||||
// A flat, fixed-size table of { name -> QUEUE* } pairs protected by a
|
||||
// spinlock. The registry holds one reference to each published queue for
|
||||
// the lifetime of the entry, so the queue object cannot be destroyed while
|
||||
// it is registered even if every process closes its own handle to it.
|
||||
|
||||
// Limits: NAMED_QUEUE_MAX names, each up to NAMED_QUEUE_NAME_MAX bytes.
|
||||
// These are generous for the intended usage (a handful of system servers).
|
||||
|
||||
#define NAMED_QUEUE_MAX 16
|
||||
#define NAMED_QUEUE_NAME_MAX 64
|
||||
|
||||
typedef struct {
|
||||
char Name[NAMED_QUEUE_NAME_MAX];
|
||||
size_t NameLength;
|
||||
QUEUE* Queue; // NULL = slot free; non-NULL = occupied
|
||||
uint32_t PublisherPid; // ProcessId of whoever called SysPublishQueue
|
||||
SYS_HANDLE PublisherHandle; // Publisher-owned handle that keeps the name live
|
||||
} NAMED_QUEUE_ENTRY;
|
||||
|
||||
static NAMED_QUEUE_ENTRY gNamedQueues[NAMED_QUEUE_MAX];
|
||||
static SPINLOCK gNamedQueueLock;
|
||||
|
||||
static int KiNamedQueueNameEquals(const NAMED_QUEUE_ENTRY* entry,
|
||||
SYS_STRING_VIEW name) {
|
||||
if (!entry || !entry->Queue) return 0;
|
||||
return SysSvEqual(SysSvFromParts(entry->Name, entry->NameLength), name);
|
||||
}
|
||||
|
||||
static int KiNamedQueueOwnedByHandle(const NAMED_QUEUE_ENTRY* entry,
|
||||
const PROCESS* process,
|
||||
SYS_HANDLE handle,
|
||||
const OBJECT* object) {
|
||||
if (!entry || !entry->Queue || !process || !object)
|
||||
return 0;
|
||||
return entry->PublisherPid == process->ProcessId &&
|
||||
entry->PublisherHandle == handle &&
|
||||
&entry->Queue->Header == object;
|
||||
}
|
||||
|
||||
// Clears a named queue slot and returns the registry reference for later release.
|
||||
static QUEUE* KiNamedQueueClearSlotLocked(NAMED_QUEUE_ENTRY* entry) {
|
||||
if (!entry || !entry->Queue)
|
||||
return (QUEUE*)0;
|
||||
|
||||
QUEUE* queue = entry->Queue;
|
||||
memset(entry, 0, sizeof(*entry));
|
||||
return queue;
|
||||
}
|
||||
|
||||
// Removes one published queue name owned by the current process.
|
||||
static KSTATUS KiNamedQueueUnpublishByName(SYS_STRING_VIEW nameView) {
|
||||
PROCESS* process = KeGetCurrentProcess();
|
||||
if (!process)
|
||||
return NTLSTATUS_FAILURE;
|
||||
|
||||
QUEUE* queue = (QUEUE*)0;
|
||||
uintptr_t flags = KeAcquireSpinlock(&gNamedQueueLock);
|
||||
for (int i = 0; i < NAMED_QUEUE_MAX; i++) {
|
||||
if (KiNamedQueueNameEquals(&gNamedQueues[i], nameView)) {
|
||||
if (gNamedQueues[i].PublisherPid != process->ProcessId) {
|
||||
KeReleaseSpinlock(&gNamedQueueLock, flags);
|
||||
return NTLSTATUS_ACCESS_DENIED;
|
||||
}
|
||||
queue = KiNamedQueueClearSlotLocked(&gNamedQueues[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
KeReleaseSpinlock(&gNamedQueueLock, flags);
|
||||
|
||||
if (!queue)
|
||||
return NTLSTATUS_NOT_FOUND;
|
||||
ObDereferenceObject(&queue->Header);
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Removes published names whose owner handle is being closed.
|
||||
void KeNamedQueueUnpublishHandle(PROCESS* process, SYS_HANDLE handle, OBJECT* object) {
|
||||
if (!process || !object || object->Type != ObjectTypeQueue)
|
||||
return;
|
||||
|
||||
while (true) {
|
||||
QUEUE* queue = (QUEUE*)0;
|
||||
uintptr_t flags = KeAcquireSpinlock(&gNamedQueueLock);
|
||||
for (int i = 0; i < NAMED_QUEUE_MAX; i++) {
|
||||
if (KiNamedQueueOwnedByHandle(&gNamedQueues[i], process, handle, object)) {
|
||||
queue = KiNamedQueueClearSlotLocked(&gNamedQueues[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
KeReleaseSpinlock(&gNamedQueueLock, flags);
|
||||
|
||||
if (!queue)
|
||||
break;
|
||||
ObDereferenceObject(&queue->Header);
|
||||
}
|
||||
}
|
||||
|
||||
// Implements SYS_PUBLISH_QUEUE.
|
||||
|
||||
// Registers the queue identified by QueueHandle under Name.
|
||||
// The published name is owned by the publishing process and handle. Closing that
|
||||
// handle or exiting the process withdraws every name published through it.
|
||||
static uint64_t SyscallPublishQueue(const SYS_PUBLISH_QUEUE_REQUEST* request) {
|
||||
KSTATUS privilegeStatus = KiRequirePrivilege(SYS_PRIV_NAMED_QUEUE_PUBLISH);
|
||||
if (!KSUCCESS(privilegeStatus)) return privilegeStatus;
|
||||
SYS_PUBLISH_QUEUE_REQUEST req;
|
||||
KSTATUS s = KiCopySizedUserRequest(request, &req, sizeof(req));
|
||||
if (!KSUCCESS(s)) return s;
|
||||
|
||||
char name[NAMED_QUEUE_NAME_MAX];
|
||||
SYS_STRING_VIEW nameView;
|
||||
s = KiImportUserTextView(req.Name, name, sizeof(name), &nameView, false);
|
||||
if (!KSUCCESS(s)) return s;
|
||||
if (nameView.Length == 0) return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
KSTATUS handleStatus = NTLSTATUS_SUCCESS;
|
||||
QUEUE* q = (QUEUE*)KiHandleToObject(req.QueueHandle, ObjectTypeQueue, SYS_QUEUE_RIGHT_PUBLISH, &handleStatus);
|
||||
if (!q) return handleStatus;
|
||||
|
||||
uintptr_t flags = KeAcquireSpinlock(&gNamedQueueLock);
|
||||
|
||||
for (int i = 0; i < NAMED_QUEUE_MAX; i++) {
|
||||
if (KiNamedQueueNameEquals(&gNamedQueues[i], nameView)) {
|
||||
KeReleaseSpinlock(&gNamedQueueLock, flags);
|
||||
ObDereferenceObject(&q->Header);
|
||||
return NTLSTATUS_ALREADY_EXISTS;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < NAMED_QUEUE_MAX; i++) {
|
||||
if (!gNamedQueues[i].Queue) {
|
||||
memcpy(gNamedQueues[i].Name, name, nameView.Length);
|
||||
gNamedQueues[i].NameLength = nameView.Length;
|
||||
gNamedQueues[i].Queue = q;
|
||||
gNamedQueues[i].PublisherPid = KeGetCurrentProcess()->ProcessId;
|
||||
gNamedQueues[i].PublisherHandle = req.QueueHandle;
|
||||
KeReleaseSpinlock(&gNamedQueueLock, flags);
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
KeReleaseSpinlock(&gNamedQueueLock, flags);
|
||||
ObDereferenceObject(&q->Header);
|
||||
return NTLSTATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
// Implements SYS_UNPUBLISH_QUEUE.
|
||||
// Withdraws a published queue name owned by the calling process.
|
||||
static uint64_t SyscallUnpublishQueue(const SYS_UNPUBLISH_QUEUE_REQUEST* request) {
|
||||
KSTATUS privilegeStatus = KiRequirePrivilege(SYS_PRIV_NAMED_QUEUE_PUBLISH);
|
||||
if (!KSUCCESS(privilegeStatus)) return privilegeStatus;
|
||||
SYS_UNPUBLISH_QUEUE_REQUEST req;
|
||||
KSTATUS s = KiCopySizedUserRequest(request, &req, sizeof(req));
|
||||
if (!KSUCCESS(s)) return s;
|
||||
|
||||
char name[NAMED_QUEUE_NAME_MAX];
|
||||
SYS_STRING_VIEW nameView;
|
||||
s = KiImportUserTextView(req.Name, name, sizeof(name), &nameView, false);
|
||||
if (!KSUCCESS(s)) return s;
|
||||
if (nameView.Length == 0) return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
return KiNamedQueueUnpublishByName(nameView);
|
||||
}
|
||||
|
||||
// Implements SYS_OPEN_NAMED_QUEUE.
|
||||
|
||||
// Looks up 'name' in the registry and allocates a handle to the queue in the
|
||||
// calling process's handle table. Returns NTLSTATUS_NOT_FOUND if no match.
|
||||
// Callers that race against the publisher should retry on NOT_FOUND.
|
||||
static uint64_t SyscallOpenNamedQueue(const SYS_OPEN_NAMED_QUEUE_REQUEST* request) {
|
||||
SYS_OPEN_NAMED_QUEUE_REQUEST req;
|
||||
KSTATUS s = KiCopySizedUserRequest(request, &req, sizeof(req));
|
||||
if (!KSUCCESS(s)) return s;
|
||||
if (!req.HandleOut) return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
char name[NAMED_QUEUE_NAME_MAX];
|
||||
SYS_STRING_VIEW nameView;
|
||||
s = KiImportUserTextView(req.Name, name, sizeof(name), &nameView, false);
|
||||
if (!KSUCCESS(s)) return s;
|
||||
if (nameView.Length == 0) return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
s = MmProbeUserWrite(req.HandleOut, sizeof(SYS_HANDLE));
|
||||
if (!KSUCCESS(s)) return s;
|
||||
|
||||
uintptr_t flags = KeAcquireSpinlock(&gNamedQueueLock);
|
||||
|
||||
QUEUE* q = NULL;
|
||||
for (int i = 0; i < NAMED_QUEUE_MAX; i++) {
|
||||
if (KiNamedQueueNameEquals(&gNamedQueues[i], nameView)) {
|
||||
q = gNamedQueues[i].Queue;
|
||||
if (q && !ObTryReferenceObject(&q->Header))
|
||||
q = (QUEUE*)0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
KeReleaseSpinlock(&gNamedQueueLock, flags);
|
||||
|
||||
if (!q) return NTLSTATUS_NOT_FOUND;
|
||||
|
||||
SYS_HANDLE handle = SYS_HANDLE_INVALID;
|
||||
s = KiAllocHandleForCurrentWithRights(&q->Header, KeGetValidHandleRights(ObjectTypeQueue), &handle);
|
||||
if (!KSUCCESS(s)) return s;
|
||||
|
||||
s = KiCopyHandleToUser(req.HandleOut, handle);
|
||||
if (!KSUCCESS(s)) {
|
||||
PROCESS* proc = KeGetCurrentProcess();
|
||||
if (proc) KeCloseHandle(proc, handle);
|
||||
return s;
|
||||
}
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Implements SYS_DUPLICATE_HANDLE.
|
||||
|
||||
// Duplicates a handle from the caller into the target process table.
|
||||
@@ -4240,65 +3784,6 @@ static uint64_t SyscallOpenProcessSecurityContext(SYS_HANDLE processHandle,
|
||||
return status;
|
||||
}
|
||||
|
||||
// Implements SYS_OPEN_NAMED_QUEUE_OWNER_PROCESS.
|
||||
|
||||
// Opens a process handle for the process that published a named queue.
|
||||
static uint64_t SyscallOpenNamedQueueOwnerProcess(const SYS_NAMED_QUEUE_OWNER_REQUEST* request) {
|
||||
SYS_NAMED_QUEUE_OWNER_REQUEST req;
|
||||
KSTATUS s = KiCopySizedUserRequest(request, &req, sizeof(req));
|
||||
if (!KSUCCESS(s)) return s;
|
||||
if (!req.ProcessHandleOut || req.DesiredAccess == 0) return NTLSTATUS_INVALID_PARAMETER;
|
||||
SYS_RIGHTS validAccess = KeGetValidHandleRights(ObjectTypeProcess);
|
||||
if ((req.DesiredAccess & ~validAccess) != 0) return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
KSTATUS privilegeStatus = KiRequirePrivilege(SYS_PRIV_PROCESS_OPEN_ANY);
|
||||
if (!KSUCCESS(privilegeStatus)) return privilegeStatus;
|
||||
|
||||
char name[NAMED_QUEUE_NAME_MAX];
|
||||
SYS_STRING_VIEW nameView;
|
||||
s = KiImportUserTextView(req.Name, name, sizeof(name), &nameView, false);
|
||||
if (!KSUCCESS(s)) return s;
|
||||
if (nameView.Length == 0) return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
s = MmProbeUserWrite(req.ProcessHandleOut, sizeof(SYS_HANDLE));
|
||||
if (!KSUCCESS(s)) return s;
|
||||
|
||||
uint32_t pid = 0;
|
||||
uintptr_t flags = KeAcquireSpinlock(&gNamedQueueLock);
|
||||
for (int i = 0; i < NAMED_QUEUE_MAX; i++) {
|
||||
if (KiNamedQueueNameEquals(&gNamedQueues[i], nameView)) {
|
||||
pid = gNamedQueues[i].PublisherPid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
KeReleaseSpinlock(&gNamedQueueLock, flags);
|
||||
if (!pid) return NTLSTATUS_NOT_FOUND;
|
||||
|
||||
PROCESS* owner = KeGetProcessById(pid);
|
||||
if (!owner) return NTLSTATUS_NOT_FOUND;
|
||||
|
||||
PROCESS* caller = KeGetCurrentProcess();
|
||||
if (!caller) {
|
||||
ObDereferenceObject(&owner->Header);
|
||||
return NTLSTATUS_FAILURE;
|
||||
}
|
||||
|
||||
SYS_HANDLE handle = SYS_HANDLE_INVALID;
|
||||
s = KeCreateHandle(caller,
|
||||
&owner->Header,
|
||||
req.DesiredAccess,
|
||||
&handle);
|
||||
ObDereferenceObject(&owner->Header);
|
||||
if (!KSUCCESS(s)) return s;
|
||||
|
||||
s = KiCopyHandleToUser(req.ProcessHandleOut, handle);
|
||||
if (!KSUCCESS(s)) {
|
||||
KeCloseHandle(caller, handle);
|
||||
return s;
|
||||
}
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Terminates the process referenced by one process handle.
|
||||
static uint64_t SyscallKillProcess(SYS_HANDLE processHandle, int32_t exitCode) {
|
||||
KSTATUS handleStatus = NTLSTATUS_SUCCESS;
|
||||
@@ -5108,13 +4593,13 @@ static uint64_t SyscallGetSocketOption(SYS_HANDLE socket, const SYS_SOCKET_OPTIO
|
||||
}
|
||||
|
||||
// Polls deadline Expired.
|
||||
static int KiPollDeadlineExpired(uint64_t start, uint32_t timeoutMs) {
|
||||
static bool KiPollDeadlineExpired(uint64_t start, uint32_t timeoutMs) {
|
||||
if (timeoutMs == 0)
|
||||
return 1;
|
||||
return true;
|
||||
if (timeoutMs == SYS_POLL_TIMEOUT_INFINITE)
|
||||
return 0;
|
||||
return false;
|
||||
if (!gHal)
|
||||
return 1;
|
||||
return true;
|
||||
return (gHal->Timer.QueryTicks() - start) >= ((uint64_t)timeoutMs * 1000u);
|
||||
}
|
||||
|
||||
@@ -5788,7 +5273,7 @@ static uint64_t SyscallQueryDisplayManagerConsoleInfo(SYS_HANDLE managerHandle,
|
||||
}
|
||||
|
||||
// Updates the console cursor through an explicitly delegated display-manager capability.
|
||||
static uint64_t SyscallSetDisplayManagerConsoleCursor(SYS_HANDLE managerHandle, int x, int y) {
|
||||
static uint64_t SyscallSetDisplayManagerConsoleCursor(SYS_HANDLE managerHandle, int32_t x, int32_t y) {
|
||||
KSTATUS handleStatus = NTLSTATUS_SUCCESS;
|
||||
KE_DISPLAY_MANAGER* manager = KiReferenceDisplayManagerConsole(managerHandle, &handleStatus);
|
||||
if (!manager) return handleStatus;
|
||||
@@ -6659,7 +6144,8 @@ static uint64_t SyscallAudioSetVolume(const SYS_AUDIO_SET_VOLUME_REQUEST* userRe
|
||||
KSTATUS status = KiCopySizedUserRequest(userRequest, &request, sizeof(request));
|
||||
if (!KSUCCESS(status)) return status;
|
||||
if (request.Flags != 0 || !request.StreamHandle ||
|
||||
request.Muted > 1u || request.VolumeQ16 > SYS_AUDIO_GAIN_Q16_UNITY ||
|
||||
((const uint8_t*)&request)[offsetof(SYS_AUDIO_SET_VOLUME_REQUEST, Muted)] > 1u ||
|
||||
request.VolumeQ16 > SYS_AUDIO_GAIN_Q16_UNITY ||
|
||||
request.PanQ16 < SYS_AUDIO_PAN_Q16_LEFT ||
|
||||
request.PanQ16 > SYS_AUDIO_PAN_Q16_RIGHT)
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
@@ -6682,7 +6168,8 @@ static uint64_t SyscallAudioSetMasterVolume(const SYS_AUDIO_SET_MASTER_VOLUME_RE
|
||||
KSTATUS status = KiCopySizedUserRequest(userRequest, &request, sizeof(request));
|
||||
if (!KSUCCESS(status)) return status;
|
||||
if (request.Flags != 0 || !request.EndpointId ||
|
||||
request.Muted > 1u || request.VolumeQ16 > SYS_AUDIO_GAIN_Q16_UNITY)
|
||||
((const uint8_t*)&request)[offsetof(SYS_AUDIO_SET_MASTER_VOLUME_REQUEST, Muted)] > 1u ||
|
||||
request.VolumeQ16 > SYS_AUDIO_GAIN_Q16_UNITY)
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
return KeAudioSetMasterVolume(request.EndpointId,
|
||||
@@ -6774,10 +6261,6 @@ static const SYSCALL_ENTRY gSyscallTable[SYS_MAX] = {
|
||||
[SYS_CREATE_QUEUE] = SYSCALL_ENTRY1(SyscallQueueCreate),
|
||||
[SYS_SEND_QUEUE] = SYSCALL_ENTRY1(SyscallQueueSend),
|
||||
[SYS_RECV_QUEUE] = SYSCALL_ENTRY1(SyscallQueueRecv),
|
||||
[SYS_PUBLISH_QUEUE] = SYSCALL_ENTRY1(SyscallPublishQueue),
|
||||
[SYS_UNPUBLISH_QUEUE] = SYSCALL_ENTRY1(SyscallUnpublishQueue),
|
||||
[SYS_OPEN_NAMED_QUEUE] = SYSCALL_ENTRY1(SyscallOpenNamedQueue),
|
||||
[SYS_OPEN_NAMED_QUEUE_OWNER_PROCESS] = SYSCALL_ENTRY1(SyscallOpenNamedQueueOwnerProcess),
|
||||
|
||||
// LPC-like Ports and well-known system services.
|
||||
[SYS_CREATE_PORT] = SYSCALL_ENTRY1(SyscallCreatePort),
|
||||
@@ -6869,18 +6352,6 @@ static const SYSCALL_ENTRY gSyscallTable[SYS_MAX] = {
|
||||
|
||||
// Input.
|
||||
[SYS_READ_INPUT_MANAGER_EVENT] = SYSCALL_ENTRY1(SyscallReadInputManagerEvent),
|
||||
[SYS_POLL_KEYBOARD] = SYSCALL_ENTRY1(SyscallKbPoll),
|
||||
[SYS_IS_KEY_DOWN] = SYSCALL_ENTRY2(SyscallKbIsKeyDown),
|
||||
[SYS_READ_KEYBOARD_CHAR] = SYSCALL_ENTRY1(SyscallKbReadChar),
|
||||
[SYS_READ_KEY] = SYSCALL_ENTRY1(SyscallKbReadKey),
|
||||
[SYS_GET_KEY_MODIFIERS] = SYSCALL_ENTRY0(SyscallKbGetModifiers),
|
||||
[SYS_QUERY_GLOBAL_INPUT_STATE] = SYSCALL_ENTRY1(SyscallQueryGlobalInputState),
|
||||
[SYS_OPEN_INPUT_QUEUE] = SYSCALL_ENTRY2(SyscallOpenInputQueue),
|
||||
[SYS_READ_INPUT_EVENT] = SYSCALL_ENTRY1(SyscallKbReadInputEvent),
|
||||
[SYS_PEEK_INPUT_EVENT] = SYSCALL_ENTRY1(SyscallKbPeekInputEvent),
|
||||
[SYS_PEEK_MOUSE] = SYSCALL_ENTRY1(SyscallMousePeek),
|
||||
[SYS_READ_MOUSE] = SYSCALL_ENTRY1(SyscallMouseRead),
|
||||
[SYS_GET_MOUSE_POS] = SYSCALL_ENTRY2(SyscallMouseGetPos),
|
||||
|
||||
// Time, debug, and system information.
|
||||
[SYS_CREATE_TIMER] = SYSCALL_ENTRY1(SyscallCreateTimer),
|
||||
|
||||
Reference in new issue
Block a user