1 /** @file
2   X64 specific functions to support Debug Support protocol.
3 
4 Copyright (c) 2008 - 2010, 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 #include "PlDebugSupport.h"
16 
17 IA32_IDT_GATE_DESCRIPTOR  NullDesc = {{0,0}};
18 
19 /**
20   Get Interrupt Handle from IDT Gate Descriptor.
21 
22   @param  IdtGateDecriptor  IDT Gate Descriptor.
23 
24   @return Interrupt Handle stored in IDT Gate Descriptor.
25 
26 **/
27 UINTN
GetInterruptHandleFromIdt(IN IA32_IDT_GATE_DESCRIPTOR * IdtGateDecriptor)28 GetInterruptHandleFromIdt (
29   IN IA32_IDT_GATE_DESCRIPTOR  *IdtGateDecriptor
30   )
31 {
32   UINTN      InterruptHandle;
33 
34   //
35   // InterruptHandle  0-15 : OffsetLow
36   // InterruptHandle 16-31 : OffsetHigh
37   // InterruptHandle 32-63 : OffsetUpper
38   //
39   InterruptHandle = ((UINTN) IdtGateDecriptor->Bits.OffsetLow) |
40                     (((UINTN) IdtGateDecriptor->Bits.OffsetHigh)  << 16) |
41                     (((UINTN) IdtGateDecriptor->Bits.OffsetUpper) << 32) ;
42 
43   return InterruptHandle;
44 }
45 
46 /**
47   Allocate pool for a new IDT entry stub.
48 
49   Copy the generic stub into the new buffer and fixup the vector number
50   and jump target address.
51 
52   @param  ExceptionType   This is the exception type that the new stub will be created
53                           for.
54   @param  Stub            On successful exit, *Stub contains the newly allocated entry stub.
55 
56 **/
57 VOID
CreateEntryStub(IN EFI_EXCEPTION_TYPE ExceptionType,OUT VOID ** Stub)58 CreateEntryStub (
59   IN EFI_EXCEPTION_TYPE     ExceptionType,
60   OUT VOID                  **Stub
61   )
62 {
63   UINT8       *StubCopy;
64 
65   StubCopy = *Stub;
66 
67   //
68   // Fixup the stub code for this vector
69   //
70 
71   // The stub code looks like this:
72   //
73   //    00000000  6A 00               push    0                       ; push vector number - will be modified before installed
74   //    00000002  E9                  db      0e9h                    ; jump rel32
75   //    00000003  00000000            dd      0                       ; fixed up to relative address of CommonIdtEntry
76   //
77 
78   //
79   // poke in the exception type so the second push pushes the exception type
80   //
81   StubCopy[0x1] = (UINT8) ExceptionType;
82 
83   //
84   // fixup the jump target to point to the common entry
85   //
86   *(UINT32 *) &StubCopy[0x3] = (UINT32)((UINTN) CommonIdtEntry - (UINTN) &StubCopy[StubSize]);
87 
88   return;
89 }
90 
91 /**
92   This is the main worker function that manages the state of the interrupt
93   handlers.  It both installs and uninstalls interrupt handlers based on the
94   value of NewCallback.  If NewCallback is NULL, then uninstall is indicated.
95   If NewCallback is non-NULL, then install is indicated.
96 
97   @param  NewCallback   If non-NULL, NewCallback specifies the new handler to register.
98                         If NULL, specifies that the previously registered handler should
99                         be uninstalled.
100   @param  ExceptionType Indicates which entry to manage.
101 
102   @retval EFI_SUCCESS            Process is ok.
103   @retval EFI_INVALID_PARAMETER  Requested uninstalling a handler from a vector that has
104                                  no handler registered for it
105   @retval EFI_ALREADY_STARTED    Requested install to a vector that already has a handler registered.
106   @retval others                 Possible return values are passed through from UnHookEntry and HookEntry.
107 
108 **/
109 EFI_STATUS
ManageIdtEntryTable(CALLBACK_FUNC NewCallback,EFI_EXCEPTION_TYPE ExceptionType)110 ManageIdtEntryTable (
111   CALLBACK_FUNC      NewCallback,
112   EFI_EXCEPTION_TYPE ExceptionType
113   )
114 {
115   EFI_STATUS  Status;
116 
117   Status = EFI_SUCCESS;
118 
119   if (CompareMem (&IdtEntryTable[ExceptionType].NewDesc, &NullDesc, sizeof (IA32_IDT_GATE_DESCRIPTOR)) != 0) {
120     //
121     // we've already installed to this vector
122     //
123     if (NewCallback != NULL) {
124       //
125       // if the input handler is non-null, error
126       //
127       Status = EFI_ALREADY_STARTED;
128     } else {
129       UnhookEntry (ExceptionType);
130     }
131   } else {
132     //
133     // no user handler installed on this vector
134     //
135     if (NewCallback == NULL) {
136       //
137       // if the input handler is null, error
138       //
139       Status = EFI_INVALID_PARAMETER;
140     } else {
141       HookEntry (ExceptionType, NewCallback);
142     }
143   }
144 
145   return Status;
146 }
147