summaryrefslogblamecommitdiffstats
path: root/private/ntos/nthals/halx86/i386/ixmcaa.asm
blob: 2296218924891308d14338e5cc335ae5ce911b6d (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420



































































































































































































































































































































































































































                                                                                           
;++
;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, <eax, ebx, edx, esi, edi>

        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