Trap handlers in C patch 7 of X:

[NTOS]: Implement GPF handler (trap 13) in C. This was by far the most complex one of them, since it also servces two complex purposes: to handle V86 emulation since the real-mode code will generate GPFs during privileged instructions, and it will detect an illegal IRET, check if it's the known V8086 Exit IRET, and then jump to V86 exit code.
    [NTOS]: Get rid of even more V8086 assembly since the GPF handler is now C. Deleted the entire V8086 assembly file.
    [NTOS]: Get rid of a bunch of helper ASM functions that nobody is using anymore since almost all the trap handlers are in C.

svn path=/trunk/; revision=45038
This commit is contained in:
Sir Richard 2010-01-11 05:53:57 +00:00
parent 38de4a0a1c
commit 0fc870d7d9
7 changed files with 352 additions and 618 deletions

View file

@ -409,6 +409,12 @@ KiEoiHelper(
IN PKTRAP_FRAME TrapFrame
);
VOID
FASTCALL
KiExitV86Mode(
IN PKTRAP_FRAME TrapFrame
);
//
// Global x86 only Kernel data
//
@ -518,5 +524,20 @@ Ke386SanitizeDr(IN PVOID DrAddress,
(DrAddress <= MM_HIGHEST_USER_ADDRESS) ? DrAddress : 0);
}
FORCEINLINE
VOID
KiV86TrapReturn(IN ULONG_PTR Stack)
{
/* Restore volatiles and stack */
__asm__ __volatile__
(
"movl %0, %%esp\n"
"popa\n"
"ret\n"
:
: "r"(Stack)
: "%esp"
);
}
#endif
#endif /* __NTOSKRNL_INCLUDE_INTERNAL_I386_KE_H */

View file

@ -864,3 +864,13 @@ WrongCpu2:
int 3
#endif
.endfunc
.globl _Ki386SetupAndExitToV86Mode@4
.func Ki386SetupAndExitToV86Mode@4
_Ki386SetupAndExitToV86Mode@4:
/* Enter V8086 mode */
pushad
call @KiEnterV86Mode@0
.endfunc

View file

