;++ ;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 KGDT_MCA_TSS EQU 0A0H MINIMUM_TSS_SIZE EQU TssIoMaps ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; TEXT Segment ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; _TEXT SEGMENT PARA PUBLIC 'CODE' ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; .586p ;++ ; ;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 ; ; Set CR3, the I/O map base address, and LDT segment selector ; in the old TSS since they are not set on context ; switches. These values will be needed to return to the ; interrupted task. mov eax, PCR[PcTss] ; get old TSS address mov ecx, PCR[PcPrcbData+PbCurrentThread] ; get thread address mov edi, [ecx].ThApcState.AsProcess ; get process address mov ecx, [edi]+PrDirectoryTableBase ; get directory base mov [eax]+TssCR3, ecx ; set previous cr3 mov cx, [edi]+PrIopmOffset ; get IOPM offset mov [eax]+TssIoMapBase, cx ; set IOPM offset mov ecx, [edi]+PrLdtDescriptor ; get LDT descriptor test ecx, ecx ; does task use LDT? jz @f mov cx, KGDT_LDT @@: mov [eax]+TssLDT, cx ; set LDT into old TSS ; ; 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 Nested Task bit in EFLAGS ; pushfd and [esp], not 04000h popfd ; ; 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 ; ; 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 _HalpMcaExceptionHandlerWrapper ; For next Machine check exception _HalpMcaExceptionHandlerWrapper endp _TEXT ends INIT SEGMENT DWORD PUBLIC 'CODE' ;++ ;VOID ;HalpMcaCurrentProcessorSetTSS( ; IN PULONG pTSS // MCE TSS area for this processor ; ) ; Routine Description: ; This function sets up the TSS for MCA exception 18 ; ; Arguments: ; pTSS : Pointer to the TSS to be used for MCE ; ; Return Value: ; None ; ;-- cPublicProc _HalpMcaCurrentProcessorSetTSS,1 ; ; 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, [esp+4] ; the address of TSS in edx ; ; Set various fields in TSS ; mov eax, cr3 mov [edx + TssCR3], eax ; ; Get double fault stack 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] ; ; Set address of MCA Exception stack to double fault stack address ; mov dword ptr [edx+038h], ecx ; Set ESP mov dword ptr [edx+TssEsp0], ecx ; 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 INIT ends PAGELK SEGMENT DWORD PUBLIC 'CODE' ;++ ; ;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 PAGELK ends end