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