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 *MailboxLocationInHob
= (UINT64
)(UINTN
)NewMailbox
;
285 SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationInHob
);
287 // Update Debug Port Handle in new Mailbox
289 UpdateMailboxContent (NewMailbox
, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX
, (UINT64
)(UINTN
)(NewMailbox
+ 1));
291 // Set physical memory ready flag
293 SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY
, 1);
295 if (IsHostAttached ()) {
297 // Trigger one software interrupt to inform HOST
299 TriggerSoftInterrupt (MEMORY_READY_SIGNATURE
);
303 // Restore interrupt state.
305 SetInterruptState (InterruptStatus
);
311 Initialize debug agent.
313 This function is used to set up debug environment for SEC and PEI phase.
315 If InitFlag is DEBUG_AGENT_INIT_PREMEM_SEC, it will overirde IDT table entries
316 and initialize debug port. It will enable interrupt to support break-in feature.
317 It will set up debug agent Mailbox in cache-as-ramfrom. It will be called before
318 physical memory is ready.
319 If InitFlag is DEBUG_AGENT_INIT_POSTMEM_SEC, debug agent will build one GUIDed
320 HOB to copy debug agent Mailbox. It will be called after physical memory is ready.
322 This function is used to set up debug environment to support source level debugging.
323 If certain Debug Agent Library instance has to save some private data in the stack,
324 this function must work on the mode that doesn't return to the caller, then
325 the caller needs to wrap up all rest of logic after InitializeDebugAgent() into one
326 function and pass it into InitializeDebugAgent(). InitializeDebugAgent() is
327 responsible to invoke the passing-in function at the end of InitializeDebugAgent().
329 If the parameter Function is not NULL, Debug Agent Libary instance will invoke it by
330 passing in the Context to be its parameter.
332 If Function() is NULL, Debug Agent Library instance will return after setup debug
335 @param[in] InitFlag Init flag is used to decide the initialize process.
336 @param[in] Context Context needed according to InitFlag; it was optional.
337 @param[in] Function Continue function called by debug agent library; it was
343 InitializeDebugAgent (
345 IN VOID
*Context
, OPTIONAL
346 IN DEBUG_AGENT_CONTINUE Function OPTIONAL
349 DEBUG_AGENT_MAILBOX
*Mailbox
;
350 DEBUG_AGENT_MAILBOX MailboxInStack
;
351 DEBUG_AGENT_PHASE2_CONTEXT Phase2Context
;
352 DEBUG_AGENT_CONTEXT_POSTMEM_SEC
*DebugAgentContext
;
354 IA32_DESCRIPTOR
*Ia32Idtr
;
355 IA32_IDT_ENTRY
*Ia32IdtEntry
;
356 UINT64 DebugPortHandle
;
357 UINT64 MailboxLocation
;
358 UINT64
*MailboxLocationPointer
;
360 DisableInterrupts ();
364 case DEBUG_AGENT_INIT_PREMEM_SEC
:
366 InitializeDebugIdt ();
368 MailboxLocation
= (UINT64
)(UINTN
)&MailboxInStack
;
369 Mailbox
= &MailboxInStack
;
370 ZeroMem ((VOID
*) Mailbox
, sizeof (DEBUG_AGENT_MAILBOX
));
372 // Get and save debug port handle and set the length of memory block.
374 SetLocationSavedMailboxPointerInIdtEntry (&MailboxLocation
);
376 // Force error message could be printed during the first shakehand between Target/HOST.
378 SetDebugFlag (DEBUG_AGENT_FLAG_PRINT_ERROR_LEVEL
, DEBUG_AGENT_ERROR
);
380 // Save init arch type when debug agent initialized
382 SetDebugFlag (DEBUG_AGENT_FLAG_INIT_ARCH
, sizeof (UINTN
) / 4);
384 InitializeDebugTimer ();
386 Phase2Context
.Context
= Context
;
387 Phase2Context
.Function
= Function
;
388 DebugPortInitialize ((VOID
*) &Phase2Context
, InitializeDebugAgentPhase2
);
390 // If reaches here, it means Debug Port initialization failed.
392 DEBUG ((EFI_D_ERROR
, "Debug Agent: Debug port initialization failed.\n"));
396 case DEBUG_AGENT_INIT_POSTMEM_SEC
:
397 Mailbox
= GetMailboxPointer ();
399 // Memory has been ready
401 SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY
, 1);
402 if (IsHostAttached ()) {
404 // Trigger one software interrupt to inform HOST
406 TriggerSoftInterrupt (MEMORY_READY_SIGNATURE
);
410 // Fix up Debug Port handle address and mailbox address
412 DebugAgentContext
= (DEBUG_AGENT_CONTEXT_POSTMEM_SEC
*) Context
;
413 DebugPortHandle
= (UINT64
)(UINT32
)(Mailbox
->DebugPortHandle
+ DebugAgentContext
->StackMigrateOffset
);
414 UpdateMailboxContent (Mailbox
, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX
, DebugPortHandle
);
415 Mailbox
= (DEBUG_AGENT_MAILBOX
*) ((UINTN
) Mailbox
+ DebugAgentContext
->StackMigrateOffset
);
416 MailboxLocation
= (UINT64
)(UINTN
)Mailbox
;
418 // Build mailbox location in HOB and fix-up its address
420 MailboxLocationPointer
= BuildGuidDataHob (
425 MailboxLocationPointer
= (UINT64
*) ((UINTN
) MailboxLocationPointer
+ DebugAgentContext
->HeapMigrateOffset
);
427 // Update IDT entry to save the location saved mailbox pointer
429 SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationPointer
);
431 // Enable CPU interrupts so debug timer interrupts can be delivered
437 case DEBUG_AGENT_INIT_PEI
:
439 // Check if Debug Agent has initialized before
441 if (IsDebugAgentInitialzed()) {
442 DEBUG ((EFI_D_WARN
, "Debug Agent: It has already initialized in SEC Core!\n"));
446 // Set up IDT entries
448 InitializeDebugIdt ();
450 // Build mailbox in HOB and setup Mailbox Set In Pei flag
452 Mailbox
= AllocateZeroPool (sizeof (DEBUG_AGENT_MAILBOX
));
453 MailboxLocation
= (UINT64
)(UINTN
)Mailbox
;
454 MailboxLocationPointer
= BuildGuidDataHob (
460 InitializeDebugTimer ();
462 // Update IDT entry to save the location pointer saved mailbox pointer
464 SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationPointer
);
466 // Save init arch type when debug agent initialized
468 SetDebugFlag (DEBUG_AGENT_FLAG_INIT_ARCH
, DEBUG_ARCH_SYMBOL
);
470 // Register for a callback once memory has been initialized.
471 // If memery has been ready, the callback funtion will be invoked immediately
473 Status
= PeiServicesNotifyPpi (&mMemoryDiscoveredNotifyList
[0]);
474 ASSERT_EFI_ERROR (Status
);
476 // Set HOB check flag if memory has not been ready yet
478 if (GetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY
) == 0) {
479 SetDebugFlag (DEBUG_AGENT_FLAG_CHECK_MAILBOX_IN_HOB
, 1);
482 Phase2Context
.Context
= Context
;
483 Phase2Context
.Function
= Function
;
484 DebugPortInitialize ((VOID
*) &Phase2Context
, InitializeDebugAgentPhase2
);
486 FindAndReportModuleImageInfo (4);
490 case DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64
:
491 if (Context
== NULL
) {
492 DEBUG ((EFI_D_ERROR
, "DebugAgent: Input parameter Context cannot be NULL!\n"));
495 Ia32Idtr
= (IA32_DESCRIPTOR
*) Context
;
496 Ia32IdtEntry
= (IA32_IDT_ENTRY
*)(Ia32Idtr
->Base
);
497 MailboxLocationPointer
= (UINT64
*) (UINTN
) (Ia32IdtEntry
[DEBUG_MAILBOX_VECTOR
].Bits
.OffsetLow
+
498 (Ia32IdtEntry
[DEBUG_MAILBOX_VECTOR
].Bits
.OffsetHigh
<< 16));
499 Mailbox
= (DEBUG_AGENT_MAILBOX
*) (UINTN
)(*MailboxLocationPointer
);
501 // Mailbox should valid and setup before executing thunk code
503 VerifyMailboxChecksum (Mailbox
);
505 DebugPortHandle
= (UINT64
) (UINTN
)DebugPortInitialize ((VOID
*)(UINTN
)Mailbox
->DebugPortHandle
, NULL
);
506 UpdateMailboxContent (Mailbox
, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX
, DebugPortHandle
);
508 // Set up IDT entries
510 InitializeDebugIdt ();
512 // Update IDT entry to save location pointer saved the mailbox pointer
514 SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationPointer
);
516 FindAndReportModuleImageInfo (4);
522 // Only DEBUG_AGENT_INIT_PREMEM_SEC and DEBUG_AGENT_INIT_POSTMEM_SEC are allowed for this
523 // Debug Agent library instance.
525 DEBUG ((EFI_D_ERROR
, "Debug Agent: The InitFlag value is not allowed!\n"));
533 // If Function is not NULL, invoke it always whatever debug agent was initialized sucesssfully or not.
535 if (Function
!= NULL
) {
541 Caller provided function to be invoked at the end of DebugPortInitialize().
543 Refer to the descrption for DebugPortInitialize() for more details.
545 @param[in] Context The first input argument of DebugPortInitialize().
546 @param[in] DebugPortHandle Debug port handle created by Debug Communication Libary.
551 InitializeDebugAgentPhase2 (
553 IN DEBUG_PORT_HANDLE DebugPortHandle
556 DEBUG_AGENT_PHASE2_CONTEXT
*Phase2Context
;
557 UINT64
*MailboxLocation
;
558 DEBUG_AGENT_MAILBOX
*Mailbox
;
559 EFI_SEC_PEI_HAND_OFF
*SecCoreData
;
561 UINT64 NewDebugPortHandle
;
563 Phase2Context
= (DEBUG_AGENT_PHASE2_CONTEXT
*) Context
;
564 MailboxLocation
= GetLocationSavedMailboxPointerInIdtEntry ();
565 Mailbox
= (DEBUG_AGENT_MAILBOX
*)(UINTN
)(*MailboxLocation
);
566 BufferSize
= PcdGet16(PcdDebugPortHandleBufferSize
);
567 if (Phase2Context
->Function
== NULL
&& DebugPortHandle
!= NULL
&& BufferSize
!= 0) {
568 NewDebugPortHandle
= (UINT64
)(UINTN
)AllocateCopyPool (BufferSize
, DebugPortHandle
);
570 NewDebugPortHandle
= (UINT64
)(UINTN
)DebugPortHandle
;
572 UpdateMailboxContent (Mailbox
, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX
, NewDebugPortHandle
);
575 // Trigger one software interrupt to inform HOST
577 TriggerSoftInterrupt (SYSTEM_RESET_SIGNATURE
);
580 // If Temporary RAM region is below 128 MB, then send message to
581 // host to disable low memory filtering.
583 SecCoreData
= (EFI_SEC_PEI_HAND_OFF
*)Phase2Context
->Context
;
584 if ((UINTN
)SecCoreData
->TemporaryRamBase
< BASE_128MB
&& IsHostAttached ()) {
585 SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY
, 1);
586 TriggerSoftInterrupt (MEMORY_READY_SIGNATURE
);
590 // Enable CPU interrupts so debug timer interrupts can be delivered
595 // Call continuation function if it is not NULL.
597 if (Phase2Context
->Function
!= NULL
) {
598 Phase2Context
->Function (Phase2Context
->Context
);