2 SEC Core Debug Agent Library instance implementition.
4 Copyright (c) 2010 - 2013, 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.
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.
15 #include "SecPeiDebugAgentLib.h"
17 BOOLEAN mSkipBreakpoint
= FALSE
;
19 EFI_PEI_NOTIFY_DESCRIPTOR mMemoryDiscoveredNotifyList
[1] = {
21 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
22 &gEfiPeiMemoryDiscoveredPpiGuid
,
23 DebugAgentCallbackMemoryDiscoveredPpi
28 Check if debug agent support multi-processor.
30 @retval TRUE Multi-processor is supported.
31 @retval FALSE Multi-processor is not supported.
35 MultiProcessorDebugSupport (
43 Read the Attach/Break-in symbols from the debug port.
45 @param[in] Handle Pointer to Debug Port handle.
46 @param[out] BreakSymbol Returned break symbol.
48 @retval EFI_SUCCESS Read the symbol in BreakSymbol.
49 @retval EFI_NOT_FOUND No read the break symbol.
53 DebugReadBreakSymbol (
54 IN DEBUG_PORT_HANDLE Handle
,
55 OUT UINT8
*BreakSymbol
59 DEBUG_PACKET_HEADER DebugHeader
;
64 // If Debug Port buffer has data, read it till it was break symbol or Debug Port buffer empty.
66 Data8
= (UINT8
*) &DebugHeader
;
69 // If start symbol is not received
71 if (!DebugPortPollBuffer (Handle
)) {
73 // If no data in Debug Port, exit
78 // Try to read the start symbol
80 DebugPortReadBuffer (Handle
, Data8
, 1, 0);
81 if (*Data8
== DEBUG_STARTING_SYMBOL_ATTACH
) {
82 *BreakSymbol
= *Data8
;
83 DebugAgentMsgPrint (DEBUG_AGENT_INFO
, "Debug Timer attach symbol received %x", *BreakSymbol
);
86 if (*Data8
== DEBUG_STARTING_SYMBOL_NORMAL
) {
87 Status
= ReadRemainingBreakPacket (Handle
, &DebugHeader
);
88 if (Status
== EFI_SUCCESS
) {
89 *BreakSymbol
= DebugHeader
.Command
;
90 DebugAgentMsgPrint (DEBUG_AGENT_INFO
, "Debug Timer break symbol received %x", *BreakSymbol
);
93 if (Status
== EFI_TIMEOUT
) {
103 Get the pointer to location saved Mailbox pointer from IDT entry.
107 GetLocationSavedMailboxPointerInIdtEntry (
111 UINTN
*MailboxLocation
;
113 MailboxLocation
= (UINTN
*) GetExceptionHandlerInIdtEntry (DEBUG_MAILBOX_VECTOR
);
115 // *MailboxLocation is the pointer to Mailbox
117 VerifyMailboxChecksum ((DEBUG_AGENT_MAILBOX
*) (*MailboxLocation
));
118 return MailboxLocation
;
122 Set the pointer of Mailbox into IDT entry before memory is ready.
124 @param[in] MailboxLocation Pointer to location saved Mailbox pointer.
128 SetLocationSavedMailboxPointerInIdtEntry (
129 IN VOID
*MailboxLocation
132 SetExceptionHandlerInIdtEntry (DEBUG_MAILBOX_VECTOR
, MailboxLocation
);
136 Get the location of Mailbox pointer from the GUIDed HOB.
138 @return Pointer to the location saved Mailbox pointer.
142 GetMailboxLocationFromHob (
146 EFI_HOB_GUID_TYPE
*GuidHob
;
148 GuidHob
= GetFirstGuidHob (&gEfiDebugAgentGuid
);
149 if (GuidHob
== NULL
) {
152 return (UINT64
*) (GET_GUID_HOB_DATA(GuidHob
));
156 Get Debug Agent Mailbox pointer.
158 @return Mailbox pointer.
161 DEBUG_AGENT_MAILBOX
*
166 UINT64 DebugPortHandle
;
167 UINT64
*MailboxLocationInIdt
;
168 UINT64
*MailboxLocationInHob
;
169 DEBUG_AGENT_MAILBOX
*Mailbox
;
172 // Get mailbox from IDT entry firstly
174 MailboxLocationInIdt
= GetLocationSavedMailboxPointerInIdtEntry ();
175 Mailbox
= (DEBUG_AGENT_MAILBOX
*)(UINTN
)(*MailboxLocationInIdt
);
177 // Cannot used GetDebugFlag() to get Debug Flag to avoid GetMailboxPointer() nested
179 if (Mailbox
->DebugFlag
.Bits
.CheckMailboxInHob
!= 1 ||
180 Mailbox
->DebugFlag
.Bits
.InitArch
!= DEBUG_ARCH_SYMBOL
) {
182 // If mailbox was setup in SEC or the current CPU arch is different from the init arch
183 // Debug Agent initialized, return the mailbox from IDT entry directly.
184 // Otherwise, we need to check the mailbox location saved in GUIDed HOB further.
189 MailboxLocationInHob
= GetMailboxLocationFromHob ();
191 // Compare mailbox in IDT enry with mailbox in HOB,
192 // need to fix mailbox location if HOB moved by PEI CORE
194 if (MailboxLocationInHob
!= MailboxLocationInIdt
&& MailboxLocationInHob
!= NULL
) {
195 Mailbox
= (DEBUG_AGENT_MAILBOX
*)(UINTN
)(*MailboxLocationInHob
);
197 // Fix up Debug Port handler and save new mailbox in IDT entry
199 Mailbox
= (DEBUG_AGENT_MAILBOX
*)((UINTN
)Mailbox
+ ((UINTN
)(MailboxLocationInHob
) - (UINTN
)MailboxLocationInIdt
));
200 DebugPortHandle
= (UINT64
)((UINTN
)Mailbox
->DebugPortHandle
+ ((UINTN
)(MailboxLocationInHob
) - (UINTN
)MailboxLocationInIdt
));
201 UpdateMailboxContent (Mailbox
, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX
, DebugPortHandle
);
202 *MailboxLocationInHob
= (UINT64
)(UINTN
)Mailbox
;
203 SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationInHob
);
205 // Clean CheckMailboxInHob flag
207 Mailbox
->DebugFlag
.Bits
.CheckMailboxInHob
= 0;
208 UpdateMailboxChecksum (Mailbox
);
215 Get debug port handle.
217 @return Debug port handle.
225 DEBUG_AGENT_MAILBOX
*DebugAgentMailbox
;
227 DebugAgentMailbox
= GetMailboxPointer ();
229 return (DEBUG_PORT_HANDLE
) (UINTN
)(DebugAgentMailbox
->DebugPortHandle
);
233 Debug Agent provided notify callback function on Memory Discovered PPI.
235 @param[in] PeiServices Indirect reference to the PEI Services Table.
236 @param[in] NotifyDescriptor Address of the notification descriptor data structure.
237 @param[in] Ppi Address of the PPI that was installed.
239 @retval EFI_SUCCESS If the function completed successfully.
244 DebugAgentCallbackMemoryDiscoveredPpi (
245 IN EFI_PEI_SERVICES
**PeiServices
,
246 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDescriptor
,
251 DEBUG_AGENT_MAILBOX
*Mailbox
;
252 BOOLEAN InterruptStatus
;
253 EFI_PHYSICAL_ADDRESS Address
;
254 DEBUG_AGENT_MAILBOX
*NewMailbox
;
255 UINT64
*MailboxLocationInHob
;
258 // Save and disable original interrupt status
260 InterruptStatus
= SaveAndDisableInterrupts ();
263 // Allocate ACPI NVS memory for new Mailbox and Debug Port Handle buffer
265 Status
= PeiServicesAllocatePages (
267 EFI_SIZE_TO_PAGES (sizeof(DEBUG_AGENT_MAILBOX
) + PcdGet16(PcdDebugPortHandleBufferSize
)),
270 ASSERT_EFI_ERROR (Status
);
271 NewMailbox
= (DEBUG_AGENT_MAILBOX
*) (UINTN
) Address
;
273 // Copy Mailbox and Debug Port Handle buffer to new location in ACPI NVS memory, because original Mailbox
274 // and Debug Port Handle buffer in the allocated pool that may be marked as free by DXE Core after DXE Core
275 // reallocates the HOB.
277 Mailbox
= GetMailboxPointer ();
278 CopyMem (NewMailbox
, Mailbox
, sizeof (DEBUG_AGENT_MAILBOX
));
279 CopyMem (NewMailbox
+ 1, (VOID
*)(UINTN
)Mailbox
->DebugPortHandle
, PcdGet16(PcdDebugPortHandleBufferSize
));
281 // Update Mailbox Location pointer in GUIDed HOB and IDT entry with new one
283 MailboxLocationInHob
= GetMailboxLocationFromHob ();
284 ASSERT (MailboxLocationInHob
!= NULL
);
285 *MailboxLocationInHob
= (UINT64
)(UINTN
)NewMailbox
;
286 SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationInHob
);
288 // Update Debug Port Handle in new Mailbox
290 UpdateMailboxContent (NewMailbox
, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX
, (UINT64
)(UINTN
)(NewMailbox
+ 1));
292 // Set physical memory ready flag
294 SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY
, 1);
296 if (IsHostAttached ()) {
298 // Trigger one software interrupt to inform HOST
300 TriggerSoftInterrupt (MEMORY_READY_SIGNATURE
);
304 // Restore interrupt state.
306 SetInterruptState (InterruptStatus
);
312 Initialize debug agent.
314 This function is used to set up debug environment for SEC and PEI phase.
316 If InitFlag is DEBUG_AGENT_INIT_PREMEM_SEC, it will overirde IDT table entries
317 and initialize debug port. It will enable interrupt to support break-in feature.
318 It will set up debug agent Mailbox in cache-as-ramfrom. It will be called before
319 physical memory is ready.
320 If InitFlag is DEBUG_AGENT_INIT_POSTMEM_SEC, debug agent will build one GUIDed
321 HOB to copy debug agent Mailbox. It will be called after physical memory is ready.
323 This function is used to set up debug environment to support source level debugging.
324 If certain Debug Agent Library instance has to save some private data in the stack,
325 this function must work on the mode that doesn't return to the caller, then
326 the caller needs to wrap up all rest of logic after InitializeDebugAgent() into one
327 function and pass it into InitializeDebugAgent(). InitializeDebugAgent() is
328 responsible to invoke the passing-in function at the end of InitializeDebugAgent().
330 If the parameter Function is not NULL, Debug Agent Libary instance will invoke it by
331 passing in the Context to be its parameter.
333 If Function() is NULL, Debug Agent Library instance will return after setup debug
336 @param[in] InitFlag Init flag is used to decide the initialize process.
337 @param[in] Context Context needed according to InitFlag; it was optional.
338 @param[in] Function Continue function called by debug agent library; it was
344 InitializeDebugAgent (
346 IN VOID
*Context
, OPTIONAL
347 IN DEBUG_AGENT_CONTINUE Function OPTIONAL
350 DEBUG_AGENT_MAILBOX
*Mailbox
;
351 DEBUG_AGENT_MAILBOX MailboxInStack
;
352 DEBUG_AGENT_PHASE2_CONTEXT Phase2Context
;
353 DEBUG_AGENT_CONTEXT_POSTMEM_SEC
*DebugAgentContext
;
355 IA32_DESCRIPTOR
*Ia32Idtr
;
356 IA32_IDT_ENTRY
*Ia32IdtEntry
;
357 UINT64 DebugPortHandle
;
358 UINT64 MailboxLocation
;
359 UINT64
*MailboxLocationPointer
;
361 DisableInterrupts ();
365 case DEBUG_AGENT_INIT_PREMEM_SEC
:
367 InitializeDebugIdt ();
369 MailboxLocation
= (UINT64
)(UINTN
)&MailboxInStack
;
370 Mailbox
= &MailboxInStack
;
371 ZeroMem ((VOID
*) Mailbox
, sizeof (DEBUG_AGENT_MAILBOX
));
373 // Get and save debug port handle and set the length of memory block.
375 SetLocationSavedMailboxPointerInIdtEntry (&MailboxLocation
);
377 // Force error message could be printed during the first shakehand between Target/HOST.
379 SetDebugFlag (DEBUG_AGENT_FLAG_PRINT_ERROR_LEVEL
, DEBUG_AGENT_ERROR
);
381 // Save init arch type when debug agent initialized
383 SetDebugFlag (DEBUG_AGENT_FLAG_INIT_ARCH
, DEBUG_ARCH_SYMBOL
);
385 InitializeDebugTimer ();
387 Phase2Context
.Context
= Context
;
388 Phase2Context
.Function
= Function
;
389 DebugPortInitialize ((VOID
*) &Phase2Context
, InitializeDebugAgentPhase2
);
391 // If reaches here, it means Debug Port initialization failed.
393 DEBUG ((EFI_D_ERROR
, "Debug Agent: Debug port initialization failed.\n"));
397 case DEBUG_AGENT_INIT_POSTMEM_SEC
:
398 Mailbox
= GetMailboxPointer ();
400 // Memory has been ready
402 SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY
, 1);
403 if (IsHostAttached ()) {
405 // Trigger one software interrupt to inform HOST
407 TriggerSoftInterrupt (MEMORY_READY_SIGNATURE
);
411 // Fix up Debug Port handle address and mailbox address
413 DebugAgentContext
= (DEBUG_AGENT_CONTEXT_POSTMEM_SEC
*) Context
;
414 DebugPortHandle
= (UINT64
)(UINT32
)(Mailbox
->DebugPortHandle
+ DebugAgentContext
->StackMigrateOffset
);
415 UpdateMailboxContent (Mailbox
, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX
, DebugPortHandle
);
416 Mailbox
= (DEBUG_AGENT_MAILBOX
*) ((UINTN
) Mailbox
+ DebugAgentContext
->StackMigrateOffset
);
417 MailboxLocation
= (UINT64
)(UINTN
)Mailbox
;
419 // Build mailbox location in HOB and fix-up its address
421 MailboxLocationPointer
= BuildGuidDataHob (
426 MailboxLocationPointer
= (UINT64
*) ((UINTN
) MailboxLocationPointer
+ DebugAgentContext
->HeapMigrateOffset
);
428 // Update IDT entry to save the location saved mailbox pointer
430 SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationPointer
);
432 // Enable CPU interrupts so debug timer interrupts can be delivered
438 case DEBUG_AGENT_INIT_PEI
:
440 // Check if Debug Agent has initialized before
442 if (IsDebugAgentInitialzed()) {
443 DEBUG ((EFI_D_WARN
, "Debug Agent: It has already initialized in SEC Core!\n"));
447 // Set up IDT entries
449 InitializeDebugIdt ();
451 // Build mailbox in HOB and setup Mailbox Set In Pei flag
453 Mailbox
= AllocateZeroPool (sizeof (DEBUG_AGENT_MAILBOX
));
454 MailboxLocation
= (UINT64
)(UINTN
)Mailbox
;
455 MailboxLocationPointer
= BuildGuidDataHob (
461 InitializeDebugTimer ();
463 // Update IDT entry to save the location pointer saved mailbox pointer
465 SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationPointer
);
467 // Save init arch type when debug agent initialized
469 SetDebugFlag (DEBUG_AGENT_FLAG_INIT_ARCH
, DEBUG_ARCH_SYMBOL
);
471 // Register for a callback once memory has been initialized.
472 // If memery has been ready, the callback funtion will be invoked immediately
474 Status
= PeiServicesNotifyPpi (&mMemoryDiscoveredNotifyList
[0]);
475 ASSERT_EFI_ERROR (Status
);
477 // Set HOB check flag if memory has not been ready yet
479 if (GetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY
) == 0) {
480 SetDebugFlag (DEBUG_AGENT_FLAG_CHECK_MAILBOX_IN_HOB
, 1);
483 Phase2Context
.Context
= Context
;
484 Phase2Context
.Function
= Function
;
485 DebugPortInitialize ((VOID
*) &Phase2Context
, InitializeDebugAgentPhase2
);
487 FindAndReportModuleImageInfo (4);
491 case DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64
:
492 if (Context
== NULL
) {
493 DEBUG ((EFI_D_ERROR
, "DebugAgent: Input parameter Context cannot be NULL!\n"));
496 Ia32Idtr
= (IA32_DESCRIPTOR
*) Context
;
497 Ia32IdtEntry
= (IA32_IDT_ENTRY
*)(Ia32Idtr
->Base
);
498 MailboxLocationPointer
= (UINT64
*) (UINTN
) (Ia32IdtEntry
[DEBUG_MAILBOX_VECTOR
].Bits
.OffsetLow
+
499 (Ia32IdtEntry
[DEBUG_MAILBOX_VECTOR
].Bits
.OffsetHigh
<< 16));
500 Mailbox
= (DEBUG_AGENT_MAILBOX
*) (UINTN
)(*MailboxLocationPointer
);
502 // Mailbox should valid and setup before executing thunk code
504 VerifyMailboxChecksum (Mailbox
);
506 DebugPortHandle
= (UINT64
) (UINTN
)DebugPortInitialize ((VOID
*)(UINTN
)Mailbox
->DebugPortHandle
, NULL
);
507 UpdateMailboxContent (Mailbox
, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX
, DebugPortHandle
);
509 // Set up IDT entries
511 InitializeDebugIdt ();
513 // Update IDT entry to save location pointer saved the mailbox pointer
515 SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationPointer
);
517 FindAndReportModuleImageInfo (4);
523 // Only DEBUG_AGENT_INIT_PREMEM_SEC and DEBUG_AGENT_INIT_POSTMEM_SEC are allowed for this
524 // Debug Agent library instance.
526 DEBUG ((EFI_D_ERROR
, "Debug Agent: The InitFlag value is not allowed!\n"));
534 // If Function is not NULL, invoke it always whatever debug agent was initialized sucesssfully or not.
536 if (Function
!= NULL
) {
542 Caller provided function to be invoked at the end of DebugPortInitialize().
544 Refer to the descrption for DebugPortInitialize() for more details.
546 @param[in] Context The first input argument of DebugPortInitialize().
547 @param[in] DebugPortHandle Debug port handle created by Debug Communication Libary.
552 InitializeDebugAgentPhase2 (
554 IN DEBUG_PORT_HANDLE DebugPortHandle
557 DEBUG_AGENT_PHASE2_CONTEXT
*Phase2Context
;
558 UINT64
*MailboxLocation
;
559 DEBUG_AGENT_MAILBOX
*Mailbox
;
560 EFI_SEC_PEI_HAND_OFF
*SecCoreData
;
562 UINT64 NewDebugPortHandle
;
564 Phase2Context
= (DEBUG_AGENT_PHASE2_CONTEXT
*) Context
;
565 MailboxLocation
= GetLocationSavedMailboxPointerInIdtEntry ();
566 Mailbox
= (DEBUG_AGENT_MAILBOX
*)(UINTN
)(*MailboxLocation
);
567 BufferSize
= PcdGet16(PcdDebugPortHandleBufferSize
);
568 if (Phase2Context
->Function
== NULL
&& DebugPortHandle
!= NULL
&& BufferSize
!= 0) {
569 NewDebugPortHandle
= (UINT64
)(UINTN
)AllocateCopyPool (BufferSize
, DebugPortHandle
);
571 NewDebugPortHandle
= (UINT64
)(UINTN
)DebugPortHandle
;
573 UpdateMailboxContent (Mailbox
, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX
, NewDebugPortHandle
);
576 // Trigger one software interrupt to inform HOST
578 TriggerSoftInterrupt (SYSTEM_RESET_SIGNATURE
);
581 // If Temporary RAM region is below 128 MB, then send message to
582 // host to disable low memory filtering.
584 SecCoreData
= (EFI_SEC_PEI_HAND_OFF
*)Phase2Context
->Context
;
585 if ((UINTN
)SecCoreData
->TemporaryRamBase
< BASE_128MB
&& IsHostAttached ()) {
586 SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY
, 1);
587 TriggerSoftInterrupt (MEMORY_READY_SIGNATURE
);
591 // Enable CPU interrupts so debug timer interrupts can be delivered
596 // Call continuation function if it is not NULL.
598 if (Phase2Context
->Function
!= NULL
) {
599 Phase2Context
->Function (Phase2Context
->Context
);