]> git.proxmox.com Git - mirror_edk2.git/blob - SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/DxeDebugAgentLib.c
Not to copy mailbox into new space when debug agent initialization for S3 Boot Script.
[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 - 2014, 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 setup IDT table and initialize the IDT entries.
239
240 @param[in] Mailbox Pointer to Mailbox.
241
242 **/
243 VOID
244 SetupDebugAgentEnviroment (
245 IN DEBUG_AGENT_MAILBOX *Mailbox
246 )
247 {
248 IA32_DESCRIPTOR Idtr;
249 UINT16 IdtEntryCount;
250 UINT64 DebugPortHandle;
251
252 if (mMultiProcessorDebugSupport) {
253 InitializeSpinLock (&mDebugMpContext.MpContextSpinLock);
254 InitializeSpinLock (&mDebugMpContext.DebugPortSpinLock);
255 InitializeSpinLock (&mDebugMpContext.MailboxSpinLock);
256 //
257 // Clear Break CPU index value
258 //
259 mDebugMpContext.BreakAtCpuIndex = (UINT32) -1;
260 }
261
262 //
263 // Get original IDT address and size.
264 //
265 AsmReadIdtr ((IA32_DESCRIPTOR *) &Idtr);
266 IdtEntryCount = (UINT16) ((Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR));
267 if (IdtEntryCount < 33) {
268 ZeroMem (&mIdtEntryTable, sizeof (IA32_IDT_GATE_DESCRIPTOR) * 33);
269 //
270 // Copy original IDT table into new one
271 //
272 CopyMem (&mIdtEntryTable, (VOID *) Idtr.Base, Idtr.Limit + 1);
273 //
274 // Load new IDT table
275 //
276 Idtr.Limit = (UINT16) (sizeof (IA32_IDT_GATE_DESCRIPTOR) * 33 - 1);
277 Idtr.Base = (UINTN) &mIdtEntryTable;
278 AsmWriteIdtr ((IA32_DESCRIPTOR *) &Idtr);
279 }
280
281 //
282 // Initialize the IDT table entries to support source level debug.
283 //
284 InitializeDebugIdt ();
285
286 //
287 // If mMailboxPointer is not set before, set it
288 //
289 if (mMailboxPointer == NULL) {
290 if (Mailbox != NULL) {
291 //
292 // If Mailbox exists, copy it into one global variable
293 //
294 CopyMem (&mMailbox, Mailbox, sizeof (DEBUG_AGENT_MAILBOX));
295 } else {
296 ZeroMem (&mMailbox, sizeof (DEBUG_AGENT_MAILBOX));
297 }
298 mMailboxPointer = &mMailbox;
299 }
300
301 //
302 // Initialize debug communication port
303 //
304 DebugPortHandle = (UINT64) (UINTN)DebugPortInitialize ((VOID *)(UINTN)mMailboxPointer->DebugPortHandle, NULL);
305 UpdateMailboxContent (mMailboxPointer, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle);
306
307 if (Mailbox == NULL) {
308 //
309 // Trigger one software interrupt to inform HOST
310 //
311 TriggerSoftInterrupt (SYSTEM_RESET_SIGNATURE);
312 SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1);
313 //
314 // Memory has been ready
315 //
316 if (IsHostAttached ()) {
317 //
318 // Trigger one software interrupt to inform HOST
319 //
320 TriggerSoftInterrupt (MEMORY_READY_SIGNATURE);
321 }
322 }
323 }
324
325
326 /**
327 Initialize debug agent.
328
329 This function is used to set up debug enviroment for DXE phase.
330
331 If this function is called by DXE Core, Context must be the pointer
332 to HOB list which will be used to get GUIDed HOB. It will enable
333 interrupt to support break-in feature.
334 If this function is called by DXE module, Context must be NULL. It
335 will enable interrupt to support break-in feature.
336
337 @param[in] InitFlag Init flag is used to decide initialize process.
338 @param[in] Context Context needed according to InitFlag.
339 @param[in] Function Continue function called by debug agent library; it was
340 optional.
341
342 **/
343 VOID
344 EFIAPI
345 InitializeDebugAgent (
346 IN UINT32 InitFlag,
347 IN VOID *Context, OPTIONAL
348 IN DEBUG_AGENT_CONTINUE Function OPTIONAL
349 )
350 {
351 UINT64 *MailboxLocation;
352 DEBUG_AGENT_MAILBOX *Mailbox;
353 BOOLEAN InterruptStatus;
354 VOID *HobList;
355 IA32_DESCRIPTOR IdtDescriptor;
356 IA32_DESCRIPTOR *Ia32Idtr;
357 IA32_IDT_ENTRY *Ia32IdtEntry;
358
359 if (InitFlag == DEBUG_AGENT_INIT_DXE_AP) {
360 //
361 // Invoked by AP, enable interrupt to let AP could receive IPI from other processors
362 //
363 EnableInterrupts ();
364 return ;
365 }
366
367 //
368 // Disable Debug Timer interrupt
369 //
370 SaveAndSetDebugTimerInterrupt (FALSE);
371 //
372 // Save and disable original interrupt status
373 //
374 InterruptStatus = SaveAndDisableInterrupts ();
375
376 //
377 // Try to get mailbox firstly
378 //
379 HobList = NULL;
380 Mailbox = NULL;
381 MailboxLocation = NULL;
382
383 switch (InitFlag) {
384
385 case DEBUG_AGENT_INIT_DXE_LOAD:
386 //
387 // Check if Debug Agent has been initialized before
388 //
389 if (IsDebugAgentInitialzed ()) {
390 DEBUG ((EFI_D_INFO, "Debug Agent: The former agent will be overwritten by the new one!\n"));
391 }
392
393 mMultiProcessorDebugSupport = TRUE;
394 //
395 // Save original IDT table
396 //
397 AsmReadIdtr (&IdtDescriptor);
398 mSaveIdtTableSize = IdtDescriptor.Limit + 1;
399 mSavedIdtTable = AllocateCopyPool (mSaveIdtTableSize, (VOID *) IdtDescriptor.Base);
400 //
401 // Initialize Debug Timer hardware
402 //
403 InitializeDebugTimer ();
404 //
405 // Check if Debug Agent initialized in DXE phase
406 //
407 Mailbox = GetMailboxFromConfigurationTable ();
408 if (Mailbox == NULL) {
409 //
410 // Try to get mailbox from GUIDed HOB build in PEI
411 //
412 HobList = GetHobList ();
413 Mailbox = GetMailboxFromHob (HobList);
414 }
415 //
416 // Set up IDT table and prepare for IDT entries
417 //
418 SetupDebugAgentEnviroment (Mailbox);
419 //
420 // For DEBUG_AGENT_INIT_S3, needn't to install configuration table and EFI Serial IO protocol
421 // For DEBUG_AGENT_INIT_DXE_CORE, InternalConstructorWorker() will invoked in Constructor()
422 //
423 InternalConstructorWorker ();
424 //
425 // Enable interrupt to receive Debug Timer interrupt
426 //
427 EnableInterrupts ();
428
429 mDebugAgentInitialized = TRUE;
430 FindAndReportModuleImageInfo (SIZE_4KB);
431
432 *(EFI_STATUS *)Context = EFI_SUCCESS;
433
434 if (gST->ConOut != NULL) {
435 Print (L"Debug Agent: Initialized successfully!\r\n");
436 Print (L"If the Debug Port is serial port, please make sure this serial port isn't connected by ISA Serial driver\r\n");
437 Print (L"You could do the following steps to disconnect the serial port:\r\n");
438 Print (L"1: Shell> drivers\r\n");
439 Print (L" ...\r\n");
440 Print (L" V VERSION E G G #D #C DRIVER NAME IMAGE NAME\r\n");
441 Print (L" == ======== = = = == == =================================== ===================\r\n");
442 Print (L" 8F 0000000A B - - 1 14 PCI Bus Driver PciBusDxe\r\n");
443 Print (L" 91 00000010 ? - - - - ATA Bus Driver AtaBusDxe\r\n");
444 Print (L" ...\r\n");
445 Print (L" A7 0000000A B - - 1 1 ISA Serial Driver IsaSerialDxe\r\n");
446 Print (L" ...\r\n");
447 Print (L"2: Shell> dh -d A7\r\n");
448 Print (L" A7: Image(IsaSerialDxe) ImageDevPath (..9FB3-11D4-9A3A-0090273FC14D))DriverBinding ComponentName ComponentName2\r\n");
449 Print (L" Driver Name : ISA Serial Driver\r\n");
450 Print (L" Image Name : FvFile(93B80003-9FB3-11D4-9A3A-0090273FC14D)\r\n");
451 Print (L" Driver Version : 0000000A\r\n");
452 Print (L" Driver Type : BUS\r\n");
453 Print (L" Configuration : NO\r\n");
454 Print (L" Diagnostics : NO\r\n");
455 Print (L" Managing :\r\n");
456 Print (L" Ctrl[EA] : PciRoot(0x0)/Pci(0x1F,0x0)/Serial(0x0)\r\n");
457 Print (L" Child[EB] : PciRoot(0x0)/Pci(0x1F,0x0)/Serial(0x0)/Uart(115200,8,N,1)\r\n");
458 Print (L"3: Shell> disconnect EA\r\n");
459 Print (L"4: Shell> load -nc DebugAgentDxe.efi\r\n\r\n");
460 }
461 break;
462
463 case DEBUG_AGENT_INIT_DXE_UNLOAD:
464 if (mDebugAgentInitialized) {
465 if (IsHostAttached ()) {
466 Print (L"Debug Agent: Host is still connected, please de-attach TARGET firstly!\r\n");
467 *(EFI_STATUS *)Context = EFI_ACCESS_DENIED;
468 //
469 // Enable Debug Timer interrupt again
470 //
471 SaveAndSetDebugTimerInterrupt (TRUE);
472 } else {
473 //
474 // Restore original IDT table
475 //
476 AsmReadIdtr (&IdtDescriptor);
477 IdtDescriptor.Limit = (UINT16) (mSaveIdtTableSize - 1);
478 CopyMem ((VOID *) IdtDescriptor.Base, mSavedIdtTable, mSaveIdtTableSize);
479 AsmWriteIdtr (&IdtDescriptor);
480 FreePool (mSavedIdtTable);
481 mDebugAgentInitialized = FALSE;
482 *(EFI_STATUS *)Context = EFI_SUCCESS;
483 }
484 } else {
485 Print (L"Debug Agent: It hasn't been initialized, cannot unload it!\r\n");
486 *(EFI_STATUS *)Context = EFI_NOT_STARTED;
487 }
488
489 //
490 // Restore interrupt state.
491 //
492 SetInterruptState (InterruptStatus);
493 break;
494
495 case DEBUG_AGENT_INIT_DXE_CORE:
496 mDxeCoreFlag = TRUE;
497 mMultiProcessorDebugSupport = TRUE;
498 //
499 // Initialize Debug Timer hardware
500 //
501 InitializeDebugTimer ();
502 //
503 // Try to get mailbox from GUIDed HOB build in PEI
504 //
505 HobList = Context;
506 Mailbox = GetMailboxFromHob (HobList);
507 //
508 // Set up IDT table and prepare for IDT entries
509 //
510 SetupDebugAgentEnviroment (Mailbox);
511 //
512 // Enable interrupt to receive Debug Timer interrupt
513 //
514 EnableInterrupts ();
515
516 break;
517
518 case DEBUG_AGENT_INIT_S3:
519
520 if (Context != NULL) {
521 Ia32Idtr = (IA32_DESCRIPTOR *) Context;
522 Ia32IdtEntry = (IA32_IDT_ENTRY *)(Ia32Idtr->Base);
523 MailboxLocation = (UINT64 *) (UINTN) (Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetLow +
524 (Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetHigh << 16));
525 Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation);
526 VerifyMailboxChecksum (Mailbox);
527 }
528 //
529 // Save Mailbox pointer in global variable
530 //
531 mMailboxPointer = Mailbox;
532 //
533 // Set up IDT table and prepare for IDT entries
534 //
535 SetupDebugAgentEnviroment (Mailbox);
536 //
537 // Disable interrupt
538 //
539 DisableInterrupts ();
540 FindAndReportModuleImageInfo (SIZE_4KB);
541 if (GetDebugFlag (DEBUG_AGENT_FLAG_BREAK_BOOT_SCRIPT) == 1) {
542 //
543 // If Boot Script entry break is set, code will be break at here.
544 //
545 CpuBreakpoint ();
546 }
547 break;
548
549 default:
550 //
551 // Only DEBUG_AGENT_INIT_PREMEM_SEC and DEBUG_AGENT_INIT_POSTMEM_SEC are allowed for this
552 // Debug Agent library instance.
553 //
554 DEBUG ((EFI_D_ERROR, "Debug Agent: The InitFlag value is not allowed!\n"));
555 CpuDeadLoop ();
556 break;
557 }
558 }