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 // Check if mailbox was setup in PEI firstly, cannot used GetDebugFlag() to
178 // get CheckMailboxInHob flag to avoid GetMailboxPointer() nesting.
180 if (Mailbox
->DebugFlag
.Bits
.CheckMailboxInHob
!= 1) {
182 // If mailbox in IDT entry has already been the final one
187 MailboxLocationInHob
= GetMailboxLocationFromHob ();
189 // Compare mailbox in IDT enry with mailbox in HOB
191 if (MailboxLocationInHob
!= MailboxLocationInIdt
&& MailboxLocationInHob
!= NULL
) {
192 Mailbox
= (DEBUG_AGENT_MAILBOX
*)(UINTN
)(*MailboxLocationInHob
);
194 // Fix up Debug Port handler and save new mailbox in IDT entry
196 Mailbox
= (DEBUG_AGENT_MAILBOX
*)((UINTN
)Mailbox
+ ((UINTN
)(MailboxLocationInHob
) - (UINTN
)MailboxLocationInIdt
));
197 DebugPortHandle
= (UINT64
)((UINTN
)Mailbox
->DebugPortHandle
+ ((UINTN
)(MailboxLocationInHob
) - (UINTN
)MailboxLocationInIdt
));
198 UpdateMailboxContent (Mailbox
, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX
, DebugPortHandle
);
199 *MailboxLocationInHob
= (UINT64
)(UINTN
)Mailbox
;
200 SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationInHob
);
202 // Clean CheckMailboxInHob flag
204 Mailbox
->DebugFlag
.Bits
.CheckMailboxInHob
= 0;
205 UpdateMailboxChecksum (Mailbox
);
212 Get debug port handle.
214 @return Debug port handle.
222 DEBUG_AGENT_MAILBOX
*DebugAgentMailbox
;
224 DebugAgentMailbox
= GetMailboxPointer ();
226 return (DEBUG_PORT_HANDLE
) (UINTN
)(DebugAgentMailbox
->DebugPortHandle
);
230 Debug Agent provided notify callback function on Memory Discovered PPI.
232 @param[in] PeiServices Indirect reference to the PEI Services Table.
233 @param[in] NotifyDescriptor Address of the notification descriptor data structure.
234 @param[in] Ppi Address of the PPI that was installed.
236 @retval EFI_SUCCESS If the function completed successfully.
241 DebugAgentCallbackMemoryDiscoveredPpi (
242 IN EFI_PEI_SERVICES
**PeiServices
,
243 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDescriptor
,
248 DEBUG_AGENT_MAILBOX
*Mailbox
;
249 BOOLEAN InterruptStatus
;
250 EFI_PHYSICAL_ADDRESS Memory
;
251 DEBUG_AGENT_MAILBOX
*NewMailbox
;
252 UINT64
*MailboxLocationInHob
;
255 // Save and disable original interrupt status
257 InterruptStatus
= SaveAndDisableInterrupts ();
260 // Allocate ACPI NVS memory for new Mailbox and Debug Port Handle buffer
262 Status
= PeiServicesAllocatePages (
264 EFI_SIZE_TO_PAGES (sizeof(DEBUG_AGENT_MAILBOX
) + PcdGet16(PcdDebugPortHandleBufferSize
)),
267 ASSERT_EFI_ERROR (Status
);
268 NewMailbox
= (DEBUG_AGENT_MAILBOX
*) (UINTN
) Memory
;
270 // Copy Mailbox and Debug Port Handle buffer to new location in ACPI NVS memory, because original Mailbox
271 // and Debug Port Handle buffer in the allocated pool that may be marked as free by DXE Core after DXE Core
272 // reallocates the HOB.
274 Mailbox
= GetMailboxPointer ();
275 CopyMem (NewMailbox
, Mailbox
, sizeof (DEBUG_AGENT_MAILBOX
));
276 CopyMem (NewMailbox
+ 1, (VOID
*)(UINTN
)Mailbox
->DebugPortHandle
, PcdGet16(PcdDebugPortHandleBufferSize
));
278 // Update Mailbox Location pointer in GUIDed HOB and IDT entry with new one
280 MailboxLocationInHob
= GetMailboxLocationFromHob ();
281 *MailboxLocationInHob
= (UINT64
)(UINTN
)NewMailbox
;
282 SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationInHob
);
284 // Update Debug Port Handle in new Mailbox
286 UpdateMailboxContent (NewMailbox
, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX
, (UINT64
)(UINTN
)(NewMailbox
+ 1));
288 // Set physical memory ready flag
290 SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY
, 1);
292 if (IsHostAttached ()) {
294 // Trigger one software interrupt to inform HOST
296 TriggerSoftInterrupt (MEMORY_READY_SIGNATURE
);
300 // Restore interrupt state.
302 SetInterruptState (InterruptStatus
);
308 Initialize debug agent.
310 This function is used to set up debug environment for SEC and PEI phase.
312 If InitFlag is DEBUG_AGENT_INIT_PREMEM_SEC, it will overirde IDT table entries
313 and initialize debug port. It will enable interrupt to support break-in feature.
314 It will set up debug agent Mailbox in cache-as-ramfrom. It will be called before
315 physical memory is ready.
316 If InitFlag is DEBUG_AGENT_INIT_POSTMEM_SEC, debug agent will build one GUIDed
317 HOB to copy debug agent Mailbox. It will be called after physical memory is ready.
319 This function is used to set up debug environment to support source level debugging.
320 If certain Debug Agent Library instance has to save some private data in the stack,
321 this function must work on the mode that doesn't return to the caller, then
322 the caller needs to wrap up all rest of logic after InitializeDebugAgent() into one
323 function and pass it into InitializeDebugAgent(). InitializeDebugAgent() is
324 responsible to invoke the passing-in function at the end of InitializeDebugAgent().
326 If the parameter Function is not NULL, Debug Agent Libary instance will invoke it by
327 passing in the Context to be its parameter.
329 If Function() is NULL, Debug Agent Library instance will return after setup debug
332 @param[in] InitFlag Init flag is used to decide the initialize process.
333 @param[in] Context Context needed according to InitFlag; it was optional.
334 @param[in] Function Continue function called by debug agent library; it was
340 InitializeDebugAgent (
342 IN VOID
*Context
, OPTIONAL
343 IN DEBUG_AGENT_CONTINUE Function OPTIONAL
346 DEBUG_AGENT_MAILBOX
*Mailbox
;
347 DEBUG_AGENT_MAILBOX MailboxInStack
;
348 DEBUG_AGENT_PHASE2_CONTEXT Phase2Context
;
349 DEBUG_AGENT_CONTEXT_POSTMEM_SEC
*DebugAgentContext
;
351 IA32_DESCRIPTOR
*Ia32Idtr
;
352 IA32_IDT_ENTRY
*Ia32IdtEntry
;
353 UINT64 DebugPortHandle
;
354 UINT64 MailboxLocation
;
355 UINT64
*MailboxLocationPointer
;
357 DisableInterrupts ();
361 case DEBUG_AGENT_INIT_PREMEM_SEC
:
363 InitializeDebugIdt ();
365 MailboxLocation
= (UINT64
)(UINTN
)&MailboxInStack
;
366 Mailbox
= &MailboxInStack
;
367 ZeroMem ((VOID
*) Mailbox
, sizeof (DEBUG_AGENT_MAILBOX
));
369 // Get and save debug port handle and set the length of memory block.
371 SetLocationSavedMailboxPointerInIdtEntry (&MailboxLocation
);
372 SetDebugFlag (DEBUG_AGENT_FLAG_PRINT_ERROR_LEVEL
, DEBUG_AGENT_ERROR
);
374 InitializeDebugTimer ();
376 Phase2Context
.Context
= Context
;
377 Phase2Context
.Function
= Function
;
378 DebugPortInitialize ((VOID
*) &Phase2Context
, InitializeDebugAgentPhase2
);
380 // If reaches here, it means Debug Port initialization failed.
382 DEBUG ((EFI_D_ERROR
, "Debug Agent: Debug port initialization failed.\n"));
386 case DEBUG_AGENT_INIT_POSTMEM_SEC
:
387 Mailbox
= GetMailboxPointer ();
389 // Memory has been ready
391 SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY
, 1);
392 if (IsHostAttached ()) {
394 // Trigger one software interrupt to inform HOST
396 TriggerSoftInterrupt (MEMORY_READY_SIGNATURE
);
400 // Fix up Debug Port handle address and mailbox address
402 DebugAgentContext
= (DEBUG_AGENT_CONTEXT_POSTMEM_SEC
*) Context
;
403 DebugPortHandle
= (UINT64
)(UINT32
)(Mailbox
->DebugPortHandle
+ DebugAgentContext
->StackMigrateOffset
);
404 UpdateMailboxContent (Mailbox
, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX
, DebugPortHandle
);
405 Mailbox
= (DEBUG_AGENT_MAILBOX
*) ((UINTN
) Mailbox
+ DebugAgentContext
->StackMigrateOffset
);
406 MailboxLocation
= (UINT64
)(UINTN
)Mailbox
;
408 // Build mailbox location in HOB and fix-up its address
410 MailboxLocationPointer
= BuildGuidDataHob (
415 MailboxLocationPointer
= (UINT64
*) ((UINTN
) MailboxLocationPointer
+ DebugAgentContext
->HeapMigrateOffset
);
417 // Update IDT entry to save the location saved mailbox pointer
419 SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationPointer
);
421 // Enable CPU interrupts so debug timer interrupts can be delivered
427 case DEBUG_AGENT_INIT_PEI
:
429 // Check if Debug Agent has initialized before
431 if (IsDebugAgentInitialzed()) {
432 DEBUG ((EFI_D_WARN
, "Debug Agent: It has already initialized in SEC Core!\n"));
436 // Set up IDT entries
438 InitializeDebugIdt ();
440 // Build mailbox in HOB and setup Mailbox Set In Pei flag
442 Mailbox
= AllocateZeroPool (sizeof (DEBUG_AGENT_MAILBOX
));
443 MailboxLocation
= (UINT64
)(UINTN
)Mailbox
;
444 MailboxLocationPointer
= BuildGuidDataHob (
450 InitializeDebugTimer ();
452 // Update IDT entry to save the location pointer saved mailbox pointer
454 SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationPointer
);
456 // Register for a callback once memory has been initialized.
457 // If memery has been ready, the callback funtion will be invoked immediately
459 Status
= PeiServicesNotifyPpi (&mMemoryDiscoveredNotifyList
[0]);
460 ASSERT_EFI_ERROR (Status
);
462 // Set HOB check flag if memory has not been ready yet
464 if (GetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY
) == 0) {
465 SetDebugFlag (DEBUG_AGENT_FLAG_CHECK_MAILBOX_IN_HOB
, 1);
468 Phase2Context
.Context
= Context
;
469 Phase2Context
.Function
= Function
;
470 DebugPortInitialize ((VOID
*) &Phase2Context
, InitializeDebugAgentPhase2
);
472 FindAndReportModuleImageInfo (4);
476 case DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64
:
477 if (Context
== NULL
) {
478 DEBUG ((EFI_D_ERROR
, "DebugAgent: Input parameter Context cannot be NULL!\n"));
481 Ia32Idtr
= (IA32_DESCRIPTOR
*) Context
;
482 Ia32IdtEntry
= (IA32_IDT_ENTRY
*)(Ia32Idtr
->Base
);
483 MailboxLocationPointer
= (UINT64
*) (UINTN
) (Ia32IdtEntry
[DEBUG_MAILBOX_VECTOR
].Bits
.OffsetLow
+
484 (Ia32IdtEntry
[DEBUG_MAILBOX_VECTOR
].Bits
.OffsetHigh
<< 16));
485 Mailbox
= (DEBUG_AGENT_MAILBOX
*) (UINTN
)(*MailboxLocationPointer
);
486 VerifyMailboxChecksum (Mailbox
);
488 DebugPortHandle
= (UINT64
) (UINTN
)DebugPortInitialize ((VOID
*)(UINTN
)Mailbox
->DebugPortHandle
, NULL
);
489 UpdateMailboxContent (Mailbox
, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX
, DebugPortHandle
);
491 // Set up IDT entries
493 InitializeDebugIdt ();
495 // Update IDT entry to save location pointer saved the mailbox pointer
497 SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationPointer
);
499 FindAndReportModuleImageInfo (4);
505 // Only DEBUG_AGENT_INIT_PREMEM_SEC and DEBUG_AGENT_INIT_POSTMEM_SEC are allowed for this
506 // Debug Agent library instance.
508 DEBUG ((EFI_D_ERROR
, "Debug Agent: The InitFlag value is not allowed!\n"));
517 // If Function is not NULL, invoke it always whatever debug agent was initialized sucesssfully or not.
519 if (Function
!= NULL
) {
525 Caller provided function to be invoked at the end of DebugPortInitialize().
527 Refer to the descrption for DebugPortInitialize() for more details.
529 @param[in] Context The first input argument of DebugPortInitialize().
530 @param[in] DebugPortHandle Debug port handle created by Debug Communication Libary.
535 InitializeDebugAgentPhase2 (
537 IN DEBUG_PORT_HANDLE DebugPortHandle
540 DEBUG_AGENT_PHASE2_CONTEXT
*Phase2Context
;
541 UINT64
*MailboxLocation
;
542 DEBUG_AGENT_MAILBOX
*Mailbox
;
543 EFI_SEC_PEI_HAND_OFF
*SecCoreData
;
545 UINT64 NewDebugPortHandle
;
547 Phase2Context
= (DEBUG_AGENT_PHASE2_CONTEXT
*) Context
;
548 MailboxLocation
= GetLocationSavedMailboxPointerInIdtEntry ();
549 Mailbox
= (DEBUG_AGENT_MAILBOX
*)(UINTN
)(*MailboxLocation
);
550 BufferSize
= PcdGet16(PcdDebugPortHandleBufferSize
);
551 if (Phase2Context
->Function
== NULL
&& DebugPortHandle
!= NULL
&& BufferSize
!= 0) {
552 NewDebugPortHandle
= (UINT64
)(UINTN
)AllocateCopyPool (BufferSize
, DebugPortHandle
);
554 NewDebugPortHandle
= (UINT64
)(UINTN
)DebugPortHandle
;
556 UpdateMailboxContent (Mailbox
, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX
, NewDebugPortHandle
);
559 // Trigger one software interrupt to inform HOST
561 TriggerSoftInterrupt (SYSTEM_RESET_SIGNATURE
);
564 // If Temporary RAM region is below 128 MB, then send message to
565 // host to disable low memory filtering.
567 SecCoreData
= (EFI_SEC_PEI_HAND_OFF
*)Phase2Context
->Context
;
568 if ((UINTN
)SecCoreData
->TemporaryRamBase
< BASE_128MB
&& IsHostAttached ()) {
569 SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY
, 1);
570 TriggerSoftInterrupt (MEMORY_READY_SIGNATURE
);
574 // Enable CPU interrupts so debug timer interrupts can be delivered
579 // Call continuation function if it is not NULL.
581 if (Phase2Context
->Function
!= NULL
) {
582 Phase2Context
->Function (Phase2Context
->Context
);