1 /** @file
2   Debug Agent library implementition.
3 
4   Copyright (c) 2010 - 2015, 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 "SmmDebugAgentLib.h"
16 
17 DEBUG_AGENT_MAILBOX         *mMailboxPointer = NULL;
18 DEBUG_AGENT_MAILBOX         mLocalMailbox;
19 UINTN                       mSavedDebugRegisters[6];
20 IA32_IDT_GATE_DESCRIPTOR    mIdtEntryTable[33];
21 BOOLEAN                     mSkipBreakpoint = FALSE;
22 
23 CHAR8 mWarningMsgIgnoreSmmEntryBreak[] = "Ignore smmentrybreak setting for SMI issued during DXE debugging!\r\n";
24 
25 /**
26   Check if debug agent support multi-processor.
27 
28   @retval TRUE    Multi-processor is supported.
29   @retval FALSE   Multi-processor is not supported.
30 
31 **/
32 BOOLEAN
MultiProcessorDebugSupport(VOID)33 MultiProcessorDebugSupport (
34   VOID
35   )
36 {
37   return FALSE;
38 }
39 
40 /**
41   Read the Attach/Break-in symbols from the debug port.
42 
43   @param[in]  Handle         Pointer to Debug Port handle.
44   @param[out] BreakSymbol    Returned break symbol.
45 
46   @retval EFI_SUCCESS        Read the symbol in BreakSymbol.
47   @retval EFI_NOT_FOUND      No read the break symbol.
48 
49 **/
50 EFI_STATUS
DebugReadBreakSymbol(IN DEBUG_PORT_HANDLE Handle,OUT UINT8 * BreakSymbol)51 DebugReadBreakSymbol (
52   IN  DEBUG_PORT_HANDLE      Handle,
53   OUT UINT8                  *BreakSymbol
54   )
55 {
56   //
57   // Smm instance has no debug timer to poll break symbol.
58   //
59   return EFI_NOT_FOUND;
60 }
61 
62 /**
63   Get the pointer to Mailbox from the GUIDed HOB.
64 
65   @return Pointer to Mailbox.
66 
67 **/
68 DEBUG_AGENT_MAILBOX *
GetMailboxFromHob(VOID)69 GetMailboxFromHob (
70   VOID
71   )
72 {
73   EFI_HOB_GUID_TYPE        *GuidHob;
74   UINT64                   *MailboxLocation;
75   DEBUG_AGENT_MAILBOX      *Mailbox;
76 
77   GuidHob = GetFirstGuidHob (&gEfiDebugAgentGuid);
78   if (GuidHob == NULL) {
79     return NULL;
80   }
81   MailboxLocation = (UINT64 *) (GET_GUID_HOB_DATA(GuidHob));
82   Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation);
83   VerifyMailboxChecksum (Mailbox);
84 
85   return Mailbox;
86 }
87 
88 /**
89   Get Debug Agent Mailbox pointer.
90 
91   @return Mailbox pointer.
92 
93 **/
94 DEBUG_AGENT_MAILBOX *
GetMailboxPointer(VOID)95 GetMailboxPointer (
96   VOID
97   )
98 {
99   VerifyMailboxChecksum (mMailboxPointer);
100   return mMailboxPointer;
101 }
102 
103 /**
104   Get debug port handle.
105 
106   @return Debug port handle.
107 
108 **/
109 DEBUG_PORT_HANDLE
GetDebugPortHandle(VOID)110 GetDebugPortHandle (
111   VOID
112   )
113 {
114   return (DEBUG_PORT_HANDLE) (UINTN)(GetMailboxPointer()->DebugPortHandle);
115 }
116 
117 /**
118   Store debug register when SMI exit.
119 
120 **/
121 VOID
SaveDebugRegister(VOID)122 SaveDebugRegister (
123   VOID
124   )
125 {
126   mSavedDebugRegisters[0] = AsmReadDr0 ();
127   mSavedDebugRegisters[1] = AsmReadDr1 ();
128   mSavedDebugRegisters[2] = AsmReadDr2 ();
129   mSavedDebugRegisters[3] = AsmReadDr3 ();
130   mSavedDebugRegisters[4] = AsmReadDr6 ();
131   mSavedDebugRegisters[5] = AsmReadDr7 ();
132 }
133 
134 /**
135   Restore debug register when SMI exit.
136 
137 **/
138 VOID
RestoreDebugRegister(VOID)139 RestoreDebugRegister (
140   VOID
141   )
142 {
143   AsmWriteDr7 (0);
144   AsmWriteDr0 (mSavedDebugRegisters[0]);
145   AsmWriteDr1 (mSavedDebugRegisters[1]);
146   AsmWriteDr2 (mSavedDebugRegisters[2]);
147   AsmWriteDr3 (mSavedDebugRegisters[3]);
148   AsmWriteDr6 (mSavedDebugRegisters[4]);
149   AsmWriteDr7 (mSavedDebugRegisters[5]);
150 }
151 
152 /**
153   Initialize debug agent.
154 
155   This function is used to set up debug enviroment for source level debug
156   in SMM code.
157 
158   If InitFlag is DEBUG_AGENT_INIT_SMM, it will overirde IDT table entries
159   and initialize debug port. It will get debug agent Mailbox from GUIDed HOB,
160   it it exists, debug agent wiil copied it into the local Mailbox in SMM space.
161   it will overirde IDT table entries and initialize debug port. Context will be
162   NULL.
163   If InitFlag is DEBUG_AGENT_INIT_ENTER_SMI, debug agent will save Debug
164   Registers and get local Mailbox in SMM space. Context will be NULL.
165   If InitFlag is DEBUG_AGENT_INIT_EXIT_SMI, debug agent will restore Debug
166   Registers. Context will be NULL.
167 
168   @param[in] InitFlag     Init flag is used to decide initialize process.
169   @param[in] Context      Context needed according to InitFlag.
170   @param[in] Function     Continue function called by debug agent library; it was
171                           optional.
172 
173 **/
174 VOID
175 EFIAPI
InitializeDebugAgent(IN UINT32 InitFlag,IN VOID * Context,OPTIONAL IN DEBUG_AGENT_CONTINUE Function OPTIONAL)176 InitializeDebugAgent (
177   IN UINT32                InitFlag,
178   IN VOID                  *Context, OPTIONAL
179   IN DEBUG_AGENT_CONTINUE  Function  OPTIONAL
180   )
181 {
182   EFI_STATUS                    Status;
183   UINT64                        DebugPortHandle;
184   IA32_IDT_GATE_DESCRIPTOR      IdtEntry[33];
185   IA32_DESCRIPTOR               IdtDescriptor;
186   IA32_DESCRIPTOR               *Ia32Idtr;
187   IA32_IDT_ENTRY                *Ia32IdtEntry;
188   IA32_DESCRIPTOR               Idtr;
189   UINT16                        IdtEntryCount;
190   DEBUG_AGENT_MAILBOX           *Mailbox;
191   UINT64                        *MailboxLocation;
192   UINT32                        DebugTimerFrequency;
193   BOOLEAN                       PeriodicMode;
194   UINTN                         TimerCycle;
195 
196   switch (InitFlag) {
197   case DEBUG_AGENT_INIT_SMM:
198     //
199     // Install configuration table for persisted vector handoff info
200     //
201     Status = gSmst->SmmInstallConfigurationTable (
202                       gSmst,
203                       &gEfiVectorHandoffTableGuid,
204                       (VOID *) &mVectorHandoffInfoDebugAgent[0],
205                       sizeof (EFI_VECTOR_HANDOFF_INFO) * mVectorHandoffInfoCount
206                       );
207     if (EFI_ERROR (Status)) {
208       DEBUG ((EFI_D_ERROR, "DebugAgent: Cannot install configuration table for persisted vector handoff info!\n"));
209       CpuDeadLoop ();
210     }
211     //
212     // Check if Debug Agent initialized in DXE phase
213     //
214     Status = EfiGetSystemConfigurationTable (&gEfiDebugAgentGuid, (VOID **) &Mailbox);
215     if (Status == EFI_SUCCESS && Mailbox != NULL) {
216       VerifyMailboxChecksum (Mailbox);
217       mMailboxPointer = Mailbox;
218       break;
219     }
220     //
221     // Check if Debug Agent initialized in SEC/PEI phase
222     //
223     Mailbox = GetMailboxFromHob ();
224     if (Mailbox != NULL) {
225       mMailboxPointer = Mailbox;
226       break;
227     }
228     //
229     // Debug Agent was not initialized before, use the local mailbox.
230     //
231     ZeroMem (&mLocalMailbox, sizeof (DEBUG_AGENT_MAILBOX));
232     Mailbox = &mLocalMailbox;
233     //
234     // Save original IDT entries
235     //
236     AsmReadIdtr (&IdtDescriptor);
237     CopyMem (&IdtEntry, (VOID *)IdtDescriptor.Base, 33 * sizeof(IA32_IDT_GATE_DESCRIPTOR));
238     //
239     // Initialized Debug Agent
240     //
241     InitializeDebugIdt ();
242     //
243     // Initialize Debug Timer hardware and save its frequency
244     //
245     InitializeDebugTimer (&DebugTimerFrequency, TRUE);
246     UpdateMailboxContent (mMailboxPointer, DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY, DebugTimerFrequency);
247 
248     DebugPortHandle = (UINT64) (UINTN)DebugPortInitialize ((DEBUG_PORT_HANDLE) (UINTN)Mailbox->DebugPortHandle, NULL);
249     UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle);
250     mMailboxPointer = Mailbox;
251     //
252     // Trigger one software interrupt to inform HOST
253     //
254     TriggerSoftInterrupt (SYSTEM_RESET_SIGNATURE);
255 
256     SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1);
257     //
258     // Memory has been ready
259     //
260     if (IsHostAttached ()) {
261       //
262       // Trigger one software interrupt to inform HOST
263       //
264       TriggerSoftInterrupt (MEMORY_READY_SIGNATURE);
265     }
266     //
267     // Find and report PE/COFF image info to HOST
268     //
269     FindAndReportModuleImageInfo (SIZE_4KB);
270     //
271     // Restore saved IDT entries
272     //
273     CopyMem ((VOID *)IdtDescriptor.Base, &IdtEntry, 33 * sizeof(IA32_IDT_GATE_DESCRIPTOR));
274 
275     break;
276 
277   case DEBUG_AGENT_INIT_ENTER_SMI:
278     SaveDebugRegister ();
279     InitializeDebugIdt ();
280     //
281     // Check if CPU APIC Timer is working, otherwise initialize it.
282     //
283     InitializeLocalApicSoftwareEnable (TRUE);
284     GetApicTimerState (NULL, &PeriodicMode, NULL);
285     TimerCycle = GetApicTimerInitCount ();
286     if (!PeriodicMode || TimerCycle == 0) {
287       InitializeDebugTimer (NULL, FALSE);
288     }
289     Mailbox = GetMailboxPointer ();
290     if (GetDebugFlag (DEBUG_AGENT_FLAG_AGENT_IN_PROGRESS) == 1) {
291       //
292       // If Debug Agent has been communicaton state with HOST, we need skip
293       // any break points set in SMM, set Skip Breakpoint flag
294       //
295       mSkipBreakpoint = TRUE;
296     }
297     if (GetDebugFlag (DEBUG_AGENT_FLAG_BREAK_ON_NEXT_SMI) == 1) {
298       if (mSkipBreakpoint) {
299         //
300         // Print warning message if ignore smm entry break
301         //
302         DebugPortWriteBuffer ((DEBUG_PORT_HANDLE) (UINTN)Mailbox->DebugPortHandle,
303                                (UINT8 *)mWarningMsgIgnoreSmmEntryBreak,
304                                AsciiStrLen (mWarningMsgIgnoreSmmEntryBreak)
305                                );
306       } else {
307         //
308         // If SMM entry break is set, SMM code will be break at here.
309         //
310         CpuBreakpoint ();
311       }
312     }
313     break;
314 
315   case DEBUG_AGENT_INIT_EXIT_SMI:
316     Mailbox = GetMailboxPointer ();
317     //
318     // Clear Skip Breakpoint flag
319     //
320     mSkipBreakpoint = FALSE;
321     RestoreDebugRegister ();
322     break;
323 
324   case DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64:
325     if (Context == NULL) {
326       DEBUG ((EFI_D_ERROR, "DebugAgent: Input parameter Context cannot be NULL!\n"));
327       CpuDeadLoop ();
328     } else {
329       Ia32Idtr =  (IA32_DESCRIPTOR *) Context;
330       Ia32IdtEntry = (IA32_IDT_ENTRY *)(Ia32Idtr->Base);
331       MailboxLocation = (UINT64 *) (UINTN) (Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetLow +
332                                   (UINT32) (Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetHigh << 16));
333       mMailboxPointer = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation);
334       VerifyMailboxChecksum (mMailboxPointer);
335       //
336       // Get original IDT address and size.
337       //
338       AsmReadIdtr ((IA32_DESCRIPTOR *) &Idtr);
339       IdtEntryCount = (UINT16) ((Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR));
340       if (IdtEntryCount < 33) {
341         Idtr.Limit = (UINT16) (sizeof (IA32_IDT_GATE_DESCRIPTOR) * 33 - 1);
342         Idtr.Base  = (UINTN) &mIdtEntryTable;
343         ZeroMem (&mIdtEntryTable, Idtr.Limit + 1);
344         AsmWriteIdtr ((IA32_DESCRIPTOR *) &Idtr);
345       }
346 
347       InitializeDebugIdt ();
348       //
349       // Initialize Debug Timer hardware and save its frequency
350       //
351       InitializeDebugTimer (&DebugTimerFrequency, TRUE);
352       UpdateMailboxContent (mMailboxPointer, DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY, DebugTimerFrequency);
353       //
354       // Enable Debug Timer interrupt and CPU interrupt
355       //
356       SaveAndSetDebugTimerInterrupt (TRUE);
357       EnableInterrupts ();
358 
359       FindAndReportModuleImageInfo (SIZE_4KB);
360     }
361     break;
362 
363   default:
364     //
365     // Only DEBUG_AGENT_INIT_PREMEM_SEC and DEBUG_AGENT_INIT_POSTMEM_SEC are allowed for this
366     // Debug Agent library instance.
367     //
368     DEBUG ((EFI_D_ERROR, "Debug Agent: The InitFlag value is not allowed!\n"));
369     CpuDeadLoop ();
370     break;
371   }
372 }
373 
374