]> git.proxmox.com Git - mirror_edk2.git/blob - SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgent/SecPeiDebugAgentLib.c
This revision can only work with Intel(c) UDK Debugger Tool version 1.3 or greater...
[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 DEBUG_AGENT_MAILBOX *Mailbox;
248 BOOLEAN InterruptStatus;
249
250 //
251 // Save and disable original interrupt status
252 //
253 InterruptStatus = SaveAndDisableInterrupts ();
254
255 //
256 // Set physical memory ready flag
257 //
258 Mailbox = GetMailboxPointer ();
259 SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1);
260
261 //
262 // Memory has been ready
263 //
264 if (IsHostAttached ()) {
265 //
266 // Trigger one software interrupt to inform HOST
267 //
268 TriggerSoftInterrupt (MEMORY_READY_SIGNATURE);
269 }
270
271 //
272 // Restore interrupt state.
273 //
274 SetInterruptState (InterruptStatus);
275
276 return EFI_SUCCESS;
277 }
278
279 /**
280 Initialize debug agent.
281
282 This function is used to set up debug environment for SEC and PEI phase.
283
284 If InitFlag is DEBUG_AGENT_INIT_PREMEM_SEC, it will overirde IDT table entries
285 and initialize debug port. It will enable interrupt to support break-in feature.
286 It will set up debug agent Mailbox in cache-as-ramfrom. It will be called before
287 physical memory is ready.
288 If InitFlag is DEBUG_AGENT_INIT_POSTMEM_SEC, debug agent will build one GUIDed
289 HOB to copy debug agent Mailbox. It will be called after physical memory is ready.
290
291 This function is used to set up debug environment to support source level debugging.
292 If certain Debug Agent Library instance has to save some private data in the stack,
293 this function must work on the mode that doesn't return to the caller, then
294 the caller needs to wrap up all rest of logic after InitializeDebugAgent() into one
295 function and pass it into InitializeDebugAgent(). InitializeDebugAgent() is
296 responsible to invoke the passing-in function at the end of InitializeDebugAgent().
297
298 If the parameter Function is not NULL, Debug Agent Libary instance will invoke it by
299 passing in the Context to be its parameter.
300
301 If Function() is NULL, Debug Agent Library instance will return after setup debug
302 environment.
303
304 @param[in] InitFlag Init flag is used to decide the initialize process.
305 @param[in] Context Context needed according to InitFlag; it was optional.
306 @param[in] Function Continue function called by debug agent library; it was
307 optional.
308
309 **/
310 VOID
311 EFIAPI
312 InitializeDebugAgent (
313 IN UINT32 InitFlag,
314 IN VOID *Context, OPTIONAL
315 IN DEBUG_AGENT_CONTINUE Function OPTIONAL
316 )
317 {
318 DEBUG_AGENT_MAILBOX *Mailbox;
319 DEBUG_AGENT_MAILBOX MailboxInStack;
320 DEBUG_AGENT_PHASE2_CONTEXT Phase2Context;
321 DEBUG_AGENT_CONTEXT_POSTMEM_SEC *DebugAgentContext;
322 EFI_STATUS Status;
323 IA32_DESCRIPTOR *Ia32Idtr;
324 IA32_IDT_ENTRY *Ia32IdtEntry;
325 UINT64 DebugPortHandle;
326 UINT64 MailboxLocation;
327 UINT64 *MailboxLocationPointer;
328
329 DisableInterrupts ();
330
331 switch (InitFlag) {
332
333 case DEBUG_AGENT_INIT_PREMEM_SEC:
334
335 InitializeDebugIdt ();
336
337 MailboxLocation = (UINT64)(UINTN)&MailboxInStack;
338 Mailbox = &MailboxInStack;
339 ZeroMem ((VOID *) Mailbox, sizeof (DEBUG_AGENT_MAILBOX));
340 //
341 // Get and save debug port handle and set the length of memory block.
342 //
343 SetLocationSavedMailboxPointerInIdtEntry (&MailboxLocation);
344 SetDebugFlag (DEBUG_AGENT_FLAG_PRINT_ERROR_LEVEL, DEBUG_AGENT_ERROR);
345
346 InitializeDebugTimer ();
347
348 Phase2Context.Context = Context;
349 Phase2Context.Function = Function;
350 DebugPortInitialize ((VOID *) &Phase2Context, InitializeDebugAgentPhase2);
351 //
352 // If reaches here, it means Debug Port initialization failed.
353 //
354 DEBUG ((EFI_D_ERROR, "Debug Agent: Debug port initialization failed.\n"));
355
356 break;
357
358 case DEBUG_AGENT_INIT_POSTMEM_SEC:
359 Mailbox = GetMailboxPointer ();
360 //
361 // Memory has been ready
362 //
363 SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1);
364 if (IsHostAttached ()) {
365 //
366 // Trigger one software interrupt to inform HOST
367 //
368 TriggerSoftInterrupt (MEMORY_READY_SIGNATURE);
369 }
370
371 //
372 // Fix up Debug Port handle address and mailbox address
373 //
374 DebugAgentContext = (DEBUG_AGENT_CONTEXT_POSTMEM_SEC *) Context;
375 DebugPortHandle = (UINT64)(UINT32)(Mailbox->DebugPortHandle + DebugAgentContext->StackMigrateOffset);
376 UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle);
377 Mailbox = (DEBUG_AGENT_MAILBOX *) ((UINTN) Mailbox + DebugAgentContext->StackMigrateOffset);
378 MailboxLocation = (UINT64)(UINTN)Mailbox;
379 //
380 // Build mailbox location in HOB and fix-up its address
381 //
382 MailboxLocationPointer = BuildGuidDataHob (
383 &gEfiDebugAgentGuid,
384 &MailboxLocation,
385 sizeof (UINT64)
386 );
387 MailboxLocationPointer = (UINT64 *) ((UINTN) MailboxLocationPointer + DebugAgentContext->HeapMigrateOffset);
388 //
389 // Update IDT entry to save the location saved mailbox pointer
390 //
391 SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationPointer);
392 //
393 // Enable CPU interrupts so debug timer interrupts can be delivered
394 //
395 EnableInterrupts ();
396
397 break;
398
399 case DEBUG_AGENT_INIT_PEI:
400 //
401 // Check if Debug Agent has initialized before
402 //
403 if (IsDebugAgentInitialzed()) {
404 DEBUG ((EFI_D_WARN, "Debug Agent: It has already initialized in SEC Core!\n"));
405 break;
406 }
407 //
408 // Set up IDT entries
409 //
410 InitializeDebugIdt ();
411 //
412 // Build mailbox in HOB and setup Mailbox Set In Pei flag
413 //
414 Mailbox = AllocateZeroPool (sizeof (DEBUG_AGENT_MAILBOX));
415 MailboxLocation = (UINT64)(UINTN)Mailbox;
416 MailboxLocationPointer = BuildGuidDataHob (
417 &gEfiDebugAgentGuid,
418 &MailboxLocation,
419 sizeof (UINT64)
420 );
421
422 InitializeDebugTimer ();
423 //
424 // Update IDT entry to save the location pointer saved mailbox pointer
425 //
426 SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationPointer);
427 //
428 // Register for a callback once memory has been initialized.
429 // If memery has been ready, the callback funtion will be invoked immediately
430 //
431 Status = PeiServicesNotifyPpi (&mMemoryDiscoveredNotifyList[0]);
432 ASSERT_EFI_ERROR (Status);
433 //
434 // Set HOB check flag if memory has not been ready yet
435 //
436 if (GetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY) == 0) {
437 SetDebugFlag (DEBUG_AGENT_FLAG_CHECK_MAILBOX_IN_HOB, 1);
438 }
439
440 Phase2Context.Context = Context;
441 Phase2Context.Function = Function;
442 DebugPortInitialize ((VOID *) &Phase2Context, InitializeDebugAgentPhase2);
443
444 FindAndReportModuleImageInfo (4);
445
446 break;
447
448 case DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64:
449 if (Context == NULL) {
450 DEBUG ((EFI_D_ERROR, "DebugAgent: Input parameter Context cannot be NULL!\n"));
451 CpuDeadLoop ();
452 } else {
453 Ia32Idtr = (IA32_DESCRIPTOR *) Context;
454 Ia32IdtEntry = (IA32_IDT_ENTRY *)(Ia32Idtr->Base);
455 MailboxLocationPointer = (UINT64 *) (UINTN) (Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetLow +
456 (Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetHigh << 16));
457 Mailbox = (DEBUG_AGENT_MAILBOX *) (UINTN)(*MailboxLocationPointer);
458 VerifyMailboxChecksum (Mailbox);
459
460 DebugPortHandle = (UINT64) (UINTN)DebugPortInitialize ((VOID *)(UINTN)Mailbox->DebugPortHandle, NULL);
461 UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle);
462 //
463 // Set up IDT entries
464 //
465 InitializeDebugIdt ();
466 //
467 // Update IDT entry to save location pointer saved the mailbox pointer
468 //
469 SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationPointer);
470
471 FindAndReportModuleImageInfo (4);
472 }
473 break;
474
475 default:
476 //
477 // Only DEBUG_AGENT_INIT_PREMEM_SEC and DEBUG_AGENT_INIT_POSTMEM_SEC are allowed for this
478 // Debug Agent library instance.
479 //
480 DEBUG ((EFI_D_ERROR, "Debug Agent: The InitFlag value is not allowed!\n"));
481 CpuDeadLoop ();
482 break;
483
484 }
485
486 EnableInterrupts ();
487
488 //
489 // If Function is not NULL, invoke it always whatever debug agent was initialized sucesssfully or not.
490 //
491 if (Function != NULL) {
492 Function (Context);
493 }
494 }
495
496 /**
497 Caller provided function to be invoked at the end of DebugPortInitialize().
498
499 Refer to the descrption for DebugPortInitialize() for more details.
500
501 @param[in] Context The first input argument of DebugPortInitialize().
502 @param[in] DebugPortHandle Debug port handle created by Debug Communication Libary.
503
504 **/
505 VOID
506 EFIAPI
507 InitializeDebugAgentPhase2 (
508 IN VOID *Context,
509 IN DEBUG_PORT_HANDLE DebugPortHandle
510 )
511 {
512 DEBUG_AGENT_PHASE2_CONTEXT *Phase2Context;
513 UINT64 *MailboxLocation;
514 DEBUG_AGENT_MAILBOX *Mailbox;
515 EFI_SEC_PEI_HAND_OFF *SecCoreData;
516 UINT16 BufferSize;
517 UINT64 NewDebugPortHandle;
518
519 Phase2Context = (DEBUG_AGENT_PHASE2_CONTEXT *) Context;
520 MailboxLocation = GetLocationSavedMailboxPointerInIdtEntry ();
521 Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation);
522 BufferSize = PcdGet16(PcdDebugPortHandleBufferSize);
523 if (Phase2Context->Function == NULL && DebugPortHandle != NULL && BufferSize != 0) {
524 NewDebugPortHandle = (UINT64)(UINTN)AllocateCopyPool (BufferSize, DebugPortHandle);
525 } else {
526 NewDebugPortHandle = (UINT64)(UINTN)DebugPortHandle;
527 }
528 UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, NewDebugPortHandle);
529
530 //
531 // Trigger one software interrupt to inform HOST
532 //
533 TriggerSoftInterrupt (SYSTEM_RESET_SIGNATURE);
534
535 //
536 // If Temporary RAM region is below 128 MB, then send message to
537 // host to disable low memory filtering.
538 //
539 SecCoreData = (EFI_SEC_PEI_HAND_OFF *)Phase2Context->Context;
540 if ((UINTN)SecCoreData->TemporaryRamBase < BASE_128MB && IsHostAttached ()) {
541 SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1);
542 TriggerSoftInterrupt (MEMORY_READY_SIGNATURE);
543 }
544
545 //
546 // Enable CPU interrupts so debug timer interrupts can be delivered
547 //
548 EnableInterrupts ();
549
550 //
551 // Call continuation function if it is not NULL.
552 //
553 if (Phase2Context->Function != NULL) {
554 Phase2Context->Function (Phase2Context->Context);
555 }
556 }