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