From 614734706d13add46959aa5fab45d66355c2e0a6 Mon Sep 17 00:00:00 2001 From: Sir Richard Date: Fri, 29 Jan 2010 01:12:08 +0000 Subject: [PATCH] [NTOS]: Implement the KiInterruptTemplate in C since we now have a C entrry macro. Add a new KI_HARDWARE_INT flag for the C entry macro to generate the appropriate labels for runtime patching of the KINTERRUPT pointer to work, and issue an absolute instead of relative jmp. [NTOS]: Remove thousands of lines of assembly that are not needed anymore. [NTOS]: Put all interrupt code in irqobj.c (platform-specific). [NTOS]: DPC Interrupt is really the thread scheduler interrupt (DPC work happens in C), which mostly does contexts switching and scheduling decisions, so move it to ctxswitch.S svn path=/trunk/; revision=45309 --- .../ntoskrnl/include/internal/i386/asmmacro.S | 1412 ----------------- reactos/ntoskrnl/include/internal/i386/ke.h | 1 + reactos/ntoskrnl/include/internal/ke.h | 1 - reactos/ntoskrnl/include/internal/trap_x.h | 28 +- reactos/ntoskrnl/ke/i386/ctxswitch.S | 119 ++ reactos/ntoskrnl/ke/i386/irqobj.c | 7 +- reactos/ntoskrnl/ke/i386/trap.s | 239 +-- reactos/ntoskrnl/ke/i386/traphdlr.c | 12 + reactos/ntoskrnl/ke/i386/usercall_asm.S | 3 - 9 files changed, 163 insertions(+), 1659 deletions(-) diff --git a/reactos/ntoskrnl/include/internal/i386/asmmacro.S b/reactos/ntoskrnl/include/internal/i386/asmmacro.S index 0ada3a7f16e..d0fabe98011 100644 --- a/reactos/ntoskrnl/include/internal/i386/asmmacro.S +++ b/reactos/ntoskrnl/include/internal/i386/asmmacro.S @@ -10,43 +10,10 @@ #include -// Arguments for TRAP_EPILOG -#define FromSystemCall 1 -#define DoRestorePreviousMode 1 -#define DoRestoreEverything 1 -#define DoRestoreSegments 1 -#define DoRestoreVolatiles 1 -#define DoPushFakeErrorCode 1 -#define DoFixupV86 1 -#define DoFixupAbios 1 -#define NotFromSystemCall 0 -#define DoNotRestorePreviousMode 0 -#define DoNotRestoreEverything 0 -#define DoNotRestoreSegments 0 -#define DoNotRestoreVolatiles 0 -#define DoNotPushFakeErrorCode 0 -#define DoNotFixupV86 0 -#define DoNotFixupAbios 0 - // Arguments for idt #define INT_32_DPL0 0x8E00 #define INT_32_DPL3 0xEE00 -// -// This table contains the prefix flags that are used by V86 emulation -// -.equ PREFIX_FLAG_ES, 0x00000100 -.equ PREFIX_FLAG_CS, 0x00000200 -.equ PREFIX_FLAG_SS, 0x00000400 -.equ PREFIX_FLAG_DS, 0x00000800 -.equ PREFIX_FLAG_FS, 0x00001000 -.equ PREFIX_FLAG_GS, 0x00002000 -.equ PREFIX_FLAG_OPER32, 0x00004000 -.equ PREFIX_FLAG_ADDR32, 0x00008000 -.equ PREFIX_FLAG_LOCK, 0x00010000 -.equ PREFIX_FLAG_REPNE, 0x00020000 -.equ PREFIX_FLAG_REP, 0x00040000 - .intel_syntax noprefix // @@ -84,57 +51,6 @@ #define RELEASE_SPINLOCK(x) #endif -// -// @name UNHANDLED_PATH -// -// This macro prints out that the current code path is not expected yet -// -// @param None -// -// @remark None. -// -.macro UNHANDLED_PATH Reason - - /* Push reason */ - push offset 1f - - /* Get EIP */ - call $+5 - - /* Print debug message */ - push offset _UnhandledMsg - call _DbgPrint - add esp, 12 - - /* Loop indefinitely */ - jmp $ - -1: - .asciz \Reason -.endm - -// -// @name UNHANDLED_V86_PATH -// -// This macro prints out that the current code path is for unhandled VDM support -// -// @param None -// -// @remark None. -// -.macro UNHANDLED_V86_PATH - /* Get EIP */ - call $+5 - - /* Print debug message */ - push offset _V86UnhandledMsg - call _DbgPrint - add esp, 8 - - /* Loop indefinitely */ - jmp $ -.endm - // // @name IDT // @@ -219,1331 +135,3 @@ _KiUnexpectedInterrupt&Number: .set i, i + 1 .endr .endm - -// -// @name TRAP_HANDLER_PROLOG -// -// This macro creates a kernel trap handler. -// -// @param None. -// -// @remark None. -// -.macro TRAP_HANDLER_PROLOG ErrorCode=1, Software=0 - - /* What kind of trap is it */ - .if \Software - /* Software traps need a fake interrupt stack */ - pop eax - sub esp, KTRAP_FRAME_ESP - .elseif \ErrorCode - /* Some traps generate an error code, some don't (thanks, Intel!) */ - sub esp, KTRAP_FRAME_EIP - .else - sub esp, KTRAP_FRAME_ERROR_CODE - .endif - - /* Make space for trap frame and save registers before we enter C code */ - mov [esp+KTRAP_FRAME_EAX], eax - mov [esp+KTRAP_FRAME_EBX], ebx - mov [esp+KTRAP_FRAME_ECX], ecx - mov [esp+KTRAP_FRAME_EDX], edx - mov [esp+KTRAP_FRAME_ESI], esi - mov [esp+KTRAP_FRAME_EDI], edi - mov [esp+KTRAP_FRAME_EBP], ebp - mov ecx, esp -.endm - -// -// @name GENERATE_TRAP_HANDLER -// -// This macro creates a kernel trap handler. -// -// @param None. -// -// @remark None. -// -.macro GENERATE_TRAP_HANDLER Name, ErrorCode=1, FastV86=0, Software=0 -.globl _&Name -.func Name -_&Name: - TRAP_HANDLER_PROLOG ErrorCode, Software - /* - * The GPF and Invalid Opcode handlers are performance critical when talking - * about V8086 traps, because they control the main flow of execution during - * that mode (GPFs will be issued for any privileged instruction we need to - * emulate, and invalid opcode might be generated for BOPs). - * - * Because of this, we employ a fast entry/exit macro into V8086 mode since - * we can make certain assumptions. We detect, and use, such scenarios when - * the V8086 flag is enabled in EFLAGS. - * - * However, because we can land in a GPF handler with an invalid DS/ES, as - * some V8086 code could trample this during BIOS calls for example, we must - * make sure that we are on a valid DS/ES before dereferencing any pointer. - * - * We fixup DS/ES either in KiEnterTrap (for normal entry/exit) or, for V86, - * in KiEnterV86Trap. Notice the problem: we need to detect which of these - * to use early on but we can't touch the EFLAGS in the frame because DS/ES - * could be invalid. - * - * Thankfully SS is always guaranteed valid, so stack dereferences are game! - * - * We therefore read the EFLAGS here, in assembly, where we can touch ESP as - * we please. We save this in EDX, which will be used as the second argument - * for the FASTCALL C trap entry. - * - * When we make the fast V86 check, we use the parameter instead of the trap - * frame, leading us to using the correct trap entry function, which fixes - * up DS/ES and lets us go on our merry way... - */ - .if \FastV86 - mov edx, [esp+KTRAP_FRAME_EFLAGS] - .endif - - /* Normally we just have one parameter, but fast V86 handlers need two */ - .if \FastV86 - jmp @&Name&Handler@8 - .else - jmp @&Name&Handler@4 - .endif -.endfunc -.endm - -// -// @name GENERATE_HAL_INT_HANDLER -// -// This macro creates a HAL hardware interrupt handler. -// -// @param None. -// -// @remark None. -// -.macro GENERATE_HAL_INT_HANDLER Number -.func HalpHardwareInterrupt&Number -_HalpHardwareInterrupt&Number: - int PRIMARY_VECTOR_BASE + Number - ret -.endfunc -.endm - -// -// @name GENERATE_HAL_INT_HANDLERS -// -// This macro creates the unexpected interrupt handlers. -// -// @param None. -// -// @remark None. -// -.macro GENERATE_HAL_INT_HANDLERS -.set i, 0 -.rept 16 - GENERATE_HAL_INT_HANDLER %i - .set i, i + 1 -.endr -.endm - -// -// @name INVALID_V86_OPCODE -// -// This macro creates one or more entries for unhandled V86 Opcodes -// in the V86 Opcode Table. -// -// @param count. -// Number of entries to generate. -// -// @remark None. -// -.macro INVALID_V86_OPCODE count - .rept \count - .byte 0 - .endr -.endm - -// -// @name GENERATE_PREFIX_HANDLER -// -// This macro creates a prefix opcode handler. -// -// @param None. -// -// @remark None. -// -.macro GENERATE_PREFIX_HANDLER Name -.func Opcode&Name&PrefixV86 -_Opcode&Name&PrefixV86: - or ebx, PREFIX_FLAG_&Name - jmp _OpcodeGenericPrefixV86 -.endfunc -.endm - -// -// @name INVALID_V86_OPCODE -// -// This macro prints out visible message and hangs the computer. -// -// @param None. -// -// @remark Temporary debugging use. -// -.macro UNHANDLED_V86_OPCODE - /* Print debug message, breakpoint and freeze */ - push ecx - push offset V86DebugMsg - call _DbgPrint - add esp, 8 - jmp $ -.endm - -// -// @name TRAP_FIXUPS -// -// This macro contains out-of-line code for various Trap Frame Fixups, such as: -// -// - DR Fixup: Loads and restores DR registers. -// - V86 Fixup: Loads and restores V86 segments. -// - ABIOS Fixup: Loads and restores the ABIOS state and stack. -// -// @param None. -// -// @remark ebp = PKTRAP_FRAME -// -.macro TRAP_FIXUPS Label, EndLabel, V86Fix, AbiosFix -Dr_&Label: - - /* Check if this was V86 mode */ - test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK - jnz 2f - - /* Check if it was user mode */ - test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK - jz Dr_&EndLabel - -2: - /* Get DR0, 1, 2 */ - mov ebx, dr0 - mov ecx, dr1 - mov edi, dr2 - - /* Save them */ - mov [ebp+KTRAP_FRAME_DR0], ebx - mov [ebp+KTRAP_FRAME_DR1], ecx - mov [ebp+KTRAP_FRAME_DR2], edi - - /* Get DR3, 6, 7 */ - mov ebx, dr3 - mov ecx, dr6 - mov edi, dr7 - - /* Save them */ - mov [ebp+KTRAP_FRAME_DR3], ebx - mov [ebp+KTRAP_FRAME_DR6], ecx - mov [ebp+KTRAP_FRAME_DR7], edi - - /* Clear DR7 */ - xor ebx, ebx - mov dr7, ebx - - /* Get the PRCB */ - mov edi, fs:[KPCR_PRCB] - - /* Get DR0, 1 */ - mov ebx, [edi+KPRCB_DR0] - mov ecx, [edi+KPRCB_DR1] - - /* Set them */ - mov dr0, ebx - mov dr1, ecx - - /* Get DR2, 3 */ - mov ebx, [edi+KPRCB_DR2] - mov ecx, [edi+KPRCB_DR3] - - /* Set them */ - mov dr2, ebx - mov dr3, ecx - - /* Get DR6, 7 */ - mov ebx, [edi+KPRCB_DR6] - mov ecx, [edi+KPRCB_DR7] - - /* Set them */ - mov dr6, ebx - mov dr7, ecx - jmp Dr_&EndLabel - -.if \AbiosFix -Abios_&Label: - UNHANDLED_PATH -.endif - -.if \V86Fix -V86_&Label: - - /* Get V86 segment registers */ - mov eax, [ebp+KTRAP_FRAME_V86_FS] - mov ebx, [ebp+KTRAP_FRAME_V86_GS] - mov ecx, [ebp+KTRAP_FRAME_V86_ES] - mov edx, [ebp+KTRAP_FRAME_V86_DS] - - /* Restore them into Protected Mode trap frame */ - mov [ebp+KTRAP_FRAME_FS], ax - mov [ebp+KTRAP_FRAME_GS], bx - mov [ebp+KTRAP_FRAME_ES], cx - mov [ebp+KTRAP_FRAME_DS], dx - - /* Go back to mainline code */ - jmp V86_&EndLabel -.endif -.endm - -// -// @name SET_TF_DEBUG_HEADER -// -// This macro sets up the debug header in the trap frame. -// -// @param None. -// -// @remark ebp = PKTRAP_FRAME. -// edi/ebx = Have been saved and can be used. -// -.macro SET_TF_DEBUG_HEADER - /* Get the Debug Trap Frame EBP/EIP */ - mov ebx, [ebp+KTRAP_FRAME_EBP] - mov edi, [ebp+KTRAP_FRAME_EIP] - - /* Write the debug data */ - mov [ebp+KTRAP_FRAME_DEBUGPOINTER], edx - mov dword ptr [ebp+KTRAP_FRAME_DEBUGARGMARK], 0xBADB0D00 - mov [ebp+KTRAP_FRAME_DEBUGEBP], ebx - mov [ebp+KTRAP_FRAME_DEBUGEIP], edi -.endm - -// -// @name CHECK_FOR_APC_DELIVER -// -// This macro checks if the trapframe indicates a return to user-mode, -// and, if so, checks if user-mode APCs should be delivered. -// -// @param PreserveEax -// Determines if EAX should be preserved. Implies that the segment -// registers will also be saved. -// -// @remark ebp = PKTRAP_FRAME. -// ebx = Saved and will be used. -// -.macro CHECK_FOR_APC_DELIVER PreserveEax - /* Check for V86 mode */ - test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK - jnz 1f - - /* Deliver APCs only if we were called from user mode */ - test byte ptr [ebp+KTRAP_FRAME_CS], 1 - je 2f - - /* Get the current thread */ -1: - mov ebx, PCR[KPCR_CURRENT_THREAD] - - /* Make it non-alerted */ - mov byte ptr [ebx+KTHREAD_ALERTED], 0 - - /* And only if any are actually pending */ - cmp byte ptr [ebx+KTHREAD_PENDING_USER_APC], 0 - je 2f - - /* Save pointer to Trap Frame */ - mov ebx, ebp - -.if \PreserveEax - /* Save some stuff that raising IRQL will kill */ - mov [ebx+KTRAP_FRAME_EAX], eax - mov dword ptr [ebx+KTRAP_FRAME_FS], KGDT_R3_TEB + RPL_MASK - mov dword ptr [ebx+KTRAP_FRAME_DS], KGDT_R3_DATA + RPL_MASK - mov dword ptr [ebx+KTRAP_FRAME_ES], KGDT_R3_DATA + RPL_MASK - mov dword ptr [ebx+KTRAP_FRAME_GS], 0 -.endif - - /* Raise IRQL to APC_LEVEL */ - mov ecx, 1 - call @KfRaiseIrql@4 - - /* Save old IRQL */ - push eax - - /* Deliver APCs */ - sti - push ebx - push 0 - push UserMode - call _KiDeliverApc@12 - - /* Return to old IRQL */ - pop ecx - call @KfLowerIrql@4 - - /* Restore EAX (only in volatile case) */ -.if \PreserveEax - mov eax, [ebx+KTRAP_FRAME_EAX] -.endif - cli - jmp 1b -2: -.endm - -// -// @name TRAP_PROLOG -// -// This macro creates a standard trap entry prologue. -// It should be used for entry into any kernel trap (KiTrapXx), but not for -// system calls, which require special handling. -// -// @param Label -// Identifying name of the caller function; will be used to append -// to the name V86 and DR helper functions, which must already exist. -// -// @remark Use as follows: -// _KiTrap00: -// /* Push fake error code */ -// push 0 -// -// /* Enter common prologue */ -// TRAP_PROLOG(0) -// -// /* Handle trap */ -// -// -.macro TRAP_PROLOG Label EndLabel - /* Just to be safe, clear out the HIWORD, since it's reserved */ - mov word ptr [esp+2], 0 - - /* Save the non-volatiles */ - push ebp - push ebx - push esi - push edi - - /* Save FS and set it to PCR */ - push fs - mov ebx, KGDT_R0_PCR - .byte 0x66 - mov fs, bx - - /* Save exception list and bogus previous mode */ - push fs:[KPCR_EXCEPTION_LIST] - push -1 - - /* Save volatiles and segment registers */ - push eax - push ecx - push edx - push ds - push es - push gs - - /* Set the R3 data segment */ - mov ax, KGDT_R3_DATA + RPL_MASK - - /* Skip debug registers and debug stuff */ - sub esp, 0x30 - - /* Load the segment registers */ - .byte 0x66 - mov ds, ax - .byte 0x66 - mov es, ax - - /* Check if this interrupt happened in 16-bit mode */ - cmp esp, 0x10000 - jb _Ki16BitStackException - - /* Set up frame */ - mov ebp, esp - - /* Check if this was from V86 Mode */ - test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK - jnz V86_&Label - -V86_&EndLabel: - /* Get current thread */ - mov ecx, fs:[KPCR_CURRENT_THREAD] - cld - - /* Flush DR7 */ - and dword ptr [ebp+KTRAP_FRAME_DR7], 0 - - /* Check if the thread was being debugged */ - test byte ptr [ecx+KTHREAD_DEBUG_ACTIVE], 0xFF - jnz Dr_&Label - - /* Set the Trap Frame Debug Header */ -Dr_&EndLabel: - SET_TF_DEBUG_HEADER -.endm - -// -// @name INT_PROLOG -// -// This macro creates a standard interrupt entry prologue. -// It should be used for entry into any interrupt, including software. -// -// @param Label -// Identifying name of the caller function; will be used to append -// to the name V86, ABIOS and DR helper functions, which must exist. -// -// @remark For software interrupts, make sure that a fake INT stack is created. -// -.macro INT_PROLOG Label EndLabel FakeErrorCode - -.if \FakeErrorCode - /* Save fake error code */ - push esp -.endif - - /* Save the non-volatiles */ - push ebp - push ebx - push esi - push edi - - /* Skip debug registers and other stuff */ - sub esp, 0x54 - - /* Set up frame */ - mov ebp, esp - - /* Save volatiles */ - mov [esp+KTRAP_FRAME_EAX], eax - mov [esp+KTRAP_FRAME_ECX], ecx - mov [esp+KTRAP_FRAME_EDX], edx - mov dword ptr [esp+KTRAP_FRAME_PREVIOUS_MODE], -1 - - /* Check if this was from V86 Mode */ - test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK - jnz V86_&Label - - /* Check if this was kernel mode */ -V86_&EndLabel: - cmp word ptr [esp+KTRAP_FRAME_CS], KGDT_R0_CODE - jz 1f - - /* Set segments */ - mov word ptr [esp+KTRAP_FRAME_FS], fs - mov word ptr [esp+KTRAP_FRAME_DS], ds - mov word ptr [esp+KTRAP_FRAME_ES], es - mov [esp+KTRAP_FRAME_GS], gs - - /* Load the segment registers (use OVERRIDE (0x66)) */ - mov ebx, KGDT_R0_PCR - mov eax, KGDT_R3_DATA | RPL_MASK - .byte 0x66 - mov fs, bx - .byte 0x66 - mov ds, ax - .byte 0x66 - mov es, ax - -1: - /* Get the previous exception list */ - mov ebx, fs:[KPCR_EXCEPTION_LIST] - - /* Set the exception handler chain terminator */ - mov dword ptr fs:[KPCR_EXCEPTION_LIST], -1 - - /* Save the previous exception list */ - mov [esp+KTRAP_FRAME_EXCEPTION_LIST], ebx - -.ifeq \FakeErrorCode - /* Setup the 16-bit stack */ - lea eax, [esp+KTRAP_FRAME_ERROR_CODE] - lea ecx, [esp+KTRAP_FRAME_EIP] - mov ebx, ss:[eax] - mov ss:[eax], ecx -.endif - - /* Check if this is the ABIOS stack */ - /* cmp esp, 0x10000*/ - /* jb Abios_Label*/ - - /* Delete error code */ - and dword ptr [esp+KTRAP_FRAME_ERROR_CODE], 0 - - /* Get the current thread and clear direction flag */ - mov ecx, PCR[KPCR_CURRENT_THREAD] - cld - - /* Flush DR7 */ - and dword ptr [ebp+KTRAP_FRAME_DR7], 0 - - /* Check if the thread was being debugged */ - test byte ptr [ecx+KTHREAD_DEBUG_ACTIVE], 0xFF - -.ifeq \FakeErrorCode - /* Push parameter */ - push ebx -.endif - - /* Save DR registers if needed */ - jnz Dr_&Label - - /* Set the trap frame debug header */ -Dr_&EndLabel: - SET_TF_DEBUG_HEADER -.endm - -// -// @name SYSCALL_PROLOG -// -// This macro creates a system call entry prologue. -// It should be used for entry into any fast-system call (KiGetTickCount, -// KiCallbackReturn, KiRaiseAssertion) and the generic system call handler -// (KiSystemService) -// -// @param Label -// Unique label identifying the name of the caller function; will be -// used to append to the name of the DR helper function, which must -// already exist. -// -// @remark None. -// -.macro SYSCALL_PROLOG Label EndLabel - /* Create a trap frame */ - push 0 - push ebp - push ebx - push esi - push edi - push fs - - /* Load PCR Selector into fs */ - mov ebx, KGDT_R0_PCR - .byte 0x66 - mov fs, bx - - /* Get a pointer to the current thread */ - mov esi, PCR[KPCR_CURRENT_THREAD] - - /* Save the previous exception list */ - push PCR[KPCR_EXCEPTION_LIST] - - /* Set the exception handler chain terminator */ - mov dword ptr PCR[KPCR_EXCEPTION_LIST], -1 - - /* Save the old previous mode */ - push [esi+KTHREAD_PREVIOUS_MODE] - - /* Skip the other registers */ - sub esp, 0x48 - - /* Set the new previous mode based on the saved CS selector */ - mov ebx, [esp+0x6C] - and ebx, 1 - mov byte ptr [esi+KTHREAD_PREVIOUS_MODE], bl - - /* Go on the Kernel stack frame */ - mov ebp, esp - - /* Save the old trap frame pointer where EDX would be saved */ - mov ebx, [esi+KTHREAD_TRAP_FRAME] - mov [ebp+KTRAP_FRAME_EDX], ebx - - /* Flush DR7 */ - and dword ptr [ebp+KTRAP_FRAME_DR7], 0 - - /* Check if the thread was being debugged */ - test byte ptr [esi+KTHREAD_DEBUG_ACTIVE], 0xFF - - /* Set the thread's trap frame and clear direction flag */ - mov [esi+KTHREAD_TRAP_FRAME], ebp - cld - - /* Save DR registers if needed */ - jnz Dr_&Label - - /* Set the trap frame debug header */ -Dr_&EndLabel: - SET_TF_DEBUG_HEADER - - /* Enable interrupts */ - sti -.endm - -// -// @name FASTCALL_PROLOG -// -// TODO -// -// @param Label -// Unique label identifying the name of the caller function; will be -// used to append to the name of the DR helper function, which must -// already exist. -// -// @remark None. -// -.macro FASTCALL_PROLOG Label EndLabel - - /* Set user selector */ - mov ecx, KGDT_R3_DATA | RPL_MASK - - /* Set FS to PCR */ - push KGDT_R0_PCR - pop fs - - /* Set DS/ES to User Selector */ - mov ds, cx - mov es, cx - - /* Set the current stack to Kernel Stack */ - mov ecx, PCR[KPCR_TSS] - mov esp, [ecx+KTSS_ESP0] - - /* Set up a fake INT Stack. */ - push KGDT_R3_DATA + RPL_MASK - push edx /* Ring 3 SS:ESP */ - pushf /* Ring 3 EFLAGS */ - push 2 /* Ring 0 EFLAGS */ - add edx, 8 /* Skip user parameter list */ - popf /* Set our EFLAGS */ - or dword ptr [esp], EFLAGS_INTERRUPT_MASK /* Re-enable IRQs in EFLAGS, to fake INT */ - push KGDT_R3_CODE + RPL_MASK - push dword ptr ds:KUSER_SHARED_SYSCALL_RET - - /* Setup the Trap Frame stack */ - push 0 - push ebp - push ebx - push esi - push edi - push KGDT_R3_TEB + RPL_MASK - - /* Save pointer to our PCR */ - mov ebx, PCR[KPCR_SELF] - - /* Get a pointer to the current thread */ - mov esi, [ebx+KPCR_CURRENT_THREAD] - - /* Set the exception handler chain terminator */ - push [ebx+KPCR_EXCEPTION_LIST] - mov dword ptr [ebx+KPCR_EXCEPTION_LIST], -1 - - /* Use the thread's stack */ - mov ebp, [esi+KTHREAD_INITIAL_STACK] - - /* Push previous mode */ - push UserMode - - /* Skip the other registers */ - sub esp, 0x48 - - /* Make space for us on the stack */ - sub ebp, 0x29C - - /* Write the previous mode */ - mov byte ptr [esi+KTHREAD_PREVIOUS_MODE], UserMode - - /* Sanity check */ - cmp ebp, esp - jnz BadStack - - /* Flush DR7 */ - and dword ptr [ebp+KTRAP_FRAME_DR7], 0 - - /* Check if the thread was being debugged */ - test byte ptr [esi+KTHREAD_DEBUG_ACTIVE], 0xFF - - /* Set the thread's trap frame */ - mov [esi+KTHREAD_TRAP_FRAME], ebp - - /* Save DR registers if needed */ - jnz Dr_&Label - - /* Set the trap frame debug header */ -Dr_&EndLabel: - SET_TF_DEBUG_HEADER - - /* Enable interrupts */ - sti -.endm - -// -// @name V86_TRAP_PROLOG -// -// This macro creates a V86 Trap entry prologue. -// It should be used for entry into any fast-system call (KiGetTickCount, -// KiCallbackReturn, KiRaiseAssertion) and the generic system call handler -// (KiSystemService) -// -// @param Label -// Unique label identifying the name of the caller function; will be -// used to append to the name of the DR helper function, which must -// already exist. -// -// @remark None. -// -.macro V86_TRAP_PROLOG Label EndLabel - - /* Skip everything to the error code */ - sub esp, KTRAP_FRAME_ERROR_CODE - - /* Clear the error code */ - mov word ptr [esp+KTRAP_FRAME_ERROR_CODE+2], 0 - - /* Save the registers we'll trample */ - mov [esp+KTRAP_FRAME_EBX], ebx - mov [esp+KTRAP_FRAME_EAX], eax - mov [esp+KTRAP_FRAME_EBP], ebp - mov [esp+KTRAP_FRAME_ESI], esi - mov [esp+KTRAP_FRAME_EDI], edi - - /* Save PCR and Ring 3 segments */ - mov ebx, KGDT_R0_PCR - mov eax, KGDT_R3_DATA + RPL_MASK - - /* Save ECX and EDX too */ - mov [esp+KTRAP_FRAME_ECX], ecx - mov [esp+KTRAP_FRAME_EDX], edx - - /* Set debugging markers */ - mov dword ptr [esp+KTRAP_FRAME_PREVIOUS_MODE], -1 - mov dword ptr [esp+KTRAP_FRAME_DEBUGARGMARK], 0xBADB0D00 - - /* Now set segments (use OVERRIDE, 0x66) */ - .byte 0x66 - mov fs, bx - .byte 0x66 - mov ds, ax - .byte 0x66 - mov es, ax - - /* Set the trap frame in the stack and clear the direction flag */ - mov ebp, esp - cld - - /* Save the exception list */ - mov eax, fs:[KPCR_EXCEPTION_LIST] - mov [esp+KTRAP_FRAME_EXCEPTION_LIST], eax - - /* Check if we need debugging */ - mov eax, dr7 - test eax, ~DR7_RESERVED_MASK - mov [esp+KTRAP_FRAME_DR7], eax - jnz Dr_&Label - -Dr_&EndLabel: -.endm - -// -// @name V86_TRAP_EPILOG -// -// This macro creates an epilogue for leaving V86 traps -// -// @param None. -// -// @remark None. -// -.macro V86_TRAP_EPILOG - - /* Get the current thread and make it unalerted */ -ExitBegin: - mov ebx, PCR[KPCR_CURRENT_THREAD] - mov byte ptr [ebx+KTHREAD_ALERTED], 0 - - /* Check if it has User-mode APCs pending */ - cmp byte ptr [ebx+KTHREAD_PENDING_USER_APC], 0 - jne PendingUserApc - - /* It doesn't, pop the frame */ - add esp, KTRAP_FRAME_EDX - pop edx - pop ecx - pop eax - - /* Check if DR registers should be restored */ - test dword ptr [ebp+KTRAP_FRAME_DR7], ~DR7_RESERVED_MASK - jnz V86DebugRestore - - /* Finish popping the rest of the frame, and return to P-mode */ -V86DebugContinue: - add esp, 12 - pop edi - pop esi - pop ebx - pop ebp - add esp, 4 - iretd - -V86DebugRestore: - - /* Get DR0, 1 */ - xor ebx, ebx - mov esi, [ebp+KTRAP_FRAME_DR0] - mov edi, [ebp+KTRAP_FRAME_DR1] - - /* Clear DR 7 */ - mov dr7, ebx - - /* Get DR2 and load DR0-2 */ - mov ebx, [ebp+KTRAP_FRAME_DR2] - mov dr0, esi - mov dr1, edi - mov dr2, ebx - - /* Get DR3-7 */ - mov esi, [ebp+KTRAP_FRAME_DR0] - mov edi, [ebp+KTRAP_FRAME_DR1] - mov ebx, [ebp+KTRAP_FRAME_DR7] - - /* Load them */ - mov dr3, esi - mov dr6, edi - mov dr7, ebx - jmp V86DebugContinue - -PendingUserApc: - - /* Raise to APC level */ - mov ecx, APC_LEVEL - call @KfRaiseIrql@4 - - /* Save KIRQL and deliver APCs */ - push eax - sti - push ebp - push 0 - push UserMode - call _KiDeliverApc@12 - - /* Restore IRQL */ - pop ecx - call @KfLowerIrql@4 - cli - - /* Check if we're not in V86 anymore */ - test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK - jnz ExitBegin -.endm - -// -// @name TRAP_EPILOG -// -// This macro creates an epilogue for leaving any system trap. -// It is used for exiting system calls, exceptions, interrupts and generic -// traps. -// -// @param SystemCall -// Specifies whether this trap will exit a system call. If so, special -// code will be assembled to potentially use SYSEXIT instead of IRETD. -// -// @param RestorePreviousMode -// Specifies if the previous mode should be restored. -// -// @param RestoreSegments -// Specifies if the segment registers should be restored. -// -// @param RestoreVolatiles -// Specifies if the volatile registers should be restored. -// -// @param RestoreAllRegs -// Specifies if volatiles and segments should both be restored. -// -// @remark -// -.macro TRAP_EPILOG SystemCall, RestorePreviousMode, RestoreSegments, RestoreVolatiles, RestoreAllRegs -#if DBG - /* Assert the flags */ - pushfd - pop edx - test edx, EFLAGS_INTERRUPT_MASK - jnz 6f - - /* Assert the stack */ - cmp esp, ebp - jnz 6f - - /* Assert the trap frame */ -#endif -5: -#if DBG - sub dword ptr [esp+KTRAP_FRAME_DEBUGARGMARK], 0xBADB0D00 - jnz 0f - - /* Assert FS */ - mov bx, fs - cmp bx, KGDT_R0_PCR - jnz 1f - - /* Assert exception list */ - cmp dword ptr PCR[KPCR_EXCEPTION_LIST], 0 - jnz 2f - -1: - push -1 - call _KeBugCheck@4 -#endif - -2: - /* Get exception list */ - mov edx, [esp+KTRAP_FRAME_EXCEPTION_LIST] - -#if DBG - /* Assert the saved exception list */ - or edx, edx - jnz 1f - UNHANDLED_PATH -1: -#endif - - /* Restore it */ - mov PCR[KPCR_EXCEPTION_LIST], edx - -.if \RestorePreviousMode - /* Get previous mode */ - mov ecx, [esp+KTRAP_FRAME_PREVIOUS_MODE] - -#if DBG - /* Assert the saved previous mode */ - cmp ecx, -1 - jnz 1f - UNHANDLED_PATH -1: -#endif - - /* Restore the previous mode */ - mov esi, PCR[KPCR_CURRENT_THREAD] - mov byte ptr [esi+KTHREAD_PREVIOUS_MODE], cl -.else - -#if DBG - /* Assert the saved previous mode */ - mov ecx, [esp+KTRAP_FRAME_PREVIOUS_MODE] - cmp ecx, -1 - jz 1f - UNHANDLED_PATH -1: -#endif -.endif - - /* Check for debug registers */ - test dword ptr [esp+KTRAP_FRAME_DR7], ~DR7_RESERVED_MASK - jnz 2f - - /* Check for V86 */ -4: - test dword ptr [esp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK - jnz V86_Exit - - /* Check if the frame was edited */ - test word ptr [esp+KTRAP_FRAME_CS], FRAME_EDITED - jz 7f - -.if \RestoreAllRegs - /* Check the old mode */ - cmp word ptr [esp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK - bt word ptr [esp+KTRAP_FRAME_CS], 0 - cmc - ja 8f -.endif - -.if \RestoreVolatiles - /* Restore volatiles */ - mov edx, [esp+KTRAP_FRAME_EDX] - mov ecx, [esp+KTRAP_FRAME_ECX] - mov eax, [esp+KTRAP_FRAME_EAX] -.endif - - /* Check if we were called from kernel mode */ - cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R0_CODE - jz 9f - -.if \RestoreSegments - /* Restore segment registers */ - lea esp, [ebp+KTRAP_FRAME_GS] - pop gs - pop es - pop ds -.endif - - /* Restore FS */ -3: - lea esp, [ebp+KTRAP_FRAME_FS] - pop fs - -9: - /* Skip debug information and unsaved registers */ - lea esp, [ebp+KTRAP_FRAME_EDI] - pop edi - pop esi - pop ebx - pop ebp - - /* Check for ABIOS */ - cmp word ptr [esp+8], 0x80 - ja AbiosExit - - /* Pop error code */ - add esp, 4 - -.if \SystemCall - /* Check if previous CS is from user-mode */ - test dword ptr [esp+4], 1 - - /* It is, so use Fast Exit */ - jnz FastExit - - /* Jump back to stub */ - pop edx - pop ecx - popf - jmp edx - -.ret: -.endif - iret - -.if \SystemCall -FastExit: - /* Is SYSEXIT Supported/Wanted? */ - cmp dword ptr ss:[_KiFastSystemCallDisable], 0 - jnz .ret - test dword ptr [esp+8], EFLAGS_TF - jnz .ret - - /* Restore FS to TIB */ - mov ecx, KGDT_R3_TEB + RPL_MASK - mov fs, ecx - - /* We will be cleaning up the stack ourselves */ - pop edx /* New Ring 3 EIP */ - add esp, 4 /* Skip Ring 3 DS */ - and dword ptr [esp], 0xfffffdff /* Remove EFLAGS_INTERRUPT_MASK from EFLAGS */ - popf /* Restore old EFLAGS */ - pop ecx /* Old Ring 3 SS:ESP */ - - /* - * At this point: - * ECX points to the old User Stack. - * EDX points to the instruction to execute in usermode after the sysenter - */ - sti - sysexit -.endif - -.if \RestoreAllRegs -8: - /* Restore EAX */ - mov eax, [esp+KTRAP_FRAME_EAX] - - /* Skip registers */ - add esp, 0x30 - - /* Restore segments and volatiles */ - pop gs - pop es - pop ds - pop edx - pop ecx - - /* Jump back to mainline code */ - jmp 3b -.endif - -#if DBG -0: - /* Fix up the mask */ - add dword ptr [esp+KTRAP_FRAME_DEBUGARGMARK], 0xBADB0D00 - -6: - UNHANDLED_PATH - jmp 5b -#endif - -2: - /* Check if this was V86 mode */ - test dword ptr [esp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK - jnz 1f - - /* Check if it was user mode */ - test word ptr [esp+KTRAP_FRAME_CS], MODE_MASK - jz 4b - -1: - /* Clear DR7 */ - xor ebx, ebx - mov dr7, ebx - - /* Get DR0, 1, 2 */ - mov esi, [ebp+KTRAP_FRAME_DR0] - mov edi, [ebp+KTRAP_FRAME_DR1] - mov ebx, [ebp+KTRAP_FRAME_DR2] - - /* Set them */ - mov dr0, esi - mov dr1, edi - mov dr2, ebx - - /* Get DR3, 6, 7 */ - mov esi, [ebp+KTRAP_FRAME_DR3] - mov edi, [ebp+KTRAP_FRAME_DR6] - mov ebx, [ebp+KTRAP_FRAME_DR7] - - /* Set them */ - mov dr3, esi - mov dr6, edi - mov dr7, ebx - jmp 4b - -7: - /* Restore real CS value */ - mov ebx, [esp+KTRAP_FRAME_TEMPCS] - mov [esp+KTRAP_FRAME_CS], ebx - - /* - * If ESP was modified, then a special interrupt exit stack - * must be created to "update" ESP's value in a legal manner - */ - mov ebx, [esp+KTRAP_FRAME_TEMPESP] - sub ebx, 0xC - mov [esp+KTRAP_FRAME_ERROR_CODE], ebx - - /* Copy Interrupt Stack */ - mov esi, [esp+KTRAP_FRAME_EFLAGS] - mov [ebx+8], esi - mov esi, [esp+KTRAP_FRAME_CS] - mov [ebx+4], esi - mov esi, [esp+KTRAP_FRAME_EIP] - mov [ebx], esi - -.if \RestoreVolatiles - /* Restore volatiles */ - mov eax, [esp+KTRAP_FRAME_EAX] - mov edx, [esp+KTRAP_FRAME_EDX] - mov ecx, [esp+KTRAP_FRAME_ECX] -.endif - - /* Return */ - add esp, KTRAP_FRAME_EDI - pop edi - pop esi - pop ebx - pop ebp - mov esp, [esp] - iret -.endm - -// -// @name INT_EPILOG -// -// This macro creates an epilogue for leaving any system trap. -// It is used for exiting system calls, exceptions, interrupts and generic -// traps. -// -// @param Spurious - TRUE if the interrupt was unexpected and spurious. -// -// @remark None. -// -.macro INT_EPILOG Spurious - -.if \Spurious - /* Just exit the trap */ - jmp _Kei386EoiHelper@0 -.else - /* Disable interrupts */ - cli - - /* End the interrupt and do EOI */ - lea eax, [esp+8] - mov PCR[KPCR_VDM_ALERT], eax - call _HalEndSystemInterrupt@8 - jmp _Kei386EoiHelper@0 -.endif -.endm - -#if DBG - -.macro VERIFY_INT Label - /* Get the current time and mask it to 192 ticks */ - mov eax, _KeTickCount - and eax, 0xC0 - - /* Check if we're in the same tick area */ - cmp eax, dword ptr [edi+KINTERRUPT_TICK_COUNT] - jg VfRst_&Label - jl VfWrap_&Label - - /* If we got here, then our count is too large */ - dec word ptr [edi+KINTERRUPT_DISPATCH_COUNT] - jz VfOvr_&Label -Vf_&Label: -.endm - -.macro VERIFY_INT_END Label, Info -VfOvr_&Label: - - /* Decrement the dispatch count and check if we should bug check */ - dec word ptr [edi+KINTERRUPT_DISPATCH_COUNT+2] - jz 1f - - /* Update the tick count */ - add eax, 0x40 - mov [edi+KINTERRUPT_TICK_COUNT], eax - jmp VfRstDef_&Label - -1: - /* Check if the debugger is enabled */ - cmp byte ptr __KdDebuggerEnabled, 0 - jnz 1f - - /* It isn't, bugcheck */ - push Info - push edi - push [edi+KINTERRUPT_SERVICE_CONTEXT] - push [edi+KINTERRUPT_SERVICE_ROUTINE] - push HARDWARE_INTERRUPT_STORM - call _KeBugCheckEx@20 - -1: - /* Debugger enabled, do a debug print + break instead */ - push [edi+KINTERRUPT_SERVICE_ROUTINE] - push offset _IsrOverflowMsg - call _DbgPrint - add esp, 8 - int 3 - - /* Breakpoint handled, get the new tick count */ - mov eax, _KeTickCount - and eax, 0xC0 - -VfRst_&Label: - /* Reset tick count */ - mov dword ptr [edi+KINTERRUPT_TICK_COUNT], eax - mov word ptr [edi+KINTERRUPT_DISPATCH_COUNT+2], 64 - -VfRstDef_&Label: - /* Put default overflow count and continue */ - mov ax, _KiISROverflow - mov word ptr [edi+KINTERRUPT_DISPATCH_COUNT], ax - jmp Vf_&Label - -VfWrap_&Label: - /* Check if we wrapped */ - add eax, 0x40 - cmp eax, [edi+KINTERRUPT_TICK_COUNT] - je Vf_&Label - - /* We did, start over */ - mov eax, _KeTickCount - jmp VfRst_&Label -.endm - -#else - -/* We don't verify interrupts on retail builds */ -.macro VERIFY_INT Label -.endm -.macro VERIFY_INT_END Label, Info -.endm - -#endif - - diff --git a/reactos/ntoskrnl/include/internal/i386/ke.h b/reactos/ntoskrnl/include/internal/i386/ke.h index 1f4ee01aaf5..ceba3438a18 100644 --- a/reactos/ntoskrnl/include/internal/i386/ke.h +++ b/reactos/ntoskrnl/include/internal/i386/ke.h @@ -451,6 +451,7 @@ extern UCHAR KiDebugRegisterContextOffsets[9]; extern VOID __cdecl KiTrap02(VOID); extern VOID __cdecl KiTrap08(VOID); extern VOID __cdecl KiTrap13(VOID); +extern VOID __cdecl KiInterruptTemplate(VOID); extern VOID __cdecl KiFastCallEntry(VOID); extern VOID NTAPI ExpInterlockedPopEntrySListFault(VOID); extern VOID __cdecl CopyParams(VOID); diff --git a/reactos/ntoskrnl/include/internal/ke.h b/reactos/ntoskrnl/include/internal/ke.h index 70d743e85ee..9169dfd66db 100644 --- a/reactos/ntoskrnl/include/internal/ke.h +++ b/reactos/ntoskrnl/include/internal/ke.h @@ -98,7 +98,6 @@ extern UCHAR KeNumberNodes; extern UCHAR KeProcessNodeSeed; extern ETHREAD KiInitialThread; extern EPROCESS KiInitialProcess; -extern ULONG KiInterruptTemplate[KINTERRUPT_DISPATCH_CODES]; extern PULONG KiInterruptTemplateObject; extern PULONG KiInterruptTemplateDispatch; extern PULONG KiInterruptTemplate2ndDispatch; diff --git a/reactos/ntoskrnl/include/internal/trap_x.h b/reactos/ntoskrnl/include/internal/trap_x.h index e71b1c097de..f5ca8e9946a 100644 --- a/reactos/ntoskrnl/include/internal/trap_x.h +++ b/reactos/ntoskrnl/include/internal/trap_x.h @@ -755,6 +755,7 @@ KiEnterTrap(IN PKTRAP_FRAME TrapFrame) #define KI_NONVOLATILES_ONLY 0x4 #define KI_FAST_SYSTEM_CALL 0x8 #define KI_SOFTWARE_TRAP 0x10 +#define KI_HARDWARE_INT 0x20 #define KiTrap(x, y) VOID DECLSPEC_NORETURN x(VOID) { KiTrapStub(y, x##Handler); UNREACHABLE; } #define KiTrampoline(x, y) VOID DECLSPEC_NOINLINE x(VOID) { KiTrapStub(y, x##Handler); } @@ -849,16 +850,39 @@ KiTrapStub(IN ULONG Flags, /* Now set parameter 1 (ECX) to point to the frame */ __asm__ __volatile__ ("movl %%esp, %%ecx\n":::"%esp"); - /* For Fast-V86 traps, move set parameter 2 (EDX) to hold EFlags */ + /* For Fast-V86 traps, set parameter 2 (EDX) to hold EFlags */ if (Flags & KI_FAST_V86_TRAP) __asm__ __volatile__ ( "movl %c[f](%%esp), %%edx\n" : : [f] "i"(FIELD_OFFSET(KTRAP_FRAME, EFlags)) ); + else if (Flags & KI_HARDWARE_INT) __asm__ __volatile__ + ( + /* + * For hardware interrupts, set parameter 2 (EDX) to hold KINTERRUPT. + * This code will be dynamically patched when an interrupt is registered! + */ + ".globl _KiInterruptTemplate2ndDispatch\n_KiInterruptTemplate2ndDispatch:\n" + "movl $0, %%edx\n" + ".globl _KiInterruptTemplateObject\n_KiInterruptTemplateObject:\n" + ::: "%edx" + ); /* Now jump to the C handler */ - __asm__ __volatile__ ("jmp %c[x]\n":: [x] "i"(Handler)); + if (Flags & KI_HARDWARE_INT)__asm__ __volatile__ + ( + /* + * For hardware interrupts, use an absolute JMP instead of a relative JMP + * since the position of this code is arbitrary in memory, and therefore + * the compiler-generated offset will not be correct. + */ + "jmp *%0\n" + ".globl _KiInterruptTemplateDispatch\n_KiInterruptTemplateDispatch:\n" + : + : "a"(Handler) + ); + else __asm__ __volatile__ ("jmp %c[x]\n":: [x] "i"(Handler)); } #endif diff --git a/reactos/ntoskrnl/ke/i386/ctxswitch.S b/reactos/ntoskrnl/ke/i386/ctxswitch.S index 3cd98b916fe..4af3f9b504d 100644 --- a/reactos/ntoskrnl/ke/i386/ctxswitch.S +++ b/reactos/ntoskrnl/ke/i386/ctxswitch.S @@ -380,6 +380,124 @@ WrongCpu: ret .endfunc +/* DPC INTERRUPT HANDLER ******************************************************/ + +.globl _KiDispatchInterrupt@0 +.func KiDispatchInterrupt@0 +_KiDispatchInterrupt@0: + + /* Preserve EBX */ + push ebx + + /* Get the PCR and disable interrupts */ + mov ebx, PCR[KPCR_SELF] + cli + + /* Check if we have to deliver DPCs, timers, or deferred threads */ + mov eax, [ebx+KPCR_PRCB_DPC_QUEUE_DEPTH] + or eax, [ebx+KPCR_PRCB_TIMER_REQUEST] + or eax, [ebx+KPCR_PRCB_DEFERRED_READY_LIST_HEAD] + jz CheckQuantum + + /* Save stack pointer and exception list, then clear it */ + push ebp + push dword ptr [ebx+KPCR_EXCEPTION_LIST] + mov dword ptr [ebx+KPCR_EXCEPTION_LIST], -1 + + /* Save the stack and switch to the DPC Stack */ + mov edx, esp + mov esp, [ebx+KPCR_PRCB_DPC_STACK] + push edx + + /* Deliver DPCs */ + mov ecx, [ebx+KPCR_PRCB] + call @KiRetireDpcList@4 + + /* Restore stack and exception list */ + pop esp + pop dword ptr [ebx+KPCR_EXCEPTION_LIST] + pop ebp + +CheckQuantum: + + /* Re-enable interrupts */ + sti + + /* Check if we have quantum end */ + cmp byte ptr [ebx+KPCR_PRCB_QUANTUM_END], 0 + jnz QuantumEnd + + /* Check if we have a thread to swap to */ + cmp byte ptr [ebx+KPCR_PRCB_NEXT_THREAD], 0 + je Return + + /* Make space on the stack to save registers */ + sub esp, 3 * 4 + mov [esp+8], esi + mov [esp+4], edi + mov [esp+0], ebp + + /* Get the current thread */ + mov edi, [ebx+KPCR_CURRENT_THREAD] + +#ifdef CONFIG_SMP + /* Raise to synch level */ + call _KeRaiseIrqlToSynchLevel@0 + + /* Set context swap busy */ + mov byte ptr [edi+KTHREAD_SWAP_BUSY], 1 + + /* Acquire the PRCB Lock */ + lock bts dword ptr [ebx+KPCR_PRCB_PRCB_LOCK], 0 + jnb GetNext + lea ecx, [ebx+KPCR_PRCB_PRCB_LOCK] + call @KefAcquireSpinLockAtDpcLevel@4 +#endif + +GetNext: + /* Get the next thread and clear it */ + mov esi, [ebx+KPCR_PRCB_NEXT_THREAD] + and dword ptr [ebx+KPCR_PRCB_NEXT_THREAD], 0 + + /* Set us as the current running thread */ + mov [ebx+KPCR_CURRENT_THREAD], esi + mov byte ptr [esi+KTHREAD_STATE_], Running + mov byte ptr [edi+KTHREAD_WAIT_REASON], WrDispatchInt + + /* Put thread in ECX and get the PRCB in EDX */ + mov ecx, edi + lea edx, [ebx+KPCR_PRCB_DATA] + call @KiQueueReadyThread@8 + + /* Set APC_LEVEL and do the swap */ + mov cl, APC_LEVEL + call @KiSwapContextInternal@0 + +#ifdef CONFIG_SMP + /* Lower IRQL back to dispatch */ + mov cl, DISPATCH_LEVEL + call @KfLowerIrql@4 +#endif + + /* Restore registers */ + mov ebp, [esp+0] + mov edi, [esp+4] + mov esi, [esp+8] + add esp, 3*4 + +Return: + /* All done */ + pop ebx + ret + +QuantumEnd: + /* Disable quantum end and process it */ + mov byte ptr [ebx+KPCR_PRCB_QUANTUM_END], 0 + call _KiQuantumEnd@0 + pop ebx + ret +.endfunc + .globl @KiIdleLoop@0 .func @KiIdleLoop@0, @KiIdleLoop@0 @KiIdleLoop@0: @@ -507,6 +625,7 @@ NoNextThread: #endif .endfunc +/* FIXFIX: Move to C code ****/ .globl _Ki386SetupAndExitToV86Mode@4 .func Ki386SetupAndExitToV86Mode@4 _Ki386SetupAndExitToV86Mode@4: diff --git a/reactos/ntoskrnl/ke/i386/irqobj.c b/reactos/ntoskrnl/ke/i386/irqobj.c index 2c19ae45a38..b58b1dac951 100644 --- a/reactos/ntoskrnl/ke/i386/irqobj.c +++ b/reactos/ntoskrnl/ke/i386/irqobj.c @@ -241,8 +241,8 @@ KiChainedDispatch(IN PKTRAP_FRAME TrapFrame, VOID FASTCALL -KiInterruptHandler(IN PKTRAP_FRAME TrapFrame, - IN PKINTERRUPT Interrupt) +KiInterruptTemplateHandler(IN PKTRAP_FRAME TrapFrame, + IN PKINTERRUPT Interrupt) { /* Enter interrupt frame */ KiEnterInterruptTrap(TrapFrame); @@ -251,6 +251,7 @@ KiInterruptHandler(IN PKTRAP_FRAME TrapFrame, ((PKI_INTERRUPT_DISPATCH*)Interrupt->DispatchAddress)(TrapFrame, Interrupt); } +KiTrap(KiInterruptTemplate, KI_PUSH_FAKE_ERROR_CODE | KI_HARDWARE_INT); KiTrap(KiUnexpectedInterruptTail, KI_PUSH_FAKE_ERROR_CODE); /* PUBLIC FUNCTIONS **********************************************************/ @@ -308,7 +309,7 @@ KeInitializeInterrupt(IN PKINTERRUPT Interrupt, for (i = 0; i < KINTERRUPT_DISPATCH_CODES; i++) { /* Copy the dispatch code */ - *DispatchCode++ = KiInterruptTemplate[i]; + *DispatchCode++ = ((PULONG)KiInterruptTemplate)[i]; } /* Jump to the last 4 bytes */ diff --git a/reactos/ntoskrnl/ke/i386/trap.s b/reactos/ntoskrnl/ke/i386/trap.s index 1d6ffecdc11..293cd6f8106 100644 --- a/reactos/ntoskrnl/ke/i386/trap.s +++ b/reactos/ntoskrnl/ke/i386/trap.s @@ -10,12 +10,8 @@ #include #include -#include .intel_syntax noprefix -#define Running 2 -#define WrDispatchInt 0x1F - /* GLOBALS *******************************************************************/ .data @@ -53,28 +49,6 @@ idt _KiSystemService, INT_32_DPL3 /* INT 2E: System Call Service Handler */ idt _KiTrap0F, INT_32_DPL0 /* INT 2F: RESERVED */ GENERATE_IDT_STUBS /* INT 30-FF: UNEXPECTED INTERRUPTS */ -/* System call entrypoints: */ -.globl _KiFastCallEntry -.globl _KiSystemService - -/* And special system-defined software traps: */ -.globl _KiDispatchInterrupt@0 - -/* Interrupt template entrypoints */ -.globl _KiInterruptTemplate -.globl _KiInterruptTemplateObject -.globl _KiInterruptTemplateDispatch - -#ifndef HAL_INTERRUPT_SUPPORT_IN_C -/* Chained and Normal generic interrupt handlers for 1st and 2nd level entry*/ -.globl _KiChainedDispatch2ndLvl@0 -.globl _KiInterruptDispatch@0 -.globl _KiChainedDispatch@0 -#endif - -/* We implement the following trap exit points: */ -.globl _Kei386EoiHelper@0 /* Exit from interrupt or H/W trap */ - .globl _KiIdtDescriptor _KiIdtDescriptor: .short 0 @@ -85,63 +59,8 @@ _KiIdtDescriptor: _KiUnexpectedEntrySize: .long _KiUnexpectedInterrupt1 - _KiUnexpectedInterrupt0 -_UnexpectedMsg: - .asciz "\n\x7\x7!!! Unexpected Interrupt %02lx !!!\n" - -_V86UnhandledMsg: - .asciz "\n\x7\x7!!! Unhandled V8086 (VDM) support at line: %lx!!!\n" - -_UnhandledMsg: - .asciz "\n\x7\x7!!! Unhandled or Unexpected Code at line: %lx [%s]!!!\n" - -_IsrTimeoutMsg: - .asciz "\n*** ISR at %lx took over .5 second\n" - -_IsrOverflowMsg: - .asciz "\n*** ISR at %lx appears to have an interrupt storm\n" - -/* SOFTWARE INTERRUPT SERVICES ***********************************************/ .text - -.func Kei386EoiHelper@0 -_Kei386EoiHelper@0: - - /* Disable interrupts */ - cli - - /* Check for, and deliver, User-Mode APCs if needed */ - CHECK_FOR_APC_DELIVER 0 - - /* Exit and cleanup */ -_Kei386EoiHelper2ndEntry: - TRAP_EPILOG NotFromSystemCall, DoNotRestorePreviousMode, DoRestoreSegments, DoRestoreVolatiles, DoNotRestoreEverything -.endfunc - -V86_Exit: - /* Move to EDX position */ - add esp, KTRAP_FRAME_EDX - - /* Restore volatiles */ - pop edx - pop ecx - pop eax - - /* Move to non-volatiles */ - lea esp, [ebp+KTRAP_FRAME_EDI] - pop edi - pop esi - pop ebx - pop ebp - - /* Skip error code and return */ - add esp, 4 - iret - -AbiosExit: - /* FIXME: TODO */ - UNHANDLED_PATH - -/* UNEXPECTED INTERRUPT HANDLERS **********************************************/ +/* HARDWARE INTERRUPT HANDLERS ************************************************/ .globl _KiStartUnexpectedRange@0 _KiStartUnexpectedRange@0: @@ -151,159 +70,3 @@ GENERATE_INT_HANDLERS .globl _KiEndUnexpectedRange@0 _KiEndUnexpectedRange@0: jmp _KiUnexpectedInterruptTail - - -/* DPC INTERRUPT HANDLER ******************************************************/ - -.func KiDispatchInterrupt@0 -_KiDispatchInterrupt@0: - - /* Preserve EBX */ - push ebx - - /* Get the PCR and disable interrupts */ - mov ebx, PCR[KPCR_SELF] - cli - - /* Check if we have to deliver DPCs, timers, or deferred threads */ - mov eax, [ebx+KPCR_PRCB_DPC_QUEUE_DEPTH] - or eax, [ebx+KPCR_PRCB_TIMER_REQUEST] - or eax, [ebx+KPCR_PRCB_DEFERRED_READY_LIST_HEAD] - jz CheckQuantum - - /* Save stack pointer and exception list, then clear it */ - push ebp - push dword ptr [ebx+KPCR_EXCEPTION_LIST] - mov dword ptr [ebx+KPCR_EXCEPTION_LIST], -1 - - /* Save the stack and switch to the DPC Stack */ - mov edx, esp - mov esp, [ebx+KPCR_PRCB_DPC_STACK] - push edx - - /* Deliver DPCs */ - mov ecx, [ebx+KPCR_PRCB] - call @KiRetireDpcList@4 - - /* Restore stack and exception list */ - pop esp - pop dword ptr [ebx+KPCR_EXCEPTION_LIST] - pop ebp - -CheckQuantum: - - /* Re-enable interrupts */ - sti - - /* Check if we have quantum end */ - cmp byte ptr [ebx+KPCR_PRCB_QUANTUM_END], 0 - jnz QuantumEnd - - /* Check if we have a thread to swap to */ - cmp byte ptr [ebx+KPCR_PRCB_NEXT_THREAD], 0 - je Return - - /* Make space on the stack to save registers */ - sub esp, 3 * 4 - mov [esp+8], esi - mov [esp+4], edi - mov [esp+0], ebp - - /* Get the current thread */ - mov edi, [ebx+KPCR_CURRENT_THREAD] - -#ifdef CONFIG_SMP - /* Raise to synch level */ - call _KeRaiseIrqlToSynchLevel@0 - - /* Set context swap busy */ - mov byte ptr [edi+KTHREAD_SWAP_BUSY], 1 - - /* Acquire the PRCB Lock */ - lock bts dword ptr [ebx+KPCR_PRCB_PRCB_LOCK], 0 - jnb GetNext - lea ecx, [ebx+KPCR_PRCB_PRCB_LOCK] - call @KefAcquireSpinLockAtDpcLevel@4 -#endif - -GetNext: - /* Get the next thread and clear it */ - mov esi, [ebx+KPCR_PRCB_NEXT_THREAD] - and dword ptr [ebx+KPCR_PRCB_NEXT_THREAD], 0 - - /* Set us as the current running thread */ - mov [ebx+KPCR_CURRENT_THREAD], esi - mov byte ptr [esi+KTHREAD_STATE_], Running - mov byte ptr [edi+KTHREAD_WAIT_REASON], WrDispatchInt - - /* Put thread in ECX and get the PRCB in EDX */ - mov ecx, edi - lea edx, [ebx+KPCR_PRCB_DATA] - call @KiQueueReadyThread@8 - - /* Set APC_LEVEL and do the swap */ - mov cl, APC_LEVEL - call @KiSwapContextInternal@0 - -#ifdef CONFIG_SMP - /* Lower IRQL back to dispatch */ - mov cl, DISPATCH_LEVEL - call @KfLowerIrql@4 -#endif - - /* Restore registers */ - mov ebp, [esp+0] - mov edi, [esp+4] - mov esi, [esp+8] - add esp, 3*4 - -Return: - /* All done */ - pop ebx - ret - -QuantumEnd: - /* Disable quantum end and process it */ - mov byte ptr [ebx+KPCR_PRCB_QUANTUM_END], 0 - call _KiQuantumEnd@0 - pop ebx - ret -.endfunc - -/* - * We setup the stack for a trap frame in the KINTERRUPT DispatchCode itself and - * then move the stack address in ECX, since the handlers are FASTCALL. We also - * need to know the address of the KINTERRUPT. To do this, we maintain the old - * dynamic patching technique (EDX instead of EDI, however) and let the C API - * up in KeInitializeInterrupt replace the 0 with the address. Since this is in - * EDX, it becomes the second parameter for our FASTCALL function. - * - * Finally, we jump directly to the C interrupt handler, which will choose the - * appropriate dispatcher (chained, single, flat, floating) that was setup. The - * dispatchers themselves are also C FASTCALL functions. This double-indirection - * maintains the NT model should anything depend on it. - * - * Note that since we always jump to the C handler which then jumps to the C - * dispatcher, the first JMP in the template object is NOT patched anymore since - * it's static. Also, keep in mind this code is dynamically copied into nonpaged - * pool! It runs off the KINTERRUPT directly, so you can't just JMP to the code - * since JMPs are relative, and the location of the JMP below is dynamic. So we - * use EDI to store the absolute offset, and jump to that instead. - * - */ -.func KiInterruptTemplate -_KiInterruptTemplate: - TRAP_HANDLER_PROLOG 1, 0 - -_KiInterruptTemplate2ndDispatch: - /* Dummy code, will be replaced by the address of the KINTERRUPT */ - mov edx, 0 - -_KiInterruptTemplateObject: - /* Jump to C code */ - mov edi, offset @KiInterruptHandler@8 - jmp edi - -_KiInterruptTemplateDispatch: - /* Marks the end of the template so that the jump above can be edited */ -.endfunc diff --git a/reactos/ntoskrnl/ke/i386/traphdlr.c b/reactos/ntoskrnl/ke/i386/traphdlr.c index df7ef3da961..9e0c29cc330 100644 --- a/reactos/ntoskrnl/ke/i386/traphdlr.c +++ b/reactos/ntoskrnl/ke/i386/traphdlr.c @@ -1601,4 +1601,16 @@ KiTrap(KiDebugService, KI_PUSH_FAKE_ERROR_CODE); KiTrap(KiSystemService, KI_PUSH_FAKE_ERROR_CODE | KI_NONVOLATILES_ONLY); KiTrap(KiFastCallEntry, KI_FAST_SYSTEM_CALL); +/* + * @implemented + */ +VOID +NTAPI +Kei386EoiHelper(VOID) +{ + /* We should never see this call happening */ + DPRINT1("Mismatched NT/HAL version"); + while (TRUE); +} + /* EOF */ diff --git a/reactos/ntoskrnl/ke/i386/usercall_asm.S b/reactos/ntoskrnl/ke/i386/usercall_asm.S index da0642d8e2f..017a736d1e3 100644 --- a/reactos/ntoskrnl/ke/i386/usercall_asm.S +++ b/reactos/ntoskrnl/ke/i386/usercall_asm.S @@ -200,9 +200,6 @@ SetEip: /* Bring interrupts back */ sti - /* Write the debug data */ - SET_TF_DEBUG_HEADER - /* Exit to user-mode */ mov ecx, esp jmp @KiServiceExit@8 -- 2.17.1