1 /** @file
2   SEC Core Debug Agent Library instance implementation.
3 
4   Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.<BR>
5   SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include "SecPeiDebugAgentLib.h"
10 
11 GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN  mSkipBreakpoint = FALSE;
12 
13 
14 GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_VECTOR_HANDOFF_INFO_PPI mVectorHandoffInfoPpi = {
15   &mVectorHandoffInfoDebugAgent[0]
16 };
17 
18 //
19 // Ppis to be installed
20 //
21 GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_PPI_DESCRIPTOR           mVectorHandoffInfoPpiList[] = {
22   {
23     (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
24     &gEfiVectorHandoffInfoPpiGuid,
25     &mVectorHandoffInfoPpi
26   }
27 };
28 
29 GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_NOTIFY_DESCRIPTOR mDebugAgentMemoryDiscoveredNotifyList[1] = {
30   {
31     (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
32     &gEfiPeiMemoryDiscoveredPpiGuid,
33     DebugAgentCallbackMemoryDiscoveredPpi
34   }
35 };
36 
37 /**
38   Check if debug agent support multi-processor.
39 
40   @retval TRUE    Multi-processor is supported.
41   @retval FALSE   Multi-processor is not supported.
42 
43 **/
44 BOOLEAN
MultiProcessorDebugSupport(VOID)45 MultiProcessorDebugSupport (
46   VOID
47   )
48 {
49   return FALSE;
50 }
51 
52 /**
53   Read the Attach/Break-in symbols from the debug port.
54 
55   @param[in]  Handle         Pointer to Debug Port handle.
56   @param[out] BreakSymbol    Returned break symbol.
57 
58   @retval EFI_SUCCESS        Read the symbol in BreakSymbol.
59   @retval EFI_NOT_FOUND      No read the break symbol.
60 
61 **/
62 EFI_STATUS
DebugReadBreakSymbol(IN DEBUG_PORT_HANDLE Handle,OUT UINT8 * BreakSymbol)63 DebugReadBreakSymbol (
64   IN  DEBUG_PORT_HANDLE      Handle,
65   OUT UINT8                  *BreakSymbol
66   )
67 {
68   EFI_STATUS                 Status;
69   DEBUG_PACKET_HEADER        DebugHeader;
70   UINT8                      *Data8;
71 
72   *BreakSymbol = 0;
73   //
74   // If Debug Port buffer has data, read it till it was break symbol or Debug Port buffer empty.
75   //
76   Data8 = (UINT8 *) &DebugHeader;
77   while (TRUE) {
78     //
79     // If start symbol is not received
80     //
81     if (!DebugPortPollBuffer (Handle)) {
82       //
83       // If no data in Debug Port, exit
84       //
85       break;
86     }
87     //
88     // Try to read the start symbol
89     //
90     DebugAgentReadBuffer (Handle, Data8, 1, 0);
91     if (*Data8 == DEBUG_STARTING_SYMBOL_ATTACH) {
92       *BreakSymbol = *Data8;
93       DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Debug Timer attach symbol received %x", *BreakSymbol);
94       return EFI_SUCCESS;
95     }
96     if (*Data8 == DEBUG_STARTING_SYMBOL_NORMAL) {
97       Status = ReadRemainingBreakPacket (Handle, &DebugHeader);
98       if (Status == EFI_SUCCESS) {
99         *BreakSymbol = DebugHeader.Command;
100         DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Debug Timer break symbol received %x", *BreakSymbol);
101         return EFI_SUCCESS;
102       }
103       if (Status == EFI_TIMEOUT) {
104         break;
105       }
106     }
107   }
108 
109   return EFI_NOT_FOUND;
110 }
111 
112 /**
113   Get the pointer to location saved Mailbox pointer from IDT entry.
114 
115 **/
116 VOID *
GetLocationSavedMailboxPointerInIdtEntry(VOID)117 GetLocationSavedMailboxPointerInIdtEntry (
118   VOID
119   )
120 {
121   UINTN                     *MailboxLocation;
122 
123   MailboxLocation = (UINTN *) GetExceptionHandlerInIdtEntry (DEBUG_MAILBOX_VECTOR);
124   //
125   // *MailboxLocation is the pointer to Mailbox
126   //
127   VerifyMailboxChecksum ((DEBUG_AGENT_MAILBOX *) (*MailboxLocation));
128   return MailboxLocation;
129 }
130 
131 /**
132   Set the pointer of Mailbox into IDT entry before memory is ready.
133 
134   @param[in]  MailboxLocation    Pointer to location saved Mailbox pointer.
135 
136 **/
137 VOID
SetLocationSavedMailboxPointerInIdtEntry(IN VOID * MailboxLocation)138 SetLocationSavedMailboxPointerInIdtEntry (
139   IN VOID                  *MailboxLocation
140   )
141 {
142   SetExceptionHandlerInIdtEntry (DEBUG_MAILBOX_VECTOR, MailboxLocation);
143 }
144 
145 /**
146   Get the location of Mailbox pointer from the GUIDed HOB.
147 
148   @return Pointer to the location saved Mailbox pointer.
149 
150 **/
151 UINT64 *
GetMailboxLocationFromHob(VOID)152 GetMailboxLocationFromHob (
153   VOID
154   )
155 {
156   EFI_HOB_GUID_TYPE        *GuidHob;
157 
158   GuidHob = GetFirstGuidHob (&gEfiDebugAgentGuid);
159   if (GuidHob == NULL) {
160     return NULL;
161   }
162   return (UINT64 *) (GET_GUID_HOB_DATA(GuidHob));
163 }
164 
165 /**
166   Get Debug Agent Mailbox pointer.
167 
168   @return Mailbox pointer.
169 
170 **/
171 DEBUG_AGENT_MAILBOX *
GetMailboxPointer(VOID)172 GetMailboxPointer (
173   VOID
174   )
175 {
176   UINT64               DebugPortHandle;
177   UINT64               *MailboxLocationInIdt;
178   UINT64               *MailboxLocationInHob;
179   DEBUG_AGENT_MAILBOX  *Mailbox;
180 
181   //
182   // Get mailbox from IDT entry firstly
183   //
184   MailboxLocationInIdt = GetLocationSavedMailboxPointerInIdtEntry ();
185   Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocationInIdt);
186   //
187   // Cannot used GetDebugFlag() to get Debug Flag to avoid GetMailboxPointer() nested
188   //
189   if (Mailbox->DebugFlag.Bits.CheckMailboxInHob != 1 ||
190       Mailbox->DebugFlag.Bits.InitArch != DEBUG_ARCH_SYMBOL) {
191     //
192     // If mailbox was setup in SEC or the current CPU arch is different from the init arch
193     // Debug Agent initialized, return the mailbox from IDT entry directly.
194     // Otherwise, we need to check the mailbox location saved in GUIDed HOB further.
195     //
196     return Mailbox;
197   }
198 
199   MailboxLocationInHob = GetMailboxLocationFromHob ();
200   //
201   // Compare mailbox in IDT entry with mailbox in HOB,
202   // need to fix mailbox location if HOB moved by PEI CORE
203   //
204   if (MailboxLocationInHob != MailboxLocationInIdt && MailboxLocationInHob != NULL) {
205     Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocationInHob);
206     //
207     // Fix up Debug Port handler and save new mailbox in IDT entry
208     //
209     Mailbox = (DEBUG_AGENT_MAILBOX *)((UINTN)Mailbox + ((UINTN)(MailboxLocationInHob) - (UINTN)MailboxLocationInIdt));
210     DebugPortHandle = (UINTN)Mailbox->DebugPortHandle + ((UINTN)(MailboxLocationInHob) - (UINTN)MailboxLocationInIdt);
211     UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle);
212     *MailboxLocationInHob = (UINT64)(UINTN)Mailbox;
213     SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationInHob);
214     //
215     // Clean CheckMailboxInHob flag
216     //
217     Mailbox->DebugFlag.Bits.CheckMailboxInHob = 0;
218     UpdateMailboxChecksum (Mailbox);
219   }
220 
221   return Mailbox;
222 }
223 
224 /**
225   Get debug port handle.
226 
227   @return Debug port handle.
228 
229 **/
230 DEBUG_PORT_HANDLE
GetDebugPortHandle(VOID)231 GetDebugPortHandle (
232   VOID
233   )
234 {
235   DEBUG_AGENT_MAILBOX    *DebugAgentMailbox;
236 
237   DebugAgentMailbox = GetMailboxPointer ();
238 
239   return (DEBUG_PORT_HANDLE) (UINTN)(DebugAgentMailbox->DebugPortHandle);
240 }
241 
242 /**
243   Debug Agent provided notify callback function on Memory Discovered PPI.
244 
245   @param[in] PeiServices      Indirect reference to the PEI Services Table.
246   @param[in] NotifyDescriptor Address of the notification descriptor data structure.
247   @param[in] Ppi              Address of the PPI that was installed.
248 
249   @retval EFI_SUCCESS If the function completed successfully.
250 
251 **/
252 EFI_STATUS
253 EFIAPI
DebugAgentCallbackMemoryDiscoveredPpi(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_NOTIFY_DESCRIPTOR * NotifyDescriptor,IN VOID * Ppi)254 DebugAgentCallbackMemoryDiscoveredPpi (
255   IN EFI_PEI_SERVICES                     **PeiServices,
256   IN EFI_PEI_NOTIFY_DESCRIPTOR            *NotifyDescriptor,
257   IN VOID                                 *Ppi
258   )
259 {
260   EFI_STATUS                     Status;
261   DEBUG_AGENT_MAILBOX            *Mailbox;
262   BOOLEAN                        InterruptStatus;
263   EFI_PHYSICAL_ADDRESS           Address;
264   DEBUG_AGENT_MAILBOX            *NewMailbox;
265   UINT64                         *MailboxLocationInHob;
266 
267   //
268   // Save and disable original interrupt status
269   //
270   InterruptStatus = SaveAndDisableInterrupts ();
271 
272   //
273   // Allocate ACPI NVS memory for new Mailbox and Debug Port Handle buffer
274   //
275   Status = PeiServicesAllocatePages (
276              EfiACPIMemoryNVS,
277              EFI_SIZE_TO_PAGES (sizeof(DEBUG_AGENT_MAILBOX) + PcdGet16(PcdDebugPortHandleBufferSize)),
278              &Address
279              );
280   ASSERT_EFI_ERROR (Status);
281   NewMailbox = (DEBUG_AGENT_MAILBOX *) (UINTN) Address;
282   //
283   // Copy Mailbox and Debug Port Handle buffer to new location in ACPI NVS memory, because original Mailbox
284   // and Debug Port Handle buffer in the allocated pool that may be marked as free by DXE Core after DXE Core
285   // reallocates the HOB.
286   //
287   Mailbox = GetMailboxPointer ();
288   CopyMem (NewMailbox, Mailbox, sizeof (DEBUG_AGENT_MAILBOX));
289   CopyMem (NewMailbox + 1, (VOID *)(UINTN)Mailbox->DebugPortHandle, PcdGet16(PcdDebugPortHandleBufferSize));
290   //
291   // Update Mailbox Location pointer in GUIDed HOB and IDT entry with new one
292   //
293   MailboxLocationInHob = GetMailboxLocationFromHob ();
294   ASSERT (MailboxLocationInHob != NULL);
295   *MailboxLocationInHob = (UINT64)(UINTN)NewMailbox;
296   SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationInHob);
297   //
298   // Update Debug Port Handle in new Mailbox
299   //
300   UpdateMailboxContent (NewMailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, (UINT64)(UINTN)(NewMailbox + 1));
301   //
302   // Set physical memory ready flag
303   //
304   SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1);
305 
306   if (IsHostAttached ()) {
307     //
308     // Trigger one software interrupt to inform HOST
309     //
310     TriggerSoftInterrupt (MEMORY_READY_SIGNATURE);
311   }
312 
313   //
314   // Restore interrupt state.
315   //
316   SetInterruptState (InterruptStatus);
317 
318   return EFI_SUCCESS;
319 }
320 
321 /**
322   Initialize debug agent.
323 
324   This function is used to set up debug environment for SEC and PEI phase.
325 
326   If InitFlag is DEBUG_AGENT_INIT_PREMEM_SEC, it will override IDT table entries
327   and initialize debug port. It will enable interrupt to support break-in feature.
328   It will set up debug agent Mailbox in cache-as-ramfrom. It will be called before
329   physical memory is ready.
330   If InitFlag is DEBUG_AGENT_INIT_POSTMEM_SEC, debug agent will build one GUIDed
331   HOB to copy debug agent Mailbox. It will be called after physical memory is ready.
332 
333   This function is used to set up debug environment to support source level debugging.
334   If certain Debug Agent Library instance has to save some private data in the stack,
335   this function must work on the mode that doesn't return to the caller, then
336   the caller needs to wrap up all rest of logic after InitializeDebugAgent() into one
337   function and pass it into InitializeDebugAgent(). InitializeDebugAgent() is
338   responsible to invoke the passing-in function at the end of InitializeDebugAgent().
339 
340   If the parameter Function is not NULL, Debug Agent Library instance will invoke it by
341   passing in the Context to be its parameter.
342 
343   If Function() is NULL, Debug Agent Library instance will return after setup debug
344   environment.
345 
346   @param[in] InitFlag     Init flag is used to decide the initialize process.
347   @param[in] Context      Context needed according to InitFlag; it was optional.
348   @param[in] Function     Continue function called by debug agent library; it was
349                           optional.
350 
351 **/
352 VOID
353 EFIAPI
InitializeDebugAgent(IN UINT32 InitFlag,IN VOID * Context,OPTIONAL IN DEBUG_AGENT_CONTINUE Function OPTIONAL)354 InitializeDebugAgent (
355   IN UINT32                InitFlag,
356   IN VOID                  *Context, OPTIONAL
357   IN DEBUG_AGENT_CONTINUE  Function  OPTIONAL
358   )
359 {
360   DEBUG_AGENT_MAILBOX              *Mailbox;
361   DEBUG_AGENT_MAILBOX              *NewMailbox;
362   DEBUG_AGENT_MAILBOX              MailboxInStack;
363   DEBUG_AGENT_PHASE2_CONTEXT       Phase2Context;
364   DEBUG_AGENT_CONTEXT_POSTMEM_SEC  *DebugAgentContext;
365   EFI_STATUS                       Status;
366   IA32_DESCRIPTOR                  *Ia32Idtr;
367   IA32_IDT_ENTRY                   *Ia32IdtEntry;
368   UINT64                           DebugPortHandle;
369   UINT64                           MailboxLocation;
370   UINT64                           *MailboxLocationPointer;
371   EFI_PHYSICAL_ADDRESS             Address;
372   UINT32                           DebugTimerFrequency;
373   BOOLEAN                          CpuInterruptState;
374 
375   //
376   // Disable interrupts and save current interrupt state
377   //
378   CpuInterruptState = SaveAndDisableInterrupts();
379 
380   switch (InitFlag) {
381 
382   case DEBUG_AGENT_INIT_PREMEM_SEC:
383 
384     InitializeDebugIdt ();
385 
386     MailboxLocation = (UINT64)(UINTN)&MailboxInStack;
387     Mailbox = &MailboxInStack;
388     ZeroMem ((VOID *) Mailbox, sizeof (DEBUG_AGENT_MAILBOX));
389     //
390     // Get and save debug port handle and set the length of memory block.
391     //
392     SetLocationSavedMailboxPointerInIdtEntry (&MailboxLocation);
393     //
394     // Force error message could be printed during the first shakehand between Target/HOST.
395     //
396     SetDebugFlag (DEBUG_AGENT_FLAG_PRINT_ERROR_LEVEL, DEBUG_AGENT_ERROR);
397     //
398     // Save init arch type when debug agent initialized
399     //
400     SetDebugFlag (DEBUG_AGENT_FLAG_INIT_ARCH, DEBUG_ARCH_SYMBOL);
401     //
402     // Initialize Debug Timer hardware and save its frequency
403     //
404     InitializeDebugTimer (&DebugTimerFrequency, TRUE);
405     UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY, DebugTimerFrequency);
406 
407     Phase2Context.InitFlag = InitFlag;
408     Phase2Context.Context  = Context;
409     Phase2Context.Function = Function;
410     DebugPortInitialize ((VOID *) &Phase2Context, InitializeDebugAgentPhase2);
411     //
412     // If reaches here, it means Debug Port initialization failed.
413     //
414     DEBUG ((EFI_D_ERROR, "Debug Agent: Debug port initialization failed.\n"));
415 
416     break;
417 
418   case DEBUG_AGENT_INIT_POSTMEM_SEC:
419     Mailbox = GetMailboxPointer ();
420     //
421     // Memory has been ready
422     //
423     SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1);
424     if (IsHostAttached ()) {
425       //
426       // Trigger one software interrupt to inform HOST
427       //
428       TriggerSoftInterrupt (MEMORY_READY_SIGNATURE);
429     }
430     //
431     // Install Vector Handoff Info PPI to persist vectors used by Debug Agent
432     //
433     Status = PeiServicesInstallPpi (&mVectorHandoffInfoPpiList[0]);
434     if (EFI_ERROR (Status)) {
435       DEBUG ((EFI_D_ERROR, "DebugAgent: Failed to install Vector Handoff Info PPI!\n"));
436       CpuDeadLoop ();
437     }
438     //
439     // Fix up Debug Port handle address and mailbox address
440     //
441     DebugAgentContext = (DEBUG_AGENT_CONTEXT_POSTMEM_SEC *) Context;
442     if (DebugAgentContext != NULL) {
443       DebugPortHandle = (UINT64)(UINT32)(Mailbox->DebugPortHandle + DebugAgentContext->StackMigrateOffset);
444       UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle);
445       Mailbox = (DEBUG_AGENT_MAILBOX *) ((UINTN) Mailbox + DebugAgentContext->StackMigrateOffset);
446       MailboxLocation = (UINT64)(UINTN)Mailbox;
447       //
448       // Build mailbox location in HOB and fix-up its address
449       //
450       MailboxLocationPointer = BuildGuidDataHob (
451                                  &gEfiDebugAgentGuid,
452                                  &MailboxLocation,
453                                  sizeof (UINT64)
454                                  );
455       MailboxLocationPointer = (UINT64 *) ((UINTN) MailboxLocationPointer + DebugAgentContext->HeapMigrateOffset);
456     } else {
457       //
458       // DebugAgentContext is NULL. Then, Mailbox can directly be copied into memory.
459       // Allocate ACPI NVS memory for new Mailbox and Debug Port Handle buffer
460       //
461       Status = PeiServicesAllocatePages (
462                  EfiACPIMemoryNVS,
463                  EFI_SIZE_TO_PAGES (sizeof(DEBUG_AGENT_MAILBOX) + PcdGet16(PcdDebugPortHandleBufferSize)),
464                  &Address
465                  );
466       if (EFI_ERROR (Status)) {
467         DEBUG ((EFI_D_ERROR, "DebugAgent: Failed to allocate pages!\n"));
468         CpuDeadLoop ();
469       }
470       NewMailbox = (DEBUG_AGENT_MAILBOX *) (UINTN) Address;
471       //
472       // Copy Mailbox and Debug Port Handle buffer to new location in ACPI NVS memory, because original Mailbox
473       // and Debug Port Handle buffer in the allocated pool that may be marked as free by DXE Core after DXE Core
474       // reallocates the HOB.
475       //
476       CopyMem (NewMailbox, Mailbox, sizeof (DEBUG_AGENT_MAILBOX));
477       CopyMem (NewMailbox + 1, (VOID *)(UINTN)Mailbox->DebugPortHandle, PcdGet16(PcdDebugPortHandleBufferSize));
478       UpdateMailboxContent (NewMailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, (UINT64)(UINTN)(NewMailbox + 1));
479       MailboxLocation = (UINT64)(UINTN)NewMailbox;
480       //
481       // Build mailbox location in HOB
482       //
483       MailboxLocationPointer = BuildGuidDataHob (
484                                  &gEfiDebugAgentGuid,
485                                  &MailboxLocation,
486                                  sizeof (UINT64)
487                                  );
488     }
489     //
490     // Update IDT entry to save the location saved mailbox pointer
491     //
492     SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationPointer);
493     break;
494 
495   case DEBUG_AGENT_INIT_PEI:
496     if (Context == NULL) {
497       DEBUG ((EFI_D_ERROR, "DebugAgent: Input parameter Context cannot be NULL!\n"));
498       CpuDeadLoop ();
499     }
500     //
501     // Check if Debug Agent has initialized before
502     //
503     if (IsDebugAgentInitialzed()) {
504       DEBUG ((EFI_D_WARN, "Debug Agent: It has already initialized in SEC Core!\n"));
505       break;
506     }
507     //
508     // Install Vector Handoff Info PPI to persist vectors used by Debug Agent
509     //
510     Status = PeiServicesInstallPpi (&mVectorHandoffInfoPpiList[0]);
511     if (EFI_ERROR (Status)) {
512       DEBUG ((EFI_D_ERROR, "DebugAgent: Failed to install Vector Handoff Info PPI!\n"));
513       CpuDeadLoop ();
514     }
515     //
516     // Set up IDT entries
517     //
518     InitializeDebugIdt ();
519     //
520     // Build mailbox in HOB and setup Mailbox Set In Pei flag
521     //
522     Mailbox = AllocateZeroPool (sizeof (DEBUG_AGENT_MAILBOX));
523     if (Mailbox == NULL) {
524       DEBUG ((EFI_D_ERROR, "DebugAgent: Failed to allocate memory!\n"));
525       CpuDeadLoop ();
526     } else {
527       MailboxLocation = (UINT64)(UINTN)Mailbox;
528       MailboxLocationPointer = BuildGuidDataHob (
529                                  &gEfiDebugAgentGuid,
530                                  &MailboxLocation,
531                                  sizeof (UINT64)
532                                  );
533       //
534       // Initialize Debug Timer hardware and save its frequency
535       //
536       InitializeDebugTimer (&DebugTimerFrequency, TRUE);
537       UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY, DebugTimerFrequency);
538       //
539       // Update IDT entry to save the location pointer saved mailbox pointer
540       //
541       SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationPointer);
542     }
543     //
544     // Save init arch type when debug agent initialized
545     //
546     SetDebugFlag (DEBUG_AGENT_FLAG_INIT_ARCH, DEBUG_ARCH_SYMBOL);
547     //
548     // Register for a callback once memory has been initialized.
549     // If memory has been ready, the callback function will be invoked immediately
550     //
551     Status = PeiServicesNotifyPpi (&mDebugAgentMemoryDiscoveredNotifyList[0]);
552     if (EFI_ERROR (Status)) {
553       DEBUG ((EFI_D_ERROR, "DebugAgent: Failed to register memory discovered callback function!\n"));
554       CpuDeadLoop ();
555     }
556     //
557     // Set HOB check flag if memory has not been ready yet
558     //
559     if (GetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY) == 0) {
560       SetDebugFlag (DEBUG_AGENT_FLAG_CHECK_MAILBOX_IN_HOB, 1);
561     }
562 
563     Phase2Context.InitFlag = InitFlag;
564     Phase2Context.Context  = Context;
565     Phase2Context.Function = Function;
566     DebugPortInitialize ((VOID *) &Phase2Context, InitializeDebugAgentPhase2);
567 
568     FindAndReportModuleImageInfo (4);
569 
570     break;
571 
572   case DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64:
573     if (Context == NULL) {
574       DEBUG ((EFI_D_ERROR, "DebugAgent: Input parameter Context cannot be NULL!\n"));
575       CpuDeadLoop ();
576     } else {
577       Ia32Idtr =  (IA32_DESCRIPTOR *) Context;
578       Ia32IdtEntry = (IA32_IDT_ENTRY *)(Ia32Idtr->Base);
579       MailboxLocationPointer = (UINT64 *) ((UINTN) Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetLow +
580                                           ((UINTN) Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetHigh << 16));
581       Mailbox = (DEBUG_AGENT_MAILBOX *) (UINTN)(*MailboxLocationPointer);
582       //
583       // Mailbox should valid and setup before executing thunk code
584       //
585       VerifyMailboxChecksum (Mailbox);
586 
587       DebugPortHandle = (UINT64) (UINTN)DebugPortInitialize ((VOID *)(UINTN)Mailbox->DebugPortHandle, NULL);
588       UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle);
589       //
590       // Set up IDT entries
591       //
592       InitializeDebugIdt ();
593       //
594       // Update IDT entry to save location pointer saved the mailbox pointer
595       //
596       SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationPointer);
597 
598       FindAndReportModuleImageInfo (4);
599     }
600     break;
601 
602   default:
603     //
604     // Only DEBUG_AGENT_INIT_PREMEM_SEC and DEBUG_AGENT_INIT_POSTMEM_SEC are allowed for this
605     // Debug Agent library instance.
606     //
607     DEBUG ((EFI_D_ERROR, "Debug Agent: The InitFlag value is not allowed!\n"));
608     CpuDeadLoop ();
609     break;
610   }
611 
612   if (InitFlag == DEBUG_AGENT_INIT_POSTMEM_SEC) {
613     //
614     // Restore CPU Interrupt state and keep debug timer interrupt state as is
615     // in DEBUG_AGENT_INIT_POSTMEM_SEC case
616     //
617     SetInterruptState (CpuInterruptState);
618   } else {
619     //
620     // Enable Debug Timer interrupt
621     //
622     SaveAndSetDebugTimerInterrupt (TRUE);
623     //
624     // Enable CPU interrupts so debug timer interrupts can be delivered
625     //
626     EnableInterrupts ();
627   }
628   //
629   // If Function is not NULL, invoke it always whatever debug agent was initialized successfully or not.
630   //
631   if (Function != NULL) {
632     Function (Context);
633   }
634   //
635   // Set return status for DEBUG_AGENT_INIT_PEI
636   //
637   if (InitFlag == DEBUG_AGENT_INIT_PEI && Context != NULL) {
638     *(EFI_STATUS *)Context = EFI_SUCCESS;
639   }
640 }
641 
642 /**
643   Caller provided function to be invoked at the end of DebugPortInitialize().
644 
645   Refer to the description for DebugPortInitialize() for more details.
646 
647   @param[in] Context           The first input argument of DebugPortInitialize().
648   @param[in] DebugPortHandle   Debug port handle created by Debug Communication Library.
649 
650 **/
651 VOID
652 EFIAPI
InitializeDebugAgentPhase2(IN VOID * Context,IN DEBUG_PORT_HANDLE DebugPortHandle)653 InitializeDebugAgentPhase2 (
654   IN VOID                  *Context,
655   IN DEBUG_PORT_HANDLE     DebugPortHandle
656   )
657 {
658   DEBUG_AGENT_PHASE2_CONTEXT *Phase2Context;
659   UINT64                     *MailboxLocation;
660   DEBUG_AGENT_MAILBOX        *Mailbox;
661   EFI_SEC_PEI_HAND_OFF       *SecCoreData;
662   UINT16                     BufferSize;
663   UINT64                     NewDebugPortHandle;
664 
665   Phase2Context = (DEBUG_AGENT_PHASE2_CONTEXT *) Context;
666   MailboxLocation = GetLocationSavedMailboxPointerInIdtEntry ();
667   Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation);
668   BufferSize = PcdGet16(PcdDebugPortHandleBufferSize);
669   if (Phase2Context->InitFlag == DEBUG_AGENT_INIT_PEI && BufferSize != 0) {
670     NewDebugPortHandle = (UINT64)(UINTN)AllocateCopyPool (BufferSize, DebugPortHandle);
671   } else {
672     NewDebugPortHandle = (UINT64)(UINTN)DebugPortHandle;
673   }
674   UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, NewDebugPortHandle);
675 
676   //
677   // Trigger one software interrupt to inform HOST
678   //
679   TriggerSoftInterrupt (SYSTEM_RESET_SIGNATURE);
680 
681   if (Phase2Context->InitFlag == DEBUG_AGENT_INIT_PREMEM_SEC) {
682     //
683     // If Temporary RAM region is below 128 MB, then send message to
684     // host to disable low memory filtering.
685     //
686     SecCoreData = (EFI_SEC_PEI_HAND_OFF *)Phase2Context->Context;
687     if ((UINTN)SecCoreData->TemporaryRamBase < BASE_128MB && IsHostAttached ()) {
688       SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1);
689       TriggerSoftInterrupt (MEMORY_READY_SIGNATURE);
690     }
691     //
692     // Enable Debug Timer interrupt
693     //
694     SaveAndSetDebugTimerInterrupt (TRUE);
695     //
696     // Enable CPU interrupts so debug timer interrupts can be delivered
697     //
698     EnableInterrupts ();
699     //
700     // Call continuation function if it is not NULL.
701     //
702     Phase2Context->Function (Phase2Context->Context);
703   }
704 }
705