/** Write the specified number of bytes to serial device. @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL. @param[in, out] BufferSize On input the size of Buffer, on output the amount of data actually written. @param[in] Buffer The buffer of data to write. @retval EFI_SUCCESS The data were written successfully. @retval EFI_DEVICE_ERROR The device reported an error. @retval EFI_TIMEOUT The write operation was stopped due to timeout. **/ EFI_STATUS EFIAPI SerialWrite ( IN EFI_SERIAL_IO_PROTOCOL *This, IN OUT UINTN *BufferSize, IN VOID *Buffer ) { DEBUG_PORT_HANDLE Handle; BOOLEAN DebugTimerInterruptState; EFI_TPL Tpl; // // Raise TPL to prevent recursion from EFI timer interrupts // Tpl = gBS->RaiseTPL (TPL_NOTIFY); // // Save and disable Debug Timer interrupt to avoid it to access Debug Port // DebugTimerInterruptState = SaveAndSetDebugTimerInterrupt (FALSE); Handle = GetDebugPortHandle (); if ((mSerialIoMode.ControlMask & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) != 0) { if (*BufferSize == 0) { return EFI_SUCCESS; } if ((mLoopbackBuffer & SERIAL_PORT_LOOPBACK_BUFFER_FULL) != 0) { *BufferSize = 0; return EFI_TIMEOUT; } mLoopbackBuffer = SERIAL_PORT_LOOPBACK_BUFFER_FULL | *(UINT8 *)Buffer; *BufferSize = 1; } else { *BufferSize = DebugPortWriteBuffer (Handle, Buffer, *BufferSize); } // // Restore Debug Timer interrupt // SaveAndSetDebugTimerInterrupt (DebugTimerInterruptState); // // Restore to original TPL // gBS->RestoreTPL (Tpl); return EFI_SUCCESS; }
/** Get ControlBits. @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL. @param[out] Control Control signals of the serial device. @retval EFI_SUCCESS Get Control signals successfully. **/ EFI_STATUS EFIAPI SerialGetControl ( IN EFI_SERIAL_IO_PROTOCOL *This, OUT UINT32 *Control ) { DEBUG_PORT_HANDLE Handle; BOOLEAN DebugTimerInterruptState; EFI_TPL Tpl; // // Raise TPL to prevent recursion from EFI timer interrupts // Tpl = gBS->RaiseTPL (TPL_NOTIFY); // // Save and disable Debug Timer interrupt to avoid it to access Debug Port // DebugTimerInterruptState = SaveAndSetDebugTimerInterrupt (FALSE); Handle = GetDebugPortHandle (); // // Always assume the output buffer is empty and the Debug Communication Library can process // more write requests. // *Control = mSerialIoMode.ControlMask | EFI_SERIAL_OUTPUT_BUFFER_EMPTY; // // Check to see if the Terminal FIFO is empty and // check to see if the input buffer in the Debug Communication Library is empty // if (!IsDebugTermianlFifoEmpty (&mSerialFifoForTerminal) || DebugPortPollBuffer (Handle)) { *Control &= ~EFI_SERIAL_INPUT_BUFFER_EMPTY; } // // Restore Debug Timer interrupt // SaveAndSetDebugTimerInterrupt (DebugTimerInterruptState); // // Restore to original TPL // gBS->RestoreTPL (Tpl); return EFI_SUCCESS; }
/** One notified function to disable Debug Timer interrupt when gBS->ExitBootServices() called. @param[in] Event Pointer to this event @param[in] Context Event handler private data **/ VOID EFIAPI DisableDebugTimerExitBootService ( EFI_EVENT Event, VOID *Context ) { SaveAndSetDebugTimerInterrupt (FALSE); }
/** Caller provided function to be invoked at the end of DebugPortInitialize(). Refer to the description for DebugPortInitialize() for more details. @param[in] Context The first input argument of DebugPortInitialize(). @param[in] DebugPortHandle Debug port handle created by Debug Communication Library. **/ VOID EFIAPI InitializeDebugAgentPhase2 ( IN VOID *Context, IN DEBUG_PORT_HANDLE DebugPortHandle ) { DEBUG_AGENT_PHASE2_CONTEXT *Phase2Context; UINT64 *MailboxLocation; DEBUG_AGENT_MAILBOX *Mailbox; EFI_SEC_PEI_HAND_OFF *SecCoreData; UINT16 BufferSize; UINT64 NewDebugPortHandle; Phase2Context = (DEBUG_AGENT_PHASE2_CONTEXT *) Context; MailboxLocation = GetLocationSavedMailboxPointerInIdtEntry (); Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation); BufferSize = PcdGet16(PcdDebugPortHandleBufferSize); if (Phase2Context->InitFlag == DEBUG_AGENT_INIT_PEI && BufferSize != 0) { NewDebugPortHandle = (UINT64)(UINTN)AllocateCopyPool (BufferSize, DebugPortHandle); } else { NewDebugPortHandle = (UINT64)(UINTN)DebugPortHandle; } UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, NewDebugPortHandle); // // Trigger one software interrupt to inform HOST // TriggerSoftInterrupt (SYSTEM_RESET_SIGNATURE); if (Phase2Context->InitFlag == DEBUG_AGENT_INIT_PREMEM_SEC) { // // If Temporary RAM region is below 128 MB, then send message to // host to disable low memory filtering. // SecCoreData = (EFI_SEC_PEI_HAND_OFF *)Phase2Context->Context; if ((UINTN)SecCoreData->TemporaryRamBase < BASE_128MB && IsHostAttached ()) { SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1); TriggerSoftInterrupt (MEMORY_READY_SIGNATURE); } // // Enable Debug Timer interrupt // SaveAndSetDebugTimerInterrupt (TRUE); // // Enable CPU interrupts so debug timer interrupts can be delivered // EnableInterrupts (); // // Call continuation function if it is not NULL. // Phase2Context->Function (Phase2Context->Context); } }
VOID CEntryPoint ( IN UINTN MpId, IN EFI_PEI_CORE_ENTRY_POINT PeiCoreEntryPoint ) { // Data Cache enabled on Primary core when MMU is enabled. ArmDisableDataCache (); // Invalidate Data cache ArmInvalidateDataCache (); // Invalidate instruction cache ArmInvalidateInstructionCache (); // Enable Instruction Caches on all cores. ArmEnableInstructionCache (); // // Note: Doesn't have to Enable CPU interface in non-secure world, // as Non-secure interface is already enabled in Secure world. // // Write VBAR - The Exception Vector table must be aligned to its requirement // Note: The AArch64 Vector table must be 2k-byte aligned - if this assertion fails ensure // 'Align=4K' is defined into your FDF for this module. ASSERT (((UINTN)PeiVectorTable & ARM_VECTOR_TABLE_ALIGNMENT) == 0); ArmWriteVBar ((UINTN)PeiVectorTable); //Note: The MMU will be enabled by MemoryPeim. Only the primary core will have the MMU on. // If not primary Jump to Secondary Main if (ArmPlatformIsPrimaryCore (MpId)) { // Initialize the Debug Agent for Source Level Debugging InitializeDebugAgent (DEBUG_AGENT_INIT_POSTMEM_SEC, NULL, NULL); SaveAndSetDebugTimerInterrupt (TRUE); // Initialize the platform specific controllers ArmPlatformInitialize (MpId); // Goto primary Main. PrimaryMain (PeiCoreEntryPoint); } else { SecondaryMain (MpId); } // PEI Core should always load and never return ASSERT (FALSE); }
// | Heap | PeiTemporayRamSize // |-------------------|----> // | Stack | PeiStackSize // |-------------------|----> PermanentMemoryBase // OldHeap = (VOID*)(UINTN)TemporaryMemoryBase; NewHeap = (VOID*)((UINTN)PermanentMemoryBase + PeiStackSize); OldStack = (VOID*)((UINTN)TemporaryMemoryBase + CopySize - PeiStackSize); NewStack = (VOID*)(UINTN)PermanentMemoryBase; DebugAgentContext.HeapMigrateOffset = (UINTN)NewHeap - (UINTN)OldHeap; DebugAgentContext.StackMigrateOffset = (UINTN)NewStack - (UINTN)OldStack; OldStatus = SaveAndSetDebugTimerInterrupt (FALSE); // // Initialize Debug Agent to support source level debug in PEI phase after memory ready. // It will build HOB and fix up the pointer in IDT table. // InitializeDebugAgent (DEBUG_AGENT_INIT_POSTMEM_SEC, (VOID *) &DebugAgentContext, NULL); // // Migrate Heap // CopyMem (NewHeap, OldHeap, CopySize - PeiStackSize); // // Migrate Stack // CopyMem (NewStack, OldStack, PeiStackSize);
/** 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 Library 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 *NewMailbox; DEBUG_AGENT_MAILBOX MailboxInStack; DEBUG_AGENT_PHASE2_CONTEXT Phase2Context; DEBUG_AGENT_CONTEXT_POSTMEM_SEC *DebugAgentContext; EFI_STATUS Status; IA32_DESCRIPTOR *Ia32Idtr; IA32_IDT_ENTRY *Ia32IdtEntry; UINT64 DebugPortHandle; UINT64 MailboxLocation; UINT64 *MailboxLocationPointer; EFI_PHYSICAL_ADDRESS Address; UINT32 DebugTimerFrequency; BOOLEAN CpuInterruptState; // // Disable interrupts and save current interrupt state // CpuInterruptState = SaveAndDisableInterrupts(); switch (InitFlag) { case DEBUG_AGENT_INIT_PREMEM_SEC: InitializeDebugIdt (); MailboxLocation = (UINT64)(UINTN)&MailboxInStack; Mailbox = &MailboxInStack; ZeroMem ((VOID *) Mailbox, sizeof (DEBUG_AGENT_MAILBOX)); // // Get and save debug port handle and set the length of memory block. // SetLocationSavedMailboxPointerInIdtEntry (&MailboxLocation); // // Force error message could be printed during the first shakehand between Target/HOST. // SetDebugFlag (DEBUG_AGENT_FLAG_PRINT_ERROR_LEVEL, DEBUG_AGENT_ERROR); // // Save init arch type when debug agent initialized // SetDebugFlag (DEBUG_AGENT_FLAG_INIT_ARCH, DEBUG_ARCH_SYMBOL); // // Initialize Debug Timer hardware and save its frequency // InitializeDebugTimer (&DebugTimerFrequency, TRUE); UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY, DebugTimerFrequency); Phase2Context.InitFlag = InitFlag; Phase2Context.Context = Context; Phase2Context.Function = Function; DebugPortInitialize ((VOID *) &Phase2Context, InitializeDebugAgentPhase2); // // If reaches here, it means Debug Port initialization failed. // DEBUG ((EFI_D_ERROR, "Debug Agent: Debug port initialization failed.\n")); break; case DEBUG_AGENT_INIT_POSTMEM_SEC: Mailbox = GetMailboxPointer (); // // Memory has been ready // SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1); if (IsHostAttached ()) { // // Trigger one software interrupt to inform HOST // TriggerSoftInterrupt (MEMORY_READY_SIGNATURE); } // // Install Vector Handoff Info PPI to persist vectors used by Debug Agent // Status = PeiServicesInstallPpi (&mVectorHandoffInfoPpiList[0]); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "DebugAgent: Failed to install Vector Handoff Info PPI!\n")); CpuDeadLoop (); } // // Fix up Debug Port handle address and mailbox address // DebugAgentContext = (DEBUG_AGENT_CONTEXT_POSTMEM_SEC *) Context; if (DebugAgentContext != NULL) { DebugPortHandle = (UINT64)(UINT32)(Mailbox->DebugPortHandle + DebugAgentContext->StackMigrateOffset); UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle); Mailbox = (DEBUG_AGENT_MAILBOX *) ((UINTN) Mailbox + DebugAgentContext->StackMigrateOffset); MailboxLocation = (UINT64)(UINTN)Mailbox; // // Build mailbox location in HOB and fix-up its address // MailboxLocationPointer = BuildGuidDataHob ( &gEfiDebugAgentGuid, &MailboxLocation, sizeof (UINT64) ); MailboxLocationPointer = (UINT64 *) ((UINTN) MailboxLocationPointer + DebugAgentContext->HeapMigrateOffset); } else { // // DebugAgentContext is NULL. Then, Mailbox can directly be copied into memory. // Allocate ACPI NVS memory for new Mailbox and Debug Port Handle buffer // Status = PeiServicesAllocatePages ( EfiACPIMemoryNVS, EFI_SIZE_TO_PAGES (sizeof(DEBUG_AGENT_MAILBOX) + PcdGet16(PcdDebugPortHandleBufferSize)), &Address ); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "DebugAgent: Failed to allocate pages!\n")); CpuDeadLoop (); } NewMailbox = (DEBUG_AGENT_MAILBOX *) (UINTN) Address; // // Copy Mailbox and Debug Port Handle buffer to new location in ACPI NVS memory, because original Mailbox // and Debug Port Handle buffer in the allocated pool that may be marked as free by DXE Core after DXE Core // reallocates the HOB. // CopyMem (NewMailbox, Mailbox, sizeof (DEBUG_AGENT_MAILBOX)); CopyMem (NewMailbox + 1, (VOID *)(UINTN)Mailbox->DebugPortHandle, PcdGet16(PcdDebugPortHandleBufferSize)); UpdateMailboxContent (NewMailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, (UINT64)(UINTN)(NewMailbox + 1)); MailboxLocation = (UINT64)(UINTN)NewMailbox; // // Build mailbox location in HOB // MailboxLocationPointer = BuildGuidDataHob ( &gEfiDebugAgentGuid, &MailboxLocation, sizeof (UINT64) ); } // // Update IDT entry to save the location saved mailbox pointer // SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationPointer); break; case DEBUG_AGENT_INIT_PEI: if (Context == NULL) { DEBUG ((EFI_D_ERROR, "DebugAgent: Input parameter Context cannot be NULL!\n")); CpuDeadLoop (); } // // Check if Debug Agent has initialized before // if (IsDebugAgentInitialzed()) { DEBUG ((EFI_D_WARN, "Debug Agent: It has already initialized in SEC Core!\n")); break; } // // Install Vector Handoff Info PPI to persist vectors used by Debug Agent // Status = PeiServicesInstallPpi (&mVectorHandoffInfoPpiList[0]); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "DebugAgent: Failed to install Vector Handoff Info PPI!\n")); CpuDeadLoop (); } // // Set up IDT entries // InitializeDebugIdt (); // // Build mailbox in HOB and setup Mailbox Set In Pei flag // Mailbox = AllocateZeroPool (sizeof (DEBUG_AGENT_MAILBOX)); if (Mailbox == NULL) { DEBUG ((EFI_D_ERROR, "DebugAgent: Failed to allocate memory!\n")); CpuDeadLoop (); } else { MailboxLocation = (UINT64)(UINTN)Mailbox; MailboxLocationPointer = BuildGuidDataHob ( &gEfiDebugAgentGuid, &MailboxLocation, sizeof (UINT64) ); // // Initialize Debug Timer hardware and save its frequency // InitializeDebugTimer (&DebugTimerFrequency, TRUE); UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY, DebugTimerFrequency); // // Update IDT entry to save the location pointer saved mailbox pointer // SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationPointer); } // // Save init arch type when debug agent initialized // SetDebugFlag (DEBUG_AGENT_FLAG_INIT_ARCH, DEBUG_ARCH_SYMBOL); // // Register for a callback once memory has been initialized. // If memery has been ready, the callback funtion will be invoked immediately // Status = PeiServicesNotifyPpi (&mMemoryDiscoveredNotifyList[0]); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "DebugAgent: Failed to register memory discovered callback function!\n")); CpuDeadLoop (); } // // Set HOB check flag if memory has not been ready yet // if (GetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY) == 0) { SetDebugFlag (DEBUG_AGENT_FLAG_CHECK_MAILBOX_IN_HOB, 1); } Phase2Context.InitFlag = InitFlag; Phase2Context.Context = Context; Phase2Context.Function = Function; DebugPortInitialize ((VOID *) &Phase2Context, InitializeDebugAgentPhase2); FindAndReportModuleImageInfo (4); break; case DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64: if (Context == NULL) { DEBUG ((EFI_D_ERROR, "DebugAgent: Input parameter Context cannot be NULL!\n")); CpuDeadLoop (); } else { Ia32Idtr = (IA32_DESCRIPTOR *) Context; Ia32IdtEntry = (IA32_IDT_ENTRY *)(Ia32Idtr->Base); MailboxLocationPointer = (UINT64 *) (UINTN) (Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetLow + (UINT32) (Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetHigh << 16)); Mailbox = (DEBUG_AGENT_MAILBOX *) (UINTN)(*MailboxLocationPointer); // // Mailbox should valid and setup before executing thunk code // VerifyMailboxChecksum (Mailbox); DebugPortHandle = (UINT64) (UINTN)DebugPortInitialize ((VOID *)(UINTN)Mailbox->DebugPortHandle, NULL); UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle); // // Set up IDT entries // InitializeDebugIdt (); // // Update IDT entry to save location pointer saved the mailbox pointer // SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationPointer); FindAndReportModuleImageInfo (4); } break; default: // // Only DEBUG_AGENT_INIT_PREMEM_SEC and DEBUG_AGENT_INIT_POSTMEM_SEC are allowed for this // Debug Agent library instance. // DEBUG ((EFI_D_ERROR, "Debug Agent: The InitFlag value is not allowed!\n")); CpuDeadLoop (); break; } if (InitFlag == DEBUG_AGENT_INIT_POSTMEM_SEC) { // // Restore CPU Interrupt state and keep debug timer interrupt state as is // in DEBUG_AGENT_INIT_POSTMEM_SEC case // SetInterruptState (CpuInterruptState); } else { // // Enable Debug Timer interrupt // SaveAndSetDebugTimerInterrupt (TRUE); // // Enable CPU interrupts so debug timer interrupts can be delivered // EnableInterrupts (); } // // If Function is not NULL, invoke it always whatever debug agent was initialized sucesssfully or not. // if (Function != NULL) { Function (Context); } // // Set return status for DEBUG_AGENT_INIT_PEI // if (InitFlag == DEBUG_AGENT_INIT_PEI && Context != NULL) { *(EFI_STATUS *)Context = EFI_SUCCESS; } }
/** Entry function of Boot script exector. This function will be executed in S3 boot path. This function should not return, because it is invoked by switch stack. @param AcpiS3Context a pointer to a structure of ACPI_S3_CONTEXT @param PeiS3ResumeState a pointer to a structure of PEI_S3_RESUME_STATE @retval EFI_INVALID_PARAMETER - OS waking vector not found @retval EFI_UNSUPPORTED - something wrong when we resume to OS **/ EFI_STATUS EFIAPI S3BootScriptExecutorEntryFunction ( IN ACPI_S3_CONTEXT *AcpiS3Context, IN PEI_S3_RESUME_STATE *PeiS3ResumeState ) { EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs; EFI_STATUS Status; UINTN TempStackTop; UINTN TempStack[0x10]; UINTN AsmTransferControl16Address; IA32_DESCRIPTOR IdtDescriptor; // // Disable interrupt of Debug timer, since new IDT table cannot handle it. // SaveAndSetDebugTimerInterrupt (FALSE); AsmReadIdtr (&IdtDescriptor); // // Restore IDT for debug // SetIdtEntry (AcpiS3Context); // // Initialize Debug Agent to support source level debug in S3 path, it will disable interrupt and Debug Timer. // InitializeDebugAgent (DEBUG_AGENT_INIT_S3, (VOID *)&IdtDescriptor, NULL); // // Because not install BootScriptExecute PPI(used just in this module), So just pass NULL // for that parameter. // Status = S3BootScriptExecute (); // // If invalid script table or opcode in S3 boot script table. // ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { CpuDeadLoop (); return Status; } AsmWbinvd (); // // Get ACPI Table Address // Facs = (EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) ((UINTN) (AcpiS3Context->AcpiFacsTable)); // // We need turn back to S3Resume - install boot script done ppi and report status code on S3resume. // if (PeiS3ResumeState != 0) { // // Need report status back to S3ResumePeim. // If boot script execution is failed, S3ResumePeim wil report the error status code. // PeiS3ResumeState->ReturnStatus = (UINT64)(UINTN)Status; if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) { // // X64 S3 Resume // DEBUG ((EFI_D_ERROR, "Call AsmDisablePaging64() to return to S3 Resume in PEI Phase\n")); PeiS3ResumeState->AsmTransferControl = (EFI_PHYSICAL_ADDRESS)(UINTN)AsmTransferControl32; if ((Facs != NULL) && (Facs->Signature == EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) && (Facs->FirmwareWakingVector != 0) ) { // // more step needed - because relative address is handled differently between X64 and IA32. // AsmTransferControl16Address = (UINTN)AsmTransferControl16; AsmFixAddress16 = (UINT32)AsmTransferControl16Address; AsmJmpAddr32 = (UINT32)((Facs->FirmwareWakingVector & 0xF) | ((Facs->FirmwareWakingVector & 0xFFFF0) << 12)); } AsmDisablePaging64 ( PeiS3ResumeState->ReturnCs, (UINT32)PeiS3ResumeState->ReturnEntryPoint, (UINT32)(UINTN)AcpiS3Context, (UINT32)(UINTN)PeiS3ResumeState, (UINT32)PeiS3ResumeState->ReturnStackPointer ); } else { // // IA32 S3 Resume // DEBUG ((EFI_D_ERROR, "Call SwitchStack() to return to S3 Resume in PEI Phase\n")); PeiS3ResumeState->AsmTransferControl = (EFI_PHYSICAL_ADDRESS)(UINTN)AsmTransferControl; SwitchStack ( (SWITCH_STACK_ENTRY_POINT)(UINTN)PeiS3ResumeState->ReturnEntryPoint, (VOID *)(UINTN)AcpiS3Context, (VOID *)(UINTN)PeiS3ResumeState, (VOID *)(UINTN)PeiS3ResumeState->ReturnStackPointer ); } // // Never run to here // CpuDeadLoop(); return EFI_UNSUPPORTED; } // // S3ResumePeim does not provide a way to jump back to itself, so resume to OS here directly // if (Facs->XFirmwareWakingVector != 0) { // // Switch to native waking vector // TempStackTop = (UINTN)&TempStack + sizeof(TempStack); if ((Facs->Version == EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION) && ((Facs->Flags & EFI_ACPI_4_0_64BIT_WAKE_SUPPORTED_F) != 0) && ((Facs->Flags & EFI_ACPI_4_0_OSPM_64BIT_WAKE__F) != 0)) { // // X64 long mode waking vector // DEBUG (( EFI_D_ERROR, "Transfer to 64bit OS waking vector - %x\r\n", (UINTN)Facs->XFirmwareWakingVector)); if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) { SwitchStack ( (SWITCH_STACK_ENTRY_POINT)(UINTN)Facs->XFirmwareWakingVector, NULL, NULL, (VOID *)(UINTN)TempStackTop ); } else { // Unsupported for 32bit DXE, 64bit OS vector DEBUG (( EFI_D_ERROR, "Unsupported for 32bit DXE transfer to 64bit OS waking vector!\r\n")); ASSERT (FALSE); } } else { // // IA32 protected mode waking vector (Page disabled) // DEBUG (( EFI_D_ERROR, "Transfer to 32bit OS waking vector - %x\r\n", (UINTN)Facs->XFirmwareWakingVector)); if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) { AsmDisablePaging64 ( 0x10, (UINT32)Facs->XFirmwareWakingVector, 0, 0, (UINT32)TempStackTop ); } else { SwitchStack ( (SWITCH_STACK_ENTRY_POINT)(UINTN)Facs->XFirmwareWakingVector, NULL, NULL, (VOID *)(UINTN)TempStackTop ); } } } else { // // 16bit Realmode waking vector // DEBUG (( EFI_D_ERROR, "Transfer to 16bit OS waking vector - %x\r\n", (UINTN)Facs->FirmwareWakingVector)); AsmTransferControl (Facs->FirmwareWakingVector, 0x0); } // // Never run to here // CpuDeadLoop(); return EFI_UNSUPPORTED; }
/** Read the specified number of bytes from serial device. @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL. @param[in, out] BufferSize On input the size of Buffer, on output the amount of data returned in buffer. @param[out] Buffer The buffer to return the data into. @retval EFI_SUCCESS The data were read successfully. @retval EFI_DEVICE_ERROR The device reported an error. @retval EFI_TIMEOUT The read operation was stopped due to timeout. **/ EFI_STATUS EFIAPI SerialRead ( IN EFI_SERIAL_IO_PROTOCOL *This, IN OUT UINTN *BufferSize, OUT VOID *Buffer ) { EFI_STATUS Status; UINTN Index; UINT8 *Uint8Buffer; BOOLEAN DebugTimerInterruptState; EFI_TPL Tpl; DEBUG_PORT_HANDLE Handle; DEBUG_PACKET_HEADER DebugHeader; UINT8 *Data8; // // Raise TPL to prevent recursion from EFI timer interrupts // Tpl = gBS->RaiseTPL (TPL_NOTIFY); // // Save and disable Debug Timer interrupt to avoid it to access Debug Port // DebugTimerInterruptState = SaveAndSetDebugTimerInterrupt (FALSE); Handle = GetDebugPortHandle (); Data8 = (UINT8 *) &DebugHeader; Uint8Buffer = (UINT8 *)Buffer; if ((mSerialIoMode.ControlMask & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) != 0) { if ((mLoopbackBuffer & SERIAL_PORT_LOOPBACK_BUFFER_FULL) == 0) { return EFI_TIMEOUT; } *Uint8Buffer = (UINT8)(mLoopbackBuffer & 0xff); mLoopbackBuffer = 0; *BufferSize = 1; } else { for (Index = 0; Index < *BufferSize; Index++) { // // Read input character from terminal FIFO firstly // Status = DebugTerminalFifoRemove (&mSerialFifoForTerminal, Data8); if (Status == EFI_SUCCESS) { *Uint8Buffer = *Data8; Uint8Buffer ++; continue; } // // Read the input character from Debug Port // if (!DebugPortPollBuffer (Handle)) { break; } DebugPortReadBuffer (Handle, Data8, 1, 0); if (*Data8 == DEBUG_STARTING_SYMBOL_ATTACH) { // // Add the debug symbol into Debug FIFO // DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Terminal Timer attach symbol received %x", *Data8); DebugTerminalFifoAdd (&mSerialFifoForDebug, *Data8); } else if (*Data8 == DEBUG_STARTING_SYMBOL_NORMAL) { Status = ReadRemainingBreakPacket (Handle, &DebugHeader); if (Status == EFI_SUCCESS) { DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Terminal Timer break symbol received %x", DebugHeader.Command); DebugTerminalFifoAdd (&mSerialFifoForDebug, DebugHeader.Command); } if (Status == EFI_TIMEOUT) { continue; } } else { *Uint8Buffer = *Data8; Uint8Buffer ++; } } *BufferSize = (UINTN)Uint8Buffer - (UINTN)Buffer; } // // Restore Debug Timer interrupt // SaveAndSetDebugTimerInterrupt (DebugTimerInterruptState); // // Restore to original TPL // gBS->RestoreTPL (Tpl); return EFI_SUCCESS; }
/** Entry function of Boot script exector. This function will be executed in S3 boot path. This function should not return, because it is invoked by switch stack. @param AcpiS3Context a pointer to a structure of ACPI_S3_CONTEXT @param PeiS3ResumeState a pointer to a structure of PEI_S3_RESUME_STATE @retval EFI_INVALID_PARAMETER - OS waking vector not found @retval EFI_UNSUPPORTED - something wrong when we resume to OS **/ EFI_STATUS EFIAPI S3BootScriptExecutorEntryFunction ( IN ACPI_S3_CONTEXT *AcpiS3Context, IN PEI_S3_RESUME_STATE *PeiS3ResumeState ) { EFI_STATUS Status; // // Disable interrupt of Debug timer, since new IDT table cannot handle it. // SaveAndSetDebugTimerInterrupt (FALSE); // // Restore IDT for debug // SetIdtEntry (AcpiS3Context); // // Initialize Debug Agent to support source level debug in S3 path. // InitializeDebugAgent (DEBUG_AGENT_INIT_S3, NULL, NULL); // // Because not install BootScriptExecute PPI(used just in this module), So just pass NULL // for that parameter. // Status = S3BootScriptExecute (); AsmWbinvd (); // // We need turn back to S3Resume - install boot script done ppi and report status code on S3resume. // if (PeiS3ResumeState != 0) { // // Need report status back to S3ResumePeim. // If boot script execution is failed, S3ResumePeim wil report the error status code. // PeiS3ResumeState->ReturnStatus = (UINT64)(UINTN)Status; // // IA32 S3 Resume // DEBUG ((EFI_D_INFO, "Call SwitchStack() to return to S3 Resume in PEI Phase\n")); PeiS3ResumeState->AsmTransferControl = (EFI_PHYSICAL_ADDRESS)(UINTN)PlatformTransferControl16; SwitchStack ( (SWITCH_STACK_ENTRY_POINT)(UINTN)PeiS3ResumeState->ReturnEntryPoint, (VOID *)(UINTN)AcpiS3Context, (VOID *)(UINTN)PeiS3ResumeState, (VOID *)(UINTN)PeiS3ResumeState->ReturnStackPointer ); // // Never run to here // CpuDeadLoop(); return EFI_UNSUPPORTED; } // // Never run to here // CpuDeadLoop(); return EFI_UNSUPPORTED; }
VOID CEntryPoint ( IN VOID *MemoryBase, IN UINTN MemorySize, IN VOID *StackBase, IN UINTN StackSize ) { VOID *HobBase; // Build a basic HOB list HobBase = (VOID *)(UINTN)(FixedPcdGet32(PcdEmbeddedFdBaseAddress) + FixedPcdGet32(PcdEmbeddedFdSize)); CreateHobList (MemoryBase, MemorySize, HobBase, StackBase); //Set up Pin muxing. PadConfiguration (); // Set up system clocking ClockInit (); // Enable program flow prediction, if supported. ArmEnableBranchPrediction (); // Initialize CPU cache InitCache ((UINT32)MemoryBase, (UINT32)MemorySize); // Add memory allocation hob for relocated FD BuildMemoryAllocationHob (FixedPcdGet32(PcdEmbeddedFdBaseAddress), FixedPcdGet32(PcdEmbeddedFdSize), EfiBootServicesData); // Add the FVs to the hob list BuildFvHob (PcdGet32(PcdFlashFvMainBase), PcdGet32(PcdFlashFvMainSize)); // Start talking UartInit (); InitializeDebugAgent (DEBUG_AGENT_INIT_PREMEM_SEC, NULL, NULL); SaveAndSetDebugTimerInterrupt (TRUE); DEBUG ((EFI_D_ERROR, "UART Enabled\n")); // Start up a free running timer so that the timer lib will work TimerInit (); // SEC phase needs to run library constructors by hand. ExtractGuidedSectionLibConstructor (); LzmaDecompressLibConstructor (); // Build HOBs to pass up our version of stuff the DXE Core needs to save space BuildPeCoffLoaderHob (); BuildExtractSectionHob ( &gLzmaCustomDecompressGuid, LzmaGuidedSectionGetInfo, LzmaGuidedSectionExtraction ); // Assume the FV that contains the SEC (our code) also contains a compressed FV. DecompressFirstFv (); // Load the DXE Core and transfer control to it LoadDxeCoreFromFv (NULL, 0); // DXE Core should always load and never return ASSERT (FALSE); }
VOID PrePiMain ( IN UINTN UefiMemoryBase, IN UINTN StacksBase, IN UINT64 StartTimeStamp ) { EFI_HOB_HANDOFF_INFO_TABLE* HobList; ARM_MP_CORE_INFO_PPI* ArmMpCoreInfoPpi; UINTN ArmCoreCount; ARM_CORE_INFO* ArmCoreInfoTable; EFI_STATUS Status; CHAR8 Buffer[100]; UINTN CharCount; UINTN StacksSize; // If ensure the FD is either part of the System Memory or totally outside of the System Memory (XIP) ASSERT (IS_XIP() || ((FixedPcdGet64 (PcdFdBaseAddress) >= FixedPcdGet64 (PcdSystemMemoryBase)) && ((UINT64)(FixedPcdGet64 (PcdFdBaseAddress) + FixedPcdGet32 (PcdFdSize)) <= (UINT64)mSystemMemoryEnd))); // Initialize the architecture specific bits ArchInitialize (); // Initialize the Serial Port SerialPortInitialize (); CharCount = AsciiSPrint (Buffer,sizeof (Buffer),"UEFI firmware (version %s built at %a on %a)\n\r", (CHAR16*)PcdGetPtr(PcdFirmwareVersionString), __TIME__, __DATE__); SerialPortWrite ((UINT8 *) Buffer, CharCount); // Initialize the Debug Agent for Source Level Debugging InitializeDebugAgent (DEBUG_AGENT_INIT_POSTMEM_SEC, NULL, NULL); SaveAndSetDebugTimerInterrupt (TRUE); // Declare the PI/UEFI memory region HobList = HobConstructor ( (VOID*)UefiMemoryBase, FixedPcdGet32 (PcdSystemMemoryUefiRegionSize), (VOID*)UefiMemoryBase, (VOID*)StacksBase // The top of the UEFI Memory is reserved for the stacks ); PrePeiSetHobList (HobList); // Initialize MMU and Memory HOBs (Resource Descriptor HOBs) Status = MemoryPeim (UefiMemoryBase, FixedPcdGet32 (PcdSystemMemoryUefiRegionSize)); ASSERT_EFI_ERROR (Status); // Create the Stacks HOB (reserve the memory for all stacks) if (ArmIsMpCore ()) { StacksSize = PcdGet32 (PcdCPUCorePrimaryStackSize) + ((FixedPcdGet32 (PcdCoreCount) - 1) * FixedPcdGet32 (PcdCPUCoreSecondaryStackSize)); } else { StacksSize = PcdGet32 (PcdCPUCorePrimaryStackSize); } BuildStackHob (StacksBase, StacksSize); //TODO: Call CpuPei as a library BuildCpuHob (PcdGet8 (PcdPrePiCpuMemorySize), PcdGet8 (PcdPrePiCpuIoSize)); if (ArmIsMpCore ()) { // Only MP Core platform need to produce gArmMpCoreInfoPpiGuid Status = GetPlatformPpi (&gArmMpCoreInfoPpiGuid, (VOID**)&ArmMpCoreInfoPpi); // On MP Core Platform we must implement the ARM MP Core Info PPI (gArmMpCoreInfoPpiGuid) ASSERT_EFI_ERROR (Status); // Build the MP Core Info Table ArmCoreCount = 0; Status = ArmMpCoreInfoPpi->GetMpCoreInfo (&ArmCoreCount, &ArmCoreInfoTable); if (!EFI_ERROR(Status) && (ArmCoreCount > 0)) { // Build MPCore Info HOB BuildGuidDataHob (&gArmMpCoreInfoGuid, ArmCoreInfoTable, sizeof (ARM_CORE_INFO) * ArmCoreCount); } } // Set the Boot Mode SetBootMode (ArmPlatformGetBootMode ()); // Initialize Platform HOBs (CpuHob and FvHob) Status = PlatformPeim (); ASSERT_EFI_ERROR (Status); // Now, the HOB List has been initialized, we can register performance information PERF_START (NULL, "PEI", NULL, StartTimeStamp); // SEC phase needs to run library constructors by hand. ExtractGuidedSectionLibConstructor (); LzmaDecompressLibConstructor (); // Build HOBs to pass up our version of stuff the DXE Core needs to save space BuildPeCoffLoaderHob (); BuildExtractSectionHob ( &gLzmaCustomDecompressGuid, LzmaGuidedSectionGetInfo, LzmaGuidedSectionExtraction ); // Assume the FV that contains the SEC (our code) also contains a compressed FV. Status = DecompressFirstFv (); ASSERT_EFI_ERROR (Status); // Load the DXE Core and transfer control to it Status = LoadDxeCoreFromFv (NULL, 0); ASSERT_EFI_ERROR (Status); }
/** Terminates all boot services. @param ImageHandle Handle that identifies the exiting image. @param MapKey Key to the latest memory map. @retval EFI_SUCCESS Boot Services terminated @retval EFI_INVALID_PARAMETER MapKey is incorrect. **/ EFI_STATUS EFIAPI CoreExitBootServices ( IN EFI_HANDLE ImageHandle, IN UINTN MapKey ) { EFI_STATUS Status; // // Disable Timer // gTimer->SetTimerPeriod (gTimer, 0); // // Terminate memory services if the MapKey matches // Status = CoreTerminateMemoryMap (MapKey); if (EFI_ERROR (Status)) { // // Notify other drivers that ExitBootServices fail // CoreNotifySignalList (&gEventExitBootServicesFailedGuid); return Status; } gMemoryMapTerminated = TRUE; // // Notify other drivers that we are exiting boot services. // CoreNotifySignalList (&gEfiEventExitBootServicesGuid); // // Report that ExitBootServices() has been called // REPORT_STATUS_CODE ( EFI_PROGRESS_CODE, (EFI_SOFTWARE_EFI_BOOT_SERVICE | EFI_SW_BS_PC_EXIT_BOOT_SERVICES) ); // // Disable interrupt of Debug timer. // SaveAndSetDebugTimerInterrupt (FALSE); // // Disable CPU Interrupts // gCpu->DisableInterrupt (gCpu); // // Clear the non-runtime values of the EFI System Table // gDxeCoreST->BootServices = NULL; gDxeCoreST->ConIn = NULL; gDxeCoreST->ConsoleInHandle = NULL; gDxeCoreST->ConOut = NULL; gDxeCoreST->ConsoleOutHandle = NULL; gDxeCoreST->StdErr = NULL; gDxeCoreST->StandardErrorHandle = NULL; // // Recompute the 32-bit CRC of the EFI System Table // CalculateEfiHdrCrc (&gDxeCoreST->Hdr); // // Zero out the Boot Service Table // ZeroMem (gBS, sizeof (EFI_BOOT_SERVICES)); gBS = NULL; // // Update the AtRuntime field in Runtiem AP. // gRuntime->AtRuntime = TRUE; return Status; }
/** Read the specified number of bytes from serial device. @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL. @param[in, out] BufferSize On input the size of Buffer, on output the amount of data returned in buffer. @param[out] Buffer The buffer to return the data into. @retval EFI_SUCCESS The data were read successfully. @retval EFI_DEVICE_ERROR The device reported an error. @retval EFI_TIMEOUT The read operation was stopped due to timeout. **/ EFI_STATUS EFIAPI SerialRead ( IN EFI_SERIAL_IO_PROTOCOL *This, IN OUT UINTN *BufferSize, OUT VOID *Buffer ) { EFI_STATUS Status; UINTN Index; UINT8 *Uint8Buffer; BOOLEAN OldInterruptState; DEBUG_PORT_HANDLE Handle; UINT8 Data; Handle = GetDebugPortHandle (); // // Save and disable Debug Timer interrupt to avoid it to access Debug Port // OldInterruptState = SaveAndSetDebugTimerInterrupt (FALSE); Uint8Buffer = (UINT8 *)Buffer; if ((mSerialIoMode.ControlMask & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) != 0) { if ((mLoopbackBuffer & SERIAL_PORT_LOOPBACK_BUFFER_FULL) == 0) { return EFI_TIMEOUT; } *Uint8Buffer = (UINT8)(mLoopbackBuffer & 0xff); mLoopbackBuffer = 0; *BufferSize = 1; } else { for (Index = 0; Index < *BufferSize; Index++) { // // Read input character from terminal FIFO firstly // Status = DebugTerminalFifoRemove (&mSerialFifoForTerminal, &Data); if (Status == EFI_SUCCESS) { *Uint8Buffer = Data; Uint8Buffer ++; continue; } // // Read the input character from Debug Port // if (!DebugPortPollBuffer (Handle)) { break; } DebugPortReadBuffer (Handle, &Data, 1, 0); if (Data== DEBUG_STARTING_SYMBOL_ATTACH || Data == DEBUG_STARTING_SYMBOL_BREAK) { // // Add the debug symbol into Debug FIFO // DebugTerminalFifoAdd (&mSerialFifoForDebug, Data); } else { *Uint8Buffer = Data; Uint8Buffer ++; } } *BufferSize = (UINTN)Uint8Buffer - (UINTN)Buffer; } // // Restore Debug Timer interrupt // SaveAndSetDebugTimerInterrupt (OldInterruptState); return EFI_SUCCESS; }
/** The X64 entrypoint is used to process capsule in long mode then return to 32-bit protected mode. @param EntrypointContext Pointer to the context of long mode. @param ReturnContext Pointer to the context of 32-bit protected mode. @retval This function should never return actually. **/ EFI_STATUS EFIAPI _ModuleEntryPoint ( SWITCH_32_TO_64_CONTEXT *EntrypointContext, SWITCH_64_TO_32_CONTEXT *ReturnContext ) { EFI_STATUS Status; IA32_DESCRIPTOR Ia32Idtr; IA32_DESCRIPTOR X64Idtr; IA32_IDT_GATE_DESCRIPTOR IdtEntryTable[EXCEPTION_VECTOR_NUMBER]; // // Save the IA32 IDT Descriptor // AsmReadIdtr ((IA32_DESCRIPTOR *) &Ia32Idtr); // // Setup X64 IDT table // ZeroMem (IdtEntryTable, sizeof (IA32_IDT_GATE_DESCRIPTOR) * EXCEPTION_VECTOR_NUMBER); X64Idtr.Base = (UINTN) IdtEntryTable; X64Idtr.Limit = (UINT16) (sizeof (IA32_IDT_GATE_DESCRIPTOR) * EXCEPTION_VECTOR_NUMBER - 1); AsmWriteIdtr ((IA32_DESCRIPTOR *) &X64Idtr); // // Setup the default CPU exception handlers // Status = InitializeCpuExceptionHandlers (NULL); ASSERT_EFI_ERROR (Status); // // Initialize Debug Agent to support source level debug // InitializeDebugAgent (DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64, (VOID *) &Ia32Idtr, NULL); // // Call CapsuleDataCoalesce to process capsule. // Status = CapsuleDataCoalesce ( NULL, (EFI_PHYSICAL_ADDRESS *) (UINTN) EntrypointContext->BlockListAddr, (VOID **) (UINTN) EntrypointContext->MemoryBase64Ptr, (UINTN *) (UINTN) EntrypointContext->MemorySize64Ptr ); ReturnContext->ReturnStatus = Status; // // Disable interrupt of Debug timer, since the new IDT table cannot work in long mode // SaveAndSetDebugTimerInterrupt (FALSE); // // Restore IA32 IDT table // AsmWriteIdtr ((IA32_DESCRIPTOR *) &Ia32Idtr); // // Finish to coalesce capsule, and return to 32-bit mode. // AsmDisablePaging64 ( ReturnContext->ReturnCs, (UINT32) ReturnContext->ReturnEntryPoint, (UINT32) (UINTN) EntrypointContext, (UINT32) (UINTN) ReturnContext, (UINT32) (EntrypointContext->StackBufferBase + EntrypointContext->StackBufferLength) ); // // Should never be here. // ASSERT (FALSE); return EFI_SUCCESS; }
VOID CEntryPoint ( IN UINTN MpId, IN UINTN SecBootMode ) { CHAR8 Buffer[100]; UINTN CharCount; UINTN JumpAddress; // Invalidate the data cache. Doesn't have to do the Data cache clean. ArmInvalidateDataCache (); // Invalidate Instruction Cache ArmInvalidateInstructionCache (); // Invalidate I & D TLBs ArmInvalidateInstructionAndDataTlb (); // CPU specific settings ArmCpuSetup (MpId); // Enable Floating Point Coprocessor if supported by the platform if (FixedPcdGet32 (PcdVFPEnabled)) { ArmEnableVFP (); } // Initialize peripherals that must be done at the early stage // Example: Some L2 controller, interconnect, clock, DMC, etc ArmPlatformSecInitialize (MpId); // Primary CPU clears out the SCU tag RAMs, secondaries wait if (ArmPlatformIsPrimaryCore (MpId) && (SecBootMode == ARM_SEC_COLD_BOOT)) { if (ArmIsMpCore()) { // Signal for the initial memory is configured (event: BOOT_MEM_INIT) ArmCallSEV (); } // SEC phase needs to run library constructors by hand. This assumes we are linked against the SerialLib // In non SEC modules the init call is in autogenerated code. SerialPortInitialize (); // Start talking if (FixedPcdGetBool (PcdTrustzoneSupport)) { CharCount = AsciiSPrint (Buffer,sizeof (Buffer),"Secure firmware (version %s built at %a on %a)\n\r", (CHAR16*)PcdGetPtr(PcdFirmwareVersionString), __TIME__, __DATE__); } else { CharCount = AsciiSPrint (Buffer,sizeof (Buffer),"Boot firmware (version %s built at %a on %a)\n\r", (CHAR16*)PcdGetPtr(PcdFirmwareVersionString), __TIME__, __DATE__); } SerialPortWrite ((UINT8 *) Buffer, CharCount); // Initialize the Debug Agent for Source Level Debugging InitializeDebugAgent (DEBUG_AGENT_INIT_PREMEM_SEC, NULL, NULL); SaveAndSetDebugTimerInterrupt (TRUE); // Enable the GIC distributor and CPU Interface // - no other Interrupts are enabled, doesn't have to worry about the priority. // - all the cores are in secure state, use secure SGI's ArmGicEnableDistributor (PcdGet32(PcdGicDistributorBase)); ArmGicEnableInterruptInterface (PcdGet32(PcdGicInterruptInterfaceBase)); } else { // Enable the GIC CPU Interface ArmGicEnableInterruptInterface (PcdGet32(PcdGicInterruptInterfaceBase)); } // Enable Full Access to CoProcessors ArmWriteCpacr (CPACR_CP_FULL_ACCESS); // Test if Trustzone is supported on this platform if (FixedPcdGetBool (PcdTrustzoneSupport)) { if (ArmIsMpCore ()) { // Setup SMP in Non Secure world ArmCpuSetupSmpNonSecure (GET_CORE_ID(MpId)); } // Either we use the Secure Stacks for Secure Monitor (in this case (Base == 0) && (Size == 0)) // Or we use separate Secure Monitor stacks (but (Base != 0) && (Size != 0)) ASSERT (((PcdGet32(PcdCPUCoresSecMonStackBase) == 0) && (PcdGet32(PcdCPUCoreSecMonStackSize) == 0)) || ((PcdGet32(PcdCPUCoresSecMonStackBase) != 0) && (PcdGet32(PcdCPUCoreSecMonStackSize) != 0))); // Enter Monitor Mode enter_monitor_mode ( (UINTN)TrustedWorldInitialization, MpId, SecBootMode, (VOID*) (PcdGet32 (PcdCPUCoresSecMonStackBase) + (PcdGet32 (PcdCPUCoreSecMonStackSize) * (ArmPlatformGetCorePosition (MpId) + 1))) ); } else { if (ArmPlatformIsPrimaryCore (MpId)) { SerialPrint ("Trust Zone Configuration is disabled\n\r"); } // With Trustzone support the transition from Sec to Normal world is done by return_from_exception(). // If we want to keep this function call we need to ensure the SVC's SPSR point to the same Program // Status Register as the the current one (CPSR). copy_cpsr_into_spsr (); // Call the Platform specific function to execute additional actions if required JumpAddress = PcdGet32 (PcdFvBaseAddress); ArmPlatformSecExtraAction (MpId, &JumpAddress); NonTrustedWorldTransition (MpId, JumpAddress); } ASSERT (0); // We must never return from the above function }
/** Internal constructor worker function. It will register one callback function on EFI PCD Protocol. It will allocate the NVS memory to store Mailbox and install configuration table in system table to store its pointer. **/ VOID InternalConstructorWorker ( VOID ) { EFI_STATUS Status; EFI_PHYSICAL_ADDRESS Address; BOOLEAN DebugTimerInterruptState; DEBUG_AGENT_MAILBOX *Mailbox; DEBUG_AGENT_MAILBOX *NewMailbox; EFI_HOB_GUID_TYPE *GuidHob; EFI_VECTOR_HANDOFF_INFO *VectorHandoffInfo; // // Check persisted vector handoff info // Status = EFI_SUCCESS; GuidHob = GetFirstGuidHob (&gEfiVectorHandoffInfoPpiGuid); if (GuidHob != NULL && !mDxeCoreFlag) { // // Check if configuration table is installed or not if GUIDed HOB existed, // only when Debug Agent is not linked by DXE Core // Status = EfiGetSystemConfigurationTable (&gEfiVectorHandoffTableGuid, (VOID **) &VectorHandoffInfo); } if (GuidHob == NULL || Status != EFI_SUCCESS) { // // Install configuration table for persisted vector handoff info if GUIDed HOB cannot be found or // configuration table does not exist // Status = gBS->InstallConfigurationTable (&gEfiVectorHandoffTableGuid, (VOID *) &mVectorHandoffInfoDebugAgent[0]); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "DebugAgent: Cannot install configuration table for persisted vector handoff info!\n")); CpuDeadLoop (); } } // // Install EFI Serial IO protocol on debug port // InstallSerialIo (); Address = 0; Status = gBS->AllocatePages ( AllocateAnyPages, EfiACPIMemoryNVS, EFI_SIZE_TO_PAGES (sizeof(DEBUG_AGENT_MAILBOX) + PcdGet16(PcdDebugPortHandleBufferSize)), &Address ); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "DebugAgent: Cannot install configuration table for mailbox!\n")); CpuDeadLoop (); } DebugTimerInterruptState = SaveAndSetDebugTimerInterrupt (FALSE); NewMailbox = (DEBUG_AGENT_MAILBOX *) (UINTN) Address; // // Copy Mailbox and Debug Port Handle buffer to new location in ACPI NVS memory, because original Mailbox // and Debug Port Handle buffer may be free at runtime, SMM debug agent needs to access them // Mailbox = GetMailboxPointer (); CopyMem (NewMailbox, Mailbox, sizeof (DEBUG_AGENT_MAILBOX)); CopyMem (NewMailbox + 1, (VOID *)(UINTN)Mailbox->DebugPortHandle, PcdGet16(PcdDebugPortHandleBufferSize)); // // Update Debug Port Handle in new Mailbox // UpdateMailboxContent (NewMailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, (UINT64)(UINTN)(NewMailbox + 1)); mMailboxPointer = NewMailbox; DebugTimerInterruptState = SaveAndSetDebugTimerInterrupt (DebugTimerInterruptState); Status = gBS->InstallConfigurationTable (&gEfiDebugAgentGuid, (VOID *) mMailboxPointer); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "DebugAgent: Failed to install configuration for mailbox!\n")); CpuDeadLoop (); } }
/** Initialize debug agent. This function is used to set up debug enviroment for DXE phase. If this function is called by DXE Core, Context must be the pointer to HOB list which will be used to get GUIDed HOB. It will enable interrupt to support break-in feature. If this function is called by DXE module, Context must be NULL. It will enable interrupt to support break-in feature. @param[in] InitFlag Init flag is used to decide initialize process. @param[in] Context Context needed according to InitFlag. @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 ) { UINT64 *MailboxLocation; DEBUG_AGENT_MAILBOX *Mailbox; BOOLEAN InterruptStatus; VOID *HobList; IA32_DESCRIPTOR IdtDescriptor; IA32_DESCRIPTOR *Ia32Idtr; IA32_IDT_ENTRY *Ia32IdtEntry; if (InitFlag == DEBUG_AGENT_INIT_DXE_AP) { // // Invoked by AP, enable interrupt to let AP could receive IPI from other processors // EnableInterrupts (); return ; } // // Disable Debug Timer interrupt // SaveAndSetDebugTimerInterrupt (FALSE); // // Save and disable original interrupt status // InterruptStatus = SaveAndDisableInterrupts (); // // Try to get mailbox firstly // HobList = NULL; Mailbox = NULL; MailboxLocation = NULL; switch (InitFlag) { case DEBUG_AGENT_INIT_DXE_LOAD: // // Check if Debug Agent has been initialized before // if (IsDebugAgentInitialzed ()) { DEBUG ((EFI_D_INFO, "Debug Agent: The former agent will be overwritten by the new one!\n")); } mMultiProcessorDebugSupport = TRUE; // // Save original IDT table // AsmReadIdtr (&IdtDescriptor); mSaveIdtTableSize = IdtDescriptor.Limit + 1; mSavedIdtTable = AllocateCopyPool (mSaveIdtTableSize, (VOID *) IdtDescriptor.Base); // // Initialize Debug Timer hardware and save its initial count // mDebugMpContext.DebugTimerInitCount = InitializeDebugTimer (); // // Check if Debug Agent initialized in DXE phase // Mailbox = GetMailboxFromConfigurationTable (); if (Mailbox == NULL) { // // Try to get mailbox from GUIDed HOB build in PEI // HobList = GetHobList (); Mailbox = GetMailboxFromHob (HobList); } // // Set up IDT table and prepare for IDT entries // SetupDebugAgentEnviroment (Mailbox); // // For DEBUG_AGENT_INIT_S3, needn't to install configuration table and EFI Serial IO protocol // For DEBUG_AGENT_INIT_DXE_CORE, InternalConstructorWorker() will invoked in Constructor() // InternalConstructorWorker (); // // Enable interrupt to receive Debug Timer interrupt // EnableInterrupts (); mDebugAgentInitialized = TRUE; FindAndReportModuleImageInfo (SIZE_4KB); *(EFI_STATUS *)Context = EFI_SUCCESS; if (gST->ConOut != NULL) { Print (L"Debug Agent: Initialized successfully!\r\n"); Print (L"If the Debug Port is serial port, please make sure this serial port isn't connected by ISA Serial driver\r\n"); Print (L"You could do the following steps to disconnect the serial port:\r\n"); Print (L"1: Shell> drivers\r\n"); Print (L" ...\r\n"); Print (L" V VERSION E G G #D #C DRIVER NAME IMAGE NAME\r\n"); Print (L" == ======== = = = == == =================================== ===================\r\n"); Print (L" 8F 0000000A B - - 1 14 PCI Bus Driver PciBusDxe\r\n"); Print (L" 91 00000010 ? - - - - ATA Bus Driver AtaBusDxe\r\n"); Print (L" ...\r\n"); Print (L" A7 0000000A B - - 1 1 ISA Serial Driver IsaSerialDxe\r\n"); Print (L" ...\r\n"); Print (L"2: Shell> dh -d A7\r\n"); Print (L" A7: Image(IsaSerialDxe) ImageDevPath (..9FB3-11D4-9A3A-0090273FC14D))DriverBinding ComponentName ComponentName2\r\n"); Print (L" Driver Name : ISA Serial Driver\r\n"); Print (L" Image Name : FvFile(93B80003-9FB3-11D4-9A3A-0090273FC14D)\r\n"); Print (L" Driver Version : 0000000A\r\n"); Print (L" Driver Type : BUS\r\n"); Print (L" Configuration : NO\r\n"); Print (L" Diagnostics : NO\r\n"); Print (L" Managing :\r\n"); Print (L" Ctrl[EA] : PciRoot(0x0)/Pci(0x1F,0x0)/Serial(0x0)\r\n"); Print (L" Child[EB] : PciRoot(0x0)/Pci(0x1F,0x0)/Serial(0x0)/Uart(115200,8,N,1)\r\n"); Print (L"3: Shell> disconnect EA\r\n"); Print (L"4: Shell> load -nc DebugAgentDxe.efi\r\n\r\n"); } break; case DEBUG_AGENT_INIT_DXE_UNLOAD: if (mDebugAgentInitialized) { if (IsHostAttached ()) { Print (L"Debug Agent: Host is still connected, please de-attach TARGET firstly!\r\n"); *(EFI_STATUS *)Context = EFI_ACCESS_DENIED; // // Enable Debug Timer interrupt again // SaveAndSetDebugTimerInterrupt (TRUE); } else { // // Restore original IDT table // AsmReadIdtr (&IdtDescriptor); IdtDescriptor.Limit = (UINT16) (mSaveIdtTableSize - 1); CopyMem ((VOID *) IdtDescriptor.Base, mSavedIdtTable, mSaveIdtTableSize); AsmWriteIdtr (&IdtDescriptor); FreePool (mSavedIdtTable); mDebugAgentInitialized = FALSE; *(EFI_STATUS *)Context = EFI_SUCCESS; } } else { Print (L"Debug Agent: It hasn't been initialized, cannot unload it!\r\n"); *(EFI_STATUS *)Context = EFI_NOT_STARTED; } // // Restore interrupt state. // SetInterruptState (InterruptStatus); break; case DEBUG_AGENT_INIT_DXE_CORE: mDxeCoreFlag = TRUE; mMultiProcessorDebugSupport = TRUE; // // Initialize Debug Timer hardware and its initial count // mDebugMpContext.DebugTimerInitCount = InitializeDebugTimer (); // // Try to get mailbox from GUIDed HOB build in PEI // HobList = Context; Mailbox = GetMailboxFromHob (HobList); // // Set up IDT table and prepare for IDT entries // SetupDebugAgentEnviroment (Mailbox); // // Enable interrupt to receive Debug Timer interrupt // EnableInterrupts (); break; case DEBUG_AGENT_INIT_S3: if (Context != NULL) { Ia32Idtr = (IA32_DESCRIPTOR *) Context; Ia32IdtEntry = (IA32_IDT_ENTRY *)(Ia32Idtr->Base); MailboxLocation = (UINT64 *) (UINTN) (Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetLow + (Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetHigh << 16)); Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation); VerifyMailboxChecksum (Mailbox); } // // Save Mailbox pointer in global variable // mMailboxPointer = Mailbox; // // Set up IDT table and prepare for IDT entries // SetupDebugAgentEnviroment (Mailbox); // // Disable interrupt // DisableInterrupts (); FindAndReportModuleImageInfo (SIZE_4KB); if (GetDebugFlag (DEBUG_AGENT_FLAG_BREAK_BOOT_SCRIPT) == 1) { // // If Boot Script entry break is set, code will be break at here. // CpuBreakpoint (); } break; default: // // Only DEBUG_AGENT_INIT_PREMEM_SEC and DEBUG_AGENT_INIT_POSTMEM_SEC are allowed for this // Debug Agent library instance. // DEBUG ((EFI_D_ERROR, "Debug Agent: The InitFlag value is not allowed!\n")); CpuDeadLoop (); break; } }
/** Perform SMM initialization for all processors in the S3 boot path. For a native platform, MP initialization in the S3 boot path is also performed in this function. **/ VOID EFIAPI SmmRestoreCpu ( VOID ) { SMM_S3_RESUME_STATE *SmmS3ResumeState; IA32_DESCRIPTOR Ia32Idtr; IA32_DESCRIPTOR X64Idtr; IA32_IDT_GATE_DESCRIPTOR IdtEntryTable[EXCEPTION_VECTOR_NUMBER]; EFI_STATUS Status; DEBUG ((EFI_D_INFO, "SmmRestoreCpu()\n")); mSmmS3Flag = TRUE; InitializeSpinLock (mMemoryMappedLock); // // See if there is enough context to resume PEI Phase // if (mSmmS3ResumeState == NULL) { DEBUG ((EFI_D_ERROR, "No context to return to PEI Phase\n")); CpuDeadLoop (); } SmmS3ResumeState = mSmmS3ResumeState; ASSERT (SmmS3ResumeState != NULL); if (SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_64) { // // Save the IA32 IDT Descriptor // AsmReadIdtr ((IA32_DESCRIPTOR *) &Ia32Idtr); // // Setup X64 IDT table // ZeroMem (IdtEntryTable, sizeof (IA32_IDT_GATE_DESCRIPTOR) * 32); X64Idtr.Base = (UINTN) IdtEntryTable; X64Idtr.Limit = (UINT16) (sizeof (IA32_IDT_GATE_DESCRIPTOR) * 32 - 1); AsmWriteIdtr ((IA32_DESCRIPTOR *) &X64Idtr); // // Setup the default exception handler // Status = InitializeCpuExceptionHandlers (NULL); ASSERT_EFI_ERROR (Status); // // Initialize Debug Agent to support source level debug // InitializeDebugAgent (DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64, (VOID *)&Ia32Idtr, NULL); } // // Skip initialization if mAcpiCpuData is not valid // if (mAcpiCpuData.NumberOfCpus > 0) { // // First time microcode load and restore MTRRs // InitializeCpuBeforeRebase (); } // // Restore SMBASE for BSP and all APs // SmmRelocateBases (); // // Skip initialization if mAcpiCpuData is not valid // if (mAcpiCpuData.NumberOfCpus > 0) { // // Restore MSRs for BSP and all APs // InitializeCpuAfterRebase (); } // // Set a flag to restore SMM configuration in S3 path. // mRestoreSmmConfigurationInS3 = TRUE; DEBUG (( EFI_D_INFO, "SMM S3 Return CS = %x\n", SmmS3ResumeState->ReturnCs)); DEBUG (( EFI_D_INFO, "SMM S3 Return Entry Point = %x\n", SmmS3ResumeState->ReturnEntryPoint)); DEBUG (( EFI_D_INFO, "SMM S3 Return Context1 = %x\n", SmmS3ResumeState->ReturnContext1)); DEBUG (( EFI_D_INFO, "SMM S3 Return Context2 = %x\n", SmmS3ResumeState->ReturnContext2)); DEBUG (( EFI_D_INFO, "SMM S3 Return Stack Pointer = %x\n", SmmS3ResumeState->ReturnStackPointer)); // // If SMM is in 32-bit mode, then use SwitchStack() to resume PEI Phase // if (SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_32) { DEBUG ((EFI_D_INFO, "Call SwitchStack() to return to S3 Resume in PEI Phase\n")); SwitchStack ( (SWITCH_STACK_ENTRY_POINT)(UINTN)SmmS3ResumeState->ReturnEntryPoint, (VOID *)(UINTN)SmmS3ResumeState->ReturnContext1, (VOID *)(UINTN)SmmS3ResumeState->ReturnContext2, (VOID *)(UINTN)SmmS3ResumeState->ReturnStackPointer ); } // // If SMM is in 64-bit mode, then use AsmDisablePaging64() to resume PEI Phase // if (SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_64) { DEBUG ((EFI_D_INFO, "Call AsmDisablePaging64() to return to S3 Resume in PEI Phase\n")); // // Disable interrupt of Debug timer, since new IDT table is for IA32 and will not work in long mode. // SaveAndSetDebugTimerInterrupt (FALSE); // // Restore IA32 IDT table // AsmWriteIdtr ((IA32_DESCRIPTOR *) &Ia32Idtr); AsmDisablePaging64 ( SmmS3ResumeState->ReturnCs, (UINT32)SmmS3ResumeState->ReturnEntryPoint, (UINT32)SmmS3ResumeState->ReturnContext1, (UINT32)SmmS3ResumeState->ReturnContext2, (UINT32)SmmS3ResumeState->ReturnStackPointer ); } // // Can not resume PEI Phase // DEBUG ((EFI_D_ERROR, "No context to return to PEI Phase\n")); CpuDeadLoop (); }
/** Transfers control to DxeCore. This function performs a CPU architecture specific operations to execute the entry point of DxeCore with the parameters of HobList. It also installs EFI_END_OF_PEI_PPI to signal the end of PEI phase. @param DxeCoreEntryPoint The entry point of DxeCore. @param HobList The start of HobList passed to DxeCore. **/ VOID HandOffToDxeCore ( IN EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint, IN EFI_PEI_HOB_POINTERS HobList ) { EFI_STATUS Status; EFI_PHYSICAL_ADDRESS BaseOfStack; EFI_PHYSICAL_ADDRESS TopOfStack; UINTN PageTables; X64_IDT_GATE_DESCRIPTOR *IdtTable; UINTN SizeOfTemplate; VOID *TemplateBase; EFI_PHYSICAL_ADDRESS VectorAddress; UINT32 Index; X64_IDT_TABLE *IdtTableForX64; EFI_VECTOR_HANDOFF_INFO *VectorInfo; EFI_PEI_VECTOR_HANDOFF_INFO_PPI *VectorHandoffInfoPpi; BOOLEAN BuildPageTablesIa32Pae; if (IsNullDetectionEnabled ()) { ClearFirst4KPage (HobList.Raw); } Status = PeiServicesAllocatePages (EfiBootServicesData, EFI_SIZE_TO_PAGES (STACK_SIZE), &BaseOfStack); ASSERT_EFI_ERROR (Status); if (FeaturePcdGet(PcdDxeIplSwitchToLongMode)) { // // Compute the top of the stack we were allocated, which is used to load X64 dxe core. // Pre-allocate a 32 bytes which confroms to x64 calling convention. // // The first four parameters to a function are passed in rcx, rdx, r8 and r9. // Any further parameters are pushed on the stack. Furthermore, space (4 * 8bytes) for the // register parameters is reserved on the stack, in case the called function // wants to spill them; this is important if the function is variadic. // TopOfStack = BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - 32; // // x64 Calling Conventions requires that the stack must be aligned to 16 bytes // TopOfStack = (EFI_PHYSICAL_ADDRESS) (UINTN) ALIGN_POINTER (TopOfStack, 16); // // Load the GDT of Go64. Since the GDT of 32-bit Tiano locates in the BS_DATA // memory, it may be corrupted when copying FV to high-end memory // AsmWriteGdtr (&gGdt); // // Create page table and save PageMapLevel4 to CR3 // PageTables = CreateIdentityMappingPageTables (BaseOfStack, STACK_SIZE); // // End of PEI phase signal // PERF_EVENT_SIGNAL_BEGIN (gEndOfPeiSignalPpi.Guid); Status = PeiServicesInstallPpi (&gEndOfPeiSignalPpi); PERF_EVENT_SIGNAL_END (gEndOfPeiSignalPpi.Guid); ASSERT_EFI_ERROR (Status); // // Paging might be already enabled. To avoid conflict configuration, // disable paging first anyway. // AsmWriteCr0 (AsmReadCr0 () & (~BIT31)); AsmWriteCr3 (PageTables); // // Update the contents of BSP stack HOB to reflect the real stack info passed to DxeCore. // UpdateStackHob (BaseOfStack, STACK_SIZE); SizeOfTemplate = AsmGetVectorTemplatInfo (&TemplateBase); Status = PeiServicesAllocatePages ( EfiBootServicesData, EFI_SIZE_TO_PAGES(sizeof (X64_IDT_TABLE) + SizeOfTemplate * IDT_ENTRY_COUNT), &VectorAddress ); ASSERT_EFI_ERROR (Status); // // Store EFI_PEI_SERVICES** in the 4 bytes immediately preceding IDT to avoid that // it may not be gotten correctly after IDT register is re-written. // IdtTableForX64 = (X64_IDT_TABLE *) (UINTN) VectorAddress; IdtTableForX64->PeiService = GetPeiServicesTablePointer (); VectorAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) (IdtTableForX64 + 1); IdtTable = IdtTableForX64->IdtTable; for (Index = 0; Index < IDT_ENTRY_COUNT; Index++) { IdtTable[Index].Ia32IdtEntry.Bits.GateType = 0x8e; IdtTable[Index].Ia32IdtEntry.Bits.Reserved_0 = 0; IdtTable[Index].Ia32IdtEntry.Bits.Selector = SYS_CODE64_SEL; IdtTable[Index].Ia32IdtEntry.Bits.OffsetLow = (UINT16) VectorAddress; IdtTable[Index].Ia32IdtEntry.Bits.OffsetHigh = (UINT16) (RShiftU64 (VectorAddress, 16)); IdtTable[Index].Offset32To63 = (UINT32) (RShiftU64 (VectorAddress, 32)); IdtTable[Index].Reserved = 0; CopyMem ((VOID *) (UINTN) VectorAddress, TemplateBase, SizeOfTemplate); AsmVectorFixup ((VOID *) (UINTN) VectorAddress, (UINT8) Index); VectorAddress += SizeOfTemplate; } gLidtDescriptor.Base = (UINTN) IdtTable; // // Disable interrupt of Debug timer, since new IDT table cannot handle it. // SaveAndSetDebugTimerInterrupt (FALSE); AsmWriteIdtr (&gLidtDescriptor); DEBUG (( DEBUG_INFO, "%a() Stack Base: 0x%lx, Stack Size: 0x%x\n", __FUNCTION__, BaseOfStack, STACK_SIZE )); // // Go to Long Mode and transfer control to DxeCore. // Interrupts will not get turned on until the CPU AP is loaded. // Call x64 drivers passing in single argument, a pointer to the HOBs. // AsmEnablePaging64 ( SYS_CODE64_SEL, DxeCoreEntryPoint, (EFI_PHYSICAL_ADDRESS)(UINTN)(HobList.Raw), 0, TopOfStack ); } else { // // Get Vector Hand-off Info PPI and build Guided HOB // Status = PeiServicesLocatePpi ( &gEfiVectorHandoffInfoPpiGuid, 0, NULL, (VOID **)&VectorHandoffInfoPpi ); if (Status == EFI_SUCCESS) { DEBUG ((EFI_D_INFO, "Vector Hand-off Info PPI is gotten, GUIDed HOB is created!\n")); VectorInfo = VectorHandoffInfoPpi->Info; Index = 1; while (VectorInfo->Attribute != EFI_VECTOR_HANDOFF_LAST_ENTRY) { VectorInfo ++; Index ++; } BuildGuidDataHob ( &gEfiVectorHandoffInfoPpiGuid, VectorHandoffInfoPpi->Info, sizeof (EFI_VECTOR_HANDOFF_INFO) * Index ); } // // Compute the top of the stack we were allocated. Pre-allocate a UINTN // for safety. // TopOfStack = BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - CPU_STACK_ALIGNMENT; TopOfStack = (EFI_PHYSICAL_ADDRESS) (UINTN) ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT); PageTables = 0; BuildPageTablesIa32Pae = ToBuildPageTable (); if (BuildPageTablesIa32Pae) { PageTables = Create4GPageTablesIa32Pae (BaseOfStack, STACK_SIZE); if (IsEnableNonExecNeeded ()) { EnableExecuteDisableBit(); } } // // End of PEI phase signal // PERF_EVENT_SIGNAL_BEGIN (gEndOfPeiSignalPpi.Guid); Status = PeiServicesInstallPpi (&gEndOfPeiSignalPpi); PERF_EVENT_SIGNAL_END (gEndOfPeiSignalPpi.Guid); ASSERT_EFI_ERROR (Status); if (BuildPageTablesIa32Pae) { // // Paging might be already enabled. To avoid conflict configuration, // disable paging first anyway. // AsmWriteCr0 (AsmReadCr0 () & (~BIT31)); AsmWriteCr3 (PageTables); // // Set Physical Address Extension (bit 5 of CR4). // AsmWriteCr4 (AsmReadCr4 () | BIT5); } // // Update the contents of BSP stack HOB to reflect the real stack info passed to DxeCore. // UpdateStackHob (BaseOfStack, STACK_SIZE); DEBUG (( DEBUG_INFO, "%a() Stack Base: 0x%lx, Stack Size: 0x%x\n", __FUNCTION__, BaseOfStack, STACK_SIZE )); // // Transfer the control to the entry point of DxeCore. // if (BuildPageTablesIa32Pae) { AsmEnablePaging32 ( (SWITCH_STACK_ENTRY_POINT)(UINTN)DxeCoreEntryPoint, HobList.Raw, NULL, (VOID *) (UINTN) TopOfStack ); } else { SwitchStack ( (SWITCH_STACK_ENTRY_POINT)(UINTN)DxeCoreEntryPoint, HobList.Raw, NULL, (VOID *) (UINTN) TopOfStack ); } } }
/** Initialize debug agent. This function is used to set up debug enviroment for source level debug in SMM code. If InitFlag is DEBUG_AGENT_INIT_SMM, it will overirde IDT table entries and initialize debug port. It will get debug agent Mailbox from GUIDed HOB, it it exists, debug agent wiil copied it into the local Mailbox in SMM space. it will overirde IDT table entries and initialize debug port. Context will be NULL. If InitFlag is DEBUG_AGENT_INIT_ENTER_SMI, debug agent will save Debug Registers and get local Mailbox in SMM space. Context will be NULL. If InitFlag is DEBUG_AGENT_INIT_EXIT_SMI, debug agent will restore Debug Registers. Context will be NULL. @param[in] InitFlag Init flag is used to decide initialize process. @param[in] Context Context needed according to InitFlag. @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 ) { EFI_STATUS Status; UINT64 DebugPortHandle; IA32_IDT_GATE_DESCRIPTOR IdtEntry[33]; IA32_DESCRIPTOR IdtDescriptor; IA32_DESCRIPTOR *Ia32Idtr; IA32_IDT_ENTRY *Ia32IdtEntry; IA32_DESCRIPTOR Idtr; UINT16 IdtEntryCount; DEBUG_AGENT_MAILBOX *Mailbox; UINT64 *MailboxLocation; UINT32 DebugTimerFrequency; BOOLEAN PeriodicMode; UINTN TimerCycle; switch (InitFlag) { case DEBUG_AGENT_INIT_SMM: // // Install configuration table for persisted vector handoff info // Status = gSmst->SmmInstallConfigurationTable ( gSmst, &gEfiVectorHandoffTableGuid, (VOID *) &mVectorHandoffInfoDebugAgent[0], sizeof (EFI_VECTOR_HANDOFF_INFO) * mVectorHandoffInfoCount ); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "DebugAgent: Cannot install configuration table for persisted vector handoff info!\n")); CpuDeadLoop (); } // // Check if Debug Agent initialized in DXE phase // Status = EfiGetSystemConfigurationTable (&gEfiDebugAgentGuid, (VOID **) &Mailbox); if (Status == EFI_SUCCESS && Mailbox != NULL) { VerifyMailboxChecksum (Mailbox); mMailboxPointer = Mailbox; break; } // // Check if Debug Agent initialized in SEC/PEI phase // Mailbox = GetMailboxFromHob (); if (Mailbox != NULL) { mMailboxPointer = Mailbox; break; } // // Debug Agent was not initialized before, use the local mailbox. // ZeroMem (&mLocalMailbox, sizeof (DEBUG_AGENT_MAILBOX)); Mailbox = &mLocalMailbox; // // Save original IDT entries // AsmReadIdtr (&IdtDescriptor); CopyMem (&IdtEntry, (VOID *)IdtDescriptor.Base, 33 * sizeof(IA32_IDT_GATE_DESCRIPTOR)); // // Initialized Debug Agent // InitializeDebugIdt (); // // Initialize Debug Timer hardware and save its frequency // InitializeDebugTimer (&DebugTimerFrequency, TRUE); UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY, DebugTimerFrequency); DebugPortHandle = (UINT64) (UINTN)DebugPortInitialize ((DEBUG_PORT_HANDLE) (UINTN)Mailbox->DebugPortHandle, NULL); UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle); mMailboxPointer = Mailbox; // // Trigger one software interrupt to inform HOST // TriggerSoftInterrupt (SYSTEM_RESET_SIGNATURE); SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1); // // Memory has been ready // if (IsHostAttached ()) { // // Trigger one software interrupt to inform HOST // TriggerSoftInterrupt (MEMORY_READY_SIGNATURE); } // // Find and report PE/COFF image info to HOST // FindAndReportModuleImageInfo (SIZE_4KB); // // Restore saved IDT entries // CopyMem ((VOID *)IdtDescriptor.Base, &IdtEntry, 33 * sizeof(IA32_IDT_GATE_DESCRIPTOR)); break; case DEBUG_AGENT_INIT_ENTER_SMI: SaveDebugRegister (); if (!mSmmDebugIdtInitFlag) { // // We only need to initialize Debug IDT table at first SMI entry // after SMM relocation. // InitializeDebugIdt (); mSmmDebugIdtInitFlag = TRUE; } // // Check if CPU APIC Timer is working, otherwise initialize it. // InitializeLocalApicSoftwareEnable (TRUE); GetApicTimerState (NULL, &PeriodicMode, NULL); TimerCycle = GetApicTimerInitCount (); if (!PeriodicMode || TimerCycle == 0) { InitializeDebugTimer (NULL, FALSE); } Mailbox = GetMailboxPointer (); if (GetDebugFlag (DEBUG_AGENT_FLAG_AGENT_IN_PROGRESS) == 1) { // // If Debug Agent has been communicaton state with HOST, we need skip // any break points set in SMM, set Skip Breakpoint flag // mSkipBreakpoint = TRUE; } if (GetDebugFlag (DEBUG_AGENT_FLAG_BREAK_ON_NEXT_SMI) == 1) { if (mSkipBreakpoint) { // // Print warning message if ignore smm entry break // DebugPortWriteBuffer ((DEBUG_PORT_HANDLE) (UINTN)Mailbox->DebugPortHandle, (UINT8 *)mWarningMsgIgnoreSmmEntryBreak, AsciiStrLen (mWarningMsgIgnoreSmmEntryBreak) ); } else { // // If SMM entry break is set, SMM code will be break at here. // CpuBreakpoint (); } } break; case DEBUG_AGENT_INIT_EXIT_SMI: Mailbox = GetMailboxPointer (); // // Clear Skip Breakpoint flag // mSkipBreakpoint = FALSE; RestoreDebugRegister (); break; case DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64: if (Context == NULL) { DEBUG ((EFI_D_ERROR, "DebugAgent: Input parameter Context cannot be NULL!\n")); CpuDeadLoop (); } else { Ia32Idtr = (IA32_DESCRIPTOR *) Context; Ia32IdtEntry = (IA32_IDT_ENTRY *)(Ia32Idtr->Base); MailboxLocation = (UINT64 *) (UINTN) (Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetLow + (UINT32) (Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetHigh << 16)); mMailboxPointer = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation); VerifyMailboxChecksum (mMailboxPointer); // // Get original IDT address and size. // AsmReadIdtr ((IA32_DESCRIPTOR *) &Idtr); IdtEntryCount = (UINT16) ((Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR)); if (IdtEntryCount < 33) { Idtr.Limit = (UINT16) (sizeof (IA32_IDT_GATE_DESCRIPTOR) * 33 - 1); Idtr.Base = (UINTN) &mIdtEntryTable; ZeroMem (&mIdtEntryTable, Idtr.Limit + 1); AsmWriteIdtr ((IA32_DESCRIPTOR *) &Idtr); } InitializeDebugIdt (); // // Initialize Debug Timer hardware and save its frequency // InitializeDebugTimer (&DebugTimerFrequency, TRUE); UpdateMailboxContent (mMailboxPointer, DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY, DebugTimerFrequency); // // Enable Debug Timer interrupt and CPU interrupt // SaveAndSetDebugTimerInterrupt (TRUE); EnableInterrupts (); FindAndReportModuleImageInfo (SIZE_4KB); } break; default: // // Only DEBUG_AGENT_INIT_PREMEM_SEC and DEBUG_AGENT_INIT_POSTMEM_SEC are allowed for this // Debug Agent library instance. // DEBUG ((EFI_D_ERROR, "Debug Agent: The InitFlag value is not allowed!\n")); CpuDeadLoop (); break; } }
/** Initialize debug agent. This function is used to set up debug enviroment for DXE phase. If this function is called by DXE Core, Context must be the pointer to HOB list which will be used to get GUIDed HOB. It will enable interrupt to support break-in feature. If this function is called by DXE module, Context must be NULL. It will enable interrupt to support break-in feature. @param[in] InitFlag Init flag is used to decide initialize process. @param[in] Context Context needed according to InitFlag. @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; IA32_DESCRIPTOR Idtr; UINT16 IdtEntryCount; BOOLEAN InterruptStatus; if (InitFlag != DEBUG_AGENT_INIT_DXE_CORE && InitFlag != DEBUG_AGENT_INIT_S3 && InitFlag != DEBUG_AGENT_INIT_DXE_AP) { return; } // // Save and disable original interrupt status // InterruptStatus = SaveAndDisableInterrupts (); if (InitFlag == DEBUG_AGENT_INIT_DXE_CORE) { // // Try to get Mailbox from GUIDed HOB. // mDxeCoreFlag = TRUE; Mailbox = GetMailboxFromHob (Context); // // Clear Break CPU index value // mDebugMpContext.BreakAtCpuIndex = (UINT32) -1; } else if (InitFlag == DEBUG_AGENT_INIT_DXE_AP) { EnableInterrupts (); return; } else { // // If it is in S3 path, needn't to install configuration table. // Mailbox = NULL; } if (Mailbox != NULL) { // // If Mailbox exists, copy it into one global variable. // CopyMem (&mMailbox, Mailbox, sizeof (DEBUG_AGENT_MAILBOX)); } else { // // If Mailbox not exists, used the local Mailbox. // ZeroMem (&mMailbox, sizeof (DEBUG_AGENT_MAILBOX)); } mMailboxPointer = &mMailbox; // // Get original IDT address and size. // AsmReadIdtr ((IA32_DESCRIPTOR *) &Idtr); IdtEntryCount = (UINT16) ((Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR)); if (IdtEntryCount < 33) { Idtr.Limit = (UINT16) (sizeof (IA32_IDT_GATE_DESCRIPTOR) * 33 - 1); Idtr.Base = (UINTN) &mIdtEntryTable; ZeroMem (&mIdtEntryTable, Idtr.Limit + 1); AsmWriteIdtr ((IA32_DESCRIPTOR *) &Idtr); } // // Initialize the IDT table entries to support source level debug. // InitializeDebugIdt (); // // Initialize debug communication port // mMailboxPointer->DebugPortHandle = (UINT64) (UINTN)DebugPortInitialize ((VOID *)(UINTN)mMailbox.DebugPortHandle, NULL); InitializeSpinLock (&mDebugMpContext.MpContextSpinLock); InitializeSpinLock (&mDebugMpContext.DebugPortSpinLock); if (InitFlag == DEBUG_AGENT_INIT_DXE_CORE) { // // Initialize Debug Timer hardware and enable interrupt. // InitializeDebugTimer (); EnableInterrupts (); return; } else { // // Disable Debug Timer interrupt in S3 path. // SaveAndSetDebugTimerInterrupt (FALSE); // // Restore interrupt state. // SetInterruptState (InterruptStatus); } }