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