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