NtSyscallFailure(void)
{
/* This is the failure function */
- return STATUS_ACCESS_VIOLATION;
+ return (NTSTATUS)KeGetCurrentThread()->TrapFrame->Rax;
}
PVOID
KiSystemCallHandler(
- IN PKTRAP_FRAME TrapFrame,
- IN ULONG64 P2,
- IN ULONG64 P3,
- IN ULONG64 P4)
+ _In_ ULONG64 ReturnAddress,
+ _In_ ULONG64 P2,
+ _In_ ULONG64 P3,
+ _In_ ULONG64 P4)
{
+ PKTRAP_FRAME TrapFrame;
PKSERVICE_TABLE_DESCRIPTOR DescriptorTable;
PKTHREAD Thread;
PULONG64 KernelParams, UserParams;
ULONG ServiceNumber, Offset, Count;
ULONG64 UserRsp;
- NTSTATUS Status;
+
+ /* Get a pointer to the trap frame */
+ TrapFrame = (PKTRAP_FRAME)((PULONG64)_AddressOfReturnAddress() + 1 + MAX_SYSCALL_PARAMS);
+
+ /* Save some values in the trap frame */
+ TrapFrame->Rip = ReturnAddress;
+ TrapFrame->Rdx = P2;
+ TrapFrame->R8 = P3;
+ TrapFrame->R9 = P4;
/* Increase system call count */
__addgsdword(FIELD_OFFSET(KIPCR, Prcb.KeSystemCalls), 1);
return (PVOID)NtSyscallFailure;
}
- /* Convert us to a GUI thread -- must wrap in ASM to get new EBP */
- Status = KiConvertToGuiThread();
-
- /* Reload trap frame and descriptor table pointer from new stack */
- TrapFrame = *(volatile PVOID*)&Thread->TrapFrame;
- DescriptorTable = (PVOID)(*(volatile ULONG_PTR*)&Thread->ServiceTable + Offset);
-
- if (!NT_SUCCESS(Status))
- {
- /* Set the last error and fail */
- TrapFrame->Rax = Status;
- return (PVOID)NtSyscallFailure;
- }
-
- /* Validate the system call number again */
- if (ServiceNumber >= DescriptorTable->Limit)
- {
- /* Fail the call */
- TrapFrame->Rax = STATUS_INVALID_SYSTEM_SERVICE;
- return (PVOID)NtSyscallFailure;
- }
+ /* Convert us to a GUI thread
+ To be entirely correct. we return KiConvertToGuiThread,
+ which allocates a new stack, switches to it, calls
+ PsConvertToGuiThread and resumes in the middle of
+ KiSystemCallEntry64 to restart the system call handling. */
+ return (PVOID)KiConvertToGuiThread;
}
/* Get stack bytes and calculate argument count */
case 7: KernelParams[6] = UserParams[6];
case 6: KernelParams[5] = UserParams[5];
case 5: KernelParams[4] = UserParams[4];
- case 4: KernelParams[3] = P4;
- case 3: KernelParams[2] = P3;
- case 2: KernelParams[1] = P2;
- case 1: KernelParams[0] = TrapFrame->R10;
+ case 4:
+ case 3:
+ case 2:
+ case 1:
case 0:
break;
EXTERN KiDeliverApc:PROC
EXTERN KiDpcInterruptHandler:PROC
EXTERN PsConvertToGuiThread:PROC
+EXTERN MmCreateKernelStack:PROC
+EXTERN KeSwitchKernelStack:PROC
+EXTERN MmDeleteKernelStack:PROC
#ifdef _WINKD_
EXTERN KdSetOwedBreakpoints:PROC
#define MAX_SYSCALL_PARAM_SIZE (16 * 8)
-#define HOME_SIZE 6*8
-#define SYSCALL_ALLOCATION (MAX_SYSCALL_PARAM_SIZE + HOME_SIZE)
EXTERN KiSystemCallHandler:PROC
mov rsp, gs:[PcRspBase]
/* Allocate a TRAP_FRAME and space for parameters */
- sub rsp, (KTRAP_FRAME_LENGTH + MAX_SYSCALL_PARAM_SIZE + HOME_SIZE)
+ sub rsp, (KTRAP_FRAME_LENGTH + MAX_SYSCALL_PARAM_SIZE)
#if DBG
/* Save rbp and load it with the old stack pointer */
- mov [rsp + HOME_SIZE + MAX_SYSCALL_PARAM_SIZE + HOME_SIZE + KTRAP_FRAME_Rbp], rbp
+ mov [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rbp], rbp
mov rbp, gs:[PcUserRsp]
#endif
- /* Save important volatiles in the trap frame */
- mov [rsp + HOME_SIZE + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rax], rax
- mov [rsp + HOME_SIZE + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rcx], rcx
- mov [rsp + HOME_SIZE + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_R10], r10
- mov [rsp + HOME_SIZE + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_R11], r11
+ /* Save important registers in the trap frame */
+ mov [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rax], rax
+ mov [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rcx], r10
+ mov [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_EFlags], r11
/* Set sane segments */
mov ax, (KGDT64_R3_DATA or RPL_MASK)
mov ds, ax
mov es, ax
+.ENDP
+
+.PROC KiSystemCall64Again
+
+ /* Old stack pointer is in rcx, lie and say we saved it in rbp */
+ .setframe rbp, 0
+ .endprolog
+
/* Call the C-handler (will enable interrupts) */
- lea rcx, [rsp + SYSCALL_ALLOCATION]
call KiSystemCallHandler
- /* Deallocate the handlers home stack frame */
- add rsp, HOME_SIZE
-
- /* The return value is the address of the Nt-function */
- mov rcx, [rsp + 0]
- mov rdx, [rsp + 8]
- mov r8, [rsp + 16]
- mov r9, [rsp + 24]
+ /* The return value from KiSystemCallHandler is the address of the Nt-function */
+ mov rcx, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rcx]
+ mov rdx, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rdx]
+ mov r8, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_R8]
+ mov r9, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_R9]
call rax
#if DBG
/* Restore rbp */
- mov rbp, [rsp + SYSCALL_ALLOCATION + KTRAP_FRAME_Rbp]
+ mov rbp, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rbp]
test dword ptr [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_EFlags], HEX(200)
jnz IntsEnabled
mov [rcx + KTHREAD_TrapFrame], rdx
/* Prepare user mode return address (rcx) and eflags (r11) for sysret */
- mov rcx, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rcx]
- mov r11, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_R11]
+ mov rcx, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rip]
+ mov r11, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_EFlags]
/* Load user mode stack (It was copied to the trap frame) */
mov rsp, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rsp]
/* return to user mode */
.byte HEX(48) // REX prefix to return to long mode
sysret
+
.ENDP
PUBLIC KiConvertToGuiThread
FUNC KiConvertToGuiThread
- push rbp
- .pushreg rbp
- sub rsp, 32
- .allocstack 32
+ sub rsp, 40
+ .allocstack 40
.endprolog
+ // NewStack = (ULONG_PTR)MmCreateKernelStack(TRUE, 0);
+ mov cl, 1
+ xor rdx, rdx
+ call MmCreateKernelStack
+
+ /* Check for failure */
+ test rax, rax
+ jz KiConvertToGuiThreadFailed
+
+ ; OldStack = KeSwitchKernelStack((PVOID)NewStack, (PVOID)(NewStack - KERNEL_STACK_SIZE));
+ mov rcx, rax
+ mov rdx, rax
+ sub rdx, KERNEL_STACK_SIZE
+ call KeSwitchKernelStack
+
+ // MmDeleteKernelStack(OldStack, FALSE);
+ mov rcx, rax
+ xor rdx, rdx
+ call MmDeleteKernelStack
+
/* Call the worker function */
call PsConvertToGuiThread
- /* Adjust rsp */
- add rsp, 32
+ /* Check for failure */
+ test rax, rax
+ js KiConvertToGuiThreadFailed
- /* Restore rbp */
- pop rbp
+ /* Disable interrupts for return */
+ cli
+
+ // FIXME: should just do the trap frame switch in KiSystemCallHandler64
+ /* Restore old trap frame */
+ mov rcx, gs:[PcCurrentThread]
+ mov rdx, [rsp + 48 + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_TrapFrame]
+ mov [rcx + KTHREAD_TrapFrame], rdx
+
+ // Restore register parameters
+ mov rcx, [rsp + 48 + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rip]
+ mov rdx, [rsp + 48 + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rdx]
+ mov r8, [rsp + 48 + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_R8]
+ mov r9, [rsp + 48 + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_R9]
- /* return to the caller */
+ /* Run KiSystemCallHandler again */
+ add rsp, 48
+ jmp KiSystemCall64Again
+
+KiConvertToGuiThreadFailed:
+
+ /* Clean up the stack and return failure */
+ add rsp, 40
+ mov eax, HEX(C0000017) // STATUS_NO_MEMORY
ret
ENDFUNC
/* Return on new stack */
mov rax, rdx
- ret;
+ ret
#ifdef _MSC_VER