git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@10867 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			308 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			308 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   SEC Core Debug Agent Library instance implementition.
 | |
| 
 | |
|   Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
 | |
|   This program and the accompanying materials
 | |
|   are licensed and made available under the terms and conditions of the BSD License
 | |
|   which accompanies this distribution.  The full text of the license may be found at
 | |
|   http://opensource.org/licenses/bsd-license.php.
 | |
| 
 | |
|   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
|   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "SecPeiDebugAgentLib.h"
 | |
| 
 | |
| CONST BOOLEAN                MultiProcessorDebugSupport = FALSE;
 | |
| 
 | |
| /**
 | |
|   Get pointer to Mailbox from IDT entry before memory is ready.
 | |
| 
 | |
| **/
 | |
| VOID *
 | |
| GetMailboxPointerInIdtEntry (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   IA32_IDT_GATE_DESCRIPTOR   *IdtEntry;
 | |
|   IA32_DESCRIPTOR            IdtDescriptor;
 | |
|   UINTN                      Mailbox;
 | |
| 
 | |
|   AsmReadIdtr (&IdtDescriptor);
 | |
|   IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor.Base;
 | |
| 
 | |
|   Mailbox = IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetLow + (IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetHigh << 16);
 | |
|   return (VOID *) Mailbox;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Set the pointer of Mailbox into IDT entry before memory is ready.
 | |
| 
 | |
|   @param[in]  Mailbox       The pointer of Mailbox.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| SetMailboxPointerInIdtEntry (
 | |
|   IN VOID                    *Mailbox
 | |
|   )
 | |
| {
 | |
|   IA32_IDT_GATE_DESCRIPTOR   *IdtEntry;
 | |
|   IA32_DESCRIPTOR            IdtDescriptor;
 | |
| 
 | |
|   AsmReadIdtr (&IdtDescriptor);
 | |
|   IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor.Base;
 | |
| 
 | |
|   IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetLow  = (UINT16)(UINTN)Mailbox;
 | |
|   IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetHigh = (UINT16)((UINTN)Mailbox >> 16);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get the pointer to Mailbox from IDT entry and build the Mailbox into GUIDed Hob
 | |
|   after memory is ready.
 | |
| 
 | |
|   @return Pointer to Mailbox.
 | |
| 
 | |
| **/
 | |
| DEBUG_AGENT_MAILBOX *
 | |
| BuildMailboxHob (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   DEBUG_AGENT_MAILBOX       *Mailbox;
 | |
| 
 | |
|   Mailbox = (DEBUG_AGENT_MAILBOX *) GetMailboxPointerInIdtEntry ();
 | |
| 
 | |
|   return BuildGuidDataHob (
 | |
|            &gEfiDebugAgentGuid,
 | |
|            Mailbox,
 | |
|            sizeof (DEBUG_AGENT_MAILBOX)
 | |
|            );
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get Debug Agent Mailbox pointer.
 | |
| 
 | |
|   @return Mailbox pointer.
 | |
| 
 | |
| **/
 | |
| DEBUG_AGENT_MAILBOX *
 | |
| GetMailboxPointer (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   return (DEBUG_AGENT_MAILBOX *) GetMailboxPointerInIdtEntry ();
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get debug port handle.
 | |
| 
 | |
|   @return Debug port handle.
 | |
| 
 | |
| **/
 | |
| DEBUG_PORT_HANDLE
 | |
| GetDebugPortHandle (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   DEBUG_AGENT_MAILBOX    *DebugAgentMailbox;
 | |
|   
 | |
|   DebugAgentMailbox = (DEBUG_AGENT_MAILBOX *)GetMailboxPointerInIdtEntry ();
 | |
| 
 | |
|   return (DEBUG_PORT_HANDLE) (UINTN)(DebugAgentMailbox->DebugPortHandle);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Trigger one software interrupt to debug agent to handle it.
 | |
| 
 | |
|   @param Signature       Software interrupt signature.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| TriggerSoftInterrupt (
 | |
|   UINT32                 Signature
 | |
|   )
 | |
| {
 | |
|   UINTN                  Dr0;
 | |
|   UINTN                  Dr1;
 | |
| 
 | |
|   //
 | |
|   // Save Debug Register State
 | |
|   //
 | |
|   Dr0 = AsmReadDr0 ();
 | |
|   Dr1 = AsmReadDr1 ();
 | |
| 
 | |
|   //
 | |
|   // DR0 = Signature
 | |
|   //
 | |
|   AsmWriteDr0 (SOFT_INTERRUPT_SIGNATURE);
 | |
|   AsmWriteDr1 (Signature);
 | |
| 
 | |
|   //
 | |
|   // Do INT3 to communicate with HOST side
 | |
|   //
 | |
|   CpuBreakpoint ();
 | |
| 
 | |
|   //
 | |
|   // Restore Debug Register State only when Host didn't change it inside exception handler.
 | |
|   //   Dr registers can only be changed by setting the HW breakpoint.
 | |
|   //
 | |
|   AsmWriteDr0 (Dr0);
 | |
|   AsmWriteDr1 (Dr1);
 | |
| 
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Initialize debug agent.
 | |
| 
 | |
|   This function is used to set up debug environment for SEC and PEI phase.
 | |
| 
 | |
|   If InitFlag is DEBUG_AGENT_INIT_PREMEM_SEC, it will overirde IDT table entries
 | |
|   and initialize debug port. It will enable interrupt to support break-in feature.
 | |
|   It will set up debug agent Mailbox in cache-as-ramfrom. It will be called before
 | |
|   physical memory is ready.
 | |
|   If InitFlag is DEBUG_AGENT_INIT_POSTMEM_SEC, debug agent will build one GUIDed
 | |
|   HOB to copy debug agent Mailbox. It will be called after physical memory is ready.
 | |
| 
 | |
|   This function is used to set up debug environment to support source level debugging.
 | |
|   If certain Debug Agent Library instance has to save some private data in the stack,
 | |
|   this function must work on the mode that doesn't return to the caller, then
 | |
|   the caller needs to wrap up all rest of logic after InitializeDebugAgent() into one
 | |
|   function and pass it into InitializeDebugAgent(). InitializeDebugAgent() is
 | |
|   responsible to invoke the passing-in function at the end of InitializeDebugAgent().
 | |
| 
 | |
|   If the parameter Function is not NULL, Debug Agent Libary instance will invoke it by
 | |
|   passing in the Context to be its parameter.
 | |
| 
 | |
|   If Function() is NULL, Debug Agent Library instance will return after setup debug
 | |
|   environment.
 | |
| 
 | |
|   @param[in] InitFlag     Init flag is used to decide the initialize process.
 | |
|   @param[in] Context      Context needed according to InitFlag; it was optional.
 | |
|   @param[in] Function     Continue function called by debug agent library; it was
 | |
|                           optional.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| InitializeDebugAgent (
 | |
|   IN UINT32                InitFlag,
 | |
|   IN VOID                  *Context, OPTIONAL
 | |
|   IN DEBUG_AGENT_CONTINUE  Function  OPTIONAL
 | |
|   )
 | |
| {
 | |
|   DEBUG_AGENT_MAILBOX              *Mailbox;
 | |
|   DEBUG_AGENT_MAILBOX              MailboxInStack;
 | |
|   DEBUG_AGENT_PHASE2_CONTEXT       Phase2Context;
 | |
|   DEBUG_AGENT_CONTEXT_POSTMEM_SEC  *DebugAgentContext;
 | |
| 
 | |
|   if (InitFlag != DEBUG_AGENT_INIT_PREMEM_SEC &&
 | |
|       InitFlag != DEBUG_AGENT_INIT_POSTMEM_SEC) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   DisableInterrupts ();
 | |
| 
 | |
|   if (InitFlag == DEBUG_AGENT_INIT_POSTMEM_SEC) {
 | |
| 
 | |
|     //
 | |
|     // Memory has been ready
 | |
|     //
 | |
|     if (IsHostConnected()) {
 | |
|       //
 | |
|       // Trigger one software interrupt to inform HOST
 | |
|       //
 | |
|       TriggerSoftInterrupt (MEMORY_READY_SIGNATURE);
 | |
|     }
 | |
| 
 | |
|     DebugAgentContext = (DEBUG_AGENT_CONTEXT_POSTMEM_SEC *) Context;
 | |
| 
 | |
|     Mailbox = (DEBUG_AGENT_MAILBOX *) GetMailboxPointerInIdtEntry ();
 | |
|     Mailbox->DebugPortHandle = Mailbox->DebugPortHandle + DebugAgentContext->StackMigrateOffset;
 | |
| 
 | |
|     Mailbox = BuildMailboxHob ();
 | |
|     Mailbox = (DEBUG_AGENT_MAILBOX *) ((UINTN) Mailbox + DebugAgentContext->HeapMigrateOffset);
 | |
| 
 | |
|     SetMailboxPointerInIdtEntry ((VOID *) Mailbox);
 | |
| 
 | |
|     EnableInterrupts ();
 | |
| 
 | |
|     if (Function != NULL) {
 | |
|       Function (Context);
 | |
|     }
 | |
| 
 | |
|     return;
 | |
| 
 | |
|   } else {
 | |
| 
 | |
|     InitializeDebugIdt ();
 | |
| 
 | |
|     Mailbox = &MailboxInStack;
 | |
|     ZeroMem ((VOID *) Mailbox, sizeof (DEBUG_AGENT_MAILBOX));
 | |
| 
 | |
|     //
 | |
|     // Get and save debug port handle and set the length of memory block.
 | |
|     //
 | |
|     SetMailboxPointerInIdtEntry ((VOID *) Mailbox);
 | |
| 
 | |
|     InitializeDebugTimer ();
 | |
| 
 | |
|     Phase2Context.Context  = Context;
 | |
|     Phase2Context.Function = Function;
 | |
|     DebugPortInitialize ((VOID *) &Phase2Context, InitializeDebugAgentPhase2);
 | |
| 
 | |
|     return;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Caller provided function to be invoked at the end of DebugPortInitialize().
 | |
| 
 | |
|   Refer to the descrption for DebugPortInitialize() for more details.
 | |
| 
 | |
|   @param[in] Context           The first input argument of DebugPortInitialize().
 | |
|   @param[in] DebugPortHandle   Debug port handle created by Debug Communication Libary.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| InitializeDebugAgentPhase2 (
 | |
|   IN VOID                  *Context,
 | |
|   IN DEBUG_PORT_HANDLE     DebugPortHandle
 | |
|   )
 | |
| {
 | |
|   DEBUG_AGENT_PHASE2_CONTEXT *Phase2Context;
 | |
|   DEBUG_AGENT_MAILBOX        *Mailbox;
 | |
|   EFI_SEC_PEI_HAND_OFF       *SecCoreData;
 | |
| 
 | |
|   Mailbox = GetMailboxPointerInIdtEntry ();
 | |
|   Mailbox->DebugPortHandle = (UINT64) (UINTN)DebugPortHandle;
 | |
| 
 | |
|   //
 | |
|   // Trigger one software interrupt to inform HOST
 | |
|   //
 | |
|   TriggerSoftInterrupt (SYSTEM_RESET_SIGNATURE);
 | |
| 
 | |
|   //
 | |
|   // If Temporary RAM region is below 128 MB, then send message to 
 | |
|   // host to disable low memory filtering.
 | |
|   //
 | |
|   Phase2Context = (DEBUG_AGENT_PHASE2_CONTEXT *) Context;
 | |
|   SecCoreData = (EFI_SEC_PEI_HAND_OFF *)Phase2Context->Context;
 | |
|   if ((UINTN)SecCoreData->TemporaryRamBase < BASE_128MB) {
 | |
|     TriggerSoftInterrupt (MEMORY_READY_SIGNATURE);
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Enable CPU interrupts so debug timer interrupts can be delivered
 | |
|   //
 | |
|   EnableInterrupts ();
 | |
| 
 | |
|   //
 | |
|   // Call continuation function is it is not NULL.
 | |
|   //
 | |
|   if (Phase2Context->Function != NULL) {
 | |
|     Phase2Context->Function (Phase2Context->Context);
 | |
|   }
 | |
| }
 |