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