;++ ;Module Name ; imca.asm ; ;Abstract: ; Assembly support needed for Intel MCA ; ; Author: ; Anil Aggarwal (Intel Corp) ; ;Revision History: ; ; ;-- .586p .xlist include hal386.inc include callconv.inc include i386\kimacro.inc .list EXTRNP _HalpMcaExceptionHandler,0 EXTRNP _KeBugCheckEx,5,IMPORT ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; DATA Segment ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; _DATA SEGMENT PARA PUBLIC 'DATA' ; ; MCA Exception task stack ; MINIMUM_TSS_SIZE EQU TssIoMaps if DBG ; ; If we use DbgPrint, we need a larger stack ; MCA_EXCEPTION_STACK_SIZE EQU 01000H else MCA_EXCEPTION_STACK_SIZE EQU 0100H endif KGDT_MCA_TSS EQU 0A0H ; ; TSS for MCA Exception ; align 16 public _HalpMcaExceptionTSS _HalpMcaExceptionTSS label byte db MINIMUM_TSS_SIZE dup(0) ; ; Stack for MCA exception task ; public _HalpMcaExceptionStack db MCA_EXCEPTION_STACK_SIZE dup ("*") _HalpMcaExceptionStack label byte _DATA ends ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; TEXT Segment ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; _TEXT SEGMENT PARA PUBLIC 'CODE' ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; .586p ;++ ;ULONGLONG ;FASTCALL ;RDMSR( ; IN ULONG MsrAddress ; ) ; Routine Description: ; This function reads an MSR ; ; Arguments: ; Msr: The address of MSR to be read ; ; Return Value: ; Returns the low 32 bit of MSR in eax and high 32 bits of MSR in edx ; ;-- cPublicFastCall RDMSR,1 rdmsr fstRET RDMSR fstENDP RDMSR ;++ ; ;VOID ;WRMSR( ; IN ULONG MsrAddress, ; IN ULONGLONG MsrValue ; ) ; Routine Description: ; This function writes an MSR ; ; Arguments: ; Msr: The address of MSR to be written ; Data: The value to be written to the MSR register ; ; Return Value: ; None ; ;-- cPublicProc _WRMSR,3 mov ecx, [esp + 4] ; MsrAddress mov eax, [esp + 8] ; Low 32 bits of MsrValue mov edx, [esp + 12] ; High 32 bits of MsrValue wrmsr stdRET _WRMSR stdENDP _WRMSR ;++ ; ;VOID ;HalpSerialize( ; VOID ; ) ; ; Routine Description: ; This function implements the fence operation for out-of-order execution ; ; Arguments: ; None ; ; Return Value: ; None ; ;-- cPublicProc _HalpSerialize,0 push ebx xor eax, eax cpuid pop ebx stdRET _HalpSerialize stdENDP _HalpSerialize ;++ ; ; Routine Description: ; ; Machine Check exception handler ; ; ; Arguments: ; ; Return value: ; ; If the error is non-restartable, we will bugcheck. ; Otherwise, we just return ; ;-- ASSUME DS:NOTHING, SS:NOTHING, ES:NOTHING align dword public _HalpMcaExceptionHandlerWrapper _HalpMcaExceptionHandlerWrapper proc .FPO (0, 0, 0, 0, 0, 2) cli ; ; Update the TSS pointer in the PCR to point to the MCA TSS ; (which is what we're running on, or else we wouldn't be here) ; push dword ptr PCR[PcTss] mov eax, PCR[PcGdt] mov ch, [eax+KGDT_MCA_TSS+KgdtBaseHi] mov cl, [eax+KGDT_MCA_TSS+KgdtBaseMid] shl ecx, 16 mov cx, [eax+KGDT_MCA_TSS+KgdtBaseLow] mov PCR[PcTss], ecx ; ; Clear the busy bit in the TSS selector ; mov ecx, PCR[PcGdt] lea eax, [ecx] + KGDT_MCA_TSS mov byte ptr [eax+5], 089h ; 32bit, dpl=0, present, TSS32, not busy ; ; Clear Nested Task bit in EFLAGS ; pushfd and [esp], not 04000h popfd ; ; Check if there is a bugcheck-able error. If need to bugcheck, the ; caller does it. ; stdCall _HalpMcaExceptionHandler ; ; We're back which means that the error was restartable. ; pop dword ptr PCR[PcTss] ; restore PcTss mov ecx, PCR[PcGdt] lea eax, [ecx] + KGDT_TSS mov byte ptr [eax+5], 08bh ; 32bit, dpl=0, present, TSS32, *busy* pushfd ; Set Nested Task bit in EFLAGS or [esp], 04000h ; so iretd will do a tast switch popfd iretd ; Return from MCA Exception handler jmp short _HalpMcaExceptionHandlerWrapper ; For next Machine check exception _HalpMcaExceptionHandlerWrapper endp ;++ ; ; Routine Description: ; ; MCA exception is run off a small stack pointed to by MCA TSS. When ; the error is non-restartable, this routine is called to switch to a larger ; stack which is the overlay of ZW thunks (as is done for double fault stack) ; ; Arguments: ; ; The arguments to KeMachineCheck are passed to this function ; ; Return value: ; ; Never returns. End up doing the bugcheck. ; ;-- cPublicProc _HalpMcaSwitchMcaExceptionStackAndBugCheck,5 ; Get Task gate descriptor for double fault handler mov ecx, PCR[PcIdt] ; Get IDT address lea eax, [ecx] + 040h ; DF Exception is 8 ; Get to TSS Descriptor of double fault handler TSS xor ecx, ecx mov cx, word ptr [eax+2] add ecx, PCR[PcGdt] ; Get the address of TSS from this TSS Descriptor mov ah, [ecx+KgdtBaseHi] mov al, [ecx+KgdtBaseMid] shl eax, 16 mov ax, [ecx+KgdtBaseLow] ; Get ESP from DF TSS mov ecx, [eax+038h] ; Save the passed arguments before we switch the stacks mov eax, [esp+4] mov ebx, [esp+8] mov edx, [esp+12] mov esi, [esp+16] mov edi, [esp+20] ; Use the ZW thunk area for the stack to operate on for crash mov esp, ecx stdCall _KeBugCheckEx, stdRET _HalpMcaSwitchMcaExceptionStackAndBugCheck stdENDP _HalpMcaSwitchMcaExceptionStackAndBugCheck _TEXT ends INIT SEGMENT DWORD PUBLIC 'CODE' ;++ ;VOID ;HalpMcaCurrentProcessorSetTSS( ; VOID ; ) ; Routine Description: ; This function sets up the TSS for MCA exception 18 ; ; Arguments: ; Context: We don't care about this but is there since HalpGenericCall ; needs one ; ; Return Value: ; None ; ;-- cPublicProc _HalpMcaCurrentProcessorSetTSS,0 ; ; Edit IDT Entry for MCA Exception (18) to contain a task gate ; mov ecx, PCR[PcIdt] ; Get IDT address lea eax, [ecx] + 090h ; MCA Exception is 18 mov byte ptr [eax + 5], 085h ; P=1,DPL=0,Type=5 mov word ptr [eax + 2], KGDT_MCA_TSS ; TSS Segment Selector mov edx, offset FLAT:_HalpMcaExceptionTSS ; the address of TSS in edx ; ; Set various fields in TSS ; mov eax, cr3 mov [edx + TssCR3], eax mov eax, offset FLAT:_HalpMcaExceptionStack; address of MCA Exception stack mov dword ptr [edx+038h], eax ; Set ESP mov dword ptr [edx+TssEsp0], eax ; Set ESP0 mov dword ptr [edx+020h], offset FLAT:_HalpMcaExceptionHandlerWrapper ; set EIP mov dword ptr [edx+024h], 0 ; set EFLAGS mov word ptr [edx+04ch],KGDT_R0_CODE ; set value for CS mov word ptr [edx+058h],KGDT_R0_PCR ; set value for FS mov [edx+050h], ss mov word ptr [edx+048h],KGDT_R3_DATA OR RPL_MASK ; Es mov word ptr [edx+054h],KGDT_R3_DATA OR RPL_MASK ; Ds ; ; Part that gets done in KiInitialiazeTSS() ; mov word ptr [edx + 08], KGDT_R0_DATA ; Set SS0 mov word ptr [edx + 060h],0 ; Set LDT mov word ptr [edx + 064h],0 ; Set T bit mov word ptr [edx + 066h],020adh ; I/O Map base address = sizeof(KTSS)+1 ; ; Edit GDT entry for KGDT_MCA_TSS to create a valid TSS Descriptor ; mov ecx, PCR[PcGdt] ; Get GDT address lea eax, [ecx] + KGDT_MCA_TSS ; offset of MCA TSS in GDT mov ecx, eax ; ; Set Type field of TSS Descriptor ; mov byte ptr [ecx + 5], 089H ; P=1, DPL=0, Type = 9 ; ; Set Base Address field of TSS Descriptor ; mov eax, edx ; TSS address in eax mov [ecx + KgdtBaseLow], ax shr eax, 16 mov [ecx + KgdtBaseHi],ah mov [ecx + KgdtBaseMid],al ; ; Set Segment limit for TSS Descriptor ; mov eax, MINIMUM_TSS_SIZE mov [ecx + KgdtLimitLow],ax stdRET _HalpMcaCurrentProcessorSetTSS stdENDP _HalpMcaCurrentProcessorSetTSS ;++ ; ;VOID ;HalpSetCr4MCEBit( ; VOID ; ) ; ; Routine Description: ; This function sets the CR4.MCE bit ; ; Arguments: ; None ; ; Return Value: ; None ; ;-- cPublicProc _HalpSetCr4MCEBit,0 mov eax, cr4 or eax, CR4_MCE mov cr4, eax stdRET _HalpSetCr4MCEBit stdENDP _HalpSetCr4MCEBit INIT ends end