]> git.proxmox.com Git - mirror_edk2.git/blob - SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgent/SecPeiDebugAgentLib.c
Allocate ACPImemoryNVS type memory to save mailbox and debug port handle buffer since...
[mirror_edk2.git] / SourceLevelDebugPkg / Library / DebugAgent / SecPeiDebugAgent / SecPeiDebugAgentLib.c
1 /** @file
2 SEC Core Debug Agent Library instance implementition.
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 "SecPeiDebugAgentLib.h"
16
17 BOOLEAN mSkipBreakpoint = FALSE;
18
19 EFI_PEI_NOTIFY_DESCRIPTOR mMemoryDiscoveredNotifyList[1] = {
20 {
21 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
22 &gEfiPeiMemoryDiscoveredPpiGuid,
23 DebugAgentCallbackMemoryDiscoveredPpi
24 }
25 };
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 FALSE;
40 }
41
42 /**
43 Read the Attach/Break-in symbols from the debug port.
44
45 @param[in] Handle Pointer to Debug Port handle.
46 @param[out] BreakSymbol Returned break symbol.
47
48 @retval EFI_SUCCESS Read the symbol in BreakSymbol.
49 @retval EFI_NOT_FOUND No read the break symbol.
50
51 **/
52 EFI_STATUS
53 DebugReadBreakSymbol (
54 IN DEBUG_PORT_HANDLE Handle,
55 OUT UINT8 *BreakSymbol
56 )
57 {
58 EFI_STATUS Status;
59 DEBUG_PACKET_HEADER DebugHeader;
60 UINT8 *Data8;
61
62 *BreakSymbol = 0;
63 //
64 // If Debug Port buffer has data, read it till it was break symbol or Debug Port buffer empty.
65 //
66 Data8 = (UINT8 *) &DebugHeader;
67 while (TRUE) {
68 //
69 // If start symbol is not received
70 //
71 if (!DebugPortPollBuffer (Handle)) {
72 //
73 // If no data in Debug Port, exit
74 //
75 break;
76 }
77 //
78 // Try to read the start symbol
79 //
80 DebugPortReadBuffer (Handle, Data8, 1, 0);
81 if (*Data8 == DEBUG_STARTING_SYMBOL_ATTACH) {
82 *BreakSymbol = *Data8;
83 DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Debug Timer attach symbol received %x", *BreakSymbol);
84 return EFI_SUCCESS;
85 }
86 if (*Data8 == DEBUG_STARTING_SYMBOL_NORMAL) {
87 Status = ReadRemainingBreakPacket (Handle, &DebugHeader);
88 if (Status == EFI_SUCCESS) {
89 *BreakSymbol = DebugHeader.Command;
90 DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Debug Timer break symbol received %x", *BreakSymbol);
91 return EFI_SUCCESS;
92 }
93 if (Status == EFI_TIMEOUT) {
94 break;
95 }
96 }
97 }
98
99 return EFI_NOT_FOUND;
100 }
101
102 /**
103 Get the pointer to location saved Mailbox pointer from IDT entry.
104
105 **/
106 VOID *
107 GetLocationSavedMailboxPointerInIdtEntry (
108 VOID
109 )
110 {
111 UINTN *MailboxLocation;
112
113 MailboxLocation = (UINTN *) GetExceptionHandlerInIdtEntry (DEBUG_MAILBOX_VECTOR);
114 //
115 // *MailboxLocation is the pointer to Mailbox
116 //
117 VerifyMailboxChecksum ((DEBUG_AGENT_MAILBOX *) (*MailboxLocation));
118 return MailboxLocation;
119 }
120
121 /**
122 Set the pointer of Mailbox into IDT entry before memory is ready.
123
124 @param[in] MailboxLocation Pointer to location saved Mailbox pointer.
125
126 **/
127 VOID
128 SetLocationSavedMailboxPointerInIdtEntry (
129 IN VOID *MailboxLocation
130 )
131 {
132 SetExceptionHandlerInIdtEntry (DEBUG_MAILBOX_VECTOR, MailboxLocation);
133 }
134
135 /**
136 Get the location of Mailbox pointer from the GUIDed HOB.
137
138 @return Pointer to the location saved Mailbox pointer.
139
140 **/
141 UINT64 *
142 GetMailboxLocationFromHob (
143 VOID
144 )
145 {
146 EFI_HOB_GUID_TYPE *GuidHob;
147
148 GuidHob = GetFirstGuidHob (&gEfiDebugAgentGuid);
149 if (GuidHob == NULL) {
150 return NULL;
151 }
152 return (UINT64 *) (GET_GUID_HOB_DATA(GuidHob));
153 }
154
155 /**
156 Get Debug Agent Mailbox pointer.
157
158 @return Mailbox pointer.
159
160 **/
161 DEBUG_AGENT_MAILBOX *
162 GetMailboxPointer (
163 VOID
164 )
165 {
166 UINT64 DebugPortHandle;
167 UINT64 *MailboxLocationInIdt;
168 UINT64 *MailboxLocationInHob;
169 DEBUG_AGENT_MAILBOX *Mailbox;
170
171 //
172 // Get mailbox from IDT entry firstly
173 //
174 MailboxLocationInIdt = GetLocationSavedMailboxPointerInIdtEntry ();
175 Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocationInIdt);
176 //
177 // Check if mailbox was setup in PEI firstly, cannot used GetDebugFlag() to
178 // get CheckMailboxInHob flag to avoid GetMailboxPointer() nesting.
179 //
180 if (Mailbox->DebugFlag.Bits.CheckMailboxInHob != 1) {
181 //
182 // If mailbox in IDT entry has already been the final one
183 //
184 return Mailbox;
185 }
186
187 MailboxLocationInHob = GetMailboxLocationFromHob ();
188 //
189 // Compare mailbox in IDT enry with mailbox in HOB
190 //
191 if (MailboxLocationInHob != MailboxLocationInIdt && MailboxLocationInHob != NULL) {
192 Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocationInHob);
193 //
194 // Fix up Debug Port handler and save new mailbox in IDT entry
195 //
196 Mailbox = (DEBUG_AGENT_MAILBOX *)((UINTN)Mailbox + ((UINTN)(MailboxLocationInHob) - (UINTN)MailboxLocationInIdt));
197 DebugPortHandle = (UINT64)((UINTN)Mailbox->DebugPortHandle + ((UINTN)(MailboxLocationInHob) - (UINTN)MailboxLocationInIdt));
198 UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle);
199 *MailboxLocationInHob = (UINT64)(UINTN)Mailbox;
200 SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationInHob);
201 //
202 // Clean CheckMailboxInHob flag
203 //
204 Mailbox->DebugFlag.Bits.CheckMailboxInHob = 0;
205 UpdateMailboxChecksum (Mailbox);
206 }
207
208 return Mailbox;
209 }
210
211 /**
212 Get debug port handle.
213
214 @return Debug port handle.
215
216 **/
217 DEBUG_PORT_HANDLE
218 GetDebugPortHandle (
219 VOID
220 )
221 {
222 DEBUG_AGENT_MAILBOX *DebugAgentMailbox;
223
224 DebugAgentMailbox = GetMailboxPointer ();
225
226 return (DEBUG_PORT_HANDLE) (UINTN)(DebugAgentMailbox->DebugPortHandle);
227 }
228
229 /**
230 Debug Agent provided notify callback function on Memory Discovered PPI.
231
232 @param[in] PeiServices Indirect reference to the PEI Services Table.
233 @param[in] NotifyDescriptor Address of the notification descriptor data structure.
234 @param[in] Ppi Address of the PPI that was installed.
235
236 @retval EFI_SUCCESS If the function completed successfully.
237
238 **/
239 EFI_STATUS
240 EFIAPI
241 DebugAgentCallbackMemoryDiscoveredPpi (
242 IN EFI_PEI_SERVICES **PeiServices,
243 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
244 IN VOID *Ppi
245 )
246 {
247 EFI_STATUS Status;
248 DEBUG_AGENT_MAILBOX *Mailbox;
249 BOOLEAN InterruptStatus;
250 EFI_PHYSICAL_ADDRESS Memory;
251 DEBUG_AGENT_MAILBOX *NewMailbox;
252 UINT64 *MailboxLocationInHob;
253
254 //
255 // Save and disable original interrupt status
256 //
257 InterruptStatus = SaveAndDisableInterrupts ();
258
259 //
260 // Allocate ACPI NVS memory for new Mailbox and Debug Port Handle buffer
261 //
262 Status = PeiServicesAllocatePages (
263 EfiACPIMemoryNVS,
264 EFI_SIZE_TO_PAGES (sizeof(DEBUG_AGENT_MAILBOX) + PcdGet16(PcdDebugPortHandleBufferSize)),
265 &Memory
266 );
267 ASSERT_EFI_ERROR (Status);
268 NewMailbox = (DEBUG_AGENT_MAILBOX *) (UINTN) Memory;
269 //
270 // Copy Mailbox and Debug Port Handle buffer to new location in ACPI NVS memory, because original Mailbox
271 // and Debug Port Handle buffer in the allocated pool that may be marked as free by DXE Core after DXE Core
272 // reallocates the HOB.
273 //
274 Mailbox = GetMailboxPointer ();
275 CopyMem (NewMailbox, Mailbox, sizeof (DEBUG_AGENT_MAILBOX));
276 CopyMem (NewMailbox + 1, (VOID *)(UINTN)Mailbox->DebugPortHandle, PcdGet16(PcdDebugPortHandleBufferSize));
277 //
278 // Update Mailbox Location pointer in GUIDed HOB and IDT entry with new one
279 //
280 MailboxLocationInHob = GetMailboxLocationFromHob ();
281 *MailboxLocationInHob = (UINT64)(UINTN)NewMailbox;
282 SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationInHob);
283 //
284 // Update Debug Port Handle in new Mailbox
285 //
286 UpdateMailboxContent (NewMailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, (UINT64)(UINTN)(NewMailbox + 1));
287 //
288 // Set physical memory ready flag
289 //
290 SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1);
291
292 if (IsHostAttached ()) {
293 //
294 // Trigger one software interrupt to inform HOST
295 //
296 TriggerSoftInterrupt (MEMORY_READY_SIGNATURE);
297 }
298
299 //
300 // Restore interrupt state.
301 //
302 SetInterruptState (InterruptStatus);
303
304 return EFI_SUCCESS;
305 }
306
307 /**
308 Initialize debug agent.
309
310 This function is used to set up debug environment for SEC and PEI phase.
311
312 If InitFlag is DEBUG_AGENT_INIT_PREMEM_SEC, it will overirde IDT table entries
313 and initialize debug port. It will enable interrupt to support break-in feature.
314 It will set up debug agent Mailbox in cache-as-ramfrom. It will be called before
315 physical memory is ready.
316 If InitFlag is DEBUG_AGENT_INIT_POSTMEM_SEC, debug agent will build one GUIDed
317 HOB to copy debug agent Mailbox. It will be called after physical memory is ready.
318
319 This function is used to set up debug environment to support source level debugging.
320 If certain Debug Agent Library instance has to save some private data in the stack,
321 this function must work on the mode that doesn't return to the caller, then
322 the caller needs to wrap up all rest of logic after InitializeDebugAgent() into one
323 function and pass it into InitializeDebugAgent(). InitializeDebugAgent() is
324 responsible to invoke the passing-in function at the end of InitializeDebugAgent().
325
326 If the parameter Function is not NULL, Debug Agent Libary instance will invoke it by
327 passing in the Context to be its parameter.
328
329 If Function() is NULL, Debug Agent Library instance will return after setup debug
330 environment.
331
332 @param[in] InitFlag Init flag is used to decide the initialize process.
333 @param[in] Context Context needed according to InitFlag; it was optional.
334 @param[in] Function Continue function called by debug agent library; it was
335 optional.
336
337 **/
338 VOID
339 EFIAPI
340 InitializeDebugAgent (
341 IN UINT32 InitFlag,
342 IN VOID *Context, OPTIONAL
343 IN DEBUG_AGENT_CONTINUE Function OPTIONAL
344 )
345 {
346 DEBUG_AGENT_MAILBOX *Mailbox;
347 DEBUG_AGENT_MAILBOX MailboxInStack;
348 DEBUG_AGENT_PHASE2_CONTEXT Phase2Context;
349 DEBUG_AGENT_CONTEXT_POSTMEM_SEC *DebugAgentContext;
350 EFI_STATUS Status;
351 IA32_DESCRIPTOR *Ia32Idtr;
352 IA32_IDT_ENTRY *Ia32IdtEntry;
353 UINT64 DebugPortHandle;
354 UINT64 MailboxLocation;
355 UINT64 *MailboxLocationPointer;
356
357 DisableInterrupts ();
358
359 switch (InitFlag) {
360
361 case DEBUG_AGENT_INIT_PREMEM_SEC:
362
363 InitializeDebugIdt ();
364
365 MailboxLocation = (UINT64)(UINTN)&MailboxInStack;
366 Mailbox = &MailboxInStack;
367 ZeroMem ((VOID *) Mailbox, sizeof (DEBUG_AGENT_MAILBOX));
368 //
369 // Get and save debug port handle and set the length of memory block.
370 //
371 SetLocationSavedMailboxPointerInIdtEntry (&MailboxLocation);
372 SetDebugFlag (DEBUG_AGENT_FLAG_PRINT_ERROR_LEVEL, DEBUG_AGENT_ERROR);
373
374 InitializeDebugTimer ();
375
376 Phase2Context.Context = Context;
377 Phase2Context.Function = Function;
378 DebugPortInitialize ((VOID *) &Phase2Context, InitializeDebugAgentPhase2);
379 //
380 // If reaches here, it means Debug Port initialization failed.
381 //
382 DEBUG ((EFI_D_ERROR, "Debug Agent: Debug port initialization failed.\n"));
383
384 break;
385
386 case DEBUG_AGENT_INIT_POSTMEM_SEC:
387 Mailbox = GetMailboxPointer ();
388 //
389 // Memory has been ready
390 //
391 SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1);
392 if (IsHostAttached ()) {
393 //
394 // Trigger one software interrupt to inform HOST
395 //
396 TriggerSoftInterrupt (MEMORY_READY_SIGNATURE);
397 }
398
399 //
400 // Fix up Debug Port handle address and mailbox address
401 //
402 DebugAgentContext = (DEBUG_AGENT_CONTEXT_POSTMEM_SEC *) Context;
403 DebugPortHandle = (UINT64)(UINT32)(Mailbox->DebugPortHandle + DebugAgentContext->StackMigrateOffset);
404 UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle);
405 Mailbox = (DEBUG_AGENT_MAILBOX *) ((UINTN) Mailbox + DebugAgentContext->StackMigrateOffset);
406 MailboxLocation = (UINT64)(UINTN)Mailbox;
407 //
408 // Build mailbox location in HOB and fix-up its address
409 //
410 MailboxLocationPointer = BuildGuidDataHob (
411 &gEfiDebugAgentGuid,
412 &MailboxLocation,
413 sizeof (UINT64)
414 );
415 MailboxLocationPointer = (UINT64 *) ((UINTN) MailboxLocationPointer + DebugAgentContext->HeapMigrateOffset);
416 //
417 // Update IDT entry to save the location saved mailbox pointer
418 //
419 SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationPointer);
420 //
421 // Enable CPU interrupts so debug timer interrupts can be delivered
422 //
423 EnableInterrupts ();
424
425 break;
426
427 case DEBUG_AGENT_INIT_PEI:
428 //
429 // Check if Debug Agent has initialized before
430 //
431 if (IsDebugAgentInitialzed()) {
432 DEBUG ((EFI_D_WARN, "Debug Agent: It has already initialized in SEC Core!\n"));
433 break;
434 }
435 //
436 // Set up IDT entries
437 //
438 InitializeDebugIdt ();
439 //
440 // Build mailbox in HOB and setup Mailbox Set In Pei flag
441 //
442 Mailbox = AllocateZeroPool (sizeof (DEBUG_AGENT_MAILBOX));
443 MailboxLocation = (UINT64)(UINTN)Mailbox;
444 MailboxLocationPointer = BuildGuidDataHob (
445 &gEfiDebugAgentGuid,
446 &MailboxLocation,
447 sizeof (UINT64)
448 );
449
450 InitializeDebugTimer ();
451 //
452 // Update IDT entry to save the location pointer saved mailbox pointer
453 //
454 SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationPointer);
455 //
456 // Register for a callback once memory has been initialized.
457 // If memery has been ready, the callback funtion will be invoked immediately
458 //
459 Status = PeiServicesNotifyPpi (&mMemoryDiscoveredNotifyList[0]);
460 ASSERT_EFI_ERROR (Status);
461 //
462 // Set HOB check flag if memory has not been ready yet
463 //
464 if (GetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY) == 0) {
465 SetDebugFlag (DEBUG_AGENT_FLAG_CHECK_MAILBOX_IN_HOB, 1);
466 }
467
468 Phase2Context.Context = Context;
469 Phase2Context.Function = Function;
470 DebugPortInitialize ((VOID *) &Phase2Context, InitializeDebugAgentPhase2);
471
472 FindAndReportModuleImageInfo (4);
473
474 break;
475
476 case DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64:
477 if (Context == NULL) {
478 DEBUG ((EFI_D_ERROR, "DebugAgent: Input parameter Context cannot be NULL!\n"));
479 CpuDeadLoop ();
480 } else {
481 Ia32Idtr = (IA32_DESCRIPTOR *) Context;
482 Ia32IdtEntry = (IA32_IDT_ENTRY *)(Ia32Idtr->Base);
483 MailboxLocationPointer = (UINT64 *) (UINTN) (Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetLow +
484 (Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetHigh << 16));
485 Mailbox = (DEBUG_AGENT_MAILBOX *) (UINTN)(*MailboxLocationPointer);
486 VerifyMailboxChecksum (Mailbox);
487
488 DebugPortHandle = (UINT64) (UINTN)DebugPortInitialize ((VOID *)(UINTN)Mailbox->DebugPortHandle, NULL);
489 UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle);
490 //
491 // Set up IDT entries
492 //
493 InitializeDebugIdt ();
494 //
495 // Update IDT entry to save location pointer saved the mailbox pointer
496 //
497 SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationPointer);
498
499 FindAndReportModuleImageInfo (4);
500 }
501 break;
502
503 default:
504 //
505 // Only DEBUG_AGENT_INIT_PREMEM_SEC and DEBUG_AGENT_INIT_POSTMEM_SEC are allowed for this
506 // Debug Agent library instance.
507 //
508 DEBUG ((EFI_D_ERROR, "Debug Agent: The InitFlag value is not allowed!\n"));
509 CpuDeadLoop ();
510 break;
511
512 }
513
514 EnableInterrupts ();
515
516 //
517 // If Function is not NULL, invoke it always whatever debug agent was initialized sucesssfully or not.
518 //
519 if (Function != NULL) {
520 Function (Context);
521 }
522 }
523
524 /**
525 Caller provided function to be invoked at the end of DebugPortInitialize().
526
527 Refer to the descrption for DebugPortInitialize() for more details.
528
529 @param[in] Context The first input argument of DebugPortInitialize().
530 @param[in] DebugPortHandle Debug port handle created by Debug Communication Libary.
531
532 **/
533 VOID
534 EFIAPI
535 InitializeDebugAgentPhase2 (
536 IN VOID *Context,
537 IN DEBUG_PORT_HANDLE DebugPortHandle
538 )
539 {
540 DEBUG_AGENT_PHASE2_CONTEXT *Phase2Context;
541 UINT64 *MailboxLocation;
542 DEBUG_AGENT_MAILBOX *Mailbox;
543 EFI_SEC_PEI_HAND_OFF *SecCoreData;
544 UINT16 BufferSize;
545 UINT64 NewDebugPortHandle;
546
547 Phase2Context = (DEBUG_AGENT_PHASE2_CONTEXT *) Context;
548 MailboxLocation = GetLocationSavedMailboxPointerInIdtEntry ();
549 Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation);
550 BufferSize = PcdGet16(PcdDebugPortHandleBufferSize);
551 if (Phase2Context->Function == NULL && DebugPortHandle != NULL && BufferSize != 0) {
552 NewDebugPortHandle = (UINT64)(UINTN)AllocateCopyPool (BufferSize, DebugPortHandle);
553 } else {
554 NewDebugPortHandle = (UINT64)(UINTN)DebugPortHandle;
555 }
556 UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, NewDebugPortHandle);
557
558 //
559 // Trigger one software interrupt to inform HOST
560 //
561 TriggerSoftInterrupt (SYSTEM_RESET_SIGNATURE);
562
563 //
564 // If Temporary RAM region is below 128 MB, then send message to
565 // host to disable low memory filtering.
566 //
567 SecCoreData = (EFI_SEC_PEI_HAND_OFF *)Phase2Context->Context;
568 if ((UINTN)SecCoreData->TemporaryRamBase < BASE_128MB && IsHostAttached ()) {
569 SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1);
570 TriggerSoftInterrupt (MEMORY_READY_SIGNATURE);
571 }
572
573 //
574 // Enable CPU interrupts so debug timer interrupts can be delivered
575 //
576 EnableInterrupts ();
577
578 //
579 // Call continuation function if it is not NULL.
580 //
581 if (Phase2Context->Function != NULL) {
582 Phase2Context->Function (Phase2Context->Context);
583 }
584 }