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);
 | 
						|
  }
 | 
						|
}
 |