]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/DebugSupportDxe/Ia32/AsmFuncs.nasm
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Universal / DebugSupportDxe / Ia32 / AsmFuncs.nasm
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
43 SECTION .data
44
45 global ASM_PFX(OrigVector)
46 global ASM_PFX(InterruptEntryStub)
47 global ASM_PFX(StubSize)
48 global ASM_PFX(CommonIdtEntry)
49 global ASM_PFX(FxStorSupport)
50 extern ASM_PFX(InterruptDistrubutionHub)
51
52 ASM_PFX(StubSize): dd InterruptEntryStubEnd - ASM_PFX(InterruptEntryStub)
53 AppEsp: dd 0x11111111 ; ?
54 DebugEsp: dd 0x22222222 ; ?
55 ExtraPush: dd 0x33333333 ; ?
56 ExceptData: dd 0x44444444 ; ?
57 Eflags: dd 0x55555555 ; ?
58 ASM_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
91 align 16
92 DebugStackEnd: 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 ;;
98 ExceptionNumber: dd 0 ;; first entry will be the vector number pushed by the stub
99
100 DebugStackBegin: db "<<<< DbgStkBegin" ;; initial debug ESP == DebugStackBegin, set in stub
101
102 SECTION .text
103
104 ;------------------------------------------------------------------------------
105 ; BOOLEAN
106 ; FxStorSupport (
107 ; void
108 ; )
109 ;
110 ; Abstract: Returns TRUE if FxStor instructions are supported
111 ;
112 global ASM_PFX(FxStorSupport)
113 ASM_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 ;
136 global ASM_PFX(Vect2Desc)
137 ASM_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 ;
157 ASM_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
163 InterruptEntryStubEnd:
164
165 ;------------------------------------------------------------------------------
166 ; CommonIdtEntry
167 ;
168 ; Abstract: This code is not a function, but is the common part for all IDT
169 ; vectors.
170 ;
171 ASM_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
239 ExtraPushOne:
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
250 ExtraPushDone:
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
454 NoAppStackMove:
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
462 Chain:
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
473 PhonyIretd:
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
484 NoChain:
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