]> git.proxmox.com Git - mirror_edk2.git/blob - SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgent/SmmDebugAgentLib.c
SourceLevelDebugPkg: Apply uncrustify changes
[mirror_edk2.git] / SourceLevelDebugPkg / Library / DebugAgent / SmmDebugAgent / SmmDebugAgentLib.c
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
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
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 *
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
82 MailboxLocation = (UINT64 *)(GET_GUID_HOB_DATA (GuidHob));
83 Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation);
84 VerifyMailboxChecksum (Mailbox);
85
86 return Mailbox;
87 }
88
89 /**
90 Get Debug Agent Mailbox pointer.
91
92 @return Mailbox pointer.
93
94 **/
95 DEBUG_AGENT_MAILBOX *
96 GetMailboxPointer (
97 VOID
98 )
99 {
100 VerifyMailboxChecksum (mMailboxPointer);
101 return mMailboxPointer;
102 }
103
104 /**
105 Get debug port handle.
106
107 @return Debug port handle.
108
109 **/
110 DEBUG_PORT_HANDLE
111 GetDebugPortHandle (
112 VOID
113 )
114 {
115 return (DEBUG_PORT_HANDLE)(UINTN)(GetMailboxPointer ()->DebugPortHandle);
116 }
117
118 /**
119 Store debug register when SMI exit.
120
121 **/
122 VOID
123 SaveDebugRegister (
124 VOID
125 )
126 {
127 mSavedDebugRegisters[0] = AsmReadDr0 ();
128 mSavedDebugRegisters[1] = AsmReadDr1 ();
129 mSavedDebugRegisters[2] = AsmReadDr2 ();
130 mSavedDebugRegisters[3] = AsmReadDr3 ();
131 mSavedDebugRegisters[4] = AsmReadDr6 ();
132 mSavedDebugRegisters[5] = AsmReadDr7 ();
133 }
134
135 /**
136 Restore debug register when SMI exit.
137
138 **/
139 VOID
140 RestoreDebugRegister (
141 VOID
142 )
143 {
144 AsmWriteDr7 (0);
145 AsmWriteDr0 (mSavedDebugRegisters[0]);
146 AsmWriteDr1 (mSavedDebugRegisters[1]);
147 AsmWriteDr2 (mSavedDebugRegisters[2]);
148 AsmWriteDr3 (mSavedDebugRegisters[3]);
149 AsmWriteDr6 (mSavedDebugRegisters[4]);
150 AsmWriteDr7 (mSavedDebugRegisters[5]);
151 }
152
153 /**
154 Initialize debug agent.
155
156 This function is used to set up debug environment for source level debug
157 in SMM code.
158
159 If InitFlag is DEBUG_AGENT_INIT_SMM, it will override IDT table entries
160 and initialize debug port. It will get debug agent Mailbox from GUIDed HOB,
161 it it exists, debug agent wiil copied it into the local Mailbox in SMM space.
162 it will override IDT table entries and initialize debug port. Context will be
163 NULL.
164 If InitFlag is DEBUG_AGENT_INIT_ENTER_SMI, debug agent will save Debug
165 Registers and get local Mailbox in SMM space. Context will be NULL.
166 If InitFlag is DEBUG_AGENT_INIT_EXIT_SMI, debug agent will restore Debug
167 Registers. Context will be NULL.
168
169 @param[in] InitFlag Init flag is used to decide initialize process.
170 @param[in] Context Context needed according to InitFlag.
171 @param[in] Function Continue function called by debug agent library; it was
172 optional.
173
174 **/
175 VOID
176 EFIAPI
177 InitializeDebugAgent (
178 IN UINT32 InitFlag,
179 IN VOID *Context OPTIONAL,
180 IN DEBUG_AGENT_CONTINUE Function OPTIONAL
181 )
182 {
183 EFI_STATUS Status;
184 UINT64 DebugPortHandle;
185 IA32_IDT_GATE_DESCRIPTOR IdtEntry[33];
186 IA32_DESCRIPTOR IdtDescriptor;
187 IA32_DESCRIPTOR *Ia32Idtr;
188 IA32_IDT_ENTRY *Ia32IdtEntry;
189 IA32_DESCRIPTOR Idtr;
190 UINT16 IdtEntryCount;
191 DEBUG_AGENT_MAILBOX *Mailbox;
192 UINT64 *MailboxLocation;
193 UINT32 DebugTimerFrequency;
194
195 switch (InitFlag) {
196 case DEBUG_AGENT_INIT_SMM:
197 //
198 // Install configuration table for persisted vector handoff info
199 //
200 Status = gSmst->SmmInstallConfigurationTable (
201 gSmst,
202 &gEfiVectorHandoffTableGuid,
203 (VOID *)&mVectorHandoffInfoDebugAgent[0],
204 sizeof (EFI_VECTOR_HANDOFF_INFO) * mVectorHandoffInfoCount
205 );
206 if (EFI_ERROR (Status)) {
207 DEBUG ((DEBUG_ERROR, "DebugAgent: Cannot install configuration table for persisted vector handoff info!\n"));
208 CpuDeadLoop ();
209 }
210
211 //
212 // Check if Debug Agent initialized in DXE phase
213 //
214 Status = EfiGetSystemConfigurationTable (&gEfiDebugAgentGuid, (VOID **)&Mailbox);
215 if ((Status == EFI_SUCCESS) && (Mailbox != NULL)) {
216 VerifyMailboxChecksum (Mailbox);
217 mMailboxPointer = Mailbox;
218 break;
219 }
220
221 //
222 // Check if Debug Agent initialized in SEC/PEI phase
223 //
224 Mailbox = GetMailboxFromHob ();
225 if (Mailbox != NULL) {
226 mMailboxPointer = Mailbox;
227 break;
228 }
229
230 //
231 // Debug Agent was not initialized before, use the local mailbox.
232 //
233 ZeroMem (&mLocalMailbox, sizeof (DEBUG_AGENT_MAILBOX));
234 Mailbox = &mLocalMailbox;
235 //
236 // Save original IDT entries
237 //
238 AsmReadIdtr (&IdtDescriptor);
239 CopyMem (&IdtEntry, (VOID *)IdtDescriptor.Base, 33 * sizeof (IA32_IDT_GATE_DESCRIPTOR));
240 //
241 // Initialized Debug Agent
242 //
243 InitializeDebugIdt ();
244 //
245 // Initialize Debug Timer hardware and save its frequency
246 //
247 InitializeDebugTimer (&DebugTimerFrequency, TRUE);
248 UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY, DebugTimerFrequency);
249
250 DebugPortHandle = (UINT64)(UINTN)DebugPortInitialize ((DEBUG_PORT_HANDLE)(UINTN)Mailbox->DebugPortHandle, NULL);
251 UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle);
252 mMailboxPointer = Mailbox;
253 //
254 // Trigger one software interrupt to inform HOST
255 //
256 TriggerSoftInterrupt (SYSTEM_RESET_SIGNATURE);
257
258 SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1);
259 //
260 // Memory has been ready
261 //
262 if (IsHostAttached ()) {
263 //
264 // Trigger one software interrupt to inform HOST
265 //
266 TriggerSoftInterrupt (MEMORY_READY_SIGNATURE);
267 }
268
269 //
270 // Find and report PE/COFF image info to HOST
271 //
272 FindAndReportModuleImageInfo (SIZE_4KB);
273 //
274 // Restore saved IDT entries
275 //
276 CopyMem ((VOID *)IdtDescriptor.Base, &IdtEntry, 33 * sizeof (IA32_IDT_GATE_DESCRIPTOR));
277
278 break;
279
280 case DEBUG_AGENT_INIT_ENTER_SMI:
281 SaveDebugRegister ();
282 if (!mSmmDebugIdtInitFlag) {
283 //
284 // We only need to initialize Debug IDT table at first SMI entry
285 // after SMM relocation.
286 //
287 InitializeDebugIdt ();
288 mSmmDebugIdtInitFlag = TRUE;
289 }
290
291 //
292 // Check if CPU APIC Timer is working, otherwise initialize it.
293 //
294 InitializeLocalApicSoftwareEnable (TRUE);
295 GetApicTimerState (&mApicTimerDivisor, &mPeriodicMode, &mVector);
296 mTimerCycle = GetApicTimerInitCount ();
297 if (!mPeriodicMode || (mTimerCycle == 0)) {
298 mApicTimerRestore = TRUE;
299 InitializeDebugTimer (NULL, FALSE);
300 }
301
302 Mailbox = GetMailboxPointer ();
303 if (GetDebugFlag (DEBUG_AGENT_FLAG_AGENT_IN_PROGRESS) == 1) {
304 //
305 // If Debug Agent has been communication state with HOST, we need skip
306 // any break points set in SMM, set Skip Breakpoint flag
307 //
308 mSkipBreakpoint = TRUE;
309 }
310
311 if (GetDebugFlag (DEBUG_AGENT_FLAG_BREAK_ON_NEXT_SMI) == 1) {
312 if (mSkipBreakpoint) {
313 //
314 // Print warning message if ignore smm entry break
315 //
316 DebugPortWriteBuffer (
317 (DEBUG_PORT_HANDLE)(UINTN)Mailbox->DebugPortHandle,
318 (UINT8 *)mWarningMsgIgnoreSmmEntryBreak,
319 AsciiStrLen (mWarningMsgIgnoreSmmEntryBreak)
320 );
321 } else {
322 //
323 // If SMM entry break is set, SMM code will be break at here.
324 //
325 CpuBreakpoint ();
326 }
327 }
328
329 break;
330
331 case DEBUG_AGENT_INIT_EXIT_SMI:
332 Mailbox = GetMailboxPointer ();
333 //
334 // Clear Skip Breakpoint flag
335 //
336 mSkipBreakpoint = FALSE;
337 RestoreDebugRegister ();
338 //
339 // Restore APIC Timer
340 //
341 if (mApicTimerRestore) {
342 InitializeApicTimer (mApicTimerDivisor, mTimerCycle, mPeriodicMode, mVector);
343 mApicTimerRestore = FALSE;
344 }
345
346 break;
347
348 case DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64:
349 if (Context == NULL) {
350 DEBUG ((DEBUG_ERROR, "DebugAgent: Input parameter Context cannot be NULL!\n"));
351 CpuDeadLoop ();
352 } else {
353 Ia32Idtr = (IA32_DESCRIPTOR *)Context;
354 Ia32IdtEntry = (IA32_IDT_ENTRY *)(Ia32Idtr->Base);
355 MailboxLocation = (UINT64 *)((UINTN)Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetLow +
356 ((UINTN)Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetHigh << 16));
357 mMailboxPointer = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation);
358 VerifyMailboxChecksum (mMailboxPointer);
359 //
360 // Get original IDT address and size.
361 //
362 AsmReadIdtr ((IA32_DESCRIPTOR *)&Idtr);
363 IdtEntryCount = (UINT16)((Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR));
364 if (IdtEntryCount < 33) {
365 Idtr.Limit = (UINT16)(sizeof (IA32_IDT_GATE_DESCRIPTOR) * 33 - 1);
366 Idtr.Base = (UINTN)&mIdtEntryTable;
367 ZeroMem (&mIdtEntryTable, Idtr.Limit + 1);
368 AsmWriteIdtr ((IA32_DESCRIPTOR *)&Idtr);
369 }
370
371 InitializeDebugIdt ();
372 //
373 // Initialize Debug Timer hardware and save its frequency
374 //
375 InitializeDebugTimer (&DebugTimerFrequency, TRUE);
376 UpdateMailboxContent (mMailboxPointer, DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY, DebugTimerFrequency);
377 //
378 // Enable Debug Timer interrupt and CPU interrupt
379 //
380 SaveAndSetDebugTimerInterrupt (TRUE);
381 EnableInterrupts ();
382
383 FindAndReportModuleImageInfo (SIZE_4KB);
384 }
385
386 break;
387
388 default:
389 //
390 // Only DEBUG_AGENT_INIT_PREMEM_SEC and DEBUG_AGENT_INIT_POSTMEM_SEC are allowed for this
391 // Debug Agent library instance.
392 //
393 DEBUG ((DEBUG_ERROR, "Debug Agent: The InitFlag value is not allowed!\n"));
394 CpuDeadLoop ();
395 break;
396 }
397 }