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