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