1;/** @file
2;  Low leve IA32 specific debug support functions.
3;
4;  Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
5;  This program and the accompanying materials
6;  are licensed and made available under the terms and conditions of the BSD License
7;  which accompanies this distribution.  The full text of the license may be found at
8;  http://opensource.org/licenses/bsd-license.php
9;
10;  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11;  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12;
13;**/
14
15.586p
16.MODEL          FLAT, C
17
18EXCPT32_DIVIDE_ERROR     EQU    0
19EXCPT32_DEBUG            EQU    1
20EXCPT32_NMI              EQU    2
21EXCPT32_BREAKPOINT       EQU    3
22EXCPT32_OVERFLOW         EQU    4
23EXCPT32_BOUND            EQU    5
24EXCPT32_INVALID_OPCODE   EQU    6
25EXCPT32_DOUBLE_FAULT     EQU    8
26EXCPT32_INVALID_TSS      EQU   10
27EXCPT32_SEG_NOT_PRESENT  EQU   11
28EXCPT32_STACK_FAULT      EQU   12
29EXCPT32_GP_FAULT         EQU   13
30EXCPT32_PAGE_FAULT       EQU   14
31EXCPT32_FP_ERROR         EQU   16
32EXCPT32_ALIGNMENT_CHECK  EQU   17
33EXCPT32_MACHINE_CHECK    EQU   18
34EXCPT32_SIMD             EQU   19
35
36FXSTOR_FLAG              EQU   01000000h         ; bit cpuid 24 of feature flags
37
38;; The FXSTOR and FXRSTOR commands are used for saving and restoring the x87,
39;; MMX, SSE, SSE2, etc registers.  The initialization of the debugsupport driver
40;; MUST check the CPUID feature flags to see that these instructions are available
41;; and fail to init if they are not.
42
43;; fxstor [edi]
44FXSTOR_EDI               MACRO
45                         db 0fh, 0aeh, 00000111y ; mod = 00, reg/op = 000, r/m = 111 = [edi]
46ENDM
47
48;; fxrstor [esi]
49FXRSTOR_ESI              MACRO
50                         db 0fh, 0aeh, 00001110y ; mod = 00, reg/op = 001, r/m = 110 = [esi]
51ENDM
52.DATA
53
54public          OrigVector, InterruptEntryStub, StubSize, CommonIdtEntry, FxStorSupport
55
56StubSize        dd      InterruptEntryStubEnd - InterruptEntryStub
57AppEsp          dd      11111111h ; ?
58DebugEsp        dd      22222222h ; ?
59ExtraPush       dd      33333333h ; ?
60ExceptData      dd      44444444h ; ?
61Eflags          dd      55555555h ; ?
62OrigVector      dd      66666666h ; ?
63
64;; The declarations below define the memory region that will be used for the debug stack.
65;; The context record will be built by pushing register values onto this stack.
66;; It is imparitive that alignment be carefully managed, since the FXSTOR and
67;; FXRSTOR instructions will GP fault if their memory operand is not 16 byte aligned.
68;;
69;; The stub will switch stacks from the application stack to the debuger stack
70;; and pushes the exception number.
71;;
72;; Then we building the context record on the stack. Since the stack grows down,
73;; we push the fields of the context record from the back to the front.  There
74;; are 132 bytes of stack used prior allocating the 512 bytes of stack to be
75;; used as the memory buffer for the fxstor instruction. Therefore address of
76;; the buffer used for the FXSTOR instruction is &Eax - 132 - 512, which
77;; must be 16 byte aligned.
78;;
79;; We carefully locate the stack to make this happen.
80;;
81;; For reference, the context structure looks like this:
82;;      struct {
83;;        UINT32             ExceptionData;
84;;        FX_SAVE_STATE_IA32 FxSaveState;    // 512 bytes, must be 16 byte aligned
85;;        UINT32             Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
86;;        UINT32             Cr0, Cr1, Cr2, Cr3, Cr4;
87;;        UINT32             EFlags;
88;;        UINT32             Ldtr, Tr;
89;;        UINT32             Gdtr[2], Idtr[2];
90;;        UINT32             Eip;
91;;        UINT32             Gs, Fs, Es, Ds, Cs, Ss;
92;;        UINT32             Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
93;;      } SYSTEM_CONTEXT_IA32;  // 32 bit system context record
94
95
96align           16
97DebugStackEnd   db      "DbgStkEnd >>>>>>"      ;; 16 byte long string - must be 16 bytes to preserve alignment
98                dd      1ffdh dup (000000000h)  ;; 32K should be enough stack
99                                                ;;   This allocation is coocked to insure
100                                                ;;   that the the buffer for the FXSTORE instruction
101                                                ;;   will be 16 byte aligned also.
102                                                ;;
103ExceptionNumber dd      ?                       ;; first entry will be the vector number pushed by the stub
104
105DebugStackBegin db      "<<<< DbgStkBegin"      ;; initial debug ESP == DebugStackBegin, set in stub
106
107.CODE
108
109externdef InterruptDistrubutionHub:near
110
111;------------------------------------------------------------------------------
112; BOOLEAN
113; FxStorSupport (
114;   void
115;   )
116;
117; Abstract: Returns TRUE if FxStor instructions are supported
118;
119FxStorSupport   PROC    C PUBLIC
120
121;
122; cpuid corrupts ebx which must be preserved per the C calling convention
123;
124                push    ebx
125                mov     eax, 1
126                cpuid
127                mov     eax, edx
128                and     eax, FXSTOR_FLAG
129                shr     eax, 24
130                pop     ebx
131                ret
132FxStorSupport   ENDP
133
134
135
136;------------------------------------------------------------------------------
137; void
138; Vect2Desc (
139;   DESCRIPTOR * DestDesc,
140;   void (*Vector) (void)
141;   )
142;
143; Abstract: Encodes an IDT descriptor with the given physical address
144;
145Vect2Desc       PROC    C PUBLIC DestPtr:DWORD, Vector:DWORD
146
147                mov     eax, Vector
148                mov     ecx, DestPtr
149                mov     word ptr [ecx], ax                  ; write bits 15..0 of offset
150                mov     dx, cs
151                mov     word ptr [ecx+2], dx                ; SYS_CODE_SEL from GDT
152                mov     word ptr [ecx+4], 0e00h OR 8000h    ; type = 386 interrupt gate, present
153                shr     eax, 16
154                mov     word ptr [ecx+6], ax                ; write bits 31..16 of offset
155
156                ret
157
158Vect2Desc       ENDP
159
160
161
162;------------------------------------------------------------------------------
163; InterruptEntryStub
164;
165; Abstract: This code is not a function, but is a small piece of code that is
166;               copied and fixed up once for each IDT entry that is hooked.
167;
168InterruptEntryStub::
169                mov     AppEsp, esp                  ; save stack top
170                mov     esp, offset DebugStackBegin  ; switch to debugger stack
171                push    0                            ; push vector number - will be modified before installed
172                db      0e9h                         ; jump rel32
173                dd      0                            ; fixed up to relative address of CommonIdtEntry
174InterruptEntryStubEnd:
175
176
177
178;------------------------------------------------------------------------------
179; CommonIdtEntry
180;
181; Abstract: This code is not a function, but is the common part for all IDT
182;               vectors.
183;
184CommonIdtEntry::
185;;
186;; At this point, the stub has saved the current application stack esp into AppEsp
187;; and switched stacks to the debug stack, where it pushed the vector number
188;;
189;; The application stack looks like this:
190;;
191;;              ...
192;;              (last application stack entry)
193;;              eflags from interrupted task
194;;              CS from interrupted task
195;;              EIP from interrupted task
196;;              Error code <-------------------- Only present for some exeption types
197;;
198;;
199
200
201;; The stub switched us to the debug stack and pushed the interrupt number.
202;;
203;; Next, construct the context record.  It will be build on the debug stack by
204;; pushing the registers in the correct order so as to create the context structure
205;; on the debug stack.  The context record must be built from the end back to the
206;; beginning because the stack grows down...
207;
208;; For reference, the context record looks like this:
209;;
210;; typedef
211;; struct {
212;;   UINT32             ExceptionData;
213;;   FX_SAVE_STATE_IA32 FxSaveState;
214;;   UINT32             Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
215;;   UINT32             Cr0, Cr2, Cr3, Cr4;
216;;   UINT32             EFlags;
217;;   UINT32             Ldtr, Tr;
218;;   UINT32             Gdtr[2], Idtr[2];
219;;   UINT32             Eip;
220;;   UINT32             Gs, Fs, Es, Ds, Cs, Ss;
221;;   UINT32             Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
222;; } SYSTEM_CONTEXT_IA32;  // 32 bit system context record
223
224;; UINT32  Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
225                pushad
226
227;; Save interrupt state eflags register...
228                pushfd
229                pop     eax
230                mov     dword ptr Eflags, eax
231
232;; We need to determine if any extra data was pushed by the exception, and if so, save it
233;; To do this, we check the exception number pushed by the stub, and cache the
234;; result in a variable since we'll need this again.
235                .IF     ExceptionNumber == EXCPT32_DOUBLE_FAULT
236                mov     ExtraPush, 1
237                .ELSEIF ExceptionNumber == EXCPT32_INVALID_TSS
238                mov     ExtraPush, 1
239                .ELSEIF ExceptionNumber == EXCPT32_SEG_NOT_PRESENT
240                mov     ExtraPush, 1
241                .ELSEIF ExceptionNumber == EXCPT32_STACK_FAULT
242                mov     ExtraPush, 1
243                .ELSEIF ExceptionNumber == EXCPT32_GP_FAULT
244                mov     ExtraPush, 1
245                .ELSEIF ExceptionNumber == EXCPT32_PAGE_FAULT
246                mov     ExtraPush, 1
247                .ELSEIF ExceptionNumber == EXCPT32_ALIGNMENT_CHECK
248                mov     ExtraPush, 1
249                .ELSE
250                mov     ExtraPush, 0
251                .ENDIF
252
253;; If there's some extra data, save it also, and modify the saved AppEsp to effectively
254;; pop this value off the application's stack.
255                .IF     ExtraPush == 1
256                mov     eax, AppEsp
257                mov     ebx, [eax]
258                mov     ExceptData, ebx
259                add     eax, 4
260                mov     AppEsp, eax
261                .ELSE
262                mov     ExceptData, 0
263                .ENDIF
264
265;; The "pushad" above pushed the debug stack esp.  Since what we're actually doing
266;; is building the context record on the debug stack, we need to save the pushed
267;; debug ESP, and replace it with the application's last stack entry...
268                mov     eax, [esp + 12]
269                mov     DebugEsp, eax
270                mov     eax, AppEsp
271                add     eax, 12
272                ; application stack has eflags, cs, & eip, so
273                ; last actual application stack entry is
274                ; 12 bytes into the application stack.
275                mov     [esp + 12], eax
276
277;; continue building context record
278;; UINT32  Gs, Fs, Es, Ds, Cs, Ss;  insure high 16 bits of each is zero
279                mov     eax, ss
280                push    eax
281
282                ; CS from application is one entry back in application stack
283                mov     eax, AppEsp
284                movzx   eax, word ptr [eax + 4]
285                push    eax
286
287                mov     eax, ds
288                push    eax
289                mov     eax, es
290                push    eax
291                mov     eax, fs
292                push    eax
293                mov     eax, gs
294                push    eax
295
296;; UINT32  Eip;
297                ; Eip from application is on top of application stack
298                mov     eax, AppEsp
299                push    dword ptr [eax]
300
301;; UINT32  Gdtr[2], Idtr[2];
302                push    0
303                push    0
304                sidt    fword ptr [esp]
305                push    0
306                push    0
307                sgdt    fword ptr [esp]
308
309;; UINT32  Ldtr, Tr;
310                xor     eax, eax
311                str     ax
312                push    eax
313                sldt    ax
314                push    eax
315
316;; UINT32  EFlags;
317;; Eflags from application is two entries back in application stack
318                mov     eax, AppEsp
319                push    dword ptr [eax + 8]
320
321;; UINT32  Cr0, Cr1, Cr2, Cr3, Cr4;
322;; insure FXSAVE/FXRSTOR is enabled in CR4...
323;; ... while we're at it, make sure DE is also enabled...
324                mov     eax, cr4
325                or      eax, 208h
326                mov     cr4, eax
327                push    eax
328                mov     eax, cr3
329                push    eax
330                mov     eax, cr2
331                push    eax
332                push    0
333                mov     eax, cr0
334                push    eax
335
336;; UINT32  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
337                mov     eax, dr7
338                push    eax
339;; clear Dr7 while executing debugger itself
340                xor     eax, eax
341                mov     dr7, eax
342
343                mov     eax, dr6
344                push    eax
345;; insure all status bits in dr6 are clear...
346                xor     eax, eax
347                mov     dr6, eax
348
349                mov     eax, dr3
350                push    eax
351                mov     eax, dr2
352                push    eax
353                mov     eax, dr1
354                push    eax
355                mov     eax, dr0
356                push    eax
357
358;; FX_SAVE_STATE_IA32 FxSaveState;
359                sub     esp, 512
360                mov     edi, esp
361                ; IMPORTANT!! The debug stack has been carefully constructed to
362                ; insure that esp and edi are 16 byte aligned when we get here.
363                ; They MUST be.  If they are not, a GP fault will occur.
364                FXSTOR_EDI
365
366;; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
367                cld
368
369;; UINT32  ExceptionData;
370                mov     eax, ExceptData
371                push    eax
372
373; call to C code which will in turn call registered handler
374; pass in the vector number
375                mov     eax, esp
376                push    eax
377                mov     eax, ExceptionNumber
378                push    eax
379                call    InterruptDistrubutionHub
380                add     esp, 8
381
382; restore context...
383;; UINT32  ExceptionData;
384                add     esp, 4
385
386;; FX_SAVE_STATE_IA32 FxSaveState;
387                mov     esi, esp
388                FXRSTOR_ESI
389                add     esp, 512
390
391;; UINT32  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
392                pop     eax
393                mov     dr0, eax
394                pop     eax
395                mov     dr1, eax
396                pop     eax
397                mov     dr2, eax
398                pop     eax
399                mov     dr3, eax
400;; skip restore of dr6.  We cleared dr6 during the context save.
401                add     esp, 4
402                pop     eax
403                mov     dr7, eax
404
405;; UINT32  Cr0, Cr1, Cr2, Cr3, Cr4;
406                pop     eax
407                mov     cr0, eax
408                add     esp, 4
409                pop     eax
410                mov     cr2, eax
411                pop     eax
412                mov     cr3, eax
413                pop     eax
414                mov     cr4, eax
415
416;; UINT32  EFlags;
417                mov     eax, AppEsp
418                pop     dword ptr [eax + 8]
419
420;; UINT32  Ldtr, Tr;
421;; UINT32  Gdtr[2], Idtr[2];
422;; Best not let anyone mess with these particular registers...
423                add     esp, 24
424
425;; UINT32  Eip;
426                pop     dword ptr [eax]
427
428;; UINT32  SegGs, SegFs, SegEs, SegDs, SegCs, SegSs;
429;; NOTE - modified segment registers could hang the debugger...  We
430;;        could attempt to insulate ourselves against this possibility,
431;;        but that poses risks as well.
432;;
433
434                pop     gs
435                pop     fs
436                pop     es
437                pop     ds
438                pop     [eax + 4]
439                pop     ss
440
441;; The next stuff to restore is the general purpose registers that were pushed
442;; using the "pushad" instruction.
443;;
444;; The value of ESP as stored in the context record is the application ESP
445;; including the 3 entries on the application stack caused by the exception
446;; itself. It may have been modified by the debug agent, so we need to
447;; determine if we need to relocate the application stack.
448
449                mov     ebx, [esp + 12]  ; move the potentially modified AppEsp into ebx
450                mov     eax, AppEsp
451                add     eax, 12
452                cmp     ebx, eax
453                je      NoAppStackMove
454
455                mov     eax, AppEsp
456                mov     ecx, [eax]       ; EIP
457                mov     [ebx], ecx
458
459                mov     ecx, [eax + 4]   ; CS
460                mov     [ebx + 4], ecx
461
462                mov     ecx, [eax + 8]   ; EFLAGS
463                mov     [ebx + 8], ecx
464
465                mov     eax, ebx         ; modify the saved AppEsp to the new AppEsp
466                mov     AppEsp, eax
467NoAppStackMove:
468                mov     eax, DebugEsp    ; restore the DebugEsp on the debug stack
469                                         ; so our "popad" will not cause a stack switch
470                mov     [esp + 12], eax
471
472                cmp     ExceptionNumber, 068h
473                jne     NoChain
474
475Chain:
476
477;; Restore eflags so when we chain, the flags will be exactly as if we were never here.
478;; We gin up the stack to do an iretd so we can get ALL the flags.
479                mov     eax, AppEsp
480                mov     ebx, [eax + 8]
481                and     ebx, NOT 300h ; special handling for IF and TF
482                push    ebx
483                push    cs
484                push    PhonyIretd
485                iretd
486PhonyIretd:
487
488;; UINT32  Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
489                popad
490
491;; Switch back to application stack
492                mov     esp, AppEsp
493
494;; Jump to original handler
495                jmp     OrigVector
496
497NoChain:
498;; UINT32  Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
499                popad
500
501;; Switch back to application stack
502                mov     esp, AppEsp
503
504;; We're outa here...
505                iretd
506END
507
508
509
510