1 /** @file
2 Debug Agent library implementation.
3
4 Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "SmmDebugAgentLib.h"
10
11 DEBUG_AGENT_MAILBOX *mMailboxPointer = NULL;
12 DEBUG_AGENT_MAILBOX mLocalMailbox;
13 UINTN mSavedDebugRegisters[6];
14 IA32_IDT_GATE_DESCRIPTOR mIdtEntryTable[33];
15 BOOLEAN mSkipBreakpoint = FALSE;
16 BOOLEAN mSmmDebugIdtInitFlag = FALSE;
17 BOOLEAN mApicTimerRestore = FALSE;
18 BOOLEAN mPeriodicMode;
19 UINT32 mTimerCycle;
20 UINTN mApicTimerDivisor;
21 UINT8 mVector;
22
23 CHAR8 mWarningMsgIgnoreSmmEntryBreak[] = "Ignore smmentrybreak setting for SMI issued during DXE debugging!\r\n";
24
25 /**
26 Check if debug agent support multi-processor.
27
28 @retval TRUE Multi-processor is supported.
29 @retval FALSE Multi-processor is not supported.
30
31 **/
32 BOOLEAN
MultiProcessorDebugSupport(VOID)33 MultiProcessorDebugSupport (
34 VOID
35 )
36 {
37 return FALSE;
38 }
39
40 /**
41 Read the Attach/Break-in symbols from the debug port.
42
43 @param[in] Handle Pointer to Debug Port handle.
44 @param[out] BreakSymbol Returned break symbol.
45
46 @retval EFI_SUCCESS Read the symbol in BreakSymbol.
47 @retval EFI_NOT_FOUND No read the break symbol.
48
49 **/
50 EFI_STATUS
DebugReadBreakSymbol(IN DEBUG_PORT_HANDLE Handle,OUT UINT8 * BreakSymbol)51 DebugReadBreakSymbol (
52 IN DEBUG_PORT_HANDLE Handle,
53 OUT UINT8 *BreakSymbol
54 )
55 {
56 //
57 // Smm instance has no debug timer to poll break symbol.
58 //
59 return EFI_NOT_FOUND;
60 }
61
62 /**
63 Get the pointer to Mailbox from the GUIDed HOB.
64
65 @return Pointer to Mailbox.
66
67 **/
68 DEBUG_AGENT_MAILBOX *
GetMailboxFromHob(VOID)69 GetMailboxFromHob (
70 VOID
71 )
72 {
73 EFI_HOB_GUID_TYPE *GuidHob;
74 UINT64 *MailboxLocation;
75 DEBUG_AGENT_MAILBOX *Mailbox;
76
77 GuidHob = GetFirstGuidHob (&gEfiDebugAgentGuid);
78 if (GuidHob == NULL) {
79 return NULL;
80 }
81 MailboxLocation = (UINT64 *) (GET_GUID_HOB_DATA(GuidHob));
82 Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation);
83 VerifyMailboxChecksum (Mailbox);
84
85 return Mailbox;
86 }
87
88 /**
89 Get Debug Agent Mailbox pointer.
90
91 @return Mailbox pointer.
92
93 **/
94 DEBUG_AGENT_MAILBOX *
GetMailboxPointer(VOID)95 GetMailboxPointer (
96 VOID
97 )
98 {
99 VerifyMailboxChecksum (mMailboxPointer);
100 return mMailboxPointer;
101 }
102
103 /**
104 Get debug port handle.
105
106 @return Debug port handle.
107
108 **/
109 DEBUG_PORT_HANDLE
GetDebugPortHandle(VOID)110 GetDebugPortHandle (
111 VOID
112 )
113 {
114 return (DEBUG_PORT_HANDLE) (UINTN)(GetMailboxPointer()->DebugPortHandle);
115 }
116
117 /**
118 Store debug register when SMI exit.
119
120 **/
121 VOID
SaveDebugRegister(VOID)122 SaveDebugRegister (
123 VOID
124 )
125 {
126 mSavedDebugRegisters[0] = AsmReadDr0 ();
127 mSavedDebugRegisters[1] = AsmReadDr1 ();
128 mSavedDebugRegisters[2] = AsmReadDr2 ();
129 mSavedDebugRegisters[3] = AsmReadDr3 ();
130 mSavedDebugRegisters[4] = AsmReadDr6 ();
131 mSavedDebugRegisters[5] = AsmReadDr7 ();
132 }
133
134 /**
135 Restore debug register when SMI exit.
136
137 **/
138 VOID
RestoreDebugRegister(VOID)139 RestoreDebugRegister (
140 VOID
141 )
142 {
143 AsmWriteDr7 (0);
144 AsmWriteDr0 (mSavedDebugRegisters[0]);
145 AsmWriteDr1 (mSavedDebugRegisters[1]);
146 AsmWriteDr2 (mSavedDebugRegisters[2]);
147 AsmWriteDr3 (mSavedDebugRegisters[3]);
148 AsmWriteDr6 (mSavedDebugRegisters[4]);
149 AsmWriteDr7 (mSavedDebugRegisters[5]);
150 }
151
152 /**
153 Initialize debug agent.
154
155 This function is used to set up debug environment for source level debug
156 in SMM code.
157
158 If InitFlag is DEBUG_AGENT_INIT_SMM, it will override IDT table entries
159 and initialize debug port. It will get debug agent Mailbox from GUIDed HOB,
160 it it exists, debug agent wiil copied it into the local Mailbox in SMM space.
161 it will override IDT table entries and initialize debug port. Context will be
162 NULL.
163 If InitFlag is DEBUG_AGENT_INIT_ENTER_SMI, debug agent will save Debug
164 Registers and get local Mailbox in SMM space. Context will be NULL.
165 If InitFlag is DEBUG_AGENT_INIT_EXIT_SMI, debug agent will restore Debug
166 Registers. Context will be NULL.
167
168 @param[in] InitFlag Init flag is used to decide initialize process.
169 @param[in] Context Context needed according to InitFlag.
170 @param[in] Function Continue function called by debug agent library; it was
171 optional.
172
173 **/
174 VOID
175 EFIAPI
InitializeDebugAgent(IN UINT32 InitFlag,IN VOID * Context,OPTIONAL IN DEBUG_AGENT_CONTINUE Function OPTIONAL)176 InitializeDebugAgent (
177 IN UINT32 InitFlag,
178 IN VOID *Context, OPTIONAL
179 IN DEBUG_AGENT_CONTINUE Function OPTIONAL
180 )
181 {
182 EFI_STATUS Status;
183 UINT64 DebugPortHandle;
184 IA32_IDT_GATE_DESCRIPTOR IdtEntry[33];
185 IA32_DESCRIPTOR IdtDescriptor;
186 IA32_DESCRIPTOR *Ia32Idtr;
187 IA32_IDT_ENTRY *Ia32IdtEntry;
188 IA32_DESCRIPTOR Idtr;
189 UINT16 IdtEntryCount;
190 DEBUG_AGENT_MAILBOX *Mailbox;
191 UINT64 *MailboxLocation;
192 UINT32 DebugTimerFrequency;
193
194 switch (InitFlag) {
195 case DEBUG_AGENT_INIT_SMM:
196 //
197 // Install configuration table for persisted vector handoff info
198 //
199 Status = gSmst->SmmInstallConfigurationTable (
200 gSmst,
201 &gEfiVectorHandoffTableGuid,
202 (VOID *) &mVectorHandoffInfoDebugAgent[0],
203 sizeof (EFI_VECTOR_HANDOFF_INFO) * mVectorHandoffInfoCount
204 );
205 if (EFI_ERROR (Status)) {
206 DEBUG ((EFI_D_ERROR, "DebugAgent: Cannot install configuration table for persisted vector handoff info!\n"));
207 CpuDeadLoop ();
208 }
209 //
210 // Check if Debug Agent initialized in DXE phase
211 //
212 Status = EfiGetSystemConfigurationTable (&gEfiDebugAgentGuid, (VOID **) &Mailbox);
213 if (Status == EFI_SUCCESS && Mailbox != NULL) {
214 VerifyMailboxChecksum (Mailbox);
215 mMailboxPointer = Mailbox;
216 break;
217 }
218 //
219 // Check if Debug Agent initialized in SEC/PEI phase
220 //
221 Mailbox = GetMailboxFromHob ();
222 if (Mailbox != NULL) {
223 mMailboxPointer = Mailbox;
224 break;
225 }
226 //
227 // Debug Agent was not initialized before, use the local mailbox.
228 //
229 ZeroMem (&mLocalMailbox, sizeof (DEBUG_AGENT_MAILBOX));
230 Mailbox = &mLocalMailbox;
231 //
232 // Save original IDT entries
233 //
234 AsmReadIdtr (&IdtDescriptor);
235 CopyMem (&IdtEntry, (VOID *)IdtDescriptor.Base, 33 * sizeof(IA32_IDT_GATE_DESCRIPTOR));
236 //
237 // Initialized Debug Agent
238 //
239 InitializeDebugIdt ();
240 //
241 // Initialize Debug Timer hardware and save its frequency
242 //
243 InitializeDebugTimer (&DebugTimerFrequency, TRUE);
244 UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY, DebugTimerFrequency);
245
246 DebugPortHandle = (UINT64) (UINTN)DebugPortInitialize ((DEBUG_PORT_HANDLE) (UINTN)Mailbox->DebugPortHandle, NULL);
247 UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle);
248 mMailboxPointer = Mailbox;
249 //
250 // Trigger one software interrupt to inform HOST
251 //
252 TriggerSoftInterrupt (SYSTEM_RESET_SIGNATURE);
253
254 SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1);
255 //
256 // Memory has been ready
257 //
258 if (IsHostAttached ()) {
259 //
260 // Trigger one software interrupt to inform HOST
261 //
262 TriggerSoftInterrupt (MEMORY_READY_SIGNATURE);
263 }
264 //
265 // Find and report PE/COFF image info to HOST
266 //
267 FindAndReportModuleImageInfo (SIZE_4KB);
268 //
269 // Restore saved IDT entries
270 //
271 CopyMem ((VOID *)IdtDescriptor.Base, &IdtEntry, 33 * sizeof(IA32_IDT_GATE_DESCRIPTOR));
272
273 break;
274
275 case DEBUG_AGENT_INIT_ENTER_SMI:
276 SaveDebugRegister ();
277 if (!mSmmDebugIdtInitFlag) {
278 //
279 // We only need to initialize Debug IDT table at first SMI entry
280 // after SMM relocation.
281 //
282 InitializeDebugIdt ();
283 mSmmDebugIdtInitFlag = TRUE;
284 }
285 //
286 // Check if CPU APIC Timer is working, otherwise initialize it.
287 //
288 InitializeLocalApicSoftwareEnable (TRUE);
289 GetApicTimerState (&mApicTimerDivisor, &mPeriodicMode, &mVector);
290 mTimerCycle = GetApicTimerInitCount ();
291 if (!mPeriodicMode || mTimerCycle == 0) {
292 mApicTimerRestore = TRUE;
293 InitializeDebugTimer (NULL, FALSE);
294 }
295 Mailbox = GetMailboxPointer ();
296 if (GetDebugFlag (DEBUG_AGENT_FLAG_AGENT_IN_PROGRESS) == 1) {
297 //
298 // If Debug Agent has been communication state with HOST, we need skip
299 // any break points set in SMM, set Skip Breakpoint flag
300 //
301 mSkipBreakpoint = TRUE;
302 }
303 if (GetDebugFlag (DEBUG_AGENT_FLAG_BREAK_ON_NEXT_SMI) == 1) {
304 if (mSkipBreakpoint) {
305 //
306 // Print warning message if ignore smm entry break
307 //
308 DebugPortWriteBuffer ((DEBUG_PORT_HANDLE) (UINTN)Mailbox->DebugPortHandle,
309 (UINT8 *)mWarningMsgIgnoreSmmEntryBreak,
310 AsciiStrLen (mWarningMsgIgnoreSmmEntryBreak)
311 );
312 } else {
313 //
314 // If SMM entry break is set, SMM code will be break at here.
315 //
316 CpuBreakpoint ();
317 }
318 }
319 break;
320
321 case DEBUG_AGENT_INIT_EXIT_SMI:
322 Mailbox = GetMailboxPointer ();
323 //
324 // Clear Skip Breakpoint flag
325 //
326 mSkipBreakpoint = FALSE;
327 RestoreDebugRegister ();
328 //
329 // Restore APIC Timer
330 //
331 if (mApicTimerRestore) {
332 InitializeApicTimer (mApicTimerDivisor, mTimerCycle, mPeriodicMode, mVector);
333 mApicTimerRestore = FALSE;
334 }
335 break;
336
337 case DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64:
338 if (Context == NULL) {
339 DEBUG ((EFI_D_ERROR, "DebugAgent: Input parameter Context cannot be NULL!\n"));
340 CpuDeadLoop ();
341 } else {
342 Ia32Idtr = (IA32_DESCRIPTOR *) Context;
343 Ia32IdtEntry = (IA32_IDT_ENTRY *)(Ia32Idtr->Base);
344 MailboxLocation = (UINT64 *) ((UINTN) Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetLow +
345 ((UINTN) Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetHigh << 16));
346 mMailboxPointer = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation);
347 VerifyMailboxChecksum (mMailboxPointer);
348 //
349 // Get original IDT address and size.
350 //
351 AsmReadIdtr ((IA32_DESCRIPTOR *) &Idtr);
352 IdtEntryCount = (UINT16) ((Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR));
353 if (IdtEntryCount < 33) {
354 Idtr.Limit = (UINT16) (sizeof (IA32_IDT_GATE_DESCRIPTOR) * 33 - 1);
355 Idtr.Base = (UINTN) &mIdtEntryTable;
356 ZeroMem (&mIdtEntryTable, Idtr.Limit + 1);
357 AsmWriteIdtr ((IA32_DESCRIPTOR *) &Idtr);
358 }
359
360 InitializeDebugIdt ();
361 //
362 // Initialize Debug Timer hardware and save its frequency
363 //
364 InitializeDebugTimer (&DebugTimerFrequency, TRUE);
365 UpdateMailboxContent (mMailboxPointer, DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY, DebugTimerFrequency);
366 //
367 // Enable Debug Timer interrupt and CPU interrupt
368 //
369 SaveAndSetDebugTimerInterrupt (TRUE);
370 EnableInterrupts ();
371
372 FindAndReportModuleImageInfo (SIZE_4KB);
373 }
374 break;
375
376 default:
377 //
378 // Only DEBUG_AGENT_INIT_PREMEM_SEC and DEBUG_AGENT_INIT_POSTMEM_SEC are allowed for this
379 // Debug Agent library instance.
380 //
381 DEBUG ((EFI_D_ERROR, "Debug Agent: The InitFlag value is not allowed!\n"));
382 CpuDeadLoop ();
383 break;
384 }
385 }
386
387