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