@ -573,95 +573,6 @@ Error:
jmp _KiServiceExit
.endfunc
/* EXCEPTION DISPATCHERS *****************************************************/
.func CommonDispatchException
_CommonDispatchException:
/* Make space for an exception record */
sub esp, EXCEPTION_RECORD_LENGTH
/* Set it up */
mov [esp+EXCEPTION_RECORD_EXCEPTION_CODE], eax
xor eax, eax
mov [esp+EXCEPTION_RECORD_EXCEPTION_FLAGS], eax
mov [esp+EXCEPTION_RECORD_EXCEPTION_RECORD], eax
mov [esp+EXCEPTION_RECORD_EXCEPTION_ADDRESS], ebx
mov [esp+EXCEPTION_RECORD_NUMBER_PARAMETERS], ecx
/* Check parameter count */
cmp ecx, 0
jz NoParams
/* Get information */
lea ebx, [esp+SIZEOF_EXCEPTION_RECORD]
mov [ebx], edx
mov [ebx+4], esi
mov [ebx+8], edi
NoParams:
/* Set the record in ECX and check if this was V86 */
mov ecx, esp
test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
jz SetPreviousMode
/* Set V86 mode */
mov eax, 0xFFFF
jmp MaskMode
SetPreviousMode:
/* Get the caller's CS */
mov eax, [ebp+KTRAP_FRAME_CS]
MaskMode:
/* Check if it was user-mode or kernel-mode */
and eax, MODE_MASK
/* Dispatch the exception */
push 1
push eax
push ebp
push 0
push ecx
call _KiDispatchException@20
/* End the trap */
mov esp, ebp
jmp _Kei386EoiHelper@0
.endfunc
.func DispatchNoParam
_DispatchNoParam:
/* Call the common dispatcher */
xor ecx, ecx
call _CommonDispatchException
.endfunc
.func DispatchOneParamZero
_DispatchOneParamZero:
/* Call the common dispatcher */
xor edx, edx
mov ecx, 1
call _CommonDispatchException
.endfunc
.func DispatchTwoParamZero
_DispatchTwoParamZero:
/* Call the common dispatcher */
xor edx, edx
mov ecx, 2
call _CommonDispatchException
.endfunc
.func DispatchTwoParam
_DispatchTwoParam:
/* Call the common dispatcher */
mov ecx, 2
call _CommonDispatchException
.endfunc
/* HARDWARE TRAP HANDLERS ****************************************************/
GENERATE_TRAP_HANDLER KiTrap0, 1
@ -699,492 +610,7 @@ GENERATE_TRAP_HANDLER KiTrap9, 1
GENERATE_TRAP_HANDLER KiTrap10, 0
GENERATE_TRAP_HANDLER KiTrap11, 0
GENERATE_TRAP_HANDLER KiTrap12, 0
.func KiTrapExceptHandler
_KiTrapExceptHandler:
/* Setup SEH handler frame */
mov esp, [esp+8]
pop PCR[KPCR_EXCEPTION_LIST]
add esp, 4
pop ebp
/* Check if the fault came from user mode */
test dword ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
jnz SetException
/* Kernel fault, bugcheck */
push ebp
push 0
push 0
push 0
push 0
push KMODE_EXCEPTION_NOT_HANDLED
call _KeBugCheckWithTf@24
.endfunc
.func KiTrap13
TRAP_FIXUPS kitd_a, kitd_t, DoFixupV86, DoNotFixupAbios
_KiTrap13:
/* It this a V86 GPF? */
test dword ptr [esp+12], EFLAGS_V86_MASK
jz NotV86
/* Enter V86 Trap */
V86_TRAP_PROLOG kitd_a, kitd_v
/* Make sure that this is a V86 process */
mov ecx, PCR[KPCR_CURRENT_THREAD]
mov ecx, [ecx+KTHREAD_APCSTATE_PROCESS]
cmp dword ptr [ecx+EPROCESS_VDM_OBJECTS], 0
jnz RaiseIrql
/* Otherwise, something is very wrong, raise an exception */
sti
jmp SetException
RaiseIrql:
/* Go to APC level */
mov ecx, APC_LEVEL
call @KfRaiseIrql@4
/* Save old IRQL and enable interrupts */
push eax
sti
/* Handle the opcode */
mov ecx, ebp
call @Ki386HandleOpcodeV86@4
/* Check if this was VDM */
test al, 0xFF
jnz NoReflect
/* FIXME: TODO */
UNHANDLED_V86_PATH
NoReflect:
/* Lower IRQL and disable interrupts */
pop ecx
call @KfLowerIrql@4
cli
/* Check if this was a V86 trap */
test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
jz NotV86Trap
/* Exit the V86 Trap */
V86_TRAP_EPILOG
NotV86Trap:
/* Either this wasn't V86, or it was, but an APC interrupted us */
jmp _Kei386EoiHelper@0
NotV86:
/* Enter trap */
TRAP_PROLOG kitd_a, kitd_t
/* Check if this was from kernel-mode */
test dword ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
jnz UserModeGpf
///* Check if we have a VDM alert */
//cmp dword ptr PCR[KPCR_VDM_ALERT], 0 // BUGBUG: Add this back later
//jnz VdmAlertGpf
/* Check for GPF during GPF */
mov eax, [ebp+KTRAP_FRAME_EIP]
cmp eax, offset CheckPrivilegedInstruction
jbe KmodeGpf
cmp eax, offset CheckPrivilegedInstruction2
jae KmodeGpf
/* FIXME: TODO */
UNHANDLED_PATH "Double GPF"
/* Get the opcode and trap frame */
KmodeGpf:
mov eax, [ebp+KTRAP_FRAME_EIP]
mov eax, [eax]
mov edx, [ebp+KTRAP_FRAME_EBP]
/* We want to check if this was POP [DS/ES/FS/GS] */
add edx, KTRAP_FRAME_DS
cmp al, 0x1F
jz SegPopGpf
add edx, KTRAP_FRAME_ES - KTRAP_FRAME_DS
cmp al, 7
jz SegPopGpf
add edx, KTRAP_FRAME_FS - KTRAP_FRAME_ES
cmp ax, 0xA10F
jz SegPopGpf
add edx, KTRAP_FRAME_GS - KTRAP_FRAME_FS
cmp ax, 0xA90F
jz SegPopGpf
/* It isn't, was it IRETD? */
cmp al, 0xCF
jne NotIretGpf
/* Get error code */
lea edx, [ebp+KTRAP_FRAME_ESP]
mov ax, [ebp+KTRAP_FRAME_ERROR_CODE]
and ax, ~RPL_MASK
/* Get CS */
mov cx, word ptr [edx+4]
and cx, ~RPL_MASK
cmp cx, ax
jnz NotCsGpf
/* This should be a Ki386CallBios return */
mov eax, offset _Ki386BiosCallReturnAddress
cmp eax, [edx]
jne NotBiosGpf
mov eax, [edx+4]
cmp ax, KGDT_R0_CODE + RPL_MASK
jne NotBiosGpf
/* Jump to return address */
jmp _Ki386BiosCallReturnAddress
NotBiosGpf:
/* Check if the thread was in kernel mode */
mov ebx, PCR[KPCR_CURRENT_THREAD]
test byte ptr [ebx+KTHREAD_PREVIOUS_MODE], 0xFF
jz UserModeGpf
/* Set RPL_MASK for check below */
or word ptr [edx+4], RPL_MASK
NotCsGpf:
/* Check if the IRET goes to user-mode */
test dword ptr [edx+4], RPL_MASK
jz UserModeGpf
/* Setup trap frame to copy */
mov ecx, (KTRAP_FRAME_LENGTH - 12) / 4
lea edx, [ebp+KTRAP_FRAME_ERROR_CODE]
TrapCopy:
/* Copy each field */
mov eax, [edx]
mov [edx+12], eax
sub edx, 4
loop TrapCopy
/* Enable interrupts and adjust stack */
sti
add esp, 12
add ebp, 12
/* Setup exception record */
mov ebx, [ebp+KTRAP_FRAME_EIP]
mov esi, [ebp+KTRAP_FRAME_ERROR_CODE]
and esi, 0xFFFF
mov eax, STATUS_ACCESS_VIOLATION
jmp _DispatchTwoParamZero
MsrCheck:
/* FIXME: Handle RDMSR/WRMSR */
UNHANDLED_PATH "RDMSR/WRMSR"
NotIretGpf:
/* Check if this was an MSR opcode */
cmp al, 0xF
jz MsrCheck
/* Check if DS is Ring 3 */
cmp word ptr [ebp+KTRAP_FRAME_DS], KGDT_R3_DATA + RPL_MASK
jz CheckEs
/* Otherwise, fix it up */
mov dword ptr [ebp+KTRAP_FRAME_DS], KGDT_R3_DATA + RPL_MASK
jmp ExitGpfTrap
CheckEs:
/* Check if ES is Ring 3 */
cmp word ptr [ebp+KTRAP_FRAME_ES], KGDT_R3_DATA + RPL_MASK
jz UserModeGpf
/* Otherwise, fix it up */
mov dword ptr [ebp+KTRAP_FRAME_ES], KGDT_R3_DATA + RPL_MASK
jmp ExitGpfTrap
SegPopGpf:
/* Sanity check */
lea eax, [ebp+KTRAP_FRAME_ESP]
cmp edx, eax
jz HandleSegPop
int 3
/* Handle segment POP fault by setting it to 0 */
HandleSegPop:
xor eax, eax
mov dword ptr [edx], eax
ExitGpfTrap:
/* Do a trap exit */
TRAP_EPILOG NotFromSystemCall, DoNotRestorePreviousMode, DoNotRestoreSegments, DoRestoreVolatiles, DoRestoreEverything
UserModeGpf:
/* If the previous mode was kernel, raise a fatal exception */
mov eax, 13
test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
jz _KiSystemFatalException
/* Get the process and check which CS this came from */
mov ebx, PCR[KPCR_CURRENT_THREAD]
mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
jz CheckVdmGpf
/* Check if this is a VDM */
cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
jnz DispatchV86Gpf
/* Enable interrupts and check if we have an error code */
sti
cmp word ptr [ebp+KTRAP_FRAME_ERROR_CODE], 0
jnz SetException
jmp CheckPrivilegedInstruction
HandleSegPop2:
/* Update EIP (will be updated below again) */
add dword ptr [ebp+KTRAP_FRAME_EIP], 1
HandleEsPop:
/* Clear the segment, update EIP and ESP */
mov dword ptr [edx], 0
add dword ptr [ebp+KTRAP_FRAME_EIP], 1
add dword ptr [ebp+KTRAP_FRAME_ESP], 4
jmp _Kei386EoiHelper@0
CheckVdmGpf:
/* Check if this is a VDM */
cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
jz CheckPrivilegedInstruction
/* Bring interrupts back */
sti
/* Check what kind of instruction this is */
mov eax, [ebp+KTRAP_FRAME_EIP]
mov eax, [eax]
/* FIXME: Check for BOP4 */
/* Check if this is POP ES */
mov edx, ebp
add edx, KTRAP_FRAME_ES
cmp al, 0x07
jz HandleEsPop
/* Check if this is POP FS */
add edx, KTRAP_FRAME_FS - KTRAP_FRAME_ES
cmp ax, 0xA10F
jz HandleSegPop2
/* Check if this is POP GS */
add edx, KTRAP_FRAME_GS - KTRAP_FRAME_FS
cmp ax, 0xA90F
jz HandleSegPop2
CheckPrivilegedInstruction:
/* Bring interrupts back */
sti
/* Setup a SEH handler */
push ebp
push offset _KiTrapExceptHandler
push PCR[KPCR_EXCEPTION_LIST]
mov PCR[KPCR_EXCEPTION_LIST], esp
/* Get EIP */
mov esi, [ebp+KTRAP_FRAME_EIP]
/* Setup loop count */
mov ecx, 15
InstLoop:
/* Save loop count */
push ecx
/* Get the instruction */
lods byte ptr [esi]
/* Now lookup in the prefix table */
mov ecx, 11
mov edi, offset _KiTrapPrefixTable
repnz scasb
/* Restore loop count */
pop ecx
/* If it's not a prefix byte, check other instructions */
jnz NotPrefixByte
/* Keep looping */
loop InstLoop
/* Fixup the stack */
pop PCR[KPCR_EXCEPTION_LIST]
add esp, 8
/* Re-enable interrupts */
sti
/* Setup illegal instruction exception and dispatch it */
mov ebx, [ebp+KTRAP_FRAME_EIP]
mov eax, STATUS_ILLEGAL_INSTRUCTION
jmp _DispatchNoParam
NotPrefixByte:
/* Check if it's a HLT */
cmp al, 0x0F4
je IsPrivInstruction
/* Check if the instruction has two bytes */
cmp al, 0xF
jne CheckRing3Io
/* Check if this is a LLDT or LTR */
lods byte ptr [esi]
cmp al, 0
jne NotLldt
/* Check if this is an LLDT */
lods byte ptr [esi]
and al, 0x38
cmp al, 0x10
je IsPrivInstruction
/* Check if this is an LTR */
cmp al, 0x18
je IsPrivInstruction
/* Otherwise, access violation */
jmp NotIoViolation
NotLldt:
/* Check if this is LGDT or LIDT or LMSW */
cmp al, 0x01
jne NotGdt
/* Check if this is an LGDT */
lods byte ptr [esi]
and al, 0x38
cmp al, 0x10
je IsPrivInstruction
/* Check if this is an LIDT */
cmp al, 0x18
je IsPrivInstruction
/* Check if this is an LMSW */
cmp al, 0x30
je IsPrivInstruction
/* Otherwise, access violation */
jmp NotIoViolation
NotGdt:
/* Check if it's INVD or WBINVD */
cmp al, 0x8
je IsPrivInstruction
cmp al, 0x9
je IsPrivInstruction
/* Check if it's sysexit */
cmp al, 0x35
je IsPrivInstruction
/* Check if it's a DR move */
cmp al, 0x26
je IsPrivInstruction
/* Check if it's a CLTS */
cmp al, 0x6
je IsPrivInstruction
/* Check if it's a CR move */
cmp al, 0x20
jb NotIoViolation
/* Check if it's a DR move */
cmp al, 0x24
jbe IsPrivInstruction
/* Everything else is an access violation */
jmp NotIoViolation
CheckRing3Io:
/* Get EFLAGS and IOPL */
mov ebx, [ebp+KTRAP_FRAME_EFLAGS]
and ebx, EFLAGS_IOPL
shr ebx, 12
/* Check the CS's RPL mask */
mov ecx, [ebp+KTRAP_FRAME_CS]
and ecx, RPL_MASK
cmp ebx, ecx
jge NotIoViolation
CheckPrivilegedInstruction2:
/* Check if this is a CLI or STI */
cmp al, 0xFA
je IsPrivInstruction
cmp al, 0xFB
je IsPrivInstruction
/* Setup I/O table lookup */
mov ecx, 13
mov edi, offset _KiTrapIoTable
/* Loopup in the table */
repnz scasb
jnz NotIoViolation
/* FIXME: Check IOPM!!! */
IsPrivInstruction:
/* Cleanup the SEH frame */
pop PCR[KPCR_EXCEPTION_LIST]
add esp, 8
/* Setup the exception */
mov ebx, [ebp+KTRAP_FRAME_EIP]
mov eax, STATUS_PRIVILEGED_INSTRUCTION
jmp _DispatchNoParam
NotIoViolation:
/* Cleanup the SEH frame */
pop PCR[KPCR_EXCEPTION_LIST]
add esp, 8
SetException:
/* Setup the exception */
mov ebx, [ebp+KTRAP_FRAME_EIP]
mov esi, -1
mov eax, STATUS_ACCESS_VIOLATION
jmp _DispatchTwoParamZero
DispatchV86Gpf:
/* FIXME */
UNHANDLED_V86_PATH
.endfunc
GENERATE_TRAP_HANDLER KiTrap13, 0
GENERATE_TRAP_HANDLER KiTrap14, 0
GENERATE_TRAP_HANDLER KiTrap0F, 1
GENERATE_TRAP_HANDLER KiTrap16, 1

