1332 lines
59 KiB
C
1332 lines
59 KiB
C
// ke_syscall.c - system call dispatcher
|
|
//
|
|
// KeSyscallEntry (ke_syscall.asm) handles the INT 0x40 ring-3 -> ring-0
|
|
// transition, re-orders the arguments to match MS x64, and calls
|
|
// KeSyscallDispatch with:
|
|
//
|
|
// nr = original RAX (syscall number)
|
|
// a0 .. a5 = RCX, RDX, R8, R9, R10, R11 (user arguments)
|
|
//
|
|
// Every handler receives the same (a0..a5) signature even if it uses fewer
|
|
// arguments; unused parameters are silently ignored.
|
|
//
|
|
// Return value (RAX) is a KSTATUS code *or* an arbitrary 64-bit datum
|
|
// (pointer, size, tick count, etc.) depending on the call; conventions are
|
|
// documented in syscall_nr.h.
|
|
//
|
|
// ---------------------------------------------------------------------------
|
|
// Unified handle design
|
|
// ---------------------------------------------------------------------------
|
|
// All kernel objects (FILE_OBJECT, MUTEX, SEMAPHORE, EVENT, QUEUE) are
|
|
// reference-counted OBJECTs stored in the per-process handle table.
|
|
// SYS_CLOSE_HANDLE is the single close path for every type:
|
|
//
|
|
// KeCloseHandle(proc, handle)
|
|
// -> ObDereferenceObject(obj)
|
|
// -> obj->Destroy(obj) [type-specific cleanup, e.g. FileDestroy]
|
|
// -> MmFreePool(obj)
|
|
//
|
|
// There is no separate SyscallCloseFile. Removing that stub was the right
|
|
// call: the object model already handled it; the dedicated syscall was only
|
|
// adding a footgun where callers could bypass the unified refcount path.
|
|
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <string.h>
|
|
#include <ke_thread.h>
|
|
#include <ke_sched.h>
|
|
#include <ke_process.h>
|
|
#include <ke_mutex.h>
|
|
#include <ke_semaphore.h>
|
|
#include <ke_event.h>
|
|
#include <ke_queue.h>
|
|
#include <ke_debug.h>
|
|
#include <mm_virt.h>
|
|
#include <ldr_image.h>
|
|
#include <syscall_nr.h>
|
|
#include <hal_api.h>
|
|
#include <io_file.h>
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// HAL pointer - set once at boot by KeSyscallSetHal()
|
|
// ---------------------------------------------------------------------------
|
|
static const HAL_API* gHal;
|
|
|
|
void KeSyscallSetHal(const HAL_API* hal) { gHal = hal; }
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Helper: look up a handle and type-check it in one call.
|
|
// Bumps the refcount on success; caller must ObDereferenceObject when done.
|
|
// Returns NULL if the handle is invalid or the type does not match.
|
|
// ---------------------------------------------------------------------------
|
|
static OBJECT* HandleToObject(uint32_t handle, OBJECT_TYPE expected) {
|
|
PROCESS* proc = KeGetCurrentProcess();
|
|
if (!proc) return NULL;
|
|
OBJECT* obj = KeLookupHandle(proc, handle); // bumps refcount
|
|
if (!obj) return NULL;
|
|
if (obj->Type != expected) {
|
|
ObDereferenceObject(obj); // undo the bump
|
|
return NULL;
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Helper: allocate a handle in the current process's table for 'obj'.
|
|
// Takes one reference on behalf of the handle slot.
|
|
// On failure, drops the reference it would have stored.
|
|
// ---------------------------------------------------------------------------
|
|
static KSTATUS AllocHandleForCurrent(OBJECT* obj, uint32_t* handleOut) {
|
|
PROCESS* proc = KeGetCurrentProcess();
|
|
if (!proc) return STATUS_FAILURE;
|
|
KSTATUS s = KeAllocateHandle(proc, obj, handleOut);
|
|
if (!KSUCCESS(s)) ObDereferenceObject(obj);
|
|
return s;
|
|
}
|
|
|
|
// ===========================================================================
|
|
// Individual syscall handlers
|
|
// ===========================================================================
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_EXIT_PROCESS (0) a0 = exitCode
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallExitProcess(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
|
THREAD* t = KeGetCurrentThread();
|
|
PROCESS* proc = t ? t->Owner : NULL;
|
|
if (proc) KeExitProcess(proc, (int)a0);
|
|
if (t) KeExitThread(t, (int)a0);
|
|
while (true) ; // unreachable - KeExitThread does not return
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_EXIT_THREAD (1) a0 = exitCode
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallExitThread(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
|
THREAD* t = KeGetCurrentThread();
|
|
if (t) KeExitThread(t, (int)a0);
|
|
while (true);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_CREATE_THREAD (2) a0=entry a1=arg a2=priority a3=*tidOut
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallCreateThread(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a4; (void)a5;
|
|
PROCESS* proc = KeGetCurrentProcess();
|
|
if (!proc) return STATUS_FAILURE;
|
|
if (a2 >= PriorityCount) return STATUS_INVALID_PARAMETER;
|
|
|
|
THREAD* newt = NULL;
|
|
KSTATUS s = KeCreateThread(proc, (uintptr_t)a0, (uintptr_t)a1,
|
|
(THREAD_PRIORITY)a2, &newt);
|
|
if (!KSUCCESS(s)) return s;
|
|
if (a3) *(uint32_t*)(uintptr_t)a3 = newt->ThreadId;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_GET_CURRENT_TID (3)
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallGetCurrentTid(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a0; (void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
|
THREAD* t = KeGetCurrentThread();
|
|
return t ? t->ThreadId : 0;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_GET_CURRENT_PID (4)
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallGetCurrentPid(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a0; (void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
|
PROCESS* p = KeGetCurrentProcess();
|
|
return p ? p->ProcessId : 0;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_YIELD (5)
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallYield(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a0; (void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
|
KeYield();
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_SLEEP (6) a0 = milliseconds
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallSleep(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
|
if (!gHal) return STATUS_FAILURE;
|
|
uint64_t deadline = gHal->Timer.QueryTicks() + (uint64_t)a0;
|
|
while (gHal->Timer.QueryTicks() < deadline)
|
|
KeYield();
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_SET_THREAD_PRIORITY (7) a0 = priority
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallSetThreadPriority(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
|
if (a0 >= PriorityCount) return STATUS_INVALID_PARAMETER;
|
|
THREAD* t = KeGetCurrentThread();
|
|
if (!t) return STATUS_FAILURE;
|
|
t->Priority = (THREAD_PRIORITY)a0;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_ALLOC (8) a0 = size -> void*
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallAlloc(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
|
if (!a0) return 0;
|
|
return (uint64_t)(uintptr_t)MmAllocateUserMemory((size_t)a0);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_FREE (9) a0 = ptr, a1 = size
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallFree(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a2; (void)a3; (void)a4; (void)a5;
|
|
if (a0) MmFreeUserMemory((void*)(uintptr_t)a0, (size_t)a1);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_REALLOC (10) a0 = ptr, a1 = newSize -> void*
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallRealloc(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a2; (void)a3; (void)a4; (void)a5;
|
|
return (uint64_t)(uintptr_t)MmReallocateUserMemory(
|
|
(void*)(uintptr_t)a0, (size_t)a1);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_MUTEX_CREATE (11) a0 = *handleOut
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallMutexCreate(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
|
if (!a0) return STATUS_INVALID_PARAMETER;
|
|
MUTEX* mx = NULL;
|
|
KSTATUS s = MutexCreate(&mx);
|
|
if (!KSUCCESS(s)) return s;
|
|
uint32_t h = 0;
|
|
s = AllocHandleForCurrent(&mx->Header, &h); // takes ownership of the ref
|
|
if (!KSUCCESS(s)) return s;
|
|
*(uint32_t*)(uintptr_t)a0 = h;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_MUTEX_ACQUIRE (12) a0 = handle
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallMutexAcquire(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
|
MUTEX* mx = (MUTEX*)HandleToObject((uint32_t)a0, ObjectTypeMutex);
|
|
if (!mx) return STATUS_NOT_FOUND;
|
|
KSTATUS s = KeAcquireMutex(mx);
|
|
ObDereferenceObject(&mx->Header);
|
|
return s;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_MUTEX_TRY_ACQUIRE (13) a0 = handle
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallMutexTryAcquire(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
|
MUTEX* mx = (MUTEX*)HandleToObject((uint32_t)a0, ObjectTypeMutex);
|
|
if (!mx) return STATUS_NOT_FOUND;
|
|
KSTATUS s = KeTryAcquireMutex(mx);
|
|
ObDereferenceObject(&mx->Header);
|
|
return s;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_MUTEX_RELEASE (14) a0 = handle
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallMutexRelease(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
|
MUTEX* mx = (MUTEX*)HandleToObject((uint32_t)a0, ObjectTypeMutex);
|
|
if (!mx) return STATUS_NOT_FOUND;
|
|
KeReleaseMutex(mx);
|
|
ObDereferenceObject(&mx->Header);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_SEM_CREATE (15) a0=initial a1=max a2=*handleOut
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallSemCreate(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a3; (void)a4; (void)a5;
|
|
if (!a2) return STATUS_INVALID_PARAMETER;
|
|
SEMAPHORE* sem = NULL;
|
|
KSTATUS s = KeSemaphoreCreate((int32_t)a0, (int32_t)a1, &sem);
|
|
if (!KSUCCESS(s)) return s;
|
|
uint32_t h = 0;
|
|
s = AllocHandleForCurrent(&sem->Header, &h);
|
|
if (!KSUCCESS(s)) return s;
|
|
*(uint32_t*)(uintptr_t)a2 = h;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_SEM_WAIT (16) a0 = handle
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallSemWait(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
|
SEMAPHORE* sem = (SEMAPHORE*)HandleToObject((uint32_t)a0, ObjectTypeSemaphore);
|
|
if (!sem) return STATUS_NOT_FOUND;
|
|
KSTATUS s = KeWaitSemaphore(sem);
|
|
ObDereferenceObject(&sem->Header);
|
|
return s;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_SEM_TRY_WAIT (17) a0 = handle
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallSemTryWait(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
|
SEMAPHORE* sem = (SEMAPHORE*)HandleToObject((uint32_t)a0, ObjectTypeSemaphore);
|
|
if (!sem) return STATUS_NOT_FOUND;
|
|
KSTATUS s = KeTrySemaphore(sem);
|
|
ObDereferenceObject(&sem->Header);
|
|
return s;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_SEM_SIGNAL (18) a0 = handle
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallSemSignal(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
|
SEMAPHORE* sem = (SEMAPHORE*)HandleToObject((uint32_t)a0, ObjectTypeSemaphore);
|
|
if (!sem) return STATUS_NOT_FOUND;
|
|
KeSignalSemaphore(sem);
|
|
ObDereferenceObject(&sem->Header);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_EVENT_CREATE (19) a0=type a1=initialState a2=*handleOut
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallEventCreate(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a3; (void)a4; (void)a5;
|
|
if (!a2 || a0 > EventManualReset) return STATUS_INVALID_PARAMETER;
|
|
EVENT* ev = NULL;
|
|
KSTATUS s = KeEventCreate((EVENT_TYPE)a0, (uint32_t)a1, &ev);
|
|
if (!KSUCCESS(s)) return s;
|
|
uint32_t h = 0;
|
|
s = AllocHandleForCurrent(&ev->Header, &h);
|
|
if (!KSUCCESS(s)) return s;
|
|
*(uint32_t*)(uintptr_t)a2 = h;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_EVENT_SIGNAL (20) a0 = handle
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallEventSignal(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
|
EVENT* ev = (EVENT*)HandleToObject((uint32_t)a0, ObjectTypeEvent);
|
|
if (!ev) return STATUS_NOT_FOUND;
|
|
KeSignalEvent(ev);
|
|
ObDereferenceObject(&ev->Header);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_EVENT_CLEAR (21) a0 = handle
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallEventClear(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
|
EVENT* ev = (EVENT*)HandleToObject((uint32_t)a0, ObjectTypeEvent);
|
|
if (!ev) return STATUS_NOT_FOUND;
|
|
KeClearEvent(ev);
|
|
ObDereferenceObject(&ev->Header);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_EVENT_WAIT (22) a0 = handle
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallEventWait(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
|
EVENT* ev = (EVENT*)HandleToObject((uint32_t)a0, ObjectTypeEvent);
|
|
if (!ev) return STATUS_NOT_FOUND;
|
|
KSTATUS s = KeWaitForEvent(ev);
|
|
ObDereferenceObject(&ev->Header);
|
|
return s;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_QUEUE_CREATE (23) a0 = *handleOut
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallQueueCreate(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
|
if (!a0) return STATUS_INVALID_PARAMETER;
|
|
QUEUE* q = NULL;
|
|
KSTATUS s = QueueCreate(&q);
|
|
if (!KSUCCESS(s)) return s;
|
|
uint32_t h = 0;
|
|
s = AllocHandleForCurrent(&q->Header, &h);
|
|
if (!KSUCCESS(s)) return s;
|
|
*(uint32_t*)(uintptr_t)a0 = h;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_QUEUE_SEND (24) a0=handle a1=*msg a2=blocking
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallQueueSend(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a3; (void)a4; (void)a5;
|
|
if (!a1) return STATUS_INVALID_PARAMETER;
|
|
QUEUE* q = (QUEUE*)HandleToObject((uint32_t)a0, ObjectTypeQueue);
|
|
if (!q) return STATUS_NOT_FOUND;
|
|
KSTATUS s = KeSendMessage(q, (const QUEUE_MESSAGE*)(uintptr_t)a1, (bool)a2);
|
|
ObDereferenceObject(&q->Header);
|
|
return s;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_QUEUE_RECV (25) a0=handle a1=*msg a2=blocking
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallQueueRecv(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a3; (void)a4; (void)a5;
|
|
if (!a1) return STATUS_INVALID_PARAMETER;
|
|
QUEUE* q = (QUEUE*)HandleToObject((uint32_t)a0, ObjectTypeQueue);
|
|
if (!q) return STATUS_NOT_FOUND;
|
|
KSTATUS s = KeReceiveMessage(q, (QUEUE_MESSAGE*)(uintptr_t)a1, (bool)a2);
|
|
ObDereferenceObject(&q->Header);
|
|
return s;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_CLOSE_HANDLE (26) a0 = handle
|
|
//
|
|
// The one and only close path. KeCloseHandle drops the handle-table reference
|
|
// on 'obj'. If that was the last reference, ObDereferenceObject runs the
|
|
// type-specific Destroy callback (FileDestroy, etc.) and frees the pool memory.
|
|
// No per-type close syscall needed or wanted.
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallCloseHandle(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
|
PROCESS* proc = KeGetCurrentProcess();
|
|
if (!proc) return STATUS_FAILURE;
|
|
KeCloseHandle(proc, (uint32_t)a0);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_OPEN_FILE (27) a0=*path a1=*handleOut
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallOpenFile(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a2; (void)a3; (void)a4; (void)a5;
|
|
if (!a0 || !a1) return STATUS_INVALID_PARAMETER;
|
|
FILE_OBJECT* file = NULL;
|
|
KSTATUS s = IoOpenFile((const char*)(uintptr_t)a0, &file);
|
|
if (!KSUCCESS(s)) return s;
|
|
uint32_t h = 0;
|
|
s = AllocHandleForCurrent(&file->Header, &h);
|
|
if (!KSUCCESS(s)) {
|
|
// AllocHandleForCurrent already dropped the ref on failure;
|
|
// the refcount is now 0, so ObDereferenceObject will run FileDestroy.
|
|
ObDereferenceObject(&file->Header);
|
|
return s;
|
|
}
|
|
*(uint32_t*)(uintptr_t)a1 = h;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_READ_FILE (28) a0=handle a1=buf a2=size a3=*bytesReadOut
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallReadFile(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a4; (void)a5;
|
|
if (!a1) return STATUS_INVALID_PARAMETER;
|
|
FILE_OBJECT* file = (FILE_OBJECT*)HandleToObject((uint32_t)a0, ObjectTypeFile);
|
|
if (!file) return STATUS_NOT_FOUND;
|
|
size_t got = 0;
|
|
KSTATUS s = IoReadFile(file, (void*)(uintptr_t)a1, (size_t)a2, &got);
|
|
if (a3) *(size_t*)(uintptr_t)a3 = got;
|
|
ObDereferenceObject(&file->Header);
|
|
return s;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_WRITE_FILE (29) a0=handle a1=buf a2=size a3=*bytesWrittenOut
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallWriteFile(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a4; (void)a5;
|
|
if (!a1) return STATUS_INVALID_PARAMETER;
|
|
FILE_OBJECT* file = (FILE_OBJECT*)HandleToObject((uint32_t)a0, ObjectTypeFile);
|
|
if (!file) return STATUS_NOT_FOUND;
|
|
size_t written = 0;
|
|
KSTATUS s = IoWriteFile(file, (const void*)(uintptr_t)a1, (size_t)a2, &written);
|
|
if (a3) *(size_t*)(uintptr_t)a3 = written;
|
|
ObDereferenceObject(&file->Header);
|
|
return s;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_CREATE_FILE (30) a0=*path a1=*handleOut
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallCreateFile(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a2; (void)a3; (void)a4; (void)a5;
|
|
if (!a0 || !a1) return STATUS_INVALID_PARAMETER;
|
|
FILE_OBJECT* file = NULL;
|
|
KSTATUS s = IoCreateFile((const char*)(uintptr_t)a0, &file);
|
|
if (!KSUCCESS(s)) return s;
|
|
uint32_t h = 0;
|
|
s = AllocHandleForCurrent(&file->Header, &h);
|
|
if (!KSUCCESS(s)) {
|
|
ObDereferenceObject(&file->Header);
|
|
return s;
|
|
}
|
|
*(uint32_t*)(uintptr_t)a1 = h;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_DELETE_FILE (31) a0=*path
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallDeleteFile(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
|
if (!a0) return STATUS_INVALID_PARAMETER;
|
|
return IoDeleteFile((const char*)(uintptr_t)a0);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_TRUNCATE_FILE (32) a0=handle a1=newSize
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallTruncateFile(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a2; (void)a3; (void)a4; (void)a5;
|
|
FILE_OBJECT* file = (FILE_OBJECT*)HandleToObject((uint32_t)a0, ObjectTypeFile);
|
|
if (!file) return STATUS_NOT_FOUND;
|
|
KSTATUS s = IoTruncateFile(file, (uint64_t)a1);
|
|
ObDereferenceObject(&file->Header);
|
|
return s;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_GET_FILE_POS (33) a0=handle -> current seek offset
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallGetFilePos(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
|
FILE_OBJECT* file = (FILE_OBJECT*)HandleToObject((uint32_t)a0, ObjectTypeFile);
|
|
if (!file) return (uint64_t)-1;
|
|
uint64_t pos = file->Offset;
|
|
ObDereferenceObject(&file->Header);
|
|
return pos;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_SEEK_FILE (34) a0=handle a1=offset
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallSeekFile(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a2; (void)a3; (void)a4; (void)a5;
|
|
FILE_OBJECT* file = (FILE_OBJECT*)HandleToObject((uint32_t)a0, ObjectTypeFile);
|
|
if (!file) return STATUS_NOT_FOUND;
|
|
KSTATUS s = IoSeekFile(file, (uint64_t)a1);
|
|
ObDereferenceObject(&file->Header);
|
|
return s;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_GET_FILE_SIZE (35) a0=handle -> uint64_t
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallGetFileSize(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
|
FILE_OBJECT* file = (FILE_OBJECT*)HandleToObject((uint32_t)a0, ObjectTypeFile);
|
|
if (!file) return 0;
|
|
uint64_t sz = IoGetFileSize(file);
|
|
ObDereferenceObject(&file->Header);
|
|
return sz;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_SCREEN_BLIT (36) a0=x a1=y a2=w a3=h a4=*pixels
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallScreenBlit(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a5;
|
|
if (!gHal || !a4) return STATUS_FAILURE;
|
|
gHal->Screen.Blit((int)a0, (int)a1, (int)a2, (int)a3,
|
|
(const uint32_t*)(uintptr_t)a4);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_SCREEN_CLEAR (37) a0=color
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallScreenClear(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
|
if (!gHal) return STATUS_FAILURE;
|
|
gHal->Screen.Clear((uint32_t)a0);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_SCREEN_GET_SIZE (38) a0=*widthOut a1=*heightOut
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallScreenGetSize(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a2; (void)a3; (void)a4; (void)a5;
|
|
if (!gHal) return STATUS_FAILURE;
|
|
int w = 0, h = 0;
|
|
gHal->Screen.GetSize(&w, &h);
|
|
if (a0) *(int*)(uintptr_t)a0 = w;
|
|
if (a1) *(int*)(uintptr_t)a1 = h;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_SCREEN_PUT_CHAR (39) a0=c a1=x a2=y a3=fg a4=bg
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallScreenPutChar(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a5;
|
|
if (!gHal) return STATUS_FAILURE;
|
|
gHal->Screen.PutChar((char)a0, (int)a1, (int)a2,
|
|
(uint32_t)a3, (uint32_t)a4);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_KB_POLL (40) -> 1 or 0
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallKbPoll(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a0; (void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
|
if (!gHal) return 0;
|
|
return gHal->Keyboard.Poll();
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_KB_IS_KEY_DOWN (41) a0=scancode a1=extended -> 1 or 0
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallKbIsKeyDown(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a2; (void)a3; (void)a4; (void)a5;
|
|
|
|
// Check gHal and ensure the HAL struct actually has the new function pointer
|
|
if (!gHal || !gHal->Keyboard.IsKeyDown) return 0;
|
|
|
|
return gHal->Keyboard.IsKeyDown((uint8_t)a0, (bool)a1) ? 1u : 0u;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_KB_READ_CHAR (42) -> char (blocks, yields while waiting)
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallKbReadChar(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a0; (void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
|
if (!gHal) return 0;
|
|
while (!gHal->Keyboard.Poll()) KeYield();
|
|
return (uint64_t)(uint8_t)gHal->Keyboard.ReadChar();
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_KB_READ_SCANCODE (43) -> uint8_t (blocks, yields while waiting)
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallKbReadScancode(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a0; (void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
|
if (!gHal) return 0;
|
|
while (!gHal->Keyboard.Poll()) KeYield();
|
|
return (uint64_t)gHal->Keyboard.ReadScancode();
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_KB_GET_MODIFIERS (44) -> uint32_t
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallKbGetModifiers(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a0; (void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
|
if (!gHal) return 0;
|
|
return (uint64_t)gHal->Keyboard.GetModifiers();
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_MOUSE_POLL (45) -> 1 or 0
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallMousePoll(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a0; (void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
|
if (!gHal) return 0;
|
|
return gHal->Mouse.Poll() ? 1u : 0u;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_MOUSE_READ (46) a0=*dx a1=*dy a2=*buttons -> 1 or 0
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallMouseRead(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a3; (void)a4; (void)a5;
|
|
if (!gHal) return 0;
|
|
return gHal->Mouse.Read((int*)(uintptr_t)a0,
|
|
(int*)(uintptr_t)a1,
|
|
(uint8_t*)(uintptr_t)a2) ? 1u : 0u;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_MOUSE_GET_POS (47) a0=*x a1=*y
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallMouseGetPos(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a2; (void)a3; (void)a4; (void)a5;
|
|
if (!gHal) return 0;
|
|
gHal->Mouse.GetPosition((int*)(uintptr_t)a0, (int*)(uintptr_t)a1);
|
|
return 0;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_GET_TICK (48) -> uint64_t milliseconds
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallGetTick(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a0; (void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
|
return gHal ? gHal->Timer.QueryTicks() : 0;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_DEBUG_PRINT (49) a0=*str
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallDebugPrint(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
|
if (a0) DbgPrint("%s", (const char*)(uintptr_t)a0);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_CREATE_PROCESS (50) a0=*path a1=*handleOut a2=*cmdline (optional)
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallCreateProcess(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a3; (void)a4; (void)a5;
|
|
|
|
const char* path = (const char*)(uintptr_t)a0;
|
|
uint32_t* handleOut = (uint32_t*)(uintptr_t)a1;
|
|
const char* cmdline = (const char*)(uintptr_t)a2; // NULL = no args
|
|
if (!path || !handleOut) return STATUS_INVALID_PARAMETER;
|
|
|
|
// Read the executable from disk.
|
|
FILE_OBJECT* f;
|
|
KSTATUS s = IoOpenFile(path, &f);
|
|
if (!KSUCCESS(s)) return s;
|
|
|
|
uint64_t size = IoGetFileSize(f);
|
|
void* mem = MmAllocatePool(size);
|
|
if (!mem) { IoCloseFile(f); return STATUS_NO_MEMORY; }
|
|
|
|
size_t got;
|
|
s = IoReadFile(f, mem, size, &got);
|
|
IoCloseFile(f);
|
|
if (!KSUCCESS(s)) { MmFreePool(mem); return s; }
|
|
|
|
// Create the process object.
|
|
PROCESS* proc;
|
|
s = KeCreateProcess(path, &proc);
|
|
if (!KSUCCESS(s)) { MmFreePool(mem); return s; }
|
|
|
|
// Inherit CWD from parent
|
|
PROCESS* parent = KeGetCurrentProcess();
|
|
if (parent) {
|
|
uintptr_t flags = KeAcquireSpinlock(&parent->CwdLock);
|
|
strncpy(proc->CurrentDirectory, parent->CurrentDirectory, sizeof(proc->CurrentDirectory) - 1);
|
|
proc->CurrentDirectory[sizeof(proc->CurrentDirectory) - 1] = '\0';
|
|
KeReleaseSpinlock(&parent->CwdLock, flags);
|
|
}
|
|
|
|
s = KeSetupUserProcessEnvironment(proc, path, cmdline, proc->CurrentDirectory);
|
|
if (!KSUCCESS(s)) { MmFreePool(mem); ObDereferenceObject(&proc->Header); return s; }
|
|
|
|
// Map the PE image into memory.
|
|
uintptr_t imageBase = 0;
|
|
s = LdrLoadImage(mem, size, &imageBase, true);
|
|
MmFreePool(mem);
|
|
if (!KSUCCESS(s)) { ObDereferenceObject(&proc->Header); return s; }
|
|
|
|
s = LdrResolveImportsForProcess(proc, imageBase);
|
|
if (!KSUCCESS(s)) {
|
|
MmFreeUserMemory((void*)imageBase, LdrGetImageSize(imageBase));
|
|
ObDereferenceObject(&proc->Header);
|
|
return s;
|
|
}
|
|
|
|
proc->ImageBase = imageBase;
|
|
proc->ImageSize = LdrGetImageSize(imageBase);
|
|
|
|
// Give the caller a handle before making the child runnable. Otherwise a
|
|
// fast crash/exit can destroy the PROCESS while the syscall is still trying
|
|
// to finish wiring it up.
|
|
PROCESS* caller = KeGetCurrentProcess();
|
|
if (!caller) {
|
|
MmFreeUserMemory((void*)imageBase, proc->ImageSize);
|
|
ObDereferenceObject(&proc->Header);
|
|
return STATUS_FAILURE;
|
|
}
|
|
|
|
uint32_t handle;
|
|
s = KeAllocateHandle(caller, &proc->Header, &handle);
|
|
if (!KSUCCESS(s)) {
|
|
KeCloseHandle(caller, handle);
|
|
proc->ImageBase = 0;
|
|
proc->ImageSize = 0;
|
|
MmFreeUserMemory((void*)imageBase, proc->ImageSize);
|
|
ObDereferenceObject(&proc->Header);
|
|
return s;
|
|
}
|
|
|
|
// Spin up the initial thread last. KeCreateThread queues the thread before
|
|
// returning, so everything visible from exit/fault/wait paths must already
|
|
// be valid at this point.
|
|
THREAD* thread;
|
|
uintptr_t entryPoint = LdrGetEntryPoint(imageBase);
|
|
s = KeCreateThread(proc, entryPoint, 0, PriorityNormal, &thread);
|
|
if (!KSUCCESS(s)) {
|
|
MmFreeUserMemory((void*)imageBase, LdrGetImageSize(imageBase));
|
|
ObDereferenceObject(&proc->Header);
|
|
return s;
|
|
}
|
|
|
|
*handleOut = handle;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_WAIT_FOR_PROCESS (51) a0=handle
|
|
// Blocks until the target process signals its ExitEvent.
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallWaitForProcess(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
|
|
|
PROCESS* proc = (PROCESS*)HandleToObject((uint32_t)a0, ObjectTypeProcess);
|
|
if (!proc) return STATUS_INVALID_HANDLE;
|
|
|
|
KSTATUS s = KeWaitForEvent(proc->ExitEvent);
|
|
ObDereferenceObject(&proc->Header);
|
|
return s;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_GET_PROCESS_EXIT_CODE (52) a0=handle a1=*exitCodeOut
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallGetProcessExitCode(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a2; (void)a3; (void)a4; (void)a5;
|
|
|
|
PROCESS* proc = (PROCESS*)HandleToObject((uint32_t)a0, ObjectTypeProcess);
|
|
if (!proc) return STATUS_INVALID_HANDLE;
|
|
|
|
int* exitCodeOut = (int*)(uintptr_t)a1;
|
|
KSTATUS s = KeGetProcessExitCode(proc, exitCodeOut);
|
|
ObDereferenceObject(&proc->Header);
|
|
return s;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_WRITE_CONSOLE (53) a0=*buf a1=len
|
|
// Writes user console text in white; distinct from green SYS_DEBUG_PRINT.
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallWriteConsole(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a2; (void)a3; (void)a4; (void)a5;
|
|
const char* buf = (const char*)(uintptr_t)a0;
|
|
size_t len = (size_t)a1;
|
|
if (buf && len) KePrintConsole(buf, len);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_OPEN_DIR (54) a0=*dirPath a1=*handleOut
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallOpenDir(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a2; (void)a3; (void)a4; (void)a5;
|
|
const char* dirPath = (const char*)(uintptr_t)a0;
|
|
uint32_t* handleOut = (uint32_t*)(uintptr_t)a1;
|
|
|
|
if (!handleOut) return STATUS_INVALID_PARAMETER;
|
|
|
|
DIR_OBJECT* dir = NULL;
|
|
KSTATUS s = IoOpenDir(dirPath, &dir);
|
|
if (!KSUCCESS(s)) return s;
|
|
|
|
// Put the object in the handle table and get a valid index (1-255)
|
|
s = KeAllocateHandle(KeGetCurrentProcess(), &dir->Header, handleOut);
|
|
|
|
// Drop the reference KeAllocateHandle took, so that when user space
|
|
// calls CloseHandle, the refcount drops to 0 and the object is destroyed.
|
|
ObDereferenceObject(&dir->Header);
|
|
|
|
return s;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_READ_DIR (55) a0=handle a1=*KDIR_ENTRY
|
|
// Returns STATUS_NO_MORE_FILES when the directory is exhausted.
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallReadDir(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a2; (void)a3; (void)a4; (void)a5;
|
|
|
|
// a0 = handle from user mode
|
|
// a1 = KDIR_ENTRY* buffer
|
|
|
|
// Look up a DIR_OBJECT using ObjectTypeDir (not ObjectTypeFile)
|
|
DIR_OBJECT* dir = (DIR_OBJECT*)HandleToObject((uint32_t)a0, ObjectTypeDir);
|
|
if (!dir) return STATUS_INVALID_PARAMETER;
|
|
|
|
KSTATUS s = IoReadDir(dir, (void*)(uintptr_t)a1);
|
|
|
|
ObDereferenceObject(&dir->Header); // Drop the ref taken by HandleToObject
|
|
return s;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_SET_CWD (56) a0=*path
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallSetCwd(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
|
const char* path = (const char*)(uintptr_t)a0;
|
|
if (!path) return STATUS_INVALID_PARAMETER;
|
|
return IoSetCwd(path);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_GET_CWD (57) a0=*buf a1=size
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallGetCwd(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a2; (void)a3; (void)a4; (void)a5;
|
|
char* buf = (char*)(uintptr_t)a0;
|
|
size_t size = (size_t)a1;
|
|
if (!buf || size == 0) return STATUS_INVALID_PARAMETER;
|
|
return IoGetCwd(buf, size);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_WAIT_THREAD (58) a0=tid
|
|
// Blocks the caller until the thread with the given TID exits.
|
|
// Searches the current process's thread list; cross-process join is not
|
|
// supported in v1 (POSIX pthread_join is always intra-process).
|
|
// Returns STATUS_NOT_FOUND if the TID is unknown (already reaped or never
|
|
// existed) - treat the same as a successful join at the POSIX layer.
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallWaitThread(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
|
uint32_t targetTid = (uint32_t)a0;
|
|
|
|
PROCESS* proc = KeGetCurrentProcess();
|
|
if (!proc) return STATUS_FAILURE;
|
|
|
|
// Walk the thread list under the spinlock to find the target, then bump
|
|
// its ExitEvent refcount so the event survives even if the thread exits
|
|
// and is destroyed while we wait.
|
|
EVENT* exitEvent = (EVENT*)0;
|
|
uintptr_t flags = KeAcquireSpinlock(&proc->HandleLock);
|
|
LIST_ENTRY* entry = proc->ThreadList.Fwd;
|
|
while (entry != &proc->ThreadList) {
|
|
THREAD* t = CONTAINING_RECORD(entry, THREAD, ProcessLink);
|
|
if (t->ThreadId == targetTid && t->ExitEvent) {
|
|
exitEvent = t->ExitEvent;
|
|
ObReferenceObject(&exitEvent->Header); // keep event alive
|
|
break;
|
|
}
|
|
entry = entry->Fwd;
|
|
}
|
|
KeReleaseSpinlock(&proc->HandleLock, flags);
|
|
|
|
if (!exitEvent) {
|
|
// TID not found - either already exited and reaped, or invalid.
|
|
// Treat as success at the POSIX layer (join on an already-dead thread).
|
|
return STATUS_NOT_FOUND;
|
|
}
|
|
|
|
KSTATUS s = KeWaitForEvent(exitEvent);
|
|
ObDereferenceObject(&exitEvent->Header);
|
|
return s;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_GET_PROCESS_PID (59) a0=procHandle a1=*pidOut
|
|
// Returns the numeric PID of a process identified by handle.
|
|
// Used by posix_spawn to map the kernel handle back to a pid_t for waitpid.
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallGetProcessPid(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a2; (void)a3; (void)a4; (void)a5;
|
|
|
|
PROCESS* proc = (PROCESS*)HandleToObject((uint32_t)a0, ObjectTypeProcess);
|
|
uint32_t* pidOut = (uint32_t*)(uintptr_t)a1;
|
|
if (!proc) return STATUS_INVALID_HANDLE;
|
|
if (!pidOut) { ObDereferenceObject(&proc->Header); return STATUS_INVALID_PARAMETER; }
|
|
|
|
*pidOut = proc->ProcessId;
|
|
ObDereferenceObject(&proc->Header);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
// ===========================================================================
|
|
// 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];
|
|
QUEUE* Queue; // NULL = slot free; non-NULL = occupied
|
|
uint32_t PublisherPid; // ProcessId of whoever called SysPublishQueue
|
|
} NAMED_QUEUE_ENTRY;
|
|
|
|
static NAMED_QUEUE_ENTRY gNamedQueues[NAMED_QUEUE_MAX];
|
|
static SPINLOCK gNamedQueueLock;
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_PUBLISH_QUEUE (60) a0=*name a1=queueHandle
|
|
//
|
|
// Registers the queue identified by 'queueHandle' under 'name'.
|
|
// Fails with STATUS_ALREADY_EXISTS if the name is already taken.
|
|
// The registry bumps the queue's refcount so it outlives the handle.
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallPublishQueue(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a2; (void)a3; (void)a4; (void)a5;
|
|
|
|
const char* name = (const char*)(uintptr_t)a0;
|
|
if (!name || !name[0]) return STATUS_INVALID_PARAMETER;
|
|
|
|
// Resolve the handle to a QUEUE object. HandleToObject bumps the
|
|
// refcount by one; we keep that ref in the registry slot.
|
|
QUEUE* q = (QUEUE*)HandleToObject((uint32_t)a1, ObjectTypeQueue);
|
|
if (!q) return STATUS_INVALID_HANDLE;
|
|
|
|
uintptr_t flags = KeAcquireSpinlock(&gNamedQueueLock);
|
|
|
|
// Reject duplicate names.
|
|
for (int i = 0; i < NAMED_QUEUE_MAX; i++) {
|
|
if (gNamedQueues[i].Queue &&
|
|
strncmp(gNamedQueues[i].Name, name, NAMED_QUEUE_NAME_MAX) == 0) {
|
|
KeReleaseSpinlock(&gNamedQueueLock, flags);
|
|
ObDereferenceObject(&q->Header); // drop the ref we just took
|
|
return STATUS_ALREADY_EXISTS;
|
|
}
|
|
}
|
|
|
|
// Find a free slot.
|
|
for (int i = 0; i < NAMED_QUEUE_MAX; i++) {
|
|
if (!gNamedQueues[i].Queue) {
|
|
strncpy(gNamedQueues[i].Name, name, NAMED_QUEUE_NAME_MAX - 1);
|
|
gNamedQueues[i].Name[NAMED_QUEUE_NAME_MAX - 1] = '\0';
|
|
gNamedQueues[i].Queue = q; // ref transferred to registry
|
|
gNamedQueues[i].PublisherPid = KeGetCurrentProcess()->ProcessId;
|
|
KeReleaseSpinlock(&gNamedQueueLock, flags);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
KeReleaseSpinlock(&gNamedQueueLock, flags);
|
|
ObDereferenceObject(&q->Header); // no room - drop the ref
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_OPEN_NAMED_QUEUE (61) a0=*name a1=*handleOut
|
|
//
|
|
// Looks up 'name' in the registry and allocates a handle to the queue in the
|
|
// calling process's handle table. Returns STATUS_NOT_FOUND if no match.
|
|
// Callers that race against the publisher should retry on NOT_FOUND.
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallOpenNamedQueue(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a2; (void)a3; (void)a4; (void)a5;
|
|
|
|
const char* name = (const char*)(uintptr_t)a0;
|
|
uint32_t* handleOut = (uint32_t*)(uintptr_t)a1;
|
|
if (!name || !name[0] || !handleOut) return STATUS_INVALID_PARAMETER;
|
|
|
|
uintptr_t flags = KeAcquireSpinlock(&gNamedQueueLock);
|
|
|
|
QUEUE* q = NULL;
|
|
for (int i = 0; i < NAMED_QUEUE_MAX; i++) {
|
|
if (gNamedQueues[i].Queue &&
|
|
strncmp(gNamedQueues[i].Name, name, NAMED_QUEUE_NAME_MAX) == 0) {
|
|
q = gNamedQueues[i].Queue;
|
|
ObReferenceObject(&q->Header); // one ref for the new handle
|
|
break;
|
|
}
|
|
}
|
|
|
|
KeReleaseSpinlock(&gNamedQueueLock, flags);
|
|
|
|
if (!q) return STATUS_NOT_FOUND;
|
|
|
|
// AllocHandleForCurrent consumes the ref we just bumped.
|
|
// On failure it calls ObDereferenceObject internally.
|
|
return AllocHandleForCurrent(&q->Header, handleOut);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_QUEUE_DUPLICATE (62) a0=handle a1=targetPid a2=*handleOut
|
|
//
|
|
// Looks up the QUEUE behind 'handle' in the CALLER's table, then allocates
|
|
// a new handle for the same object in the TARGET process's table.
|
|
// Both processes share the same underlying QUEUE (refcount bumped).
|
|
// The caller's own handle is unchanged.
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallQueueDuplicate(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a3; (void)a4; (void)a5;
|
|
if (!a2) return STATUS_INVALID_PARAMETER;
|
|
|
|
QUEUE* q = (QUEUE*)HandleToObject((uint32_t)a0, ObjectTypeQueue);
|
|
if (!q) return STATUS_NOT_FOUND;
|
|
|
|
PROCESS* target = KeGetProcessById((uint32_t)a1);
|
|
if (!target) {
|
|
ObDereferenceObject(&q->Header);
|
|
return STATUS_NOT_FOUND;
|
|
}
|
|
|
|
uint32_t newHandle = 0;
|
|
KSTATUS s = KeAllocateHandle(target, &q->Header, &newHandle);
|
|
ObDereferenceObject(&target->Header);
|
|
ObDereferenceObject(&q->Header);
|
|
if (!KSUCCESS(s)) return s;
|
|
|
|
*(uint32_t*)(uintptr_t)a2 = newHandle;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_NAMED_QUEUE_OWNER_PID (63) a0=*name a1=*pidOut
|
|
//
|
|
// Returns the ProcessId of whoever published the named queue.
|
|
// Lets a client get the publisher's PID so it can duplicate one of its
|
|
// own handles into that process via SYS_QUEUE_DUPLICATE.
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallNamedQueueOwnerPid(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a2; (void)a3; (void)a4; (void)a5;
|
|
const char* name = (const char*)(uintptr_t)a0;
|
|
uint32_t* pidOut = (uint32_t*)(uintptr_t)a1;
|
|
if (!name || !name[0] || !pidOut) return STATUS_INVALID_PARAMETER;
|
|
|
|
uintptr_t flags = KeAcquireSpinlock(&gNamedQueueLock);
|
|
for (int i = 0; i < NAMED_QUEUE_MAX; i++) {
|
|
if (gNamedQueues[i].Queue &&
|
|
strncmp(gNamedQueues[i].Name, name, NAMED_QUEUE_NAME_MAX) == 0) {
|
|
*pidOut = gNamedQueues[i].PublisherPid;
|
|
KeReleaseSpinlock(&gNamedQueueLock, flags);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
KeReleaseSpinlock(&gNamedQueueLock, flags);
|
|
return STATUS_NOT_FOUND;
|
|
}
|
|
|
|
static uint64_t SyscallKillProcess(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a2; (void)a3; (void)a4; (void)a5;
|
|
PROCESS* proc = KeGetProcessById((uint32_t)a0);
|
|
if (!proc) return STATUS_NOT_FOUND;
|
|
THREAD* self = KeGetCurrentThread();
|
|
int exitCode = (int)a1;
|
|
if (self && self->Owner == proc) {
|
|
KeExitProcess(proc, exitCode);
|
|
ObDereferenceObject(&proc->Header);
|
|
KeExitThread(self, exitCode);
|
|
while (true) ;
|
|
}
|
|
KeExitProcess(proc, exitCode);
|
|
ObDereferenceObject(&proc->Header);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_GET_PROCESS_LIST (65) a0=*pidsOut a1=maxCount a2=*countOut
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallGetProcessList(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a3; (void)a4; (void)a5;
|
|
uint32_t* pidsOut = (uint32_t*)(uintptr_t)a0;
|
|
size_t maxCount = (size_t)a1;
|
|
size_t* countOut = (size_t*)(uintptr_t)a2;
|
|
size_t count = KeCopyProcessIds(pidsOut, maxCount);
|
|
if (countOut) *countOut = count;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_RENAME_FILE (66) a0=*oldPath a1=*newPath
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallRenameFile(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a2; (void)a3; (void)a4; (void)a5;
|
|
const char* oldPath = (const char*)(uintptr_t)a0;
|
|
const char* newPath = (const char*)(uintptr_t)a1;
|
|
if (!oldPath || !newPath) return STATUS_INVALID_PARAMETER;
|
|
return IoRenameFile(oldPath, newPath);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_CREATE_DIR (67) a0=*path
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallCreateDir(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
|
const char* path = (const char*)(uintptr_t)a0;
|
|
if (!path) return STATUS_INVALID_PARAMETER;
|
|
return IoCreateDir(path);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SYS_REMOVE_DIR (68) a0=*path
|
|
// ---------------------------------------------------------------------------
|
|
static uint64_t SyscallRemoveDir(uint64_t a0, uint64_t a1, uint64_t a2,
|
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
(void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
|
const char* path = (const char*)(uintptr_t)a0;
|
|
if (!path) return STATUS_INVALID_PARAMETER;
|
|
return IoRemoveDir(path);
|
|
}
|
|
|
|
// ===========================================================================
|
|
// Dispatch table - index must match SYS_* in syscall_nr.h exactly.
|
|
// ===========================================================================
|
|
typedef uint64_t (*SYSCALL_HANDLER)(uint64_t, uint64_t, uint64_t,
|
|
uint64_t, uint64_t, uint64_t);
|
|
|
|
static const SYSCALL_HANDLER gSyscallTable[SYS_MAX] = {
|
|
/* 00 SYS_EXIT_PROCESS */ SyscallExitProcess,
|
|
/* 01 SYS_EXIT_THREAD */ SyscallExitThread,
|
|
/* 02 SYS_CREATE_THREAD */ SyscallCreateThread,
|
|
/* 03 SYS_GET_CURRENT_TID */ SyscallGetCurrentTid,
|
|
/* 04 SYS_GET_CURRENT_PID */ SyscallGetCurrentPid,
|
|
/* 05 SYS_YIELD */ SyscallYield,
|
|
/* 06 SYS_SLEEP */ SyscallSleep,
|
|
/* 07 SYS_SET_THREAD_PRIORITY */ SyscallSetThreadPriority,
|
|
/* 08 SYS_ALLOC */ SyscallAlloc,
|
|
/* 09 SYS_FREE */ SyscallFree,
|
|
/* 10 SYS_REALLOC */ SyscallRealloc,
|
|
/* 11 SYS_MUTEX_CREATE */ SyscallMutexCreate,
|
|
/* 12 SYS_MUTEX_ACQUIRE */ SyscallMutexAcquire,
|
|
/* 13 SYS_MUTEX_TRY_ACQUIRE */ SyscallMutexTryAcquire,
|
|
/* 14 SYS_MUTEX_RELEASE */ SyscallMutexRelease,
|
|
/* 15 SYS_SEM_CREATE */ SyscallSemCreate,
|
|
/* 16 SYS_SEM_WAIT */ SyscallSemWait,
|
|
/* 17 SYS_SEM_TRY_WAIT */ SyscallSemTryWait,
|
|
/* 18 SYS_SEM_SIGNAL */ SyscallSemSignal,
|
|
/* 19 SYS_EVENT_CREATE */ SyscallEventCreate,
|
|
/* 20 SYS_EVENT_SIGNAL */ SyscallEventSignal,
|
|
/* 21 SYS_EVENT_CLEAR */ SyscallEventClear,
|
|
/* 22 SYS_EVENT_WAIT */ SyscallEventWait,
|
|
/* 23 SYS_QUEUE_CREATE */ SyscallQueueCreate,
|
|
/* 24 SYS_QUEUE_SEND */ SyscallQueueSend,
|
|
/* 25 SYS_QUEUE_RECV */ SyscallQueueRecv,
|
|
/* 26 SYS_CLOSE_HANDLE */ SyscallCloseHandle,
|
|
/* 27 SYS_OPEN_FILE */ SyscallOpenFile,
|
|
/* 28 SYS_READ_FILE */ SyscallReadFile,
|
|
/* 29 SYS_WRITE_FILE */ SyscallWriteFile,
|
|
/* 30 SYS_CREATE_FILE */ SyscallCreateFile,
|
|
/* 31 SYS_DELETE_FILE */ SyscallDeleteFile,
|
|
/* 32 SYS_TRUNCATE_FILE */ SyscallTruncateFile,
|
|
/* 33 SYS_GET_FILE_POS */ SyscallGetFilePos,
|
|
/* 34 SYS_SEEK_FILE */ SyscallSeekFile,
|
|
/* 35 SYS_GET_FILE_SIZE */ SyscallGetFileSize,
|
|
/* 36 SYS_SCREEN_BLIT */ SyscallScreenBlit,
|
|
/* 37 SYS_SCREEN_CLEAR */ SyscallScreenClear,
|
|
/* 38 SYS_SCREEN_GET_SIZE */ SyscallScreenGetSize,
|
|
/* 39 SYS_SCREEN_PUT_CHAR */ SyscallScreenPutChar,
|
|
/* 40 SYS_KB_POLL */ SyscallKbPoll,
|
|
/* 41 SYS_KB_IS_KEY_DOWN */ SyscallKbIsKeyDown,
|
|
/* 42 SYS_KB_READ_CHAR */ SyscallKbReadChar,
|
|
/* 43 SYS_KB_READ_SCANCODE */ SyscallKbReadScancode,
|
|
/* 44 SYS_KB_GET_MODIFIERS */ SyscallKbGetModifiers,
|
|
/* 45 SYS_MOUSE_POLL */ SyscallMousePoll,
|
|
/* 46 SYS_MOUSE_READ */ SyscallMouseRead,
|
|
/* 47 SYS_MOUSE_GET_POS */ SyscallMouseGetPos,
|
|
/* 48 SYS_GET_TICK */ SyscallGetTick,
|
|
/* 49 SYS_DEBUG_PRINT */ SyscallDebugPrint,
|
|
/* 50 SYS_CREATE_PROCESS */ SyscallCreateProcess,
|
|
/* 51 SYS_WAIT_FOR_PROCESS */ SyscallWaitForProcess,
|
|
/* 52 SYS_GET_PROCESS_EXIT_CODE */ SyscallGetProcessExitCode,
|
|
/* 53 SYS_WRITE_CONSOLE */ SyscallWriteConsole,
|
|
/* 54 SYS_OPEN_DIR */ SyscallOpenDir,
|
|
/* 55 SYS_READ_DIR */ SyscallReadDir,
|
|
/* 56 SYS_SET_CWD */ SyscallSetCwd,
|
|
/* 57 SYS_GET_CWD */ SyscallGetCwd,
|
|
/* 58 SYS_WAIT_THREAD */ SyscallWaitThread,
|
|
/* 59 SYS_GET_PROCESS_PID */ SyscallGetProcessPid,
|
|
/* 60 SYS_PUBLISH_QUEUE */ SyscallPublishQueue,
|
|
/* 61 SYS_OPEN_NAMED_QUEUE */ SyscallOpenNamedQueue,
|
|
/* 62 SYS_QUEUE_DUPLICATE */ SyscallQueueDuplicate,
|
|
/* 63 SYS_NAMED_QUEUE_OWNER_PID */ SyscallNamedQueueOwnerPid,
|
|
/* 64 SYS_KILL_PROCESS */ SyscallKillProcess,
|
|
/* 65 SYS_GET_PROCESS_LIST */ SyscallGetProcessList,
|
|
/* 66 SYS_RENAME_FILE */ SyscallRenameFile,
|
|
/* 67 SYS_CREATE_DIR */ SyscallCreateDir,
|
|
/* 68 SYS_REMOVE_DIR */ SyscallRemoveDir,
|
|
};
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Entry point - called from ke_syscall.asm after argument re-ordering
|
|
// ---------------------------------------------------------------------------
|
|
KSTATUS KeSyscallDispatch(uint64_t nr, uint64_t a0, uint64_t a1,
|
|
uint64_t a2, uint64_t a3, uint64_t a4, uint64_t a5) {
|
|
if (nr >= SYS_MAX || !gSyscallTable[nr]) return STATUS_NOT_SUPPORTED;
|
|
return (KSTATUS)gSyscallTable[nr](a0, a1, a2, a3, a4, a5);
|
|
}
|