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