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 ASM_GLOBAL ASM_PFX(OrigVector) 16 ASM_GLOBAL ASM_PFX(InterruptEntryStub) 17 ASM_GLOBAL ASM_PFX(StubSize) 18 ASM_GLOBAL ASM_PFX(CommonIdtEntry) 19 ASM_GLOBAL ASM_PFX(FxStorSupport) 20 21 ASM_PFX(StubSize): .long ASM_PFX(InterruptEntryStubEnd) - ASM_PFX(InterruptEntryStub) 22 ASM_PFX(AppEsp): .long 0x11111111 # ? 23 ASM_PFX(DebugEsp): .long 0x22222222 # ? 24 ASM_PFX(ExtraPush): .long 0x33333333 # ? 25 ASM_PFX(ExceptData): .long 0x44444444 # ? 26 ASM_PFX(Eflags): .long 0x55555555 # ? 27 ASM_PFX(OrigVector): .long 0x66666666 # ? 28 29 #------------------------------------------------------------------------------ 30 # BOOLEAN 31 # FxStorSupport ( 32 # void 33 # ) 34 # 35 # Abstract: Returns TRUE if FxStor instructions are supported 36 # 37 ASM_GLOBAL ASM_PFX(FxStorSupport) 38 ASM_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 60 ASM_GLOBAL ASM_PFX(Vect2Desc) 61 ASM_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 74 ASM_GLOBAL ASM_PFX(InterruptEntryStub) 75 ASM_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 80 ASM_GLOBAL ASM_PFX(InterruptEntryStubEnd) 81 ASM_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 # 89 ASM_GLOBAL ASM_PFX(CommonIdtEntry) 90 ASM_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 393 PhonyIretd: 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