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