• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   Debug Agent library implementition for Dxe Core and Dxr modules.
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 "DxeDebugAgentLib.h"
16 
17 DEBUG_AGENT_MAILBOX          mMailbox;
18 DEBUG_AGENT_MAILBOX          *mMailboxPointer = NULL;
19 IA32_IDT_GATE_DESCRIPTOR     mIdtEntryTable[33];
20 BOOLEAN                      mDxeCoreFlag                = FALSE;
21 BOOLEAN                      mMultiProcessorDebugSupport = FALSE;
22 VOID                         *mSavedIdtTable             = NULL;
23 UINTN                        mSaveIdtTableSize           = 0;
24 BOOLEAN                      mDebugAgentInitialized      = FALSE;
25 BOOLEAN                      mSkipBreakpoint             = FALSE;
26 
27 /**
28   Check if debug agent support multi-processor.
29 
30   @retval TRUE    Multi-processor is supported.
31   @retval FALSE   Multi-processor is not supported.
32 
33 **/
34 BOOLEAN
MultiProcessorDebugSupport(VOID)35 MultiProcessorDebugSupport (
36   VOID
37   )
38 {
39   return mMultiProcessorDebugSupport;
40 }
41 
42 /**
43   Internal constructor worker function.
44 
45   It will register one callback function on EFI PCD Protocol.
46   It will allocate the NVS memory to store Mailbox and install configuration table
47   in system table to store its pointer.
48 
49 **/
50 VOID
InternalConstructorWorker(VOID)51 InternalConstructorWorker (
52   VOID
53   )
54 {
55   EFI_STATUS                  Status;
56   EFI_PHYSICAL_ADDRESS        Address;
57   BOOLEAN                     DebugTimerInterruptState;
58   DEBUG_AGENT_MAILBOX         *Mailbox;
59   DEBUG_AGENT_MAILBOX         *NewMailbox;
60   EFI_HOB_GUID_TYPE           *GuidHob;
61   EFI_VECTOR_HANDOFF_INFO     *VectorHandoffInfo;
62 
63   //
64   // Check persisted vector handoff info
65   //
66   Status = EFI_SUCCESS;
67   GuidHob = GetFirstGuidHob (&gEfiVectorHandoffInfoPpiGuid);
68   if (GuidHob != NULL && !mDxeCoreFlag) {
69     //
70     // Check if configuration table is installed or not if GUIDed HOB existed,
71     // only when Debug Agent is not linked by DXE Core
72     //
73     Status = EfiGetSystemConfigurationTable (&gEfiVectorHandoffTableGuid, (VOID **) &VectorHandoffInfo);
74   }
75   if (GuidHob == NULL || Status != EFI_SUCCESS) {
76     //
77     // Install configuration table for persisted vector handoff info if GUIDed HOB cannot be found or
78     // configuration table does not exist
79     //
80     Status = gBS->InstallConfigurationTable (&gEfiVectorHandoffTableGuid, (VOID *) &mVectorHandoffInfoDebugAgent[0]);
81     if (EFI_ERROR (Status)) {
82       DEBUG ((EFI_D_ERROR, "DebugAgent: Cannot install configuration table for persisted vector handoff info!\n"));
83       CpuDeadLoop ();
84     }
85   }
86 
87   //
88   // Install EFI Serial IO protocol on debug port
89   //
90   InstallSerialIo ();
91 
92   Address = 0;
93   Status = gBS->AllocatePages (
94                   AllocateAnyPages,
95                   EfiACPIMemoryNVS,
96                   EFI_SIZE_TO_PAGES (sizeof(DEBUG_AGENT_MAILBOX) + PcdGet16(PcdDebugPortHandleBufferSize)),
97                   &Address
98                   );
99   if (EFI_ERROR (Status)) {
100     DEBUG ((EFI_D_ERROR, "DebugAgent: Cannot install configuration table for mailbox!\n"));
101     CpuDeadLoop ();
102   }
103 
104   DebugTimerInterruptState = SaveAndSetDebugTimerInterrupt (FALSE);
105 
106   NewMailbox = (DEBUG_AGENT_MAILBOX *) (UINTN) Address;
107   //
108   // Copy Mailbox and Debug Port Handle buffer to new location in ACPI NVS memory, because original Mailbox
109   // and Debug Port Handle buffer may be free at runtime, SMM debug agent needs to access them
110   //
111   Mailbox = GetMailboxPointer ();
112   CopyMem (NewMailbox, Mailbox, sizeof (DEBUG_AGENT_MAILBOX));
113   CopyMem (NewMailbox + 1, (VOID *)(UINTN)Mailbox->DebugPortHandle, PcdGet16(PcdDebugPortHandleBufferSize));
114   //
115   // Update Debug Port Handle in new Mailbox
116   //
117   UpdateMailboxContent (NewMailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, (UINT64)(UINTN)(NewMailbox + 1));
118   mMailboxPointer = NewMailbox;
119 
120   DebugTimerInterruptState = SaveAndSetDebugTimerInterrupt (DebugTimerInterruptState);
121 
122   Status = gBS->InstallConfigurationTable (&gEfiDebugAgentGuid, (VOID *) mMailboxPointer);
123   if (EFI_ERROR (Status)) {
124     DEBUG ((EFI_D_ERROR, "DebugAgent: Failed to install configuration for mailbox!\n"));
125     CpuDeadLoop ();
126   }
127 }
128 
129 /**
130   Debug Agent constructor function.
131 
132   @param[in]  ImageHandle   The firmware allocated handle for the EFI image.
133   @param[in]  SystemTable   A pointer to the EFI System Table.
134 
135   @retval  RETURN_SUCCESS  When this function completed.
136 
137 **/
138 RETURN_STATUS
139 EFIAPI
DxeDebugAgentLibConstructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)140 DxeDebugAgentLibConstructor (
141   IN EFI_HANDLE        ImageHandle,
142   IN EFI_SYSTEM_TABLE  *SystemTable
143   )
144 {
145   if (mDxeCoreFlag) {
146     //
147     // Invoke internal constructor function only when DXE core links this library instance
148     //
149     InternalConstructorWorker ();
150   }
151 
152   return RETURN_SUCCESS;
153 }
154 
155 /**
156   Get the pointer to Mailbox from the configuration table.
157 
158   @return Pointer to Mailbox.
159 
160 **/
161 DEBUG_AGENT_MAILBOX *
GetMailboxFromConfigurationTable(VOID)162 GetMailboxFromConfigurationTable (
163   VOID
164   )
165 {
166   EFI_STATUS               Status;
167   DEBUG_AGENT_MAILBOX      *Mailbox;
168 
169   Status = EfiGetSystemConfigurationTable (&gEfiDebugAgentGuid, (VOID **) &Mailbox);
170   if (Status == EFI_SUCCESS && Mailbox != NULL) {
171     VerifyMailboxChecksum (Mailbox);
172     return Mailbox;
173   } else {
174     return NULL;
175   }
176 }
177 
178 /**
179   Get the pointer to Mailbox from the GUIDed HOB.
180 
181   @param[in]  HobStart      The starting HOB pointer to search from.
182 
183   @return Pointer to Mailbox.
184 
185 **/
186 DEBUG_AGENT_MAILBOX *
GetMailboxFromHob(IN VOID * HobStart)187 GetMailboxFromHob (
188   IN VOID                  *HobStart
189   )
190 {
191   EFI_HOB_GUID_TYPE        *GuidHob;
192   UINT64                   *MailboxLocation;
193   DEBUG_AGENT_MAILBOX      *Mailbox;
194 
195   GuidHob = GetNextGuidHob (&gEfiDebugAgentGuid, HobStart);
196   if (GuidHob == NULL) {
197     return NULL;
198   }
199   MailboxLocation = (UINT64 *) (GET_GUID_HOB_DATA(GuidHob));
200   Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation);
201   VerifyMailboxChecksum (Mailbox);
202 
203   return Mailbox;
204 }
205 
206 /**
207   Get Debug Agent Mailbox pointer.
208 
209   @return Mailbox pointer.
210 
211 **/
212 DEBUG_AGENT_MAILBOX *
GetMailboxPointer(VOID)213 GetMailboxPointer (
214   VOID
215   )
216 {
217   AcquireMpSpinLock (&mDebugMpContext.MailboxSpinLock);
218   VerifyMailboxChecksum (mMailboxPointer);
219   ReleaseMpSpinLock (&mDebugMpContext.MailboxSpinLock);
220   return mMailboxPointer;
221 }
222 
223 /**
224   Get debug port handle.
225 
226   @return Debug port handle.
227 
228 **/
229 DEBUG_PORT_HANDLE
GetDebugPortHandle(VOID)230 GetDebugPortHandle (
231   VOID
232   )
233 {
234   return (DEBUG_PORT_HANDLE) (UINTN)(GetMailboxPointer ()->DebugPortHandle);
235 }
236 
237 /**
238   Worker function to set up Debug Agent environment.
239 
240   This function will set up IDT table and initialize the IDT entries and
241   initialize CPU LOCAL APIC timer.
242   It also tries to connect HOST if Debug Agent was not initialized before.
243 
244   @param[in] Mailbox        Pointer to Mailbox.
245 
246 **/
247 VOID
SetupDebugAgentEnvironment(IN DEBUG_AGENT_MAILBOX * Mailbox)248 SetupDebugAgentEnvironment (
249   IN DEBUG_AGENT_MAILBOX       *Mailbox
250   )
251 {
252   IA32_DESCRIPTOR              Idtr;
253   UINT16                       IdtEntryCount;
254   UINT64                       DebugPortHandle;
255   UINT32                       DebugTimerFrequency;
256 
257   if (mMultiProcessorDebugSupport) {
258     InitializeSpinLock (&mDebugMpContext.MpContextSpinLock);
259     InitializeSpinLock (&mDebugMpContext.DebugPortSpinLock);
260     InitializeSpinLock (&mDebugMpContext.MailboxSpinLock);
261     //
262     // Clear Break CPU index value
263     //
264     mDebugMpContext.BreakAtCpuIndex = (UINT32) -1;
265   }
266 
267   //
268   // Get original IDT address and size.
269   //
270   AsmReadIdtr ((IA32_DESCRIPTOR *) &Idtr);
271   IdtEntryCount = (UINT16) ((Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR));
272   if (IdtEntryCount < 33) {
273     ZeroMem (&mIdtEntryTable, sizeof (IA32_IDT_GATE_DESCRIPTOR) * 33);
274     //
275     // Copy original IDT table into new one
276     //
277     CopyMem (&mIdtEntryTable, (VOID *) Idtr.Base, Idtr.Limit + 1);
278     //
279     // Load new IDT table
280     //
281     Idtr.Limit = (UINT16) (sizeof (IA32_IDT_GATE_DESCRIPTOR) * 33 - 1);
282     Idtr.Base  = (UINTN) &mIdtEntryTable;
283     AsmWriteIdtr ((IA32_DESCRIPTOR *) &Idtr);
284   }
285 
286   //
287   // Initialize the IDT table entries to support source level debug.
288   //
289   InitializeDebugIdt ();
290 
291   //
292   // If mMailboxPointer is not set before, set it
293   //
294   if (mMailboxPointer == NULL) {
295     if (Mailbox != NULL) {
296       //
297       // If Mailbox exists, copy it into one global variable
298       //
299       CopyMem (&mMailbox, Mailbox, sizeof (DEBUG_AGENT_MAILBOX));
300     } else {
301       ZeroMem (&mMailbox, sizeof (DEBUG_AGENT_MAILBOX));
302     }
303     mMailboxPointer = &mMailbox;
304   }
305 
306   //
307   // Initialize Debug Timer hardware and save its initial count and frequency
308   //
309   mDebugMpContext.DebugTimerInitCount = InitializeDebugTimer (&DebugTimerFrequency, TRUE);
310   UpdateMailboxContent (mMailboxPointer, DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY, DebugTimerFrequency);
311   //
312   // Initialize debug communication port
313   //
314   DebugPortHandle = (UINT64) (UINTN)DebugPortInitialize ((VOID *)(UINTN)mMailboxPointer->DebugPortHandle, NULL);
315   UpdateMailboxContent (mMailboxPointer, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle);
316 
317   if (Mailbox == NULL) {
318     //
319     // Trigger one software interrupt to inform HOST
320     //
321     TriggerSoftInterrupt (SYSTEM_RESET_SIGNATURE);
322     SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1);
323     //
324     // Memory has been ready
325     //
326     if (IsHostAttached ()) {
327       //
328       // Trigger one software interrupt to inform HOST
329       //
330       TriggerSoftInterrupt (MEMORY_READY_SIGNATURE);
331     }
332   }
333 }
334 
335 
336 /**
337   Initialize debug agent.
338 
339   This function is used to set up debug environment for DXE phase.
340 
341   If this function is called by DXE Core, Context must be the pointer
342   to HOB list which will be used to get GUIDed HOB. It will enable
343   interrupt to support break-in feature.
344   If this function is called by DXE module, Context must be NULL. It
345   will enable interrupt to support break-in feature.
346 
347   @param[in] InitFlag     Init flag is used to decide initialize process.
348   @param[in] Context      Context needed according to InitFlag.
349   @param[in] Function     Continue function called by debug agent library; it was
350                           optional.
351 
352 **/
353 VOID
354 EFIAPI
InitializeDebugAgent(IN UINT32 InitFlag,IN VOID * Context,OPTIONAL IN DEBUG_AGENT_CONTINUE Function OPTIONAL)355 InitializeDebugAgent (
356   IN UINT32                InitFlag,
357   IN VOID                  *Context, OPTIONAL
358   IN DEBUG_AGENT_CONTINUE  Function  OPTIONAL
359   )
360 {
361   UINT64                       *MailboxLocation;
362   DEBUG_AGENT_MAILBOX          *Mailbox;
363   BOOLEAN                      InterruptStatus;
364   VOID                         *HobList;
365   IA32_DESCRIPTOR              IdtDescriptor;
366   IA32_DESCRIPTOR              *Ia32Idtr;
367   IA32_IDT_ENTRY               *Ia32IdtEntry;
368   BOOLEAN                      PeriodicMode;
369   UINTN                        TimerCycle;
370 
371   if (InitFlag == DEBUG_AGENT_INIT_DXE_AP) {
372     //
373     // Check if CPU APIC Timer is working, otherwise initialize it.
374     //
375     InitializeLocalApicSoftwareEnable (TRUE);
376     GetApicTimerState (NULL, &PeriodicMode, NULL);
377     TimerCycle = GetApicTimerInitCount ();
378     if (!PeriodicMode || TimerCycle == 0) {
379       InitializeDebugTimer (NULL, FALSE);
380     }
381     //
382     // Invoked by AP, enable interrupt to let AP could receive IPI from other processors
383     //
384     EnableInterrupts ();
385     return ;
386   }
387 
388   //
389   // Disable Debug Timer interrupt
390   //
391   SaveAndSetDebugTimerInterrupt (FALSE);
392   //
393   // Save and disable original interrupt status
394   //
395   InterruptStatus = SaveAndDisableInterrupts ();
396 
397   //
398   // Try to get mailbox firstly
399   //
400   HobList         = NULL;
401   Mailbox         = NULL;
402   MailboxLocation = NULL;
403 
404   switch (InitFlag) {
405 
406   case DEBUG_AGENT_INIT_DXE_LOAD:
407     //
408     // Check if Debug Agent has been initialized before
409     //
410     if (IsDebugAgentInitialzed ()) {
411       DEBUG ((EFI_D_INFO, "Debug Agent: The former agent will be overwritten by the new one!\n"));
412     }
413 
414     mMultiProcessorDebugSupport = TRUE;
415     //
416     // Save original IDT table
417     //
418     AsmReadIdtr (&IdtDescriptor);
419     mSaveIdtTableSize = IdtDescriptor.Limit + 1;
420     mSavedIdtTable    = AllocateCopyPool (mSaveIdtTableSize, (VOID *) IdtDescriptor.Base);
421     //
422     // Check if Debug Agent initialized in DXE phase
423     //
424     Mailbox = GetMailboxFromConfigurationTable ();
425     if (Mailbox == NULL) {
426       //
427       // Try to get mailbox from GUIDed HOB build in PEI
428       //
429       HobList = GetHobList ();
430       Mailbox = GetMailboxFromHob (HobList);
431     }
432     //
433     // Set up Debug Agent Environment and try to connect HOST if required
434     //
435     SetupDebugAgentEnvironment (Mailbox);
436     //
437     // For DEBUG_AGENT_INIT_S3, needn't to install configuration table and EFI Serial IO protocol
438     // For DEBUG_AGENT_INIT_DXE_CORE, InternalConstructorWorker() will invoked in Constructor()
439     //
440     InternalConstructorWorker ();
441     //
442     // Enable Debug Timer interrupt
443     //
444     SaveAndSetDebugTimerInterrupt (TRUE);
445     //
446     // Enable interrupt to receive Debug Timer interrupt
447     //
448     EnableInterrupts ();
449 
450     mDebugAgentInitialized = TRUE;
451     FindAndReportModuleImageInfo (SIZE_4KB);
452 
453     *(EFI_STATUS *)Context = EFI_SUCCESS;
454 
455     break;
456 
457   case DEBUG_AGENT_INIT_DXE_UNLOAD:
458     if (mDebugAgentInitialized) {
459       if (IsHostAttached ()) {
460         *(EFI_STATUS *)Context = EFI_ACCESS_DENIED;
461         //
462         // Enable Debug Timer interrupt again
463         //
464         SaveAndSetDebugTimerInterrupt (TRUE);
465       } else {
466         //
467         // Restore original IDT table
468         //
469         AsmReadIdtr (&IdtDescriptor);
470         IdtDescriptor.Limit = (UINT16) (mSaveIdtTableSize - 1);
471         CopyMem ((VOID *) IdtDescriptor.Base, mSavedIdtTable, mSaveIdtTableSize);
472         AsmWriteIdtr (&IdtDescriptor);
473         FreePool (mSavedIdtTable);
474         mDebugAgentInitialized = FALSE;
475         *(EFI_STATUS *)Context = EFI_SUCCESS;
476       }
477     } else {
478       *(EFI_STATUS *)Context = EFI_NOT_STARTED;
479     }
480 
481     //
482     // Restore interrupt state.
483     //
484     SetInterruptState (InterruptStatus);
485     break;
486 
487   case DEBUG_AGENT_INIT_DXE_CORE:
488     mDxeCoreFlag                = TRUE;
489     mMultiProcessorDebugSupport = TRUE;
490     //
491     // Try to get mailbox from GUIDed HOB build in PEI
492     //
493     HobList = Context;
494     Mailbox = GetMailboxFromHob (HobList);
495     //
496     // Set up Debug Agent Environment and try to connect HOST if required
497     //
498     SetupDebugAgentEnvironment (Mailbox);
499     //
500     // Enable Debug Timer interrupt
501     //
502     SaveAndSetDebugTimerInterrupt (TRUE);
503     //
504     // Enable interrupt to receive Debug Timer interrupt
505     //
506     EnableInterrupts ();
507 
508     break;
509 
510   case DEBUG_AGENT_INIT_S3:
511 
512     if (Context != NULL) {
513       Ia32Idtr =  (IA32_DESCRIPTOR *) Context;
514       Ia32IdtEntry = (IA32_IDT_ENTRY *)(Ia32Idtr->Base);
515       MailboxLocation = (UINT64 *) (UINTN) (Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetLow +
516                                   (UINT32) (Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetHigh << 16));
517       Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation);
518       VerifyMailboxChecksum (Mailbox);
519     }
520     //
521     // Save Mailbox pointer in global variable
522     //
523     mMailboxPointer = Mailbox;
524     //
525     // Set up Debug Agent Environment and try to connect HOST if required
526     //
527     SetupDebugAgentEnvironment (Mailbox);
528     //
529     // Disable interrupt
530     //
531     DisableInterrupts ();
532     FindAndReportModuleImageInfo (SIZE_4KB);
533     if (GetDebugFlag (DEBUG_AGENT_FLAG_BREAK_BOOT_SCRIPT) == 1) {
534       //
535       // If Boot Script entry break is set, code will be break at here.
536       //
537       CpuBreakpoint ();
538     }
539     break;
540 
541   default:
542     //
543     // Only DEBUG_AGENT_INIT_PREMEM_SEC and DEBUG_AGENT_INIT_POSTMEM_SEC are allowed for this
544     // Debug Agent library instance.
545     //
546     DEBUG ((EFI_D_ERROR, "Debug Agent: The InitFlag value is not allowed!\n"));
547     CpuDeadLoop ();
548     break;
549   }
550 }
551