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