]> git.proxmox.com Git - mirror_edk2.git/blob - SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/DxeDebugAgentLib.c
SourceLevelDebugPkg/DebugTimer: Dump Debug Timer parameter
[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 - 2015, 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 DEBUG_AGENT_MAILBOX *Mailbox;
59 DEBUG_AGENT_MAILBOX *NewMailbox;
60 EFI_HOB_GUID_TYPE *GuidHob;
61 EFI_VECTOR_HANDOFF_INFO *VectorHandoffInfo;
62
63 //
64 // Check persisted vector handoff info
65 //
66 Status = EFI_SUCCESS;
67 GuidHob = GetFirstGuidHob (&gEfiVectorHandoffInfoPpiGuid);
68 if (GuidHob != NULL && !mDxeCoreFlag) {
69 //
70 // Check if configuration table is installed or not if GUIDed HOB existed,
71 // only when Debug Agent is not linked by DXE Core
72 //
73 Status = EfiGetSystemConfigurationTable (&gEfiVectorHandoffTableGuid, (VOID **) &VectorHandoffInfo);
74 }
75 if (GuidHob == NULL || Status != EFI_SUCCESS) {
76 //
77 // Install configuration table for persisted vector handoff info if GUIDed HOB cannot be found or
78 // configuration table does not exist
79 //
80 Status = gBS->InstallConfigurationTable (&gEfiVectorHandoffTableGuid, (VOID *) &mVectorHandoffInfoDebugAgent[0]);
81 if (EFI_ERROR (Status)) {
82 DEBUG ((EFI_D_ERROR, "DebugAgent: Cannot install configuration table for persisted vector handoff info!\n"));
83 CpuDeadLoop ();
84 }
85 }
86
87 //
88 // Install EFI Serial IO protocol on debug port
89 //
90 InstallSerialIo ();
91
92 Address = 0;
93 Status = gBS->AllocatePages (
94 AllocateAnyPages,
95 EfiACPIMemoryNVS,
96 EFI_SIZE_TO_PAGES (sizeof(DEBUG_AGENT_MAILBOX) + PcdGet16(PcdDebugPortHandleBufferSize)),
97 &Address
98 );
99 if (EFI_ERROR (Status)) {
100 DEBUG ((EFI_D_ERROR, "DebugAgent: Cannot install configuration table for mailbox!\n"));
101 CpuDeadLoop ();
102 }
103
104 DebugTimerInterruptState = SaveAndSetDebugTimerInterrupt (FALSE);
105
106 NewMailbox = (DEBUG_AGENT_MAILBOX *) (UINTN) Address;
107 //
108 // Copy Mailbox and Debug Port Handle buffer to new location in ACPI NVS memory, because original Mailbox
109 // and Debug Port Handle buffer may be free at runtime, SMM debug agent needs to access them
110 //
111 Mailbox = GetMailboxPointer ();
112 CopyMem (NewMailbox, Mailbox, sizeof (DEBUG_AGENT_MAILBOX));
113 CopyMem (NewMailbox + 1, (VOID *)(UINTN)Mailbox->DebugPortHandle, PcdGet16(PcdDebugPortHandleBufferSize));
114 //
115 // Update Debug Port Handle in new Mailbox
116 //
117 UpdateMailboxContent (NewMailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, (UINT64)(UINTN)(NewMailbox + 1));
118 mMailboxPointer = NewMailbox;
119
120 DebugTimerInterruptState = SaveAndSetDebugTimerInterrupt (DebugTimerInterruptState);
121
122 Status = gBS->InstallConfigurationTable (&gEfiDebugAgentGuid, (VOID *) mMailboxPointer);
123 if (EFI_ERROR (Status)) {
124 DEBUG ((EFI_D_ERROR, "DebugAgent: Failed to install configuration for mailbox!\n"));
125 CpuDeadLoop ();
126 }
127 }
128
129 /**
130 Debug Agent constructor function.
131
132 @param[in] ImageHandle The firmware allocated handle for the EFI image.
133 @param[in] SystemTable A pointer to the EFI System Table.
134
135 @retval RETURN_SUCCESS When this function completed.
136
137 **/
138 RETURN_STATUS
139 EFIAPI
140 DxeDebugAgentLibConstructor (
141 IN EFI_HANDLE ImageHandle,
142 IN EFI_SYSTEM_TABLE *SystemTable
143 )
144 {
145 if (mDxeCoreFlag) {
146 //
147 // Invoke internal constructor function only when DXE core links this library instance
148 //
149 InternalConstructorWorker ();
150 }
151
152 return RETURN_SUCCESS;
153 }
154
155 /**
156 Get the pointer to Mailbox from the configuration table.
157
158 @return Pointer to Mailbox.
159
160 **/
161 DEBUG_AGENT_MAILBOX *
162 GetMailboxFromConfigurationTable (
163 VOID
164 )
165 {
166 EFI_STATUS Status;
167 DEBUG_AGENT_MAILBOX *Mailbox;
168
169 Status = EfiGetSystemConfigurationTable (&gEfiDebugAgentGuid, (VOID **) &Mailbox);
170 if (Status == EFI_SUCCESS && Mailbox != NULL) {
171 VerifyMailboxChecksum (Mailbox);
172 return Mailbox;
173 } else {
174 return NULL;
175 }
176 }
177
178 /**
179 Get the pointer to Mailbox from the GUIDed HOB.
180
181 @param[in] HobStart The starting HOB pointer to search from.
182
183 @return Pointer to Mailbox.
184
185 **/
186 DEBUG_AGENT_MAILBOX *
187 GetMailboxFromHob (
188 IN VOID *HobStart
189 )
190 {
191 EFI_HOB_GUID_TYPE *GuidHob;
192 UINT64 *MailboxLocation;
193 DEBUG_AGENT_MAILBOX *Mailbox;
194
195 GuidHob = GetNextGuidHob (&gEfiDebugAgentGuid, HobStart);
196 if (GuidHob == NULL) {
197 return NULL;
198 }
199 MailboxLocation = (UINT64 *) (GET_GUID_HOB_DATA(GuidHob));
200 Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation);
201 VerifyMailboxChecksum (Mailbox);
202
203 return Mailbox;
204 }
205
206 /**
207 Get Debug Agent Mailbox pointer.
208
209 @return Mailbox pointer.
210
211 **/
212 DEBUG_AGENT_MAILBOX *
213 GetMailboxPointer (
214 VOID
215 )
216 {
217 AcquireMpSpinLock (&mDebugMpContext.MailboxSpinLock);
218 VerifyMailboxChecksum (mMailboxPointer);
219 ReleaseMpSpinLock (&mDebugMpContext.MailboxSpinLock);
220 return mMailboxPointer;
221 }
222
223 /**
224 Get debug port handle.
225
226 @return Debug port handle.
227
228 **/
229 DEBUG_PORT_HANDLE
230 GetDebugPortHandle (
231 VOID
232 )
233 {
234 return (DEBUG_PORT_HANDLE) (UINTN)(GetMailboxPointer ()->DebugPortHandle);
235 }
236
237 /**
238 Worker function to set up Debug Agent environment.
239
240 This function will set up IDT table and initialize the IDT entries and
241 initialize CPU LOCAL APIC timer.
242 It also tries to connect HOST if Debug Agent was not initialized before.
243
244 @param[in] Mailbox Pointer to Mailbox.
245
246 **/
247 VOID
248 SetupDebugAgentEnvironment (
249 IN DEBUG_AGENT_MAILBOX *Mailbox
250 )
251 {
252 IA32_DESCRIPTOR Idtr;
253 UINT16 IdtEntryCount;
254 UINT64 DebugPortHandle;
255 UINT32 DebugTimerFrequency;
256
257 if (mMultiProcessorDebugSupport) {
258 InitializeSpinLock (&mDebugMpContext.MpContextSpinLock);
259 InitializeSpinLock (&mDebugMpContext.DebugPortSpinLock);
260 InitializeSpinLock (&mDebugMpContext.MailboxSpinLock);
261 //
262 // Clear Break CPU index value
263 //
264 mDebugMpContext.BreakAtCpuIndex = (UINT32) -1;
265 }
266
267 //
268 // Get original IDT address and size.
269 //
270 AsmReadIdtr ((IA32_DESCRIPTOR *) &Idtr);
271 IdtEntryCount = (UINT16) ((Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR));
272 if (IdtEntryCount < 33) {
273 ZeroMem (&mIdtEntryTable, sizeof (IA32_IDT_GATE_DESCRIPTOR) * 33);
274 //
275 // Copy original IDT table into new one
276 //
277 CopyMem (&mIdtEntryTable, (VOID *) Idtr.Base, Idtr.Limit + 1);
278 //
279 // Load new IDT table
280 //
281 Idtr.Limit = (UINT16) (sizeof (IA32_IDT_GATE_DESCRIPTOR) * 33 - 1);
282 Idtr.Base = (UINTN) &mIdtEntryTable;
283 AsmWriteIdtr ((IA32_DESCRIPTOR *) &Idtr);
284 }
285
286 //
287 // Initialize the IDT table entries to support source level debug.
288 //
289 InitializeDebugIdt ();
290
291 //
292 // If mMailboxPointer is not set before, set it
293 //
294 if (mMailboxPointer == NULL) {
295 if (Mailbox != NULL) {
296 //
297 // If Mailbox exists, copy it into one global variable
298 //
299 CopyMem (&mMailbox, Mailbox, sizeof (DEBUG_AGENT_MAILBOX));
300 } else {
301 ZeroMem (&mMailbox, sizeof (DEBUG_AGENT_MAILBOX));
302 }
303 mMailboxPointer = &mMailbox;
304 }
305
306 //
307 // Initialize Debug Timer hardware and save its initial count and frequency
308 //
309 mDebugMpContext.DebugTimerInitCount = InitializeDebugTimer (&DebugTimerFrequency, TRUE);
310 UpdateMailboxContent (mMailboxPointer, DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY, DebugTimerFrequency);
311 //
312 // Initialize debug communication port
313 //
314 DebugPortHandle = (UINT64) (UINTN)DebugPortInitialize ((VOID *)(UINTN)mMailboxPointer->DebugPortHandle, NULL);
315 UpdateMailboxContent (mMailboxPointer, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle);
316
317 if (Mailbox == NULL) {
318 //
319 // Trigger one software interrupt to inform HOST
320 //
321 TriggerSoftInterrupt (SYSTEM_RESET_SIGNATURE);
322 SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1);
323 //
324 // Memory has been ready
325 //
326 if (IsHostAttached ()) {
327 //
328 // Trigger one software interrupt to inform HOST
329 //
330 TriggerSoftInterrupt (MEMORY_READY_SIGNATURE);
331 }
332 }
333 }
334
335
336 /**
337 Initialize debug agent.
338
339 This function is used to set up debug environment for DXE phase.
340
341 If this function is called by DXE Core, Context must be the pointer
342 to HOB list which will be used to get GUIDed HOB. It will enable
343 interrupt to support break-in feature.
344 If this function is called by DXE module, Context must be NULL. It
345 will enable interrupt to support break-in feature.
346
347 @param[in] InitFlag Init flag is used to decide initialize process.
348 @param[in] Context Context needed according to InitFlag.
349 @param[in] Function Continue function called by debug agent library; it was
350 optional.
351
352 **/
353 VOID
354 EFIAPI
355 InitializeDebugAgent (
356 IN UINT32 InitFlag,
357 IN VOID *Context, OPTIONAL
358 IN DEBUG_AGENT_CONTINUE Function OPTIONAL
359 )
360 {
361 UINT64 *MailboxLocation;
362 DEBUG_AGENT_MAILBOX *Mailbox;
363 BOOLEAN InterruptStatus;
364 VOID *HobList;
365 IA32_DESCRIPTOR IdtDescriptor;
366 IA32_DESCRIPTOR *Ia32Idtr;
367 IA32_IDT_ENTRY *Ia32IdtEntry;
368
369 if (InitFlag == DEBUG_AGENT_INIT_DXE_AP) {
370 //
371 // Invoked by AP, enable interrupt to let AP could receive IPI from other processors
372 //
373 EnableInterrupts ();
374 return ;
375 }
376
377 //
378 // Disable Debug Timer interrupt
379 //
380 SaveAndSetDebugTimerInterrupt (FALSE);
381 //
382 // Save and disable original interrupt status
383 //
384 InterruptStatus = SaveAndDisableInterrupts ();
385
386 //
387 // Try to get mailbox firstly
388 //
389 HobList = NULL;
390 Mailbox = NULL;
391 MailboxLocation = NULL;
392
393 switch (InitFlag) {
394
395 case DEBUG_AGENT_INIT_DXE_LOAD:
396 //
397 // Check if Debug Agent has been initialized before
398 //
399 if (IsDebugAgentInitialzed ()) {
400 DEBUG ((EFI_D_INFO, "Debug Agent: The former agent will be overwritten by the new one!\n"));
401 }
402
403 mMultiProcessorDebugSupport = TRUE;
404 //
405 // Save original IDT table
406 //
407 AsmReadIdtr (&IdtDescriptor);
408 mSaveIdtTableSize = IdtDescriptor.Limit + 1;
409 mSavedIdtTable = AllocateCopyPool (mSaveIdtTableSize, (VOID *) IdtDescriptor.Base);
410 //
411 // Check if Debug Agent initialized in DXE phase
412 //
413 Mailbox = GetMailboxFromConfigurationTable ();
414 if (Mailbox == NULL) {
415 //
416 // Try to get mailbox from GUIDed HOB build in PEI
417 //
418 HobList = GetHobList ();
419 Mailbox = GetMailboxFromHob (HobList);
420 }
421 //
422 // Set up Debug Agent Environment and try to connect HOST if required
423 //
424 SetupDebugAgentEnvironment (Mailbox);
425 //
426 // For DEBUG_AGENT_INIT_S3, needn't to install configuration table and EFI Serial IO protocol
427 // For DEBUG_AGENT_INIT_DXE_CORE, InternalConstructorWorker() will invoked in Constructor()
428 //
429 InternalConstructorWorker ();
430 //
431 // Enable interrupt to receive Debug Timer interrupt
432 //
433 EnableInterrupts ();
434
435 mDebugAgentInitialized = TRUE;
436 FindAndReportModuleImageInfo (SIZE_4KB);
437
438 *(EFI_STATUS *)Context = EFI_SUCCESS;
439
440 break;
441
442 case DEBUG_AGENT_INIT_DXE_UNLOAD:
443 if (mDebugAgentInitialized) {
444 if (IsHostAttached ()) {
445 *(EFI_STATUS *)Context = EFI_ACCESS_DENIED;
446 //
447 // Enable Debug Timer interrupt again
448 //
449 SaveAndSetDebugTimerInterrupt (TRUE);
450 } else {
451 //
452 // Restore original IDT table
453 //
454 AsmReadIdtr (&IdtDescriptor);
455 IdtDescriptor.Limit = (UINT16) (mSaveIdtTableSize - 1);
456 CopyMem ((VOID *) IdtDescriptor.Base, mSavedIdtTable, mSaveIdtTableSize);
457 AsmWriteIdtr (&IdtDescriptor);
458 FreePool (mSavedIdtTable);
459 mDebugAgentInitialized = FALSE;
460 *(EFI_STATUS *)Context = EFI_SUCCESS;
461 }
462 } else {
463 *(EFI_STATUS *)Context = EFI_NOT_STARTED;
464 }
465
466 //
467 // Restore interrupt state.
468 //
469 SetInterruptState (InterruptStatus);
470 break;
471
472 case DEBUG_AGENT_INIT_DXE_CORE:
473 mDxeCoreFlag = TRUE;
474 mMultiProcessorDebugSupport = TRUE;
475 //
476 // Try to get mailbox from GUIDed HOB build in PEI
477 //
478 HobList = Context;
479 Mailbox = GetMailboxFromHob (HobList);
480 //
481 // Set up Debug Agent Environment and try to connect HOST if required
482 //
483 SetupDebugAgentEnvironment (Mailbox);
484 //
485 // Enable interrupt to receive Debug Timer interrupt
486 //
487 EnableInterrupts ();
488
489 break;
490
491 case DEBUG_AGENT_INIT_S3:
492
493 if (Context != NULL) {
494 Ia32Idtr = (IA32_DESCRIPTOR *) Context;
495 Ia32IdtEntry = (IA32_IDT_ENTRY *)(Ia32Idtr->Base);
496 MailboxLocation = (UINT64 *) (UINTN) (Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetLow +
497 (Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetHigh << 16));
498 Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation);
499 VerifyMailboxChecksum (Mailbox);
500 }
501 //
502 // Save Mailbox pointer in global variable
503 //
504 mMailboxPointer = Mailbox;
505 //
506 // Set up Debug Agent Environment and try to connect HOST if required
507 //
508 SetupDebugAgentEnvironment (Mailbox);
509 //
510 // Disable interrupt
511 //
512 DisableInterrupts ();
513 FindAndReportModuleImageInfo (SIZE_4KB);
514 if (GetDebugFlag (DEBUG_AGENT_FLAG_BREAK_BOOT_SCRIPT) == 1) {
515 //
516 // If Boot Script entry break is set, code will be break at here.
517 //
518 CpuBreakpoint ();
519 }
520 break;
521
522 default:
523 //
524 // Only DEBUG_AGENT_INIT_PREMEM_SEC and DEBUG_AGENT_INIT_POSTMEM_SEC are allowed for this
525 // Debug Agent library instance.
526 //
527 DEBUG ((EFI_D_ERROR, "Debug Agent: The InitFlag value is not allowed!\n"));
528 CpuDeadLoop ();
529 break;
530 }
531 }