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