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