View file

@ -6,13 +6,46 @@
* PROGRAMMERS: ReactOS Portable Systems Group
*/
/* INCLUDES *****************************************************************/
/* INCLUDES *******************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
#include "internal/trap_x.h"
/* GLOBALS ********************************************************************/
UCHAR KiTrapPrefixTable[] =
{
0xF2, /* REP */
0xF3, /* REP INS/OUTS */
0x67, /* ADDR */
0xF0, /* LOCK */
0x66, /* OP */
0x2E, /* SEG */
0x3E, /* DS */
0x26, /* ES */
0x64, /* FS */
0x65, /* GS */
0x36, /* SS */
};
UCHAR KiTrapIoTable[] =
{
0xE4, /* IN */
0xE5, /* IN */
0xEC, /* IN */
0xED, /* IN */
0x6C, /* INS */
0x6D, /* INS */
0xE6, /* OUT */
0xE7, /* OUT */
0xEE, /* OUT */
0xEF, /* OUT */
0x6E, /* OUTS */
0x6F, /* OUTS */
};
/* TRAP EXIT CODE *************************************************************/
VOID
@ -782,6 +815,288 @@ KiTrap12Handler(IN PKTRAP_FRAME TrapFrame)
KiSystemFatalException(EXCEPTION_STACK_FAULT, TrapFrame);
}
VOID
FASTCALL
KiTrap13Handler(IN PKTRAP_FRAME TrapFrame)
{
ULONG i, j, Iopl;
BOOLEAN Privileged = FALSE;
PUCHAR Instructions;
UCHAR Instruction = 0;
KIRQL OldIrql;
/* Check for V86 GPF */
if (TrapFrame->EFlags & EFLAGS_V86_MASK)
{
/* Enter V86 trap */
KiEnterV86Trap(TrapFrame);
/* Must be a VDM process */
if (!PsGetCurrentProcess()->VdmObjects)
{
/* Enable interrupts */
_enable();
/* Setup illegal instruction fault */
KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION,
TrapFrame->Eip,
TrapFrame);
}
/* Go to APC level */
OldIrql = KfRaiseIrql(APC_LEVEL);
_enable();
/* Handle the V86 opcode */
if (Ki386HandleOpcodeV86(TrapFrame) == 0xFF)
{
/* Should only happen in VDM mode */
UNIMPLEMENTED;
while (TRUE);
}
/* Bring IRQL back */
KfLowerIrql(OldIrql);
_disable();
/* Do a quick V86 exit if possible */
if (TrapFrame->EFlags & EFLAGS_V86_MASK) KiExitV86Trap(TrapFrame);
/* Exit trap the slow way */
KiEoiHelper(TrapFrame);
}
/* Save trap frame */
KiEnterTrap(TrapFrame);
/* Check for user-mode GPF */
if (KiUserTrap(TrapFrame))
{
/* Must be user-mode! */
if (!KiUserTrap(TrapFrame)) KiSystemFatalException(EXCEPTION_GP_FAULT, TrapFrame);
/* Should not be VDM */
ASSERT(KiVdmTrap(TrapFrame) == FALSE);
/* Enable interrupts and check error code */
_enable();
if (!TrapFrame->ErrCode)
{
/* FIXME: Use SEH */
Instructions = (PUCHAR)TrapFrame->Eip;
/* Scan next 15 opcodes */
for (i = 0; i < 15; i++)
{
/* Skip prefix instructions */
for (j = 0; j < sizeof(KiTrapPrefixTable); j++)
{
/* Is this NOT a prefix instruction? */
if (Instructions[i] != KiTrapPrefixTable[j])
{
/* We can go ahead and handle the fault now */
Instruction = Instructions[i];
break;
}
}
/* Do we need to keep looking? */
if (Instruction) break;
}
/* If all we found was prefixes, then this instruction is too long */
if (!Instruction)
{
/* Setup illegal instruction fault */
KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION,
TrapFrame->Eip,
TrapFrame);
}
/* Check for privileged instructions */
if (Instruction == 0xF4) // HLT
{
/* HLT is privileged */
Privileged = TRUE;
}
else if (Instruction == 0x0F)
{
/* Test if it's any of the privileged two-byte opcodes */
if (((Instructions[i + 1] == 0x00) && // LLDT or LTR
(((Instructions[i + 2] & 0x38) == 0x10) || // LLDT
(Instructions[i + 2] == 0x18))) || // LTR
((Instructions[i + 1] == 0x01) && // LGDT or LIDT or LMSW
(((Instructions[i + 2] & 0x38) == 0x10) || // LLGT
(Instructions[i + 2] == 0x18) || // LIDT
(Instructions[i + 2] == 0x30))) || // LMSW
(Instructions[i + 1] == 0x08) || // INVD
(Instructions[i + 1] == 0x09) || // WBINVD
(Instructions[i + 1] == 0x35) || // SYSEXIT
(Instructions[i + 1] == 0x26) || // MOV DR, XXX
(Instructions[i + 1] == 0x06) || // CLTS
(Instructions[i + 1] == 0x20) || // MOV CR, XXX
(Instructions[i + 1] == 0x24) || // MOV YYY, DR
(Instructions[i + 1] == 0x30) || // WRMSR
(Instructions[i + 1] == 0x33)) // RDPMC
{
/* These are all privileged */
Privileged = TRUE;
}
}
else
{
/* Get the IOPL and compare with the RPL mask */
Iopl = (TrapFrame->EFlags & EFLAGS_IOPL) >> 12;
if ((TrapFrame->SegCs & RPL_MASK) == Iopl)
{
/* I/O privilege error -- check for known instructions */
if ((Instruction == 0xFA) || (Instruction == 0xFB)) // CLI or STI
{
/* These are privileged */
Privileged = TRUE;
}
else
{
/* Last hope: an IN/OUT instruction */
for (j = 0; j < sizeof(KiTrapIoTable); j++)
{
/* Is this an I/O instruction? */
if (Instruction == KiTrapIoTable[j])
{
/* Then it's privileged */
Privileged = TRUE;
break;
}
}
}
}
}
/* So now... was the instruction privileged or not? */
if (Privileged)
{
/* Whew! We have a privileged instruction, so dispatch the fault */
KiDispatchException0Args(STATUS_PRIVILEGED_INSTRUCTION,
TrapFrame->Eip,
TrapFrame);
}
}
/* If we got here, send an access violation */
KiDispatchException2Args(STATUS_ACCESS_VIOLATION,
TrapFrame->Eip,
0,
0xFFFFFFFF,
TrapFrame);
}
/* Check for custom VDM trap handler */
if (KeGetPcr()->VdmAlert)
{
/* Not implemented */
UNIMPLEMENTED;
while (TRUE);
}
/*
* Check for a fault during checking of the user instruction.
*
* Note that the SEH handler will catch invalid EIP, but we could be dealing
* with an invalid CS, which will generate another GPF instead.
*
*/
if (((PVOID)TrapFrame->Eip >= (PVOID)KiTrap13Handler) &&
((PVOID)TrapFrame->Eip < (PVOID)KiTrap13Handler))
{
/* Not implemented */
UNIMPLEMENTED;
while (TRUE);
}
/*
* NOTE: The ASM trap exit code would restore segment registers by doing
* a POP <SEG>, which could cause an invalid segment if someone had messed
* with the segment values.
*
* Another case is a bogus SS, which would hit a GPF when doing the ired.
* This could only be done through a buggy or malicious driver, or perhaps
* the kernel debugger.
*
* The kernel normally restores the "true" segment if this happens.
*
* However, since we're restoring in C, not ASM, we can't detect
* POP <SEG> since the actual instructions will be different.
*
* A better technique would be to check the EIP and somehow edit the
* trap frame before restarting the instruction -- but we would need to
* know the extract instruction that was used first.
*
* We could force a special instrinsic to use stack instructions, or write
* a simple instruction length checker.
*
* Nevertheless, this is a lot of work for the purpose of avoiding a crash
* when the user is purposedly trying to create one from kernel-mode, so
* we should probably table this for now since it's not a "real" issue.
*/
/*
* NOTE2: Another scenario is the IRET during a V8086 restore (BIOS Call)
* which will cause a GPF since the trap frame is a total mess (on purpose)
* as built in KiEnterV86Mode.
*
* The idea is to scan for IRET, scan for the known EIP adress, validate CS
* and then manually issue a jump to the V8086 return EIP.
*/
Instructions = (PUCHAR)TrapFrame->Eip;
if (Instructions[0] == 0xCF)
{
/*
* Some evil shit is going on here -- this is not the SS:ESP you're
* looking for! Instead, this is actually CS:EIP you're looking at!
* Why? Because part of the trap frame actually corresponds to the IRET
* stack during the trap exit!
*/
if ((TrapFrame->HardwareEsp == (ULONG)KiExitV86Mode) &&
(TrapFrame->HardwareSegSs == (KGDT_R0_CODE | RPL_MASK)))
{
/* Exit the V86 trap! */
KiExitV86Mode(TrapFrame);
}
else
{
/* Otherwise, this is another kind of IRET fault */
UNIMPLEMENTED;
while (TRUE);
}
}
/* So since we're not dealing with the above case, check for RDMSR/WRMSR */
if ((Instructions[0] == 0xF) && // 2-byte opcode
(((Instructions[1] >> 8) == 0x30) || // RDMSR
((Instructions[2] >> 8) == 0x32))) // WRMSR
{
/* Unknown CPU MSR, so raise an access violation */
KiDispatchException0Args(STATUS_ACCESS_VIOLATION,
TrapFrame->Eip,
TrapFrame);
}
/* Check for lazy segment load */
if (TrapFrame->SegDs != (KGDT_R3_DATA | RPL_MASK))
{
/* Fix it */
TrapFrame->SegDs = (KGDT_R3_DATA | RPL_MASK);
}
else if (TrapFrame->SegEs != (KGDT_R3_DATA | RPL_MASK))
{
/* Fix it */
TrapFrame->SegEs = (KGDT_R3_DATA | RPL_MASK);
}
/* Do a direct trap exit: restore volatiles only */
KiExitTrap(TrapFrame, KTE_SKIP_PM_BIT | KTE_SKIP_SEG_BIT);
}
VOID
FASTCALL
KiTrap14Handler(IN PKTRAP_FRAME TrapFrame)

