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