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 15ASM_GLOBAL ASM_PFX(OrigVector) 16ASM_GLOBAL ASM_PFX(InterruptEntryStub) 17ASM_GLOBAL ASM_PFX(StubSize) 18ASM_GLOBAL ASM_PFX(CommonIdtEntry) 19ASM_GLOBAL ASM_PFX(FxStorSupport) 20 21ASM_PFX(StubSize): .long ASM_PFX(InterruptEntryStubEnd) - ASM_PFX(InterruptEntryStub) 22ASM_PFX(AppEsp): .long 0x11111111 # ? 23ASM_PFX(DebugEsp): .long 0x22222222 # ? 24ASM_PFX(ExtraPush): .long 0x33333333 # ? 25ASM_PFX(ExceptData): .long 0x44444444 # ? 26ASM_PFX(Eflags): .long 0x55555555 # ? 27ASM_PFX(OrigVector): .long 0x66666666 # ? 28 29#------------------------------------------------------------------------------ 30# BOOLEAN 31# FxStorSupport ( 32# void 33# ) 34# 35# Abstract: Returns TRUE if FxStor instructions are supported 36# 37ASM_GLOBAL ASM_PFX(FxStorSupport) 38ASM_PFX(FxStorSupport): 39# 40# cpuid corrupts ebx which must be preserved per the C calling convention 41# 42 push %ebx 43 mov $0x1,%eax 44 cpuid 45 mov %edx,%eax 46 and $0x1000000,%eax 47 shr $0x18,%eax 48 pop %ebx 49 ret 50#------------------------------------------------------------------------------ 51# void 52# Vect2Desc ( 53# DESCRIPTOR * DestDesc, 54# void (*Vector) (void) 55# ) 56# 57# Abstract: Encodes an IDT descriptor with the given physical address 58# 59 60ASM_GLOBAL ASM_PFX(Vect2Desc) 61ASM_PFX(Vect2Desc): 62 push %ebp 63 mov %esp,%ebp 64 mov 0xc(%ebp),%eax 65 mov 0x8(%ebp),%ecx 66 mov %ax,(%ecx) 67 movw $0x20,0x2(%ecx) 68 movw $0x8e00,0x4(%ecx) 69 shr $0x10,%eax 70 mov %ax,0x6(%ecx) 71 leave 72 ret 73 74ASM_GLOBAL ASM_PFX(InterruptEntryStub) 75ASM_PFX(InterruptEntryStub): 76 mov %esp,0x0 # save stack top 77 mov $0x0,%esp # switch to debugger stack 78 push $0x0 # push vector number - will be modified before installed 79 jmp ASM_PFX(CommonIdtEntry) # jump CommonIdtEntry 80ASM_GLOBAL ASM_PFX(InterruptEntryStubEnd) 81ASM_PFX(InterruptEntryStubEnd): 82 83#------------------------------------------------------------------------------ 84# CommonIdtEntry 85# 86# Abstract: This code is not a function, but is the common part for all IDT 87# vectors. 88# 89ASM_GLOBAL ASM_PFX(CommonIdtEntry) 90ASM_PFX(CommonIdtEntry): 91## 92## At this point, the stub has saved the current application stack esp into AppEsp 93## and switched stacks to the debug stack, where it pushed the vector number 94## 95## The application stack looks like this: 96## 97## ... 98## (last application stack entry) 99## eflags from interrupted task 100## CS from interrupted task 101## EIP from interrupted task 102## Error code <-------------------- Only present for some exeption types 103## 104## 105 106 107## The stub switched us to the debug stack and pushed the interrupt number. 108## 109## Next, construct the context record. It will be build on the debug stack by 110## pushing the registers in the correct order so as to create the context structure 111## on the debug stack. The context record must be built from the end back to the 112## beginning because the stack grows down... 113# 114## For reference, the context record looks like this: 115## 116## typedef 117## struct { 118## UINT32 ExceptionData; 119## FX_SAVE_STATE_IA32 FxSaveState; 120## UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; 121## UINT32 Cr0, Cr2, Cr3, Cr4; 122## UINT32 EFlags; 123## UINT32 Ldtr, Tr; 124## UINT32 Gdtr[2], Idtr[2]; 125## UINT32 Eip; 126## UINT32 Gs, Fs, Es, Ds, Cs, Ss; 127## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; 128## } SYSTEM_CONTEXT_IA32; // 32 bit system context record 129 130## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; 131 pusha 132## Save interrupt state eflags register... 133 pushf 134 pop %eax 135## We need to determine if any extra data was pushed by the exception, and if so, save it 136## To do this, we check the exception number pushed by the stub, and cache the 137## result in a variable since we'll need this again. 138 mov %eax,0x0 139 cmpl $0x8,0x0 140 jne ASM_PFX(CommonIdtEntry+0x20) 141 movl $0x1,0x0 142 jmp ASM_PFX(CommonIdtEntry+0xa8) 143 cmpl $0xa,0x0 144 jne ASM_PFX(CommonIdtEntry+0x35) 145 movl $0x1,0x0 146 jmp ASM_PFX(CommonIdtEntry+0xa8) 147 cmpl $0xb,0x0 148 jne ASM_PFX(CommonIdtEntry+0x4a) 149 movl $0x1,0x0 150 jmp ASM_PFX(CommonIdtEntry+0xa8) 151 cmpl $0xc,0x0 152 jne ASM_PFX(CommonIdtEntry+0x5f) 153 movl $0x1,0x0 154 jmp ASM_PFX(CommonIdtEntry+0xa8) 155 cmpl $0xd,0x0 156 jne ASM_PFX(CommonIdtEntry+0x74) 157 movl $0x1,0x0 158 jmp ASM_PFX(CommonIdtEntry+0xa8) 159 cmpl $0xe,0x0 160 jne ASM_PFX(CommonIdtEntry+0x89) 161 movl $0x1,0x0 162 jmp ASM_PFX(CommonIdtEntry+0xa8) 163 cmpl $0x11,0x0 164 jne ASM_PFX(CommonIdtEntry+0x9e) 165 movl $0x1,0x0 166 jmp ASM_PFX(CommonIdtEntry+0xa8) 167 movl $0x0,0x0 168## If there's some extra data, save it also, and modify the saved AppEsp to effectively 169## pop this value off the application's stack. 170 171 cmpl $0x1,0x0 172 jne ASM_PFX(CommonIdtEntry+0xc8) 173 mov 0x0,%eax 174 mov (%eax),%ebx 175 mov %ebx,0x0 176 add $0x4,%eax 177 mov %eax,0x0 178 jmp ASM_PFX(CommonIdtEntry+0xd2) 179 movl $0x0,0x0 180## The "pushad" above pushed the debug stack esp. Since what we're actually doing 181## is building the context record on the debug stack, we need to save the pushed 182## debug ESP, and replace it with the application's last stack entry... 183 mov 0xc(%esp),%eax 184 mov %eax,0x0 185 mov 0x0,%eax 186 add $0xc,%eax 187 # application stack has eflags, cs, & eip, so 188 # last actual application stack entry is 189 # 12 bytes into the application stack. 190 mov %eax,0xc(%esp) 191## continue building context record 192## UINT32 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero 193 mov %ss,%eax 194 push %eax 195 196 # CS from application is one entry back in application stack 197 mov 0x0,%eax 198 movzwl 0x4(%eax),%eax 199 push %eax 200 mov %ds,%eax 201 push %eax 202 mov %es,%eax 203 push %eax 204 mov %fs,%eax 205 push %eax 206 mov %gs,%eax 207 push %eax 208 209## UINT32 Eip; 210 # Eip from application is on top of application stack 211 mov 0x0,%eax 212 pushl (%eax) 213 214## UINT32 Gdtr[2], Idtr[2]; 215 push $0x0 216 push $0x0 217 sidtl (%esp) 218 push $0x0 219 push $0x0 220 sgdtl (%esp) 221 222## UINT32 Ldtr, Tr; 223 xor %eax,%eax 224 str %eax 225 push %eax 226 sldt %eax 227 push %eax 228 229## UINT32 EFlags; 230## Eflags from application is two entries back in application stack 231 mov 0x0,%eax 232 pushl 0x8(%eax) 233 234## UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; 235## insure FXSAVE/FXRSTOR is enabled in CR4... 236## ... while we're at it, make sure DE is also enabled... 237 mov %cr4,%eax 238 or $0x208,%eax 239 mov %eax,%cr4 240 push %eax 241 mov %cr3,%eax 242 push %eax 243 mov %cr2,%eax 244 push %eax 245 push $0x0 246 mov %cr0,%eax 247 push %eax 248 249## UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; 250 mov %db7,%eax 251 push %eax 252 253## clear Dr7 while executing debugger itself 254 xor %eax,%eax 255 mov %eax,%db7 256 mov %db6,%eax 257 push %eax 258 259## insure all status bits in dr6 are clear... 260 xor %eax,%eax 261 mov %eax,%db6 262 mov %db3,%eax 263 push %eax 264 mov %db2,%eax 265 push %eax 266 mov %db1,%eax 267 push %eax 268 mov %db0,%eax 269 push %eax 270 271## FX_SAVE_STATE_IA32 FxSaveState; 272 sub $0x200,%esp 273 mov %esp,%edi 274 # IMPORTANT!! The debug stack has been carefully constructed to 275 # insure that esp and edi are 16 byte aligned when we get here. 276 # They MUST be. If they are not, a GP fault will occur. 277 fxsave (%edi) 278 279## UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear 280 cld 281 282## UINT32 ExceptionData; 283 mov 0x0,%eax 284 push %eax 285 286# call to C code which will in turn call registered handler 287# pass in the vector number 288 mov %esp,%eax 289 push %eax 290 mov 0x0,%eax 291 push %eax 292 call ASM_PFX(CommonIdtEntry+0x184) 293 add $0x8,%esp 294 295# restore context... 296## UINT32 ExceptionData; 297 add $0x4,%esp 298 299## FX_SAVE_STATE_IA32 FxSaveState; 300 mov %esp,%esi 301 fxrstor (%esi) 302 add $0x200,%esp 303 304## UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; 305 pop %eax 306 mov %eax,%db0 307 pop %eax 308 mov %eax,%db1 309 pop %eax 310 mov %eax,%db2 311 pop %eax 312 mov %eax,%db3 313 314## skip restore of dr6. We cleared dr6 during the context save. 315 add $0x4,%esp 316 pop %eax 317 mov %eax,%db7 318 319## UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; 320 pop %eax 321 mov %eax,%cr0 322 add $0x4,%esp 323 pop %eax 324 mov %eax,%cr2 325 pop %eax 326 mov %eax,%cr3 327 pop %eax 328 mov %eax,%cr4 329 330## UINT32 EFlags; 331 mov 0x0,%eax 332 popl 0x8(%eax) 333 334## UINT32 Ldtr, Tr; 335## UINT32 Gdtr[2], Idtr[2]; 336## Best not let anyone mess with these particular registers... 337 add $0x18,%esp 338 339## UINT32 Eip; 340 popl (%eax) 341 342## UINT32 SegGs, SegFs, SegEs, SegDs, SegCs, SegSs; 343## NOTE - modified segment registers could hang the debugger... We 344## could attempt to insulate ourselves against this possibility, 345## but that poses risks as well. 346## 347 348 pop %gs 349 pop %fs 350 pop %es 351 pop %ds 352 popl 0x4(%eax) 353 pop %ss 354 mov 0xc(%esp),%ebx 355 356## The next stuff to restore is the general purpose registers that were pushed 357## using the "pushad" instruction. 358## 359## The value of ESP as stored in the context record is the application ESP 360## including the 3 entries on the application stack caused by the exception 361## itself. It may have been modified by the debug agent, so we need to 362## determine if we need to relocate the application stack. 363 364 mov 0x0,%eax # move the potentially modified AppEsp into ebx 365 add $0xc,%eax 366 cmp %eax,%ebx 367 je ASM_PFX(CommonIdtEntry+0x202) 368 mov 0x0,%eax 369 mov (%eax),%ecx # EIP 370 mov %ecx,(%ebx) 371 mov 0x4(%eax),%ecx # CS 372 mov %ecx,0x4(%ebx) 373 mov 0x8(%eax),%ecx # EFLAGS 374 mov %ecx,0x8(%ebx) 375 376 mov %ebx,%eax # modify the saved AppEsp to the new AppEsp 377 mov %eax,0x0 378 mov 0x0,%eax # restore the DebugEsp on the debug stack 379 # so our "popad" will not cause a stack switch 380 mov %eax,0xc(%esp) 381 cmpl $0x68,0x0 382 jne PhonyIretd+0xd 383## Restore eflags so when we chain, the flags will be exactly as if we were never here. 384## We gin up the stack to do an iretd so we can get ALL the flags. 385 mov 0x0,%eax 386 mov 0x8(%eax),%ebx 387 and $0xfffffcff,%ebx # special handling for IF and TF 388 push %ebx 389 push %cs 390 push $0x0 391 iret 392 393PhonyIretd: 394## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; 395 popa 396 397## Switch back to application stack 398 mov 0x0,%esp 399 jmp *0x0 400## Jump to original handler 401## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; 402 popa 403## Switch back to application stack 404 mov 0x0,%esp 405 406## We're outa here... 407 iret 408