2 Debug Agent library implementition.
4 Copyright (c) 2010 - 2018, 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 "SmmDebugAgentLib.h"
17 DEBUG_AGENT_MAILBOX
*mMailboxPointer
= NULL
;
18 DEBUG_AGENT_MAILBOX mLocalMailbox
;
19 UINTN mSavedDebugRegisters
[6];
20 IA32_IDT_GATE_DESCRIPTOR mIdtEntryTable
[33];
21 BOOLEAN mSkipBreakpoint
= FALSE
;
22 BOOLEAN mSmmDebugIdtInitFlag
= FALSE
;
23 BOOLEAN mApicTimerRestore
= FALSE
;
24 BOOLEAN mPeriodicMode
;
26 UINTN mApicTimerDivisor
;
29 CHAR8 mWarningMsgIgnoreSmmEntryBreak
[] = "Ignore smmentrybreak setting for SMI issued during DXE debugging!\r\n";
32 Check if debug agent support multi-processor.
34 @retval TRUE Multi-processor is supported.
35 @retval FALSE Multi-processor is not supported.
39 MultiProcessorDebugSupport (
47 Read the Attach/Break-in symbols from the debug port.
49 @param[in] Handle Pointer to Debug Port handle.
50 @param[out] BreakSymbol Returned break symbol.
52 @retval EFI_SUCCESS Read the symbol in BreakSymbol.
53 @retval EFI_NOT_FOUND No read the break symbol.
57 DebugReadBreakSymbol (
58 IN DEBUG_PORT_HANDLE Handle
,
59 OUT UINT8
*BreakSymbol
63 // Smm instance has no debug timer to poll break symbol.
69 Get the pointer to Mailbox from the GUIDed HOB.
71 @return Pointer to Mailbox.
79 EFI_HOB_GUID_TYPE
*GuidHob
;
80 UINT64
*MailboxLocation
;
81 DEBUG_AGENT_MAILBOX
*Mailbox
;
83 GuidHob
= GetFirstGuidHob (&gEfiDebugAgentGuid
);
84 if (GuidHob
== NULL
) {
87 MailboxLocation
= (UINT64
*) (GET_GUID_HOB_DATA(GuidHob
));
88 Mailbox
= (DEBUG_AGENT_MAILBOX
*)(UINTN
)(*MailboxLocation
);
89 VerifyMailboxChecksum (Mailbox
);
95 Get Debug Agent Mailbox pointer.
97 @return Mailbox pointer.
100 DEBUG_AGENT_MAILBOX
*
105 VerifyMailboxChecksum (mMailboxPointer
);
106 return mMailboxPointer
;
110 Get debug port handle.
112 @return Debug port handle.
120 return (DEBUG_PORT_HANDLE
) (UINTN
)(GetMailboxPointer()->DebugPortHandle
);
124 Store debug register when SMI exit.
132 mSavedDebugRegisters
[0] = AsmReadDr0 ();
133 mSavedDebugRegisters
[1] = AsmReadDr1 ();
134 mSavedDebugRegisters
[2] = AsmReadDr2 ();
135 mSavedDebugRegisters
[3] = AsmReadDr3 ();
136 mSavedDebugRegisters
[4] = AsmReadDr6 ();
137 mSavedDebugRegisters
[5] = AsmReadDr7 ();
141 Restore debug register when SMI exit.
145 RestoreDebugRegister (
150 AsmWriteDr0 (mSavedDebugRegisters
[0]);
151 AsmWriteDr1 (mSavedDebugRegisters
[1]);
152 AsmWriteDr2 (mSavedDebugRegisters
[2]);
153 AsmWriteDr3 (mSavedDebugRegisters
[3]);
154 AsmWriteDr6 (mSavedDebugRegisters
[4]);
155 AsmWriteDr7 (mSavedDebugRegisters
[5]);
159 Initialize debug agent.
161 This function is used to set up debug enviroment for source level debug
164 If InitFlag is DEBUG_AGENT_INIT_SMM, it will overirde IDT table entries
165 and initialize debug port. It will get debug agent Mailbox from GUIDed HOB,
166 it it exists, debug agent wiil copied it into the local Mailbox in SMM space.
167 it will overirde IDT table entries and initialize debug port. Context will be
169 If InitFlag is DEBUG_AGENT_INIT_ENTER_SMI, debug agent will save Debug
170 Registers and get local Mailbox in SMM space. Context will be NULL.
171 If InitFlag is DEBUG_AGENT_INIT_EXIT_SMI, debug agent will restore Debug
172 Registers. Context will be NULL.
174 @param[in] InitFlag Init flag is used to decide initialize process.
175 @param[in] Context Context needed according to InitFlag.
176 @param[in] Function Continue function called by debug agent library; it was
182 InitializeDebugAgent (
184 IN VOID
*Context
, OPTIONAL
185 IN DEBUG_AGENT_CONTINUE Function OPTIONAL
189 UINT64 DebugPortHandle
;
190 IA32_IDT_GATE_DESCRIPTOR IdtEntry
[33];
191 IA32_DESCRIPTOR IdtDescriptor
;
192 IA32_DESCRIPTOR
*Ia32Idtr
;
193 IA32_IDT_ENTRY
*Ia32IdtEntry
;
194 IA32_DESCRIPTOR Idtr
;
195 UINT16 IdtEntryCount
;
196 DEBUG_AGENT_MAILBOX
*Mailbox
;
197 UINT64
*MailboxLocation
;
198 UINT32 DebugTimerFrequency
;
201 case DEBUG_AGENT_INIT_SMM
:
203 // Install configuration table for persisted vector handoff info
205 Status
= gSmst
->SmmInstallConfigurationTable (
207 &gEfiVectorHandoffTableGuid
,
208 (VOID
*) &mVectorHandoffInfoDebugAgent
[0],
209 sizeof (EFI_VECTOR_HANDOFF_INFO
) * mVectorHandoffInfoCount
211 if (EFI_ERROR (Status
)) {
212 DEBUG ((EFI_D_ERROR
, "DebugAgent: Cannot install configuration table for persisted vector handoff info!\n"));
216 // Check if Debug Agent initialized in DXE phase
218 Status
= EfiGetSystemConfigurationTable (&gEfiDebugAgentGuid
, (VOID
**) &Mailbox
);
219 if (Status
== EFI_SUCCESS
&& Mailbox
!= NULL
) {
220 VerifyMailboxChecksum (Mailbox
);
221 mMailboxPointer
= Mailbox
;
225 // Check if Debug Agent initialized in SEC/PEI phase
227 Mailbox
= GetMailboxFromHob ();
228 if (Mailbox
!= NULL
) {
229 mMailboxPointer
= Mailbox
;
233 // Debug Agent was not initialized before, use the local mailbox.
235 ZeroMem (&mLocalMailbox
, sizeof (DEBUG_AGENT_MAILBOX
));
236 Mailbox
= &mLocalMailbox
;
238 // Save original IDT entries
240 AsmReadIdtr (&IdtDescriptor
);
241 CopyMem (&IdtEntry
, (VOID
*)IdtDescriptor
.Base
, 33 * sizeof(IA32_IDT_GATE_DESCRIPTOR
));
243 // Initialized Debug Agent
245 InitializeDebugIdt ();
247 // Initialize Debug Timer hardware and save its frequency
249 InitializeDebugTimer (&DebugTimerFrequency
, TRUE
);
250 UpdateMailboxContent (Mailbox
, DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY
, DebugTimerFrequency
);
252 DebugPortHandle
= (UINT64
) (UINTN
)DebugPortInitialize ((DEBUG_PORT_HANDLE
) (UINTN
)Mailbox
->DebugPortHandle
, NULL
);
253 UpdateMailboxContent (Mailbox
, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX
, DebugPortHandle
);
254 mMailboxPointer
= Mailbox
;
256 // Trigger one software interrupt to inform HOST
258 TriggerSoftInterrupt (SYSTEM_RESET_SIGNATURE
);
260 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
);
271 // Find and report PE/COFF image info to HOST
273 FindAndReportModuleImageInfo (SIZE_4KB
);
275 // Restore saved IDT entries
277 CopyMem ((VOID
*)IdtDescriptor
.Base
, &IdtEntry
, 33 * sizeof(IA32_IDT_GATE_DESCRIPTOR
));
281 case DEBUG_AGENT_INIT_ENTER_SMI
:
282 SaveDebugRegister ();
283 if (!mSmmDebugIdtInitFlag
) {
285 // We only need to initialize Debug IDT table at first SMI entry
286 // after SMM relocation.
288 InitializeDebugIdt ();
289 mSmmDebugIdtInitFlag
= TRUE
;
292 // Check if CPU APIC Timer is working, otherwise initialize it.
294 InitializeLocalApicSoftwareEnable (TRUE
);
295 GetApicTimerState (&mApicTimerDivisor
, &mPeriodicMode
, &mVector
);
296 mTimerCycle
= GetApicTimerInitCount ();
297 if (!mPeriodicMode
|| mTimerCycle
== 0) {
298 mApicTimerRestore
= TRUE
;
299 InitializeDebugTimer (NULL
, FALSE
);
301 Mailbox
= GetMailboxPointer ();
302 if (GetDebugFlag (DEBUG_AGENT_FLAG_AGENT_IN_PROGRESS
) == 1) {
304 // If Debug Agent has been communicaton state with HOST, we need skip
305 // any break points set in SMM, set Skip Breakpoint flag
307 mSkipBreakpoint
= TRUE
;
309 if (GetDebugFlag (DEBUG_AGENT_FLAG_BREAK_ON_NEXT_SMI
) == 1) {
310 if (mSkipBreakpoint
) {
312 // Print warning message if ignore smm entry break
314 DebugPortWriteBuffer ((DEBUG_PORT_HANDLE
) (UINTN
)Mailbox
->DebugPortHandle
,
315 (UINT8
*)mWarningMsgIgnoreSmmEntryBreak
,
316 AsciiStrLen (mWarningMsgIgnoreSmmEntryBreak
)
320 // If SMM entry break is set, SMM code will be break at here.
327 case DEBUG_AGENT_INIT_EXIT_SMI
:
328 Mailbox
= GetMailboxPointer ();
330 // Clear Skip Breakpoint flag
332 mSkipBreakpoint
= FALSE
;
333 RestoreDebugRegister ();
335 // Restore APIC Timer
337 if (mApicTimerRestore
) {
338 InitializeApicTimer (mApicTimerDivisor
, mTimerCycle
, mPeriodicMode
, mVector
);
339 mApicTimerRestore
= FALSE
;
343 case DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64
:
344 if (Context
== NULL
) {
345 DEBUG ((EFI_D_ERROR
, "DebugAgent: Input parameter Context cannot be NULL!\n"));
348 Ia32Idtr
= (IA32_DESCRIPTOR
*) Context
;
349 Ia32IdtEntry
= (IA32_IDT_ENTRY
*)(Ia32Idtr
->Base
);
350 MailboxLocation
= (UINT64
*) ((UINTN
) Ia32IdtEntry
[DEBUG_MAILBOX_VECTOR
].Bits
.OffsetLow
+
351 ((UINTN
) Ia32IdtEntry
[DEBUG_MAILBOX_VECTOR
].Bits
.OffsetHigh
<< 16));
352 mMailboxPointer
= (DEBUG_AGENT_MAILBOX
*)(UINTN
)(*MailboxLocation
);
353 VerifyMailboxChecksum (mMailboxPointer
);
355 // Get original IDT address and size.
357 AsmReadIdtr ((IA32_DESCRIPTOR
*) &Idtr
);
358 IdtEntryCount
= (UINT16
) ((Idtr
.Limit
+ 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR
));
359 if (IdtEntryCount
< 33) {
360 Idtr
.Limit
= (UINT16
) (sizeof (IA32_IDT_GATE_DESCRIPTOR
) * 33 - 1);
361 Idtr
.Base
= (UINTN
) &mIdtEntryTable
;
362 ZeroMem (&mIdtEntryTable
, Idtr
.Limit
+ 1);
363 AsmWriteIdtr ((IA32_DESCRIPTOR
*) &Idtr
);
366 InitializeDebugIdt ();
368 // Initialize Debug Timer hardware and save its frequency
370 InitializeDebugTimer (&DebugTimerFrequency
, TRUE
);
371 UpdateMailboxContent (mMailboxPointer
, DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY
, DebugTimerFrequency
);
373 // Enable Debug Timer interrupt and CPU interrupt
375 SaveAndSetDebugTimerInterrupt (TRUE
);
378 FindAndReportModuleImageInfo (SIZE_4KB
);
384 // Only DEBUG_AGENT_INIT_PREMEM_SEC and DEBUG_AGENT_INIT_POSTMEM_SEC are allowed for this
385 // Debug Agent library instance.
387 DEBUG ((EFI_D_ERROR
, "Debug Agent: The InitFlag value is not allowed!\n"));