| /** @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); | |
| } | |
| } |