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
,
247 DEBUG_AGENT_MAILBOX
*Mailbox
;
248 BOOLEAN InterruptStatus
;
251 // Save and disable original interrupt status
253 InterruptStatus
= SaveAndDisableInterrupts ();
256 // Set physical memory ready flag
258 Mailbox
= GetMailboxPointer ();
259 SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY
, 1);
262 // Memory has been ready
264 if (IsHostAttached ()) {
266 // Trigger one software interrupt to inform HOST
268 TriggerSoftInterrupt (MEMORY_READY_SIGNATURE
);
272 // Restore interrupt state.
274 SetInterruptState (InterruptStatus
);
280 Initialize debug agent.
282 This function is used to set up debug environment for SEC and PEI phase.
284 If InitFlag is DEBUG_AGENT_INIT_PREMEM_SEC, it will overirde IDT table entries
285 and initialize debug port. It will enable interrupt to support break-in feature.
286 It will set up debug agent Mailbox in cache-as-ramfrom. It will be called before
287 physical memory is ready.
288 If InitFlag is DEBUG_AGENT_INIT_POSTMEM_SEC, debug agent will build one GUIDed
289 HOB to copy debug agent Mailbox. It will be called after physical memory is ready.
291 This function is used to set up debug environment to support source level debugging.
292 If certain Debug Agent Library instance has to save some private data in the stack,
293 this function must work on the mode that doesn't return to the caller, then
294 the caller needs to wrap up all rest of logic after InitializeDebugAgent() into one
295 function and pass it into InitializeDebugAgent(). InitializeDebugAgent() is
296 responsible to invoke the passing-in function at the end of InitializeDebugAgent().
298 If the parameter Function is not NULL, Debug Agent Libary instance will invoke it by
299 passing in the Context to be its parameter.
301 If Function() is NULL, Debug Agent Library instance will return after setup debug
304 @param[in] InitFlag Init flag is used to decide the initialize process.
305 @param[in] Context Context needed according to InitFlag; it was optional.
306 @param[in] Function Continue function called by debug agent library; it was
312 InitializeDebugAgent (
314 IN VOID
*Context
, OPTIONAL
315 IN DEBUG_AGENT_CONTINUE Function OPTIONAL
318 DEBUG_AGENT_MAILBOX
*Mailbox
;
319 DEBUG_AGENT_MAILBOX MailboxInStack
;
320 DEBUG_AGENT_PHASE2_CONTEXT Phase2Context
;
321 DEBUG_AGENT_CONTEXT_POSTMEM_SEC
*DebugAgentContext
;
323 IA32_DESCRIPTOR
*Ia32Idtr
;
324 IA32_IDT_ENTRY
*Ia32IdtEntry
;
325 UINT64 DebugPortHandle
;
326 UINT64 MailboxLocation
;
327 UINT64
*MailboxLocationPointer
;
329 DisableInterrupts ();
333 case DEBUG_AGENT_INIT_PREMEM_SEC
:
335 InitializeDebugIdt ();
337 MailboxLocation
= (UINT64
)(UINTN
)&MailboxInStack
;
338 Mailbox
= &MailboxInStack
;
339 ZeroMem ((VOID
*) Mailbox
, sizeof (DEBUG_AGENT_MAILBOX
));
341 // Get and save debug port handle and set the length of memory block.
343 SetLocationSavedMailboxPointerInIdtEntry (&MailboxLocation
);
344 SetDebugFlag (DEBUG_AGENT_FLAG_PRINT_ERROR_LEVEL
, DEBUG_AGENT_ERROR
);
346 InitializeDebugTimer ();
348 Phase2Context
.Context
= Context
;
349 Phase2Context
.Function
= Function
;
350 DebugPortInitialize ((VOID
*) &Phase2Context
, InitializeDebugAgentPhase2
);
352 // If reaches here, it means Debug Port initialization failed.
354 DEBUG ((EFI_D_ERROR
, "Debug Agent: Debug port initialization failed.\n"));
358 case DEBUG_AGENT_INIT_POSTMEM_SEC
:
359 Mailbox
= GetMailboxPointer ();
361 // Memory has been ready
363 SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY
, 1);
364 if (IsHostAttached ()) {
366 // Trigger one software interrupt to inform HOST
368 TriggerSoftInterrupt (MEMORY_READY_SIGNATURE
);
372 // Fix up Debug Port handle address and mailbox address
374 DebugAgentContext
= (DEBUG_AGENT_CONTEXT_POSTMEM_SEC
*) Context
;
375 DebugPortHandle
= (UINT64
)(UINT32
)(Mailbox
->DebugPortHandle
+ DebugAgentContext
->StackMigrateOffset
);
376 UpdateMailboxContent (Mailbox
, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX
, DebugPortHandle
);
377 Mailbox
= (DEBUG_AGENT_MAILBOX
*) ((UINTN
) Mailbox
+ DebugAgentContext
->StackMigrateOffset
);
378 MailboxLocation
= (UINT64
)(UINTN
)Mailbox
;
380 // Build mailbox location in HOB and fix-up its address
382 MailboxLocationPointer
= BuildGuidDataHob (
387 MailboxLocationPointer
= (UINT64
*) ((UINTN
) MailboxLocationPointer
+ DebugAgentContext
->HeapMigrateOffset
);
389 // Update IDT entry to save the location saved mailbox pointer
391 SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationPointer
);
393 // Enable CPU interrupts so debug timer interrupts can be delivered
399 case DEBUG_AGENT_INIT_PEI
:
401 // Check if Debug Agent has initialized before
403 if (IsDebugAgentInitialzed()) {
404 DEBUG ((EFI_D_WARN
, "Debug Agent: It has already initialized in SEC Core!\n"));
408 // Set up IDT entries
410 InitializeDebugIdt ();
412 // Build mailbox in HOB and setup Mailbox Set In Pei flag
414 Mailbox
= AllocateZeroPool (sizeof (DEBUG_AGENT_MAILBOX
));
415 MailboxLocation
= (UINT64
)(UINTN
)Mailbox
;
416 MailboxLocationPointer
= BuildGuidDataHob (
422 InitializeDebugTimer ();
424 // Update IDT entry to save the location pointer saved mailbox pointer
426 SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationPointer
);
428 // Register for a callback once memory has been initialized.
429 // If memery has been ready, the callback funtion will be invoked immediately
431 Status
= PeiServicesNotifyPpi (&mMemoryDiscoveredNotifyList
[0]);
432 ASSERT_EFI_ERROR (Status
);
434 // Set HOB check flag if memory has not been ready yet
436 if (GetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY
) == 0) {
437 SetDebugFlag (DEBUG_AGENT_FLAG_CHECK_MAILBOX_IN_HOB
, 1);
440 Phase2Context
.Context
= Context
;
441 Phase2Context
.Function
= Function
;
442 DebugPortInitialize ((VOID
*) &Phase2Context
, InitializeDebugAgentPhase2
);
444 FindAndReportModuleImageInfo (4);
448 case DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64
:
449 if (Context
== NULL
) {
450 DEBUG ((EFI_D_ERROR
, "DebugAgent: Input parameter Context cannot be NULL!\n"));
453 Ia32Idtr
= (IA32_DESCRIPTOR
*) Context
;
454 Ia32IdtEntry
= (IA32_IDT_ENTRY
*)(Ia32Idtr
->Base
);
455 MailboxLocationPointer
= (UINT64
*) (UINTN
) (Ia32IdtEntry
[DEBUG_MAILBOX_VECTOR
].Bits
.OffsetLow
+
456 (Ia32IdtEntry
[DEBUG_MAILBOX_VECTOR
].Bits
.OffsetHigh
<< 16));
457 Mailbox
= (DEBUG_AGENT_MAILBOX
*) (UINTN
)(*MailboxLocationPointer
);
458 VerifyMailboxChecksum (Mailbox
);
460 DebugPortHandle
= (UINT64
) (UINTN
)DebugPortInitialize ((VOID
*)(UINTN
)Mailbox
->DebugPortHandle
, NULL
);
461 UpdateMailboxContent (Mailbox
, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX
, DebugPortHandle
);
463 // Set up IDT entries
465 InitializeDebugIdt ();
467 // Update IDT entry to save location pointer saved the mailbox pointer
469 SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationPointer
);
471 FindAndReportModuleImageInfo (4);
477 // Only DEBUG_AGENT_INIT_PREMEM_SEC and DEBUG_AGENT_INIT_POSTMEM_SEC are allowed for this
478 // Debug Agent library instance.
480 DEBUG ((EFI_D_ERROR
, "Debug Agent: The InitFlag value is not allowed!\n"));
489 // If Function is not NULL, invoke it always whatever debug agent was initialized sucesssfully or not.
491 if (Function
!= NULL
) {
497 Caller provided function to be invoked at the end of DebugPortInitialize().
499 Refer to the descrption for DebugPortInitialize() for more details.
501 @param[in] Context The first input argument of DebugPortInitialize().
502 @param[in] DebugPortHandle Debug port handle created by Debug Communication Libary.
507 InitializeDebugAgentPhase2 (
509 IN DEBUG_PORT_HANDLE DebugPortHandle
512 DEBUG_AGENT_PHASE2_CONTEXT
*Phase2Context
;
513 UINT64
*MailboxLocation
;
514 DEBUG_AGENT_MAILBOX
*Mailbox
;
515 EFI_SEC_PEI_HAND_OFF
*SecCoreData
;
517 UINT64 NewDebugPortHandle
;
519 Phase2Context
= (DEBUG_AGENT_PHASE2_CONTEXT
*) Context
;
520 MailboxLocation
= GetLocationSavedMailboxPointerInIdtEntry ();
521 Mailbox
= (DEBUG_AGENT_MAILBOX
*)(UINTN
)(*MailboxLocation
);
522 BufferSize
= PcdGet16(PcdDebugPortHandleBufferSize
);
523 if (Phase2Context
->Function
== NULL
&& DebugPortHandle
!= NULL
&& BufferSize
!= 0) {
524 NewDebugPortHandle
= (UINT64
)(UINTN
)AllocateCopyPool (BufferSize
, DebugPortHandle
);
526 NewDebugPortHandle
= (UINT64
)(UINTN
)DebugPortHandle
;
528 UpdateMailboxContent (Mailbox
, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX
, NewDebugPortHandle
);
531 // Trigger one software interrupt to inform HOST
533 TriggerSoftInterrupt (SYSTEM_RESET_SIGNATURE
);
536 // If Temporary RAM region is below 128 MB, then send message to
537 // host to disable low memory filtering.
539 SecCoreData
= (EFI_SEC_PEI_HAND_OFF
*)Phase2Context
->Context
;
540 if ((UINTN
)SecCoreData
->TemporaryRamBase
< BASE_128MB
&& IsHostAttached ()) {
541 SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY
, 1);
542 TriggerSoftInterrupt (MEMORY_READY_SIGNATURE
);
546 // Enable CPU interrupts so debug timer interrupts can be delivered
551 // Call continuation function if it is not NULL.
553 if (Phase2Context
->Function
!= NULL
) {
554 Phase2Context
->Function (Phase2Context
->Context
);