View file

@ -1,37 +0,0 @@
/*
* FILE: ntoskrnl/ke/i386/v86m_sup.S
* COPYRIGHT: See COPYING in the top level directory
* PURPOSE: Virtual 8086 (V86) Mode Support
* PROGRAMMER: Alex Ionescu (alex@relsoft.net)
* NOTE: See asmmacro.S for the V86 trap code.
*/
/* INCLUDES ******************************************************************/
#include <asm.h>
#include <internal/i386/asmmacro.S>
.intel_syntax noprefix
/* FUNCTIONS *****************************************************************/
.globl _Ki386SetupAndExitToV86Mode@4
.func Ki386SetupAndExitToV86Mode@4
_Ki386SetupAndExitToV86Mode@4:
/* Enter V8086 mode */
pushad
call @KiEnterV86Mode@0
.endfunc
.globl _Ki386BiosCallReturnAddress
.func Ki386BiosCallReturnAddress
_Ki386BiosCallReturnAddress:
/* Exit V8086 mode */
mov ecx, ebp
call @KiExitV86Mode@4
mov esp, eax
popad
.endfunc

View file

@ -429,7 +429,7 @@ Ki386HandleOpcodeV86(IN PKTRAP_FRAME TrapFrame)
return KiVdmHandleOpcode(TrapFrame, 1);
}
ULONG_PTR
VOID
FASTCALL
KiExitV86Mode(IN PKTRAP_FRAME TrapFrame)
{
@ -466,9 +466,9 @@ KiExitV86Mode(IN PKTRAP_FRAME TrapFrame)
GdtEntry->HighWord.Bytes.BaseMid = (UCHAR)((ULONG_PTR)Thread->Teb >> 16);
GdtEntry->HighWord.Bytes.BaseHi = (UCHAR)((ULONG_PTR)Thread->Teb >> 24);
/* Enable interrupts and pop back non-volatiles */
/* Enable interrupts and get back to protected mode */
_enable();
return TrapFrame->Edi;
KiV86TrapReturn(TrapFrame->Edi);
}
VOID
@ -497,7 +497,7 @@ KiEnterV86Mode(VOID)
V86Frame->PcrTeb = KeGetPcr()->Tib.Self;
/* Save return EIP */
TrapFrame->Eip = (ULONG_PTR)Ki386BiosCallReturnAddress;
TrapFrame->Eip = (ULONG_PTR)KiExitV86Mode;
/* Save our stack (after the frames) */
TrapFrame->Esi = (ULONG_PTR)V86Frame;

View file

@ -55,7 +55,6 @@
<file>usercall_asm.S</file>
<file>usercall.c</file>
<file>v86vdm.c</file>
<file>v86m_sup.S</file>
</directory>
</if>
<if property="ARCH" value="arm">