]> git.proxmox.com Git - mirror_edk2.git/blame - SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/DxeDebugAgentLib.c
1. Add CPU arch type in Mailbox, debug agent will not access HOB if CPU arch changed.
[mirror_edk2.git] / SourceLevelDebugPkg / Library / DebugAgent / DxeDebugAgent / DxeDebugAgentLib.c
CommitLineData
18b144ea 1/** @file\r
2 Debug Agent library implementition for Dxe Core and Dxr modules.\r
3\r
b422b62c 4 Copyright (c) 2010 - 2013, Intel Corporation. All rights reserved.<BR>\r
18b144ea 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 "DxeDebugAgentLib.h"\r
16\r
17DEBUG_AGENT_MAILBOX mMailbox;\r
b422b62c 18DEBUG_AGENT_MAILBOX *mMailboxPointer = NULL;\r
18b144ea 19IA32_IDT_GATE_DESCRIPTOR mIdtEntryTable[33];\r
b422b62c 20BOOLEAN mDxeCoreFlag = FALSE;\r
21BOOLEAN mMultiProcessorDebugSupport = FALSE;\r
22VOID *mSavedIdtTable = NULL;\r
23UINTN mSaveIdtTableSize = 0;\r
24BOOLEAN mDebugAgentInitialized = FALSE;\r
25BOOLEAN mSkipBreakpoint = FALSE;\r
18b144ea 26\r
27/**\r
b422b62c 28 Check if debug agent support multi-processor.\r
18b144ea 29\r
b422b62c 30 @retval TRUE Multi-processor is supported.\r
31 @retval FALSE Multi-processor is not supported.\r
32\r
33**/\r
34BOOLEAN\r
35MultiProcessorDebugSupport (\r
36 VOID\r
37 )\r
38{\r
39 return mMultiProcessorDebugSupport;\r
40}\r
18b144ea 41\r
b422b62c 42/**\r
43 Internal constructor worker function.\r
44\r
45 It will register one callback function on EFI PCD Protocol.\r
46 It will allocate the NVS memory to store Mailbox and install configuration table\r
47 in system table to store its pointer.\r
18b144ea 48\r
49**/\r
b422b62c 50VOID\r
51InternalConstructorWorker (\r
52 VOID\r
18b144ea 53 )\r
54{\r
55 EFI_STATUS Status;\r
56 EFI_PHYSICAL_ADDRESS Address;\r
b422b62c 57 BOOLEAN DebugTimerInterruptState;\r
0a488765 58 DEBUG_AGENT_MAILBOX *Mailbox;\r
59 DEBUG_AGENT_MAILBOX *NewMailbox;\r
93c0bdec 60\r
61 //\r
b422b62c 62 // Install EFI Serial IO protocol on debug port\r
93c0bdec 63 //\r
b422b62c 64 InstallSerialIo ();\r
93c0bdec 65\r
18b144ea 66 Address = 0;\r
67 Status = gBS->AllocatePages (\r
68 AllocateAnyPages,\r
69 EfiACPIMemoryNVS,\r
0a488765 70 EFI_SIZE_TO_PAGES (sizeof(DEBUG_AGENT_MAILBOX) + PcdGet16(PcdDebugPortHandleBufferSize)),\r
18b144ea 71 &Address\r
72 );\r
93c0bdec 73 ASSERT_EFI_ERROR (Status);\r
18b144ea 74\r
b422b62c 75 DebugTimerInterruptState = SaveAndSetDebugTimerInterrupt (FALSE);\r
18b144ea 76\r
0a488765 77 NewMailbox = (DEBUG_AGENT_MAILBOX *) (UINTN) Address;\r
78 //\r
79 // Copy Mailbox and Debug Port Handle buffer to new location in ACPI NVS memory, because original Mailbox\r
80 // and Debug Port Handle buffer may be free at runtime, SMM debug agent needs to access them\r
81 //\r
82 Mailbox = GetMailboxPointer ();\r
83 CopyMem (NewMailbox, Mailbox, sizeof (DEBUG_AGENT_MAILBOX));\r
84 CopyMem (NewMailbox + 1, (VOID *)(UINTN)Mailbox->DebugPortHandle, PcdGet16(PcdDebugPortHandleBufferSize));\r
85 //\r
86 // Update Debug Port Handle in new Mailbox\r
87 //\r
88 UpdateMailboxContent (NewMailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, (UINT64)(UINTN)(NewMailbox + 1));\r
89 mMailboxPointer = NewMailbox;\r
90\r
91 DebugTimerInterruptState = SaveAndSetDebugTimerInterrupt (DebugTimerInterruptState);\r
18b144ea 92\r
93c0bdec 93 Status = gBS->InstallConfigurationTable (&gEfiDebugAgentGuid, (VOID *) mMailboxPointer);\r
94 ASSERT_EFI_ERROR (Status);\r
b422b62c 95}\r
96\r
97/**\r
98 Debug Agent constructor function.\r
99\r
100 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
101 @param[in] SystemTable A pointer to the EFI System Table.\r
102\r
103 @retval RETURN_SUCCESS When this function completed.\r
104\r
105**/\r
106RETURN_STATUS\r
107EFIAPI\r
108DxeDebugAgentLibConstructor (\r
109 IN EFI_HANDLE ImageHandle,\r
110 IN EFI_SYSTEM_TABLE *SystemTable\r
111 )\r
112{\r
113 if (mDxeCoreFlag) {\r
114 //\r
115 // Invoke internal constructor function only when DXE core links this library instance\r
116 //\r
117 InternalConstructorWorker ();\r
118 }\r
119\r
120 return RETURN_SUCCESS;\r
121}\r
122\r
123/**\r
124 Get the pointer to Mailbox from the configuration table.\r
125\r
126 @return Pointer to Mailbox.\r
127\r
128**/\r
129DEBUG_AGENT_MAILBOX *\r
130GetMailboxFromConfigurationTable (\r
131 VOID\r
132 )\r
133{\r
134 EFI_STATUS Status;\r
135 DEBUG_AGENT_MAILBOX *Mailbox;\r
93c0bdec 136 \r
b422b62c 137 Status = EfiGetSystemConfigurationTable (&gEfiDebugAgentGuid, (VOID **) &Mailbox);\r
138 if (Status == EFI_SUCCESS && Mailbox != NULL) {\r
139 VerifyMailboxChecksum (Mailbox);\r
140 return Mailbox;\r
141 } else {\r
142 return NULL;\r
143 }\r
18b144ea 144}\r
145\r
146/**\r
147 Get the pointer to Mailbox from the GUIDed HOB.\r
148\r
149 @param[in] HobStart The starting HOB pointer to search from.\r
150\r
151 @return Pointer to Mailbox.\r
152\r
153**/\r
154DEBUG_AGENT_MAILBOX *\r
155GetMailboxFromHob (\r
156 IN VOID *HobStart\r
157 )\r
158{\r
159 EFI_HOB_GUID_TYPE *GuidHob;\r
b422b62c 160 UINT64 *MailboxLocation;\r
161 DEBUG_AGENT_MAILBOX *Mailbox;\r
18b144ea 162\r
163 GuidHob = GetNextGuidHob (&gEfiDebugAgentGuid, HobStart);\r
164 if (GuidHob == NULL) {\r
165 return NULL;\r
166 }\r
b422b62c 167 MailboxLocation = (UINT64 *) (GET_GUID_HOB_DATA(GuidHob));\r
168 Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation);\r
169 VerifyMailboxChecksum (Mailbox);\r
18b144ea 170\r
b422b62c 171 return Mailbox;\r
18b144ea 172}\r
173\r
174/**\r
175 Get Debug Agent Mailbox pointer.\r
176\r
177 @return Mailbox pointer.\r
178\r
179**/\r
180DEBUG_AGENT_MAILBOX *\r
181GetMailboxPointer (\r
182 VOID\r
183 )\r
184{\r
b422b62c 185 AcquireMpSpinLock (&mDebugMpContext.MailboxSpinLock);\r
186 VerifyMailboxChecksum (mMailboxPointer);\r
187 ReleaseMpSpinLock (&mDebugMpContext.MailboxSpinLock);\r
18b144ea 188 return mMailboxPointer;\r
189}\r
190\r
191/**\r
192 Get debug port handle.\r
193\r
194 @return Debug port handle.\r
195\r
196**/\r
197DEBUG_PORT_HANDLE\r
198GetDebugPortHandle (\r
199 VOID\r
200 )\r
201{\r
b422b62c 202 return (DEBUG_PORT_HANDLE) (UINTN)(GetMailboxPointer ()->DebugPortHandle);\r
203}\r
204\r
205/**\r
206 Worker function to setup IDT table and initialize the IDT entries.\r
207\r
208 @param[in] Mailbox Pointer to Mailbox.\r
209\r
210**/\r
211VOID\r
212SetupDebugAgentEnviroment (\r
213 IN DEBUG_AGENT_MAILBOX *Mailbox\r
214 )\r
215{\r
216 IA32_DESCRIPTOR Idtr;\r
217 UINT16 IdtEntryCount;\r
218 UINT64 DebugPortHandle;\r
219\r
220 if (mMultiProcessorDebugSupport) {\r
221 InitializeSpinLock (&mDebugMpContext.MpContextSpinLock);\r
222 InitializeSpinLock (&mDebugMpContext.DebugPortSpinLock);\r
223 InitializeSpinLock (&mDebugMpContext.MailboxSpinLock);\r
224 //\r
225 // Clear Break CPU index value\r
226 //\r
227 mDebugMpContext.BreakAtCpuIndex = (UINT32) -1;\r
228 }\r
229\r
230 //\r
231 // Get original IDT address and size.\r
232 //\r
233 AsmReadIdtr ((IA32_DESCRIPTOR *) &Idtr);\r
234 IdtEntryCount = (UINT16) ((Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR));\r
235 if (IdtEntryCount < 33) {\r
236 Idtr.Limit = (UINT16) (sizeof (IA32_IDT_GATE_DESCRIPTOR) * 33 - 1);\r
237 Idtr.Base = (UINTN) &mIdtEntryTable;\r
238 ZeroMem (&mIdtEntryTable, Idtr.Limit + 1);\r
239 AsmWriteIdtr ((IA32_DESCRIPTOR *) &Idtr);\r
240 }\r
241\r
242 //\r
243 // Initialize the IDT table entries to support source level debug.\r
244 //\r
245 InitializeDebugIdt ();\r
246\r
247 if (Mailbox != NULL) {\r
248 //\r
249 // If Mailbox exists, copy it into one global variable,\r
250 //\r
251 CopyMem (&mMailbox, Mailbox, sizeof (DEBUG_AGENT_MAILBOX));\r
252 } else {\r
253 ZeroMem (&mMailbox, sizeof (DEBUG_AGENT_MAILBOX));\r
254 } \r
255\r
256 mMailboxPointer = &mMailbox;\r
257 //\r
258 // Initialize debug communication port\r
259 //\r
260 DebugPortHandle = (UINT64) (UINTN)DebugPortInitialize ((VOID *)(UINTN)mMailboxPointer->DebugPortHandle, NULL);\r
261 UpdateMailboxContent (mMailboxPointer, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle);\r
262\r
263 if (Mailbox == NULL) {\r
264 //\r
265 // Trigger one software interrupt to inform HOST\r
266 //\r
267 TriggerSoftInterrupt (SYSTEM_RESET_SIGNATURE);\r
268 SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1);\r
269 //\r
270 // Memory has been ready\r
271 //\r
272 if (IsHostAttached ()) {\r
273 //\r
274 // Trigger one software interrupt to inform HOST\r
275 //\r
276 TriggerSoftInterrupt (MEMORY_READY_SIGNATURE);\r
277 }\r
278 }\r
18b144ea 279}\r
280\r
b422b62c 281\r
18b144ea 282/**\r
283 Initialize debug agent.\r
284\r
285 This function is used to set up debug enviroment for DXE phase.\r
286\r
287 If this function is called by DXE Core, Context must be the pointer\r
288 to HOB list which will be used to get GUIDed HOB. It will enable\r
289 interrupt to support break-in feature.\r
290 If this function is called by DXE module, Context must be NULL. It\r
291 will enable interrupt to support break-in feature.\r
292\r
293 @param[in] InitFlag Init flag is used to decide initialize process.\r
294 @param[in] Context Context needed according to InitFlag.\r
295 @param[in] Function Continue function called by debug agent library; it was\r
296 optional.\r
297\r
298**/\r
299VOID\r
300EFIAPI\r
301InitializeDebugAgent (\r
302 IN UINT32 InitFlag,\r
303 IN VOID *Context, OPTIONAL\r
304 IN DEBUG_AGENT_CONTINUE Function OPTIONAL\r
305 )\r
306{\r
b422b62c 307 UINT64 *MailboxLocation;\r
18b144ea 308 DEBUG_AGENT_MAILBOX *Mailbox;\r
18b144ea 309 BOOLEAN InterruptStatus;\r
b422b62c 310 VOID *HobList;\r
311 IA32_DESCRIPTOR IdtDescriptor;\r
312 IA32_DESCRIPTOR *Ia32Idtr;\r
313 IA32_IDT_ENTRY *Ia32IdtEntry;\r
18b144ea 314\r
b422b62c 315 if (InitFlag == DEBUG_AGENT_INIT_DXE_AP) {\r
316 //\r
317 // Invoked by AP, enable interrupt to let AP could receive IPI from other processors\r
318 //\r
319 EnableInterrupts ();\r
320 return ;\r
18b144ea 321 }\r
322\r
b422b62c 323 // \r
324 // Disable Debug Timer interrupt\r
325 //\r
326 SaveAndSetDebugTimerInterrupt (FALSE);\r
18b144ea 327 //\r
328 // Save and disable original interrupt status\r
329 //\r
330 InterruptStatus = SaveAndDisableInterrupts ();\r
331\r
b422b62c 332 //\r
333 // Try to get mailbox firstly\r
334 //\r
335 HobList = NULL;\r
336 Mailbox = NULL;\r
337 MailboxLocation = NULL;\r
338\r
339 switch (InitFlag) {\r
340\r
341 case DEBUG_AGENT_INIT_DXE_LOAD:\r
18b144ea 342 //\r
b422b62c 343 // Check if Debug Agent has been initialized before\r
18b144ea 344 //\r
b422b62c 345 if (IsDebugAgentInitialzed ()) {\r
346 DEBUG ((EFI_D_INFO, "Debug Agent: The former agent will be overwritten by the new one!\n"));\r
347 }\r
348\r
349 mMultiProcessorDebugSupport = TRUE;\r
93c0bdec 350 //\r
b422b62c 351 // Save original IDT table\r
352 //\r
353 AsmReadIdtr (&IdtDescriptor);\r
354 mSaveIdtTableSize = IdtDescriptor.Limit + 1;\r
355 mSavedIdtTable = AllocateCopyPool (mSaveIdtTableSize, (VOID *) IdtDescriptor.Base);\r
356 //\r
357 // Initialize Debug Timer hardware\r
358 //\r
359 InitializeDebugTimer ();\r
360 //\r
361 // Check if Debug Agent initialized in DXE phase\r
362 //\r
363 Mailbox = GetMailboxFromConfigurationTable ();\r
364 if (Mailbox == NULL) {\r
365 //\r
366 // Try to get mailbox from GUIDed HOB build in PEI \r
367 //\r
368 HobList = GetHobList ();\r
369 Mailbox = GetMailboxFromHob (HobList);\r
370 }\r
371 //\r
372 // Set up IDT table and prepare for IDT entries\r
373 //\r
374 SetupDebugAgentEnviroment (Mailbox);\r
375 //\r
376 // For DEBUG_AGENT_INIT_S3, needn't to install configuration table and EFI Serial IO protocol\r
377 // For DEBUG_AGENT_INIT_DXE_CORE, InternalConstructorWorker() will invoked in Constructor()\r
378 //\r
379 InternalConstructorWorker ();\r
380 //\r
381 // Enable interrupt to receive Debug Timer interrupt\r
93c0bdec 382 //\r
18b144ea 383 EnableInterrupts ();\r
384\r
b422b62c 385 mDebugAgentInitialized = TRUE;\r
386 FindAndReportModuleImageInfo (SIZE_4KB);\r
387\r
388 *(EFI_STATUS *)Context = EFI_SUCCESS;\r
389\r
390 if (gST->ConOut != NULL) {\r
391 Print (L"Debug Agent: Initialized successfully!\r\n");\r
392 Print (L"If the Debug Port is serial port, please make sure this serial port isn't connected by ISA Serial driver\r\n");\r
393 Print (L"You could do the following steps to disconnect the serial port:\r\n");\r
394 Print (L"1: Shell> drivers\r\n");\r
395 Print (L" ...\r\n");\r
396 Print (L" V VERSION E G G #D #C DRIVER NAME IMAGE NAME\r\n");\r
397 Print (L" == ======== = = = == == =================================== ===================\r\n");\r
398 Print (L" 8F 0000000A B - - 1 14 PCI Bus Driver PciBusDxe\r\n");\r
399 Print (L" 91 00000010 ? - - - - ATA Bus Driver AtaBusDxe\r\n");\r
400 Print (L" ...\r\n");\r
401 Print (L" A7 0000000A B - - 1 1 ISA Serial Driver IsaSerialDxe\r\n");\r
402 Print (L" ...\r\n");\r
403 Print (L"2: Shell> dh -d A7\r\n");\r
404 Print (L" A7: Image(IsaSerialDxe) ImageDevPath (..9FB3-11D4-9A3A-0090273FC14D))DriverBinding ComponentName ComponentName2\r\n");\r
405 Print (L" Driver Name : ISA Serial Driver\r\n");\r
406 Print (L" Image Name : FvFile(93B80003-9FB3-11D4-9A3A-0090273FC14D)\r\n");\r
407 Print (L" Driver Version : 0000000A\r\n");\r
408 Print (L" Driver Type : BUS\r\n");\r
409 Print (L" Configuration : NO\r\n");\r
410 Print (L" Diagnostics : NO\r\n");\r
411 Print (L" Managing :\r\n");\r
412 Print (L" Ctrl[EA] : PciRoot(0x0)/Pci(0x1F,0x0)/Serial(0x0)\r\n");\r
413 Print (L" Child[EB] : PciRoot(0x0)/Pci(0x1F,0x0)/Serial(0x0)/Uart(115200,8,N,1)\r\n");\r
414 Print (L"3: Shell> disconnect EA\r\n");\r
415 Print (L"4: Shell> load -nc DebugAgentDxe.efi\r\n\r\n");\r
416 }\r
417 break;\r
418\r
419 case DEBUG_AGENT_INIT_DXE_UNLOAD:\r
420 if (mDebugAgentInitialized) {\r
421 if (IsHostAttached ()) {\r
422 Print (L"Debug Agent: Host is still connected, please de-attach TARGET firstly!\r\n");\r
423 *(EFI_STATUS *)Context = EFI_ACCESS_DENIED;\r
424 // \r
425 // Enable Debug Timer interrupt again\r
426 //\r
427 SaveAndSetDebugTimerInterrupt (TRUE);\r
428 } else {\r
429 //\r
430 // Restore original IDT table\r
431 //\r
432 AsmReadIdtr (&IdtDescriptor);\r
433 IdtDescriptor.Limit = (UINT16) (mSaveIdtTableSize - 1);\r
434 CopyMem ((VOID *) IdtDescriptor.Base, mSavedIdtTable, mSaveIdtTableSize);\r
435 AsmWriteIdtr (&IdtDescriptor);\r
436 FreePool (mSavedIdtTable);\r
437 mDebugAgentInitialized = FALSE;\r
438 *(EFI_STATUS *)Context = EFI_SUCCESS;\r
439 }\r
440 } else {\r
441 Print (L"Debug Agent: It hasn't been initialized, cannot unload it!\r\n");\r
442 *(EFI_STATUS *)Context = EFI_NOT_STARTED;\r
443 }\r
18b144ea 444\r
18b144ea 445 //\r
b422b62c 446 // Restore interrupt state.\r
18b144ea 447 //\r
b422b62c 448 SetInterruptState (InterruptStatus);\r
449 break;\r
18b144ea 450\r
b422b62c 451 case DEBUG_AGENT_INIT_DXE_CORE:\r
452 mDxeCoreFlag = TRUE;\r
453 mMultiProcessorDebugSupport = TRUE;\r
18b144ea 454 //\r
b422b62c 455 // Initialize Debug Timer hardware\r
18b144ea 456 //\r
b422b62c 457 InitializeDebugTimer ();\r
18b144ea 458 //\r
b422b62c 459 // Try to get mailbox from GUIDed HOB build in PEI \r
18b144ea 460 //\r
b422b62c 461 HobList = Context;\r
462 Mailbox = GetMailboxFromHob (HobList);\r
463 //\r
464 // Set up IDT table and prepare for IDT entries\r
465 //\r
466 SetupDebugAgentEnviroment (Mailbox);\r
467 //\r
468 // Enable interrupt to receive Debug Timer interrupt\r
469 //\r
470 EnableInterrupts ();\r
18b144ea 471\r
b422b62c 472 break;\r
18b144ea 473\r
b422b62c 474 case DEBUG_AGENT_INIT_S3:\r
18b144ea 475\r
b422b62c 476 if (Context != NULL) {\r
477 Ia32Idtr = (IA32_DESCRIPTOR *) Context;\r
478 Ia32IdtEntry = (IA32_IDT_ENTRY *)(Ia32Idtr->Base);\r
479 MailboxLocation = (UINT64 *) (UINTN) (Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetLow + \r
480 (Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetHigh << 16));\r
481 Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation);\r
482 VerifyMailboxChecksum (Mailbox);\r
483 }\r
18b144ea 484 //\r
b422b62c 485 // Set up IDT table and prepare for IDT entries\r
18b144ea 486 //\r
b422b62c 487 SetupDebugAgentEnviroment (Mailbox);\r
18b144ea 488 //\r
b422b62c 489 // Disable interrupt\r
18b144ea 490 //\r
b422b62c 491 DisableInterrupts ();\r
492 FindAndReportModuleImageInfo (SIZE_4KB);\r
493 if (GetDebugFlag (DEBUG_AGENT_FLAG_BREAK_BOOT_SCRIPT) == 1) {\r
494 //\r
495 // If Boot Script entry break is set, code will be break at here.\r
496 //\r
497 CpuBreakpoint ();\r
498 }\r
499 break;\r
500\r
501 default:\r
18b144ea 502 //\r
b422b62c 503 // Only DEBUG_AGENT_INIT_PREMEM_SEC and DEBUG_AGENT_INIT_POSTMEM_SEC are allowed for this \r
504 // Debug Agent library instance.\r
18b144ea 505 //\r
b422b62c 506 DEBUG ((EFI_D_ERROR, "Debug Agent: The InitFlag value is not allowed!\n"));\r
507 CpuDeadLoop ();\r
508 break;\r
18b144ea 509 }\r
18b144ea 510}\r