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