Permalink
Cannot retrieve contributors at this time
Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.
Sign up
Fetching contributors…
| /*++ | |
| Copyright (c) 2013 Minoca Corp. | |
| This file is licensed under the terms of the GNU General Public License | |
| version 3. Alternative licensing terms are available. Contact | |
| info@minocacorp.com for details. See the LICENSE file at the root of this | |
| project for complete licensing information. | |
| Module Name: | |
| syscall.c | |
| Abstract: | |
| This module implements the interface between user and kernel mode. | |
| Author: | |
| Evan Green 6-Feb-2013 | |
| Environment: | |
| Kernel | |
| --*/ | |
| // | |
| // ------------------------------------------------------------------- Includes | |
| // | |
| #include <minoca/kernel/kernel.h> | |
| // | |
| // ---------------------------------------------------------------- Definitions | |
| // | |
| // | |
| // ------------------------------------------------------ Data Type Definitions | |
| // | |
| /*++ | |
| Structure Description: | |
| This structure stores information about a particular system call. | |
| Members: | |
| HandlerRoutine - Supplies a pointer to the routine that handles this system | |
| call. | |
| CopyInSize - Supplies the size, in bytes, of the parameter structure for | |
| this system call that needs to be copied in from user mode to kernel | |
| mode. This should be set to a sizeof(something), rather than a | |
| hard-coded number. | |
| CopyOutSize - Supplies the size, in bytes, of the parameter structure for | |
| this system call that needs to be copied out to user mode from kernel | |
| mode after the handler routine is executed. This should be set to | |
| sizeof(something), rather than a hard-coded number. | |
| --*/ | |
| typedef struct _SYSTEM_CALL_TABLE_ENTRY { | |
| PSYSTEM_CALL_ROUTINE HandlerRoutine; | |
| ULONG CopyInSize; | |
| ULONG CopyOutSize; | |
| } SYSTEM_CALL_TABLE_ENTRY, *PSYSTEM_CALL_TABLE_ENTRY; | |
| // | |
| // ----------------------------------------------- Internal Function Prototypes | |
| // | |
| INTN | |
| KepTestSystemCall ( | |
| PVOID SystemCallParameter | |
| ); | |
| // | |
| // -------------------------------------------------------------------- Globals | |
| // | |
| // | |
| // Store the global system call table. | |
| // | |
| SYSTEM_CALL_TABLE_ENTRY KeSystemCallTable[SystemCallCount] = { | |
| {KepTestSystemCall, 0, 0}, | |
| {PsSysRestoreContext, 0, 0}, | |
| {PsSysForkProcess, sizeof(SYSTEM_CALL_FORK), 0}, | |
| {PsSysExitThread, sizeof(SYSTEM_CALL_EXIT_THREAD), 0}, | |
| {IoSysOpen, sizeof(SYSTEM_CALL_OPEN), sizeof(SYSTEM_CALL_OPEN)}, | |
| {IoSysClose, 0, 0}, | |
| {IoSysPerformIo, sizeof(SYSTEM_CALL_PERFORM_IO), 0}, | |
| {IoSysCreatePipe, | |
| sizeof(SYSTEM_CALL_CREATE_PIPE), | |
| sizeof(SYSTEM_CALL_CREATE_PIPE)}, | |
| {PsSysCreateThread, | |
| sizeof(SYSTEM_CALL_CREATE_THREAD), | |
| sizeof(SYSTEM_CALL_CREATE_THREAD)}, | |
| {PsSysExecuteImage, sizeof(SYSTEM_CALL_EXECUTE_IMAGE), 0}, | |
| {IoSysChangeDirectory, sizeof(SYSTEM_CALL_CHANGE_DIRECTORY), 0}, | |
| {PsSysSetSignalHandler, | |
| sizeof(SYSTEM_CALL_SET_SIGNAL_HANDLER), | |
| sizeof(SYSTEM_CALL_SET_SIGNAL_HANDLER)}, | |
| {PsSysSendSignal, sizeof(SYSTEM_CALL_SEND_SIGNAL), 0}, | |
| {PsSysGetSetProcessId, sizeof(SYSTEM_CALL_GET_SET_PROCESS_ID), 0}, | |
| {PsSysSetSignalBehavior, | |
| sizeof(SYSTEM_CALL_SET_SIGNAL_BEHAVIOR), | |
| sizeof(SYSTEM_CALL_SET_SIGNAL_BEHAVIOR)}, | |
| {PsSysWaitForChildProcess, | |
| sizeof(SYSTEM_CALL_WAIT_FOR_CHILD), | |
| sizeof(SYSTEM_CALL_WAIT_FOR_CHILD)}, | |
| {PsSysSuspendExecution, | |
| sizeof(SYSTEM_CALL_SUSPEND_EXECUTION), | |
| sizeof(SYSTEM_CALL_SUSPEND_EXECUTION)}, | |
| {PsSysExitProcess, 0, 0}, | |
| {IoSysPoll, sizeof(SYSTEM_CALL_POLL), 0}, | |
| {IoSysSocketCreate, | |
| sizeof(SYSTEM_CALL_SOCKET_CREATE), | |
| sizeof(SYSTEM_CALL_SOCKET_CREATE)}, | |
| {IoSysSocketBind, sizeof(SYSTEM_CALL_SOCKET_BIND), 0}, | |
| {IoSysSocketListen, sizeof(SYSTEM_CALL_SOCKET_LISTEN), 0}, | |
| {IoSysSocketAccept, | |
| sizeof(SYSTEM_CALL_SOCKET_ACCEPT), | |
| sizeof(SYSTEM_CALL_SOCKET_ACCEPT)}, | |
| {IoSysSocketConnect, sizeof(SYSTEM_CALL_SOCKET_CONNECT), 0}, | |
| {IoSysSocketPerformIo, sizeof(SYSTEM_CALL_SOCKET_PERFORM_IO), 0}, | |
| {IoSysFileControl, sizeof(SYSTEM_CALL_FILE_CONTROL), 0}, | |
| {IoSysGetSetFileInformation, | |
| sizeof(SYSTEM_CALL_GET_SET_FILE_INFORMATION), | |
| sizeof(SYSTEM_CALL_GET_SET_FILE_INFORMATION)}, | |
| {PsSysDebug, sizeof(SYSTEM_CALL_DEBUG), sizeof(SYSTEM_CALL_DEBUG)}, | |
| {IoSysSeek, sizeof(SYSTEM_CALL_SEEK), sizeof(SYSTEM_CALL_SEEK)}, | |
| {IoSysCreateSymbolicLink, sizeof(SYSTEM_CALL_CREATE_SYMBOLIC_LINK), 0}, | |
| {IoSysReadSymbolicLink, | |
| sizeof(SYSTEM_CALL_READ_SYMBOLIC_LINK), | |
| sizeof(SYSTEM_CALL_READ_SYMBOLIC_LINK)}, | |
| {IoSysDelete, sizeof(SYSTEM_CALL_DELETE), 0}, | |
| {IoSysRename, sizeof(SYSTEM_CALL_RENAME), 0}, | |
| {IoSysMountOrUnmount, sizeof(SYSTEM_CALL_MOUNT_UNMOUNT), 0}, | |
| {PsSysQueryTimeCounter, 0, sizeof(SYSTEM_CALL_QUERY_TIME_COUNTER)}, | |
| {PsSysTimerControl, | |
| sizeof(SYSTEM_CALL_TIMER_CONTROL), | |
| sizeof(SYSTEM_CALL_TIMER_CONTROL)}, | |
| {IoSysGetEffectiveAccess, | |
| sizeof(SYSTEM_CALL_GET_EFFECTIVE_ACCESS), | |
| sizeof(SYSTEM_CALL_GET_EFFECTIVE_ACCESS)}, | |
| {KeSysDelayExecution, sizeof(SYSTEM_CALL_DELAY_EXECUTION), 0}, | |
| {IoSysUserControl, sizeof(SYSTEM_CALL_USER_CONTROL), 0}, | |
| {IoSysFlush, sizeof(SYSTEM_CALL_FLUSH), 0}, | |
| {PsSysGetResourceUsage, | |
| sizeof(SYSTEM_CALL_GET_RESOURCE_USAGE), | |
| sizeof(SYSTEM_CALL_GET_RESOURCE_USAGE)}, | |
| {IoSysLoadDriver, sizeof(SYSTEM_CALL_LOAD_DRIVER), 0}, | |
| {MmSysFlushCache, sizeof(SYSTEM_CALL_FLUSH_CACHE), 0}, | |
| {IoSysGetCurrentDirectory, | |
| sizeof(SYSTEM_CALL_GET_CURRENT_DIRECTORY), | |
| sizeof(SYSTEM_CALL_GET_CURRENT_DIRECTORY)}, | |
| {IoSysSocketGetSetInformation, | |
| sizeof(SYSTEM_CALL_SOCKET_GET_SET_INFORMATION), | |
| sizeof(SYSTEM_CALL_SOCKET_GET_SET_INFORMATION)}, | |
| {IoSysSocketShutdown, sizeof(SYSTEM_CALL_SOCKET_SHUTDOWN), 0}, | |
| {IoSysCreateHardLink, sizeof(SYSTEM_CALL_CREATE_HARD_LINK), 0}, | |
| {MmSysMapOrUnmapMemory, | |
| sizeof(SYSTEM_CALL_MAP_UNMAP_MEMORY), | |
| sizeof(SYSTEM_CALL_MAP_UNMAP_MEMORY)}, | |
| {MmSysFlushMemory, sizeof(SYSTEM_CALL_FLUSH_MEMORY), 0}, | |
| {IoSysLocateDeviceInformation, | |
| sizeof(SYSTEM_CALL_LOCATE_DEVICE_INFORMATION), | |
| sizeof(SYSTEM_CALL_LOCATE_DEVICE_INFORMATION)}, | |
| {IoSysGetSetDeviceInformation, | |
| sizeof(SYSTEM_CALL_GET_SET_DEVICE_INFORMATION), | |
| sizeof(SYSTEM_CALL_GET_SET_DEVICE_INFORMATION)}, | |
| {IoSysOpenDevice, | |
| sizeof(SYSTEM_CALL_OPEN_DEVICE), | |
| sizeof(SYSTEM_CALL_OPEN_DEVICE)}, | |
| {KeSysGetSetSystemInformation, | |
| sizeof(SYSTEM_CALL_GET_SET_SYSTEM_INFORMATION), | |
| sizeof(SYSTEM_CALL_GET_SET_SYSTEM_INFORMATION)}, | |
| {KeSysResetSystem, 0, 0}, | |
| {KeSysSetSystemTime, sizeof(SYSTEM_CALL_SET_SYSTEM_TIME), 0}, | |
| {MmSysSetMemoryProtection, sizeof(SYSTEM_CALL_SET_MEMORY_PROTECTION), 0}, | |
| {PsSysSetThreadIdentity, | |
| sizeof(SYSTEM_CALL_SET_THREAD_IDENTITY), | |
| sizeof(SYSTEM_CALL_SET_THREAD_IDENTITY)}, | |
| {PsSysSetThreadPermissions, | |
| sizeof(SYSTEM_CALL_SET_THREAD_PERMISSIONS), | |
| sizeof(SYSTEM_CALL_SET_THREAD_PERMISSIONS)}, | |
| {PsSysSetSupplementaryGroups, | |
| sizeof(SYSTEM_CALL_SET_SUPPLEMENTARY_GROUPS), | |
| sizeof(SYSTEM_CALL_SET_SUPPLEMENTARY_GROUPS)}, | |
| {IoSysSocketCreatePair, | |
| sizeof(SYSTEM_CALL_SOCKET_CREATE_PAIR), | |
| sizeof(SYSTEM_CALL_SOCKET_CREATE_PAIR)}, | |
| {IoSysCreateTerminal, | |
| sizeof(SYSTEM_CALL_CREATE_TERMINAL), | |
| sizeof(SYSTEM_CALL_CREATE_TERMINAL)}, | |
| {IoSysSocketPerformVectoredIo, | |
| sizeof(SYSTEM_CALL_SOCKET_PERFORM_VECTORED_IO), | |
| 0}, | |
| {PsSysSetThreadPointer, 0, 0}, | |
| {PsSysUserLock, | |
| sizeof(SYSTEM_CALL_USER_LOCK), | |
| sizeof(SYSTEM_CALL_USER_LOCK)}, | |
| {PsSysSetThreadIdPointer, 0, 0}, | |
| {PsSysSetUmask, | |
| sizeof(SYSTEM_CALL_SET_UMASK), | |
| sizeof(SYSTEM_CALL_SET_UMASK)}, | |
| {IoSysDuplicateHandle, | |
| sizeof(SYSTEM_CALL_DUPLICATE_HANDLE), | |
| sizeof(SYSTEM_CALL_DUPLICATE_HANDLE)}, | |
| {IoSysPerformVectoredIo, sizeof(SYSTEM_CALL_PERFORM_VECTORED_IO), 0}, | |
| {PsSysSetITimer, | |
| sizeof(SYSTEM_CALL_SET_ITIMER), | |
| sizeof(SYSTEM_CALL_SET_ITIMER)}, | |
| {PsSysSetResourceLimit, | |
| sizeof(SYSTEM_CALL_SET_RESOURCE_LIMIT), | |
| sizeof(SYSTEM_CALL_SET_RESOURCE_LIMIT)}, | |
| {MmSysSetBreak, | |
| sizeof(SYSTEM_CALL_SET_BREAK), | |
| sizeof(SYSTEM_CALL_SET_BREAK)}, | |
| }; | |
| // | |
| // ------------------------------------------------------------------ Functions | |
| // | |
| INTN | |
| KeSystemCallHandler ( | |
| ULONG SystemCallNumber, | |
| PVOID SystemCallParameter, | |
| PTRAP_FRAME TrapFrame, | |
| PUINTN SignalPending | |
| ) | |
| /*++ | |
| Routine Description: | |
| This routine responds to requests from user mode entered via a system call. | |
| It may also be called by the restore system call in order to restart a | |
| system call. This should not be seen as a general way to invoke system call | |
| behavior from inside the kernel. | |
| Arguments: | |
| SystemCallNumber - Supplies the system call number. | |
| SystemCallParameter - Supplies a pointer to the parameters supplied with | |
| the system call. | |
| TrapFrame - Supplies a pointer to the trap frame generated by this jump | |
| from user mode to kernel mode. | |
| SignalPending - Supplies a pointer where a boolean will be returned | |
| indicating if a signal is pending on the current thread or process that | |
| needs to be dispatched. | |
| Return Value: | |
| STATUS_SUCCESS or positive integer on success. | |
| Error status code on failure. | |
| --*/ | |
| { | |
| PSYSTEM_CALL_TABLE_ENTRY Handler; | |
| SYSTEM_CALL_PARAMETER_UNION LocalParameters; | |
| INTN Result; | |
| KSTATUS Status; | |
| PKTHREAD Thread; | |
| // | |
| // Begin charging kernel mode for cycles. | |
| // | |
| Status = STATUS_SUCCESS; | |
| KeBeginCycleAccounting(CycleAccountKernel); | |
| Thread = KeGetCurrentThread(); | |
| Thread->Flags |= THREAD_FLAG_IN_SYSTEM_CALL; | |
| Thread->TrapFrame = TrapFrame; | |
| // | |
| // Validate the system call number. | |
| // | |
| if (SystemCallNumber >= SystemCallCount) { | |
| Status = STATUS_OUT_OF_BOUNDS; | |
| goto SystemCallHandlerEnd; | |
| } | |
| Handler = &(KeSystemCallTable[SystemCallNumber]); | |
| // | |
| // Copy the parameters to the stack local copy, if there are any. | |
| // | |
| if ((Handler->CopyInSize != 0) || (Handler->CopyOutSize != 0)) { | |
| if (Handler->CopyInSize != 0) { | |
| ASSERT(Handler->CopyInSize <= sizeof(SYSTEM_CALL_PARAMETER_UNION)); | |
| Status = MmCopyFromUserMode(&LocalParameters, | |
| SystemCallParameter, | |
| Handler->CopyInSize); | |
| if (!KSUCCESS(Status)) { | |
| PsSignalThread(Thread, SIGNAL_ACCESS_VIOLATION, NULL, TRUE); | |
| goto SystemCallHandlerEnd; | |
| } | |
| } | |
| // | |
| // Call the handler. | |
| // | |
| Result = Handler->HandlerRoutine(&LocalParameters); | |
| // | |
| // Copy the local parameters back into user mode. | |
| // | |
| if (Handler->CopyOutSize != 0) { | |
| ASSERT(Handler->CopyOutSize <= sizeof(SYSTEM_CALL_PARAMETER_UNION)); | |
| Status = MmCopyToUserMode(SystemCallParameter, | |
| &LocalParameters, | |
| Handler->CopyOutSize); | |
| if (!KSUCCESS(Status)) { | |
| PsSignalThread(Thread, SIGNAL_ACCESS_VIOLATION, NULL, TRUE); | |
| goto SystemCallHandlerEnd; | |
| } | |
| } | |
| // | |
| // Even if there is no data to copy in, still pass the system call | |
| // parameters along. The handler may be doing something special with them. | |
| // | |
| } else { | |
| Result = Handler->HandlerRoutine(SystemCallParameter); | |
| } | |
| SystemCallHandlerEnd: | |
| if (!KSUCCESS(Status)) { | |
| Result = Status; | |
| } | |
| PsCheckRuntimeTimers(Thread); | |
| // | |
| // Let the assembly know whether or not there's a signal pending so they | |
| // don't have to do a bunch of complicated work. | |
| // | |
| *SignalPending = (Thread->SignalPending != ThreadNoSignalPending); | |
| // | |
| // Return to the previous thread state and cycle account. | |
| // | |
| Thread->Flags &= ~THREAD_FLAG_IN_SYSTEM_CALL; | |
| KeBeginCycleAccounting(CycleAccountUser); | |
| return Result; | |
| } | |
| // | |
| // --------------------------------------------------------- Internal Functions | |
| // | |
| INTN | |
| KepTestSystemCall ( | |
| PVOID SystemCallParameter | |
| ) | |
| /*++ | |
| Routine Description: | |
| This routine implements a test system call. | |
| Arguments: | |
| SystemCallParameter - Supplies a pointer to the parameters supplied with | |
| the system call. This structure will be a stack-local copy of the | |
| actual parameters passed from user-mode. | |
| Return Value: | |
| STATUS_SUCCESS or positive integer on success. | |
| Error status code on failure. | |
| --*/ | |
| { | |
| RtlDebugPrint("Test system call!\n"); | |
| return STATUS_SUCCESS; | |
| } | |