diff options
Diffstat (limited to 'SourceLevelDebugPkg/Library')
50 files changed, 13508 insertions, 13508 deletions
diff --git a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.c b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.c index b553a2a9aa..64319a4b31 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.c +++ b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.c @@ -1,2698 +1,2698 @@ -/** @file
- Common Debug Agent library implementation. It mainly includes
- the first C function called by exception/interrupt handlers,
- read/write debug packet to communication with HOST based on transfer
- protocol.
-
- Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DebugAgent.h"
-#include "Ia32/DebugException.h"
-
-GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 mErrorMsgVersionAlert[] = "\rThe SourceLevelDebugPkg you are using requires a newer version of the Intel(R) UDK Debugger Tool.\r\n";
-GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 mErrorMsgSendInitPacket[] = "\rSend INIT break packet and try to connect the HOST (Intel(R) UDK Debugger Tool v1.5) ...\r\n";
-GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 mErrorMsgConnectOK[] = "HOST connection is successful!\r\n";
-GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 mErrorMsgConnectFail[] = "HOST connection is failed!\r\n";
-GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 mWarningMsgIngoreBreakpoint[] = "Ignore break point in SMM for SMI issued during DXE debugging!\r\n";
-
-//
-// Vector Handoff Info list used by Debug Agent for persist
-//
-GLOBAL_REMOVE_IF_UNREFERENCED EFI_VECTOR_HANDOFF_INFO mVectorHandoffInfoDebugAgent[] = {
- {
- DEBUG_EXCEPT_DIVIDE_ERROR, // Vector 0
- EFI_VECTOR_HANDOFF_HOOK_BEFORE,
- EFI_DEBUG_AGENT_GUID
- },
- {
- DEBUG_EXCEPT_DEBUG, // Vector 1
- EFI_VECTOR_HANDOFF_DO_NOT_HOOK,
- EFI_DEBUG_AGENT_GUID
- },
- {
- DEBUG_EXCEPT_NMI, // Vector 2
- EFI_VECTOR_HANDOFF_HOOK_BEFORE,
- EFI_DEBUG_AGENT_GUID
- },
- {
- DEBUG_EXCEPT_BREAKPOINT, // Vector 3
- EFI_VECTOR_HANDOFF_DO_NOT_HOOK,
- EFI_DEBUG_AGENT_GUID
- },
- {
- DEBUG_EXCEPT_OVERFLOW, // Vector 4
- EFI_VECTOR_HANDOFF_HOOK_BEFORE,
- EFI_DEBUG_AGENT_GUID
- },
- {
- DEBUG_EXCEPT_BOUND, // Vector 5
- EFI_VECTOR_HANDOFF_HOOK_BEFORE,
- EFI_DEBUG_AGENT_GUID
- },
- {
- DEBUG_EXCEPT_INVALID_OPCODE, // Vector 6
- EFI_VECTOR_HANDOFF_HOOK_BEFORE,
- EFI_DEBUG_AGENT_GUID
- },
- {
- DEBUG_EXCEPT_DOUBLE_FAULT, // Vector 8
- EFI_VECTOR_HANDOFF_HOOK_BEFORE,
- EFI_DEBUG_AGENT_GUID
- },
- {
- DEBUG_EXCEPT_INVALID_TSS, // Vector 10
- EFI_VECTOR_HANDOFF_HOOK_BEFORE,
- EFI_DEBUG_AGENT_GUID
- },
- {
- DEBUG_EXCEPT_SEG_NOT_PRESENT, // Vector 11
- EFI_VECTOR_HANDOFF_HOOK_BEFORE,
- EFI_DEBUG_AGENT_GUID
- },
- {
- DEBUG_EXCEPT_STACK_FAULT, // Vector 12
- EFI_VECTOR_HANDOFF_HOOK_BEFORE,
- EFI_DEBUG_AGENT_GUID
- },
- {
- DEBUG_EXCEPT_GP_FAULT, // Vector 13
- EFI_VECTOR_HANDOFF_HOOK_BEFORE,
- EFI_DEBUG_AGENT_GUID
- },
- {
- DEBUG_EXCEPT_PAGE_FAULT, // Vector 14
- EFI_VECTOR_HANDOFF_HOOK_BEFORE,
- EFI_DEBUG_AGENT_GUID
- },
- {
- DEBUG_EXCEPT_FP_ERROR, // Vector 16
- EFI_VECTOR_HANDOFF_HOOK_BEFORE,
- EFI_DEBUG_AGENT_GUID
- },
- {
- DEBUG_EXCEPT_ALIGNMENT_CHECK, // Vector 17
- EFI_VECTOR_HANDOFF_HOOK_BEFORE,
- EFI_DEBUG_AGENT_GUID
- },
- {
- DEBUG_EXCEPT_MACHINE_CHECK, // Vector 18
- EFI_VECTOR_HANDOFF_HOOK_BEFORE,
- EFI_DEBUG_AGENT_GUID
- },
- {
- DEBUG_EXCEPT_SIMD, // Vector 19
- EFI_VECTOR_HANDOFF_HOOK_BEFORE,
- EFI_DEBUG_AGENT_GUID
- },
- {
- DEBUG_TIMER_VECTOR, // Vector 32
- EFI_VECTOR_HANDOFF_DO_NOT_HOOK,
- EFI_DEBUG_AGENT_GUID
- },
- {
- DEBUG_MAILBOX_VECTOR, // Vector 33
- EFI_VECTOR_HANDOFF_DO_NOT_HOOK,
- EFI_DEBUG_AGENT_GUID
- },
- {
- 0,
- EFI_VECTOR_HANDOFF_LAST_ENTRY,
- { 0 }
- }
-};
-
-GLOBAL_REMOVE_IF_UNREFERENCED UINTN mVectorHandoffInfoCount = sizeof (mVectorHandoffInfoDebugAgent) / sizeof (EFI_VECTOR_HANDOFF_INFO);
-
-/**
- Calculate CRC16 for target data.
-
- @param[in] Data The target data.
- @param[in] DataSize The target data size.
- @param[in] Crc Initial CRC.
-
- @return UINT16 The CRC16 value.
-
-**/
-UINT16
-CalculateCrc16 (
- IN UINT8 *Data,
- IN UINTN DataSize,
- IN UINT16 Crc
- )
-{
- UINTN Index;
- UINTN BitIndex;
-
- for (Index = 0; Index < DataSize; Index++) {
- Crc ^= (UINT16)Data[Index];
- for (BitIndex = 0; BitIndex < 8; BitIndex++) {
- if ((Crc & 0x8000) != 0) {
- Crc <<= 1;
- Crc ^= 0x1021;
- } else {
- Crc <<= 1;
- }
- }
- }
-
- return Crc;
-}
-
-/**
- Read IDT entry to check if IDT entries are setup by Debug Agent.
-
- @retval TRUE IDT entries were setup by Debug Agent.
- @retval FALSE IDT entries were not setup by Debug Agent.
-
-**/
-BOOLEAN
-IsDebugAgentInitialzed (
- VOID
- )
-{
- UINTN InterruptHandler;
-
- InterruptHandler = (UINTN)GetExceptionHandlerInIdtEntry (0);
- if ((InterruptHandler >= 4) && (*(UINT32 *)(InterruptHandler - 4) == AGENT_HANDLER_SIGNATURE)) {
- return TRUE;
- } else {
- return FALSE;
- }
-}
-
-/**
- Find and report module image info to HOST.
-
- @param[in] AlignSize Image aligned size.
-
-**/
-VOID
-FindAndReportModuleImageInfo (
- IN UINTN AlignSize
- )
-{
- UINTN Pe32Data;
- PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
-
- //
- // Find Image Base
- //
- Pe32Data = PeCoffSearchImageBase ((UINTN)mErrorMsgVersionAlert);
- if (Pe32Data != 0) {
- ImageContext.ImageAddress = Pe32Data;
- ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)ImageContext.ImageAddress);
- PeCoffLoaderRelocateImageExtraAction (&ImageContext);
- }
-}
-
-/**
- Trigger one software interrupt to debug agent to handle it.
-
- @param[in] Signature Software interrupt signature.
-
-**/
-VOID
-TriggerSoftInterrupt (
- IN 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);
-}
-
-/**
- Calculate Mailbox checksum and update the checksum field.
-
- @param[in] Mailbox Debug Agent Mailbox pointer.
-
-**/
-VOID
-UpdateMailboxChecksum (
- IN DEBUG_AGENT_MAILBOX *Mailbox
- )
-{
- Mailbox->CheckSum = CalculateCheckSum8 ((UINT8 *)Mailbox, sizeof (DEBUG_AGENT_MAILBOX) - 2);
-}
-
-/**
- Verify Mailbox checksum.
-
- If checksum error, print debug message and run init dead loop.
-
- @param[in] Mailbox Debug Agent Mailbox pointer.
-
-**/
-VOID
-VerifyMailboxChecksum (
- IN DEBUG_AGENT_MAILBOX *Mailbox
- )
-{
- UINT8 CheckSum;
-
- CheckSum = CalculateCheckSum8 ((UINT8 *)Mailbox, sizeof (DEBUG_AGENT_MAILBOX) - 2);
- //
- // The checksum updating process may be disturbed by hardware SMI, we need to check CheckSum field
- // and ToBeCheckSum field to validate the mail box.
- //
- if ((CheckSum != Mailbox->CheckSum) && (CheckSum != Mailbox->ToBeCheckSum)) {
- DEBUG ((DEBUG_ERROR, "DebugAgent: Mailbox checksum error, stack or heap crashed!\n"));
- DEBUG ((DEBUG_ERROR, "DebugAgent: CheckSum = %x, Mailbox->CheckSum = %x, Mailbox->ToBeCheckSum = %x\n", CheckSum, Mailbox->CheckSum, Mailbox->ToBeCheckSum));
- CpuDeadLoop ();
- }
-}
-
-/**
- Update Mailbox content by index.
-
- @param[in] Mailbox Debug Agent Mailbox pointer.
- @param[in] Index Mailbox content index.
- @param[in] Value Value to be set into Mailbox.
-
-**/
-VOID
-UpdateMailboxContent (
- IN DEBUG_AGENT_MAILBOX *Mailbox,
- IN UINTN Index,
- IN UINT64 Value
- )
-{
- AcquireMpSpinLock (&mDebugMpContext.MailboxSpinLock);
- switch (Index) {
- case DEBUG_MAILBOX_DEBUG_FLAG_INDEX:
- Mailbox->ToBeCheckSum = Mailbox->CheckSum + CalculateSum8 ((UINT8 *)&Mailbox->DebugFlag.Uint64, sizeof (UINT64))
- - CalculateSum8 ((UINT8 *)&Value, sizeof (UINT64));
- Mailbox->DebugFlag.Uint64 = Value;
- break;
- case DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX:
- Mailbox->ToBeCheckSum = Mailbox->CheckSum + CalculateSum8 ((UINT8 *)&Mailbox->DebugPortHandle, sizeof (UINTN))
- - CalculateSum8 ((UINT8 *)&Value, sizeof (UINTN));
- Mailbox->DebugPortHandle = (UINTN)Value;
- break;
- case DEBUG_MAILBOX_EXCEPTION_BUFFER_POINTER_INDEX:
- Mailbox->ToBeCheckSum = Mailbox->CheckSum + CalculateSum8 ((UINT8 *)&Mailbox->ExceptionBufferPointer, sizeof (UINTN))
- - CalculateSum8 ((UINT8 *)&Value, sizeof (UINTN));
- Mailbox->ExceptionBufferPointer = (UINTN)Value;
- break;
- case DEBUG_MAILBOX_LAST_ACK:
- Mailbox->ToBeCheckSum = Mailbox->CheckSum + CalculateSum8 ((UINT8 *)&Mailbox->LastAck, sizeof (UINT8))
- - CalculateSum8 ((UINT8 *)&Value, sizeof (UINT8));
- Mailbox->LastAck = (UINT8)Value;
- break;
- case DEBUG_MAILBOX_SEQUENCE_NO_INDEX:
- Mailbox->ToBeCheckSum = Mailbox->CheckSum + CalculateSum8 ((UINT8 *)&Mailbox->SequenceNo, sizeof (UINT8))
- - CalculateSum8 ((UINT8 *)&Value, sizeof (UINT8));
- Mailbox->SequenceNo = (UINT8)Value;
- break;
- case DEBUG_MAILBOX_HOST_SEQUENCE_NO_INDEX:
- Mailbox->ToBeCheckSum = Mailbox->CheckSum + CalculateSum8 ((UINT8 *)&Mailbox->HostSequenceNo, sizeof (UINT8))
- - CalculateSum8 ((UINT8 *)&Value, sizeof (UINT8));
- Mailbox->HostSequenceNo = (UINT8)Value;
- break;
- case DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY:
- Mailbox->ToBeCheckSum = Mailbox->CheckSum + CalculateSum8 ((UINT8 *)&Mailbox->DebugTimerFrequency, sizeof (UINT32))
- - CalculateSum8 ((UINT8 *)&Value, sizeof (UINT32));
- Mailbox->DebugTimerFrequency = (UINT32)Value;
- break;
- }
-
- UpdateMailboxChecksum (Mailbox);
- ReleaseMpSpinLock (&mDebugMpContext.MailboxSpinLock);
-}
-
-/**
- Read data from debug device and save the data in buffer.
-
- Reads NumberOfBytes data bytes from a debug device into the buffer
- specified by Buffer. The number of bytes actually read is returned.
- If the return value is less than NumberOfBytes, then the rest operation failed.
- If NumberOfBytes is zero, then return 0.
-
- @param Handle Debug port handle.
- @param Buffer Pointer to the data buffer to store the data read from the debug device.
- @param NumberOfBytes Number of bytes which will be read.
- @param Timeout Timeout value for reading from debug device. It unit is Microsecond.
-
- @retval 0 Read data failed, no data is to be read.
- @retval >0 Actual number of bytes read from debug device.
-
-**/
-UINTN
-DebugAgentReadBuffer (
- IN DEBUG_PORT_HANDLE Handle,
- IN UINT8 *Buffer,
- IN UINTN NumberOfBytes,
- IN UINTN Timeout
- )
-{
- UINTN Index;
- UINT32 Begin;
- UINT32 TimeoutTicker;
- UINT32 TimerRound;
- UINT32 TimerFrequency;
- UINT32 TimerCycle;
-
- Begin = 0;
- TimeoutTicker = 0;
- TimerRound = 0;
- TimerFrequency = GetMailboxPointer ()->DebugTimerFrequency;
- TimerCycle = GetApicTimerInitCount ();
-
- if (Timeout != 0) {
- Begin = GetApicTimerCurrentCount ();
- TimeoutTicker = (UINT32)DivU64x32 (
- MultU64x64 (
- TimerFrequency,
- Timeout
- ),
- 1000000u
- );
- TimerRound = (UINT32)DivU64x32Remainder (TimeoutTicker, TimerCycle / 2, &TimeoutTicker);
- }
-
- Index = 0;
- while (Index < NumberOfBytes) {
- if (DebugPortPollBuffer (Handle)) {
- DebugPortReadBuffer (Handle, Buffer + Index, 1, 0);
- Index++;
- continue;
- }
-
- if (Timeout != 0) {
- if (TimerRound == 0) {
- if (IsDebugTimerTimeout (TimerCycle, Begin, TimeoutTicker)) {
- //
- // If time out occurs.
- //
- return 0;
- }
- } else {
- if (IsDebugTimerTimeout (TimerCycle, Begin, TimerCycle / 2)) {
- TimerRound--;
- Begin = GetApicTimerCurrentCount ();
- }
- }
- }
- }
-
- return Index;
-}
-
-/**
- Set debug flag in mailbox.
-
- @param[in] FlagMask Debug flag mask value.
- @param[in] FlagValue Debug flag value.
-
-**/
-VOID
-SetDebugFlag (
- IN UINT64 FlagMask,
- IN UINT32 FlagValue
- )
-{
- DEBUG_AGENT_MAILBOX *Mailbox;
- UINT64 Data64;
-
- Mailbox = GetMailboxPointer ();
- Data64 = (Mailbox->DebugFlag.Uint64 & ~FlagMask) |
- (LShiftU64 ((UINT64)FlagValue, LowBitSet64 (FlagMask)) & FlagMask);
- UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_FLAG_INDEX, Data64);
-}
-
-/**
- Get debug flag in mailbox.
-
- @param[in] FlagMask Debug flag mask value.
-
- @return Debug flag value.
-
-**/
-UINT32
-GetDebugFlag (
- IN UINT64 FlagMask
- )
-{
- DEBUG_AGENT_MAILBOX *Mailbox;
- UINT32 DebugFlag;
-
- Mailbox = GetMailboxPointer ();
- DebugFlag = (UINT32)RShiftU64 (Mailbox->DebugFlag.Uint64 & FlagMask, LowBitSet64 (FlagMask));
-
- return DebugFlag;
-}
-
-/**
- Send a debug message packet to the debug port.
-
- @param[in] Buffer The debug message.
- @param[in] Length The length of debug message.
-
-**/
-VOID
-SendDebugMsgPacket (
- IN CHAR8 *Buffer,
- IN UINTN Length
- )
-{
- DEBUG_PACKET_HEADER DebugHeader;
- DEBUG_PORT_HANDLE Handle;
-
- Handle = GetDebugPortHandle ();
-
- DebugHeader.StartSymbol = DEBUG_STARTING_SYMBOL_NORMAL;
- DebugHeader.Command = DEBUG_COMMAND_PRINT_MESSAGE;
- DebugHeader.Length = sizeof (DEBUG_PACKET_HEADER) + (UINT8)Length;
- DebugHeader.SequenceNo = 0xEE;
- DebugHeader.Crc = 0;
- DebugHeader.Crc = CalculateCrc16 (
- (UINT8 *)Buffer,
- Length,
- CalculateCrc16 ((UINT8 *)&DebugHeader, sizeof (DEBUG_PACKET_HEADER), 0)
- );
-
- DebugPortWriteBuffer (Handle, (UINT8 *)&DebugHeader, sizeof (DEBUG_PACKET_HEADER));
- DebugPortWriteBuffer (Handle, (UINT8 *)Buffer, Length);
-}
-
-/**
- Prints a debug message to the debug port if the specified error level is enabled.
-
- If any bit in ErrorLevel is also set in Mainbox, then print the message specified
- by Format and the associated variable argument list to the debug port.
-
- @param[in] ErrorLevel The error level of the debug message.
- @param[in] Format Format string for the debug message to print.
- @param[in] ... Variable argument list whose contents are accessed
- based on the format string specified by Format.
-
-**/
-VOID
-EFIAPI
-DebugAgentMsgPrint (
- IN UINT8 ErrorLevel,
- IN CHAR8 *Format,
- ...
- )
-{
- CHAR8 Buffer[DEBUG_DATA_MAXIMUM_REAL_DATA];
- VA_LIST Marker;
-
- //
- // Check driver debug mask value and global mask
- //
- if ((ErrorLevel & GetDebugFlag (DEBUG_AGENT_FLAG_PRINT_ERROR_LEVEL)) == 0) {
- return;
- }
-
- //
- // Convert the DEBUG() message to an ASCII String
- //
- VA_START (Marker, Format);
- AsciiVSPrint (Buffer, sizeof (Buffer), Format, Marker);
- VA_END (Marker);
-
- SendDebugMsgPacket (Buffer, AsciiStrLen (Buffer));
-}
-
-/**
- Prints a debug message to the debug output device if the specified error level is enabled.
-
- If any bit in ErrorLevel is also set in DebugPrintErrorLevelLib function
- GetDebugPrintErrorLevel (), then print the message specified by Format and the
- associated variable argument list to the debug output device.
-
- If Format is NULL, then ASSERT().
-
- @param[in] ErrorLevel The error level of the debug message.
- @param[in] IsSend Flag of debug message to declare that the data is being sent or being received.
- @param[in] Data Variable argument list whose contents are accessed
- @param[in] Length based on the format string specified by Format.
-
-**/
-VOID
-EFIAPI
-DebugAgentDataMsgPrint (
- IN UINT8 ErrorLevel,
- IN BOOLEAN IsSend,
- IN UINT8 *Data,
- IN UINT8 Length
- )
-{
- CHAR8 Buffer[DEBUG_DATA_MAXIMUM_REAL_DATA];
- CHAR8 *DestBuffer;
- UINTN Index;
-
- //
- // Check driver debug mask value and global mask
- //
- if ((ErrorLevel & GetDebugFlag (DEBUG_AGENT_FLAG_PRINT_ERROR_LEVEL)) == 0) {
- return;
- }
-
- DestBuffer = Buffer;
- if (IsSend) {
- DestBuffer += AsciiSPrint (DestBuffer, DEBUG_DATA_MAXIMUM_REAL_DATA, "Sent data [ ");
- } else {
- DestBuffer += AsciiSPrint (DestBuffer, DEBUG_DATA_MAXIMUM_REAL_DATA, "Received data [ ");
- }
-
- Index = 0;
- while (TRUE) {
- if (DestBuffer - Buffer > DEBUG_DATA_MAXIMUM_REAL_DATA - 6) {
- //
- // If there was no enough space in buffer, send out the debug message,
- // reserving 6 bytes is for the last data and end characters "]\n".
- //
- SendDebugMsgPacket (Buffer, DestBuffer - Buffer);
- DestBuffer = Buffer;
- }
-
- DestBuffer += AsciiSPrint (DestBuffer, DEBUG_DATA_MAXIMUM_REAL_DATA - (DestBuffer - Buffer), "%02x ", Data[Index]);
- Index++;
- if (Index >= Length) {
- //
- // The last character of debug message has been formatted in buffer
- //
- DestBuffer += AsciiSPrint (DestBuffer, DEBUG_DATA_MAXIMUM_REAL_DATA - (DestBuffer - Buffer), "]\n");
- SendDebugMsgPacket (Buffer, DestBuffer - Buffer);
- break;
- }
- }
-}
-
-/**
- Read remaining debug packet except for the start symbol
-
- @param[in] Handle Pointer to Debug Port handle.
- @param[in, out] DebugHeader Debug header buffer including start symbol.
-
- @retval EFI_SUCCESS Read the symbol in BreakSymbol.
- @retval EFI_CRC_ERROR CRC check fail.
- @retval EFI_TIMEOUT Timeout occurs when reading debug packet.
- @retval EFI_DEVICE_ERROR Receive the old or response packet.
-
-**/
-EFI_STATUS
-ReadRemainingBreakPacket (
- IN DEBUG_PORT_HANDLE Handle,
- IN OUT DEBUG_PACKET_HEADER *DebugHeader
- )
-{
- UINT16 Crc;
- DEBUG_AGENT_MAILBOX *Mailbox;
-
- //
- // Has received start symbol, try to read the rest part
- //
- if (DebugAgentReadBuffer (Handle, (UINT8 *)DebugHeader + OFFSET_OF (DEBUG_PACKET_HEADER, Command), sizeof (DEBUG_PACKET_HEADER) - OFFSET_OF (DEBUG_PACKET_HEADER, Command), READ_PACKET_TIMEOUT) == 0) {
- //
- // Timeout occur, exit
- //
- DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "Timeout in Debug Timer interrupt\n");
- return EFI_TIMEOUT;
- }
-
- Crc = DebugHeader->Crc;
- DebugHeader->Crc = 0;
- if (CalculateCrc16 ((UINT8 *)DebugHeader, DebugHeader->Length, 0) != Crc) {
- DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "Debug Timer CRC (%x) against (%x)\n", Crc, CalculateCrc16 ((UINT8 *)&DebugHeader, DebugHeader->Length, 0));
- DebugAgentDataMsgPrint (DEBUG_AGENT_VERBOSE, FALSE, (UINT8 *)DebugHeader, DebugHeader->Length);
- return EFI_CRC_ERROR;
- }
-
- Mailbox = GetMailboxPointer ();
- if (IS_REQUEST (DebugHeader)) {
- if (DebugHeader->SequenceNo == (UINT8)(Mailbox->HostSequenceNo + 1)) {
- //
- // Only update HostSequenceNo for new command packet
- //
- UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_HOST_SEQUENCE_NO_INDEX, DebugHeader->SequenceNo);
- return EFI_SUCCESS;
- }
-
- if (DebugHeader->SequenceNo == Mailbox->HostSequenceNo) {
- return EFI_SUCCESS;
- }
- }
-
- return EFI_DEVICE_ERROR;
-}
-
-/**
- Check if HOST is attached based on Mailbox.
-
- @retval TRUE HOST is attached.
- @retval FALSE HOST is not attached.
-
-**/
-BOOLEAN
-IsHostAttached (
- VOID
- )
-{
- return (BOOLEAN)(GetDebugFlag (DEBUG_AGENT_FLAG_HOST_ATTACHED) == 1);
-}
-
-/**
- Set HOST connect flag in Mailbox.
-
- @param[in] Attached Attach status.
-
-**/
-VOID
-SetHostAttached (
- IN BOOLEAN Attached
- )
-{
- DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Attach status is %d\n", Attached);
- SetDebugFlag (DEBUG_AGENT_FLAG_HOST_ATTACHED, (UINT32)Attached);
-}
-
-/**
- Set debug setting of Debug Agent in Mailbox.
-
- @param DebugSetting Pointer to Debug Setting defined by transfer protocol.
-
- @retval RETURN_SUCCESS The setting is set successfully.
- @retval RETURN_UNSUPPORTED The Key value is not supported.
-
-**/
-RETURN_STATUS
-SetDebugSetting (
- IN DEBUG_DATA_SET_DEBUG_SETTING *DebugSetting
- )
-{
- RETURN_STATUS Status;
-
- Status = RETURN_SUCCESS;
- switch (DebugSetting->Key) {
- case DEBUG_AGENT_SETTING_SMM_ENTRY_BREAK:
- SetDebugFlag (DEBUG_AGENT_FLAG_BREAK_ON_NEXT_SMI, DebugSetting->Value);
- break;
- case DEBUG_AGENT_SETTING_PRINT_ERROR_LEVEL:
- SetDebugFlag (DEBUG_AGENT_FLAG_PRINT_ERROR_LEVEL, DebugSetting->Value);
- break;
- case DEBUG_AGENT_SETTING_BOOT_SCRIPT_ENTRY_BREAK:
- SetDebugFlag (DEBUG_AGENT_FLAG_BREAK_BOOT_SCRIPT, DebugSetting->Value);
- break;
- default:
- Status = RETURN_UNSUPPORTED;
- }
-
- return Status;
-}
-
-/**
- Execute GO command.
-
- @param[in] CpuContext Pointer to saved CPU context.
-
-**/
-VOID
-CommandGo (
- IN DEBUG_CPU_CONTEXT *CpuContext
- )
-{
- IA32_EFLAGS32 *Eflags;
-
- Eflags = (IA32_EFLAGS32 *)&CpuContext->Eflags;
- Eflags->Bits.TF = 0;
- Eflags->Bits.RF = 1;
-}
-
-/**
- Execute Stepping command.
-
- @param[in] CpuContext Pointer to saved CPU context.
-
-**/
-VOID
-CommandStepping (
- IN DEBUG_CPU_CONTEXT *CpuContext
- )
-{
- IA32_EFLAGS32 *Eflags;
-
- Eflags = (IA32_EFLAGS32 *)&CpuContext->Eflags;
- Eflags->Bits.TF = 1;
- Eflags->Bits.RF = 1;
- //
- // Save and clear EFLAGS.IF to avoid interrupt happen when executing Stepping
- //
- SetDebugFlag (DEBUG_AGENT_FLAG_INTERRUPT_FLAG, Eflags->Bits.IF);
- Eflags->Bits.IF = 0;
- //
- // Set Stepping Flag
- //
- SetDebugFlag (DEBUG_AGENT_FLAG_STEPPING, 1);
-}
-
-/**
- Do some cleanup after Stepping command done.
-
- @param[in] CpuContext Pointer to saved CPU context.
-
-**/
-VOID
-CommandSteppingCleanup (
- IN DEBUG_CPU_CONTEXT *CpuContext
- )
-{
- IA32_EFLAGS32 *Eflags;
-
- Eflags = (IA32_EFLAGS32 *)&CpuContext->Eflags;
- //
- // Restore EFLAGS.IF
- //
- Eflags->Bits.IF = GetDebugFlag (DEBUG_AGENT_FLAG_INTERRUPT_FLAG);
- //
- // Clear Stepping flag
- //
- SetDebugFlag (DEBUG_AGENT_FLAG_STEPPING, 0);
-}
-
-/**
- Set debug register for hardware breakpoint.
-
- @param[in] CpuContext Pointer to saved CPU context.
- @param[in] SetHwBreakpoint Hardware breakpoint to be set.
-
-**/
-VOID
-SetDebugRegister (
- IN DEBUG_CPU_CONTEXT *CpuContext,
- IN DEBUG_DATA_SET_HW_BREAKPOINT *SetHwBreakpoint
- )
-{
- UINT8 RegisterIndex;
- UINTN Dr7Value;
-
- RegisterIndex = SetHwBreakpoint->Type.Index;
-
- //
- // Set debug address
- //
- *((UINTN *)&CpuContext->Dr0 + RegisterIndex) = (UINTN)SetHwBreakpoint->Address;
-
- Dr7Value = CpuContext->Dr7;
-
- //
- // Enable Gx, Lx
- //
- Dr7Value |= (UINTN)(0x3 << (RegisterIndex * 2));
- //
- // Set RWx and Lenx
- //
- Dr7Value &= (UINTN)(~(0xf << (16 + RegisterIndex * 4)));
- Dr7Value |= (UINTN)((SetHwBreakpoint->Type.Length << 2) | SetHwBreakpoint->Type.Access) << (16 + RegisterIndex * 4);
- //
- // Enable GE, LE
- //
- Dr7Value |= 0x300;
-
- CpuContext->Dr7 = Dr7Value;
-}
-
-/**
- Clear debug register for hardware breakpoint.
-
- @param[in] CpuContext Pointer to saved CPU context.
- @param[in] ClearHwBreakpoint Hardware breakpoint to be cleared.
-
-**/
-VOID
-ClearDebugRegister (
- IN DEBUG_CPU_CONTEXT *CpuContext,
- IN DEBUG_DATA_CLEAR_HW_BREAKPOINT *ClearHwBreakpoint
- )
-{
- if ((ClearHwBreakpoint->IndexMask & BIT0) != 0) {
- CpuContext->Dr0 = 0;
- CpuContext->Dr7 &= (UINTN)(~(0x3 << 0));
- }
-
- if ((ClearHwBreakpoint->IndexMask & BIT1) != 0) {
- CpuContext->Dr1 = 0;
- CpuContext->Dr7 &= (UINTN)(~(0x3 << 2));
- }
-
- if ((ClearHwBreakpoint->IndexMask & BIT2) != 0) {
- CpuContext->Dr2 = 0;
- CpuContext->Dr7 &= (UINTN)(~(0x3 << 4));
- }
-
- if ((ClearHwBreakpoint->IndexMask & BIT3) != 0) {
- CpuContext->Dr3 = 0;
- CpuContext->Dr7 &= (UINTN)(~(0x3 << 6));
- }
-}
-
-/**
- Return the offset of FP / MMX / XMM registers in the FPU saved state by register index.
-
- @param[in] Index Register index.
- @param[out] Width Register width returned.
-
- @return Offset in the FPU Save State.
-
-**/
-UINT16
-ArchReadFxStatOffset (
- IN UINT8 Index,
- OUT UINT8 *Width
- )
-{
- if (Index < SOFT_DEBUGGER_REGISTER_ST0) {
- switch (Index) {
- case SOFT_DEBUGGER_REGISTER_FP_FCW:
- *Width = (UINT8)sizeof (UINT16);
- return OFFSET_OF (DEBUG_DATA_FX_SAVE_STATE, Fcw);
-
- case SOFT_DEBUGGER_REGISTER_FP_FSW:
- *Width = (UINT8)sizeof (UINT16);
- return OFFSET_OF (DEBUG_DATA_FX_SAVE_STATE, Fsw);
-
- case SOFT_DEBUGGER_REGISTER_FP_FTW:
- *Width = (UINT8)sizeof (UINT16);
- return OFFSET_OF (DEBUG_DATA_FX_SAVE_STATE, Ftw);
-
- case SOFT_DEBUGGER_REGISTER_FP_OPCODE:
- *Width = (UINT8)sizeof (UINT16);
- return OFFSET_OF (DEBUG_DATA_FX_SAVE_STATE, Opcode);
-
- case SOFT_DEBUGGER_REGISTER_FP_EIP:
- *Width = (UINT8)sizeof (UINT32);
- return OFFSET_OF (DEBUG_DATA_FX_SAVE_STATE, Eip);
-
- case SOFT_DEBUGGER_REGISTER_FP_CS:
- *Width = (UINT8)sizeof (UINT16);
- return OFFSET_OF (DEBUG_DATA_FX_SAVE_STATE, Cs);
-
- case SOFT_DEBUGGER_REGISTER_FP_DATAOFFSET:
- *Width = (UINT8)sizeof (UINT32);
- return OFFSET_OF (DEBUG_DATA_FX_SAVE_STATE, DataOffset);
-
- case SOFT_DEBUGGER_REGISTER_FP_DS:
- *Width = (UINT8)sizeof (UINT16);
- return OFFSET_OF (DEBUG_DATA_FX_SAVE_STATE, Ds);
-
- case SOFT_DEBUGGER_REGISTER_FP_MXCSR:
- *Width = (UINT8)sizeof (UINT32);
- return OFFSET_OF (DEBUG_DATA_FX_SAVE_STATE, Mxcsr);
-
- case SOFT_DEBUGGER_REGISTER_FP_MXCSR_MASK:
- *Width = (UINT8)sizeof (UINT32);
- return OFFSET_OF (DEBUG_DATA_FX_SAVE_STATE, Mxcsr_Mask);
- }
- }
-
- if (Index <= SOFT_DEBUGGER_REGISTER_ST7) {
- *Width = 10;
- } else if (Index <= SOFT_DEBUGGER_REGISTER_XMM15) {
- *Width = 16;
- } else {
- //
- // MMX register
- //
- *Width = 8;
- Index -= SOFT_DEBUGGER_REGISTER_MM0 - SOFT_DEBUGGER_REGISTER_ST0;
- }
-
- return OFFSET_OF (DEBUG_DATA_FX_SAVE_STATE, St0Mm0) + (Index - SOFT_DEBUGGER_REGISTER_ST0) * 16;
-}
-
-/**
- Return the pointer of the register value in the CPU saved context.
-
- @param[in] CpuContext Pointer to saved CPU context.
- @param[in] Index Register index value.
- @param[out] Width Data width to read.
-
- @return The pointer in the CPU saved context.
-
-**/
-UINT8 *
-ArchReadRegisterBuffer (
- IN DEBUG_CPU_CONTEXT *CpuContext,
- IN UINT8 Index,
- OUT UINT8 *Width
- )
-{
- UINT8 *Buffer;
-
- if (Index < SOFT_DEBUGGER_REGISTER_FP_BASE) {
- Buffer = (UINT8 *)CpuContext + OFFSET_OF (DEBUG_CPU_CONTEXT, Dr0) + Index * sizeof (UINTN);
- *Width = (UINT8)sizeof (UINTN);
- } else {
- //
- // FPU/MMX/XMM registers
- //
- Buffer = (UINT8 *)CpuContext + OFFSET_OF (DEBUG_CPU_CONTEXT, FxSaveState) + ArchReadFxStatOffset (Index, Width);
- }
-
- return Buffer;
-}
-
-/**
- Send the packet without data to HOST.
-
- @param[in] CommandType Type of Command.
- @param[in] SequenceNo Sequence number.
-
-**/
-VOID
-SendPacketWithoutData (
- IN UINT8 CommandType,
- IN UINT8 SequenceNo
- )
-{
- DEBUG_PACKET_HEADER DebugHeader;
- DEBUG_PORT_HANDLE Handle;
-
- Handle = GetDebugPortHandle ();
-
- DebugHeader.StartSymbol = DEBUG_STARTING_SYMBOL_NORMAL;
- DebugHeader.Command = CommandType;
- DebugHeader.Length = sizeof (DEBUG_PACKET_HEADER);
- DebugHeader.SequenceNo = SequenceNo;
- DebugHeader.Crc = 0;
- DebugHeader.Crc = CalculateCrc16 ((UINT8 *)&DebugHeader, sizeof (DEBUG_PACKET_HEADER), 0);
-
- DebugAgentDataMsgPrint (DEBUG_AGENT_VERBOSE, TRUE, (UINT8 *)&DebugHeader, DebugHeader.Length);
- DebugPortWriteBuffer (Handle, (UINT8 *)&DebugHeader, DebugHeader.Length);
-}
-
-/**
- Send acknowledge packet to HOST.
-
- @param[in] AckCommand Type of Acknowledge packet.
-
-**/
-VOID
-SendAckPacket (
- IN UINT8 AckCommand
- )
-{
- UINT8 SequenceNo;
- DEBUG_AGENT_MAILBOX *Mailbox;
-
- if (AckCommand != DEBUG_COMMAND_OK) {
- //
- // This is not ACK OK packet
- //
- DebugAgentMsgPrint (DEBUG_AGENT_ERROR, "Send ACK(%d)\n", AckCommand);
- }
-
- Mailbox = GetMailboxPointer ();
- SequenceNo = Mailbox->HostSequenceNo;
- DebugAgentMsgPrint (DEBUG_AGENT_INFO, "SendAckPacket: SequenceNo = %x\n", SequenceNo);
- SendPacketWithoutData (AckCommand, SequenceNo);
- UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_LAST_ACK, AckCommand);
-}
-
-/**
- Decompress the Data in place.
-
- @param[in, out] Data The compressed data buffer.
- The buffer is assumed large enough to hold the uncompressed data.
- @param[in] Length The length of the compressed data buffer.
-
- @return The length of the uncompressed data buffer.
-**/
-UINT8
-DecompressDataInPlace (
- IN OUT UINT8 *Data,
- IN UINTN Length
- )
-{
- UINTN Index;
- UINT16 LastChar;
- UINTN LastCharCount;
- UINT8 CurrentChar;
-
- LastChar = (UINT16)-1;
- LastCharCount = 0;
- for (Index = 0; Index < Length; Index++) {
- CurrentChar = Data[Index];
- if (LastCharCount == 2) {
- LastCharCount = 0;
- CopyMem (&Data[Index + CurrentChar], &Data[Index + 1], Length - Index - 1);
- SetMem (&Data[Index], CurrentChar, (UINT8)LastChar);
- LastChar = (UINT16)-1;
- Index += CurrentChar - 1;
- Length += CurrentChar - 1;
- } else {
- if (LastChar != CurrentChar) {
- LastCharCount = 0;
- }
-
- LastCharCount++;
- LastChar = CurrentChar;
- }
- }
-
- ASSERT (Length <= DEBUG_DATA_MAXIMUM_REAL_DATA);
-
- return (UINT8)Length;
-}
-
-/**
- Receive valid packet from HOST.
-
- @param[out] InputPacket Buffer to receive packet.
- @param[out] BreakReceived TRUE means break-in symbol received.
- FALSE means break-in symbol not received.
- @param[out] IncompatibilityFlag If IncompatibilityFlag is not NULL, return
- TRUE: Compatible packet received.
- FALSE: Incompatible packet received.
- @param[in] Timeout Time out value to wait for acknowledge from HOST.
- The unit is microsecond.
- @param[in] SkipStartSymbol TRUE: Skip time out when reading start symbol.
- FALSE: Does not Skip time out when reading start symbol.
-
- @retval RETURN_SUCCESS A valid package was received in InputPacket.
- @retval RETURN_TIMEOUT Timeout occurs.
-
-**/
-RETURN_STATUS
-ReceivePacket (
- OUT UINT8 *InputPacket,
- OUT BOOLEAN *BreakReceived,
- OUT BOOLEAN *IncompatibilityFlag OPTIONAL,
- IN UINTN Timeout,
- IN BOOLEAN SkipStartSymbol
- )
-{
- DEBUG_PACKET_HEADER *DebugHeader;
- UINTN Received;
- DEBUG_PORT_HANDLE Handle;
- UINT16 Crc;
- UINTN TimeoutForStartSymbol;
-
- Handle = GetDebugPortHandle ();
- if (SkipStartSymbol) {
- TimeoutForStartSymbol = 0;
- } else {
- TimeoutForStartSymbol = Timeout;
- }
-
- DebugHeader = (DEBUG_PACKET_HEADER *)InputPacket;
- while (TRUE) {
- //
- // Find the valid start symbol
- //
- Received = DebugAgentReadBuffer (Handle, &DebugHeader->StartSymbol, sizeof (DebugHeader->StartSymbol), TimeoutForStartSymbol);
- if (Received < sizeof (DebugHeader->StartSymbol)) {
- DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "DebugAgentReadBuffer(StartSymbol) timeout\n");
- return RETURN_TIMEOUT;
- }
-
- if ((DebugHeader->StartSymbol != DEBUG_STARTING_SYMBOL_NORMAL) && (DebugHeader->StartSymbol != DEBUG_STARTING_SYMBOL_COMPRESS)) {
- DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "Invalid start symbol received [%02x]\n", DebugHeader->StartSymbol);
- continue;
- }
-
- //
- // Read Package header till field Length
- //
- Received = DebugAgentReadBuffer (
- Handle,
- (UINT8 *)DebugHeader + OFFSET_OF (DEBUG_PACKET_HEADER, Command),
- OFFSET_OF (DEBUG_PACKET_HEADER, Length) + sizeof (DebugHeader->Length) - sizeof (DebugHeader->StartSymbol),
- Timeout
- );
- if (Received == 0) {
- DebugAgentMsgPrint (DEBUG_AGENT_ERROR, "DebugAgentReadBuffer(Command) timeout\n");
- return RETURN_TIMEOUT;
- }
-
- if (DebugHeader->Length < sizeof (DEBUG_PACKET_HEADER)) {
- if (IncompatibilityFlag != NULL) {
- //
- // This is one old version debug packet format, set Incompatibility flag
- //
- *IncompatibilityFlag = TRUE;
- } else {
- //
- // Skip the bad small packet
- //
- continue;
- }
- } else {
- //
- // Read the payload data include the CRC field
- //
- Received = DebugAgentReadBuffer (Handle, &DebugHeader->SequenceNo, (UINT8)(DebugHeader->Length - OFFSET_OF (DEBUG_PACKET_HEADER, SequenceNo)), Timeout);
- if (Received == 0) {
- DebugAgentMsgPrint (DEBUG_AGENT_ERROR, "DebugAgentReadBuffer(SequenceNo) timeout\n");
- return RETURN_TIMEOUT;
- }
-
- //
- // Calculate the CRC of Debug Packet
- //
- Crc = DebugHeader->Crc;
- DebugHeader->Crc = 0;
- if (Crc == CalculateCrc16 ((UINT8 *)DebugHeader, DebugHeader->Length, 0)) {
- break;
- }
-
- DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "CRC Error (received CRC is %x)\n", Crc);
- DebugAgentDataMsgPrint (DEBUG_AGENT_VERBOSE, FALSE, (UINT8 *)DebugHeader, DebugHeader->Length);
- }
- }
-
- DebugAgentDataMsgPrint (DEBUG_AGENT_VERBOSE, FALSE, (UINT8 *)DebugHeader, DebugHeader->Length);
-
- if (DebugHeader->StartSymbol == DEBUG_STARTING_SYMBOL_COMPRESS) {
- DebugHeader->StartSymbol = DEBUG_STARTING_SYMBOL_NORMAL;
- DebugHeader->Length = DecompressDataInPlace (
- (UINT8 *)(DebugHeader + 1),
- DebugHeader->Length - sizeof (DEBUG_PACKET_HEADER)
- ) + sizeof (DEBUG_PACKET_HEADER);
- }
-
- return RETURN_SUCCESS;
-}
-
-/**
- Receive acknowledge packet OK from HOST in specified time.
-
- @param[in] Command The command type issued by TARGET.
- @param[in] Timeout Time out value to wait for acknowledge from HOST.
- The unit is microsecond.
- @param[out] BreakReceived If BreakReceived is not NULL,
- TRUE is returned if break-in symbol received.
- FALSE is returned if break-in symbol not received.
- @param[out] IncompatibilityFlag If IncompatibilityFlag is not NULL, return
- TRUE: Compatible packet received.
- FALSE: Incompatible packet received.
-
- @retval RETURN_SUCCESS Succeed to receive acknowledge packet from HOST,
- the type of acknowledge packet saved in Ack.
- @retval RETURN_TIMEOUT Specified timeout value was up.
-
-**/
-RETURN_STATUS
-SendCommandAndWaitForAckOK (
- IN UINT8 Command,
- IN UINTN Timeout,
- OUT BOOLEAN *BreakReceived OPTIONAL,
- OUT BOOLEAN *IncompatibilityFlag OPTIONAL
- )
-{
- RETURN_STATUS Status;
- UINT8 InputPacketBuffer[DEBUG_DATA_UPPER_LIMIT];
- DEBUG_PACKET_HEADER *DebugHeader;
- UINT8 SequenceNo;
- UINT8 HostSequenceNo;
- UINT8 RetryCount;
-
- RetryCount = 3;
- DebugHeader = (DEBUG_PACKET_HEADER *)InputPacketBuffer;
- Status = RETURN_TIMEOUT;
- while (RetryCount > 0) {
- SequenceNo = GetMailboxPointer ()->SequenceNo;
- HostSequenceNo = GetMailboxPointer ()->HostSequenceNo;
- SendPacketWithoutData (Command, SequenceNo);
- Status = ReceivePacket ((UINT8 *)DebugHeader, BreakReceived, IncompatibilityFlag, Timeout, FALSE);
- if (Status == RETURN_TIMEOUT) {
- if (Command == DEBUG_COMMAND_INIT_BREAK) {
- RetryCount--;
- } else {
- DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "TARGET: Timeout when waiting for ACK packet.\n");
- }
-
- continue;
- }
-
- ASSERT_EFI_ERROR (Status);
- //
- // Status == RETURN_SUCCESS
- //
- if ((DebugHeader->Command == DEBUG_COMMAND_OK) && (DebugHeader->SequenceNo == SequenceNo)) {
- //
- // Received Ack OK
- //
- UpdateMailboxContent (GetMailboxPointer (), DEBUG_MAILBOX_SEQUENCE_NO_INDEX, ++SequenceNo);
- return Status;
- }
-
- if ((DebugHeader->Command == DEBUG_COMMAND_GO) && ((DebugHeader->SequenceNo == HostSequenceNo) || (Command == DEBUG_COMMAND_INIT_BREAK))) {
- //
- // Received Old GO
- //
- if (Command == DEBUG_COMMAND_INIT_BREAK) {
- DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "TARGET: Receive GO() in last boot\n");
- }
-
- SendPacketWithoutData (DEBUG_COMMAND_OK, DebugHeader->SequenceNo);
- }
- }
-
- ASSERT (Command == DEBUG_COMMAND_INIT_BREAK);
- return Status;
-}
-
-/**
- Get current break cause.
-
- @param[in] Vector Vector value of exception or interrupt.
- @param[in] CpuContext Pointer to save CPU context.
-
- @return The type of break cause defined by XXXX
-
-**/
-UINT8
-GetBreakCause (
- IN UINTN Vector,
- IN DEBUG_CPU_CONTEXT *CpuContext
- )
-{
- UINT8 Cause;
-
- Cause = DEBUG_DATA_BREAK_CAUSE_UNKNOWN;
-
- switch (Vector) {
- case DEBUG_INT1_VECTOR:
- case DEBUG_INT3_VECTOR:
-
- if (Vector == DEBUG_INT1_VECTOR) {
- //
- // INT 1
- //
- if ((CpuContext->Dr6 & BIT14) != 0) {
- Cause = DEBUG_DATA_BREAK_CAUSE_STEPPING;
- //
- // DR6.BIT14 Indicates (when set) that the debug exception was
- // triggered by the single step execution mode.
- // The single-step mode is the highest priority debug exception.
- // This is single step, no need to check DR0, to ensure single step
- // work in PeCoffExtraActionLib (right after triggering a breakpoint
- // to report image load/unload).
- //
- return Cause;
- } else {
- Cause = DEBUG_DATA_BREAK_CAUSE_HW_BREAKPOINT;
- }
- } else {
- //
- // INT 3
- //
- Cause = DEBUG_DATA_BREAK_CAUSE_SW_BREAKPOINT;
- }
-
- switch (CpuContext->Dr0) {
- case IMAGE_LOAD_SIGNATURE:
- case IMAGE_UNLOAD_SIGNATURE:
-
- if (CpuContext->Dr3 == IO_PORT_BREAKPOINT_ADDRESS) {
- Cause = (UINT8)((CpuContext->Dr0 == IMAGE_LOAD_SIGNATURE) ?
- DEBUG_DATA_BREAK_CAUSE_IMAGE_LOAD : DEBUG_DATA_BREAK_CAUSE_IMAGE_UNLOAD);
- }
-
- break;
-
- case SOFT_INTERRUPT_SIGNATURE:
-
- if (CpuContext->Dr1 == MEMORY_READY_SIGNATURE) {
- Cause = DEBUG_DATA_BREAK_CAUSE_MEMORY_READY;
- CpuContext->Dr0 = 0;
- } else if (CpuContext->Dr1 == SYSTEM_RESET_SIGNATURE) {
- Cause = DEBUG_DATA_BREAK_CAUSE_SYSTEM_RESET;
- CpuContext->Dr0 = 0;
- }
-
- break;
-
- default:
- break;
- }
-
- break;
-
- case DEBUG_TIMER_VECTOR:
- Cause = DEBUG_DATA_BREAK_CAUSE_USER_HALT;
- break;
-
- default:
- if (Vector < 20) {
- if (GetDebugFlag (DEBUG_AGENT_FLAG_STEPPING) == 1) {
- //
- // If stepping command is executing
- //
- Cause = DEBUG_DATA_BREAK_CAUSE_STEPPING;
- } else {
- Cause = DEBUG_DATA_BREAK_CAUSE_EXCEPTION;
- }
- }
-
- break;
- }
-
- return Cause;
-}
-
-/**
- Copy memory from source to destination with specified width.
-
- @param[out] Dest A pointer to the destination buffer of the memory copy.
- @param[in] Src A pointer to the source buffer of the memory copy.
- @param[in] Count The number of data with specified width to copy from source to destination.
- @param[in] Width Data width in byte.
-
-**/
-VOID
-CopyMemByWidth (
- OUT UINT8 *Dest,
- IN UINT8 *Src,
- IN UINT16 Count,
- IN UINT8 Width
- )
-{
- UINT8 *Destination;
- UINT8 *Source;
- INT8 Step;
-
- if (Src > Dest) {
- Destination = Dest;
- Source = Src;
- Step = Width;
- } else {
- //
- // Copy memory from tail to avoid memory overlap
- //
- Destination = Dest + (Count - 1) * Width;
- Source = Src + (Count - 1) * Width;
- Step = -Width;
- }
-
- while (Count-- != 0) {
- switch (Width) {
- case 1:
- *(UINT8 *)Destination = MmioRead8 ((UINTN)Source);
- break;
- case 2:
- *(UINT16 *)Destination = MmioRead16 ((UINTN)Source);
- break;
- case 4:
- *(UINT32 *)Destination = MmioRead32 ((UINTN)Source);
- break;
- case 8:
- *(UINT64 *)Destination = MmioRead64 ((UINTN)Source);
- break;
- default:
- ASSERT (FALSE);
- }
-
- Source += Step;
- Destination += Step;
- }
-}
-
-/**
- Compress the data buffer but do not modify the original buffer.
-
- The compressed data is directly send to the debug channel.
- Compressing in place doesn't work because the data may become larger
- during compressing phase. ("3 3 ..." --> "3 3 0 ...")
- The routine is expected to be called three times:
- 1. Compute the length of the compressed data buffer;
- 2. Compute the CRC of the compressed data buffer;
- 3. Compress the data and send to the debug channel.
-
- @param[in] Handle The debug channel handle to send the compressed data buffer.
- @param[in] Data The data buffer.
- @param[in] Length The length of the data buffer.
- @param[in] Send TRUE to send the compressed data buffer.
- @param[out] CompressedLength Return the length of the compressed data buffer.
- It may be larger than the Length in some cases.
- @param[out] CompressedCrc Return the CRC of the compressed data buffer.
-**/
-VOID
-CompressData (
- IN DEBUG_PORT_HANDLE Handle,
- IN UINT8 *Data,
- IN UINT8 Length,
- IN BOOLEAN Send,
- OUT UINTN *CompressedLength OPTIONAL,
- OUT UINT16 *CompressedCrc OPTIONAL
- )
-{
- UINTN Index;
- UINT8 LastChar;
- UINT8 LastCharCount;
- UINT8 CurrentChar;
- UINTN CompressedIndex;
-
- ASSERT (Length > 0);
- LastChar = Data[0] + 1; // Just ensure it's different from the first byte.
- LastCharCount = 0;
-
- for (Index = 0, CompressedIndex = 0; Index <= Length; Index++) {
- if (Index < Length) {
- CurrentChar = Data[Index];
- } else {
- CurrentChar = (UINT8)LastChar + 1; // just ensure it's different from LastChar
- }
-
- if (LastChar != CurrentChar) {
- if (LastCharCount == 1) {
- CompressedIndex++;
- if (CompressedCrc != NULL) {
- *CompressedCrc = CalculateCrc16 (&LastChar, 1, *CompressedCrc);
- }
-
- if (Send) {
- DebugPortWriteBuffer (Handle, &LastChar, 1);
- }
- } else if (LastCharCount >= 2) {
- CompressedIndex += 3;
- LastCharCount -= 2;
- if (CompressedCrc != NULL) {
- *CompressedCrc = CalculateCrc16 (&LastChar, 1, *CompressedCrc);
- *CompressedCrc = CalculateCrc16 (&LastChar, 1, *CompressedCrc);
- *CompressedCrc = CalculateCrc16 (&LastCharCount, 1, *CompressedCrc);
- }
-
- if (Send) {
- DebugPortWriteBuffer (Handle, &LastChar, 1);
- DebugPortWriteBuffer (Handle, &LastChar, 1);
- DebugPortWriteBuffer (Handle, &LastCharCount, 1);
- }
- }
-
- LastCharCount = 0;
- }
-
- LastCharCount++;
- LastChar = CurrentChar;
- }
-
- if (CompressedLength != NULL) {
- *CompressedLength = CompressedIndex;
- }
-}
-
-/**
- Read memory with specified width and send packet with response data to HOST.
-
- @param[in] Data Pointer to response data buffer.
- @param[in] Count The number of data with specified Width.
- @param[in] Width Data width in byte.
- @param[in] DebugHeader Pointer to a buffer for creating response packet and receiving ACK packet,
- to minimize the stack usage.
-
- @retval RETURN_SUCCESS Response data was sent successfully.
-
-**/
-RETURN_STATUS
-ReadMemoryAndSendResponsePacket (
- IN UINT8 *Data,
- IN UINT16 Count,
- IN UINT8 Width,
- IN DEBUG_PACKET_HEADER *DebugHeader
- )
-{
- RETURN_STATUS Status;
- BOOLEAN LastPacket;
- DEBUG_PORT_HANDLE Handle;
- UINT8 SequenceNo;
- UINTN RemainingDataSize;
- UINT8 CurrentDataSize;
- UINTN CompressedDataSize;
-
- Handle = GetDebugPortHandle ();
-
- RemainingDataSize = Count * Width;
- while (TRUE) {
- SequenceNo = GetMailboxPointer ()->HostSequenceNo;
- if (RemainingDataSize <= DEBUG_DATA_MAXIMUM_REAL_DATA) {
- //
- // If the remaining data is less one real packet size, this is the last data packet
- //
- CurrentDataSize = (UINT8)RemainingDataSize;
- LastPacket = TRUE;
- DebugHeader->Command = DEBUG_COMMAND_OK;
- } else {
- //
- // Data is too larger to be sent in one packet, calculate the actual data size could
- // be sent in one Maximum data packet
- //
- CurrentDataSize = (DEBUG_DATA_MAXIMUM_REAL_DATA / Width) * Width;
- LastPacket = FALSE;
- DebugHeader->Command = DEBUG_COMMAND_IN_PROGRESS;
- }
-
- //
- // Construct the rest Debug header
- //
- DebugHeader->StartSymbol = DEBUG_STARTING_SYMBOL_NORMAL;
- DebugHeader->Length = CurrentDataSize + sizeof (DEBUG_PACKET_HEADER);
- DebugHeader->SequenceNo = SequenceNo;
- DebugHeader->Crc = 0;
- CopyMemByWidth ((UINT8 *)(DebugHeader + 1), Data, CurrentDataSize / Width, Width);
-
- //
- // Compression/decompression support was added since revision 0.4.
- // Revision 0.3 shouldn't compress the packet.
- //
- if (PcdGet32 (PcdTransferProtocolRevision) >= DEBUG_AGENT_REVISION_04) {
- //
- // Get the compressed data size without modifying the packet.
- //
- CompressData (
- Handle,
- (UINT8 *)(DebugHeader + 1),
- CurrentDataSize,
- FALSE,
- &CompressedDataSize,
- NULL
- );
- } else {
- CompressedDataSize = CurrentDataSize;
- }
-
- if (CompressedDataSize < CurrentDataSize) {
- DebugHeader->Length = (UINT8)CompressedDataSize + sizeof (DEBUG_PACKET_HEADER);
- DebugHeader->StartSymbol = DEBUG_STARTING_SYMBOL_COMPRESS;
- //
- // Compute the CRC of the packet head without modifying the packet.
- //
- DebugHeader->Crc = CalculateCrc16 ((UINT8 *)DebugHeader, sizeof (DEBUG_PACKET_HEADER), 0);
- CompressData (
- Handle,
- (UINT8 *)(DebugHeader + 1),
- CurrentDataSize,
- FALSE,
- NULL,
- &DebugHeader->Crc
- );
- //
- // Send out the packet head.
- //
- DebugPortWriteBuffer (Handle, (UINT8 *)DebugHeader, sizeof (DEBUG_PACKET_HEADER));
- //
- // Compress and send out the packet data.
- //
- CompressData (
- Handle,
- (UINT8 *)(DebugHeader + 1),
- CurrentDataSize,
- TRUE,
- NULL,
- NULL
- );
- } else {
- //
- // Calculate and fill the checksum, DebugHeader->Crc should be 0 before invoking CalculateCrc16 ()
- //
- DebugHeader->Crc = CalculateCrc16 ((UINT8 *)DebugHeader, DebugHeader->Length, 0);
-
- DebugAgentDataMsgPrint (DEBUG_AGENT_VERBOSE, TRUE, (UINT8 *)DebugHeader, DebugHeader->Length);
-
- DebugPortWriteBuffer (Handle, (UINT8 *)DebugHeader, DebugHeader->Length);
- }
-
- while (TRUE) {
- Status = ReceivePacket ((UINT8 *)DebugHeader, NULL, NULL, READ_PACKET_TIMEOUT, FALSE);
- if (Status == RETURN_TIMEOUT) {
- DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "TARGET: Timeout in SendDataResponsePacket()\n");
- break;
- }
-
- if ((DebugHeader->Command == DEBUG_COMMAND_OK) && (DebugHeader->SequenceNo == SequenceNo) && LastPacket) {
- //
- // If this is the last packet, return RETURN_SUCCESS.
- //
- return RETURN_SUCCESS;
- }
-
- if ((DebugHeader->Command == DEBUG_COMMAND_CONTINUE) && (DebugHeader->SequenceNo == (UINT8)(SequenceNo + 1))) {
- //
- // Calculate the rest data size
- //
- Data += CurrentDataSize;
- RemainingDataSize -= CurrentDataSize;
- UpdateMailboxContent (GetMailboxPointer (), DEBUG_MAILBOX_HOST_SEQUENCE_NO_INDEX, DebugHeader->SequenceNo);
- break;
- }
-
- if (DebugHeader->SequenceNo >= SequenceNo) {
- DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "TARGET: Received one old or new command(SequenceNo is %x, last SequenceNo is %x)\n", SequenceNo, DebugHeader->SequenceNo);
- break;
- }
- }
- }
-}
-
-/**
- Send packet with response data to HOST.
-
- @param[in] Data Pointer to response data buffer.
- @param[in] DataSize Size of response data in byte.
- @param[in, out] DebugHeader Pointer to a buffer for creating response packet and receiving ACK packet,
- to minimize the stack usage.
-
- @retval RETURN_SUCCESS Response data was sent successfully.
-
-**/
-RETURN_STATUS
-SendDataResponsePacket (
- IN UINT8 *Data,
- IN UINT16 DataSize,
- IN OUT DEBUG_PACKET_HEADER *DebugHeader
- )
-{
- return ReadMemoryAndSendResponsePacket (Data, DataSize, 1, DebugHeader);
-}
-
-/**
- Try to attach the HOST.
-
- Send init break packet to HOST:
- If no acknowledge received in specified Timeout, return RETURN_TIMEOUT.
- If received acknowledge, check the revision of HOST.
- Set Attach Flag if attach successfully.
-
- @param[in] BreakCause Break cause of this break event.
- @param[in] Timeout Time out value to wait for acknowledge from HOST.
- The unit is microsecond.
- @param[out] BreakReceived If BreakReceived is not NULL,
- TRUE is returned if break-in symbol received.
- FALSE is returned if break-in symbol not received.
-**/
-RETURN_STATUS
-AttachHost (
- IN UINT8 BreakCause,
- IN UINTN Timeout,
- OUT BOOLEAN *BreakReceived
- )
-{
- RETURN_STATUS Status;
- DEBUG_PORT_HANDLE Handle;
- BOOLEAN IncompatibilityFlag;
-
- IncompatibilityFlag = FALSE;
- Handle = GetDebugPortHandle ();
-
- //
- // Send init break and wait ack in Timeout
- //
- DebugPortWriteBuffer (Handle, (UINT8 *)mErrorMsgSendInitPacket, AsciiStrLen (mErrorMsgSendInitPacket));
- if (BreakCause == DEBUG_DATA_BREAK_CAUSE_SYSTEM_RESET) {
- Status = SendCommandAndWaitForAckOK (DEBUG_COMMAND_INIT_BREAK, Timeout, BreakReceived, &IncompatibilityFlag);
- } else {
- Status = SendCommandAndWaitForAckOK (DEBUG_COMMAND_ATTACH_BREAK, Timeout, BreakReceived, &IncompatibilityFlag);
- }
-
- if (IncompatibilityFlag) {
- //
- // If the incompatible Debug Packet received, the HOST should be running transfer protocol before PcdTransferProtocolRevision.
- // It could be UDK Debugger for Windows v1.1/v1.2 or for Linux v0.8/v1.2.
- //
- DebugPortWriteBuffer (Handle, (UINT8 *)mErrorMsgVersionAlert, AsciiStrLen (mErrorMsgVersionAlert));
- CpuDeadLoop ();
- }
-
- if (RETURN_ERROR (Status)) {
- DebugPortWriteBuffer (Handle, (UINT8 *)mErrorMsgConnectFail, AsciiStrLen (mErrorMsgConnectFail));
- } else {
- DebugPortWriteBuffer (Handle, (UINT8 *)mErrorMsgConnectOK, AsciiStrLen (mErrorMsgConnectOK));
- //
- // Set Attach flag
- //
- SetHostAttached (TRUE);
- }
-
- return Status;
-}
-
-/**
- Send Break point packet to HOST.
-
- Only the first breaking processor could sent BREAK_POINT packet.
-
- @param[in] BreakCause Break cause of this break event.
- @param[in] ProcessorIndex Processor index value.
- @param[out] BreakReceived If BreakReceived is not NULL,
- TRUE is returned if break-in symbol received.
- FALSE is returned if break-in symbol not received.
-
-**/
-VOID
-SendBreakPacketToHost (
- IN UINT8 BreakCause,
- IN UINT32 ProcessorIndex,
- OUT BOOLEAN *BreakReceived
- )
-{
- UINT8 InputCharacter;
- DEBUG_PORT_HANDLE Handle;
-
- Handle = GetDebugPortHandle ();
-
- if (IsHostAttached ()) {
- DebugAgentMsgPrint (DEBUG_AGENT_INFO, "processor[%x]:Send Break Packet to HOST.\n", ProcessorIndex);
- SendCommandAndWaitForAckOK (DEBUG_COMMAND_BREAK_POINT, READ_PACKET_TIMEOUT, BreakReceived, NULL);
- } else {
- DebugAgentMsgPrint (DEBUG_AGENT_INFO, "processor[%x]:Try to attach HOST.\n", ProcessorIndex);
- //
- // If HOST is not attached, try to attach it firstly.
- //
- //
- // Poll Attach symbols from HOST and ack OK
- //
- do {
- DebugAgentReadBuffer (Handle, &InputCharacter, 1, 0);
- } while (InputCharacter != DEBUG_STARTING_SYMBOL_ATTACH);
-
- SendAckPacket (DEBUG_COMMAND_OK);
-
- //
- // Try to attach HOST
- //
- while (AttachHost (BreakCause, 0, NULL) != RETURN_SUCCESS) {
- }
- }
-}
-
-/**
- The main function to process communication with HOST.
-
- It received the command packet from HOST, and sent response data packet to HOST.
-
- @param[in] Vector Vector value of exception or interrupt.
- @param[in, out] CpuContext Pointer to saved CPU context.
- @param[in] BreakReceived TRUE means break-in symbol received.
- FALSE means break-in symbol not received.
-
-**/
-VOID
-CommandCommunication (
- IN UINTN Vector,
- IN OUT DEBUG_CPU_CONTEXT *CpuContext,
- IN BOOLEAN BreakReceived
- )
-{
- RETURN_STATUS Status;
- UINT8 InputPacketBuffer[DEBUG_DATA_UPPER_LIMIT + sizeof (UINT64) - 1];
- DEBUG_PACKET_HEADER *DebugHeader;
- UINT8 Width;
- UINT8 Data8;
- UINT32 Data32;
- UINT64 Data64;
- DEBUG_DATA_READ_MEMORY *MemoryRead;
- DEBUG_DATA_WRITE_MEMORY *MemoryWrite;
- DEBUG_DATA_READ_IO *IoRead;
- DEBUG_DATA_WRITE_IO *IoWrite;
- DEBUG_DATA_READ_REGISTER *RegisterRead;
- DEBUG_DATA_WRITE_REGISTER *RegisterWrite;
- UINT8 *RegisterBuffer;
- DEBUG_DATA_READ_MSR *MsrRegisterRead;
- DEBUG_DATA_WRITE_MSR *MsrRegisterWrite;
- DEBUG_DATA_CPUID *Cpuid;
- DEBUG_DATA_RESPONSE_BREAK_CAUSE BreakCause;
- DEBUG_DATA_RESPONSE_CPUID CpuidResponse;
- DEBUG_DATA_SEARCH_SIGNATURE *SearchSignature;
- DEBUG_DATA_RESPONSE_GET_EXCEPTION Exception;
- DEBUG_DATA_RESPONSE_GET_REVISION DebugAgentRevision;
- DEBUG_DATA_SET_VIEWPOINT *SetViewPoint;
- BOOLEAN HaltDeferred;
- UINT32 ProcessorIndex;
- DEBUG_AGENT_EXCEPTION_BUFFER AgentExceptionBuffer;
- UINT32 IssuedViewPoint;
- DEBUG_AGENT_MAILBOX *Mailbox;
- UINT8 *AlignedDataPtr;
-
- ProcessorIndex = 0;
- IssuedViewPoint = 0;
- HaltDeferred = BreakReceived;
-
- if (MultiProcessorDebugSupport ()) {
- ProcessorIndex = GetProcessorIndex ();
- SetCpuStopFlagByIndex (ProcessorIndex, TRUE);
- if (mDebugMpContext.ViewPointIndex == ProcessorIndex) {
- //
- // Only the current view processor could set AgentInProgress Flag.
- //
- IssuedViewPoint = ProcessorIndex;
- }
- }
-
- if (IssuedViewPoint == ProcessorIndex) {
- //
- // Set AgentInProgress Flag.
- //
- SetDebugFlag (DEBUG_AGENT_FLAG_AGENT_IN_PROGRESS, 1);
- }
-
- while (TRUE) {
- if (MultiProcessorDebugSupport ()) {
- //
- // Check if the current processor is HOST view point
- //
- if (mDebugMpContext.ViewPointIndex != ProcessorIndex) {
- if (mDebugMpContext.RunCommandSet) {
- //
- // If HOST view point sets RUN flag, run GO command to leave
- //
- SetCpuStopFlagByIndex (ProcessorIndex, FALSE);
- CommandGo (CpuContext);
- break;
- } else {
- //
- // Run into loop again
- //
- CpuPause ();
- continue;
- }
- }
- }
-
- AcquireMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
-
- DebugHeader = (DEBUG_PACKET_HEADER *)InputPacketBuffer;
-
- DebugAgentMsgPrint (DEBUG_AGENT_INFO, "TARGET: Try to get command from HOST...\n");
- Status = ReceivePacket ((UINT8 *)DebugHeader, &BreakReceived, NULL, READ_PACKET_TIMEOUT, TRUE);
- if ((Status != RETURN_SUCCESS) || !IS_REQUEST (DebugHeader)) {
- DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "TARGET: Get command[%x] sequenceno[%x] returned status is [%x] \n", DebugHeader->Command, DebugHeader->SequenceNo, Status);
- DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "TARGET: Get command failed or it's response packet not expected! \n");
- ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
- continue;
- }
-
- Mailbox = GetMailboxPointer ();
- if (DebugHeader->SequenceNo == Mailbox->HostSequenceNo) {
- DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "TARGET: Receive one old command[%x] against command[%x]\n", DebugHeader->SequenceNo, Mailbox->HostSequenceNo);
- SendAckPacket (Mailbox->LastAck);
- ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
- continue;
- } else if (DebugHeader->SequenceNo == (UINT8)(Mailbox->HostSequenceNo + 1)) {
- UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_HOST_SEQUENCE_NO_INDEX, (UINT8)DebugHeader->SequenceNo);
- } else {
- DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "Receive one invalid command[%x] against command[%x]\n", DebugHeader->SequenceNo, Mailbox->HostSequenceNo);
- ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
- continue;
- }
-
- //
- // Save CPU content before executing HOST command
- //
- UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_EXCEPTION_BUFFER_POINTER_INDEX, (UINT64)(UINTN)&AgentExceptionBuffer.JumpBuffer);
- if (SetJump (&AgentExceptionBuffer.JumpBuffer) != 0) {
- //
- // If HOST command failed, continue to wait for HOST's next command
- // If needed, agent could send exception info to HOST.
- //
- SendAckPacket (DEBUG_COMMAND_ABORT);
- ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
- continue;
- }
-
- DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Processor[%x]:Received one command(%x)\n", mDebugMpContext.ViewPointIndex, DebugHeader->Command);
-
- switch (DebugHeader->Command) {
- case DEBUG_COMMAND_HALT:
- SendAckPacket (DEBUG_COMMAND_HALT_DEFERRED);
- HaltDeferred = TRUE;
- BreakReceived = FALSE;
- Status = RETURN_SUCCESS;
- break;
-
- case DEBUG_COMMAND_RESET:
- SendAckPacket (DEBUG_COMMAND_OK);
- SendAckPacket (DEBUG_COMMAND_OK);
- SendAckPacket (DEBUG_COMMAND_OK);
- ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
-
- ResetCold ();
- //
- // Assume system resets in 2 seconds, otherwise send TIMEOUT packet.
- // PCD can be used if 2 seconds isn't long enough for some platforms.
- //
- MicroSecondDelay (2000000);
- UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_HOST_SEQUENCE_NO_INDEX, Mailbox->HostSequenceNo + 1);
- SendAckPacket (DEBUG_COMMAND_TIMEOUT);
- SendAckPacket (DEBUG_COMMAND_TIMEOUT);
- SendAckPacket (DEBUG_COMMAND_TIMEOUT);
- break;
-
- case DEBUG_COMMAND_GO:
- CommandGo (CpuContext);
- //
- // Clear Dr0 to avoid to be recognized as IMAGE_LOAD/_UNLOAD again when hitting a breakpoint after GO
- // If HOST changed Dr0 before GO, we will not change Dr0 here
- //
- Data8 = GetBreakCause (Vector, CpuContext);
- if ((Data8 == DEBUG_DATA_BREAK_CAUSE_IMAGE_LOAD) || (Data8 == DEBUG_DATA_BREAK_CAUSE_IMAGE_UNLOAD)) {
- CpuContext->Dr0 = 0;
- }
-
- if (!HaltDeferred) {
- //
- // If no HALT command received when being in-active mode
- //
- if (MultiProcessorDebugSupport ()) {
- Data32 = FindNextPendingBreakCpu ();
- if (Data32 != -1) {
- //
- // If there are still others processors being in break state,
- // send OK packet to HOST to finish this go command
- //
- SendAckPacket (DEBUG_COMMAND_OK);
- CpuPause ();
- //
- // Set current view to the next breaking processor
- //
- mDebugMpContext.ViewPointIndex = Data32;
- mDebugMpContext.BreakAtCpuIndex = mDebugMpContext.ViewPointIndex;
- SetCpuBreakFlagByIndex (mDebugMpContext.ViewPointIndex, FALSE);
- //
- // Send break packet to HOST to let HOST break again
- //
- SendBreakPacketToHost (DEBUG_DATA_BREAK_CAUSE_UNKNOWN, mDebugMpContext.BreakAtCpuIndex, &BreakReceived);
- //
- // Continue to run into loop to read command packet from HOST
- //
- ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
- break;
- }
-
- //
- // If no else processor break, set stop bitmask,
- // and set Running flag for all processors.
- //
- SetCpuStopFlagByIndex (ProcessorIndex, FALSE);
- SetCpuRunningFlag (TRUE);
- CpuPause ();
- //
- // Wait for all processors are in running state
- //
- while (TRUE) {
- if (IsAllCpuRunning ()) {
- break;
- }
- }
-
- //
- // Set BSP to be current view point.
- //
- SetDebugViewPoint (mDebugMpContext.BspIndex);
- CpuPause ();
- //
- // Clear breaking processor index and running flag
- //
- mDebugMpContext.BreakAtCpuIndex = (UINT32)(-1);
- SetCpuRunningFlag (FALSE);
- }
-
- //
- // Send OK packet to HOST to finish this go command
- //
- SendAckPacket (DEBUG_COMMAND_OK);
-
- ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
-
- if (!IsHostAttached ()) {
- UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_SEQUENCE_NO_INDEX, 0);
- UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_HOST_SEQUENCE_NO_INDEX, 0);
- }
-
- return;
- } else {
- //
- // If received HALT command, need to defer the GO command
- //
- SendAckPacket (DEBUG_COMMAND_HALT_PROCESSED);
- HaltDeferred = FALSE;
-
- Vector = DEBUG_TIMER_VECTOR;
- }
-
- break;
-
- case DEBUG_COMMAND_BREAK_CAUSE:
- BreakCause.StopAddress = CpuContext->Eip;
- if (MultiProcessorDebugSupport () && (ProcessorIndex != mDebugMpContext.BreakAtCpuIndex)) {
- BreakCause.Cause = GetBreakCause (DEBUG_TIMER_VECTOR, CpuContext);
- } else {
- BreakCause.Cause = GetBreakCause (Vector, CpuContext);
- }
-
- SendDataResponsePacket ((UINT8 *)&BreakCause, (UINT16)sizeof (DEBUG_DATA_RESPONSE_BREAK_CAUSE), DebugHeader);
- break;
-
- case DEBUG_COMMAND_SET_HW_BREAKPOINT:
- SetDebugRegister (CpuContext, (DEBUG_DATA_SET_HW_BREAKPOINT *)(DebugHeader + 1));
- SendAckPacket (DEBUG_COMMAND_OK);
- break;
-
- case DEBUG_COMMAND_CLEAR_HW_BREAKPOINT:
- ClearDebugRegister (CpuContext, (DEBUG_DATA_CLEAR_HW_BREAKPOINT *)(DebugHeader + 1));
- SendAckPacket (DEBUG_COMMAND_OK);
- break;
-
- case DEBUG_COMMAND_SINGLE_STEPPING:
- CommandStepping (CpuContext);
- //
- // Clear Dr0 to avoid to be recognized as IMAGE_LOAD/_UNLOAD again when hitting a breakpoint after GO
- // If HOST changed Dr0 before GO, we will not change Dr0 here
- //
- Data8 = GetBreakCause (Vector, CpuContext);
- if ((Data8 == DEBUG_DATA_BREAK_CAUSE_IMAGE_LOAD) || (Data8 == DEBUG_DATA_BREAK_CAUSE_IMAGE_UNLOAD)) {
- CpuContext->Dr0 = 0;
- }
-
- mDebugMpContext.BreakAtCpuIndex = (UINT32)(-1);
- ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
- //
- // Executing stepping command directly without sending ACK packet,
- // ACK packet will be sent after stepping done.
- //
- return;
-
- case DEBUG_COMMAND_SET_SW_BREAKPOINT:
- Data64 = (UINTN)(((DEBUG_DATA_SET_SW_BREAKPOINT *)(DebugHeader + 1))->Address);
- Data8 = *(UINT8 *)(UINTN)Data64;
- *(UINT8 *)(UINTN)Data64 = DEBUG_SW_BREAKPOINT_SYMBOL;
- Status = SendDataResponsePacket ((UINT8 *)&Data8, (UINT16)sizeof (UINT8), DebugHeader);
- break;
-
- case DEBUG_COMMAND_READ_MEMORY:
- MemoryRead = (DEBUG_DATA_READ_MEMORY *)(DebugHeader + 1);
- Status = ReadMemoryAndSendResponsePacket ((UINT8 *)(UINTN)MemoryRead->Address, MemoryRead->Count, MemoryRead->Width, DebugHeader);
- break;
-
- case DEBUG_COMMAND_WRITE_MEMORY:
- MemoryWrite = (DEBUG_DATA_WRITE_MEMORY *)(DebugHeader + 1);
- //
- // Copy data into one memory with 8-byte alignment address
- //
- AlignedDataPtr = ALIGN_POINTER ((UINT8 *)&MemoryWrite->Data, sizeof (UINT64));
- if (AlignedDataPtr != (UINT8 *)&MemoryWrite->Data) {
- CopyMem (AlignedDataPtr, (UINT8 *)&MemoryWrite->Data, MemoryWrite->Count * MemoryWrite->Width);
- }
-
- CopyMemByWidth ((UINT8 *)(UINTN)MemoryWrite->Address, AlignedDataPtr, MemoryWrite->Count, MemoryWrite->Width);
- SendAckPacket (DEBUG_COMMAND_OK);
- break;
-
- case DEBUG_COMMAND_READ_IO:
- IoRead = (DEBUG_DATA_READ_IO *)(DebugHeader + 1);
- switch (IoRead->Width) {
- case 1:
- Data64 = IoRead8 ((UINTN)IoRead->Port);
- break;
- case 2:
- Data64 = IoRead16 ((UINTN)IoRead->Port);
- break;
- case 4:
- Data64 = IoRead32 ((UINTN)IoRead->Port);
- break;
- case 8:
- Data64 = IoRead64 ((UINTN)IoRead->Port);
- break;
- default:
- Data64 = (UINT64)-1;
- }
-
- Status = SendDataResponsePacket ((UINT8 *)&Data64, IoRead->Width, DebugHeader);
- break;
-
- case DEBUG_COMMAND_WRITE_IO:
- IoWrite = (DEBUG_DATA_WRITE_IO *)(DebugHeader + 1);
- switch (IoWrite->Width) {
- case 1:
- Data64 = IoWrite8 ((UINTN)IoWrite->Port, *(UINT8 *)&IoWrite->Data);
- break;
- case 2:
- Data64 = IoWrite16 ((UINTN)IoWrite->Port, *(UINT16 *)&IoWrite->Data);
- break;
- case 4:
- Data64 = IoWrite32 ((UINTN)IoWrite->Port, *(UINT32 *)&IoWrite->Data);
- break;
- case 8:
- Data64 = IoWrite64 ((UINTN)IoWrite->Port, *(UINT64 *)&IoWrite->Data);
- break;
- default:
- Data64 = (UINT64)-1;
- }
-
- SendAckPacket (DEBUG_COMMAND_OK);
- break;
-
- case DEBUG_COMMAND_READ_ALL_REGISTERS:
- Status = SendDataResponsePacket ((UINT8 *)CpuContext, sizeof (*CpuContext), DebugHeader);
- break;
-
- case DEBUG_COMMAND_READ_REGISTER:
- RegisterRead = (DEBUG_DATA_READ_REGISTER *)(DebugHeader + 1);
-
- if (RegisterRead->Index <= SOFT_DEBUGGER_REGISTER_MAX) {
- RegisterBuffer = ArchReadRegisterBuffer (CpuContext, RegisterRead->Index, &Width);
- Status = SendDataResponsePacket (RegisterBuffer, Width, DebugHeader);
- } else {
- Status = RETURN_UNSUPPORTED;
- }
-
- break;
-
- case DEBUG_COMMAND_WRITE_REGISTER:
- RegisterWrite = (DEBUG_DATA_WRITE_REGISTER *)(DebugHeader + 1);
- if (RegisterWrite->Index <= SOFT_DEBUGGER_REGISTER_MAX) {
- RegisterBuffer = ArchReadRegisterBuffer (CpuContext, RegisterWrite->Index, &Width);
- ASSERT (Width == RegisterWrite->Length);
- CopyMem (RegisterBuffer, RegisterWrite->Data, Width);
- SendAckPacket (DEBUG_COMMAND_OK);
- } else {
- Status = RETURN_UNSUPPORTED;
- }
-
- break;
-
- case DEBUG_COMMAND_ARCH_MODE:
- Data8 = DEBUG_ARCH_SYMBOL;
- Status = SendDataResponsePacket ((UINT8 *)&Data8, (UINT16)sizeof (UINT8), DebugHeader);
- break;
-
- case DEBUG_COMMAND_READ_MSR:
- MsrRegisterRead = (DEBUG_DATA_READ_MSR *)(DebugHeader + 1);
- Data64 = AsmReadMsr64 (MsrRegisterRead->Index);
- Status = SendDataResponsePacket ((UINT8 *)&Data64, (UINT16)sizeof (UINT64), DebugHeader);
- break;
-
- case DEBUG_COMMAND_WRITE_MSR:
- MsrRegisterWrite = (DEBUG_DATA_WRITE_MSR *)(DebugHeader + 1);
- AsmWriteMsr64 (MsrRegisterWrite->Index, MsrRegisterWrite->Value);
- SendAckPacket (DEBUG_COMMAND_OK);
- break;
-
- case DEBUG_COMMAND_SET_DEBUG_SETTING:
- Status = SetDebugSetting ((DEBUG_DATA_SET_DEBUG_SETTING *)(DebugHeader + 1));
- if (Status == RETURN_SUCCESS) {
- SendAckPacket (DEBUG_COMMAND_OK);
- }
-
- break;
-
- case DEBUG_COMMAND_GET_REVISION:
- DebugAgentRevision.Revision = PcdGet32 (PcdTransferProtocolRevision);
- DebugAgentRevision.Capabilities = DEBUG_AGENT_CAPABILITIES;
- Status = SendDataResponsePacket ((UINT8 *)&DebugAgentRevision, (UINT16)sizeof (DEBUG_DATA_RESPONSE_GET_REVISION), DebugHeader);
- break;
-
- case DEBUG_COMMAND_GET_EXCEPTION:
- Exception.ExceptionNum = (UINT8)Vector;
- Exception.ExceptionData = (UINT32)CpuContext->ExceptionData;
- Status = SendDataResponsePacket ((UINT8 *)&Exception, (UINT16)sizeof (DEBUG_DATA_RESPONSE_GET_EXCEPTION), DebugHeader);
- break;
-
- case DEBUG_COMMAND_SET_VIEWPOINT:
- SetViewPoint = (DEBUG_DATA_SET_VIEWPOINT *)(DebugHeader + 1);
- if (MultiProcessorDebugSupport ()) {
- if (IsCpuStopped (SetViewPoint->ViewPoint)) {
- SetDebugViewPoint (SetViewPoint->ViewPoint);
- SendAckPacket (DEBUG_COMMAND_OK);
- } else {
- //
- // If CPU is not halted
- //
- SendAckPacket (DEBUG_COMMAND_NOT_SUPPORTED);
- }
- } else if (SetViewPoint->ViewPoint == 0) {
- SendAckPacket (DEBUG_COMMAND_OK);
- } else {
- SendAckPacket (DEBUG_COMMAND_NOT_SUPPORTED);
- }
-
- break;
-
- case DEBUG_COMMAND_GET_VIEWPOINT:
- Data32 = mDebugMpContext.ViewPointIndex;
- SendDataResponsePacket ((UINT8 *)&Data32, (UINT16)sizeof (UINT32), DebugHeader);
- break;
-
- case DEBUG_COMMAND_MEMORY_READY:
- Data8 = (UINT8)GetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY);
- SendDataResponsePacket (&Data8, (UINT16)sizeof (UINT8), DebugHeader);
- break;
-
- case DEBUG_COMMAND_DETACH:
- SetHostAttached (FALSE);
- SendAckPacket (DEBUG_COMMAND_OK);
- break;
-
- case DEBUG_COMMAND_CPUID:
- Cpuid = (DEBUG_DATA_CPUID *)(DebugHeader + 1);
- AsmCpuidEx (
- Cpuid->Eax,
- Cpuid->Ecx,
- &CpuidResponse.Eax,
- &CpuidResponse.Ebx,
- &CpuidResponse.Ecx,
- &CpuidResponse.Edx
- );
- SendDataResponsePacket ((UINT8 *)&CpuidResponse, (UINT16)sizeof (CpuidResponse), DebugHeader);
- break;
-
- case DEBUG_COMMAND_SEARCH_SIGNATURE:
- SearchSignature = (DEBUG_DATA_SEARCH_SIGNATURE *)(DebugHeader + 1);
- if ((SearchSignature->Alignment != 0) &&
- (SearchSignature->Alignment == GetPowerOfTwo32 (SearchSignature->Alignment))
- )
- {
- if (SearchSignature->Positive) {
- for (
- Data64 = ALIGN_VALUE ((UINTN)SearchSignature->Start, SearchSignature->Alignment);
- Data64 <= SearchSignature->Start + SearchSignature->Count - SearchSignature->DataLength;
- Data64 += SearchSignature->Alignment
- )
- {
- if (CompareMem ((VOID *)(UINTN)Data64, &SearchSignature->Data, SearchSignature->DataLength) == 0) {
- break;
- }
- }
-
- if (Data64 > SearchSignature->Start + SearchSignature->Count - SearchSignature->DataLength) {
- Data64 = (UINT64)-1;
- }
- } else {
- for (
- Data64 = ALIGN_VALUE ((UINTN)SearchSignature->Start - SearchSignature->Alignment, SearchSignature->Alignment);
- Data64 >= SearchSignature->Start - SearchSignature->Count;
- Data64 -= SearchSignature->Alignment
- )
- {
- if (CompareMem ((VOID *)(UINTN)Data64, &SearchSignature->Data, SearchSignature->DataLength) == 0) {
- break;
- }
- }
-
- if (Data64 < SearchSignature->Start - SearchSignature->Count) {
- Data64 = (UINT64)-1;
- }
- }
-
- SendDataResponsePacket ((UINT8 *)&Data64, (UINT16)sizeof (Data64), DebugHeader);
- } else {
- Status = RETURN_UNSUPPORTED;
- }
-
- break;
-
- default:
- SendAckPacket (DEBUG_COMMAND_NOT_SUPPORTED);
- break;
- }
-
- if (Status == RETURN_UNSUPPORTED) {
- SendAckPacket (DEBUG_COMMAND_NOT_SUPPORTED);
- } else if (Status != RETURN_SUCCESS) {
- SendAckPacket (DEBUG_COMMAND_ABORT);
- }
-
- ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
- CpuPause ();
- }
-}
-
-/**
- C function called in interrupt handler.
-
- @param[in] Vector Vector value of exception or interrupt.
- @param[in] CpuContext Pointer to save CPU context.
-
-**/
-VOID
-EFIAPI
-InterruptProcess (
- IN UINT32 Vector,
- IN DEBUG_CPU_CONTEXT *CpuContext
- )
-{
- UINT8 InputCharacter;
- UINT8 BreakCause;
- UINTN SavedEip;
- BOOLEAN BreakReceived;
- UINT32 ProcessorIndex;
- UINT32 CurrentDebugTimerInitCount;
- DEBUG_PORT_HANDLE Handle;
- UINT8 Data8;
- UINT8 *Al;
- UINT32 IssuedViewPoint;
- DEBUG_AGENT_EXCEPTION_BUFFER *ExceptionBuffer;
-
- InputCharacter = 0;
- ProcessorIndex = 0;
- IssuedViewPoint = 0;
- BreakReceived = FALSE;
-
- if (mSkipBreakpoint) {
- //
- // If Skip Breakpoint flag is set, means communication is disturbed by hardware SMI, we need to ignore the break points in SMM
- //
- if ((Vector == DEBUG_INT1_VECTOR) || (Vector == DEBUG_INT3_VECTOR)) {
- DebugPortWriteBuffer (GetDebugPortHandle (), (UINT8 *)mWarningMsgIngoreBreakpoint, AsciiStrLen (mWarningMsgIngoreBreakpoint));
- return;
- }
- }
-
- if (MultiProcessorDebugSupport ()) {
- ProcessorIndex = GetProcessorIndex ();
- //
- // If this processor has already halted before, need to check it later
- //
- if (IsCpuStopped (ProcessorIndex)) {
- IssuedViewPoint = ProcessorIndex;
- }
- }
-
- if ((IssuedViewPoint == ProcessorIndex) && (GetDebugFlag (DEBUG_AGENT_FLAG_STEPPING) != 1)) {
- //
- // Check if this exception is issued by Debug Agent itself
- // If yes, fill the debug agent exception buffer and LongJump() back to
- // the saved CPU content in CommandCommunication()
- // If exception is issued when executing Stepping, will be handled in
- // exception handle procedure.
- //
- if (GetDebugFlag (DEBUG_AGENT_FLAG_AGENT_IN_PROGRESS) == 1) {
- DebugAgentMsgPrint (
- DEBUG_AGENT_ERROR,
- "Debug agent meet one Exception, ExceptionNum is %d, EIP = 0x%x.\n",
- Vector,
- (UINTN)CpuContext->Eip
- );
- ExceptionBuffer = (DEBUG_AGENT_EXCEPTION_BUFFER *)(UINTN)GetMailboxPointer ()->ExceptionBufferPointer;
- ExceptionBuffer->ExceptionContent.ExceptionNum = (UINT8)Vector;
- ExceptionBuffer->ExceptionContent.ExceptionData = (UINT32)CpuContext->ExceptionData;
- LongJump ((BASE_LIBRARY_JUMP_BUFFER *)(UINTN)(ExceptionBuffer), 1);
- }
- }
-
- if (MultiProcessorDebugSupport ()) {
- //
- // If RUN command is executing, wait for it done.
- //
- while (mDebugMpContext.RunCommandSet) {
- CpuPause ();
- }
- }
-
- Handle = GetDebugPortHandle ();
- BreakCause = GetBreakCause (Vector, CpuContext);
- switch (Vector) {
- case DEBUG_INT1_VECTOR:
- case DEBUG_INT3_VECTOR:
- switch (BreakCause) {
- case DEBUG_DATA_BREAK_CAUSE_SYSTEM_RESET:
- if (AttachHost (BreakCause, READ_PACKET_TIMEOUT, &BreakReceived) != RETURN_SUCCESS) {
- //
- // Try to connect HOST, return if fails
- //
- break;
- }
-
- CommandCommunication (Vector, CpuContext, BreakReceived);
- break;
-
- case DEBUG_DATA_BREAK_CAUSE_STEPPING:
- //
- // Stepping is finished, send Ack package.
- //
- if (MultiProcessorDebugSupport ()) {
- mDebugMpContext.BreakAtCpuIndex = ProcessorIndex;
- }
-
- //
- // Clear Stepping Flag and restore EFLAGS.IF
- //
- CommandSteppingCleanup (CpuContext);
- SendAckPacket (DEBUG_COMMAND_OK);
- CommandCommunication (Vector, CpuContext, BreakReceived);
- break;
-
- case DEBUG_DATA_BREAK_CAUSE_MEMORY_READY:
- //
- // Memory is ready
- //
- SendCommandAndWaitForAckOK (DEBUG_COMMAND_MEMORY_READY, READ_PACKET_TIMEOUT, &BreakReceived, NULL);
- CommandCommunication (Vector, CpuContext, BreakReceived);
- break;
-
- case DEBUG_DATA_BREAK_CAUSE_IMAGE_LOAD:
- case DEBUG_DATA_BREAK_CAUSE_IMAGE_UNLOAD:
- //
- // Set AL to DEBUG_AGENT_IMAGE_CONTINUE
- //
- Al = ArchReadRegisterBuffer (CpuContext, SOFT_DEBUGGER_REGISTER_AX, &Data8);
- *Al = DEBUG_AGENT_IMAGE_CONTINUE;
-
- if (!IsHostAttached ()) {
- //
- // If HOST is not connected for image load/unload, return
- //
- break;
- }
-
- //
- // Continue to run the following common code
- //
-
- case DEBUG_DATA_BREAK_CAUSE_HW_BREAKPOINT:
- case DEBUG_DATA_BREAK_CAUSE_SW_BREAKPOINT:
- default:
- //
- // Send Break packet to HOST
- //
- AcquireMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
- //
- // Only the first breaking processor could send BREAK_POINT to HOST
- //
- if (IsFirstBreakProcessor (ProcessorIndex)) {
- SendBreakPacketToHost (BreakCause, ProcessorIndex, &BreakReceived);
- }
-
- ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
-
- if (Vector == DEBUG_INT3_VECTOR) {
- //
- // go back address located "0xCC"
- //
- CpuContext->Eip--;
- SavedEip = CpuContext->Eip;
- CommandCommunication (Vector, CpuContext, BreakReceived);
- if ((SavedEip == CpuContext->Eip) &&
- (*(UINT8 *)(UINTN)CpuContext->Eip == DEBUG_SW_BREAKPOINT_SYMBOL))
- {
- //
- // If this is not a software breakpoint set by HOST,
- // restore EIP
- //
- CpuContext->Eip++;
- }
- } else {
- CommandCommunication (Vector, CpuContext, BreakReceived);
- }
-
- break;
- }
-
- break;
-
- case DEBUG_TIMER_VECTOR:
-
- AcquireMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
-
- if (MultiProcessorDebugSupport ()) {
- if (DebugAgentIsBsp (ProcessorIndex)) {
- //
- // If current processor is BSP, check Apic timer's init count if changed,
- // it may be re-written when switching BSP.
- // If it changed, re-initialize debug timer
- //
- CurrentDebugTimerInitCount = GetApicTimerInitCount ();
- if (mDebugMpContext.DebugTimerInitCount != CurrentDebugTimerInitCount) {
- InitializeDebugTimer (NULL, FALSE);
- SaveAndSetDebugTimerInterrupt (TRUE);
- }
- }
-
- if (!DebugAgentIsBsp (ProcessorIndex) || mDebugMpContext.IpiSentByAp) {
- ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
- //
- // If current processor is not BSP or this is one IPI sent by AP
- //
- if (mDebugMpContext.BreakAtCpuIndex != (UINT32)(-1)) {
- CommandCommunication (Vector, CpuContext, FALSE);
- }
-
- //
- // Clear EOI before exiting interrupt process routine.
- //
- SendApicEoi ();
- break;
- }
- }
-
- //
- // Only BSP could run here
- //
- while (TRUE) {
- //
- // If there is data in debug port, will check whether it is break(attach/break-in) symbol,
- // If yes, go into communication mode with HOST.
- // If no, exit interrupt process.
- //
- if (DebugReadBreakSymbol (Handle, &InputCharacter) == EFI_NOT_FOUND) {
- break;
- }
-
- if ((!IsHostAttached () && (InputCharacter == DEBUG_STARTING_SYMBOL_ATTACH)) ||
- (IsHostAttached () && (InputCharacter == DEBUG_COMMAND_HALT)) ||
- (IsHostAttached () && (InputCharacter == DEBUG_COMMAND_GO))
- )
- {
- DebugAgentMsgPrint (DEBUG_AGENT_VERBOSE, "Received data [%02x]\n", InputCharacter);
- //
- // Ack OK for break-in symbol
- //
- SendAckPacket (DEBUG_COMMAND_OK);
-
- //
- // If receive GO command in Debug Timer, means HOST may lost ACK packet before.
- //
- if (InputCharacter == DEBUG_COMMAND_GO) {
- break;
- }
-
- if (!IsHostAttached ()) {
- //
- // Try to attach HOST, if no ack received after 200ms, return
- //
- if (AttachHost (BreakCause, READ_PACKET_TIMEOUT, &BreakReceived) != RETURN_SUCCESS) {
- break;
- }
- }
-
- if (MultiProcessorDebugSupport ()) {
- if (FindNextPendingBreakCpu () != -1) {
- SetCpuBreakFlagByIndex (ProcessorIndex, TRUE);
- } else {
- HaltOtherProcessors (ProcessorIndex);
- }
- }
-
- ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
- CommandCommunication (Vector, CpuContext, BreakReceived);
- AcquireMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
- break;
- }
- }
-
- //
- // Clear EOI before exiting interrupt process routine.
- //
- SendApicEoi ();
-
- ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
-
- break;
-
- default:
- if (Vector <= DEBUG_EXCEPT_SIMD) {
- DebugAgentMsgPrint (
- DEBUG_AGENT_ERROR,
- "Exception happened, ExceptionNum is %d, EIP = 0x%x.\n",
- Vector,
- (UINTN)CpuContext->Eip
- );
- if (BreakCause == DEBUG_DATA_BREAK_CAUSE_STEPPING) {
- //
- // If exception happened when executing Stepping, send Ack package.
- // HOST consider Stepping command was finished.
- //
- if (MultiProcessorDebugSupport ()) {
- mDebugMpContext.BreakAtCpuIndex = ProcessorIndex;
- }
-
- //
- // Clear Stepping flag and restore EFLAGS.IF
- //
- CommandSteppingCleanup (CpuContext);
- SendAckPacket (DEBUG_COMMAND_OK);
- } else {
- //
- // Exception occurs, send Break packet to HOST
- //
- AcquireMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
- //
- // Only the first breaking processor could send BREAK_POINT to HOST
- //
- if (IsFirstBreakProcessor (ProcessorIndex)) {
- SendBreakPacketToHost (BreakCause, ProcessorIndex, &BreakReceived);
- }
-
- ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
- }
-
- CommandCommunication (Vector, CpuContext, BreakReceived);
- }
-
- break;
- }
-
- if (MultiProcessorDebugSupport ()) {
- //
- // Clear flag and wait for all processors run here
- //
- SetIpiSentByApFlag (FALSE);
- while (mDebugMpContext.RunCommandSet) {
- CpuPause ();
- }
-
- //
- // Only current (view) processor could clean up AgentInProgress flag.
- //
- if (mDebugMpContext.ViewPointIndex == ProcessorIndex) {
- IssuedViewPoint = mDebugMpContext.ViewPointIndex;
- }
- }
-
- if ((IssuedViewPoint == ProcessorIndex) && (GetDebugFlag (DEBUG_AGENT_FLAG_STEPPING) != 1)) {
- //
- // If the command is not stepping, clean up AgentInProgress flag
- //
- SetDebugFlag (DEBUG_AGENT_FLAG_AGENT_IN_PROGRESS, 0);
- }
-
- return;
-}
+/** @file + Common Debug Agent library implementation. It mainly includes + the first C function called by exception/interrupt handlers, + read/write debug packet to communication with HOST based on transfer + protocol. + + Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "DebugAgent.h" +#include "Ia32/DebugException.h" + +GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 mErrorMsgVersionAlert[] = "\rThe SourceLevelDebugPkg you are using requires a newer version of the Intel(R) UDK Debugger Tool.\r\n"; +GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 mErrorMsgSendInitPacket[] = "\rSend INIT break packet and try to connect the HOST (Intel(R) UDK Debugger Tool v1.5) ...\r\n"; +GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 mErrorMsgConnectOK[] = "HOST connection is successful!\r\n"; +GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 mErrorMsgConnectFail[] = "HOST connection is failed!\r\n"; +GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 mWarningMsgIngoreBreakpoint[] = "Ignore break point in SMM for SMI issued during DXE debugging!\r\n"; + +// +// Vector Handoff Info list used by Debug Agent for persist +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_VECTOR_HANDOFF_INFO mVectorHandoffInfoDebugAgent[] = { + { + DEBUG_EXCEPT_DIVIDE_ERROR, // Vector 0 + EFI_VECTOR_HANDOFF_HOOK_BEFORE, + EFI_DEBUG_AGENT_GUID + }, + { + DEBUG_EXCEPT_DEBUG, // Vector 1 + EFI_VECTOR_HANDOFF_DO_NOT_HOOK, + EFI_DEBUG_AGENT_GUID + }, + { + DEBUG_EXCEPT_NMI, // Vector 2 + EFI_VECTOR_HANDOFF_HOOK_BEFORE, + EFI_DEBUG_AGENT_GUID + }, + { + DEBUG_EXCEPT_BREAKPOINT, // Vector 3 + EFI_VECTOR_HANDOFF_DO_NOT_HOOK, + EFI_DEBUG_AGENT_GUID + }, + { + DEBUG_EXCEPT_OVERFLOW, // Vector 4 + EFI_VECTOR_HANDOFF_HOOK_BEFORE, + EFI_DEBUG_AGENT_GUID + }, + { + DEBUG_EXCEPT_BOUND, // Vector 5 + EFI_VECTOR_HANDOFF_HOOK_BEFORE, + EFI_DEBUG_AGENT_GUID + }, + { + DEBUG_EXCEPT_INVALID_OPCODE, // Vector 6 + EFI_VECTOR_HANDOFF_HOOK_BEFORE, + EFI_DEBUG_AGENT_GUID + }, + { + DEBUG_EXCEPT_DOUBLE_FAULT, // Vector 8 + EFI_VECTOR_HANDOFF_HOOK_BEFORE, + EFI_DEBUG_AGENT_GUID + }, + { + DEBUG_EXCEPT_INVALID_TSS, // Vector 10 + EFI_VECTOR_HANDOFF_HOOK_BEFORE, + EFI_DEBUG_AGENT_GUID + }, + { + DEBUG_EXCEPT_SEG_NOT_PRESENT, // Vector 11 + EFI_VECTOR_HANDOFF_HOOK_BEFORE, + EFI_DEBUG_AGENT_GUID + }, + { + DEBUG_EXCEPT_STACK_FAULT, // Vector 12 + EFI_VECTOR_HANDOFF_HOOK_BEFORE, + EFI_DEBUG_AGENT_GUID + }, + { + DEBUG_EXCEPT_GP_FAULT, // Vector 13 + EFI_VECTOR_HANDOFF_HOOK_BEFORE, + EFI_DEBUG_AGENT_GUID + }, + { + DEBUG_EXCEPT_PAGE_FAULT, // Vector 14 + EFI_VECTOR_HANDOFF_HOOK_BEFORE, + EFI_DEBUG_AGENT_GUID + }, + { + DEBUG_EXCEPT_FP_ERROR, // Vector 16 + EFI_VECTOR_HANDOFF_HOOK_BEFORE, + EFI_DEBUG_AGENT_GUID + }, + { + DEBUG_EXCEPT_ALIGNMENT_CHECK, // Vector 17 + EFI_VECTOR_HANDOFF_HOOK_BEFORE, + EFI_DEBUG_AGENT_GUID + }, + { + DEBUG_EXCEPT_MACHINE_CHECK, // Vector 18 + EFI_VECTOR_HANDOFF_HOOK_BEFORE, + EFI_DEBUG_AGENT_GUID + }, + { + DEBUG_EXCEPT_SIMD, // Vector 19 + EFI_VECTOR_HANDOFF_HOOK_BEFORE, + EFI_DEBUG_AGENT_GUID + }, + { + DEBUG_TIMER_VECTOR, // Vector 32 + EFI_VECTOR_HANDOFF_DO_NOT_HOOK, + EFI_DEBUG_AGENT_GUID + }, + { + DEBUG_MAILBOX_VECTOR, // Vector 33 + EFI_VECTOR_HANDOFF_DO_NOT_HOOK, + EFI_DEBUG_AGENT_GUID + }, + { + 0, + EFI_VECTOR_HANDOFF_LAST_ENTRY, + { 0 } + } +}; + +GLOBAL_REMOVE_IF_UNREFERENCED UINTN mVectorHandoffInfoCount = sizeof (mVectorHandoffInfoDebugAgent) / sizeof (EFI_VECTOR_HANDOFF_INFO); + +/** + Calculate CRC16 for target data. + + @param[in] Data The target data. + @param[in] DataSize The target data size. + @param[in] Crc Initial CRC. + + @return UINT16 The CRC16 value. + +**/ +UINT16 +CalculateCrc16 ( + IN UINT8 *Data, + IN UINTN DataSize, + IN UINT16 Crc + ) +{ + UINTN Index; + UINTN BitIndex; + + for (Index = 0; Index < DataSize; Index++) { + Crc ^= (UINT16)Data[Index]; + for (BitIndex = 0; BitIndex < 8; BitIndex++) { + if ((Crc & 0x8000) != 0) { + Crc <<= 1; + Crc ^= 0x1021; + } else { + Crc <<= 1; + } + } + } + + return Crc; +} + +/** + Read IDT entry to check if IDT entries are setup by Debug Agent. + + @retval TRUE IDT entries were setup by Debug Agent. + @retval FALSE IDT entries were not setup by Debug Agent. + +**/ +BOOLEAN +IsDebugAgentInitialzed ( + VOID + ) +{ + UINTN InterruptHandler; + + InterruptHandler = (UINTN)GetExceptionHandlerInIdtEntry (0); + if ((InterruptHandler >= 4) && (*(UINT32 *)(InterruptHandler - 4) == AGENT_HANDLER_SIGNATURE)) { + return TRUE; + } else { + return FALSE; + } +} + +/** + Find and report module image info to HOST. + + @param[in] AlignSize Image aligned size. + +**/ +VOID +FindAndReportModuleImageInfo ( + IN UINTN AlignSize + ) +{ + UINTN Pe32Data; + PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + + // + // Find Image Base + // + Pe32Data = PeCoffSearchImageBase ((UINTN)mErrorMsgVersionAlert); + if (Pe32Data != 0) { + ImageContext.ImageAddress = Pe32Data; + ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)ImageContext.ImageAddress); + PeCoffLoaderRelocateImageExtraAction (&ImageContext); + } +} + +/** + Trigger one software interrupt to debug agent to handle it. + + @param[in] Signature Software interrupt signature. + +**/ +VOID +TriggerSoftInterrupt ( + IN 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); +} + +/** + Calculate Mailbox checksum and update the checksum field. + + @param[in] Mailbox Debug Agent Mailbox pointer. + +**/ +VOID +UpdateMailboxChecksum ( + IN DEBUG_AGENT_MAILBOX *Mailbox + ) +{ + Mailbox->CheckSum = CalculateCheckSum8 ((UINT8 *)Mailbox, sizeof (DEBUG_AGENT_MAILBOX) - 2); +} + +/** + Verify Mailbox checksum. + + If checksum error, print debug message and run init dead loop. + + @param[in] Mailbox Debug Agent Mailbox pointer. + +**/ +VOID +VerifyMailboxChecksum ( + IN DEBUG_AGENT_MAILBOX *Mailbox + ) +{ + UINT8 CheckSum; + + CheckSum = CalculateCheckSum8 ((UINT8 *)Mailbox, sizeof (DEBUG_AGENT_MAILBOX) - 2); + // + // The checksum updating process may be disturbed by hardware SMI, we need to check CheckSum field + // and ToBeCheckSum field to validate the mail box. + // + if ((CheckSum != Mailbox->CheckSum) && (CheckSum != Mailbox->ToBeCheckSum)) { + DEBUG ((DEBUG_ERROR, "DebugAgent: Mailbox checksum error, stack or heap crashed!\n")); + DEBUG ((DEBUG_ERROR, "DebugAgent: CheckSum = %x, Mailbox->CheckSum = %x, Mailbox->ToBeCheckSum = %x\n", CheckSum, Mailbox->CheckSum, Mailbox->ToBeCheckSum)); + CpuDeadLoop (); + } +} + +/** + Update Mailbox content by index. + + @param[in] Mailbox Debug Agent Mailbox pointer. + @param[in] Index Mailbox content index. + @param[in] Value Value to be set into Mailbox. + +**/ +VOID +UpdateMailboxContent ( + IN DEBUG_AGENT_MAILBOX *Mailbox, + IN UINTN Index, + IN UINT64 Value + ) +{ + AcquireMpSpinLock (&mDebugMpContext.MailboxSpinLock); + switch (Index) { + case DEBUG_MAILBOX_DEBUG_FLAG_INDEX: + Mailbox->ToBeCheckSum = Mailbox->CheckSum + CalculateSum8 ((UINT8 *)&Mailbox->DebugFlag.Uint64, sizeof (UINT64)) + - CalculateSum8 ((UINT8 *)&Value, sizeof (UINT64)); + Mailbox->DebugFlag.Uint64 = Value; + break; + case DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX: + Mailbox->ToBeCheckSum = Mailbox->CheckSum + CalculateSum8 ((UINT8 *)&Mailbox->DebugPortHandle, sizeof (UINTN)) + - CalculateSum8 ((UINT8 *)&Value, sizeof (UINTN)); + Mailbox->DebugPortHandle = (UINTN)Value; + break; + case DEBUG_MAILBOX_EXCEPTION_BUFFER_POINTER_INDEX: + Mailbox->ToBeCheckSum = Mailbox->CheckSum + CalculateSum8 ((UINT8 *)&Mailbox->ExceptionBufferPointer, sizeof (UINTN)) + - CalculateSum8 ((UINT8 *)&Value, sizeof (UINTN)); + Mailbox->ExceptionBufferPointer = (UINTN)Value; + break; + case DEBUG_MAILBOX_LAST_ACK: + Mailbox->ToBeCheckSum = Mailbox->CheckSum + CalculateSum8 ((UINT8 *)&Mailbox->LastAck, sizeof (UINT8)) + - CalculateSum8 ((UINT8 *)&Value, sizeof (UINT8)); + Mailbox->LastAck = (UINT8)Value; + break; + case DEBUG_MAILBOX_SEQUENCE_NO_INDEX: + Mailbox->ToBeCheckSum = Mailbox->CheckSum + CalculateSum8 ((UINT8 *)&Mailbox->SequenceNo, sizeof (UINT8)) + - CalculateSum8 ((UINT8 *)&Value, sizeof (UINT8)); + Mailbox->SequenceNo = (UINT8)Value; + break; + case DEBUG_MAILBOX_HOST_SEQUENCE_NO_INDEX: + Mailbox->ToBeCheckSum = Mailbox->CheckSum + CalculateSum8 ((UINT8 *)&Mailbox->HostSequenceNo, sizeof (UINT8)) + - CalculateSum8 ((UINT8 *)&Value, sizeof (UINT8)); + Mailbox->HostSequenceNo = (UINT8)Value; + break; + case DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY: + Mailbox->ToBeCheckSum = Mailbox->CheckSum + CalculateSum8 ((UINT8 *)&Mailbox->DebugTimerFrequency, sizeof (UINT32)) + - CalculateSum8 ((UINT8 *)&Value, sizeof (UINT32)); + Mailbox->DebugTimerFrequency = (UINT32)Value; + break; + } + + UpdateMailboxChecksum (Mailbox); + ReleaseMpSpinLock (&mDebugMpContext.MailboxSpinLock); +} + +/** + Read data from debug device and save the data in buffer. + + Reads NumberOfBytes data bytes from a debug device into the buffer + specified by Buffer. The number of bytes actually read is returned. + If the return value is less than NumberOfBytes, then the rest operation failed. + If NumberOfBytes is zero, then return 0. + + @param Handle Debug port handle. + @param Buffer Pointer to the data buffer to store the data read from the debug device. + @param NumberOfBytes Number of bytes which will be read. + @param Timeout Timeout value for reading from debug device. It unit is Microsecond. + + @retval 0 Read data failed, no data is to be read. + @retval >0 Actual number of bytes read from debug device. + +**/ +UINTN +DebugAgentReadBuffer ( + IN DEBUG_PORT_HANDLE Handle, + IN UINT8 *Buffer, + IN UINTN NumberOfBytes, + IN UINTN Timeout + ) +{ + UINTN Index; + UINT32 Begin; + UINT32 TimeoutTicker; + UINT32 TimerRound; + UINT32 TimerFrequency; + UINT32 TimerCycle; + + Begin = 0; + TimeoutTicker = 0; + TimerRound = 0; + TimerFrequency = GetMailboxPointer ()->DebugTimerFrequency; + TimerCycle = GetApicTimerInitCount (); + + if (Timeout != 0) { + Begin = GetApicTimerCurrentCount (); + TimeoutTicker = (UINT32)DivU64x32 ( + MultU64x64 ( + TimerFrequency, + Timeout + ), + 1000000u + ); + TimerRound = (UINT32)DivU64x32Remainder (TimeoutTicker, TimerCycle / 2, &TimeoutTicker); + } + + Index = 0; + while (Index < NumberOfBytes) { + if (DebugPortPollBuffer (Handle)) { + DebugPortReadBuffer (Handle, Buffer + Index, 1, 0); + Index++; + continue; + } + + if (Timeout != 0) { + if (TimerRound == 0) { + if (IsDebugTimerTimeout (TimerCycle, Begin, TimeoutTicker)) { + // + // If time out occurs. + // + return 0; + } + } else { + if (IsDebugTimerTimeout (TimerCycle, Begin, TimerCycle / 2)) { + TimerRound--; + Begin = GetApicTimerCurrentCount (); + } + } + } + } + + return Index; +} + +/** + Set debug flag in mailbox. + + @param[in] FlagMask Debug flag mask value. + @param[in] FlagValue Debug flag value. + +**/ +VOID +SetDebugFlag ( + IN UINT64 FlagMask, + IN UINT32 FlagValue + ) +{ + DEBUG_AGENT_MAILBOX *Mailbox; + UINT64 Data64; + + Mailbox = GetMailboxPointer (); + Data64 = (Mailbox->DebugFlag.Uint64 & ~FlagMask) | + (LShiftU64 ((UINT64)FlagValue, LowBitSet64 (FlagMask)) & FlagMask); + UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_FLAG_INDEX, Data64); +} + +/** + Get debug flag in mailbox. + + @param[in] FlagMask Debug flag mask value. + + @return Debug flag value. + +**/ +UINT32 +GetDebugFlag ( + IN UINT64 FlagMask + ) +{ + DEBUG_AGENT_MAILBOX *Mailbox; + UINT32 DebugFlag; + + Mailbox = GetMailboxPointer (); + DebugFlag = (UINT32)RShiftU64 (Mailbox->DebugFlag.Uint64 & FlagMask, LowBitSet64 (FlagMask)); + + return DebugFlag; +} + +/** + Send a debug message packet to the debug port. + + @param[in] Buffer The debug message. + @param[in] Length The length of debug message. + +**/ +VOID +SendDebugMsgPacket ( + IN CHAR8 *Buffer, + IN UINTN Length + ) +{ + DEBUG_PACKET_HEADER DebugHeader; + DEBUG_PORT_HANDLE Handle; + + Handle = GetDebugPortHandle (); + + DebugHeader.StartSymbol = DEBUG_STARTING_SYMBOL_NORMAL; + DebugHeader.Command = DEBUG_COMMAND_PRINT_MESSAGE; + DebugHeader.Length = sizeof (DEBUG_PACKET_HEADER) + (UINT8)Length; + DebugHeader.SequenceNo = 0xEE; + DebugHeader.Crc = 0; + DebugHeader.Crc = CalculateCrc16 ( + (UINT8 *)Buffer, + Length, + CalculateCrc16 ((UINT8 *)&DebugHeader, sizeof (DEBUG_PACKET_HEADER), 0) + ); + + DebugPortWriteBuffer (Handle, (UINT8 *)&DebugHeader, sizeof (DEBUG_PACKET_HEADER)); + DebugPortWriteBuffer (Handle, (UINT8 *)Buffer, Length); +} + +/** + Prints a debug message to the debug port if the specified error level is enabled. + + If any bit in ErrorLevel is also set in Mainbox, then print the message specified + by Format and the associated variable argument list to the debug port. + + @param[in] ErrorLevel The error level of the debug message. + @param[in] Format Format string for the debug message to print. + @param[in] ... Variable argument list whose contents are accessed + based on the format string specified by Format. + +**/ +VOID +EFIAPI +DebugAgentMsgPrint ( + IN UINT8 ErrorLevel, + IN CHAR8 *Format, + ... + ) +{ + CHAR8 Buffer[DEBUG_DATA_MAXIMUM_REAL_DATA]; + VA_LIST Marker; + + // + // Check driver debug mask value and global mask + // + if ((ErrorLevel & GetDebugFlag (DEBUG_AGENT_FLAG_PRINT_ERROR_LEVEL)) == 0) { + return; + } + + // + // Convert the DEBUG() message to an ASCII String + // + VA_START (Marker, Format); + AsciiVSPrint (Buffer, sizeof (Buffer), Format, Marker); + VA_END (Marker); + + SendDebugMsgPacket (Buffer, AsciiStrLen (Buffer)); +} + +/** + Prints a debug message to the debug output device if the specified error level is enabled. + + If any bit in ErrorLevel is also set in DebugPrintErrorLevelLib function + GetDebugPrintErrorLevel (), then print the message specified by Format and the + associated variable argument list to the debug output device. + + If Format is NULL, then ASSERT(). + + @param[in] ErrorLevel The error level of the debug message. + @param[in] IsSend Flag of debug message to declare that the data is being sent or being received. + @param[in] Data Variable argument list whose contents are accessed + @param[in] Length based on the format string specified by Format. + +**/ +VOID +EFIAPI +DebugAgentDataMsgPrint ( + IN UINT8 ErrorLevel, + IN BOOLEAN IsSend, + IN UINT8 *Data, + IN UINT8 Length + ) +{ + CHAR8 Buffer[DEBUG_DATA_MAXIMUM_REAL_DATA]; + CHAR8 *DestBuffer; + UINTN Index; + + // + // Check driver debug mask value and global mask + // + if ((ErrorLevel & GetDebugFlag (DEBUG_AGENT_FLAG_PRINT_ERROR_LEVEL)) == 0) { + return; + } + + DestBuffer = Buffer; + if (IsSend) { + DestBuffer += AsciiSPrint (DestBuffer, DEBUG_DATA_MAXIMUM_REAL_DATA, "Sent data [ "); + } else { + DestBuffer += AsciiSPrint (DestBuffer, DEBUG_DATA_MAXIMUM_REAL_DATA, "Received data [ "); + } + + Index = 0; + while (TRUE) { + if (DestBuffer - Buffer > DEBUG_DATA_MAXIMUM_REAL_DATA - 6) { + // + // If there was no enough space in buffer, send out the debug message, + // reserving 6 bytes is for the last data and end characters "]\n". + // + SendDebugMsgPacket (Buffer, DestBuffer - Buffer); + DestBuffer = Buffer; + } + + DestBuffer += AsciiSPrint (DestBuffer, DEBUG_DATA_MAXIMUM_REAL_DATA - (DestBuffer - Buffer), "%02x ", Data[Index]); + Index++; + if (Index >= Length) { + // + // The last character of debug message has been formatted in buffer + // + DestBuffer += AsciiSPrint (DestBuffer, DEBUG_DATA_MAXIMUM_REAL_DATA - (DestBuffer - Buffer), "]\n"); + SendDebugMsgPacket (Buffer, DestBuffer - Buffer); + break; + } + } +} + +/** + Read remaining debug packet except for the start symbol + + @param[in] Handle Pointer to Debug Port handle. + @param[in, out] DebugHeader Debug header buffer including start symbol. + + @retval EFI_SUCCESS Read the symbol in BreakSymbol. + @retval EFI_CRC_ERROR CRC check fail. + @retval EFI_TIMEOUT Timeout occurs when reading debug packet. + @retval EFI_DEVICE_ERROR Receive the old or response packet. + +**/ +EFI_STATUS +ReadRemainingBreakPacket ( + IN DEBUG_PORT_HANDLE Handle, + IN OUT DEBUG_PACKET_HEADER *DebugHeader + ) +{ + UINT16 Crc; + DEBUG_AGENT_MAILBOX *Mailbox; + + // + // Has received start symbol, try to read the rest part + // + if (DebugAgentReadBuffer (Handle, (UINT8 *)DebugHeader + OFFSET_OF (DEBUG_PACKET_HEADER, Command), sizeof (DEBUG_PACKET_HEADER) - OFFSET_OF (DEBUG_PACKET_HEADER, Command), READ_PACKET_TIMEOUT) == 0) { + // + // Timeout occur, exit + // + DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "Timeout in Debug Timer interrupt\n"); + return EFI_TIMEOUT; + } + + Crc = DebugHeader->Crc; + DebugHeader->Crc = 0; + if (CalculateCrc16 ((UINT8 *)DebugHeader, DebugHeader->Length, 0) != Crc) { + DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "Debug Timer CRC (%x) against (%x)\n", Crc, CalculateCrc16 ((UINT8 *)&DebugHeader, DebugHeader->Length, 0)); + DebugAgentDataMsgPrint (DEBUG_AGENT_VERBOSE, FALSE, (UINT8 *)DebugHeader, DebugHeader->Length); + return EFI_CRC_ERROR; + } + + Mailbox = GetMailboxPointer (); + if (IS_REQUEST (DebugHeader)) { + if (DebugHeader->SequenceNo == (UINT8)(Mailbox->HostSequenceNo + 1)) { + // + // Only update HostSequenceNo for new command packet + // + UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_HOST_SEQUENCE_NO_INDEX, DebugHeader->SequenceNo); + return EFI_SUCCESS; + } + + if (DebugHeader->SequenceNo == Mailbox->HostSequenceNo) { + return EFI_SUCCESS; + } + } + + return EFI_DEVICE_ERROR; +} + +/** + Check if HOST is attached based on Mailbox. + + @retval TRUE HOST is attached. + @retval FALSE HOST is not attached. + +**/ +BOOLEAN +IsHostAttached ( + VOID + ) +{ + return (BOOLEAN)(GetDebugFlag (DEBUG_AGENT_FLAG_HOST_ATTACHED) == 1); +} + +/** + Set HOST connect flag in Mailbox. + + @param[in] Attached Attach status. + +**/ +VOID +SetHostAttached ( + IN BOOLEAN Attached + ) +{ + DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Attach status is %d\n", Attached); + SetDebugFlag (DEBUG_AGENT_FLAG_HOST_ATTACHED, (UINT32)Attached); +} + +/** + Set debug setting of Debug Agent in Mailbox. + + @param DebugSetting Pointer to Debug Setting defined by transfer protocol. + + @retval RETURN_SUCCESS The setting is set successfully. + @retval RETURN_UNSUPPORTED The Key value is not supported. + +**/ +RETURN_STATUS +SetDebugSetting ( + IN DEBUG_DATA_SET_DEBUG_SETTING *DebugSetting + ) +{ + RETURN_STATUS Status; + + Status = RETURN_SUCCESS; + switch (DebugSetting->Key) { + case DEBUG_AGENT_SETTING_SMM_ENTRY_BREAK: + SetDebugFlag (DEBUG_AGENT_FLAG_BREAK_ON_NEXT_SMI, DebugSetting->Value); + break; + case DEBUG_AGENT_SETTING_PRINT_ERROR_LEVEL: + SetDebugFlag (DEBUG_AGENT_FLAG_PRINT_ERROR_LEVEL, DebugSetting->Value); + break; + case DEBUG_AGENT_SETTING_BOOT_SCRIPT_ENTRY_BREAK: + SetDebugFlag (DEBUG_AGENT_FLAG_BREAK_BOOT_SCRIPT, DebugSetting->Value); + break; + default: + Status = RETURN_UNSUPPORTED; + } + + return Status; +} + +/** + Execute GO command. + + @param[in] CpuContext Pointer to saved CPU context. + +**/ +VOID +CommandGo ( + IN DEBUG_CPU_CONTEXT *CpuContext + ) +{ + IA32_EFLAGS32 *Eflags; + + Eflags = (IA32_EFLAGS32 *)&CpuContext->Eflags; + Eflags->Bits.TF = 0; + Eflags->Bits.RF = 1; +} + +/** + Execute Stepping command. + + @param[in] CpuContext Pointer to saved CPU context. + +**/ +VOID +CommandStepping ( + IN DEBUG_CPU_CONTEXT *CpuContext + ) +{ + IA32_EFLAGS32 *Eflags; + + Eflags = (IA32_EFLAGS32 *)&CpuContext->Eflags; + Eflags->Bits.TF = 1; + Eflags->Bits.RF = 1; + // + // Save and clear EFLAGS.IF to avoid interrupt happen when executing Stepping + // + SetDebugFlag (DEBUG_AGENT_FLAG_INTERRUPT_FLAG, Eflags->Bits.IF); + Eflags->Bits.IF = 0; + // + // Set Stepping Flag + // + SetDebugFlag (DEBUG_AGENT_FLAG_STEPPING, 1); +} + +/** + Do some cleanup after Stepping command done. + + @param[in] CpuContext Pointer to saved CPU context. + +**/ +VOID +CommandSteppingCleanup ( + IN DEBUG_CPU_CONTEXT *CpuContext + ) +{ + IA32_EFLAGS32 *Eflags; + + Eflags = (IA32_EFLAGS32 *)&CpuContext->Eflags; + // + // Restore EFLAGS.IF + // + Eflags->Bits.IF = GetDebugFlag (DEBUG_AGENT_FLAG_INTERRUPT_FLAG); + // + // Clear Stepping flag + // + SetDebugFlag (DEBUG_AGENT_FLAG_STEPPING, 0); +} + +/** + Set debug register for hardware breakpoint. + + @param[in] CpuContext Pointer to saved CPU context. + @param[in] SetHwBreakpoint Hardware breakpoint to be set. + +**/ +VOID +SetDebugRegister ( + IN DEBUG_CPU_CONTEXT *CpuContext, + IN DEBUG_DATA_SET_HW_BREAKPOINT *SetHwBreakpoint + ) +{ + UINT8 RegisterIndex; + UINTN Dr7Value; + + RegisterIndex = SetHwBreakpoint->Type.Index; + + // + // Set debug address + // + *((UINTN *)&CpuContext->Dr0 + RegisterIndex) = (UINTN)SetHwBreakpoint->Address; + + Dr7Value = CpuContext->Dr7; + + // + // Enable Gx, Lx + // + Dr7Value |= (UINTN)(0x3 << (RegisterIndex * 2)); + // + // Set RWx and Lenx + // + Dr7Value &= (UINTN)(~(0xf << (16 + RegisterIndex * 4))); + Dr7Value |= (UINTN)((SetHwBreakpoint->Type.Length << 2) | SetHwBreakpoint->Type.Access) << (16 + RegisterIndex * 4); + // + // Enable GE, LE + // + Dr7Value |= 0x300; + + CpuContext->Dr7 = Dr7Value; +} + +/** + Clear debug register for hardware breakpoint. + + @param[in] CpuContext Pointer to saved CPU context. + @param[in] ClearHwBreakpoint Hardware breakpoint to be cleared. + +**/ +VOID +ClearDebugRegister ( + IN DEBUG_CPU_CONTEXT *CpuContext, + IN DEBUG_DATA_CLEAR_HW_BREAKPOINT *ClearHwBreakpoint + ) +{ + if ((ClearHwBreakpoint->IndexMask & BIT0) != 0) { + CpuContext->Dr0 = 0; + CpuContext->Dr7 &= (UINTN)(~(0x3 << 0)); + } + + if ((ClearHwBreakpoint->IndexMask & BIT1) != 0) { + CpuContext->Dr1 = 0; + CpuContext->Dr7 &= (UINTN)(~(0x3 << 2)); + } + + if ((ClearHwBreakpoint->IndexMask & BIT2) != 0) { + CpuContext->Dr2 = 0; + CpuContext->Dr7 &= (UINTN)(~(0x3 << 4)); + } + + if ((ClearHwBreakpoint->IndexMask & BIT3) != 0) { + CpuContext->Dr3 = 0; + CpuContext->Dr7 &= (UINTN)(~(0x3 << 6)); + } +} + +/** + Return the offset of FP / MMX / XMM registers in the FPU saved state by register index. + + @param[in] Index Register index. + @param[out] Width Register width returned. + + @return Offset in the FPU Save State. + +**/ +UINT16 +ArchReadFxStatOffset ( + IN UINT8 Index, + OUT UINT8 *Width + ) +{ + if (Index < SOFT_DEBUGGER_REGISTER_ST0) { + switch (Index) { + case SOFT_DEBUGGER_REGISTER_FP_FCW: + *Width = (UINT8)sizeof (UINT16); + return OFFSET_OF (DEBUG_DATA_FX_SAVE_STATE, Fcw); + + case SOFT_DEBUGGER_REGISTER_FP_FSW: + *Width = (UINT8)sizeof (UINT16); + return OFFSET_OF (DEBUG_DATA_FX_SAVE_STATE, Fsw); + + case SOFT_DEBUGGER_REGISTER_FP_FTW: + *Width = (UINT8)sizeof (UINT16); + return OFFSET_OF (DEBUG_DATA_FX_SAVE_STATE, Ftw); + + case SOFT_DEBUGGER_REGISTER_FP_OPCODE: + *Width = (UINT8)sizeof (UINT16); + return OFFSET_OF (DEBUG_DATA_FX_SAVE_STATE, Opcode); + + case SOFT_DEBUGGER_REGISTER_FP_EIP: + *Width = (UINT8)sizeof (UINT32); + return OFFSET_OF (DEBUG_DATA_FX_SAVE_STATE, Eip); + + case SOFT_DEBUGGER_REGISTER_FP_CS: + *Width = (UINT8)sizeof (UINT16); + return OFFSET_OF (DEBUG_DATA_FX_SAVE_STATE, Cs); + + case SOFT_DEBUGGER_REGISTER_FP_DATAOFFSET: + *Width = (UINT8)sizeof (UINT32); + return OFFSET_OF (DEBUG_DATA_FX_SAVE_STATE, DataOffset); + + case SOFT_DEBUGGER_REGISTER_FP_DS: + *Width = (UINT8)sizeof (UINT16); + return OFFSET_OF (DEBUG_DATA_FX_SAVE_STATE, Ds); + + case SOFT_DEBUGGER_REGISTER_FP_MXCSR: + *Width = (UINT8)sizeof (UINT32); + return OFFSET_OF (DEBUG_DATA_FX_SAVE_STATE, Mxcsr); + + case SOFT_DEBUGGER_REGISTER_FP_MXCSR_MASK: + *Width = (UINT8)sizeof (UINT32); + return OFFSET_OF (DEBUG_DATA_FX_SAVE_STATE, Mxcsr_Mask); + } + } + + if (Index <= SOFT_DEBUGGER_REGISTER_ST7) { + *Width = 10; + } else if (Index <= SOFT_DEBUGGER_REGISTER_XMM15) { + *Width = 16; + } else { + // + // MMX register + // + *Width = 8; + Index -= SOFT_DEBUGGER_REGISTER_MM0 - SOFT_DEBUGGER_REGISTER_ST0; + } + + return OFFSET_OF (DEBUG_DATA_FX_SAVE_STATE, St0Mm0) + (Index - SOFT_DEBUGGER_REGISTER_ST0) * 16; +} + +/** + Return the pointer of the register value in the CPU saved context. + + @param[in] CpuContext Pointer to saved CPU context. + @param[in] Index Register index value. + @param[out] Width Data width to read. + + @return The pointer in the CPU saved context. + +**/ +UINT8 * +ArchReadRegisterBuffer ( + IN DEBUG_CPU_CONTEXT *CpuContext, + IN UINT8 Index, + OUT UINT8 *Width + ) +{ + UINT8 *Buffer; + + if (Index < SOFT_DEBUGGER_REGISTER_FP_BASE) { + Buffer = (UINT8 *)CpuContext + OFFSET_OF (DEBUG_CPU_CONTEXT, Dr0) + Index * sizeof (UINTN); + *Width = (UINT8)sizeof (UINTN); + } else { + // + // FPU/MMX/XMM registers + // + Buffer = (UINT8 *)CpuContext + OFFSET_OF (DEBUG_CPU_CONTEXT, FxSaveState) + ArchReadFxStatOffset (Index, Width); + } + + return Buffer; +} + +/** + Send the packet without data to HOST. + + @param[in] CommandType Type of Command. + @param[in] SequenceNo Sequence number. + +**/ +VOID +SendPacketWithoutData ( + IN UINT8 CommandType, + IN UINT8 SequenceNo + ) +{ + DEBUG_PACKET_HEADER DebugHeader; + DEBUG_PORT_HANDLE Handle; + + Handle = GetDebugPortHandle (); + + DebugHeader.StartSymbol = DEBUG_STARTING_SYMBOL_NORMAL; + DebugHeader.Command = CommandType; + DebugHeader.Length = sizeof (DEBUG_PACKET_HEADER); + DebugHeader.SequenceNo = SequenceNo; + DebugHeader.Crc = 0; + DebugHeader.Crc = CalculateCrc16 ((UINT8 *)&DebugHeader, sizeof (DEBUG_PACKET_HEADER), 0); + + DebugAgentDataMsgPrint (DEBUG_AGENT_VERBOSE, TRUE, (UINT8 *)&DebugHeader, DebugHeader.Length); + DebugPortWriteBuffer (Handle, (UINT8 *)&DebugHeader, DebugHeader.Length); +} + +/** + Send acknowledge packet to HOST. + + @param[in] AckCommand Type of Acknowledge packet. + +**/ +VOID +SendAckPacket ( + IN UINT8 AckCommand + ) +{ + UINT8 SequenceNo; + DEBUG_AGENT_MAILBOX *Mailbox; + + if (AckCommand != DEBUG_COMMAND_OK) { + // + // This is not ACK OK packet + // + DebugAgentMsgPrint (DEBUG_AGENT_ERROR, "Send ACK(%d)\n", AckCommand); + } + + Mailbox = GetMailboxPointer (); + SequenceNo = Mailbox->HostSequenceNo; + DebugAgentMsgPrint (DEBUG_AGENT_INFO, "SendAckPacket: SequenceNo = %x\n", SequenceNo); + SendPacketWithoutData (AckCommand, SequenceNo); + UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_LAST_ACK, AckCommand); +} + +/** + Decompress the Data in place. + + @param[in, out] Data The compressed data buffer. + The buffer is assumed large enough to hold the uncompressed data. + @param[in] Length The length of the compressed data buffer. + + @return The length of the uncompressed data buffer. +**/ +UINT8 +DecompressDataInPlace ( + IN OUT UINT8 *Data, + IN UINTN Length + ) +{ + UINTN Index; + UINT16 LastChar; + UINTN LastCharCount; + UINT8 CurrentChar; + + LastChar = (UINT16)-1; + LastCharCount = 0; + for (Index = 0; Index < Length; Index++) { + CurrentChar = Data[Index]; + if (LastCharCount == 2) { + LastCharCount = 0; + CopyMem (&Data[Index + CurrentChar], &Data[Index + 1], Length - Index - 1); + SetMem (&Data[Index], CurrentChar, (UINT8)LastChar); + LastChar = (UINT16)-1; + Index += CurrentChar - 1; + Length += CurrentChar - 1; + } else { + if (LastChar != CurrentChar) { + LastCharCount = 0; + } + + LastCharCount++; + LastChar = CurrentChar; + } + } + + ASSERT (Length <= DEBUG_DATA_MAXIMUM_REAL_DATA); + + return (UINT8)Length; +} + +/** + Receive valid packet from HOST. + + @param[out] InputPacket Buffer to receive packet. + @param[out] BreakReceived TRUE means break-in symbol received. + FALSE means break-in symbol not received. + @param[out] IncompatibilityFlag If IncompatibilityFlag is not NULL, return + TRUE: Compatible packet received. + FALSE: Incompatible packet received. + @param[in] Timeout Time out value to wait for acknowledge from HOST. + The unit is microsecond. + @param[in] SkipStartSymbol TRUE: Skip time out when reading start symbol. + FALSE: Does not Skip time out when reading start symbol. + + @retval RETURN_SUCCESS A valid package was received in InputPacket. + @retval RETURN_TIMEOUT Timeout occurs. + +**/ +RETURN_STATUS +ReceivePacket ( + OUT UINT8 *InputPacket, + OUT BOOLEAN *BreakReceived, + OUT BOOLEAN *IncompatibilityFlag OPTIONAL, + IN UINTN Timeout, + IN BOOLEAN SkipStartSymbol + ) +{ + DEBUG_PACKET_HEADER *DebugHeader; + UINTN Received; + DEBUG_PORT_HANDLE Handle; + UINT16 Crc; + UINTN TimeoutForStartSymbol; + + Handle = GetDebugPortHandle (); + if (SkipStartSymbol) { + TimeoutForStartSymbol = 0; + } else { + TimeoutForStartSymbol = Timeout; + } + + DebugHeader = (DEBUG_PACKET_HEADER *)InputPacket; + while (TRUE) { + // + // Find the valid start symbol + // + Received = DebugAgentReadBuffer (Handle, &DebugHeader->StartSymbol, sizeof (DebugHeader->StartSymbol), TimeoutForStartSymbol); + if (Received < sizeof (DebugHeader->StartSymbol)) { + DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "DebugAgentReadBuffer(StartSymbol) timeout\n"); + return RETURN_TIMEOUT; + } + + if ((DebugHeader->StartSymbol != DEBUG_STARTING_SYMBOL_NORMAL) && (DebugHeader->StartSymbol != DEBUG_STARTING_SYMBOL_COMPRESS)) { + DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "Invalid start symbol received [%02x]\n", DebugHeader->StartSymbol); + continue; + } + + // + // Read Package header till field Length + // + Received = DebugAgentReadBuffer ( + Handle, + (UINT8 *)DebugHeader + OFFSET_OF (DEBUG_PACKET_HEADER, Command), + OFFSET_OF (DEBUG_PACKET_HEADER, Length) + sizeof (DebugHeader->Length) - sizeof (DebugHeader->StartSymbol), + Timeout + ); + if (Received == 0) { + DebugAgentMsgPrint (DEBUG_AGENT_ERROR, "DebugAgentReadBuffer(Command) timeout\n"); + return RETURN_TIMEOUT; + } + + if (DebugHeader->Length < sizeof (DEBUG_PACKET_HEADER)) { + if (IncompatibilityFlag != NULL) { + // + // This is one old version debug packet format, set Incompatibility flag + // + *IncompatibilityFlag = TRUE; + } else { + // + // Skip the bad small packet + // + continue; + } + } else { + // + // Read the payload data include the CRC field + // + Received = DebugAgentReadBuffer (Handle, &DebugHeader->SequenceNo, (UINT8)(DebugHeader->Length - OFFSET_OF (DEBUG_PACKET_HEADER, SequenceNo)), Timeout); + if (Received == 0) { + DebugAgentMsgPrint (DEBUG_AGENT_ERROR, "DebugAgentReadBuffer(SequenceNo) timeout\n"); + return RETURN_TIMEOUT; + } + + // + // Calculate the CRC of Debug Packet + // + Crc = DebugHeader->Crc; + DebugHeader->Crc = 0; + if (Crc == CalculateCrc16 ((UINT8 *)DebugHeader, DebugHeader->Length, 0)) { + break; + } + + DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "CRC Error (received CRC is %x)\n", Crc); + DebugAgentDataMsgPrint (DEBUG_AGENT_VERBOSE, FALSE, (UINT8 *)DebugHeader, DebugHeader->Length); + } + } + + DebugAgentDataMsgPrint (DEBUG_AGENT_VERBOSE, FALSE, (UINT8 *)DebugHeader, DebugHeader->Length); + + if (DebugHeader->StartSymbol == DEBUG_STARTING_SYMBOL_COMPRESS) { + DebugHeader->StartSymbol = DEBUG_STARTING_SYMBOL_NORMAL; + DebugHeader->Length = DecompressDataInPlace ( + (UINT8 *)(DebugHeader + 1), + DebugHeader->Length - sizeof (DEBUG_PACKET_HEADER) + ) + sizeof (DEBUG_PACKET_HEADER); + } + + return RETURN_SUCCESS; +} + +/** + Receive acknowledge packet OK from HOST in specified time. + + @param[in] Command The command type issued by TARGET. + @param[in] Timeout Time out value to wait for acknowledge from HOST. + The unit is microsecond. + @param[out] BreakReceived If BreakReceived is not NULL, + TRUE is returned if break-in symbol received. + FALSE is returned if break-in symbol not received. + @param[out] IncompatibilityFlag If IncompatibilityFlag is not NULL, return + TRUE: Compatible packet received. + FALSE: Incompatible packet received. + + @retval RETURN_SUCCESS Succeed to receive acknowledge packet from HOST, + the type of acknowledge packet saved in Ack. + @retval RETURN_TIMEOUT Specified timeout value was up. + +**/ +RETURN_STATUS +SendCommandAndWaitForAckOK ( + IN UINT8 Command, + IN UINTN Timeout, + OUT BOOLEAN *BreakReceived OPTIONAL, + OUT BOOLEAN *IncompatibilityFlag OPTIONAL + ) +{ + RETURN_STATUS Status; + UINT8 InputPacketBuffer[DEBUG_DATA_UPPER_LIMIT]; + DEBUG_PACKET_HEADER *DebugHeader; + UINT8 SequenceNo; + UINT8 HostSequenceNo; + UINT8 RetryCount; + + RetryCount = 3; + DebugHeader = (DEBUG_PACKET_HEADER *)InputPacketBuffer; + Status = RETURN_TIMEOUT; + while (RetryCount > 0) { + SequenceNo = GetMailboxPointer ()->SequenceNo; + HostSequenceNo = GetMailboxPointer ()->HostSequenceNo; + SendPacketWithoutData (Command, SequenceNo); + Status = ReceivePacket ((UINT8 *)DebugHeader, BreakReceived, IncompatibilityFlag, Timeout, FALSE); + if (Status == RETURN_TIMEOUT) { + if (Command == DEBUG_COMMAND_INIT_BREAK) { + RetryCount--; + } else { + DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "TARGET: Timeout when waiting for ACK packet.\n"); + } + + continue; + } + + ASSERT_EFI_ERROR (Status); + // + // Status == RETURN_SUCCESS + // + if ((DebugHeader->Command == DEBUG_COMMAND_OK) && (DebugHeader->SequenceNo == SequenceNo)) { + // + // Received Ack OK + // + UpdateMailboxContent (GetMailboxPointer (), DEBUG_MAILBOX_SEQUENCE_NO_INDEX, ++SequenceNo); + return Status; + } + + if ((DebugHeader->Command == DEBUG_COMMAND_GO) && ((DebugHeader->SequenceNo == HostSequenceNo) || (Command == DEBUG_COMMAND_INIT_BREAK))) { + // + // Received Old GO + // + if (Command == DEBUG_COMMAND_INIT_BREAK) { + DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "TARGET: Receive GO() in last boot\n"); + } + + SendPacketWithoutData (DEBUG_COMMAND_OK, DebugHeader->SequenceNo); + } + } + + ASSERT (Command == DEBUG_COMMAND_INIT_BREAK); + return Status; +} + +/** + Get current break cause. + + @param[in] Vector Vector value of exception or interrupt. + @param[in] CpuContext Pointer to save CPU context. + + @return The type of break cause defined by XXXX + +**/ +UINT8 +GetBreakCause ( + IN UINTN Vector, + IN DEBUG_CPU_CONTEXT *CpuContext + ) +{ + UINT8 Cause; + + Cause = DEBUG_DATA_BREAK_CAUSE_UNKNOWN; + + switch (Vector) { + case DEBUG_INT1_VECTOR: + case DEBUG_INT3_VECTOR: + + if (Vector == DEBUG_INT1_VECTOR) { + // + // INT 1 + // + if ((CpuContext->Dr6 & BIT14) != 0) { + Cause = DEBUG_DATA_BREAK_CAUSE_STEPPING; + // + // DR6.BIT14 Indicates (when set) that the debug exception was + // triggered by the single step execution mode. + // The single-step mode is the highest priority debug exception. + // This is single step, no need to check DR0, to ensure single step + // work in PeCoffExtraActionLib (right after triggering a breakpoint + // to report image load/unload). + // + return Cause; + } else { + Cause = DEBUG_DATA_BREAK_CAUSE_HW_BREAKPOINT; + } + } else { + // + // INT 3 + // + Cause = DEBUG_DATA_BREAK_CAUSE_SW_BREAKPOINT; + } + + switch (CpuContext->Dr0) { + case IMAGE_LOAD_SIGNATURE: + case IMAGE_UNLOAD_SIGNATURE: + + if (CpuContext->Dr3 == IO_PORT_BREAKPOINT_ADDRESS) { + Cause = (UINT8)((CpuContext->Dr0 == IMAGE_LOAD_SIGNATURE) ? + DEBUG_DATA_BREAK_CAUSE_IMAGE_LOAD : DEBUG_DATA_BREAK_CAUSE_IMAGE_UNLOAD); + } + + break; + + case SOFT_INTERRUPT_SIGNATURE: + + if (CpuContext->Dr1 == MEMORY_READY_SIGNATURE) { + Cause = DEBUG_DATA_BREAK_CAUSE_MEMORY_READY; + CpuContext->Dr0 = 0; + } else if (CpuContext->Dr1 == SYSTEM_RESET_SIGNATURE) { + Cause = DEBUG_DATA_BREAK_CAUSE_SYSTEM_RESET; + CpuContext->Dr0 = 0; + } + + break; + + default: + break; + } + + break; + + case DEBUG_TIMER_VECTOR: + Cause = DEBUG_DATA_BREAK_CAUSE_USER_HALT; + break; + + default: + if (Vector < 20) { + if (GetDebugFlag (DEBUG_AGENT_FLAG_STEPPING) == 1) { + // + // If stepping command is executing + // + Cause = DEBUG_DATA_BREAK_CAUSE_STEPPING; + } else { + Cause = DEBUG_DATA_BREAK_CAUSE_EXCEPTION; + } + } + + break; + } + + return Cause; +} + +/** + Copy memory from source to destination with specified width. + + @param[out] Dest A pointer to the destination buffer of the memory copy. + @param[in] Src A pointer to the source buffer of the memory copy. + @param[in] Count The number of data with specified width to copy from source to destination. + @param[in] Width Data width in byte. + +**/ +VOID +CopyMemByWidth ( + OUT UINT8 *Dest, + IN UINT8 *Src, + IN UINT16 Count, + IN UINT8 Width + ) +{ + UINT8 *Destination; + UINT8 *Source; + INT8 Step; + + if (Src > Dest) { + Destination = Dest; + Source = Src; + Step = Width; + } else { + // + // Copy memory from tail to avoid memory overlap + // + Destination = Dest + (Count - 1) * Width; + Source = Src + (Count - 1) * Width; + Step = -Width; + } + + while (Count-- != 0) { + switch (Width) { + case 1: + *(UINT8 *)Destination = MmioRead8 ((UINTN)Source); + break; + case 2: + *(UINT16 *)Destination = MmioRead16 ((UINTN)Source); + break; + case 4: + *(UINT32 *)Destination = MmioRead32 ((UINTN)Source); + break; + case 8: + *(UINT64 *)Destination = MmioRead64 ((UINTN)Source); + break; + default: + ASSERT (FALSE); + } + + Source += Step; + Destination += Step; + } +} + +/** + Compress the data buffer but do not modify the original buffer. + + The compressed data is directly send to the debug channel. + Compressing in place doesn't work because the data may become larger + during compressing phase. ("3 3 ..." --> "3 3 0 ...") + The routine is expected to be called three times: + 1. Compute the length of the compressed data buffer; + 2. Compute the CRC of the compressed data buffer; + 3. Compress the data and send to the debug channel. + + @param[in] Handle The debug channel handle to send the compressed data buffer. + @param[in] Data The data buffer. + @param[in] Length The length of the data buffer. + @param[in] Send TRUE to send the compressed data buffer. + @param[out] CompressedLength Return the length of the compressed data buffer. + It may be larger than the Length in some cases. + @param[out] CompressedCrc Return the CRC of the compressed data buffer. +**/ +VOID +CompressData ( + IN DEBUG_PORT_HANDLE Handle, + IN UINT8 *Data, + IN UINT8 Length, + IN BOOLEAN Send, + OUT UINTN *CompressedLength OPTIONAL, + OUT UINT16 *CompressedCrc OPTIONAL + ) +{ + UINTN Index; + UINT8 LastChar; + UINT8 LastCharCount; + UINT8 CurrentChar; + UINTN CompressedIndex; + + ASSERT (Length > 0); + LastChar = Data[0] + 1; // Just ensure it's different from the first byte. + LastCharCount = 0; + + for (Index = 0, CompressedIndex = 0; Index <= Length; Index++) { + if (Index < Length) { + CurrentChar = Data[Index]; + } else { + CurrentChar = (UINT8)LastChar + 1; // just ensure it's different from LastChar + } + + if (LastChar != CurrentChar) { + if (LastCharCount == 1) { + CompressedIndex++; + if (CompressedCrc != NULL) { + *CompressedCrc = CalculateCrc16 (&LastChar, 1, *CompressedCrc); + } + + if (Send) { + DebugPortWriteBuffer (Handle, &LastChar, 1); + } + } else if (LastCharCount >= 2) { + CompressedIndex += 3; + LastCharCount -= 2; + if (CompressedCrc != NULL) { + *CompressedCrc = CalculateCrc16 (&LastChar, 1, *CompressedCrc); + *CompressedCrc = CalculateCrc16 (&LastChar, 1, *CompressedCrc); + *CompressedCrc = CalculateCrc16 (&LastCharCount, 1, *CompressedCrc); + } + + if (Send) { + DebugPortWriteBuffer (Handle, &LastChar, 1); + DebugPortWriteBuffer (Handle, &LastChar, 1); + DebugPortWriteBuffer (Handle, &LastCharCount, 1); + } + } + + LastCharCount = 0; + } + + LastCharCount++; + LastChar = CurrentChar; + } + + if (CompressedLength != NULL) { + *CompressedLength = CompressedIndex; + } +} + +/** + Read memory with specified width and send packet with response data to HOST. + + @param[in] Data Pointer to response data buffer. + @param[in] Count The number of data with specified Width. + @param[in] Width Data width in byte. + @param[in] DebugHeader Pointer to a buffer for creating response packet and receiving ACK packet, + to minimize the stack usage. + + @retval RETURN_SUCCESS Response data was sent successfully. + +**/ +RETURN_STATUS +ReadMemoryAndSendResponsePacket ( + IN UINT8 *Data, + IN UINT16 Count, + IN UINT8 Width, + IN DEBUG_PACKET_HEADER *DebugHeader + ) +{ + RETURN_STATUS Status; + BOOLEAN LastPacket; + DEBUG_PORT_HANDLE Handle; + UINT8 SequenceNo; + UINTN RemainingDataSize; + UINT8 CurrentDataSize; + UINTN CompressedDataSize; + + Handle = GetDebugPortHandle (); + + RemainingDataSize = Count * Width; + while (TRUE) { + SequenceNo = GetMailboxPointer ()->HostSequenceNo; + if (RemainingDataSize <= DEBUG_DATA_MAXIMUM_REAL_DATA) { + // + // If the remaining data is less one real packet size, this is the last data packet + // + CurrentDataSize = (UINT8)RemainingDataSize; + LastPacket = TRUE; + DebugHeader->Command = DEBUG_COMMAND_OK; + } else { + // + // Data is too larger to be sent in one packet, calculate the actual data size could + // be sent in one Maximum data packet + // + CurrentDataSize = (DEBUG_DATA_MAXIMUM_REAL_DATA / Width) * Width; + LastPacket = FALSE; + DebugHeader->Command = DEBUG_COMMAND_IN_PROGRESS; + } + + // + // Construct the rest Debug header + // + DebugHeader->StartSymbol = DEBUG_STARTING_SYMBOL_NORMAL; + DebugHeader->Length = CurrentDataSize + sizeof (DEBUG_PACKET_HEADER); + DebugHeader->SequenceNo = SequenceNo; + DebugHeader->Crc = 0; + CopyMemByWidth ((UINT8 *)(DebugHeader + 1), Data, CurrentDataSize / Width, Width); + + // + // Compression/decompression support was added since revision 0.4. + // Revision 0.3 shouldn't compress the packet. + // + if (PcdGet32 (PcdTransferProtocolRevision) >= DEBUG_AGENT_REVISION_04) { + // + // Get the compressed data size without modifying the packet. + // + CompressData ( + Handle, + (UINT8 *)(DebugHeader + 1), + CurrentDataSize, + FALSE, + &CompressedDataSize, + NULL + ); + } else { + CompressedDataSize = CurrentDataSize; + } + + if (CompressedDataSize < CurrentDataSize) { + DebugHeader->Length = (UINT8)CompressedDataSize + sizeof (DEBUG_PACKET_HEADER); + DebugHeader->StartSymbol = DEBUG_STARTING_SYMBOL_COMPRESS; + // + // Compute the CRC of the packet head without modifying the packet. + // + DebugHeader->Crc = CalculateCrc16 ((UINT8 *)DebugHeader, sizeof (DEBUG_PACKET_HEADER), 0); + CompressData ( + Handle, + (UINT8 *)(DebugHeader + 1), + CurrentDataSize, + FALSE, + NULL, + &DebugHeader->Crc + ); + // + // Send out the packet head. + // + DebugPortWriteBuffer (Handle, (UINT8 *)DebugHeader, sizeof (DEBUG_PACKET_HEADER)); + // + // Compress and send out the packet data. + // + CompressData ( + Handle, + (UINT8 *)(DebugHeader + 1), + CurrentDataSize, + TRUE, + NULL, + NULL + ); + } else { + // + // Calculate and fill the checksum, DebugHeader->Crc should be 0 before invoking CalculateCrc16 () + // + DebugHeader->Crc = CalculateCrc16 ((UINT8 *)DebugHeader, DebugHeader->Length, 0); + + DebugAgentDataMsgPrint (DEBUG_AGENT_VERBOSE, TRUE, (UINT8 *)DebugHeader, DebugHeader->Length); + + DebugPortWriteBuffer (Handle, (UINT8 *)DebugHeader, DebugHeader->Length); + } + + while (TRUE) { + Status = ReceivePacket ((UINT8 *)DebugHeader, NULL, NULL, READ_PACKET_TIMEOUT, FALSE); + if (Status == RETURN_TIMEOUT) { + DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "TARGET: Timeout in SendDataResponsePacket()\n"); + break; + } + + if ((DebugHeader->Command == DEBUG_COMMAND_OK) && (DebugHeader->SequenceNo == SequenceNo) && LastPacket) { + // + // If this is the last packet, return RETURN_SUCCESS. + // + return RETURN_SUCCESS; + } + + if ((DebugHeader->Command == DEBUG_COMMAND_CONTINUE) && (DebugHeader->SequenceNo == (UINT8)(SequenceNo + 1))) { + // + // Calculate the rest data size + // + Data += CurrentDataSize; + RemainingDataSize -= CurrentDataSize; + UpdateMailboxContent (GetMailboxPointer (), DEBUG_MAILBOX_HOST_SEQUENCE_NO_INDEX, DebugHeader->SequenceNo); + break; + } + + if (DebugHeader->SequenceNo >= SequenceNo) { + DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "TARGET: Received one old or new command(SequenceNo is %x, last SequenceNo is %x)\n", SequenceNo, DebugHeader->SequenceNo); + break; + } + } + } +} + +/** + Send packet with response data to HOST. + + @param[in] Data Pointer to response data buffer. + @param[in] DataSize Size of response data in byte. + @param[in, out] DebugHeader Pointer to a buffer for creating response packet and receiving ACK packet, + to minimize the stack usage. + + @retval RETURN_SUCCESS Response data was sent successfully. + +**/ +RETURN_STATUS +SendDataResponsePacket ( + IN UINT8 *Data, + IN UINT16 DataSize, + IN OUT DEBUG_PACKET_HEADER *DebugHeader + ) +{ + return ReadMemoryAndSendResponsePacket (Data, DataSize, 1, DebugHeader); +} + +/** + Try to attach the HOST. + + Send init break packet to HOST: + If no acknowledge received in specified Timeout, return RETURN_TIMEOUT. + If received acknowledge, check the revision of HOST. + Set Attach Flag if attach successfully. + + @param[in] BreakCause Break cause of this break event. + @param[in] Timeout Time out value to wait for acknowledge from HOST. + The unit is microsecond. + @param[out] BreakReceived If BreakReceived is not NULL, + TRUE is returned if break-in symbol received. + FALSE is returned if break-in symbol not received. +**/ +RETURN_STATUS +AttachHost ( + IN UINT8 BreakCause, + IN UINTN Timeout, + OUT BOOLEAN *BreakReceived + ) +{ + RETURN_STATUS Status; + DEBUG_PORT_HANDLE Handle; + BOOLEAN IncompatibilityFlag; + + IncompatibilityFlag = FALSE; + Handle = GetDebugPortHandle (); + + // + // Send init break and wait ack in Timeout + // + DebugPortWriteBuffer (Handle, (UINT8 *)mErrorMsgSendInitPacket, AsciiStrLen (mErrorMsgSendInitPacket)); + if (BreakCause == DEBUG_DATA_BREAK_CAUSE_SYSTEM_RESET) { + Status = SendCommandAndWaitForAckOK (DEBUG_COMMAND_INIT_BREAK, Timeout, BreakReceived, &IncompatibilityFlag); + } else { + Status = SendCommandAndWaitForAckOK (DEBUG_COMMAND_ATTACH_BREAK, Timeout, BreakReceived, &IncompatibilityFlag); + } + + if (IncompatibilityFlag) { + // + // If the incompatible Debug Packet received, the HOST should be running transfer protocol before PcdTransferProtocolRevision. + // It could be UDK Debugger for Windows v1.1/v1.2 or for Linux v0.8/v1.2. + // + DebugPortWriteBuffer (Handle, (UINT8 *)mErrorMsgVersionAlert, AsciiStrLen (mErrorMsgVersionAlert)); + CpuDeadLoop (); + } + + if (RETURN_ERROR (Status)) { + DebugPortWriteBuffer (Handle, (UINT8 *)mErrorMsgConnectFail, AsciiStrLen (mErrorMsgConnectFail)); + } else { + DebugPortWriteBuffer (Handle, (UINT8 *)mErrorMsgConnectOK, AsciiStrLen (mErrorMsgConnectOK)); + // + // Set Attach flag + // + SetHostAttached (TRUE); + } + + return Status; +} + +/** + Send Break point packet to HOST. + + Only the first breaking processor could sent BREAK_POINT packet. + + @param[in] BreakCause Break cause of this break event. + @param[in] ProcessorIndex Processor index value. + @param[out] BreakReceived If BreakReceived is not NULL, + TRUE is returned if break-in symbol received. + FALSE is returned if break-in symbol not received. + +**/ +VOID +SendBreakPacketToHost ( + IN UINT8 BreakCause, + IN UINT32 ProcessorIndex, + OUT BOOLEAN *BreakReceived + ) +{ + UINT8 InputCharacter; + DEBUG_PORT_HANDLE Handle; + + Handle = GetDebugPortHandle (); + + if (IsHostAttached ()) { + DebugAgentMsgPrint (DEBUG_AGENT_INFO, "processor[%x]:Send Break Packet to HOST.\n", ProcessorIndex); + SendCommandAndWaitForAckOK (DEBUG_COMMAND_BREAK_POINT, READ_PACKET_TIMEOUT, BreakReceived, NULL); + } else { + DebugAgentMsgPrint (DEBUG_AGENT_INFO, "processor[%x]:Try to attach HOST.\n", ProcessorIndex); + // + // If HOST is not attached, try to attach it firstly. + // + // + // Poll Attach symbols from HOST and ack OK + // + do { + DebugAgentReadBuffer (Handle, &InputCharacter, 1, 0); + } while (InputCharacter != DEBUG_STARTING_SYMBOL_ATTACH); + + SendAckPacket (DEBUG_COMMAND_OK); + + // + // Try to attach HOST + // + while (AttachHost (BreakCause, 0, NULL) != RETURN_SUCCESS) { + } + } +} + +/** + The main function to process communication with HOST. + + It received the command packet from HOST, and sent response data packet to HOST. + + @param[in] Vector Vector value of exception or interrupt. + @param[in, out] CpuContext Pointer to saved CPU context. + @param[in] BreakReceived TRUE means break-in symbol received. + FALSE means break-in symbol not received. + +**/ +VOID +CommandCommunication ( + IN UINTN Vector, + IN OUT DEBUG_CPU_CONTEXT *CpuContext, + IN BOOLEAN BreakReceived + ) +{ + RETURN_STATUS Status; + UINT8 InputPacketBuffer[DEBUG_DATA_UPPER_LIMIT + sizeof (UINT64) - 1]; + DEBUG_PACKET_HEADER *DebugHeader; + UINT8 Width; + UINT8 Data8; + UINT32 Data32; + UINT64 Data64; + DEBUG_DATA_READ_MEMORY *MemoryRead; + DEBUG_DATA_WRITE_MEMORY *MemoryWrite; + DEBUG_DATA_READ_IO *IoRead; + DEBUG_DATA_WRITE_IO *IoWrite; + DEBUG_DATA_READ_REGISTER *RegisterRead; + DEBUG_DATA_WRITE_REGISTER *RegisterWrite; + UINT8 *RegisterBuffer; + DEBUG_DATA_READ_MSR *MsrRegisterRead; + DEBUG_DATA_WRITE_MSR *MsrRegisterWrite; + DEBUG_DATA_CPUID *Cpuid; + DEBUG_DATA_RESPONSE_BREAK_CAUSE BreakCause; + DEBUG_DATA_RESPONSE_CPUID CpuidResponse; + DEBUG_DATA_SEARCH_SIGNATURE *SearchSignature; + DEBUG_DATA_RESPONSE_GET_EXCEPTION Exception; + DEBUG_DATA_RESPONSE_GET_REVISION DebugAgentRevision; + DEBUG_DATA_SET_VIEWPOINT *SetViewPoint; + BOOLEAN HaltDeferred; + UINT32 ProcessorIndex; + DEBUG_AGENT_EXCEPTION_BUFFER AgentExceptionBuffer; + UINT32 IssuedViewPoint; + DEBUG_AGENT_MAILBOX *Mailbox; + UINT8 *AlignedDataPtr; + + ProcessorIndex = 0; + IssuedViewPoint = 0; + HaltDeferred = BreakReceived; + + if (MultiProcessorDebugSupport ()) { + ProcessorIndex = GetProcessorIndex (); + SetCpuStopFlagByIndex (ProcessorIndex, TRUE); + if (mDebugMpContext.ViewPointIndex == ProcessorIndex) { + // + // Only the current view processor could set AgentInProgress Flag. + // + IssuedViewPoint = ProcessorIndex; + } + } + + if (IssuedViewPoint == ProcessorIndex) { + // + // Set AgentInProgress Flag. + // + SetDebugFlag (DEBUG_AGENT_FLAG_AGENT_IN_PROGRESS, 1); + } + + while (TRUE) { + if (MultiProcessorDebugSupport ()) { + // + // Check if the current processor is HOST view point + // + if (mDebugMpContext.ViewPointIndex != ProcessorIndex) { + if (mDebugMpContext.RunCommandSet) { + // + // If HOST view point sets RUN flag, run GO command to leave + // + SetCpuStopFlagByIndex (ProcessorIndex, FALSE); + CommandGo (CpuContext); + break; + } else { + // + // Run into loop again + // + CpuPause (); + continue; + } + } + } + + AcquireMpSpinLock (&mDebugMpContext.DebugPortSpinLock); + + DebugHeader = (DEBUG_PACKET_HEADER *)InputPacketBuffer; + + DebugAgentMsgPrint (DEBUG_AGENT_INFO, "TARGET: Try to get command from HOST...\n"); + Status = ReceivePacket ((UINT8 *)DebugHeader, &BreakReceived, NULL, READ_PACKET_TIMEOUT, TRUE); + if ((Status != RETURN_SUCCESS) || !IS_REQUEST (DebugHeader)) { + DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "TARGET: Get command[%x] sequenceno[%x] returned status is [%x] \n", DebugHeader->Command, DebugHeader->SequenceNo, Status); + DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "TARGET: Get command failed or it's response packet not expected! \n"); + ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock); + continue; + } + + Mailbox = GetMailboxPointer (); + if (DebugHeader->SequenceNo == Mailbox->HostSequenceNo) { + DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "TARGET: Receive one old command[%x] against command[%x]\n", DebugHeader->SequenceNo, Mailbox->HostSequenceNo); + SendAckPacket (Mailbox->LastAck); + ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock); + continue; + } else if (DebugHeader->SequenceNo == (UINT8)(Mailbox->HostSequenceNo + 1)) { + UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_HOST_SEQUENCE_NO_INDEX, (UINT8)DebugHeader->SequenceNo); + } else { + DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "Receive one invalid command[%x] against command[%x]\n", DebugHeader->SequenceNo, Mailbox->HostSequenceNo); + ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock); + continue; + } + + // + // Save CPU content before executing HOST command + // + UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_EXCEPTION_BUFFER_POINTER_INDEX, (UINT64)(UINTN)&AgentExceptionBuffer.JumpBuffer); + if (SetJump (&AgentExceptionBuffer.JumpBuffer) != 0) { + // + // If HOST command failed, continue to wait for HOST's next command + // If needed, agent could send exception info to HOST. + // + SendAckPacket (DEBUG_COMMAND_ABORT); + ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock); + continue; + } + + DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Processor[%x]:Received one command(%x)\n", mDebugMpContext.ViewPointIndex, DebugHeader->Command); + + switch (DebugHeader->Command) { + case DEBUG_COMMAND_HALT: + SendAckPacket (DEBUG_COMMAND_HALT_DEFERRED); + HaltDeferred = TRUE; + BreakReceived = FALSE; + Status = RETURN_SUCCESS; + break; + + case DEBUG_COMMAND_RESET: + SendAckPacket (DEBUG_COMMAND_OK); + SendAckPacket (DEBUG_COMMAND_OK); + SendAckPacket (DEBUG_COMMAND_OK); + ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock); + + ResetCold (); + // + // Assume system resets in 2 seconds, otherwise send TIMEOUT packet. + // PCD can be used if 2 seconds isn't long enough for some platforms. + // + MicroSecondDelay (2000000); + UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_HOST_SEQUENCE_NO_INDEX, Mailbox->HostSequenceNo + 1); + SendAckPacket (DEBUG_COMMAND_TIMEOUT); + SendAckPacket (DEBUG_COMMAND_TIMEOUT); + SendAckPacket (DEBUG_COMMAND_TIMEOUT); + break; + + case DEBUG_COMMAND_GO: + CommandGo (CpuContext); + // + // Clear Dr0 to avoid to be recognized as IMAGE_LOAD/_UNLOAD again when hitting a breakpoint after GO + // If HOST changed Dr0 before GO, we will not change Dr0 here + // + Data8 = GetBreakCause (Vector, CpuContext); + if ((Data8 == DEBUG_DATA_BREAK_CAUSE_IMAGE_LOAD) || (Data8 == DEBUG_DATA_BREAK_CAUSE_IMAGE_UNLOAD)) { + CpuContext->Dr0 = 0; + } + + if (!HaltDeferred) { + // + // If no HALT command received when being in-active mode + // + if (MultiProcessorDebugSupport ()) { + Data32 = FindNextPendingBreakCpu (); + if (Data32 != -1) { + // + // If there are still others processors being in break state, + // send OK packet to HOST to finish this go command + // + SendAckPacket (DEBUG_COMMAND_OK); + CpuPause (); + // + // Set current view to the next breaking processor + // + mDebugMpContext.ViewPointIndex = Data32; + mDebugMpContext.BreakAtCpuIndex = mDebugMpContext.ViewPointIndex; + SetCpuBreakFlagByIndex (mDebugMpContext.ViewPointIndex, FALSE); + // + // Send break packet to HOST to let HOST break again + // + SendBreakPacketToHost (DEBUG_DATA_BREAK_CAUSE_UNKNOWN, mDebugMpContext.BreakAtCpuIndex, &BreakReceived); + // + // Continue to run into loop to read command packet from HOST + // + ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock); + break; + } + + // + // If no else processor break, set stop bitmask, + // and set Running flag for all processors. + // + SetCpuStopFlagByIndex (ProcessorIndex, FALSE); + SetCpuRunningFlag (TRUE); + CpuPause (); + // + // Wait for all processors are in running state + // + while (TRUE) { + if (IsAllCpuRunning ()) { + break; + } + } + + // + // Set BSP to be current view point. + // + SetDebugViewPoint (mDebugMpContext.BspIndex); + CpuPause (); + // + // Clear breaking processor index and running flag + // + mDebugMpContext.BreakAtCpuIndex = (UINT32)(-1); + SetCpuRunningFlag (FALSE); + } + + // + // Send OK packet to HOST to finish this go command + // + SendAckPacket (DEBUG_COMMAND_OK); + + ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock); + + if (!IsHostAttached ()) { + UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_SEQUENCE_NO_INDEX, 0); + UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_HOST_SEQUENCE_NO_INDEX, 0); + } + + return; + } else { + // + // If received HALT command, need to defer the GO command + // + SendAckPacket (DEBUG_COMMAND_HALT_PROCESSED); + HaltDeferred = FALSE; + + Vector = DEBUG_TIMER_VECTOR; + } + + break; + + case DEBUG_COMMAND_BREAK_CAUSE: + BreakCause.StopAddress = CpuContext->Eip; + if (MultiProcessorDebugSupport () && (ProcessorIndex != mDebugMpContext.BreakAtCpuIndex)) { + BreakCause.Cause = GetBreakCause (DEBUG_TIMER_VECTOR, CpuContext); + } else { + BreakCause.Cause = GetBreakCause (Vector, CpuContext); + } + + SendDataResponsePacket ((UINT8 *)&BreakCause, (UINT16)sizeof (DEBUG_DATA_RESPONSE_BREAK_CAUSE), DebugHeader); + break; + + case DEBUG_COMMAND_SET_HW_BREAKPOINT: + SetDebugRegister (CpuContext, (DEBUG_DATA_SET_HW_BREAKPOINT *)(DebugHeader + 1)); + SendAckPacket (DEBUG_COMMAND_OK); + break; + + case DEBUG_COMMAND_CLEAR_HW_BREAKPOINT: + ClearDebugRegister (CpuContext, (DEBUG_DATA_CLEAR_HW_BREAKPOINT *)(DebugHeader + 1)); + SendAckPacket (DEBUG_COMMAND_OK); + break; + + case DEBUG_COMMAND_SINGLE_STEPPING: + CommandStepping (CpuContext); + // + // Clear Dr0 to avoid to be recognized as IMAGE_LOAD/_UNLOAD again when hitting a breakpoint after GO + // If HOST changed Dr0 before GO, we will not change Dr0 here + // + Data8 = GetBreakCause (Vector, CpuContext); + if ((Data8 == DEBUG_DATA_BREAK_CAUSE_IMAGE_LOAD) || (Data8 == DEBUG_DATA_BREAK_CAUSE_IMAGE_UNLOAD)) { + CpuContext->Dr0 = 0; + } + + mDebugMpContext.BreakAtCpuIndex = (UINT32)(-1); + ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock); + // + // Executing stepping command directly without sending ACK packet, + // ACK packet will be sent after stepping done. + // + return; + + case DEBUG_COMMAND_SET_SW_BREAKPOINT: + Data64 = (UINTN)(((DEBUG_DATA_SET_SW_BREAKPOINT *)(DebugHeader + 1))->Address); + Data8 = *(UINT8 *)(UINTN)Data64; + *(UINT8 *)(UINTN)Data64 = DEBUG_SW_BREAKPOINT_SYMBOL; + Status = SendDataResponsePacket ((UINT8 *)&Data8, (UINT16)sizeof (UINT8), DebugHeader); + break; + + case DEBUG_COMMAND_READ_MEMORY: + MemoryRead = (DEBUG_DATA_READ_MEMORY *)(DebugHeader + 1); + Status = ReadMemoryAndSendResponsePacket ((UINT8 *)(UINTN)MemoryRead->Address, MemoryRead->Count, MemoryRead->Width, DebugHeader); + break; + + case DEBUG_COMMAND_WRITE_MEMORY: + MemoryWrite = (DEBUG_DATA_WRITE_MEMORY *)(DebugHeader + 1); + // + // Copy data into one memory with 8-byte alignment address + // + AlignedDataPtr = ALIGN_POINTER ((UINT8 *)&MemoryWrite->Data, sizeof (UINT64)); + if (AlignedDataPtr != (UINT8 *)&MemoryWrite->Data) { + CopyMem (AlignedDataPtr, (UINT8 *)&MemoryWrite->Data, MemoryWrite->Count * MemoryWrite->Width); + } + + CopyMemByWidth ((UINT8 *)(UINTN)MemoryWrite->Address, AlignedDataPtr, MemoryWrite->Count, MemoryWrite->Width); + SendAckPacket (DEBUG_COMMAND_OK); + break; + + case DEBUG_COMMAND_READ_IO: + IoRead = (DEBUG_DATA_READ_IO *)(DebugHeader + 1); + switch (IoRead->Width) { + case 1: + Data64 = IoRead8 ((UINTN)IoRead->Port); + break; + case 2: + Data64 = IoRead16 ((UINTN)IoRead->Port); + break; + case 4: + Data64 = IoRead32 ((UINTN)IoRead->Port); + break; + case 8: + Data64 = IoRead64 ((UINTN)IoRead->Port); + break; + default: + Data64 = (UINT64)-1; + } + + Status = SendDataResponsePacket ((UINT8 *)&Data64, IoRead->Width, DebugHeader); + break; + + case DEBUG_COMMAND_WRITE_IO: + IoWrite = (DEBUG_DATA_WRITE_IO *)(DebugHeader + 1); + switch (IoWrite->Width) { + case 1: + Data64 = IoWrite8 ((UINTN)IoWrite->Port, *(UINT8 *)&IoWrite->Data); + break; + case 2: + Data64 = IoWrite16 ((UINTN)IoWrite->Port, *(UINT16 *)&IoWrite->Data); + break; + case 4: + Data64 = IoWrite32 ((UINTN)IoWrite->Port, *(UINT32 *)&IoWrite->Data); + break; + case 8: + Data64 = IoWrite64 ((UINTN)IoWrite->Port, *(UINT64 *)&IoWrite->Data); + break; + default: + Data64 = (UINT64)-1; + } + + SendAckPacket (DEBUG_COMMAND_OK); + break; + + case DEBUG_COMMAND_READ_ALL_REGISTERS: + Status = SendDataResponsePacket ((UINT8 *)CpuContext, sizeof (*CpuContext), DebugHeader); + break; + + case DEBUG_COMMAND_READ_REGISTER: + RegisterRead = (DEBUG_DATA_READ_REGISTER *)(DebugHeader + 1); + + if (RegisterRead->Index <= SOFT_DEBUGGER_REGISTER_MAX) { + RegisterBuffer = ArchReadRegisterBuffer (CpuContext, RegisterRead->Index, &Width); + Status = SendDataResponsePacket (RegisterBuffer, Width, DebugHeader); + } else { + Status = RETURN_UNSUPPORTED; + } + + break; + + case DEBUG_COMMAND_WRITE_REGISTER: + RegisterWrite = (DEBUG_DATA_WRITE_REGISTER *)(DebugHeader + 1); + if (RegisterWrite->Index <= SOFT_DEBUGGER_REGISTER_MAX) { + RegisterBuffer = ArchReadRegisterBuffer (CpuContext, RegisterWrite->Index, &Width); + ASSERT (Width == RegisterWrite->Length); + CopyMem (RegisterBuffer, RegisterWrite->Data, Width); + SendAckPacket (DEBUG_COMMAND_OK); + } else { + Status = RETURN_UNSUPPORTED; + } + + break; + + case DEBUG_COMMAND_ARCH_MODE: + Data8 = DEBUG_ARCH_SYMBOL; + Status = SendDataResponsePacket ((UINT8 *)&Data8, (UINT16)sizeof (UINT8), DebugHeader); + break; + + case DEBUG_COMMAND_READ_MSR: + MsrRegisterRead = (DEBUG_DATA_READ_MSR *)(DebugHeader + 1); + Data64 = AsmReadMsr64 (MsrRegisterRead->Index); + Status = SendDataResponsePacket ((UINT8 *)&Data64, (UINT16)sizeof (UINT64), DebugHeader); + break; + + case DEBUG_COMMAND_WRITE_MSR: + MsrRegisterWrite = (DEBUG_DATA_WRITE_MSR *)(DebugHeader + 1); + AsmWriteMsr64 (MsrRegisterWrite->Index, MsrRegisterWrite->Value); + SendAckPacket (DEBUG_COMMAND_OK); + break; + + case DEBUG_COMMAND_SET_DEBUG_SETTING: + Status = SetDebugSetting ((DEBUG_DATA_SET_DEBUG_SETTING *)(DebugHeader + 1)); + if (Status == RETURN_SUCCESS) { + SendAckPacket (DEBUG_COMMAND_OK); + } + + break; + + case DEBUG_COMMAND_GET_REVISION: + DebugAgentRevision.Revision = PcdGet32 (PcdTransferProtocolRevision); + DebugAgentRevision.Capabilities = DEBUG_AGENT_CAPABILITIES; + Status = SendDataResponsePacket ((UINT8 *)&DebugAgentRevision, (UINT16)sizeof (DEBUG_DATA_RESPONSE_GET_REVISION), DebugHeader); + break; + + case DEBUG_COMMAND_GET_EXCEPTION: + Exception.ExceptionNum = (UINT8)Vector; + Exception.ExceptionData = (UINT32)CpuContext->ExceptionData; + Status = SendDataResponsePacket ((UINT8 *)&Exception, (UINT16)sizeof (DEBUG_DATA_RESPONSE_GET_EXCEPTION), DebugHeader); + break; + + case DEBUG_COMMAND_SET_VIEWPOINT: + SetViewPoint = (DEBUG_DATA_SET_VIEWPOINT *)(DebugHeader + 1); + if (MultiProcessorDebugSupport ()) { + if (IsCpuStopped (SetViewPoint->ViewPoint)) { + SetDebugViewPoint (SetViewPoint->ViewPoint); + SendAckPacket (DEBUG_COMMAND_OK); + } else { + // + // If CPU is not halted + // + SendAckPacket (DEBUG_COMMAND_NOT_SUPPORTED); + } + } else if (SetViewPoint->ViewPoint == 0) { + SendAckPacket (DEBUG_COMMAND_OK); + } else { + SendAckPacket (DEBUG_COMMAND_NOT_SUPPORTED); + } + + break; + + case DEBUG_COMMAND_GET_VIEWPOINT: + Data32 = mDebugMpContext.ViewPointIndex; + SendDataResponsePacket ((UINT8 *)&Data32, (UINT16)sizeof (UINT32), DebugHeader); + break; + + case DEBUG_COMMAND_MEMORY_READY: + Data8 = (UINT8)GetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY); + SendDataResponsePacket (&Data8, (UINT16)sizeof (UINT8), DebugHeader); + break; + + case DEBUG_COMMAND_DETACH: + SetHostAttached (FALSE); + SendAckPacket (DEBUG_COMMAND_OK); + break; + + case DEBUG_COMMAND_CPUID: + Cpuid = (DEBUG_DATA_CPUID *)(DebugHeader + 1); + AsmCpuidEx ( + Cpuid->Eax, + Cpuid->Ecx, + &CpuidResponse.Eax, + &CpuidResponse.Ebx, + &CpuidResponse.Ecx, + &CpuidResponse.Edx + ); + SendDataResponsePacket ((UINT8 *)&CpuidResponse, (UINT16)sizeof (CpuidResponse), DebugHeader); + break; + + case DEBUG_COMMAND_SEARCH_SIGNATURE: + SearchSignature = (DEBUG_DATA_SEARCH_SIGNATURE *)(DebugHeader + 1); + if ((SearchSignature->Alignment != 0) && + (SearchSignature->Alignment == GetPowerOfTwo32 (SearchSignature->Alignment)) + ) + { + if (SearchSignature->Positive) { + for ( + Data64 = ALIGN_VALUE ((UINTN)SearchSignature->Start, SearchSignature->Alignment); + Data64 <= SearchSignature->Start + SearchSignature->Count - SearchSignature->DataLength; + Data64 += SearchSignature->Alignment + ) + { + if (CompareMem ((VOID *)(UINTN)Data64, &SearchSignature->Data, SearchSignature->DataLength) == 0) { + break; + } + } + + if (Data64 > SearchSignature->Start + SearchSignature->Count - SearchSignature->DataLength) { + Data64 = (UINT64)-1; + } + } else { + for ( + Data64 = ALIGN_VALUE ((UINTN)SearchSignature->Start - SearchSignature->Alignment, SearchSignature->Alignment); + Data64 >= SearchSignature->Start - SearchSignature->Count; + Data64 -= SearchSignature->Alignment + ) + { + if (CompareMem ((VOID *)(UINTN)Data64, &SearchSignature->Data, SearchSignature->DataLength) == 0) { + break; + } + } + + if (Data64 < SearchSignature->Start - SearchSignature->Count) { + Data64 = (UINT64)-1; + } + } + + SendDataResponsePacket ((UINT8 *)&Data64, (UINT16)sizeof (Data64), DebugHeader); + } else { + Status = RETURN_UNSUPPORTED; + } + + break; + + default: + SendAckPacket (DEBUG_COMMAND_NOT_SUPPORTED); + break; + } + + if (Status == RETURN_UNSUPPORTED) { + SendAckPacket (DEBUG_COMMAND_NOT_SUPPORTED); + } else if (Status != RETURN_SUCCESS) { + SendAckPacket (DEBUG_COMMAND_ABORT); + } + + ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock); + CpuPause (); + } +} + +/** + C function called in interrupt handler. + + @param[in] Vector Vector value of exception or interrupt. + @param[in] CpuContext Pointer to save CPU context. + +**/ +VOID +EFIAPI +InterruptProcess ( + IN UINT32 Vector, + IN DEBUG_CPU_CONTEXT *CpuContext + ) +{ + UINT8 InputCharacter; + UINT8 BreakCause; + UINTN SavedEip; + BOOLEAN BreakReceived; + UINT32 ProcessorIndex; + UINT32 CurrentDebugTimerInitCount; + DEBUG_PORT_HANDLE Handle; + UINT8 Data8; + UINT8 *Al; + UINT32 IssuedViewPoint; + DEBUG_AGENT_EXCEPTION_BUFFER *ExceptionBuffer; + + InputCharacter = 0; + ProcessorIndex = 0; + IssuedViewPoint = 0; + BreakReceived = FALSE; + + if (mSkipBreakpoint) { + // + // If Skip Breakpoint flag is set, means communication is disturbed by hardware SMI, we need to ignore the break points in SMM + // + if ((Vector == DEBUG_INT1_VECTOR) || (Vector == DEBUG_INT3_VECTOR)) { + DebugPortWriteBuffer (GetDebugPortHandle (), (UINT8 *)mWarningMsgIngoreBreakpoint, AsciiStrLen (mWarningMsgIngoreBreakpoint)); + return; + } + } + + if (MultiProcessorDebugSupport ()) { + ProcessorIndex = GetProcessorIndex (); + // + // If this processor has already halted before, need to check it later + // + if (IsCpuStopped (ProcessorIndex)) { + IssuedViewPoint = ProcessorIndex; + } + } + + if ((IssuedViewPoint == ProcessorIndex) && (GetDebugFlag (DEBUG_AGENT_FLAG_STEPPING) != 1)) { + // + // Check if this exception is issued by Debug Agent itself + // If yes, fill the debug agent exception buffer and LongJump() back to + // the saved CPU content in CommandCommunication() + // If exception is issued when executing Stepping, will be handled in + // exception handle procedure. + // + if (GetDebugFlag (DEBUG_AGENT_FLAG_AGENT_IN_PROGRESS) == 1) { + DebugAgentMsgPrint ( + DEBUG_AGENT_ERROR, + "Debug agent meet one Exception, ExceptionNum is %d, EIP = 0x%x.\n", + Vector, + (UINTN)CpuContext->Eip + ); + ExceptionBuffer = (DEBUG_AGENT_EXCEPTION_BUFFER *)(UINTN)GetMailboxPointer ()->ExceptionBufferPointer; + ExceptionBuffer->ExceptionContent.ExceptionNum = (UINT8)Vector; + ExceptionBuffer->ExceptionContent.ExceptionData = (UINT32)CpuContext->ExceptionData; + LongJump ((BASE_LIBRARY_JUMP_BUFFER *)(UINTN)(ExceptionBuffer), 1); + } + } + + if (MultiProcessorDebugSupport ()) { + // + // If RUN command is executing, wait for it done. + // + while (mDebugMpContext.RunCommandSet) { + CpuPause (); + } + } + + Handle = GetDebugPortHandle (); + BreakCause = GetBreakCause (Vector, CpuContext); + switch (Vector) { + case DEBUG_INT1_VECTOR: + case DEBUG_INT3_VECTOR: + switch (BreakCause) { + case DEBUG_DATA_BREAK_CAUSE_SYSTEM_RESET: + if (AttachHost (BreakCause, READ_PACKET_TIMEOUT, &BreakReceived) != RETURN_SUCCESS) { + // + // Try to connect HOST, return if fails + // + break; + } + + CommandCommunication (Vector, CpuContext, BreakReceived); + break; + + case DEBUG_DATA_BREAK_CAUSE_STEPPING: + // + // Stepping is finished, send Ack package. + // + if (MultiProcessorDebugSupport ()) { + mDebugMpContext.BreakAtCpuIndex = ProcessorIndex; + } + + // + // Clear Stepping Flag and restore EFLAGS.IF + // + CommandSteppingCleanup (CpuContext); + SendAckPacket (DEBUG_COMMAND_OK); + CommandCommunication (Vector, CpuContext, BreakReceived); + break; + + case DEBUG_DATA_BREAK_CAUSE_MEMORY_READY: + // + // Memory is ready + // + SendCommandAndWaitForAckOK (DEBUG_COMMAND_MEMORY_READY, READ_PACKET_TIMEOUT, &BreakReceived, NULL); + CommandCommunication (Vector, CpuContext, BreakReceived); + break; + + case DEBUG_DATA_BREAK_CAUSE_IMAGE_LOAD: + case DEBUG_DATA_BREAK_CAUSE_IMAGE_UNLOAD: + // + // Set AL to DEBUG_AGENT_IMAGE_CONTINUE + // + Al = ArchReadRegisterBuffer (CpuContext, SOFT_DEBUGGER_REGISTER_AX, &Data8); + *Al = DEBUG_AGENT_IMAGE_CONTINUE; + + if (!IsHostAttached ()) { + // + // If HOST is not connected for image load/unload, return + // + break; + } + + // + // Continue to run the following common code + // + + case DEBUG_DATA_BREAK_CAUSE_HW_BREAKPOINT: + case DEBUG_DATA_BREAK_CAUSE_SW_BREAKPOINT: + default: + // + // Send Break packet to HOST + // + AcquireMpSpinLock (&mDebugMpContext.DebugPortSpinLock); + // + // Only the first breaking processor could send BREAK_POINT to HOST + // + if (IsFirstBreakProcessor (ProcessorIndex)) { + SendBreakPacketToHost (BreakCause, ProcessorIndex, &BreakReceived); + } + + ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock); + + if (Vector == DEBUG_INT3_VECTOR) { + // + // go back address located "0xCC" + // + CpuContext->Eip--; + SavedEip = CpuContext->Eip; + CommandCommunication (Vector, CpuContext, BreakReceived); + if ((SavedEip == CpuContext->Eip) && + (*(UINT8 *)(UINTN)CpuContext->Eip == DEBUG_SW_BREAKPOINT_SYMBOL)) + { + // + // If this is not a software breakpoint set by HOST, + // restore EIP + // + CpuContext->Eip++; + } + } else { + CommandCommunication (Vector, CpuContext, BreakReceived); + } + + break; + } + + break; + + case DEBUG_TIMER_VECTOR: + + AcquireMpSpinLock (&mDebugMpContext.DebugPortSpinLock); + + if (MultiProcessorDebugSupport ()) { + if (DebugAgentIsBsp (ProcessorIndex)) { + // + // If current processor is BSP, check Apic timer's init count if changed, + // it may be re-written when switching BSP. + // If it changed, re-initialize debug timer + // + CurrentDebugTimerInitCount = GetApicTimerInitCount (); + if (mDebugMpContext.DebugTimerInitCount != CurrentDebugTimerInitCount) { + InitializeDebugTimer (NULL, FALSE); + SaveAndSetDebugTimerInterrupt (TRUE); + } + } + + if (!DebugAgentIsBsp (ProcessorIndex) || mDebugMpContext.IpiSentByAp) { + ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock); + // + // If current processor is not BSP or this is one IPI sent by AP + // + if (mDebugMpContext.BreakAtCpuIndex != (UINT32)(-1)) { + CommandCommunication (Vector, CpuContext, FALSE); + } + + // + // Clear EOI before exiting interrupt process routine. + // + SendApicEoi (); + break; + } + } + + // + // Only BSP could run here + // + while (TRUE) { + // + // If there is data in debug port, will check whether it is break(attach/break-in) symbol, + // If yes, go into communication mode with HOST. + // If no, exit interrupt process. + // + if (DebugReadBreakSymbol (Handle, &InputCharacter) == EFI_NOT_FOUND) { + break; + } + + if ((!IsHostAttached () && (InputCharacter == DEBUG_STARTING_SYMBOL_ATTACH)) || + (IsHostAttached () && (InputCharacter == DEBUG_COMMAND_HALT)) || + (IsHostAttached () && (InputCharacter == DEBUG_COMMAND_GO)) + ) + { + DebugAgentMsgPrint (DEBUG_AGENT_VERBOSE, "Received data [%02x]\n", InputCharacter); + // + // Ack OK for break-in symbol + // + SendAckPacket (DEBUG_COMMAND_OK); + + // + // If receive GO command in Debug Timer, means HOST may lost ACK packet before. + // + if (InputCharacter == DEBUG_COMMAND_GO) { + break; + } + + if (!IsHostAttached ()) { + // + // Try to attach HOST, if no ack received after 200ms, return + // + if (AttachHost (BreakCause, READ_PACKET_TIMEOUT, &BreakReceived) != RETURN_SUCCESS) { + break; + } + } + + if (MultiProcessorDebugSupport ()) { + if (FindNextPendingBreakCpu () != -1) { + SetCpuBreakFlagByIndex (ProcessorIndex, TRUE); + } else { + HaltOtherProcessors (ProcessorIndex); + } + } + + ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock); + CommandCommunication (Vector, CpuContext, BreakReceived); + AcquireMpSpinLock (&mDebugMpContext.DebugPortSpinLock); + break; + } + } + + // + // Clear EOI before exiting interrupt process routine. + // + SendApicEoi (); + + ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock); + + break; + + default: + if (Vector <= DEBUG_EXCEPT_SIMD) { + DebugAgentMsgPrint ( + DEBUG_AGENT_ERROR, + "Exception happened, ExceptionNum is %d, EIP = 0x%x.\n", + Vector, + (UINTN)CpuContext->Eip + ); + if (BreakCause == DEBUG_DATA_BREAK_CAUSE_STEPPING) { + // + // If exception happened when executing Stepping, send Ack package. + // HOST consider Stepping command was finished. + // + if (MultiProcessorDebugSupport ()) { + mDebugMpContext.BreakAtCpuIndex = ProcessorIndex; + } + + // + // Clear Stepping flag and restore EFLAGS.IF + // + CommandSteppingCleanup (CpuContext); + SendAckPacket (DEBUG_COMMAND_OK); + } else { + // + // Exception occurs, send Break packet to HOST + // + AcquireMpSpinLock (&mDebugMpContext.DebugPortSpinLock); + // + // Only the first breaking processor could send BREAK_POINT to HOST + // + if (IsFirstBreakProcessor (ProcessorIndex)) { + SendBreakPacketToHost (BreakCause, ProcessorIndex, &BreakReceived); + } + + ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock); + } + + CommandCommunication (Vector, CpuContext, BreakReceived); + } + + break; + } + + if (MultiProcessorDebugSupport ()) { + // + // Clear flag and wait for all processors run here + // + SetIpiSentByApFlag (FALSE); + while (mDebugMpContext.RunCommandSet) { + CpuPause (); + } + + // + // Only current (view) processor could clean up AgentInProgress flag. + // + if (mDebugMpContext.ViewPointIndex == ProcessorIndex) { + IssuedViewPoint = mDebugMpContext.ViewPointIndex; + } + } + + if ((IssuedViewPoint == ProcessorIndex) && (GetDebugFlag (DEBUG_AGENT_FLAG_STEPPING) != 1)) { + // + // If the command is not stepping, clean up AgentInProgress flag + // + SetDebugFlag (DEBUG_AGENT_FLAG_AGENT_IN_PROGRESS, 0); + } + + return; +} diff --git a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.h b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.h index 4c72f8f3a9..0e14bcde55 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.h +++ b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.h @@ -1,496 +1,496 @@ -/** @file
- Command header of for Debug Agent library instance.
-
- Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _DEBUG_AGENT_H_
-#define _DEBUG_AGENT_H_
-
-#include <Register/LocalApic.h>
-#include <Guid/DebugAgentGuid.h>
-#include <Guid/VectorHandoffTable.h>
-#include <Ppi/VectorHandoffInfo.h>
-#include <Library/BaseLib.h>
-#include <Library/BaseMemoryLib.h>
-#include <Library/ResetSystemLib.h>
-#include <Library/IoLib.h>
-#include <Library/HobLib.h>
-#include <Library/DebugCommunicationLib.h>
-#include <Library/DebugAgentLib.h>
-#include <Library/PcdLib.h>
-#include <Library/SynchronizationLib.h>
-#include <Library/LocalApicLib.h>
-#include <Library/DebugLib.h>
-#include <Library/TimerLib.h>
-#include <Library/PrintLib.h>
-#include <Library/PeCoffGetEntryPointLib.h>
-#include <Library/PeCoffExtraActionLib.h>
-#include <Register/ArchitecturalMsr.h>
-
-#include <TransferProtocol.h>
-#include <ImageDebugSupport.h>
-
-#include "DebugMp.h"
-#include "DebugTimer.h"
-#include "ArchDebugSupport.h"
-#include "DebugException.h"
-
-//
-// These macros may be already defined in DebugAgentLib.h
-//
-#define DEBUG_AGENT_INIT_PEI 9
-#define DEBUG_AGENT_INIT_DXE_LOAD 10
-#define DEBUG_AGENT_INIT_DXE_UNLOAD 11
-#define DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64 12
-
-#define DEBUG_INT1_VECTOR DEBUG_EXCEPT_DEBUG
-#define DEBUG_INT3_VECTOR DEBUG_EXCEPT_BREAKPOINT
-#define DEBUG_TIMER_VECTOR 32
-#define DEBUG_MAILBOX_VECTOR 33
-
-//
-// Timeout value for reading packet (unit is microsecond)
-//
-#define READ_PACKET_TIMEOUT (500 * 1000)
-#define DEBUG_TIMER_INTERVAL (100 * 1000)
-
-#define SOFT_INTERRUPT_SIGNATURE SIGNATURE_32('S','O','F','T')
-#define SYSTEM_RESET_SIGNATURE SIGNATURE_32('S','Y','S','R')
-#define MEMORY_READY_SIGNATURE SIGNATURE_32('M','E','M','R')
-
-extern UINTN Exception0Handle;
-extern UINTN TimerInterruptHandle;
-extern UINT32 ExceptionStubHeaderSize;
-extern BOOLEAN mSkipBreakpoint;
-extern EFI_VECTOR_HANDOFF_INFO mVectorHandoffInfoDebugAgent[];
-extern UINTN mVectorHandoffInfoCount;
-
-//
-// CPU exception information issued by debug agent
-//
-typedef struct {
- //
- // This field is used to save CPU content before executing HOST command
- //
- BASE_LIBRARY_JUMP_BUFFER JumpBuffer;
- //
- // This field returns the exception information issued by the HOST command
- //
- DEBUG_DATA_RESPONSE_GET_EXCEPTION ExceptionContent;
-} DEBUG_AGENT_EXCEPTION_BUFFER;
-
-#define DEBUG_AGENT_FLAG_HOST_ATTACHED BIT0
-#define DEBUG_AGENT_FLAG_AGENT_IN_PROGRESS BIT1
-#define DEBUG_AGENT_FLAG_MEMORY_READY BIT2
-#define DEBUG_AGENT_FLAG_STEPPING BIT3
-#define DEBUG_AGENT_FLAG_CHECK_MAILBOX_IN_HOB BIT4
-#define DEBUG_AGENT_FLAG_INIT_ARCH BIT5|BIT6
-#define DEBUG_AGENT_FLAG_INTERRUPT_FLAG BIT7
-#define DEBUG_AGENT_FLAG_BREAK_ON_NEXT_SMI BIT32
-#define DEBUG_AGENT_FLAG_PRINT_ERROR_LEVEL (BIT33|BIT34|BIT35|BIT36)
-#define DEBUG_AGENT_FLAG_BREAK_BOOT_SCRIPT BIT37
-
-#define DEBUG_MAILBOX_DEBUG_FLAG_INDEX 1
-#define DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX 2
-#define DEBUG_MAILBOX_EXCEPTION_BUFFER_POINTER_INDEX 3
-#define DEBUG_MAILBOX_LAST_ACK 4
-#define DEBUG_MAILBOX_SEQUENCE_NO_INDEX 5
-#define DEBUG_MAILBOX_HOST_SEQUENCE_NO_INDEX 6
-#define DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY 7
-
-#pragma pack(1)
-typedef union {
- struct {
- //
- // Lower 32 bits to store the status of DebugAgent
- //
- UINT32 HostAttached : 1; // 1: HOST is attached
- UINT32 AgentInProgress : 1; // 1: Debug Agent is communicating with HOST
- UINT32 MemoryReady : 1; // 1: Memory is ready
- UINT32 SteppingFlag : 1; // 1: Agent is running stepping command
- UINT32 CheckMailboxInHob : 1; // 1: Need to check mailbox saved in HOB
- UINT32 InitArch : 2; // value of DEBUG_DATA_RESPONSE_ARCH_MODE
- UINT32 InterruptFlag : 1; // 1: EFLAGS.IF is set
- UINT32 Reserved1 : 24;
- //
- // Higher 32bits to control the behavior of DebugAgent
- //
- UINT32 BreakOnNextSmi : 1; // 1: Break on next SMI
- UINT32 PrintErrorLevel : 4; // Bitmask of print error level for debug message
- UINT32 BreakOnBootScript : 1; // 1: Break before executing boot script
- UINT32 Reserved2 : 26;
- } Bits;
- UINT64 Uint64;
-} DEBUG_AGENT_FLAG;
-
-typedef struct {
- DEBUG_AGENT_FLAG DebugFlag;
- UINT64 DebugPortHandle;
- //
- // Pointer to DEBUG_AGENT_EXCEPTION_BUFFER
- //
- UINT64 ExceptionBufferPointer;
- UINT8 LastAck; // The last ack packet type
- UINT8 SequenceNo;
- UINT8 HostSequenceNo;
- UINT32 DebugTimerFrequency;
- UINT8 CheckSum; // Mailbox checksum
- UINT8 ToBeCheckSum; // To be Mailbox checksum at the next
-} DEBUG_AGENT_MAILBOX;
-#pragma pack()
-
-///
-/// Byte packed structure for an IA-32 Interrupt Gate Descriptor.
-///
-typedef union {
- struct {
- UINT32 OffsetLow : 16; ///< Offset bits 15..0.
- UINT32 Selector : 16; ///< Selector.
- UINT32 Reserved_0 : 8; ///< Reserved.
- UINT32 GateType : 8; ///< Gate Type. See #defines above.
- UINT32 OffsetHigh : 16; ///< Offset bits 31..16.
- } Bits;
- UINT64 Uint64;
-} IA32_IDT_ENTRY;
-
-typedef union {
- struct {
- UINT32 LimitLow : 16;
- UINT32 BaseLow : 16;
- UINT32 BaseMid : 8;
- UINT32 Type : 4;
- UINT32 System : 1;
- UINT32 Dpl : 2;
- UINT32 Present : 1;
- UINT32 LimitHigh : 4;
- UINT32 Software : 1;
- UINT32 Reserved : 1;
- UINT32 DefaultSize : 1;
- UINT32 Granularity : 1;
- UINT32 BaseHigh : 8;
- } Bits;
- UINT64 Uint64;
-} IA32_GDT;
-
-/**
- Initialize IDT entries to support source level debug.
-
-**/
-VOID
-InitializeDebugIdt (
- VOID
- );
-
-/**
- Read register value from saved CPU context.
-
- @param[in] CpuContext Pointer to saved CPU context.
- @param[in] Index Register index value.
- @param[in] Width Data width to read.
-
- @return The address of register value.
-
-**/
-UINT8 *
-ArchReadRegisterBuffer (
- IN DEBUG_CPU_CONTEXT *CpuContext,
- IN UINT8 Index,
- IN UINT8 *Width
- );
-
-/**
- Send packet with response data to HOST.
-
- @param[in] Data Pointer to response data buffer.
- @param[in] DataSize Size of response data in byte.
- @param[in, out] DebugHeader Pointer to a buffer for creating response packet and receiving ACK packet,
- to minimize the stack usage.
-
- @retval RETURN_SUCCESS Response data was sent successfully.
- @retval RETURN_DEVICE_ERROR Cannot receive DEBUG_COMMAND_OK from HOST.
-
-**/
-RETURN_STATUS
-SendDataResponsePacket (
- IN UINT8 *Data,
- IN UINT16 DataSize,
- IN OUT DEBUG_PACKET_HEADER *DebugHeader
- );
-
-/**
- Check if HOST is attached based on Mailbox.
-
- @retval TRUE HOST is attached.
- @retval FALSE HOST is not attached.
-
-**/
-BOOLEAN
-IsHostAttached (
- VOID
- );
-
-/**
- Get Debug Agent Mailbox pointer.
-
- @return Mailbox pointer.
-
-**/
-DEBUG_AGENT_MAILBOX *
-GetMailboxPointer (
- VOID
- );
-
-/**
- Get debug port handle.
-
- @return Debug port handle.
-
-**/
-DEBUG_PORT_HANDLE
-GetDebugPortHandle (
- VOID
- );
-
-/**
- Read the Attach/Break-in symbols from the debug port.
-
- @param[in] Handle Pointer to Debug Port handle.
- @param[out] BreakSymbol Returned break symbol.
-
- @retval EFI_SUCCESS Read the symbol in BreakSymbol.
- @retval EFI_NOT_FOUND No read the break symbol.
-
-**/
-EFI_STATUS
-DebugReadBreakSymbol (
- IN DEBUG_PORT_HANDLE Handle,
- OUT UINT8 *BreakSymbol
- );
-
-/**
- Prints a debug message to the debug port if the specified error level is enabled.
-
- If any bit in ErrorLevel is also set in Mainbox, then print the message specified
- by Format and the associated variable argument list to the debug port.
-
- @param[in] ErrorLevel The error level of the debug message.
- @param[in] Format Format string for the debug message to print.
- @param[in] ... Variable argument list whose contents are accessed
- based on the format string specified by Format.
-
-**/
-VOID
-EFIAPI
-DebugAgentMsgPrint (
- IN UINT8 ErrorLevel,
- IN CHAR8 *Format,
- ...
- );
-
-/**
- Trigger one software interrupt to debug agent to handle it.
-
- @param[in] Signature Software interrupt signature.
-
-**/
-VOID
-TriggerSoftInterrupt (
- IN UINT32 Signature
- );
-
-/**
- Check if debug agent support multi-processor.
-
- @retval TRUE Multi-processor is supported.
- @retval FALSE Multi-processor is not supported.
-
-**/
-BOOLEAN
-MultiProcessorDebugSupport (
- VOID
- );
-
-/**
- Find and report module image info to HOST.
-
- @param[in] AlignSize Image aligned size.
-
-**/
-VOID
-FindAndReportModuleImageInfo (
- IN UINTN AlignSize
- );
-
-/**
- Read IDT entry to check if IDT entries are setup by Debug Agent.
-
- @retval TRUE IDT entries were setup by Debug Agent.
- @retval FALSE IDT entries were not setup by Debug Agent.
-
-**/
-BOOLEAN
-IsDebugAgentInitialzed (
- VOID
- );
-
-/**
- Calculate Mailbox checksum and update the checksum field.
-
- @param[in] Mailbox Debug Agent Mailbox pointer.
-
-**/
-VOID
-UpdateMailboxChecksum (
- IN DEBUG_AGENT_MAILBOX *Mailbox
- );
-
-/**
- Verify Mailbox checksum.
-
- If checksum error, print debug message and run init dead loop.
-
- @param[in] Mailbox Debug Agent Mailbox pointer.
-
-**/
-VOID
-VerifyMailboxChecksum (
- IN DEBUG_AGENT_MAILBOX *Mailbox
- );
-
-/**
- Set debug flag in mailbox.
-
- @param[in] FlagMask Debug flag mask value.
- @param[in] FlagValue Debug flag value.
-
-**/
-VOID
-SetDebugFlag (
- IN UINT64 FlagMask,
- IN UINT32 FlagValue
- );
-
-/**
- Get debug flag in mailbox.
-
- @param[in] FlagMask Debug flag mask value.
-
- @return Debug flag value.
-
-**/
-UINT32
-GetDebugFlag (
- IN UINT64 FlagMask
- );
-
-/**
- Update Mailbox content by index.
-
- @param[in] Mailbox Debug Agent Mailbox pointer.
- @param[in] Index Mailbox content index.
- @param[in] Value Value to be set into mail box.
-
-**/
-VOID
-UpdateMailboxContent (
- IN DEBUG_AGENT_MAILBOX *Mailbox,
- IN UINTN Index,
- IN UINT64 Value
- );
-
-/**
- Retrieve exception handler from IDT table by ExceptionNum.
-
- @param[in] ExceptionNum Exception number
-
- @return Exception handler
-
-**/
-VOID *
-GetExceptionHandlerInIdtEntry (
- IN UINTN ExceptionNum
- );
-
-/**
- Set exception handler in IDT table by ExceptionNum.
-
- @param[in] ExceptionNum Exception number
- @param[in] ExceptionHandler Exception Handler to be set
-
-**/
-VOID
-SetExceptionHandlerInIdtEntry (
- IN UINTN ExceptionNum,
- IN VOID *ExceptionHandler
- );
-
-/**
- Prints a debug message to the debug output device if the specified error level is enabled.
-
- If any bit in ErrorLevel is also set in DebugPrintErrorLevelLib function
- GetDebugPrintErrorLevel (), then print the message specified by Format and the
- associated variable argument list to the debug output device.
-
- If Format is NULL, then ASSERT().
-
- @param[in] ErrorLevel The error level of the debug message.
- @param[in] IsSend Flag of debug message to declare that the data is being sent or being received.
- @param[in] Data Variable argument list whose contents are accessed
- @param[in] Length based on the format string specified by Format.
-
-**/
-VOID
-EFIAPI
-DebugAgentDataMsgPrint (
- IN UINT8 ErrorLevel,
- IN BOOLEAN IsSend,
- IN UINT8 *Data,
- IN UINT8 Length
- );
-
-/**
- Read remaining debug packet except for the start symbol
-
- @param[in] Handle Pointer to Debug Port handle.
- @param[in, out] DebugHeader Debug header buffer including start symbol.
-
- @retval EFI_SUCCESS Read the symbol in BreakSymbol.
- @retval EFI_CRC_ERROR CRC check fail.
- @retval EFI_TIMEOUT Timeout occurs when reading debug packet.
-
-**/
-EFI_STATUS
-ReadRemainingBreakPacket (
- IN DEBUG_PORT_HANDLE Handle,
- IN OUT DEBUG_PACKET_HEADER *DebugHeader
- );
-
-/**
- Read data from debug channel and save the data in buffer.
-
- Reads NumberOfBytes data bytes from a debug device into the buffer
- specified by Buffer. The number of bytes actually read is returned.
- If the return value is less than NumberOfBytes, then the rest operation failed.
- If NumberOfBytes is zero, then return 0.
-
- @param Handle Debug port handle.
- @param Buffer Pointer to the data buffer to store the data read from the debug device.
- @param NumberOfBytes Number of bytes which will be read.
- @param Timeout Timeout value for reading from debug device. It unit is Microsecond.
-
- @retval 0 Read data failed, no data is to be read.
- @retval >0 Actual number of bytes read from debug device.
-
-**/
-UINTN
-DebugAgentReadBuffer (
- IN DEBUG_PORT_HANDLE Handle,
- IN OUT UINT8 *Buffer,
- IN UINTN NumberOfBytes,
- IN UINTN Timeout
- );
-
-#endif
+/** @file + Command header of for Debug Agent library instance. + + Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _DEBUG_AGENT_H_ +#define _DEBUG_AGENT_H_ + +#include <Register/LocalApic.h> +#include <Guid/DebugAgentGuid.h> +#include <Guid/VectorHandoffTable.h> +#include <Ppi/VectorHandoffInfo.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/ResetSystemLib.h> +#include <Library/IoLib.h> +#include <Library/HobLib.h> +#include <Library/DebugCommunicationLib.h> +#include <Library/DebugAgentLib.h> +#include <Library/PcdLib.h> +#include <Library/SynchronizationLib.h> +#include <Library/LocalApicLib.h> +#include <Library/DebugLib.h> +#include <Library/TimerLib.h> +#include <Library/PrintLib.h> +#include <Library/PeCoffGetEntryPointLib.h> +#include <Library/PeCoffExtraActionLib.h> +#include <Register/ArchitecturalMsr.h> + +#include <TransferProtocol.h> +#include <ImageDebugSupport.h> + +#include "DebugMp.h" +#include "DebugTimer.h" +#include "ArchDebugSupport.h" +#include "DebugException.h" + +// +// These macros may be already defined in DebugAgentLib.h +// +#define DEBUG_AGENT_INIT_PEI 9 +#define DEBUG_AGENT_INIT_DXE_LOAD 10 +#define DEBUG_AGENT_INIT_DXE_UNLOAD 11 +#define DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64 12 + +#define DEBUG_INT1_VECTOR DEBUG_EXCEPT_DEBUG +#define DEBUG_INT3_VECTOR DEBUG_EXCEPT_BREAKPOINT +#define DEBUG_TIMER_VECTOR 32 +#define DEBUG_MAILBOX_VECTOR 33 + +// +// Timeout value for reading packet (unit is microsecond) +// +#define READ_PACKET_TIMEOUT (500 * 1000) +#define DEBUG_TIMER_INTERVAL (100 * 1000) + +#define SOFT_INTERRUPT_SIGNATURE SIGNATURE_32('S','O','F','T') +#define SYSTEM_RESET_SIGNATURE SIGNATURE_32('S','Y','S','R') +#define MEMORY_READY_SIGNATURE SIGNATURE_32('M','E','M','R') + +extern UINTN Exception0Handle; +extern UINTN TimerInterruptHandle; +extern UINT32 ExceptionStubHeaderSize; +extern BOOLEAN mSkipBreakpoint; +extern EFI_VECTOR_HANDOFF_INFO mVectorHandoffInfoDebugAgent[]; +extern UINTN mVectorHandoffInfoCount; + +// +// CPU exception information issued by debug agent +// +typedef struct { + // + // This field is used to save CPU content before executing HOST command + // + BASE_LIBRARY_JUMP_BUFFER JumpBuffer; + // + // This field returns the exception information issued by the HOST command + // + DEBUG_DATA_RESPONSE_GET_EXCEPTION ExceptionContent; +} DEBUG_AGENT_EXCEPTION_BUFFER; + +#define DEBUG_AGENT_FLAG_HOST_ATTACHED BIT0 +#define DEBUG_AGENT_FLAG_AGENT_IN_PROGRESS BIT1 +#define DEBUG_AGENT_FLAG_MEMORY_READY BIT2 +#define DEBUG_AGENT_FLAG_STEPPING BIT3 +#define DEBUG_AGENT_FLAG_CHECK_MAILBOX_IN_HOB BIT4 +#define DEBUG_AGENT_FLAG_INIT_ARCH BIT5|BIT6 +#define DEBUG_AGENT_FLAG_INTERRUPT_FLAG BIT7 +#define DEBUG_AGENT_FLAG_BREAK_ON_NEXT_SMI BIT32 +#define DEBUG_AGENT_FLAG_PRINT_ERROR_LEVEL (BIT33|BIT34|BIT35|BIT36) +#define DEBUG_AGENT_FLAG_BREAK_BOOT_SCRIPT BIT37 + +#define DEBUG_MAILBOX_DEBUG_FLAG_INDEX 1 +#define DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX 2 +#define DEBUG_MAILBOX_EXCEPTION_BUFFER_POINTER_INDEX 3 +#define DEBUG_MAILBOX_LAST_ACK 4 +#define DEBUG_MAILBOX_SEQUENCE_NO_INDEX 5 +#define DEBUG_MAILBOX_HOST_SEQUENCE_NO_INDEX 6 +#define DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY 7 + +#pragma pack(1) +typedef union { + struct { + // + // Lower 32 bits to store the status of DebugAgent + // + UINT32 HostAttached : 1; // 1: HOST is attached + UINT32 AgentInProgress : 1; // 1: Debug Agent is communicating with HOST + UINT32 MemoryReady : 1; // 1: Memory is ready + UINT32 SteppingFlag : 1; // 1: Agent is running stepping command + UINT32 CheckMailboxInHob : 1; // 1: Need to check mailbox saved in HOB + UINT32 InitArch : 2; // value of DEBUG_DATA_RESPONSE_ARCH_MODE + UINT32 InterruptFlag : 1; // 1: EFLAGS.IF is set + UINT32 Reserved1 : 24; + // + // Higher 32bits to control the behavior of DebugAgent + // + UINT32 BreakOnNextSmi : 1; // 1: Break on next SMI + UINT32 PrintErrorLevel : 4; // Bitmask of print error level for debug message + UINT32 BreakOnBootScript : 1; // 1: Break before executing boot script + UINT32 Reserved2 : 26; + } Bits; + UINT64 Uint64; +} DEBUG_AGENT_FLAG; + +typedef struct { + DEBUG_AGENT_FLAG DebugFlag; + UINT64 DebugPortHandle; + // + // Pointer to DEBUG_AGENT_EXCEPTION_BUFFER + // + UINT64 ExceptionBufferPointer; + UINT8 LastAck; // The last ack packet type + UINT8 SequenceNo; + UINT8 HostSequenceNo; + UINT32 DebugTimerFrequency; + UINT8 CheckSum; // Mailbox checksum + UINT8 ToBeCheckSum; // To be Mailbox checksum at the next +} DEBUG_AGENT_MAILBOX; +#pragma pack() + +/// +/// Byte packed structure for an IA-32 Interrupt Gate Descriptor. +/// +typedef union { + struct { + UINT32 OffsetLow : 16; ///< Offset bits 15..0. + UINT32 Selector : 16; ///< Selector. + UINT32 Reserved_0 : 8; ///< Reserved. + UINT32 GateType : 8; ///< Gate Type. See #defines above. + UINT32 OffsetHigh : 16; ///< Offset bits 31..16. + } Bits; + UINT64 Uint64; +} IA32_IDT_ENTRY; + +typedef union { + struct { + UINT32 LimitLow : 16; + UINT32 BaseLow : 16; + UINT32 BaseMid : 8; + UINT32 Type : 4; + UINT32 System : 1; + UINT32 Dpl : 2; + UINT32 Present : 1; + UINT32 LimitHigh : 4; + UINT32 Software : 1; + UINT32 Reserved : 1; + UINT32 DefaultSize : 1; + UINT32 Granularity : 1; + UINT32 BaseHigh : 8; + } Bits; + UINT64 Uint64; +} IA32_GDT; + +/** + Initialize IDT entries to support source level debug. + +**/ +VOID +InitializeDebugIdt ( + VOID + ); + +/** + Read register value from saved CPU context. + + @param[in] CpuContext Pointer to saved CPU context. + @param[in] Index Register index value. + @param[in] Width Data width to read. + + @return The address of register value. + +**/ +UINT8 * +ArchReadRegisterBuffer ( + IN DEBUG_CPU_CONTEXT *CpuContext, + IN UINT8 Index, + IN UINT8 *Width + ); + +/** + Send packet with response data to HOST. + + @param[in] Data Pointer to response data buffer. + @param[in] DataSize Size of response data in byte. + @param[in, out] DebugHeader Pointer to a buffer for creating response packet and receiving ACK packet, + to minimize the stack usage. + + @retval RETURN_SUCCESS Response data was sent successfully. + @retval RETURN_DEVICE_ERROR Cannot receive DEBUG_COMMAND_OK from HOST. + +**/ +RETURN_STATUS +SendDataResponsePacket ( + IN UINT8 *Data, + IN UINT16 DataSize, + IN OUT DEBUG_PACKET_HEADER *DebugHeader + ); + +/** + Check if HOST is attached based on Mailbox. + + @retval TRUE HOST is attached. + @retval FALSE HOST is not attached. + +**/ +BOOLEAN +IsHostAttached ( + VOID + ); + +/** + Get Debug Agent Mailbox pointer. + + @return Mailbox pointer. + +**/ +DEBUG_AGENT_MAILBOX * +GetMailboxPointer ( + VOID + ); + +/** + Get debug port handle. + + @return Debug port handle. + +**/ +DEBUG_PORT_HANDLE +GetDebugPortHandle ( + VOID + ); + +/** + Read the Attach/Break-in symbols from the debug port. + + @param[in] Handle Pointer to Debug Port handle. + @param[out] BreakSymbol Returned break symbol. + + @retval EFI_SUCCESS Read the symbol in BreakSymbol. + @retval EFI_NOT_FOUND No read the break symbol. + +**/ +EFI_STATUS +DebugReadBreakSymbol ( + IN DEBUG_PORT_HANDLE Handle, + OUT UINT8 *BreakSymbol + ); + +/** + Prints a debug message to the debug port if the specified error level is enabled. + + If any bit in ErrorLevel is also set in Mainbox, then print the message specified + by Format and the associated variable argument list to the debug port. + + @param[in] ErrorLevel The error level of the debug message. + @param[in] Format Format string for the debug message to print. + @param[in] ... Variable argument list whose contents are accessed + based on the format string specified by Format. + +**/ +VOID +EFIAPI +DebugAgentMsgPrint ( + IN UINT8 ErrorLevel, + IN CHAR8 *Format, + ... + ); + +/** + Trigger one software interrupt to debug agent to handle it. + + @param[in] Signature Software interrupt signature. + +**/ +VOID +TriggerSoftInterrupt ( + IN UINT32 Signature + ); + +/** + Check if debug agent support multi-processor. + + @retval TRUE Multi-processor is supported. + @retval FALSE Multi-processor is not supported. + +**/ +BOOLEAN +MultiProcessorDebugSupport ( + VOID + ); + +/** + Find and report module image info to HOST. + + @param[in] AlignSize Image aligned size. + +**/ +VOID +FindAndReportModuleImageInfo ( + IN UINTN AlignSize + ); + +/** + Read IDT entry to check if IDT entries are setup by Debug Agent. + + @retval TRUE IDT entries were setup by Debug Agent. + @retval FALSE IDT entries were not setup by Debug Agent. + +**/ +BOOLEAN +IsDebugAgentInitialzed ( + VOID + ); + +/** + Calculate Mailbox checksum and update the checksum field. + + @param[in] Mailbox Debug Agent Mailbox pointer. + +**/ +VOID +UpdateMailboxChecksum ( + IN DEBUG_AGENT_MAILBOX *Mailbox + ); + +/** + Verify Mailbox checksum. + + If checksum error, print debug message and run init dead loop. + + @param[in] Mailbox Debug Agent Mailbox pointer. + +**/ +VOID +VerifyMailboxChecksum ( + IN DEBUG_AGENT_MAILBOX *Mailbox + ); + +/** + Set debug flag in mailbox. + + @param[in] FlagMask Debug flag mask value. + @param[in] FlagValue Debug flag value. + +**/ +VOID +SetDebugFlag ( + IN UINT64 FlagMask, + IN UINT32 FlagValue + ); + +/** + Get debug flag in mailbox. + + @param[in] FlagMask Debug flag mask value. + + @return Debug flag value. + +**/ +UINT32 +GetDebugFlag ( + IN UINT64 FlagMask + ); + +/** + Update Mailbox content by index. + + @param[in] Mailbox Debug Agent Mailbox pointer. + @param[in] Index Mailbox content index. + @param[in] Value Value to be set into mail box. + +**/ +VOID +UpdateMailboxContent ( + IN DEBUG_AGENT_MAILBOX *Mailbox, + IN UINTN Index, + IN UINT64 Value + ); + +/** + Retrieve exception handler from IDT table by ExceptionNum. + + @param[in] ExceptionNum Exception number + + @return Exception handler + +**/ +VOID * +GetExceptionHandlerInIdtEntry ( + IN UINTN ExceptionNum + ); + +/** + Set exception handler in IDT table by ExceptionNum. + + @param[in] ExceptionNum Exception number + @param[in] ExceptionHandler Exception Handler to be set + +**/ +VOID +SetExceptionHandlerInIdtEntry ( + IN UINTN ExceptionNum, + IN VOID *ExceptionHandler + ); + +/** + Prints a debug message to the debug output device if the specified error level is enabled. + + If any bit in ErrorLevel is also set in DebugPrintErrorLevelLib function + GetDebugPrintErrorLevel (), then print the message specified by Format and the + associated variable argument list to the debug output device. + + If Format is NULL, then ASSERT(). + + @param[in] ErrorLevel The error level of the debug message. + @param[in] IsSend Flag of debug message to declare that the data is being sent or being received. + @param[in] Data Variable argument list whose contents are accessed + @param[in] Length based on the format string specified by Format. + +**/ +VOID +EFIAPI +DebugAgentDataMsgPrint ( + IN UINT8 ErrorLevel, + IN BOOLEAN IsSend, + IN UINT8 *Data, + IN UINT8 Length + ); + +/** + Read remaining debug packet except for the start symbol + + @param[in] Handle Pointer to Debug Port handle. + @param[in, out] DebugHeader Debug header buffer including start symbol. + + @retval EFI_SUCCESS Read the symbol in BreakSymbol. + @retval EFI_CRC_ERROR CRC check fail. + @retval EFI_TIMEOUT Timeout occurs when reading debug packet. + +**/ +EFI_STATUS +ReadRemainingBreakPacket ( + IN DEBUG_PORT_HANDLE Handle, + IN OUT DEBUG_PACKET_HEADER *DebugHeader + ); + +/** + Read data from debug channel and save the data in buffer. + + Reads NumberOfBytes data bytes from a debug device into the buffer + specified by Buffer. The number of bytes actually read is returned. + If the return value is less than NumberOfBytes, then the rest operation failed. + If NumberOfBytes is zero, then return 0. + + @param Handle Debug port handle. + @param Buffer Pointer to the data buffer to store the data read from the debug device. + @param NumberOfBytes Number of bytes which will be read. + @param Timeout Timeout value for reading from debug device. It unit is Microsecond. + + @retval 0 Read data failed, no data is to be read. + @retval >0 Actual number of bytes read from debug device. + +**/ +UINTN +DebugAgentReadBuffer ( + IN DEBUG_PORT_HANDLE Handle, + IN OUT UINT8 *Buffer, + IN UINTN NumberOfBytes, + IN UINTN Timeout + ); + +#endif diff --git a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugMp.c b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugMp.c index 89f922aba0..2951c0c59a 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugMp.c +++ b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugMp.c @@ -1,382 +1,382 @@ -/** @file
- Multi-Processor support functions implementation.
-
- Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DebugAgent.h"
-
-GLOBAL_REMOVE_IF_UNREFERENCED DEBUG_MP_CONTEXT volatile mDebugMpContext = { 0, 0, 0, { 0 }, { 0 }, 0, 0, 0, 0, FALSE, FALSE };
-
-GLOBAL_REMOVE_IF_UNREFERENCED DEBUG_CPU_DATA volatile mDebugCpuData = { 0 };
-
-/**
- Acquire a spin lock when Multi-processor supported.
-
- It will block in the function if cannot get the access control.
- If Multi-processor is not supported, return directly.
-
- @param[in, out] MpSpinLock A pointer to the spin lock.
-
-**/
-VOID
-AcquireMpSpinLock (
- IN OUT SPIN_LOCK *MpSpinLock
- )
-{
- if (!MultiProcessorDebugSupport ()) {
- return;
- }
-
- while (TRUE) {
- if (AcquireSpinLockOrFail (MpSpinLock)) {
- break;
- }
-
- CpuPause ();
- continue;
- }
-}
-
-/**
- Release a spin lock when Multi-processor supported.
-
- @param[in, out] MpSpinLock A pointer to the spin lock.
-
-**/
-VOID
-ReleaseMpSpinLock (
- IN OUT SPIN_LOCK *MpSpinLock
- )
-{
- if (!MultiProcessorDebugSupport ()) {
- return;
- }
-
- ReleaseSpinLock (MpSpinLock);
-}
-
-/**
- Break the other processor by send IPI.
-
- @param[in] CurrentProcessorIndex Current processor index value.
-
-**/
-VOID
-HaltOtherProcessors (
- IN UINT32 CurrentProcessorIndex
- )
-{
- DebugAgentMsgPrint (DEBUG_AGENT_INFO, "processor[%x]:Try to halt other processors.\n", CurrentProcessorIndex);
- if (!DebugAgentIsBsp (CurrentProcessorIndex)) {
- SetIpiSentByApFlag (TRUE);
- }
-
- mDebugMpContext.BreakAtCpuIndex = CurrentProcessorIndex;
-
- //
- // Set the debug viewpoint to the current breaking CPU.
- //
- SetDebugViewPoint (CurrentProcessorIndex);
-
- //
- // Send fixed IPI to other processors.
- //
- SendFixedIpiAllExcludingSelf (DEBUG_TIMER_VECTOR);
-}
-
-/**
- Get the current processor's index.
-
- @return Processor index value.
-
-**/
-UINT32
-GetProcessorIndex (
- VOID
- )
-{
- UINT32 Index;
- UINT16 LocalApicID;
-
- LocalApicID = (UINT16)GetApicId ();
-
- AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);
-
- for (Index = 0; Index < mDebugCpuData.CpuCount; Index++) {
- if (mDebugCpuData.ApicID[Index] == LocalApicID) {
- break;
- }
- }
-
- if (Index == mDebugCpuData.CpuCount) {
- mDebugCpuData.ApicID[Index] = LocalApicID;
- mDebugCpuData.CpuCount++;
- }
-
- ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);
-
- return Index;
-}
-
-/**
- Check if the specified processor is BSP or not.
-
- @param[in] ProcessorIndex Processor index value.
-
- @retval TRUE It is BSP.
- @retval FALSE It isn't BSP.
-
-**/
-BOOLEAN
-DebugAgentIsBsp (
- IN UINT32 ProcessorIndex
- )
-{
- MSR_IA32_APIC_BASE_REGISTER MsrApicBase;
-
- //
- // If there are less than 2 CPUs detected, then the currently executing CPU
- // must be the BSP. This avoids an access to an MSR that may not be supported
- // on single core CPUs.
- //
- if (mDebugCpuData.CpuCount < 2) {
- return TRUE;
- }
-
- MsrApicBase.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
- if (MsrApicBase.Bits.BSP == 1) {
- if (mDebugMpContext.BspIndex != ProcessorIndex) {
- AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);
- mDebugMpContext.BspIndex = ProcessorIndex;
- ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);
- }
-
- return TRUE;
- } else {
- return FALSE;
- }
-}
-
-/**
- Set processor stop flag bitmask in MP context.
-
- @param[in] ProcessorIndex Processor index value.
- @param[in] StopFlag TRUE means set stop flag.
- FALSE means clean break flag.
-
-**/
-VOID
-SetCpuStopFlagByIndex (
- IN UINT32 ProcessorIndex,
- IN BOOLEAN StopFlag
- )
-{
- UINT8 Value;
- UINTN Index;
-
- AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);
-
- Value = mDebugMpContext.CpuStopStatusMask[ProcessorIndex / 8];
- Index = ProcessorIndex % 8;
- if (StopFlag) {
- Value = BitFieldWrite8 (Value, Index, Index, 1);
- } else {
- Value = BitFieldWrite8 (Value, Index, Index, 0);
- }
-
- mDebugMpContext.CpuStopStatusMask[ProcessorIndex / 8] = Value;
-
- ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);
-}
-
-/**
- Set processor break flag bitmask in MP context.
-
- @param[in] ProcessorIndex Processor index value.
- @param[in] BreakFlag TRUE means set break flag.
- FALSE means clean break flag.
-
-**/
-VOID
-SetCpuBreakFlagByIndex (
- IN UINT32 ProcessorIndex,
- IN BOOLEAN BreakFlag
- )
-{
- UINT8 Value;
- UINTN Index;
-
- AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);
-
- Value = mDebugMpContext.CpuBreakMask[ProcessorIndex / 8];
- Index = ProcessorIndex % 8;
- if (BreakFlag) {
- Value = BitFieldWrite8 (Value, Index, Index, 1);
- } else {
- Value = BitFieldWrite8 (Value, Index, Index, 0);
- }
-
- mDebugMpContext.CpuBreakMask[ProcessorIndex / 8] = Value;
-
- ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);
-}
-
-/**
- Check if processor is stopped already.
-
- @param[in] ProcessorIndex Processor index value.
-
- @retval TRUE Processor is stopped already.
- @retval TRUE Processor isn't stopped.
-
-**/
-BOOLEAN
-IsCpuStopped (
- IN UINT32 ProcessorIndex
- )
-{
- UINT8 CpuMask;
-
- CpuMask = (UINT8)(1 << (ProcessorIndex % 8));
-
- if ((mDebugMpContext.CpuStopStatusMask[ProcessorIndex / 8] & CpuMask) != 0) {
- return TRUE;
- } else {
- return FALSE;
- }
-}
-
-/**
- Set the run command flag.
-
- @param[in] RunningFlag TRUE means run command flag is set.
- FALSE means run command flag is cleared.
-
-**/
-VOID
-SetCpuRunningFlag (
- IN BOOLEAN RunningFlag
- )
-{
- AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);
- mDebugMpContext.RunCommandSet = RunningFlag;
- ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);
-}
-
-/**
- Set the current view point to be debugged.
-
- @param[in] ProcessorIndex Processor index value.
-
-**/
-VOID
-SetDebugViewPoint (
- IN UINT32 ProcessorIndex
- )
-{
- AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);
- mDebugMpContext.ViewPointIndex = ProcessorIndex;
- ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);
-}
-
-/**
- Set the IPI send by BPS/AP flag.
-
- @param[in] IpiSentByApFlag TRUE means this IPI is sent by AP.
- FALSE means this IPI is sent by BSP.
-
-**/
-VOID
-SetIpiSentByApFlag (
- IN BOOLEAN IpiSentByApFlag
- )
-{
- AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);
- mDebugMpContext.IpiSentByAp = IpiSentByApFlag;
- ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);
-}
-
-/**
- Check the next pending breaking CPU.
-
- @retval others There is at least one processor broken, the minimum
- index number of Processor returned.
- @retval -1 No any processor broken.
-
-**/
-UINT32
-FindNextPendingBreakCpu (
- VOID
- )
-{
- UINT32 Index;
-
- for (Index = 0; Index < DEBUG_CPU_MAX_COUNT / 8; Index++) {
- if (mDebugMpContext.CpuBreakMask[Index] != 0) {
- return (UINT32)LowBitSet32 (mDebugMpContext.CpuBreakMask[Index]) + Index * 8;
- }
- }
-
- return (UINT32)-1;
-}
-
-/**
- Check if all processors are in running status.
-
- @retval TRUE All processors run.
- @retval FALSE At least one processor does not run.
-
-**/
-BOOLEAN
-IsAllCpuRunning (
- VOID
- )
-{
- UINTN Index;
-
- for (Index = 0; Index < DEBUG_CPU_MAX_COUNT / 8; Index++) {
- if (mDebugMpContext.CpuStopStatusMask[Index] != 0) {
- return FALSE;
- }
- }
-
- return TRUE;
-}
-
-/**
- Check if the current processor is the first breaking processor.
-
- If yes, halt other processors.
-
- @param[in] ProcessorIndex Processor index value.
-
- @return TRUE This processor is the first breaking processor.
- @return FALSE This processor is not the first breaking processor.
-
-**/
-BOOLEAN
-IsFirstBreakProcessor (
- IN UINT32 ProcessorIndex
- )
-{
- if (MultiProcessorDebugSupport ()) {
- if (mDebugMpContext.BreakAtCpuIndex != (UINT32)-1) {
- //
- // The current processor is not the first breaking one.
- //
- SetCpuBreakFlagByIndex (ProcessorIndex, TRUE);
- return FALSE;
- } else {
- //
- // If no any processor breaks, try to halt other processors
- //
- HaltOtherProcessors (ProcessorIndex);
- return TRUE;
- }
- }
-
- return TRUE;
-}
+/** @file + Multi-Processor support functions implementation. + + Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "DebugAgent.h" + +GLOBAL_REMOVE_IF_UNREFERENCED DEBUG_MP_CONTEXT volatile mDebugMpContext = { 0, 0, 0, { 0 }, { 0 }, 0, 0, 0, 0, FALSE, FALSE }; + +GLOBAL_REMOVE_IF_UNREFERENCED DEBUG_CPU_DATA volatile mDebugCpuData = { 0 }; + +/** + Acquire a spin lock when Multi-processor supported. + + It will block in the function if cannot get the access control. + If Multi-processor is not supported, return directly. + + @param[in, out] MpSpinLock A pointer to the spin lock. + +**/ +VOID +AcquireMpSpinLock ( + IN OUT SPIN_LOCK *MpSpinLock + ) +{ + if (!MultiProcessorDebugSupport ()) { + return; + } + + while (TRUE) { + if (AcquireSpinLockOrFail (MpSpinLock)) { + break; + } + + CpuPause (); + continue; + } +} + +/** + Release a spin lock when Multi-processor supported. + + @param[in, out] MpSpinLock A pointer to the spin lock. + +**/ +VOID +ReleaseMpSpinLock ( + IN OUT SPIN_LOCK *MpSpinLock + ) +{ + if (!MultiProcessorDebugSupport ()) { + return; + } + + ReleaseSpinLock (MpSpinLock); +} + +/** + Break the other processor by send IPI. + + @param[in] CurrentProcessorIndex Current processor index value. + +**/ +VOID +HaltOtherProcessors ( + IN UINT32 CurrentProcessorIndex + ) +{ + DebugAgentMsgPrint (DEBUG_AGENT_INFO, "processor[%x]:Try to halt other processors.\n", CurrentProcessorIndex); + if (!DebugAgentIsBsp (CurrentProcessorIndex)) { + SetIpiSentByApFlag (TRUE); + } + + mDebugMpContext.BreakAtCpuIndex = CurrentProcessorIndex; + + // + // Set the debug viewpoint to the current breaking CPU. + // + SetDebugViewPoint (CurrentProcessorIndex); + + // + // Send fixed IPI to other processors. + // + SendFixedIpiAllExcludingSelf (DEBUG_TIMER_VECTOR); +} + +/** + Get the current processor's index. + + @return Processor index value. + +**/ +UINT32 +GetProcessorIndex ( + VOID + ) +{ + UINT32 Index; + UINT16 LocalApicID; + + LocalApicID = (UINT16)GetApicId (); + + AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock); + + for (Index = 0; Index < mDebugCpuData.CpuCount; Index++) { + if (mDebugCpuData.ApicID[Index] == LocalApicID) { + break; + } + } + + if (Index == mDebugCpuData.CpuCount) { + mDebugCpuData.ApicID[Index] = LocalApicID; + mDebugCpuData.CpuCount++; + } + + ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock); + + return Index; +} + +/** + Check if the specified processor is BSP or not. + + @param[in] ProcessorIndex Processor index value. + + @retval TRUE It is BSP. + @retval FALSE It isn't BSP. + +**/ +BOOLEAN +DebugAgentIsBsp ( + IN UINT32 ProcessorIndex + ) +{ + MSR_IA32_APIC_BASE_REGISTER MsrApicBase; + + // + // If there are less than 2 CPUs detected, then the currently executing CPU + // must be the BSP. This avoids an access to an MSR that may not be supported + // on single core CPUs. + // + if (mDebugCpuData.CpuCount < 2) { + return TRUE; + } + + MsrApicBase.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE); + if (MsrApicBase.Bits.BSP == 1) { + if (mDebugMpContext.BspIndex != ProcessorIndex) { + AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock); + mDebugMpContext.BspIndex = ProcessorIndex; + ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock); + } + + return TRUE; + } else { + return FALSE; + } +} + +/** + Set processor stop flag bitmask in MP context. + + @param[in] ProcessorIndex Processor index value. + @param[in] StopFlag TRUE means set stop flag. + FALSE means clean break flag. + +**/ +VOID +SetCpuStopFlagByIndex ( + IN UINT32 ProcessorIndex, + IN BOOLEAN StopFlag + ) +{ + UINT8 Value; + UINTN Index; + + AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock); + + Value = mDebugMpContext.CpuStopStatusMask[ProcessorIndex / 8]; + Index = ProcessorIndex % 8; + if (StopFlag) { + Value = BitFieldWrite8 (Value, Index, Index, 1); + } else { + Value = BitFieldWrite8 (Value, Index, Index, 0); + } + + mDebugMpContext.CpuStopStatusMask[ProcessorIndex / 8] = Value; + + ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock); +} + +/** + Set processor break flag bitmask in MP context. + + @param[in] ProcessorIndex Processor index value. + @param[in] BreakFlag TRUE means set break flag. + FALSE means clean break flag. + +**/ +VOID +SetCpuBreakFlagByIndex ( + IN UINT32 ProcessorIndex, + IN BOOLEAN BreakFlag + ) +{ + UINT8 Value; + UINTN Index; + + AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock); + + Value = mDebugMpContext.CpuBreakMask[ProcessorIndex / 8]; + Index = ProcessorIndex % 8; + if (BreakFlag) { + Value = BitFieldWrite8 (Value, Index, Index, 1); + } else { + Value = BitFieldWrite8 (Value, Index, Index, 0); + } + + mDebugMpContext.CpuBreakMask[ProcessorIndex / 8] = Value; + + ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock); +} + +/** + Check if processor is stopped already. + + @param[in] ProcessorIndex Processor index value. + + @retval TRUE Processor is stopped already. + @retval TRUE Processor isn't stopped. + +**/ +BOOLEAN +IsCpuStopped ( + IN UINT32 ProcessorIndex + ) +{ + UINT8 CpuMask; + + CpuMask = (UINT8)(1 << (ProcessorIndex % 8)); + + if ((mDebugMpContext.CpuStopStatusMask[ProcessorIndex / 8] & CpuMask) != 0) { + return TRUE; + } else { + return FALSE; + } +} + +/** + Set the run command flag. + + @param[in] RunningFlag TRUE means run command flag is set. + FALSE means run command flag is cleared. + +**/ +VOID +SetCpuRunningFlag ( + IN BOOLEAN RunningFlag + ) +{ + AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock); + mDebugMpContext.RunCommandSet = RunningFlag; + ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock); +} + +/** + Set the current view point to be debugged. + + @param[in] ProcessorIndex Processor index value. + +**/ +VOID +SetDebugViewPoint ( + IN UINT32 ProcessorIndex + ) +{ + AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock); + mDebugMpContext.ViewPointIndex = ProcessorIndex; + ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock); +} + +/** + Set the IPI send by BPS/AP flag. + + @param[in] IpiSentByApFlag TRUE means this IPI is sent by AP. + FALSE means this IPI is sent by BSP. + +**/ +VOID +SetIpiSentByApFlag ( + IN BOOLEAN IpiSentByApFlag + ) +{ + AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock); + mDebugMpContext.IpiSentByAp = IpiSentByApFlag; + ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock); +} + +/** + Check the next pending breaking CPU. + + @retval others There is at least one processor broken, the minimum + index number of Processor returned. + @retval -1 No any processor broken. + +**/ +UINT32 +FindNextPendingBreakCpu ( + VOID + ) +{ + UINT32 Index; + + for (Index = 0; Index < DEBUG_CPU_MAX_COUNT / 8; Index++) { + if (mDebugMpContext.CpuBreakMask[Index] != 0) { + return (UINT32)LowBitSet32 (mDebugMpContext.CpuBreakMask[Index]) + Index * 8; + } + } + + return (UINT32)-1; +} + +/** + Check if all processors are in running status. + + @retval TRUE All processors run. + @retval FALSE At least one processor does not run. + +**/ +BOOLEAN +IsAllCpuRunning ( + VOID + ) +{ + UINTN Index; + + for (Index = 0; Index < DEBUG_CPU_MAX_COUNT / 8; Index++) { + if (mDebugMpContext.CpuStopStatusMask[Index] != 0) { + return FALSE; + } + } + + return TRUE; +} + +/** + Check if the current processor is the first breaking processor. + + If yes, halt other processors. + + @param[in] ProcessorIndex Processor index value. + + @return TRUE This processor is the first breaking processor. + @return FALSE This processor is not the first breaking processor. + +**/ +BOOLEAN +IsFirstBreakProcessor ( + IN UINT32 ProcessorIndex + ) +{ + if (MultiProcessorDebugSupport ()) { + if (mDebugMpContext.BreakAtCpuIndex != (UINT32)-1) { + // + // The current processor is not the first breaking one. + // + SetCpuBreakFlagByIndex (ProcessorIndex, TRUE); + return FALSE; + } else { + // + // If no any processor breaks, try to halt other processors + // + HaltOtherProcessors (ProcessorIndex); + return TRUE; + } + } + + return TRUE; +} diff --git a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugMp.h b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugMp.h index a0bc24ebfd..cc75377265 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugMp.h +++ b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugMp.h @@ -1,215 +1,215 @@ -/** @file
- Header file for Multi-Processor support.
-
- Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _DEBUG_MP_H_
-#define _DEBUG_MP_H_
-
-#define DEBUG_CPU_MAX_COUNT 256
-
-typedef struct {
- UINT32 CpuCount; ///< Processor count
- UINT16 ApicID[DEBUG_CPU_MAX_COUNT]; ///< Record the local apic id for each processor
-} DEBUG_CPU_DATA;
-
-typedef struct {
- SPIN_LOCK MpContextSpinLock; ///< Lock for writing MP context
- SPIN_LOCK DebugPortSpinLock; ///< Lock for access debug port
- SPIN_LOCK MailboxSpinLock; ///< Lock for accessing mail box
- UINT8 CpuBreakMask[DEBUG_CPU_MAX_COUNT/8]; ///< Bitmask of all breaking CPUs
- UINT8 CpuStopStatusMask[DEBUG_CPU_MAX_COUNT/8]; ///< Bitmask of CPU stop status
- UINT32 ViewPointIndex; ///< Current view point to be debugged
- UINT32 BspIndex; ///< Processor index value of BSP
- UINT32 BreakAtCpuIndex; ///< Processor index value of the current breaking CPU
- UINT32 DebugTimerInitCount; ///< Record BSP's init timer count
- BOOLEAN IpiSentByAp; ///< TRUE: IPI is sent by AP. FALSE: IPI is sent by BSP
- BOOLEAN RunCommandSet; ///< TRUE: RUN command is executing. FALSE: RUN command has been executed.
-} DEBUG_MP_CONTEXT;
-
-extern DEBUG_MP_CONTEXT volatile mDebugMpContext;
-extern DEBUG_CPU_DATA volatile mDebugCpuData;
-
-/**
- Break the other processor by send IPI.
-
- @param[in] CurrentProcessorIndex Current processor index value.
-
-**/
-VOID
-HaltOtherProcessors (
- IN UINT32 CurrentProcessorIndex
- );
-
-/**
- Get the current processor's index.
-
- @return Processor index value.
-
-**/
-UINT32
-GetProcessorIndex (
- VOID
- );
-
-/**
- Acquire a spin lock when Multi-processor supported.
-
- It will block in the function if cannot get the access control.
- If Multi-processor is not supported, return directly.
-
- @param[in, out] MpSpinLock A pointer to the spin lock.
-
-**/
-VOID
-AcquireMpSpinLock (
- IN OUT SPIN_LOCK *MpSpinLock
- );
-
-/**
- Release a spin lock when Multi-processor supported.
-
- @param[in, out] MpSpinLock A pointer to the spin lock.
-
-**/
-VOID
-ReleaseMpSpinLock (
- IN OUT SPIN_LOCK *MpSpinLock
- );
-
-/**
- Check if the specified processor is BSP or not.
-
- @param[in] ProcessorIndex Processor index value.
-
- @retval TRUE It is BSP.
- @retval FALSE It isn't BSP.
-
-**/
-BOOLEAN
-DebugAgentIsBsp (
- IN UINT32 ProcessorIndex
- );
-
-/**
- Set processor stop flag bitmask in MP context.
-
- @param[in] ProcessorIndex Processor index value.
- @param[in] StopFlag TRUE means set stop flag.
- FALSE means clean break flag.
-
-**/
-VOID
-SetCpuStopFlagByIndex (
- IN UINT32 ProcessorIndex,
- IN BOOLEAN StopFlag
- );
-
-/**
- Set processor break flag bitmask in MP context.
-
- @param[in] ProcessorIndex Processor index value.
- @param[in] BreakFlag TRUE means set break flag.
- FALSE means clean break flag.
-
-**/
-VOID
-SetCpuBreakFlagByIndex (
- IN UINT32 ProcessorIndex,
- IN BOOLEAN BreakFlag
- );
-
-/**
- Check if processor is stopped already.
-
- @param[in] ProcessorIndex Processor index value.
-
- @retval TRUE Processor is stopped already.
- @retval FALSE Processor isn't stopped.
-
-**/
-BOOLEAN
-IsCpuStopped (
- IN UINT32 ProcessorIndex
- );
-
-/**
- Set the run command flag.
-
- @param[in] RunningFlag TRUE means run command flag is set.
- FALSE means run command flag is cleared.
-
-**/
-VOID
-SetCpuRunningFlag (
- IN BOOLEAN RunningFlag
- );
-
-/**
- Set the current view point to be debugged.
-
- @param[in] ProcessorIndex Processor index value.
-
-**/
-VOID
-SetDebugViewPoint (
- IN UINT32 ProcessorIndex
- );
-
-/**
- Set the IPI send by BPS/AP flag.
-
- @param[in] IpiSentByApFlag TRUE means this IPI is sent by AP.
- FALSE means this IPI is sent by BSP.
-
-**/
-VOID
-SetIpiSentByApFlag (
- IN BOOLEAN IpiSentByApFlag
- );
-
-/**
- Check the next pending breaking CPU.
-
- @retval others There is at least one processor broken, the minimum
- index number of Processor returned.
- @retval -1 No any processor broken.
-
-**/
-UINT32
-FindNextPendingBreakCpu (
- VOID
- );
-
-/**
- Check if all processors are in running status.
-
- @retval TRUE All processors run.
- @retval FALSE At least one processor does not run.
-
-**/
-BOOLEAN
-IsAllCpuRunning (
- VOID
- );
-
-/**
- Check if the current processor is the first breaking processor.
-
- If yes, halt other processors.
-
- @param[in] ProcessorIndex Processor index value.
-
- @return TRUE This processor is the first breaking processor.
- @return FALSE This processor is not the first breaking processor.
-
-**/
-BOOLEAN
-IsFirstBreakProcessor (
- IN UINT32 ProcessorIndex
- );
-
-#endif
+/** @file + Header file for Multi-Processor support. + + Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _DEBUG_MP_H_ +#define _DEBUG_MP_H_ + +#define DEBUG_CPU_MAX_COUNT 256 + +typedef struct { + UINT32 CpuCount; ///< Processor count + UINT16 ApicID[DEBUG_CPU_MAX_COUNT]; ///< Record the local apic id for each processor +} DEBUG_CPU_DATA; + +typedef struct { + SPIN_LOCK MpContextSpinLock; ///< Lock for writing MP context + SPIN_LOCK DebugPortSpinLock; ///< Lock for access debug port + SPIN_LOCK MailboxSpinLock; ///< Lock for accessing mail box + UINT8 CpuBreakMask[DEBUG_CPU_MAX_COUNT/8]; ///< Bitmask of all breaking CPUs + UINT8 CpuStopStatusMask[DEBUG_CPU_MAX_COUNT/8]; ///< Bitmask of CPU stop status + UINT32 ViewPointIndex; ///< Current view point to be debugged + UINT32 BspIndex; ///< Processor index value of BSP + UINT32 BreakAtCpuIndex; ///< Processor index value of the current breaking CPU + UINT32 DebugTimerInitCount; ///< Record BSP's init timer count + BOOLEAN IpiSentByAp; ///< TRUE: IPI is sent by AP. FALSE: IPI is sent by BSP + BOOLEAN RunCommandSet; ///< TRUE: RUN command is executing. FALSE: RUN command has been executed. +} DEBUG_MP_CONTEXT; + +extern DEBUG_MP_CONTEXT volatile mDebugMpContext; +extern DEBUG_CPU_DATA volatile mDebugCpuData; + +/** + Break the other processor by send IPI. + + @param[in] CurrentProcessorIndex Current processor index value. + +**/ +VOID +HaltOtherProcessors ( + IN UINT32 CurrentProcessorIndex + ); + +/** + Get the current processor's index. + + @return Processor index value. + +**/ +UINT32 +GetProcessorIndex ( + VOID + ); + +/** + Acquire a spin lock when Multi-processor supported. + + It will block in the function if cannot get the access control. + If Multi-processor is not supported, return directly. + + @param[in, out] MpSpinLock A pointer to the spin lock. + +**/ +VOID +AcquireMpSpinLock ( + IN OUT SPIN_LOCK *MpSpinLock + ); + +/** + Release a spin lock when Multi-processor supported. + + @param[in, out] MpSpinLock A pointer to the spin lock. + +**/ +VOID +ReleaseMpSpinLock ( + IN OUT SPIN_LOCK *MpSpinLock + ); + +/** + Check if the specified processor is BSP or not. + + @param[in] ProcessorIndex Processor index value. + + @retval TRUE It is BSP. + @retval FALSE It isn't BSP. + +**/ +BOOLEAN +DebugAgentIsBsp ( + IN UINT32 ProcessorIndex + ); + +/** + Set processor stop flag bitmask in MP context. + + @param[in] ProcessorIndex Processor index value. + @param[in] StopFlag TRUE means set stop flag. + FALSE means clean break flag. + +**/ +VOID +SetCpuStopFlagByIndex ( + IN UINT32 ProcessorIndex, + IN BOOLEAN StopFlag + ); + +/** + Set processor break flag bitmask in MP context. + + @param[in] ProcessorIndex Processor index value. + @param[in] BreakFlag TRUE means set break flag. + FALSE means clean break flag. + +**/ +VOID +SetCpuBreakFlagByIndex ( + IN UINT32 ProcessorIndex, + IN BOOLEAN BreakFlag + ); + +/** + Check if processor is stopped already. + + @param[in] ProcessorIndex Processor index value. + + @retval TRUE Processor is stopped already. + @retval FALSE Processor isn't stopped. + +**/ +BOOLEAN +IsCpuStopped ( + IN UINT32 ProcessorIndex + ); + +/** + Set the run command flag. + + @param[in] RunningFlag TRUE means run command flag is set. + FALSE means run command flag is cleared. + +**/ +VOID +SetCpuRunningFlag ( + IN BOOLEAN RunningFlag + ); + +/** + Set the current view point to be debugged. + + @param[in] ProcessorIndex Processor index value. + +**/ +VOID +SetDebugViewPoint ( + IN UINT32 ProcessorIndex + ); + +/** + Set the IPI send by BPS/AP flag. + + @param[in] IpiSentByApFlag TRUE means this IPI is sent by AP. + FALSE means this IPI is sent by BSP. + +**/ +VOID +SetIpiSentByApFlag ( + IN BOOLEAN IpiSentByApFlag + ); + +/** + Check the next pending breaking CPU. + + @retval others There is at least one processor broken, the minimum + index number of Processor returned. + @retval -1 No any processor broken. + +**/ +UINT32 +FindNextPendingBreakCpu ( + VOID + ); + +/** + Check if all processors are in running status. + + @retval TRUE All processors run. + @retval FALSE At least one processor does not run. + +**/ +BOOLEAN +IsAllCpuRunning ( + VOID + ); + +/** + Check if the current processor is the first breaking processor. + + If yes, halt other processors. + + @param[in] ProcessorIndex Processor index value. + + @return TRUE This processor is the first breaking processor. + @return FALSE This processor is not the first breaking processor. + +**/ +BOOLEAN +IsFirstBreakProcessor ( + IN UINT32 ProcessorIndex + ); + +#endif diff --git a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugTimer.c b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugTimer.c index 833aa76a7d..01eb21578e 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugTimer.c +++ b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugTimer.c @@ -1,145 +1,145 @@ -/** @file
- Code for debug timer to support debug agent library implementation.
-
- Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DebugAgent.h"
-
-/**
- Initialize CPU local APIC timer.
-
- @param[out] TimerFrequency Local APIC timer frequency returned.
- @param[in] DumpFlag If TRUE, dump Local APIC timer's parameter.
-
- @return 32-bit Local APIC timer init count.
-**/
-UINT32
-InitializeDebugTimer (
- OUT UINT32 *TimerFrequency,
- IN BOOLEAN DumpFlag
- )
-{
- UINTN ApicTimerDivisor;
- UINT32 InitialCount;
- UINT32 ApicTimerFrequency;
-
- InitializeLocalApicSoftwareEnable (TRUE);
- GetApicTimerState (&ApicTimerDivisor, NULL, NULL);
- ApicTimerFrequency = PcdGet32 (PcdFSBClock) / (UINT32)ApicTimerDivisor;
- //
- // Cpu Local Apic timer interrupt frequency, it is set to 0.1s
- //
- InitialCount = (UINT32)DivU64x32 (
- MultU64x64 (
- ApicTimerFrequency,
- DEBUG_TIMER_INTERVAL
- ),
- 1000000u
- );
-
- InitializeApicTimer (ApicTimerDivisor, InitialCount, TRUE, DEBUG_TIMER_VECTOR);
- //
- // Disable Debug Timer interrupt to avoid it is delivered before Debug Port
- // is initialized
- //
- DisableApicTimerInterrupt ();
-
- if (DumpFlag) {
- DEBUG ((DEBUG_INFO, "Debug Timer: FSB Clock = %d\n", PcdGet32 (PcdFSBClock)));
- DEBUG ((DEBUG_INFO, "Debug Timer: Divisor = %d\n", ApicTimerDivisor));
- DEBUG ((DEBUG_INFO, "Debug Timer: Frequency = %d\n", ApicTimerFrequency));
- DEBUG ((DEBUG_INFO, "Debug Timer: InitialCount = %d\n", InitialCount));
- }
-
- if (TimerFrequency != NULL) {
- *TimerFrequency = ApicTimerFrequency;
- }
-
- return InitialCount;
-}
-
-/**
- Enable/Disable the interrupt of debug timer and return the interrupt state
- prior to the operation.
-
- If EnableStatus is TRUE, enable the interrupt of debug timer.
- If EnableStatus is FALSE, disable the interrupt of debug timer.
-
- @param[in] EnableStatus Enable/Disable.
-
- @retval TRUE Debug timer interrupt were enabled on entry to this call.
- @retval FALSE Debug timer interrupt were disabled on entry to this call.
-
-**/
-BOOLEAN
-EFIAPI
-SaveAndSetDebugTimerInterrupt (
- IN BOOLEAN EnableStatus
- )
-{
- BOOLEAN OldDebugTimerInterruptState;
-
- OldDebugTimerInterruptState = GetApicTimerInterruptState ();
-
- if (OldDebugTimerInterruptState != EnableStatus) {
- if (EnableStatus) {
- EnableApicTimerInterrupt ();
- } else {
- DisableApicTimerInterrupt ();
- }
-
- //
- // Validate the Debug Timer interrupt state
- // This will make additional delay after Local Apic Timer interrupt state is changed.
- // Thus, CPU could handle the potential pending interrupt of Local Apic timer.
- //
- while (GetApicTimerInterruptState () != EnableStatus) {
- CpuPause ();
- }
- }
-
- return OldDebugTimerInterruptState;
-}
-
-/**
- Check if the timer is time out.
-
- @param[in] TimerCycle Timer initial count.
- @param[in] Timer The start timer from the begin.
- @param[in] TimeoutTicker Ticker number need time out.
-
- @return TRUE Timer time out occurs.
- @retval FALSE Timer does not time out.
-
-**/
-BOOLEAN
-IsDebugTimerTimeout (
- IN UINT32 TimerCycle,
- IN UINT32 Timer,
- IN UINT32 TimeoutTicker
- )
-{
- UINT64 CurrentTimer;
- UINT64 Delta;
-
- CurrentTimer = GetApicTimerCurrentCount ();
-
- //
- // This timer counter counts down. Check for roll over condition.
- // If CurrentTimer is equal to Timer, it does not mean that roll over
- // happened.
- //
- if (CurrentTimer <= Timer) {
- Delta = Timer - CurrentTimer;
- } else {
- //
- // Handle one roll-over.
- //
- Delta = TimerCycle - (CurrentTimer - Timer) + 1;
- }
-
- return (BOOLEAN)(Delta >= TimeoutTicker);
-}
+/** @file + Code for debug timer to support debug agent library implementation. + + Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "DebugAgent.h" + +/** + Initialize CPU local APIC timer. + + @param[out] TimerFrequency Local APIC timer frequency returned. + @param[in] DumpFlag If TRUE, dump Local APIC timer's parameter. + + @return 32-bit Local APIC timer init count. +**/ +UINT32 +InitializeDebugTimer ( + OUT UINT32 *TimerFrequency, + IN BOOLEAN DumpFlag + ) +{ + UINTN ApicTimerDivisor; + UINT32 InitialCount; + UINT32 ApicTimerFrequency; + + InitializeLocalApicSoftwareEnable (TRUE); + GetApicTimerState (&ApicTimerDivisor, NULL, NULL); + ApicTimerFrequency = PcdGet32 (PcdFSBClock) / (UINT32)ApicTimerDivisor; + // + // Cpu Local Apic timer interrupt frequency, it is set to 0.1s + // + InitialCount = (UINT32)DivU64x32 ( + MultU64x64 ( + ApicTimerFrequency, + DEBUG_TIMER_INTERVAL + ), + 1000000u + ); + + InitializeApicTimer (ApicTimerDivisor, InitialCount, TRUE, DEBUG_TIMER_VECTOR); + // + // Disable Debug Timer interrupt to avoid it is delivered before Debug Port + // is initialized + // + DisableApicTimerInterrupt (); + + if (DumpFlag) { + DEBUG ((DEBUG_INFO, "Debug Timer: FSB Clock = %d\n", PcdGet32 (PcdFSBClock))); + DEBUG ((DEBUG_INFO, "Debug Timer: Divisor = %d\n", ApicTimerDivisor)); + DEBUG ((DEBUG_INFO, "Debug Timer: Frequency = %d\n", ApicTimerFrequency)); + DEBUG ((DEBUG_INFO, "Debug Timer: InitialCount = %d\n", InitialCount)); + } + + if (TimerFrequency != NULL) { + *TimerFrequency = ApicTimerFrequency; + } + + return InitialCount; +} + +/** + Enable/Disable the interrupt of debug timer and return the interrupt state + prior to the operation. + + If EnableStatus is TRUE, enable the interrupt of debug timer. + If EnableStatus is FALSE, disable the interrupt of debug timer. + + @param[in] EnableStatus Enable/Disable. + + @retval TRUE Debug timer interrupt were enabled on entry to this call. + @retval FALSE Debug timer interrupt were disabled on entry to this call. + +**/ +BOOLEAN +EFIAPI +SaveAndSetDebugTimerInterrupt ( + IN BOOLEAN EnableStatus + ) +{ + BOOLEAN OldDebugTimerInterruptState; + + OldDebugTimerInterruptState = GetApicTimerInterruptState (); + + if (OldDebugTimerInterruptState != EnableStatus) { + if (EnableStatus) { + EnableApicTimerInterrupt (); + } else { + DisableApicTimerInterrupt (); + } + + // + // Validate the Debug Timer interrupt state + // This will make additional delay after Local Apic Timer interrupt state is changed. + // Thus, CPU could handle the potential pending interrupt of Local Apic timer. + // + while (GetApicTimerInterruptState () != EnableStatus) { + CpuPause (); + } + } + + return OldDebugTimerInterruptState; +} + +/** + Check if the timer is time out. + + @param[in] TimerCycle Timer initial count. + @param[in] Timer The start timer from the begin. + @param[in] TimeoutTicker Ticker number need time out. + + @return TRUE Timer time out occurs. + @retval FALSE Timer does not time out. + +**/ +BOOLEAN +IsDebugTimerTimeout ( + IN UINT32 TimerCycle, + IN UINT32 Timer, + IN UINT32 TimeoutTicker + ) +{ + UINT64 CurrentTimer; + UINT64 Delta; + + CurrentTimer = GetApicTimerCurrentCount (); + + // + // This timer counter counts down. Check for roll over condition. + // If CurrentTimer is equal to Timer, it does not mean that roll over + // happened. + // + if (CurrentTimer <= Timer) { + Delta = Timer - CurrentTimer; + } else { + // + // Handle one roll-over. + // + Delta = TimerCycle - (CurrentTimer - Timer) + 1; + } + + return (BOOLEAN)(Delta >= TimeoutTicker); +} diff --git a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugTimer.h b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugTimer.h index be9566643f..6c07cfcfb7 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugTimer.h +++ b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugTimer.h @@ -1,44 +1,44 @@ -/** @file
- Header file for debug timer to support debug agent library implementation.
-
- Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _DEBUG_TIMER_H_
-#define _DEBUG_TIMER_H_
-
-/**
- Initialize CPU local APIC timer.
-
- @param[out] TimerFrequency Local APIC timer frequency returned.
- @param[in] DumpFlag If TRUE, dump Local APIC timer's parameter.
-
- @return 32-bit Local APIC timer init count.
-**/
-UINT32
-InitializeDebugTimer (
- OUT UINT32 *TimerFrequency,
- IN BOOLEAN DumpFlag
- );
-
-/**
- Check if the timer is time out.
-
- @param[in] TimerCycle Timer initial count.
- @param[in] Timer The start timer from the begin.
- @param[in] TimeoutTicker Ticker number need time out.
-
- @return TRUE Timer time out occurs.
- @retval FALSE Timer does not time out.
-
-**/
-BOOLEAN
-IsDebugTimerTimeout (
- IN UINT32 TimerCycle,
- IN UINT32 Timer,
- IN UINT32 TimeoutTicker
- );
-
-#endif
+/** @file + Header file for debug timer to support debug agent library implementation. + + Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _DEBUG_TIMER_H_ +#define _DEBUG_TIMER_H_ + +/** + Initialize CPU local APIC timer. + + @param[out] TimerFrequency Local APIC timer frequency returned. + @param[in] DumpFlag If TRUE, dump Local APIC timer's parameter. + + @return 32-bit Local APIC timer init count. +**/ +UINT32 +InitializeDebugTimer ( + OUT UINT32 *TimerFrequency, + IN BOOLEAN DumpFlag + ); + +/** + Check if the timer is time out. + + @param[in] TimerCycle Timer initial count. + @param[in] Timer The start timer from the begin. + @param[in] TimeoutTicker Ticker number need time out. + + @return TRUE Timer time out occurs. + @retval FALSE Timer does not time out. + +**/ +BOOLEAN +IsDebugTimerTimeout ( + IN UINT32 TimerCycle, + IN UINT32 Timer, + IN UINT32 TimeoutTicker + ); + +#endif diff --git a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/ArchDebugSupport.c b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/ArchDebugSupport.c index 99b9a7fa98..cb8387db7b 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/ArchDebugSupport.c +++ b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/ArchDebugSupport.c @@ -1,111 +1,111 @@ -/** @file
- Supporting functions for IA32 architecture.
-
- Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DebugAgent.h"
-
-/**
- Initialize IDT entries to support source level debug.
-
-**/
-VOID
-InitializeDebugIdt (
- VOID
- )
-{
- IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
- UINTN InterruptHandler;
- IA32_DESCRIPTOR IdtDescriptor;
- UINTN Index;
- UINT16 CodeSegment;
- UINT32 RegEdx;
-
- AsmReadIdtr (&IdtDescriptor);
-
- //
- // Use current CS as the segment selector of interrupt gate in IDT
- //
- CodeSegment = AsmReadCs ();
-
- IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)IdtDescriptor.Base;
-
- for (Index = 0; Index < 20; Index++) {
- if (((PcdGet32 (PcdExceptionsIgnoredByDebugger) & ~(BIT1 | BIT3)) & (1 << Index)) != 0) {
- //
- // If the exception is masked to be reserved except for INT1 and INT3, skip it
- //
- continue;
- }
-
- InterruptHandler = (UINTN)&Exception0Handle + Index * ExceptionStubHeaderSize;
- IdtEntry[Index].Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler;
- IdtEntry[Index].Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16);
- IdtEntry[Index].Bits.Selector = CodeSegment;
- IdtEntry[Index].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
- }
-
- InterruptHandler = (UINTN)&TimerInterruptHandle;
- IdtEntry[DEBUG_TIMER_VECTOR].Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler;
- IdtEntry[DEBUG_TIMER_VECTOR].Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16);
- IdtEntry[DEBUG_TIMER_VECTOR].Bits.Selector = CodeSegment;
- IdtEntry[DEBUG_TIMER_VECTOR].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
-
- //
- // If the CPU supports Debug Extensions(CPUID:01 EDX:BIT2), then
- // Set DE flag in CR4 to enable IO breakpoint
- //
- AsmCpuid (1, NULL, NULL, NULL, &RegEdx);
- if ((RegEdx & BIT2) != 0) {
- AsmWriteCr4 (AsmReadCr4 () | BIT3);
- }
-}
-
-/**
- Retrieve exception handler from IDT table by ExceptionNum.
-
- @param[in] ExceptionNum Exception number
-
- @return Exception handler
-
-**/
-VOID *
-GetExceptionHandlerInIdtEntry (
- IN UINTN ExceptionNum
- )
-{
- IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
- IA32_DESCRIPTOR IdtDescriptor;
-
- AsmReadIdtr (&IdtDescriptor);
- IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)IdtDescriptor.Base;
-
- return (VOID *)(((UINTN)IdtEntry[ExceptionNum].Bits.OffsetLow) |
- (((UINTN)IdtEntry[ExceptionNum].Bits.OffsetHigh) << 16));
-}
-
-/**
- Set exception handler in IDT table by ExceptionNum.
-
- @param[in] ExceptionNum Exception number
- @param[in] ExceptionHandler Exception Handler to be set
-
-**/
-VOID
-SetExceptionHandlerInIdtEntry (
- IN UINTN ExceptionNum,
- IN VOID *ExceptionHandler
- )
-{
- IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
- IA32_DESCRIPTOR IdtDescriptor;
-
- AsmReadIdtr (&IdtDescriptor);
- IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)IdtDescriptor.Base;
-
- IdtEntry[ExceptionNum].Bits.OffsetLow = (UINT16)(UINTN)ExceptionHandler;
- IdtEntry[ExceptionNum].Bits.OffsetHigh = (UINT16)((UINTN)ExceptionHandler >> 16);
-}
+/** @file + Supporting functions for IA32 architecture. + + Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "DebugAgent.h" + +/** + Initialize IDT entries to support source level debug. + +**/ +VOID +InitializeDebugIdt ( + VOID + ) +{ + IA32_IDT_GATE_DESCRIPTOR *IdtEntry; + UINTN InterruptHandler; + IA32_DESCRIPTOR IdtDescriptor; + UINTN Index; + UINT16 CodeSegment; + UINT32 RegEdx; + + AsmReadIdtr (&IdtDescriptor); + + // + // Use current CS as the segment selector of interrupt gate in IDT + // + CodeSegment = AsmReadCs (); + + IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)IdtDescriptor.Base; + + for (Index = 0; Index < 20; Index++) { + if (((PcdGet32 (PcdExceptionsIgnoredByDebugger) & ~(BIT1 | BIT3)) & (1 << Index)) != 0) { + // + // If the exception is masked to be reserved except for INT1 and INT3, skip it + // + continue; + } + + InterruptHandler = (UINTN)&Exception0Handle + Index * ExceptionStubHeaderSize; + IdtEntry[Index].Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler; + IdtEntry[Index].Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16); + IdtEntry[Index].Bits.Selector = CodeSegment; + IdtEntry[Index].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32; + } + + InterruptHandler = (UINTN)&TimerInterruptHandle; + IdtEntry[DEBUG_TIMER_VECTOR].Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler; + IdtEntry[DEBUG_TIMER_VECTOR].Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16); + IdtEntry[DEBUG_TIMER_VECTOR].Bits.Selector = CodeSegment; + IdtEntry[DEBUG_TIMER_VECTOR].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32; + + // + // If the CPU supports Debug Extensions(CPUID:01 EDX:BIT2), then + // Set DE flag in CR4 to enable IO breakpoint + // + AsmCpuid (1, NULL, NULL, NULL, &RegEdx); + if ((RegEdx & BIT2) != 0) { + AsmWriteCr4 (AsmReadCr4 () | BIT3); + } +} + +/** + Retrieve exception handler from IDT table by ExceptionNum. + + @param[in] ExceptionNum Exception number + + @return Exception handler + +**/ +VOID * +GetExceptionHandlerInIdtEntry ( + IN UINTN ExceptionNum + ) +{ + IA32_IDT_GATE_DESCRIPTOR *IdtEntry; + IA32_DESCRIPTOR IdtDescriptor; + + AsmReadIdtr (&IdtDescriptor); + IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)IdtDescriptor.Base; + + return (VOID *)(((UINTN)IdtEntry[ExceptionNum].Bits.OffsetLow) | + (((UINTN)IdtEntry[ExceptionNum].Bits.OffsetHigh) << 16)); +} + +/** + Set exception handler in IDT table by ExceptionNum. + + @param[in] ExceptionNum Exception number + @param[in] ExceptionHandler Exception Handler to be set + +**/ +VOID +SetExceptionHandlerInIdtEntry ( + IN UINTN ExceptionNum, + IN VOID *ExceptionHandler + ) +{ + IA32_IDT_GATE_DESCRIPTOR *IdtEntry; + IA32_DESCRIPTOR IdtDescriptor; + + AsmReadIdtr (&IdtDescriptor); + IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)IdtDescriptor.Base; + + IdtEntry[ExceptionNum].Bits.OffsetLow = (UINT16)(UINTN)ExceptionHandler; + IdtEntry[ExceptionNum].Bits.OffsetHigh = (UINT16)((UINTN)ExceptionHandler >> 16); +} diff --git a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/ArchDebugSupport.h b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/ArchDebugSupport.h index 5205b23046..89874380cd 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/ArchDebugSupport.h +++ b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/ArchDebugSupport.h @@ -1,21 +1,21 @@ -/** @file
- IA32 specific definitions for debug agent library instance.
-
- Copyright (c) 2010 - 2012, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _ARCH_DEBUG_SUPPORT_H_
-#define _ARCH_DEBUG_SUPPORT_H_
-
-#include "ProcessorContext.h"
-#include "TransferProtocol.h"
-
-#define DEBUG_SW_BREAKPOINT_SYMBOL 0xcc
-#define DEBUG_ARCH_SYMBOL DEBUG_DATA_BREAK_CPU_ARCH_IA32
-
-typedef DEBUG_DATA_IA32_FX_SAVE_STATE DEBUG_DATA_FX_SAVE_STATE;
-typedef DEBUG_DATA_IA32_SYSTEM_CONTEXT DEBUG_CPU_CONTEXT;
-
-#endif
+/** @file + IA32 specific definitions for debug agent library instance. + + Copyright (c) 2010 - 2012, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _ARCH_DEBUG_SUPPORT_H_ +#define _ARCH_DEBUG_SUPPORT_H_ + +#include "ProcessorContext.h" +#include "TransferProtocol.h" + +#define DEBUG_SW_BREAKPOINT_SYMBOL 0xcc +#define DEBUG_ARCH_SYMBOL DEBUG_DATA_BREAK_CPU_ARCH_IA32 + +typedef DEBUG_DATA_IA32_FX_SAVE_STATE DEBUG_DATA_FX_SAVE_STATE; +typedef DEBUG_DATA_IA32_SYSTEM_CONTEXT DEBUG_CPU_CONTEXT; + +#endif diff --git a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/AsmFuncs.nasm b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/AsmFuncs.nasm index b5e5a96e34..649a276ef4 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/AsmFuncs.nasm +++ b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/AsmFuncs.nasm @@ -1,413 +1,413 @@ -;------------------------------------------------------------------------------
-;
-; Copyright (c) 2010 - 2022, Intel Corporation. All rights reserved.<BR>
-; SPDX-License-Identifier: BSD-2-Clause-Patent
-;
-; Module Name:
-;
-; AsmFuncs.nasm
-;
-; Abstract:
-;
-; Debug interrupt handle functions.
-;
-;------------------------------------------------------------------------------
-
-#include "DebugException.h"
-
-;
-; InterruptProcess()
-;
-extern ASM_PFX(InterruptProcess)
-
-global ASM_PFX(Exception0Handle)
-global ASM_PFX(TimerInterruptHandle)
-global ASM_PFX(ExceptionStubHeaderSize)
-
-%macro AGENT_HANDLER_SIGNATURE 0
- db 0x41, 0x47, 0x54, 0x48 ; SIGNATURE_32('A','G','T','H')
-%endmacro
-
-SECTION .data
-
-ASM_PFX(ExceptionStubHeaderSize): DD Exception1Handle - ASM_PFX(Exception0Handle)
-CommonEntryAddr: DD CommonEntry
-
-SECTION .text
-
-AGENT_HANDLER_SIGNATURE
-ASM_PFX(Exception0Handle):
- cli
- push eax
- mov eax, 0
- jmp dword [CommonEntryAddr]
-AGENT_HANDLER_SIGNATURE
-Exception1Handle:
- cli
- push eax
- mov eax, 1
- jmp dword [CommonEntryAddr]
-AGENT_HANDLER_SIGNATURE
-Exception2Handle:
- cli
- push eax
- mov eax, 2
- jmp dword [CommonEntryAddr]
-AGENT_HANDLER_SIGNATURE
-Exception3Handle:
- cli
- push eax
- mov eax, 3
- jmp dword [CommonEntryAddr]
-AGENT_HANDLER_SIGNATURE
-Exception4Handle:
- cli
- push eax
- mov eax, 4
- jmp dword [CommonEntryAddr]
-AGENT_HANDLER_SIGNATURE
-Exception5Handle:
- cli
- push eax
- mov eax, 5
- jmp dword [CommonEntryAddr]
-AGENT_HANDLER_SIGNATURE
-Exception6Handle:
- cli
- push eax
- mov eax, 6
- jmp dword [CommonEntryAddr]
-AGENT_HANDLER_SIGNATURE
-Exception7Handle:
- cli
- push eax
- mov eax, 7
- jmp dword [CommonEntryAddr]
-AGENT_HANDLER_SIGNATURE
-Exception8Handle:
- cli
- push eax
- mov eax, 8
- jmp dword [CommonEntryAddr]
-AGENT_HANDLER_SIGNATURE
-Exception9Handle:
- cli
- push eax
- mov eax, 9
- jmp dword [CommonEntryAddr]
-AGENT_HANDLER_SIGNATURE
-Exception10Handle:
- cli
- push eax
- mov eax, 10
- jmp dword [CommonEntryAddr]
-AGENT_HANDLER_SIGNATURE
-Exception11Handle:
- cli
- push eax
- mov eax, 11
- jmp dword [CommonEntryAddr]
-AGENT_HANDLER_SIGNATURE
-Exception12Handle:
- cli
- push eax
- mov eax, 12
- jmp dword [CommonEntryAddr]
-AGENT_HANDLER_SIGNATURE
-Exception13Handle:
- cli
- push eax
- mov eax, 13
- jmp dword [CommonEntryAddr]
-AGENT_HANDLER_SIGNATURE
-Exception14Handle:
- cli
- push eax
- mov eax, 14
- jmp dword [CommonEntryAddr]
-AGENT_HANDLER_SIGNATURE
-Exception15Handle:
- cli
- push eax
- mov eax, 15
- jmp dword [CommonEntryAddr]
-AGENT_HANDLER_SIGNATURE
-Exception16Handle:
- cli
- push eax
- mov eax, 16
- jmp dword [CommonEntryAddr]
-AGENT_HANDLER_SIGNATURE
-Exception17Handle:
- cli
- push eax
- mov eax, 17
- jmp dword [CommonEntryAddr]
-AGENT_HANDLER_SIGNATURE
-Exception18Handle:
- cli
- push eax
- mov eax, 18
- jmp dword [CommonEntryAddr]
-AGENT_HANDLER_SIGNATURE
-Exception19Handle:
- cli
- push eax
- mov eax, 19
- jmp dword [CommonEntryAddr]
-AGENT_HANDLER_SIGNATURE
-ASM_PFX(TimerInterruptHandle):
- cli
- push eax
- mov eax, 32
- jmp dword [CommonEntryAddr]
-
-CommonEntry:
-;
-; +---------------------+
-; + EFlags +
-; +---------------------+
-; + CS +
-; +---------------------+
-; + EIP +
-; +---------------------+
-; + Error Code +
-; +---------------------+
-; + EAX / Vector Number +
-; +---------------------+
-; + EBP +
-; +---------------------+ <-- EBP
-;
- cmp eax, DEBUG_EXCEPT_DOUBLE_FAULT
- je NoExtrPush
- cmp eax, DEBUG_EXCEPT_INVALID_TSS
- je NoExtrPush
- cmp eax, DEBUG_EXCEPT_SEG_NOT_PRESENT
- je NoExtrPush
- cmp eax, DEBUG_EXCEPT_STACK_FAULT
- je NoExtrPush
- cmp eax, DEBUG_EXCEPT_GP_FAULT
- je NoExtrPush
- cmp eax, DEBUG_EXCEPT_PAGE_FAULT
- je NoExtrPush
- cmp eax, DEBUG_EXCEPT_ALIGNMENT_CHECK
- je NoExtrPush
-
- push dword [esp]
- mov dword [esp + 4], 0
-
-NoExtrPush:
-
- push ebp
- mov ebp, esp ; save esp in ebp
- ;
- ; Make stack 16-byte alignment to make sure save fxrstor later
- ;
- and esp, 0xfffffff0
- sub esp, 12
-
- ; store UINT32 Edi, Esi, Ebp, Ebx, Edx, Ecx, Eax;
- push dword [ebp + 4] ; original eax
- push ebx
- push ecx
- push edx
- mov ebx, eax ; save vector in ebx
- mov eax, ebp
- add eax, 4 * 6
- push eax ; original ESP
- push dword [ebp] ; EBP
- push esi
- push edi
-
- ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
- ;; insure FXSAVE/FXRSTOR is enabled in CR4...
- ;; ... while we're at it, make sure DE is also enabled...
- mov eax, 1
- push ebx ; temporarily save value of ebx on stack
- cpuid ; use CPUID to determine if FXSAVE/FXRESTOR and
- ; DE are supported
- pop ebx ; restore value of ebx that was overwritten by CPUID
- mov eax, cr4
- push eax ; push cr4 firstly
- test edx, BIT24 ; Test for FXSAVE/FXRESTOR support
- jz .0
- or eax, BIT9 ; Set CR4.OSFXSR
-.0:
- test edx, BIT2 ; Test for Debugging Extensions support
- jz .1
- or eax, BIT3 ; Set CR4.DE
-.1:
- mov cr4, eax
- mov eax, cr3
- push eax
- mov eax, cr2
- push eax
- push 0 ; cr0 will not saved???
- mov eax, cr0
- push eax
-
- xor ecx, ecx
- mov ecx, Ss
- push ecx
- mov ecx, Cs
- push ecx
- mov ecx, Ds
- push ecx
- mov ecx, Es
- push ecx
- mov ecx, Fs
- push ecx
- mov ecx, Gs
- push ecx
-
- ;; EIP
- mov ecx, [ebp + 4 * 3] ; EIP
- push ecx
-
- ;; UINT32 Gdtr[2], Idtr[2];
- sub esp, 8
- sidt [esp]
- sub esp, 8
- sgdt [esp]
-
- ;; UINT32 Ldtr, Tr;
- xor eax, eax
- str ax
- push eax
- sldt ax
- push eax
-
- ;; EFlags
- mov ecx, [ebp + 4 * 5]
- push ecx
-
- ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
- mov eax, dr7
- push eax
-
- ;; clear Dr7 while executing debugger itself
- xor eax, eax
- mov dr7, eax
-
- ;; Dr6
- mov eax, dr6
- push eax
-
- ;; insure all status bits in dr6 are clear...
- xor eax, eax
- mov dr6, eax
-
- mov eax, dr3
- push eax
- mov eax, dr2
- push eax
- mov eax, dr1
- push eax
- mov eax, dr0
- push eax
-
- ;; Clear Direction Flag
- cld
-
- ;; FX_SAVE_STATE_IA32 FxSaveState;
- sub esp, 512
- mov edi, esp
- ;; Clear the buffer
- xor eax, eax
- mov ecx, 128 ;= 512 / 4
- rep stosd
- mov edi, esp
-
- test edx, BIT24 ; Test for FXSAVE/FXRESTOR support.
- ; edx still contains result from CPUID above
- jz .2
- fxsave [edi]
-.2:
-
- ;; save the exception data
- push dword [ebp + 8]
-
- ; call the C interrupt process function
- push esp ; Structure
- push ebx ; vector
- call ASM_PFX(InterruptProcess)
- add esp, 8
-
- ; skip the exception data
- add esp, 4
-
- ;; FX_SAVE_STATE_IA32 FxSaveState;
- mov esi, esp
- mov eax, 1
- cpuid ; use CPUID to determine if FXSAVE/FXRESTOR are supported
- test edx, BIT24 ; Test for FXSAVE/FXRESTOR support
- jz .3
- fxrstor [esi]
-.3:
- add esp, 512
-
- ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
- pop eax
- mov dr0, eax
- pop eax
- mov dr1, eax
- pop eax
- mov dr2, eax
- pop eax
- mov dr3, eax
- ;; skip restore of dr6. We cleared dr6 during the context save.
- add esp, 4
- pop eax
- mov dr7, eax
-
- ;; set EFlags
- pop dword [ebp + 4 * 5] ; set EFLAGS in stack
-
- ;; UINT32 Ldtr, Tr;
- ;; UINT32 Gdtr[2], Idtr[2];
- ;; Best not let anyone mess with these particular registers...
- add esp, 24
-
- ;; UINT32 Eip;
- pop dword [ebp + 4 * 3] ; set EIP in stack
-
- ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
- ;; NOTE - modified segment registers could hang the debugger... We
- ;; could attempt to insulate ourselves against this possibility,
- ;; but that poses risks as well.
- ;;
- pop gs
- pop fs
- pop es
- pop ds
- pop dword [ebp + 4 * 4] ; set CS in stack
- pop ss
-
- ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
- pop eax
- mov cr0, eax
- add esp, 4 ; skip for Cr1
- pop eax
- mov cr2, eax
- pop eax
- mov cr3, eax
- pop eax
- mov cr4, eax
-
- ;; restore general register
- pop edi
- pop esi
- pop dword [ebp] ; save updated ebp
- pop dword [ebp + 4] ; save updated esp
- pop edx
- pop ecx
- pop ebx
- pop eax
-
- mov esp, ebp
- pop ebp ; restore ebp maybe updated
- pop esp ; restore esp maybe updated
- sub esp, 4 * 3 ; restore interrupt pushced stack
-
- iretd
-
+;------------------------------------------------------------------------------ +; +; Copyright (c) 2010 - 2022, Intel Corporation. All rights reserved.<BR> +; SPDX-License-Identifier: BSD-2-Clause-Patent +; +; Module Name: +; +; AsmFuncs.nasm +; +; Abstract: +; +; Debug interrupt handle functions. +; +;------------------------------------------------------------------------------ + +#include "DebugException.h" + +; +; InterruptProcess() +; +extern ASM_PFX(InterruptProcess) + +global ASM_PFX(Exception0Handle) +global ASM_PFX(TimerInterruptHandle) +global ASM_PFX(ExceptionStubHeaderSize) + +%macro AGENT_HANDLER_SIGNATURE 0 + db 0x41, 0x47, 0x54, 0x48 ; SIGNATURE_32('A','G','T','H') +%endmacro + +SECTION .data + +ASM_PFX(ExceptionStubHeaderSize): DD Exception1Handle - ASM_PFX(Exception0Handle) +CommonEntryAddr: DD CommonEntry + +SECTION .text + +AGENT_HANDLER_SIGNATURE +ASM_PFX(Exception0Handle): + cli + push eax + mov eax, 0 + jmp dword [CommonEntryAddr] +AGENT_HANDLER_SIGNATURE +Exception1Handle: + cli + push eax + mov eax, 1 + jmp dword [CommonEntryAddr] +AGENT_HANDLER_SIGNATURE +Exception2Handle: + cli + push eax + mov eax, 2 + jmp dword [CommonEntryAddr] +AGENT_HANDLER_SIGNATURE +Exception3Handle: + cli + push eax + mov eax, 3 + jmp dword [CommonEntryAddr] +AGENT_HANDLER_SIGNATURE +Exception4Handle: + cli + push eax + mov eax, 4 + jmp dword [CommonEntryAddr] +AGENT_HANDLER_SIGNATURE +Exception5Handle: + cli + push eax + mov eax, 5 + jmp dword [CommonEntryAddr] +AGENT_HANDLER_SIGNATURE +Exception6Handle: + cli + push eax + mov eax, 6 + jmp dword [CommonEntryAddr] +AGENT_HANDLER_SIGNATURE +Exception7Handle: + cli + push eax + mov eax, 7 + jmp dword [CommonEntryAddr] +AGENT_HANDLER_SIGNATURE +Exception8Handle: + cli + push eax + mov eax, 8 + jmp dword [CommonEntryAddr] +AGENT_HANDLER_SIGNATURE +Exception9Handle: + cli + push eax + mov eax, 9 + jmp dword [CommonEntryAddr] +AGENT_HANDLER_SIGNATURE +Exception10Handle: + cli + push eax + mov eax, 10 + jmp dword [CommonEntryAddr] +AGENT_HANDLER_SIGNATURE +Exception11Handle: + cli + push eax + mov eax, 11 + jmp dword [CommonEntryAddr] +AGENT_HANDLER_SIGNATURE +Exception12Handle: + cli + push eax + mov eax, 12 + jmp dword [CommonEntryAddr] +AGENT_HANDLER_SIGNATURE +Exception13Handle: + cli + push eax + mov eax, 13 + jmp dword [CommonEntryAddr] +AGENT_HANDLER_SIGNATURE +Exception14Handle: + cli + push eax + mov eax, 14 + jmp dword [CommonEntryAddr] +AGENT_HANDLER_SIGNATURE +Exception15Handle: + cli + push eax + mov eax, 15 + jmp dword [CommonEntryAddr] +AGENT_HANDLER_SIGNATURE +Exception16Handle: + cli + push eax + mov eax, 16 + jmp dword [CommonEntryAddr] +AGENT_HANDLER_SIGNATURE +Exception17Handle: + cli + push eax + mov eax, 17 + jmp dword [CommonEntryAddr] +AGENT_HANDLER_SIGNATURE +Exception18Handle: + cli + push eax + mov eax, 18 + jmp dword [CommonEntryAddr] +AGENT_HANDLER_SIGNATURE +Exception19Handle: + cli + push eax + mov eax, 19 + jmp dword [CommonEntryAddr] +AGENT_HANDLER_SIGNATURE +ASM_PFX(TimerInterruptHandle): + cli + push eax + mov eax, 32 + jmp dword [CommonEntryAddr] + +CommonEntry: +; +; +---------------------+ +; + EFlags + +; +---------------------+ +; + CS + +; +---------------------+ +; + EIP + +; +---------------------+ +; + Error Code + +; +---------------------+ +; + EAX / Vector Number + +; +---------------------+ +; + EBP + +; +---------------------+ <-- EBP +; + cmp eax, DEBUG_EXCEPT_DOUBLE_FAULT + je NoExtrPush + cmp eax, DEBUG_EXCEPT_INVALID_TSS + je NoExtrPush + cmp eax, DEBUG_EXCEPT_SEG_NOT_PRESENT + je NoExtrPush + cmp eax, DEBUG_EXCEPT_STACK_FAULT + je NoExtrPush + cmp eax, DEBUG_EXCEPT_GP_FAULT + je NoExtrPush + cmp eax, DEBUG_EXCEPT_PAGE_FAULT + je NoExtrPush + cmp eax, DEBUG_EXCEPT_ALIGNMENT_CHECK + je NoExtrPush + + push dword [esp] + mov dword [esp + 4], 0 + +NoExtrPush: + + push ebp + mov ebp, esp ; save esp in ebp + ; + ; Make stack 16-byte alignment to make sure save fxrstor later + ; + and esp, 0xfffffff0 + sub esp, 12 + + ; store UINT32 Edi, Esi, Ebp, Ebx, Edx, Ecx, Eax; + push dword [ebp + 4] ; original eax + push ebx + push ecx + push edx + mov ebx, eax ; save vector in ebx + mov eax, ebp + add eax, 4 * 6 + push eax ; original ESP + push dword [ebp] ; EBP + push esi + push edi + + ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; + ;; insure FXSAVE/FXRSTOR is enabled in CR4... + ;; ... while we're at it, make sure DE is also enabled... + mov eax, 1 + push ebx ; temporarily save value of ebx on stack + cpuid ; use CPUID to determine if FXSAVE/FXRESTOR and + ; DE are supported + pop ebx ; restore value of ebx that was overwritten by CPUID + mov eax, cr4 + push eax ; push cr4 firstly + test edx, BIT24 ; Test for FXSAVE/FXRESTOR support + jz .0 + or eax, BIT9 ; Set CR4.OSFXSR +.0: + test edx, BIT2 ; Test for Debugging Extensions support + jz .1 + or eax, BIT3 ; Set CR4.DE +.1: + mov cr4, eax + mov eax, cr3 + push eax + mov eax, cr2 + push eax + push 0 ; cr0 will not saved??? + mov eax, cr0 + push eax + + xor ecx, ecx + mov ecx, Ss + push ecx + mov ecx, Cs + push ecx + mov ecx, Ds + push ecx + mov ecx, Es + push ecx + mov ecx, Fs + push ecx + mov ecx, Gs + push ecx + + ;; EIP + mov ecx, [ebp + 4 * 3] ; EIP + push ecx + + ;; UINT32 Gdtr[2], Idtr[2]; + sub esp, 8 + sidt [esp] + sub esp, 8 + sgdt [esp] + + ;; UINT32 Ldtr, Tr; + xor eax, eax + str ax + push eax + sldt ax + push eax + + ;; EFlags + mov ecx, [ebp + 4 * 5] + push ecx + + ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; + mov eax, dr7 + push eax + + ;; clear Dr7 while executing debugger itself + xor eax, eax + mov dr7, eax + + ;; Dr6 + mov eax, dr6 + push eax + + ;; insure all status bits in dr6 are clear... + xor eax, eax + mov dr6, eax + + mov eax, dr3 + push eax + mov eax, dr2 + push eax + mov eax, dr1 + push eax + mov eax, dr0 + push eax + + ;; Clear Direction Flag + cld + + ;; FX_SAVE_STATE_IA32 FxSaveState; + sub esp, 512 + mov edi, esp + ;; Clear the buffer + xor eax, eax + mov ecx, 128 ;= 512 / 4 + rep stosd + mov edi, esp + + test edx, BIT24 ; Test for FXSAVE/FXRESTOR support. + ; edx still contains result from CPUID above + jz .2 + fxsave [edi] +.2: + + ;; save the exception data + push dword [ebp + 8] + + ; call the C interrupt process function + push esp ; Structure + push ebx ; vector + call ASM_PFX(InterruptProcess) + add esp, 8 + + ; skip the exception data + add esp, 4 + + ;; FX_SAVE_STATE_IA32 FxSaveState; + mov esi, esp + mov eax, 1 + cpuid ; use CPUID to determine if FXSAVE/FXRESTOR are supported + test edx, BIT24 ; Test for FXSAVE/FXRESTOR support + jz .3 + fxrstor [esi] +.3: + add esp, 512 + + ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; + pop eax + mov dr0, eax + pop eax + mov dr1, eax + pop eax + mov dr2, eax + pop eax + mov dr3, eax + ;; skip restore of dr6. We cleared dr6 during the context save. + add esp, 4 + pop eax + mov dr7, eax + + ;; set EFlags + pop dword [ebp + 4 * 5] ; set EFLAGS in stack + + ;; UINT32 Ldtr, Tr; + ;; UINT32 Gdtr[2], Idtr[2]; + ;; Best not let anyone mess with these particular registers... + add esp, 24 + + ;; UINT32 Eip; + pop dword [ebp + 4 * 3] ; set EIP in stack + + ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss; + ;; NOTE - modified segment registers could hang the debugger... We + ;; could attempt to insulate ourselves against this possibility, + ;; but that poses risks as well. + ;; + pop gs + pop fs + pop es + pop ds + pop dword [ebp + 4 * 4] ; set CS in stack + pop ss + + ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; + pop eax + mov cr0, eax + add esp, 4 ; skip for Cr1 + pop eax + mov cr2, eax + pop eax + mov cr3, eax + pop eax + mov cr4, eax + + ;; restore general register + pop edi + pop esi + pop dword [ebp] ; save updated ebp + pop dword [ebp + 4] ; save updated esp + pop edx + pop ecx + pop ebx + pop eax + + mov esp, ebp + pop ebp ; restore ebp maybe updated + pop esp ; restore esp maybe updated + sub esp, 4 * 3 ; restore interrupt pushced stack + + iretd + diff --git a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/DebugException.h b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/DebugException.h index 05cb45c78e..b6bad9a46d 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/DebugException.h +++ b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/DebugException.h @@ -1,30 +1,30 @@ -/** @file
- Exception definitions.
-
- Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _DEBUG_EXCEPTION_H_
-#define _DEBUG_EXCEPTION_H_
-
-#define DEBUG_EXCEPT_DIVIDE_ERROR 0
-#define DEBUG_EXCEPT_DEBUG 1
-#define DEBUG_EXCEPT_NMI 2
-#define DEBUG_EXCEPT_BREAKPOINT 3
-#define DEBUG_EXCEPT_OVERFLOW 4
-#define DEBUG_EXCEPT_BOUND 5
-#define DEBUG_EXCEPT_INVALID_OPCODE 6
-#define DEBUG_EXCEPT_DOUBLE_FAULT 8
-#define DEBUG_EXCEPT_INVALID_TSS 10
-#define DEBUG_EXCEPT_SEG_NOT_PRESENT 11
-#define DEBUG_EXCEPT_STACK_FAULT 12
-#define DEBUG_EXCEPT_GP_FAULT 13
-#define DEBUG_EXCEPT_PAGE_FAULT 14
-#define DEBUG_EXCEPT_FP_ERROR 16
-#define DEBUG_EXCEPT_ALIGNMENT_CHECK 17
-#define DEBUG_EXCEPT_MACHINE_CHECK 18
-#define DEBUG_EXCEPT_SIMD 19
-
-#endif
+/** @file + Exception definitions. + + Copyright (c) 2010, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _DEBUG_EXCEPTION_H_ +#define _DEBUG_EXCEPTION_H_ + +#define DEBUG_EXCEPT_DIVIDE_ERROR 0 +#define DEBUG_EXCEPT_DEBUG 1 +#define DEBUG_EXCEPT_NMI 2 +#define DEBUG_EXCEPT_BREAKPOINT 3 +#define DEBUG_EXCEPT_OVERFLOW 4 +#define DEBUG_EXCEPT_BOUND 5 +#define DEBUG_EXCEPT_INVALID_OPCODE 6 +#define DEBUG_EXCEPT_DOUBLE_FAULT 8 +#define DEBUG_EXCEPT_INVALID_TSS 10 +#define DEBUG_EXCEPT_SEG_NOT_PRESENT 11 +#define DEBUG_EXCEPT_STACK_FAULT 12 +#define DEBUG_EXCEPT_GP_FAULT 13 +#define DEBUG_EXCEPT_PAGE_FAULT 14 +#define DEBUG_EXCEPT_FP_ERROR 16 +#define DEBUG_EXCEPT_ALIGNMENT_CHECK 17 +#define DEBUG_EXCEPT_MACHINE_CHECK 18 +#define DEBUG_EXCEPT_SIMD 19 + +#endif diff --git a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/ArchDebugSupport.c b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/ArchDebugSupport.c index bda113ecca..0838b0f5c8 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/ArchDebugSupport.c +++ b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/ArchDebugSupport.c @@ -1,115 +1,115 @@ -/** @file
- Supporting functions for X64 architecture.
-
- Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DebugAgent.h"
-
-/**
- Initialize IDT entries to support source level debug.
-
-**/
-VOID
-InitializeDebugIdt (
- VOID
- )
-{
- IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
- UINTN InterruptHandler;
- IA32_DESCRIPTOR IdtDescriptor;
- UINTN Index;
- UINT16 CodeSegment;
- UINT32 RegEdx;
-
- AsmReadIdtr (&IdtDescriptor);
-
- //
- // Use current CS as the segment selector of interrupt gate in IDT
- //
- CodeSegment = AsmReadCs ();
-
- IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)IdtDescriptor.Base;
-
- for (Index = 0; Index < 20; Index++) {
- if (((PcdGet32 (PcdExceptionsIgnoredByDebugger) & ~(BIT1 | BIT3)) & (1 << Index)) != 0) {
- //
- // If the exception is masked to be reserved except for INT1 and INT3, skip it
- //
- continue;
- }
-
- InterruptHandler = (UINTN)&Exception0Handle + Index * ExceptionStubHeaderSize;
- IdtEntry[Index].Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler;
- IdtEntry[Index].Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16);
- IdtEntry[Index].Bits.OffsetUpper = (UINT32)((UINTN)InterruptHandler >> 32);
- IdtEntry[Index].Bits.Selector = CodeSegment;
- IdtEntry[Index].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
- }
-
- InterruptHandler = (UINTN)&TimerInterruptHandle;
- IdtEntry[DEBUG_TIMER_VECTOR].Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler;
- IdtEntry[DEBUG_TIMER_VECTOR].Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16);
- IdtEntry[DEBUG_TIMER_VECTOR].Bits.OffsetUpper = (UINT32)((UINTN)InterruptHandler >> 32);
- IdtEntry[DEBUG_TIMER_VECTOR].Bits.Selector = CodeSegment;
- IdtEntry[DEBUG_TIMER_VECTOR].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
-
- //
- // If the CPU supports Debug Extensions(CPUID:01 EDX:BIT2), then
- // Set DE flag in CR4 to enable IO breakpoint
- //
- AsmCpuid (1, NULL, NULL, NULL, &RegEdx);
- if ((RegEdx & BIT2) != 0) {
- AsmWriteCr4 (AsmReadCr4 () | BIT3);
- }
-}
-
-/**
- Retrieve exception handler from IDT table by ExceptionNum.
-
- @param[in] ExceptionNum Exception number
-
- @return Exception handler
-
-**/
-VOID *
-GetExceptionHandlerInIdtEntry (
- IN UINTN ExceptionNum
- )
-{
- IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
- IA32_DESCRIPTOR IdtDescriptor;
-
- AsmReadIdtr (&IdtDescriptor);
- IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)IdtDescriptor.Base;
-
- return (VOID *)(IdtEntry[ExceptionNum].Bits.OffsetLow |
- (((UINTN)IdtEntry[ExceptionNum].Bits.OffsetHigh) << 16) |
- (((UINTN)IdtEntry[ExceptionNum].Bits.OffsetUpper) << 32));
-}
-
-/**
- Set exception handler in IDT table by ExceptionNum.
-
- @param[in] ExceptionNum Exception number
- @param[in] ExceptionHandler Exception Handler to be set
-
-**/
-VOID
-SetExceptionHandlerInIdtEntry (
- IN UINTN ExceptionNum,
- IN VOID *ExceptionHandler
- )
-{
- IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
- IA32_DESCRIPTOR IdtDescriptor;
-
- AsmReadIdtr (&IdtDescriptor);
- IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)IdtDescriptor.Base;
-
- IdtEntry[ExceptionNum].Bits.OffsetLow = (UINT16)(UINTN)ExceptionHandler;
- IdtEntry[ExceptionNum].Bits.OffsetHigh = (UINT16)((UINTN)ExceptionHandler >> 16);
- IdtEntry[ExceptionNum].Bits.OffsetUpper = (UINT32)((UINTN)ExceptionHandler >> 32);
-}
+/** @file + Supporting functions for X64 architecture. + + Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "DebugAgent.h" + +/** + Initialize IDT entries to support source level debug. + +**/ +VOID +InitializeDebugIdt ( + VOID + ) +{ + IA32_IDT_GATE_DESCRIPTOR *IdtEntry; + UINTN InterruptHandler; + IA32_DESCRIPTOR IdtDescriptor; + UINTN Index; + UINT16 CodeSegment; + UINT32 RegEdx; + + AsmReadIdtr (&IdtDescriptor); + + // + // Use current CS as the segment selector of interrupt gate in IDT + // + CodeSegment = AsmReadCs (); + + IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)IdtDescriptor.Base; + + for (Index = 0; Index < 20; Index++) { + if (((PcdGet32 (PcdExceptionsIgnoredByDebugger) & ~(BIT1 | BIT3)) & (1 << Index)) != 0) { + // + // If the exception is masked to be reserved except for INT1 and INT3, skip it + // + continue; + } + + InterruptHandler = (UINTN)&Exception0Handle + Index * ExceptionStubHeaderSize; + IdtEntry[Index].Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler; + IdtEntry[Index].Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16); + IdtEntry[Index].Bits.OffsetUpper = (UINT32)((UINTN)InterruptHandler >> 32); + IdtEntry[Index].Bits.Selector = CodeSegment; + IdtEntry[Index].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32; + } + + InterruptHandler = (UINTN)&TimerInterruptHandle; + IdtEntry[DEBUG_TIMER_VECTOR].Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler; + IdtEntry[DEBUG_TIMER_VECTOR].Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16); + IdtEntry[DEBUG_TIMER_VECTOR].Bits.OffsetUpper = (UINT32)((UINTN)InterruptHandler >> 32); + IdtEntry[DEBUG_TIMER_VECTOR].Bits.Selector = CodeSegment; + IdtEntry[DEBUG_TIMER_VECTOR].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32; + + // + // If the CPU supports Debug Extensions(CPUID:01 EDX:BIT2), then + // Set DE flag in CR4 to enable IO breakpoint + // + AsmCpuid (1, NULL, NULL, NULL, &RegEdx); + if ((RegEdx & BIT2) != 0) { + AsmWriteCr4 (AsmReadCr4 () | BIT3); + } +} + +/** + Retrieve exception handler from IDT table by ExceptionNum. + + @param[in] ExceptionNum Exception number + + @return Exception handler + +**/ +VOID * +GetExceptionHandlerInIdtEntry ( + IN UINTN ExceptionNum + ) +{ + IA32_IDT_GATE_DESCRIPTOR *IdtEntry; + IA32_DESCRIPTOR IdtDescriptor; + + AsmReadIdtr (&IdtDescriptor); + IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)IdtDescriptor.Base; + + return (VOID *)(IdtEntry[ExceptionNum].Bits.OffsetLow | + (((UINTN)IdtEntry[ExceptionNum].Bits.OffsetHigh) << 16) | + (((UINTN)IdtEntry[ExceptionNum].Bits.OffsetUpper) << 32)); +} + +/** + Set exception handler in IDT table by ExceptionNum. + + @param[in] ExceptionNum Exception number + @param[in] ExceptionHandler Exception Handler to be set + +**/ +VOID +SetExceptionHandlerInIdtEntry ( + IN UINTN ExceptionNum, + IN VOID *ExceptionHandler + ) +{ + IA32_IDT_GATE_DESCRIPTOR *IdtEntry; + IA32_DESCRIPTOR IdtDescriptor; + + AsmReadIdtr (&IdtDescriptor); + IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)IdtDescriptor.Base; + + IdtEntry[ExceptionNum].Bits.OffsetLow = (UINT16)(UINTN)ExceptionHandler; + IdtEntry[ExceptionNum].Bits.OffsetHigh = (UINT16)((UINTN)ExceptionHandler >> 16); + IdtEntry[ExceptionNum].Bits.OffsetUpper = (UINT32)((UINTN)ExceptionHandler >> 32); +} diff --git a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/ArchDebugSupport.h b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/ArchDebugSupport.h index b795202959..ebb8857fdf 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/ArchDebugSupport.h +++ b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/ArchDebugSupport.h @@ -1,21 +1,21 @@ -/** @file
- X64 specific definitions for debug agent library instance.
-
- Copyright (c) 2010 - 2012, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _ARCH_DEBUG_SUPPORT_H_
-#define _ARCH_DEBUG_SUPPORT_H_
-
-#include "ProcessorContext.h"
-#include "TransferProtocol.h"
-
-#define DEBUG_SW_BREAKPOINT_SYMBOL 0xcc
-#define DEBUG_ARCH_SYMBOL DEBUG_DATA_BREAK_CPU_ARCH_X64
-
-typedef DEBUG_DATA_X64_FX_SAVE_STATE DEBUG_DATA_FX_SAVE_STATE;
-typedef DEBUG_DATA_X64_SYSTEM_CONTEXT DEBUG_CPU_CONTEXT;
-
-#endif
+/** @file + X64 specific definitions for debug agent library instance. + + Copyright (c) 2010 - 2012, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _ARCH_DEBUG_SUPPORT_H_ +#define _ARCH_DEBUG_SUPPORT_H_ + +#include "ProcessorContext.h" +#include "TransferProtocol.h" + +#define DEBUG_SW_BREAKPOINT_SYMBOL 0xcc +#define DEBUG_ARCH_SYMBOL DEBUG_DATA_BREAK_CPU_ARCH_X64 + +typedef DEBUG_DATA_X64_FX_SAVE_STATE DEBUG_DATA_FX_SAVE_STATE; +typedef DEBUG_DATA_X64_SYSTEM_CONTEXT DEBUG_CPU_CONTEXT; + +#endif diff --git a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/AsmFuncs.nasm b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/AsmFuncs.nasm index b1019e017b..cd3b07d829 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/AsmFuncs.nasm +++ b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/AsmFuncs.nasm @@ -1,399 +1,399 @@ -;------------------------------------------------------------------------------
-;
-; Copyright (c) 2016 - 2022, Intel Corporation. All rights reserved.<BR>
-; SPDX-License-Identifier: BSD-2-Clause-Patent
-;
-; Module Name:
-;
-; AsmFuncs.nasm
-;
-; Abstract:
-;
-; Debug interrupt handle functions.
-;
-;------------------------------------------------------------------------------
-
-#include "DebugException.h"
-
-SECTION .data
-
-extern ASM_PFX(InterruptProcess)
-global ASM_PFX(Exception0Handle)
-global ASM_PFX(TimerInterruptHandle)
-global ASM_PFX(ExceptionStubHeaderSize)
-
-%macro AGENT_HANDLER_SIGNATURE 0
- db 0x41, 0x47, 0x54, 0x48 ; SIGNATURE_32('A','G','T','H')
-%endmacro
-
-ASM_PFX(ExceptionStubHeaderSize): dd Exception1Handle - ASM_PFX(Exception0Handle) ;
-CommonEntryAddr: dq CommonEntry ;
-
-DEFAULT REL
-SECTION .text
-
-AGENT_HANDLER_SIGNATURE
-ASM_PFX(Exception0Handle):
- cli
- push rcx
- mov rcx, dword 0
- jmp qword [CommonEntryAddr]
-AGENT_HANDLER_SIGNATURE
-Exception1Handle:
- cli
- push rcx
- mov rcx, dword 1
- jmp qword [CommonEntryAddr]
-AGENT_HANDLER_SIGNATURE
-Exception2Handle:
- cli
- push rcx
- mov rcx, dword 2
- jmp qword [CommonEntryAddr]
-AGENT_HANDLER_SIGNATURE
-Exception3Handle:
- cli
- push rcx
- mov rcx, dword 3
- jmp qword [CommonEntryAddr]
-AGENT_HANDLER_SIGNATURE
-Exception4Handle:
- cli
- push rcx
- mov rcx, dword 4
- jmp qword [CommonEntryAddr]
-AGENT_HANDLER_SIGNATURE
-Exception5Handle:
- cli
- push rcx
- mov rcx, dword 5
- jmp qword [CommonEntryAddr]
-AGENT_HANDLER_SIGNATURE
-Exception6Handle:
- cli
- push rcx
- mov rcx, dword 6
- jmp qword [CommonEntryAddr]
-AGENT_HANDLER_SIGNATURE
-Exception7Handle:
- cli
- push rcx
- mov rcx, dword 7
- jmp qword [CommonEntryAddr]
-AGENT_HANDLER_SIGNATURE
-Exception8Handle:
- cli
- push rcx
- mov rcx, dword 8
- jmp qword [CommonEntryAddr]
-AGENT_HANDLER_SIGNATURE
-Exception9Handle:
- cli
- push rcx
- mov rcx, dword 9
- jmp qword [CommonEntryAddr]
-AGENT_HANDLER_SIGNATURE
-Exception10Handle:
- cli
- push rcx
- mov rcx, dword 10
- jmp qword [CommonEntryAddr]
-AGENT_HANDLER_SIGNATURE
-Exception11Handle:
- cli
- push rcx
- mov rcx, dword 11
- jmp qword [CommonEntryAddr]
-AGENT_HANDLER_SIGNATURE
-Exception12Handle:
- cli
- push rcx
- mov rcx, dword 12
- jmp qword [CommonEntryAddr]
-AGENT_HANDLER_SIGNATURE
-Exception13Handle:
- cli
- push rcx
- mov rcx, dword 13
- jmp qword [CommonEntryAddr]
-AGENT_HANDLER_SIGNATURE
-Exception14Handle:
- cli
- push rcx
- mov rcx, dword 14
- jmp qword [CommonEntryAddr]
-AGENT_HANDLER_SIGNATURE
-Exception15Handle:
- cli
- push rcx
- mov rcx, dword 15
- jmp qword [CommonEntryAddr]
-AGENT_HANDLER_SIGNATURE
-Exception16Handle:
- cli
- push rcx
- mov rcx, dword 16
- jmp qword [CommonEntryAddr]
-AGENT_HANDLER_SIGNATURE
-Exception17Handle:
- cli
- push rcx
- mov rcx, dword 17
- jmp qword [CommonEntryAddr]
-AGENT_HANDLER_SIGNATURE
-Exception18Handle:
- cli
- push rcx
- mov rcx, dword 18
- jmp qword [CommonEntryAddr]
-AGENT_HANDLER_SIGNATURE
-Exception19Handle:
- cli
- push rcx
- mov rcx, dword 19
- jmp qword [CommonEntryAddr]
-AGENT_HANDLER_SIGNATURE
-ASM_PFX(TimerInterruptHandle):
- cli
- push rcx
- mov rcx, dword 32
- jmp qword [CommonEntryAddr]
-
-CommonEntry:
- ; We need to determine if any extra data was pushed by the exception
- cmp rcx, DEBUG_EXCEPT_DOUBLE_FAULT
- je NoExtrPush
- cmp rcx, DEBUG_EXCEPT_INVALID_TSS
- je NoExtrPush
- cmp rcx, DEBUG_EXCEPT_SEG_NOT_PRESENT
- je NoExtrPush
- cmp rcx, DEBUG_EXCEPT_STACK_FAULT
- je NoExtrPush
- cmp rcx, DEBUG_EXCEPT_GP_FAULT
- je NoExtrPush
- cmp rcx, DEBUG_EXCEPT_PAGE_FAULT
- je NoExtrPush
- cmp rcx, DEBUG_EXCEPT_ALIGNMENT_CHECK
- je NoExtrPush
-
- push qword [rsp]
- mov qword [rsp + 8], 0
-
-NoExtrPush:
- push rbp
- mov rbp, rsp
-
- ; store UINT64 r8, r9, r10, r11, r12, r13, r14, r15;
- push r15
- push r14
- push r13
- push r12
- push r11
- push r10
- push r9
- push r8
-
- mov r8, cr8
- push r8
-
- ; store UINT64 Rdi, Rsi, Rbp, Rsp, Rdx, Rcx, Rbx, Rax;
- push rax
- push rbx
- push qword [rbp + 8] ; original rcx
- push rdx
- push qword [rbp + 6 * 8] ; original rsp
- push qword [rbp] ; original rbp
- push rsi
- push rdi
-
- ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
- ;; insure FXSAVE/FXRSTOR is enabled in CR4...
- ;; ... while we're at it, make sure DE is also enabled...
- mov rax, cr4
- or rax, 0x208
- mov cr4, rax
- push rax
- mov rax, cr3
- push rax
- mov rax, cr2
- push rax
- push 0
- mov rax, cr0
- push rax
-
- xor rax, rax
- mov rax, Ss
- push rax
- mov rax, Cs
- push rax
- mov rax, Ds
- push rax
- mov rax, Es
- push rax
- mov rax, Fs
- push rax
- mov rax, Gs
- push rax
-
- ;; EIP
- mov rax, [rbp + 8 * 3] ; EIP
- push rax
-
- ;; UINT64 Gdtr[2], Idtr[2];
- sub rsp, 16
- sidt [rsp]
- sub rsp, 16
- sgdt [rsp]
-
- ;; UINT64 Ldtr, Tr;
- xor rax, rax
- str ax
- push rax
- sldt ax
- push rax
-
- ;; EFlags
- mov rax, [rbp + 8 * 5]
- push rax
-
- ;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
- mov rax, dr7
- push rax
-
- ;; clear Dr7 while executing debugger itself
- xor rax, rax
- mov dr7, rax
-
- ;; Dr6
- mov rax, dr6
- push rax
-
- ;; insure all status bits in dr6 are clear...
- xor rax, rax
- mov dr6, rax
-
- mov rax, dr3
- push rax
- mov rax, dr2
- push rax
- mov rax, dr1
- push rax
- mov rax, dr0
- push rax
-
- ;; Clear Direction Flag
- cld
-
- sub rsp, 512
- mov rdi, rsp
- ;; Clear the buffer
- xor rax, rax
- push rcx
- mov rcx, dword 64 ;= 512 / 8
- rep stosq
- pop rcx
- mov rdi, rsp
- fxsave [rdi]
-
- ;; save the exception data
- push qword [rbp + 16]
-
- ; call the C interrupt process function
- mov rdx, rsp ; Structure
- mov r15, rcx ; save vector in r15
-
- ;
- ; Per X64 calling convention, allocate maximum parameter stack space
- ; and make sure RSP is 16-byte aligned
- ;
- sub rsp, 32 + 8
- call ASM_PFX(InterruptProcess)
- add rsp, 32 + 8
-
- ;; skip the exception data
- add rsp, 8
-
- mov rsi, rsp
- fxrstor [rsi]
- add rsp, 512
-
- ;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
- pop rax
- mov dr0, rax
- pop rax
- mov dr1, rax
- pop rax
- mov dr2, rax
- pop rax
- mov dr3, rax
- ;; skip restore of dr6. We cleared dr6 during the context save.
- add rsp, 8
- pop rax
- mov dr7, rax
-
- ;; set EFlags
- pop qword [rbp + 8 * 5]
-
- ;; UINT64 Ldtr, Tr;
- ;; UINT64 Gdtr[2], Idtr[2];
- ;; Best not let anyone mess with these particular registers...
- add rsp, 24 * 2
-
- ;; UINT64 Eip;
- pop qword [rbp + 8 * 3] ; set EIP in stack
-
- ;; UINT64 Gs, Fs, Es, Ds, Cs, Ss;
- ;; NOTE - modified segment registers could hang the debugger... We
- ;; could attempt to insulate ourselves against this possibility,
- ;; but that poses risks as well.
- ;;
- pop rax
- pop rax
- pop rax
- mov es, rax
- pop rax
- mov ds, rax
- pop qword [rbp + 8 * 4] ; Set CS in stack
- pop rax
- mov ss, rax
-
- ;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4;
- pop rax
- mov cr0, rax
- add rsp, 8 ; skip for Cr1
- pop rax
- mov cr2, rax
- pop rax
- mov cr3, rax
- pop rax
- mov cr4, rax
-
- ;; restore general register
- pop rdi
- pop rsi
- add rsp, 8 ; skip rbp
- add rsp, 8 ; skip rsp
- pop rdx
- pop rcx
- pop rbx
- pop rax
-
- pop r8
- mov cr8, r8
-
- ; store UINT64 r8, r9, r10, r11, r12, r13, r14, r15;
- pop r8
- pop r9
- pop r10
- pop r11
- pop r12
- pop r13
- pop r14
- pop r15
-
- mov rsp, rbp
- pop rbp
- add rsp, 16 ; skip rcx and error code
-
- iretq
-
+;------------------------------------------------------------------------------ +; +; Copyright (c) 2016 - 2022, Intel Corporation. All rights reserved.<BR> +; SPDX-License-Identifier: BSD-2-Clause-Patent +; +; Module Name: +; +; AsmFuncs.nasm +; +; Abstract: +; +; Debug interrupt handle functions. +; +;------------------------------------------------------------------------------ + +#include "DebugException.h" + +SECTION .data + +extern ASM_PFX(InterruptProcess) +global ASM_PFX(Exception0Handle) +global ASM_PFX(TimerInterruptHandle) +global ASM_PFX(ExceptionStubHeaderSize) + +%macro AGENT_HANDLER_SIGNATURE 0 + db 0x41, 0x47, 0x54, 0x48 ; SIGNATURE_32('A','G','T','H') +%endmacro + +ASM_PFX(ExceptionStubHeaderSize): dd Exception1Handle - ASM_PFX(Exception0Handle) ; +CommonEntryAddr: dq CommonEntry ; + +DEFAULT REL +SECTION .text + +AGENT_HANDLER_SIGNATURE +ASM_PFX(Exception0Handle): + cli + push rcx + mov rcx, dword 0 + jmp qword [CommonEntryAddr] +AGENT_HANDLER_SIGNATURE +Exception1Handle: + cli + push rcx + mov rcx, dword 1 + jmp qword [CommonEntryAddr] +AGENT_HANDLER_SIGNATURE +Exception2Handle: + cli + push rcx + mov rcx, dword 2 + jmp qword [CommonEntryAddr] +AGENT_HANDLER_SIGNATURE +Exception3Handle: + cli + push rcx + mov rcx, dword 3 + jmp qword [CommonEntryAddr] +AGENT_HANDLER_SIGNATURE +Exception4Handle: + cli + push rcx + mov rcx, dword 4 + jmp qword [CommonEntryAddr] +AGENT_HANDLER_SIGNATURE +Exception5Handle: + cli + push rcx + mov rcx, dword 5 + jmp qword [CommonEntryAddr] +AGENT_HANDLER_SIGNATURE +Exception6Handle: + cli + push rcx + mov rcx, dword 6 + jmp qword [CommonEntryAddr] +AGENT_HANDLER_SIGNATURE +Exception7Handle: + cli + push rcx + mov rcx, dword 7 + jmp qword [CommonEntryAddr] +AGENT_HANDLER_SIGNATURE +Exception8Handle: + cli + push rcx + mov rcx, dword 8 + jmp qword [CommonEntryAddr] +AGENT_HANDLER_SIGNATURE +Exception9Handle: + cli + push rcx + mov rcx, dword 9 + jmp qword [CommonEntryAddr] +AGENT_HANDLER_SIGNATURE +Exception10Handle: + cli + push rcx + mov rcx, dword 10 + jmp qword [CommonEntryAddr] +AGENT_HANDLER_SIGNATURE +Exception11Handle: + cli + push rcx + mov rcx, dword 11 + jmp qword [CommonEntryAddr] +AGENT_HANDLER_SIGNATURE +Exception12Handle: + cli + push rcx + mov rcx, dword 12 + jmp qword [CommonEntryAddr] +AGENT_HANDLER_SIGNATURE +Exception13Handle: + cli + push rcx + mov rcx, dword 13 + jmp qword [CommonEntryAddr] +AGENT_HANDLER_SIGNATURE +Exception14Handle: + cli + push rcx + mov rcx, dword 14 + jmp qword [CommonEntryAddr] +AGENT_HANDLER_SIGNATURE +Exception15Handle: + cli + push rcx + mov rcx, dword 15 + jmp qword [CommonEntryAddr] +AGENT_HANDLER_SIGNATURE +Exception16Handle: + cli + push rcx + mov rcx, dword 16 + jmp qword [CommonEntryAddr] +AGENT_HANDLER_SIGNATURE +Exception17Handle: + cli + push rcx + mov rcx, dword 17 + jmp qword [CommonEntryAddr] +AGENT_HANDLER_SIGNATURE +Exception18Handle: + cli + push rcx + mov rcx, dword 18 + jmp qword [CommonEntryAddr] +AGENT_HANDLER_SIGNATURE +Exception19Handle: + cli + push rcx + mov rcx, dword 19 + jmp qword [CommonEntryAddr] +AGENT_HANDLER_SIGNATURE +ASM_PFX(TimerInterruptHandle): + cli + push rcx + mov rcx, dword 32 + jmp qword [CommonEntryAddr] + +CommonEntry: + ; We need to determine if any extra data was pushed by the exception + cmp rcx, DEBUG_EXCEPT_DOUBLE_FAULT + je NoExtrPush + cmp rcx, DEBUG_EXCEPT_INVALID_TSS + je NoExtrPush + cmp rcx, DEBUG_EXCEPT_SEG_NOT_PRESENT + je NoExtrPush + cmp rcx, DEBUG_EXCEPT_STACK_FAULT + je NoExtrPush + cmp rcx, DEBUG_EXCEPT_GP_FAULT + je NoExtrPush + cmp rcx, DEBUG_EXCEPT_PAGE_FAULT + je NoExtrPush + cmp rcx, DEBUG_EXCEPT_ALIGNMENT_CHECK + je NoExtrPush + + push qword [rsp] + mov qword [rsp + 8], 0 + +NoExtrPush: + push rbp + mov rbp, rsp + + ; store UINT64 r8, r9, r10, r11, r12, r13, r14, r15; + push r15 + push r14 + push r13 + push r12 + push r11 + push r10 + push r9 + push r8 + + mov r8, cr8 + push r8 + + ; store UINT64 Rdi, Rsi, Rbp, Rsp, Rdx, Rcx, Rbx, Rax; + push rax + push rbx + push qword [rbp + 8] ; original rcx + push rdx + push qword [rbp + 6 * 8] ; original rsp + push qword [rbp] ; original rbp + push rsi + push rdi + + ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; + ;; insure FXSAVE/FXRSTOR is enabled in CR4... + ;; ... while we're at it, make sure DE is also enabled... + mov rax, cr4 + or rax, 0x208 + mov cr4, rax + push rax + mov rax, cr3 + push rax + mov rax, cr2 + push rax + push 0 + mov rax, cr0 + push rax + + xor rax, rax + mov rax, Ss + push rax + mov rax, Cs + push rax + mov rax, Ds + push rax + mov rax, Es + push rax + mov rax, Fs + push rax + mov rax, Gs + push rax + + ;; EIP + mov rax, [rbp + 8 * 3] ; EIP + push rax + + ;; UINT64 Gdtr[2], Idtr[2]; + sub rsp, 16 + sidt [rsp] + sub rsp, 16 + sgdt [rsp] + + ;; UINT64 Ldtr, Tr; + xor rax, rax + str ax + push rax + sldt ax + push rax + + ;; EFlags + mov rax, [rbp + 8 * 5] + push rax + + ;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; + mov rax, dr7 + push rax + + ;; clear Dr7 while executing debugger itself + xor rax, rax + mov dr7, rax + + ;; Dr6 + mov rax, dr6 + push rax + + ;; insure all status bits in dr6 are clear... + xor rax, rax + mov dr6, rax + + mov rax, dr3 + push rax + mov rax, dr2 + push rax + mov rax, dr1 + push rax + mov rax, dr0 + push rax + + ;; Clear Direction Flag + cld + + sub rsp, 512 + mov rdi, rsp + ;; Clear the buffer + xor rax, rax + push rcx + mov rcx, dword 64 ;= 512 / 8 + rep stosq + pop rcx + mov rdi, rsp + fxsave [rdi] + + ;; save the exception data + push qword [rbp + 16] + + ; call the C interrupt process function + mov rdx, rsp ; Structure + mov r15, rcx ; save vector in r15 + + ; + ; Per X64 calling convention, allocate maximum parameter stack space + ; and make sure RSP is 16-byte aligned + ; + sub rsp, 32 + 8 + call ASM_PFX(InterruptProcess) + add rsp, 32 + 8 + + ;; skip the exception data + add rsp, 8 + + mov rsi, rsp + fxrstor [rsi] + add rsp, 512 + + ;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; + pop rax + mov dr0, rax + pop rax + mov dr1, rax + pop rax + mov dr2, rax + pop rax + mov dr3, rax + ;; skip restore of dr6. We cleared dr6 during the context save. + add rsp, 8 + pop rax + mov dr7, rax + + ;; set EFlags + pop qword [rbp + 8 * 5] + + ;; UINT64 Ldtr, Tr; + ;; UINT64 Gdtr[2], Idtr[2]; + ;; Best not let anyone mess with these particular registers... + add rsp, 24 * 2 + + ;; UINT64 Eip; + pop qword [rbp + 8 * 3] ; set EIP in stack + + ;; UINT64 Gs, Fs, Es, Ds, Cs, Ss; + ;; NOTE - modified segment registers could hang the debugger... We + ;; could attempt to insulate ourselves against this possibility, + ;; but that poses risks as well. + ;; + pop rax + pop rax + pop rax + mov es, rax + pop rax + mov ds, rax + pop qword [rbp + 8 * 4] ; Set CS in stack + pop rax + mov ss, rax + + ;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4; + pop rax + mov cr0, rax + add rsp, 8 ; skip for Cr1 + pop rax + mov cr2, rax + pop rax + mov cr3, rax + pop rax + mov cr4, rax + + ;; restore general register + pop rdi + pop rsi + add rsp, 8 ; skip rbp + add rsp, 8 ; skip rsp + pop rdx + pop rcx + pop rbx + pop rax + + pop r8 + mov cr8, r8 + + ; store UINT64 r8, r9, r10, r11, r12, r13, r14, r15; + pop r8 + pop r9 + pop r10 + pop r11 + pop r12 + pop r13 + pop r14 + pop r15 + + mov rsp, rbp + pop rbp + add rsp, 16 ; skip rcx and error code + + iretq + diff --git a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/DebugException.h b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/DebugException.h index 05cb45c78e..b6bad9a46d 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/DebugException.h +++ b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/DebugException.h @@ -1,30 +1,30 @@ -/** @file
- Exception definitions.
-
- Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _DEBUG_EXCEPTION_H_
-#define _DEBUG_EXCEPTION_H_
-
-#define DEBUG_EXCEPT_DIVIDE_ERROR 0
-#define DEBUG_EXCEPT_DEBUG 1
-#define DEBUG_EXCEPT_NMI 2
-#define DEBUG_EXCEPT_BREAKPOINT 3
-#define DEBUG_EXCEPT_OVERFLOW 4
-#define DEBUG_EXCEPT_BOUND 5
-#define DEBUG_EXCEPT_INVALID_OPCODE 6
-#define DEBUG_EXCEPT_DOUBLE_FAULT 8
-#define DEBUG_EXCEPT_INVALID_TSS 10
-#define DEBUG_EXCEPT_SEG_NOT_PRESENT 11
-#define DEBUG_EXCEPT_STACK_FAULT 12
-#define DEBUG_EXCEPT_GP_FAULT 13
-#define DEBUG_EXCEPT_PAGE_FAULT 14
-#define DEBUG_EXCEPT_FP_ERROR 16
-#define DEBUG_EXCEPT_ALIGNMENT_CHECK 17
-#define DEBUG_EXCEPT_MACHINE_CHECK 18
-#define DEBUG_EXCEPT_SIMD 19
-
-#endif
+/** @file + Exception definitions. + + Copyright (c) 2010, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _DEBUG_EXCEPTION_H_ +#define _DEBUG_EXCEPTION_H_ + +#define DEBUG_EXCEPT_DIVIDE_ERROR 0 +#define DEBUG_EXCEPT_DEBUG 1 +#define DEBUG_EXCEPT_NMI 2 +#define DEBUG_EXCEPT_BREAKPOINT 3 +#define DEBUG_EXCEPT_OVERFLOW 4 +#define DEBUG_EXCEPT_BOUND 5 +#define DEBUG_EXCEPT_INVALID_OPCODE 6 +#define DEBUG_EXCEPT_DOUBLE_FAULT 8 +#define DEBUG_EXCEPT_INVALID_TSS 10 +#define DEBUG_EXCEPT_SEG_NOT_PRESENT 11 +#define DEBUG_EXCEPT_STACK_FAULT 12 +#define DEBUG_EXCEPT_GP_FAULT 13 +#define DEBUG_EXCEPT_PAGE_FAULT 14 +#define DEBUG_EXCEPT_FP_ERROR 16 +#define DEBUG_EXCEPT_ALIGNMENT_CHECK 17 +#define DEBUG_EXCEPT_MACHINE_CHECK 18 +#define DEBUG_EXCEPT_SIMD 19 + +#endif diff --git a/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/DxeDebugAgentLib.c b/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/DxeDebugAgentLib.c index a41bba2c4b..7bea778378 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/DxeDebugAgentLib.c +++ b/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/DxeDebugAgentLib.c @@ -1,549 +1,549 @@ -/** @file
- Debug Agent library implementation for Dxe Core and Dxr modules.
-
- Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DxeDebugAgentLib.h"
-
-DEBUG_AGENT_MAILBOX mMailbox;
-DEBUG_AGENT_MAILBOX *mMailboxPointer = NULL;
-IA32_IDT_GATE_DESCRIPTOR mIdtEntryTable[33];
-BOOLEAN mDxeCoreFlag = FALSE;
-BOOLEAN mMultiProcessorDebugSupport = FALSE;
-VOID *mSavedIdtTable = NULL;
-UINTN mSaveIdtTableSize = 0;
-BOOLEAN mDebugAgentInitialized = FALSE;
-BOOLEAN mSkipBreakpoint = FALSE;
-
-/**
- Check if debug agent support multi-processor.
-
- @retval TRUE Multi-processor is supported.
- @retval FALSE Multi-processor is not supported.
-
-**/
-BOOLEAN
-MultiProcessorDebugSupport (
- VOID
- )
-{
- return mMultiProcessorDebugSupport;
-}
-
-/**
- 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 ((DEBUG_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 ((DEBUG_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 ((DEBUG_ERROR, "DebugAgent: Failed to install configuration for mailbox!\n"));
- CpuDeadLoop ();
- }
-}
-
-/**
- Debug Agent constructor function.
-
- @param[in] ImageHandle The firmware allocated handle for the EFI image.
- @param[in] SystemTable A pointer to the EFI System Table.
-
- @retval RETURN_SUCCESS When this function completed.
-
-**/
-RETURN_STATUS
-EFIAPI
-DxeDebugAgentLibConstructor (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
-{
- if (mDxeCoreFlag) {
- //
- // Invoke internal constructor function only when DXE core links this library instance
- //
- InternalConstructorWorker ();
- }
-
- return RETURN_SUCCESS;
-}
-
-/**
- Get the pointer to Mailbox from the configuration table.
-
- @return Pointer to Mailbox.
-
-**/
-DEBUG_AGENT_MAILBOX *
-GetMailboxFromConfigurationTable (
- VOID
- )
-{
- EFI_STATUS Status;
- DEBUG_AGENT_MAILBOX *Mailbox;
-
- Status = EfiGetSystemConfigurationTable (&gEfiDebugAgentGuid, (VOID **)&Mailbox);
- if ((Status == EFI_SUCCESS) && (Mailbox != NULL)) {
- VerifyMailboxChecksum (Mailbox);
- return Mailbox;
- } else {
- return NULL;
- }
-}
-
-/**
- Get the pointer to Mailbox from the GUIDed HOB.
-
- @param[in] HobStart The starting HOB pointer to search from.
-
- @return Pointer to Mailbox.
-
-**/
-DEBUG_AGENT_MAILBOX *
-GetMailboxFromHob (
- IN VOID *HobStart
- )
-{
- EFI_HOB_GUID_TYPE *GuidHob;
- UINT64 *MailboxLocation;
- DEBUG_AGENT_MAILBOX *Mailbox;
-
- GuidHob = GetNextGuidHob (&gEfiDebugAgentGuid, HobStart);
- if (GuidHob == NULL) {
- return NULL;
- }
-
- MailboxLocation = (UINT64 *)(GET_GUID_HOB_DATA (GuidHob));
- Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation);
- VerifyMailboxChecksum (Mailbox);
-
- return Mailbox;
-}
-
-/**
- Get Debug Agent Mailbox pointer.
-
- @return Mailbox pointer.
-
-**/
-DEBUG_AGENT_MAILBOX *
-GetMailboxPointer (
- VOID
- )
-{
- AcquireMpSpinLock (&mDebugMpContext.MailboxSpinLock);
- VerifyMailboxChecksum (mMailboxPointer);
- ReleaseMpSpinLock (&mDebugMpContext.MailboxSpinLock);
- return mMailboxPointer;
-}
-
-/**
- Get debug port handle.
-
- @return Debug port handle.
-
-**/
-DEBUG_PORT_HANDLE
-GetDebugPortHandle (
- VOID
- )
-{
- return (DEBUG_PORT_HANDLE)(UINTN)(GetMailboxPointer ()->DebugPortHandle);
-}
-
-/**
- Worker function to set up Debug Agent environment.
-
- This function will set up IDT table and initialize the IDT entries and
- initialize CPU LOCAL APIC timer.
- It also tries to connect HOST if Debug Agent was not initialized before.
-
- @param[in] Mailbox Pointer to Mailbox.
-
-**/
-VOID
-SetupDebugAgentEnvironment (
- IN DEBUG_AGENT_MAILBOX *Mailbox
- )
-{
- IA32_DESCRIPTOR Idtr;
- UINT16 IdtEntryCount;
- UINT64 DebugPortHandle;
- UINT32 DebugTimerFrequency;
-
- if (mMultiProcessorDebugSupport) {
- InitializeSpinLock (&mDebugMpContext.MpContextSpinLock);
- InitializeSpinLock (&mDebugMpContext.DebugPortSpinLock);
- InitializeSpinLock (&mDebugMpContext.MailboxSpinLock);
- //
- // Clear Break CPU index value
- //
- mDebugMpContext.BreakAtCpuIndex = (UINT32)-1;
- }
-
- //
- // Get original IDT address and size.
- //
- AsmReadIdtr ((IA32_DESCRIPTOR *)&Idtr);
- IdtEntryCount = (UINT16)((Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR));
- if (IdtEntryCount < 33) {
- ZeroMem (&mIdtEntryTable, sizeof (IA32_IDT_GATE_DESCRIPTOR) * 33);
- //
- // Copy original IDT table into new one
- //
- CopyMem (&mIdtEntryTable, (VOID *)Idtr.Base, Idtr.Limit + 1);
- //
- // Load new IDT table
- //
- Idtr.Limit = (UINT16)(sizeof (IA32_IDT_GATE_DESCRIPTOR) * 33 - 1);
- Idtr.Base = (UINTN)&mIdtEntryTable;
- AsmWriteIdtr ((IA32_DESCRIPTOR *)&Idtr);
- }
-
- //
- // Initialize the IDT table entries to support source level debug.
- //
- InitializeDebugIdt ();
-
- //
- // If mMailboxPointer is not set before, set it
- //
- if (mMailboxPointer == NULL) {
- if (Mailbox != NULL) {
- //
- // If Mailbox exists, copy it into one global variable
- //
- CopyMem (&mMailbox, Mailbox, sizeof (DEBUG_AGENT_MAILBOX));
- } else {
- ZeroMem (&mMailbox, sizeof (DEBUG_AGENT_MAILBOX));
- }
-
- mMailboxPointer = &mMailbox;
- }
-
- //
- // Initialize Debug Timer hardware and save its initial count and frequency
- //
- mDebugMpContext.DebugTimerInitCount = InitializeDebugTimer (&DebugTimerFrequency, TRUE);
- UpdateMailboxContent (mMailboxPointer, DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY, DebugTimerFrequency);
- //
- // Initialize debug communication port
- //
- DebugPortHandle = (UINT64)(UINTN)DebugPortInitialize ((VOID *)(UINTN)mMailboxPointer->DebugPortHandle, NULL);
- UpdateMailboxContent (mMailboxPointer, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle);
-
- if (Mailbox == NULL) {
- //
- // 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);
- }
- }
-}
-
-/**
- Initialize debug agent.
-
- This function is used to set up debug environment 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;
- BOOLEAN PeriodicMode;
- UINTN TimerCycle;
-
- if (InitFlag == DEBUG_AGENT_INIT_DXE_AP) {
- //
- // 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);
- }
-
- //
- // 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 ((DEBUG_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);
- //
- // 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 Debug Agent Environment and try to connect HOST if required
- //
- SetupDebugAgentEnvironment (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 Debug Timer interrupt
- //
- SaveAndSetDebugTimerInterrupt (TRUE);
- //
- // Enable interrupt to receive Debug Timer interrupt
- //
- EnableInterrupts ();
-
- mDebugAgentInitialized = TRUE;
- FindAndReportModuleImageInfo (SIZE_4KB);
-
- *(EFI_STATUS *)Context = EFI_SUCCESS;
-
- break;
-
- case DEBUG_AGENT_INIT_DXE_UNLOAD:
- if (mDebugAgentInitialized) {
- if (IsHostAttached ()) {
- *(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 {
- *(EFI_STATUS *)Context = EFI_NOT_STARTED;
- }
-
- //
- // Restore interrupt state.
- //
- SetInterruptState (InterruptStatus);
- break;
-
- case DEBUG_AGENT_INIT_DXE_CORE:
- mDxeCoreFlag = TRUE;
- mMultiProcessorDebugSupport = TRUE;
- //
- // Try to get mailbox from GUIDed HOB build in PEI
- //
- HobList = Context;
- Mailbox = GetMailboxFromHob (HobList);
- //
- // Set up Debug Agent Environment and try to connect HOST if required
- //
- SetupDebugAgentEnvironment (Mailbox);
- //
- // Enable Debug Timer interrupt
- //
- SaveAndSetDebugTimerInterrupt (TRUE);
- //
- // 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 +
- ((UINTN)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 Debug Agent Environment and try to connect HOST if required
- //
- SetupDebugAgentEnvironment (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 ((DEBUG_ERROR, "Debug Agent: The InitFlag value is not allowed!\n"));
- CpuDeadLoop ();
- break;
- }
-}
+/** @file + Debug Agent library implementation for Dxe Core and Dxr modules. + + Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "DxeDebugAgentLib.h" + +DEBUG_AGENT_MAILBOX mMailbox; +DEBUG_AGENT_MAILBOX *mMailboxPointer = NULL; +IA32_IDT_GATE_DESCRIPTOR mIdtEntryTable[33]; +BOOLEAN mDxeCoreFlag = FALSE; +BOOLEAN mMultiProcessorDebugSupport = FALSE; +VOID *mSavedIdtTable = NULL; +UINTN mSaveIdtTableSize = 0; +BOOLEAN mDebugAgentInitialized = FALSE; +BOOLEAN mSkipBreakpoint = FALSE; + +/** + Check if debug agent support multi-processor. + + @retval TRUE Multi-processor is supported. + @retval FALSE Multi-processor is not supported. + +**/ +BOOLEAN +MultiProcessorDebugSupport ( + VOID + ) +{ + return mMultiProcessorDebugSupport; +} + +/** + 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 ((DEBUG_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 ((DEBUG_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 ((DEBUG_ERROR, "DebugAgent: Failed to install configuration for mailbox!\n")); + CpuDeadLoop (); + } +} + +/** + Debug Agent constructor function. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval RETURN_SUCCESS When this function completed. + +**/ +RETURN_STATUS +EFIAPI +DxeDebugAgentLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + if (mDxeCoreFlag) { + // + // Invoke internal constructor function only when DXE core links this library instance + // + InternalConstructorWorker (); + } + + return RETURN_SUCCESS; +} + +/** + Get the pointer to Mailbox from the configuration table. + + @return Pointer to Mailbox. + +**/ +DEBUG_AGENT_MAILBOX * +GetMailboxFromConfigurationTable ( + VOID + ) +{ + EFI_STATUS Status; + DEBUG_AGENT_MAILBOX *Mailbox; + + Status = EfiGetSystemConfigurationTable (&gEfiDebugAgentGuid, (VOID **)&Mailbox); + if ((Status == EFI_SUCCESS) && (Mailbox != NULL)) { + VerifyMailboxChecksum (Mailbox); + return Mailbox; + } else { + return NULL; + } +} + +/** + Get the pointer to Mailbox from the GUIDed HOB. + + @param[in] HobStart The starting HOB pointer to search from. + + @return Pointer to Mailbox. + +**/ +DEBUG_AGENT_MAILBOX * +GetMailboxFromHob ( + IN VOID *HobStart + ) +{ + EFI_HOB_GUID_TYPE *GuidHob; + UINT64 *MailboxLocation; + DEBUG_AGENT_MAILBOX *Mailbox; + + GuidHob = GetNextGuidHob (&gEfiDebugAgentGuid, HobStart); + if (GuidHob == NULL) { + return NULL; + } + + MailboxLocation = (UINT64 *)(GET_GUID_HOB_DATA (GuidHob)); + Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation); + VerifyMailboxChecksum (Mailbox); + + return Mailbox; +} + +/** + Get Debug Agent Mailbox pointer. + + @return Mailbox pointer. + +**/ +DEBUG_AGENT_MAILBOX * +GetMailboxPointer ( + VOID + ) +{ + AcquireMpSpinLock (&mDebugMpContext.MailboxSpinLock); + VerifyMailboxChecksum (mMailboxPointer); + ReleaseMpSpinLock (&mDebugMpContext.MailboxSpinLock); + return mMailboxPointer; +} + +/** + Get debug port handle. + + @return Debug port handle. + +**/ +DEBUG_PORT_HANDLE +GetDebugPortHandle ( + VOID + ) +{ + return (DEBUG_PORT_HANDLE)(UINTN)(GetMailboxPointer ()->DebugPortHandle); +} + +/** + Worker function to set up Debug Agent environment. + + This function will set up IDT table and initialize the IDT entries and + initialize CPU LOCAL APIC timer. + It also tries to connect HOST if Debug Agent was not initialized before. + + @param[in] Mailbox Pointer to Mailbox. + +**/ +VOID +SetupDebugAgentEnvironment ( + IN DEBUG_AGENT_MAILBOX *Mailbox + ) +{ + IA32_DESCRIPTOR Idtr; + UINT16 IdtEntryCount; + UINT64 DebugPortHandle; + UINT32 DebugTimerFrequency; + + if (mMultiProcessorDebugSupport) { + InitializeSpinLock (&mDebugMpContext.MpContextSpinLock); + InitializeSpinLock (&mDebugMpContext.DebugPortSpinLock); + InitializeSpinLock (&mDebugMpContext.MailboxSpinLock); + // + // Clear Break CPU index value + // + mDebugMpContext.BreakAtCpuIndex = (UINT32)-1; + } + + // + // Get original IDT address and size. + // + AsmReadIdtr ((IA32_DESCRIPTOR *)&Idtr); + IdtEntryCount = (UINT16)((Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR)); + if (IdtEntryCount < 33) { + ZeroMem (&mIdtEntryTable, sizeof (IA32_IDT_GATE_DESCRIPTOR) * 33); + // + // Copy original IDT table into new one + // + CopyMem (&mIdtEntryTable, (VOID *)Idtr.Base, Idtr.Limit + 1); + // + // Load new IDT table + // + Idtr.Limit = (UINT16)(sizeof (IA32_IDT_GATE_DESCRIPTOR) * 33 - 1); + Idtr.Base = (UINTN)&mIdtEntryTable; + AsmWriteIdtr ((IA32_DESCRIPTOR *)&Idtr); + } + + // + // Initialize the IDT table entries to support source level debug. + // + InitializeDebugIdt (); + + // + // If mMailboxPointer is not set before, set it + // + if (mMailboxPointer == NULL) { + if (Mailbox != NULL) { + // + // If Mailbox exists, copy it into one global variable + // + CopyMem (&mMailbox, Mailbox, sizeof (DEBUG_AGENT_MAILBOX)); + } else { + ZeroMem (&mMailbox, sizeof (DEBUG_AGENT_MAILBOX)); + } + + mMailboxPointer = &mMailbox; + } + + // + // Initialize Debug Timer hardware and save its initial count and frequency + // + mDebugMpContext.DebugTimerInitCount = InitializeDebugTimer (&DebugTimerFrequency, TRUE); + UpdateMailboxContent (mMailboxPointer, DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY, DebugTimerFrequency); + // + // Initialize debug communication port + // + DebugPortHandle = (UINT64)(UINTN)DebugPortInitialize ((VOID *)(UINTN)mMailboxPointer->DebugPortHandle, NULL); + UpdateMailboxContent (mMailboxPointer, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle); + + if (Mailbox == NULL) { + // + // 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); + } + } +} + +/** + Initialize debug agent. + + This function is used to set up debug environment 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; + BOOLEAN PeriodicMode; + UINTN TimerCycle; + + if (InitFlag == DEBUG_AGENT_INIT_DXE_AP) { + // + // 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); + } + + // + // 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 ((DEBUG_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); + // + // 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 Debug Agent Environment and try to connect HOST if required + // + SetupDebugAgentEnvironment (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 Debug Timer interrupt + // + SaveAndSetDebugTimerInterrupt (TRUE); + // + // Enable interrupt to receive Debug Timer interrupt + // + EnableInterrupts (); + + mDebugAgentInitialized = TRUE; + FindAndReportModuleImageInfo (SIZE_4KB); + + *(EFI_STATUS *)Context = EFI_SUCCESS; + + break; + + case DEBUG_AGENT_INIT_DXE_UNLOAD: + if (mDebugAgentInitialized) { + if (IsHostAttached ()) { + *(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 { + *(EFI_STATUS *)Context = EFI_NOT_STARTED; + } + + // + // Restore interrupt state. + // + SetInterruptState (InterruptStatus); + break; + + case DEBUG_AGENT_INIT_DXE_CORE: + mDxeCoreFlag = TRUE; + mMultiProcessorDebugSupport = TRUE; + // + // Try to get mailbox from GUIDed HOB build in PEI + // + HobList = Context; + Mailbox = GetMailboxFromHob (HobList); + // + // Set up Debug Agent Environment and try to connect HOST if required + // + SetupDebugAgentEnvironment (Mailbox); + // + // Enable Debug Timer interrupt + // + SaveAndSetDebugTimerInterrupt (TRUE); + // + // 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 + + ((UINTN)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 Debug Agent Environment and try to connect HOST if required + // + SetupDebugAgentEnvironment (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 ((DEBUG_ERROR, "Debug Agent: The InitFlag value is not allowed!\n")); + CpuDeadLoop (); + break; + } +} diff --git a/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/DxeDebugAgentLib.h b/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/DxeDebugAgentLib.h index bd178db3e1..8d1d917a6a 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/DxeDebugAgentLib.h +++ b/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/DxeDebugAgentLib.h @@ -1,34 +1,34 @@ -/** @file
- Header file for Dxe Core Debug Agent Library instance.
-
- Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _DXE_CORE_DEBUG_AGENT_LIB_H_
-#define _DXE_CORE_DEBUG_AGENT_LIB_H_
-
-#include <PiDxe.h>
-
-#include <Protocol/SerialIo.h>
-#include <Protocol/DevicePath.h>
-#include <Protocol/PiPcd.h>
-
-#include <Library/UefiBootServicesTableLib.h>
-#include <Library/UefiLib.h>
-#include <Library/DevicePathLib.h>
-#include <Library/MemoryAllocationLib.h>
-
-#include "DebugAgent.h"
-
-/**
- Install EFI Serial IO protocol based on Debug Communication Library.
-
-**/
-VOID
-InstallSerialIo (
- VOID
- );
-
-#endif
+/** @file + Header file for Dxe Core Debug Agent Library instance. + + Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _DXE_CORE_DEBUG_AGENT_LIB_H_ +#define _DXE_CORE_DEBUG_AGENT_LIB_H_ + +#include <PiDxe.h> + +#include <Protocol/SerialIo.h> +#include <Protocol/DevicePath.h> +#include <Protocol/PiPcd.h> + +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiLib.h> +#include <Library/DevicePathLib.h> +#include <Library/MemoryAllocationLib.h> + +#include "DebugAgent.h" + +/** + Install EFI Serial IO protocol based on Debug Communication Library. + +**/ +VOID +InstallSerialIo ( + VOID + ); + +#endif diff --git a/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/SerialIo.c b/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/SerialIo.c index 97d30c802d..51ae757d2b 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/SerialIo.c +++ b/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/SerialIo.c @@ -1,827 +1,827 @@ -/** @file
- Install Serial IO Protocol that layers on top of a Debug Communication Library instance.
-
- Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DxeDebugAgentLib.h"
-
-//
-// Serial I/O Protocol Interface definitions.
-//
-
-/**
- Reset serial device.
-
- @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
-
- @retval EFI_SUCCESS Reset successfully.
-
-**/
-EFI_STATUS
-EFIAPI
-SerialReset (
- IN EFI_SERIAL_IO_PROTOCOL *This
- );
-
-/**
- Set new attributes to a serial device.
-
- @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
- @param[in] BaudRate The baudrate of the serial device.
- @param[in] ReceiveFifoDepth The depth of receive FIFO buffer.
- @param[in] Timeout The request timeout for a single char.
- @param[in] Parity The type of parity used in serial device.
- @param[in] DataBits Number of databits used in serial device.
- @param[in] StopBits Number of stopbits used in serial device.
-
- @retval EFI_SUCCESS The new attributes were set.
- @retval EFI_INVALID_PARAMETER One or more attributes have an unsupported value.
- @retval EFI_DEVICE_ERROR The serial device is not functioning correctly (no return).
-
-**/
-EFI_STATUS
-EFIAPI
-SerialSetAttributes (
- IN EFI_SERIAL_IO_PROTOCOL *This,
- IN UINT64 BaudRate,
- IN UINT32 ReceiveFifoDepth,
- IN UINT32 Timeout,
- IN EFI_PARITY_TYPE Parity,
- IN UINT8 DataBits,
- IN EFI_STOP_BITS_TYPE StopBits
- );
-
-/**
- Set Control Bits.
-
- @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
- @param[in] Control Control bits that can be settable.
-
- @retval EFI_SUCCESS New Control bits were set successfully.
- @retval EFI_UNSUPPORTED The Control bits wanted to set are not supported.
-
-**/
-EFI_STATUS
-EFIAPI
-SerialSetControl (
- IN EFI_SERIAL_IO_PROTOCOL *This,
- IN UINT32 Control
- );
-
-/**
- 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
- );
-
-/**
- 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
- );
-
-/**
- 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
- );
-
-//
-// Serial Driver Defaults
-//
-#define SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH 1
-#define SERIAL_PORT_DEFAULT_TIMEOUT 1000000
-#define SERIAL_PORT_DEFAULT_CONTROL_MASK 0
-#define SERIAL_PORT_LOOPBACK_BUFFER_FULL BIT8
-
-//
-// EFI_SERIAL_IO_MODE instance
-//
-EFI_SERIAL_IO_MODE mSerialIoMode = {
- SERIAL_PORT_DEFAULT_CONTROL_MASK,
- SERIAL_PORT_DEFAULT_TIMEOUT,
- 0, // default BaudRate
- SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH,
- 0, // default DataBits
- 0, // default Parity
- 0 // default StopBits
-};
-
-//
-// EFI_SERIAL_IO_PROTOCOL instance
-//
-EFI_SERIAL_IO_PROTOCOL mSerialIo = {
- SERIAL_IO_INTERFACE_REVISION,
- SerialReset,
- SerialSetAttributes,
- SerialSetControl,
- SerialGetControl,
- SerialWrite,
- SerialRead,
- &mSerialIoMode
-};
-
-//
-// Serial IO Device Path definition
-//
-typedef struct {
- VENDOR_DEVICE_PATH VendorDevicePath;
- UART_DEVICE_PATH UartDevicePath;
- EFI_DEVICE_PATH_PROTOCOL EndDevicePath;
-} SERIAL_IO_DEVICE_PATH;
-
-//
-// Serial IO Device Patch instance
-//
-SERIAL_IO_DEVICE_PATH mSerialIoDevicePath = {
- {
- {
- HARDWARE_DEVICE_PATH,
- HW_VENDOR_DP,
- {
- (UINT8)(sizeof (VENDOR_DEVICE_PATH)),
- (UINT8)((sizeof (VENDOR_DEVICE_PATH)) >> 8)
- }
- },
- EFI_DEBUG_AGENT_GUID,
- },
- {
- {
- MESSAGING_DEVICE_PATH,
- MSG_UART_DP,
- {
- (UINT8)(sizeof (UART_DEVICE_PATH)),
- (UINT8)((sizeof (UART_DEVICE_PATH)) >> 8)
- }
- },
- 0,
- 0, // default BaudRate
- 0, // default DataBits
- 0, // default Parity
- 0, // default StopBits
- },
- {
- END_DEVICE_PATH_TYPE,
- END_ENTIRE_DEVICE_PATH_SUBTYPE,
- {
- END_DEVICE_PATH_LENGTH,
- 0
- }
- }
-};
-
-#define DEBUG_SERIAL_IO_FIFO_DEPTH 10
-//
-// Data buffer for Terminal input character and Debug Symbols.
-// The depth is DEBUG_SERIAL_IO_FIFO_DEPTH.
-// Fields:
-// First UINT8: The index of the first data in array Data[].
-// Last UINT8: The index, which you can put a new data into array Data[].
-// Surplus UINT8: Identify how many data you can put into array Data[].
-// Data[] UINT8: An array, which used to store data.
-//
-typedef struct {
- UINT8 First;
- UINT8 Last;
- UINT8 Surplus;
- UINT8 Data[DEBUG_SERIAL_IO_FIFO_DEPTH];
-} DEBUG_SERIAL_FIFO;
-
-//
-// Global Variables
-//
-EFI_HANDLE mSerialIoHandle = NULL;
-UINTN mLoopbackBuffer = 0;
-DEBUG_SERIAL_FIFO mSerialFifoForTerminal = {
- 0, 0, DEBUG_SERIAL_IO_FIFO_DEPTH, { 0 }
-};
-DEBUG_SERIAL_FIFO mSerialFifoForDebug = {
- 0, 0, DEBUG_SERIAL_IO_FIFO_DEPTH, { 0 }
-};
-
-/**
- Detect whether specific FIFO is empty or not.
-
- @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO.
-
- @return whether specific FIFO is empty or not.
-
-**/
-BOOLEAN
-IsDebugTerminalFifoEmpty (
- IN DEBUG_SERIAL_FIFO *Fifo
- )
-{
- if (Fifo->Surplus == DEBUG_SERIAL_IO_FIFO_DEPTH) {
- return TRUE;
- }
-
- return FALSE;
-}
-
-/**
- Detect whether specific FIFO is full or not.
-
- @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO.
-
- @return whether specific FIFO is full or not.
-
-**/
-BOOLEAN
-IsDebugTerminalFifoFull (
- IN DEBUG_SERIAL_FIFO *Fifo
- )
-
-{
- if (Fifo->Surplus == 0) {
- return TRUE;
- }
-
- return FALSE;
-}
-
-/**
- Add data to specific FIFO.
-
- @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO.
- @param[in] Data The data added to FIFO.
-
- @retval EFI_SUCCESS Add data to specific FIFO successfully.
- @retval EFI_OUT_OF_RESOURCE Failed to add data because FIFO is already full.
-
-**/
-EFI_STATUS
-DebugTerminalFifoAdd (
- IN DEBUG_SERIAL_FIFO *Fifo,
- IN UINT8 Data
- )
-
-{
- //
- // if FIFO full can not add data
- //
- if (IsDebugTerminalFifoFull (Fifo)) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- //
- // FIFO is not full can add data
- //
- Fifo->Data[Fifo->Last] = Data;
- Fifo->Surplus--;
- Fifo->Last++;
- if (Fifo->Last == DEBUG_SERIAL_IO_FIFO_DEPTH) {
- Fifo->Last = 0;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Remove data from specific FIFO.
-
- @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO.
- @param[out] Data The data removed from FIFO.
-
- @retval EFI_SUCCESS Remove data from specific FIFO successfully.
- @retval EFI_OUT_OF_RESOURCE Failed to remove data because FIFO is empty.
-
-**/
-EFI_STATUS
-DebugTerminalFifoRemove (
- IN DEBUG_SERIAL_FIFO *Fifo,
- OUT UINT8 *Data
- )
-{
- //
- // if FIFO is empty, no data can remove
- //
- if (IsDebugTerminalFifoEmpty (Fifo)) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- //
- // FIFO is not empty, can remove data
- //
- *Data = Fifo->Data[Fifo->First];
- Fifo->Surplus++;
- Fifo->First++;
- if (Fifo->First == DEBUG_SERIAL_IO_FIFO_DEPTH) {
- Fifo->First = 0;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Install EFI Serial IO protocol based on Debug Communication Library.
-
-**/
-VOID
-InstallSerialIo (
- VOID
- )
-{
- EFI_STATUS Status;
-
- Status = gBS->InstallMultipleProtocolInterfaces (
- &mSerialIoHandle,
- &gEfiDevicePathProtocolGuid,
- &mSerialIoDevicePath,
- &gEfiSerialIoProtocolGuid,
- &mSerialIo,
- NULL
- );
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "Debug Agent: Failed to install EFI Serial IO Protocol on Debug Port!\n"));
- }
-}
-
-/**
- Reset serial device.
-
- @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
-
- @retval EFI_SUCCESS Reset successfully.
-
-**/
-EFI_STATUS
-EFIAPI
-SerialReset (
- IN EFI_SERIAL_IO_PROTOCOL *This
- )
-{
- mSerialIoMode.ControlMask = SERIAL_PORT_DEFAULT_CONTROL_MASK;
- mLoopbackBuffer = 0;
- //
- // Not reset serial device hardware indeed.
- //
- return EFI_SUCCESS;
-}
-
-/**
- Set new attributes to a serial device.
-
- @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
- @param[in] BaudRate The baudrate of the serial device.
- @param[in] ReceiveFifoDepth The depth of receive FIFO buffer.
- @param[in] Timeout The request timeout for a single char.
- @param[in] Parity The type of parity used in serial device.
- @param[in] DataBits Number of databits used in serial device.
- @param[in] StopBits Number of stopbits used in serial device.
-
- @retval EFI_SUCCESS The new attributes were set.
- @retval EFI_INVALID_PARAMETER One or more attributes have an unsupported value.
- @retval EFI_DEVICE_ERROR The serial device is not functioning correctly (no return).
-
-**/
-EFI_STATUS
-EFIAPI
-SerialSetAttributes (
- IN EFI_SERIAL_IO_PROTOCOL *This,
- IN UINT64 BaudRate,
- IN UINT32 ReceiveFifoDepth,
- IN UINT32 Timeout,
- IN EFI_PARITY_TYPE Parity,
- IN UINT8 DataBits,
- IN EFI_STOP_BITS_TYPE StopBits
- )
-{
- //
- // The Debug Communication Library CAN NOT change communications parameters (if it has)
- // actually. Because it also has no any idea on what parameters are based on, we cannot
- // check the input parameters (like BaudRate, Parity, DataBits and StopBits).
- //
-
- //
- // Update the Timeout value in the mode structure based on the request.
- // The Debug Communication Library can not support a timeout on writes, but the timeout on
- // reads can be provided by this module.
- //
- if (Timeout == 0) {
- mSerialIoMode.Timeout = SERIAL_PORT_DEFAULT_TIMEOUT;
- } else {
- mSerialIoMode.Timeout = Timeout;
- }
-
- //
- // Update the ReceiveFifoDepth value in the mode structure based on the request.
- // This module assumes that the Debug Communication Library uses a FIFO depth of
- // SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH. The Debug Communication Library may actually be
- // using a larger FIFO, but there is no way to tell.
- //
- if ((ReceiveFifoDepth == 0) || (ReceiveFifoDepth >= SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH)) {
- mSerialIoMode.ReceiveFifoDepth = SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH;
- } else {
- return EFI_INVALID_PARAMETER;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Set Control Bits.
-
- @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
- @param[in] Control Control bits that can be settable.
-
- @retval EFI_SUCCESS New Control bits were set successfully.
- @retval EFI_UNSUPPORTED The Control bits wanted to set are not supported.
-
-**/
-EFI_STATUS
-EFIAPI
-SerialSetControl (
- IN EFI_SERIAL_IO_PROTOCOL *This,
- IN UINT32 Control
- )
-{
- //
- // The only control bit supported by this module is software loopback.
- // If any other bit is set, then return an error
- //
- if ((Control & (~EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE)) != 0) {
- return EFI_UNSUPPORTED;
- }
-
- mSerialIoMode.ControlMask = Control;
- 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 (!IsDebugTerminalFifoEmpty (&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;
-}
-
-/**
- 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;
-}
-
-/**
- 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;
- }
-
- DebugAgentReadBuffer (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;
-}
-
-/**
- Read the Attach/Break-in symbols from the debug port.
-
- @param[in] Handle Pointer to Debug Port handle.
- @param[out] BreakSymbol Returned break symbol.
-
- @retval EFI_SUCCESS Read the symbol in BreakSymbol.
- @retval EFI_NOT_FOUND No read the break symbol.
-
-**/
-EFI_STATUS
-DebugReadBreakFromDebugPort (
- IN DEBUG_PORT_HANDLE Handle,
- OUT UINT8 *BreakSymbol
- )
-{
- EFI_STATUS Status;
- DEBUG_PACKET_HEADER DebugHeader;
- UINT8 *Data8;
-
- *BreakSymbol = 0;
- //
- // If Debug Port buffer has data, read it till it was break symbol or Debug Port buffer empty.
- //
- Data8 = (UINT8 *)&DebugHeader;
- while (TRUE) {
- //
- // If start symbol is not received
- //
- if (!DebugPortPollBuffer (Handle)) {
- //
- // If no data in Debug Port, exit
- //
- break;
- }
-
- //
- // Try to read the start symbol
- //
- DebugAgentReadBuffer (Handle, Data8, 1, 0);
- if (*Data8 == DEBUG_STARTING_SYMBOL_ATTACH) {
- DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Debug Timer attach symbol received %x", *Data8);
- *BreakSymbol = *Data8;
- return EFI_SUCCESS;
- }
-
- if (*Data8 == DEBUG_STARTING_SYMBOL_NORMAL) {
- Status = ReadRemainingBreakPacket (Handle, &DebugHeader);
- if (Status == EFI_SUCCESS) {
- DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Debug Timer break symbol received %x", DebugHeader.Command);
- *BreakSymbol = DebugHeader.Command;
- return EFI_SUCCESS;
- }
-
- if (Status == EFI_TIMEOUT) {
- break;
- }
- } else {
- //
- // Add to Terminal FIFO
- //
- DebugTerminalFifoAdd (&mSerialFifoForTerminal, *Data8);
- }
- }
-
- return EFI_NOT_FOUND;
-}
-
-/**
- Read the Attach/Break-in symbols.
-
- @param[in] Handle Pointer to Debug Port handle.
- @param[out] BreakSymbol Returned break symbol.
-
- @retval EFI_SUCCESS Read the symbol in BreakSymbol.
- @retval EFI_NOT_FOUND No read the break symbol.
-
-**/
-EFI_STATUS
-DebugReadBreakSymbol (
- IN DEBUG_PORT_HANDLE Handle,
- OUT UINT8 *BreakSymbol
- )
-{
- EFI_STATUS Status;
- UINT8 Data8;
-
- //
- // Read break symbol from debug FIFO firstly
- //
- Status = DebugTerminalFifoRemove (&mSerialFifoForDebug, &Data8);
- if (Status == EFI_SUCCESS) {
- *BreakSymbol = Data8;
- return EFI_SUCCESS;
- } else {
- //
- // Read Break symbol from debug port
- //
- return DebugReadBreakFromDebugPort (Handle, BreakSymbol);
- }
-}
+/** @file + Install Serial IO Protocol that layers on top of a Debug Communication Library instance. + + Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "DxeDebugAgentLib.h" + +// +// Serial I/O Protocol Interface definitions. +// + +/** + Reset serial device. + + @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL. + + @retval EFI_SUCCESS Reset successfully. + +**/ +EFI_STATUS +EFIAPI +SerialReset ( + IN EFI_SERIAL_IO_PROTOCOL *This + ); + +/** + Set new attributes to a serial device. + + @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL. + @param[in] BaudRate The baudrate of the serial device. + @param[in] ReceiveFifoDepth The depth of receive FIFO buffer. + @param[in] Timeout The request timeout for a single char. + @param[in] Parity The type of parity used in serial device. + @param[in] DataBits Number of databits used in serial device. + @param[in] StopBits Number of stopbits used in serial device. + + @retval EFI_SUCCESS The new attributes were set. + @retval EFI_INVALID_PARAMETER One or more attributes have an unsupported value. + @retval EFI_DEVICE_ERROR The serial device is not functioning correctly (no return). + +**/ +EFI_STATUS +EFIAPI +SerialSetAttributes ( + IN EFI_SERIAL_IO_PROTOCOL *This, + IN UINT64 BaudRate, + IN UINT32 ReceiveFifoDepth, + IN UINT32 Timeout, + IN EFI_PARITY_TYPE Parity, + IN UINT8 DataBits, + IN EFI_STOP_BITS_TYPE StopBits + ); + +/** + Set Control Bits. + + @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL. + @param[in] Control Control bits that can be settable. + + @retval EFI_SUCCESS New Control bits were set successfully. + @retval EFI_UNSUPPORTED The Control bits wanted to set are not supported. + +**/ +EFI_STATUS +EFIAPI +SerialSetControl ( + IN EFI_SERIAL_IO_PROTOCOL *This, + IN UINT32 Control + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +// +// Serial Driver Defaults +// +#define SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH 1 +#define SERIAL_PORT_DEFAULT_TIMEOUT 1000000 +#define SERIAL_PORT_DEFAULT_CONTROL_MASK 0 +#define SERIAL_PORT_LOOPBACK_BUFFER_FULL BIT8 + +// +// EFI_SERIAL_IO_MODE instance +// +EFI_SERIAL_IO_MODE mSerialIoMode = { + SERIAL_PORT_DEFAULT_CONTROL_MASK, + SERIAL_PORT_DEFAULT_TIMEOUT, + 0, // default BaudRate + SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH, + 0, // default DataBits + 0, // default Parity + 0 // default StopBits +}; + +// +// EFI_SERIAL_IO_PROTOCOL instance +// +EFI_SERIAL_IO_PROTOCOL mSerialIo = { + SERIAL_IO_INTERFACE_REVISION, + SerialReset, + SerialSetAttributes, + SerialSetControl, + SerialGetControl, + SerialWrite, + SerialRead, + &mSerialIoMode +}; + +// +// Serial IO Device Path definition +// +typedef struct { + VENDOR_DEVICE_PATH VendorDevicePath; + UART_DEVICE_PATH UartDevicePath; + EFI_DEVICE_PATH_PROTOCOL EndDevicePath; +} SERIAL_IO_DEVICE_PATH; + +// +// Serial IO Device Patch instance +// +SERIAL_IO_DEVICE_PATH mSerialIoDevicePath = { + { + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + { + (UINT8)(sizeof (VENDOR_DEVICE_PATH)), + (UINT8)((sizeof (VENDOR_DEVICE_PATH)) >> 8) + } + }, + EFI_DEBUG_AGENT_GUID, + }, + { + { + MESSAGING_DEVICE_PATH, + MSG_UART_DP, + { + (UINT8)(sizeof (UART_DEVICE_PATH)), + (UINT8)((sizeof (UART_DEVICE_PATH)) >> 8) + } + }, + 0, + 0, // default BaudRate + 0, // default DataBits + 0, // default Parity + 0, // default StopBits + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + END_DEVICE_PATH_LENGTH, + 0 + } + } +}; + +#define DEBUG_SERIAL_IO_FIFO_DEPTH 10 +// +// Data buffer for Terminal input character and Debug Symbols. +// The depth is DEBUG_SERIAL_IO_FIFO_DEPTH. +// Fields: +// First UINT8: The index of the first data in array Data[]. +// Last UINT8: The index, which you can put a new data into array Data[]. +// Surplus UINT8: Identify how many data you can put into array Data[]. +// Data[] UINT8: An array, which used to store data. +// +typedef struct { + UINT8 First; + UINT8 Last; + UINT8 Surplus; + UINT8 Data[DEBUG_SERIAL_IO_FIFO_DEPTH]; +} DEBUG_SERIAL_FIFO; + +// +// Global Variables +// +EFI_HANDLE mSerialIoHandle = NULL; +UINTN mLoopbackBuffer = 0; +DEBUG_SERIAL_FIFO mSerialFifoForTerminal = { + 0, 0, DEBUG_SERIAL_IO_FIFO_DEPTH, { 0 } +}; +DEBUG_SERIAL_FIFO mSerialFifoForDebug = { + 0, 0, DEBUG_SERIAL_IO_FIFO_DEPTH, { 0 } +}; + +/** + Detect whether specific FIFO is empty or not. + + @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO. + + @return whether specific FIFO is empty or not. + +**/ +BOOLEAN +IsDebugTerminalFifoEmpty ( + IN DEBUG_SERIAL_FIFO *Fifo + ) +{ + if (Fifo->Surplus == DEBUG_SERIAL_IO_FIFO_DEPTH) { + return TRUE; + } + + return FALSE; +} + +/** + Detect whether specific FIFO is full or not. + + @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO. + + @return whether specific FIFO is full or not. + +**/ +BOOLEAN +IsDebugTerminalFifoFull ( + IN DEBUG_SERIAL_FIFO *Fifo + ) + +{ + if (Fifo->Surplus == 0) { + return TRUE; + } + + return FALSE; +} + +/** + Add data to specific FIFO. + + @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO. + @param[in] Data The data added to FIFO. + + @retval EFI_SUCCESS Add data to specific FIFO successfully. + @retval EFI_OUT_OF_RESOURCE Failed to add data because FIFO is already full. + +**/ +EFI_STATUS +DebugTerminalFifoAdd ( + IN DEBUG_SERIAL_FIFO *Fifo, + IN UINT8 Data + ) + +{ + // + // if FIFO full can not add data + // + if (IsDebugTerminalFifoFull (Fifo)) { + return EFI_OUT_OF_RESOURCES; + } + + // + // FIFO is not full can add data + // + Fifo->Data[Fifo->Last] = Data; + Fifo->Surplus--; + Fifo->Last++; + if (Fifo->Last == DEBUG_SERIAL_IO_FIFO_DEPTH) { + Fifo->Last = 0; + } + + return EFI_SUCCESS; +} + +/** + Remove data from specific FIFO. + + @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO. + @param[out] Data The data removed from FIFO. + + @retval EFI_SUCCESS Remove data from specific FIFO successfully. + @retval EFI_OUT_OF_RESOURCE Failed to remove data because FIFO is empty. + +**/ +EFI_STATUS +DebugTerminalFifoRemove ( + IN DEBUG_SERIAL_FIFO *Fifo, + OUT UINT8 *Data + ) +{ + // + // if FIFO is empty, no data can remove + // + if (IsDebugTerminalFifoEmpty (Fifo)) { + return EFI_OUT_OF_RESOURCES; + } + + // + // FIFO is not empty, can remove data + // + *Data = Fifo->Data[Fifo->First]; + Fifo->Surplus++; + Fifo->First++; + if (Fifo->First == DEBUG_SERIAL_IO_FIFO_DEPTH) { + Fifo->First = 0; + } + + return EFI_SUCCESS; +} + +/** + Install EFI Serial IO protocol based on Debug Communication Library. + +**/ +VOID +InstallSerialIo ( + VOID + ) +{ + EFI_STATUS Status; + + Status = gBS->InstallMultipleProtocolInterfaces ( + &mSerialIoHandle, + &gEfiDevicePathProtocolGuid, + &mSerialIoDevicePath, + &gEfiSerialIoProtocolGuid, + &mSerialIo, + NULL + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Debug Agent: Failed to install EFI Serial IO Protocol on Debug Port!\n")); + } +} + +/** + Reset serial device. + + @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL. + + @retval EFI_SUCCESS Reset successfully. + +**/ +EFI_STATUS +EFIAPI +SerialReset ( + IN EFI_SERIAL_IO_PROTOCOL *This + ) +{ + mSerialIoMode.ControlMask = SERIAL_PORT_DEFAULT_CONTROL_MASK; + mLoopbackBuffer = 0; + // + // Not reset serial device hardware indeed. + // + return EFI_SUCCESS; +} + +/** + Set new attributes to a serial device. + + @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL. + @param[in] BaudRate The baudrate of the serial device. + @param[in] ReceiveFifoDepth The depth of receive FIFO buffer. + @param[in] Timeout The request timeout for a single char. + @param[in] Parity The type of parity used in serial device. + @param[in] DataBits Number of databits used in serial device. + @param[in] StopBits Number of stopbits used in serial device. + + @retval EFI_SUCCESS The new attributes were set. + @retval EFI_INVALID_PARAMETER One or more attributes have an unsupported value. + @retval EFI_DEVICE_ERROR The serial device is not functioning correctly (no return). + +**/ +EFI_STATUS +EFIAPI +SerialSetAttributes ( + IN EFI_SERIAL_IO_PROTOCOL *This, + IN UINT64 BaudRate, + IN UINT32 ReceiveFifoDepth, + IN UINT32 Timeout, + IN EFI_PARITY_TYPE Parity, + IN UINT8 DataBits, + IN EFI_STOP_BITS_TYPE StopBits + ) +{ + // + // The Debug Communication Library CAN NOT change communications parameters (if it has) + // actually. Because it also has no any idea on what parameters are based on, we cannot + // check the input parameters (like BaudRate, Parity, DataBits and StopBits). + // + + // + // Update the Timeout value in the mode structure based on the request. + // The Debug Communication Library can not support a timeout on writes, but the timeout on + // reads can be provided by this module. + // + if (Timeout == 0) { + mSerialIoMode.Timeout = SERIAL_PORT_DEFAULT_TIMEOUT; + } else { + mSerialIoMode.Timeout = Timeout; + } + + // + // Update the ReceiveFifoDepth value in the mode structure based on the request. + // This module assumes that the Debug Communication Library uses a FIFO depth of + // SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH. The Debug Communication Library may actually be + // using a larger FIFO, but there is no way to tell. + // + if ((ReceiveFifoDepth == 0) || (ReceiveFifoDepth >= SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH)) { + mSerialIoMode.ReceiveFifoDepth = SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH; + } else { + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} + +/** + Set Control Bits. + + @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL. + @param[in] Control Control bits that can be settable. + + @retval EFI_SUCCESS New Control bits were set successfully. + @retval EFI_UNSUPPORTED The Control bits wanted to set are not supported. + +**/ +EFI_STATUS +EFIAPI +SerialSetControl ( + IN EFI_SERIAL_IO_PROTOCOL *This, + IN UINT32 Control + ) +{ + // + // The only control bit supported by this module is software loopback. + // If any other bit is set, then return an error + // + if ((Control & (~EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE)) != 0) { + return EFI_UNSUPPORTED; + } + + mSerialIoMode.ControlMask = Control; + 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 (!IsDebugTerminalFifoEmpty (&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; +} + +/** + 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; +} + +/** + 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; + } + + DebugAgentReadBuffer (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; +} + +/** + Read the Attach/Break-in symbols from the debug port. + + @param[in] Handle Pointer to Debug Port handle. + @param[out] BreakSymbol Returned break symbol. + + @retval EFI_SUCCESS Read the symbol in BreakSymbol. + @retval EFI_NOT_FOUND No read the break symbol. + +**/ +EFI_STATUS +DebugReadBreakFromDebugPort ( + IN DEBUG_PORT_HANDLE Handle, + OUT UINT8 *BreakSymbol + ) +{ + EFI_STATUS Status; + DEBUG_PACKET_HEADER DebugHeader; + UINT8 *Data8; + + *BreakSymbol = 0; + // + // If Debug Port buffer has data, read it till it was break symbol or Debug Port buffer empty. + // + Data8 = (UINT8 *)&DebugHeader; + while (TRUE) { + // + // If start symbol is not received + // + if (!DebugPortPollBuffer (Handle)) { + // + // If no data in Debug Port, exit + // + break; + } + + // + // Try to read the start symbol + // + DebugAgentReadBuffer (Handle, Data8, 1, 0); + if (*Data8 == DEBUG_STARTING_SYMBOL_ATTACH) { + DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Debug Timer attach symbol received %x", *Data8); + *BreakSymbol = *Data8; + return EFI_SUCCESS; + } + + if (*Data8 == DEBUG_STARTING_SYMBOL_NORMAL) { + Status = ReadRemainingBreakPacket (Handle, &DebugHeader); + if (Status == EFI_SUCCESS) { + DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Debug Timer break symbol received %x", DebugHeader.Command); + *BreakSymbol = DebugHeader.Command; + return EFI_SUCCESS; + } + + if (Status == EFI_TIMEOUT) { + break; + } + } else { + // + // Add to Terminal FIFO + // + DebugTerminalFifoAdd (&mSerialFifoForTerminal, *Data8); + } + } + + return EFI_NOT_FOUND; +} + +/** + Read the Attach/Break-in symbols. + + @param[in] Handle Pointer to Debug Port handle. + @param[out] BreakSymbol Returned break symbol. + + @retval EFI_SUCCESS Read the symbol in BreakSymbol. + @retval EFI_NOT_FOUND No read the break symbol. + +**/ +EFI_STATUS +DebugReadBreakSymbol ( + IN DEBUG_PORT_HANDLE Handle, + OUT UINT8 *BreakSymbol + ) +{ + EFI_STATUS Status; + UINT8 Data8; + + // + // Read break symbol from debug FIFO firstly + // + Status = DebugTerminalFifoRemove (&mSerialFifoForDebug, &Data8); + if (Status == EFI_SUCCESS) { + *BreakSymbol = Data8; + return EFI_SUCCESS; + } else { + // + // Read Break symbol from debug port + // + return DebugReadBreakFromDebugPort (Handle, BreakSymbol); + } +} diff --git a/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.inf b/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.inf index aa50048780..562a44f460 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.inf +++ b/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.inf @@ -1,96 +1,96 @@ -## @file
-# Debug Agent library instance for Dxe Core and Dxe modules.
-#
-# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-#
-##
-
-[Defines]
- INF_VERSION = 0x00010005
- BASE_NAME = DxeDebugAgentLib
- MODULE_UNI_FILE = DxeDebugAgentLib.uni
- FILE_GUID = BA6BAD25-B814-4747-B0B0-0FBB61D40B90
- MODULE_TYPE = DXE_DRIVER
- VERSION_STRING = 0.8
- LIBRARY_CLASS = DebugAgentLib|DXE_CORE DXE_DRIVER
-
- CONSTRUCTOR = DxeDebugAgentLibConstructor
-
-#
-# The following information is for reference only and not required by the build tools.
-#
-# VALID_ARCHITECTURES = IA32 X64
-#
-
-[Sources.common]
- DxeDebugAgent/DxeDebugAgentLib.c
- DxeDebugAgent/DxeDebugAgentLib.h
- DxeDebugAgent/SerialIo.c
- DebugAgentCommon/DebugAgent.c
- DebugAgentCommon/DebugAgent.h
- DebugAgentCommon/DebugTimer.c
- DebugAgentCommon/DebugTimer.h
- DebugAgentCommon/DebugMp.c
- DebugAgentCommon/DebugMp.h
-
-[Sources.Ia32]
- DebugAgentCommon/Ia32/AsmFuncs.nasm
- DebugAgentCommon/Ia32/ArchDebugSupport.h
- DebugAgentCommon/Ia32/ArchDebugSupport.c
- DebugAgentCommon/Ia32/DebugException.h
-
-[Sources.X64]
- DebugAgentCommon/X64/AsmFuncs.nasm
- DebugAgentCommon/X64/ArchDebugSupport.h
- DebugAgentCommon/X64/ArchDebugSupport.c
- DebugAgentCommon/X64/DebugException.h
-
-[Packages]
- MdePkg/MdePkg.dec
- MdeModulePkg/MdeModulePkg.dec
- UefiCpuPkg/UefiCpuPkg.dec
- SourceLevelDebugPkg/SourceLevelDebugPkg.dec
-
-[LibraryClasses]
- BaseLib
- BaseMemoryLib
- ResetSystemLib
- IoLib
- HobLib
- DebugCommunicationLib
- UefiBootServicesTableLib
- UefiLib
- PcdLib
- SynchronizationLib
- MemoryAllocationLib
- LocalApicLib
- TimerLib
- PrintLib
- PeCoffGetEntryPointLib
- PeCoffExtraActionLib
- MemoryAllocationLib
-
-[Guids]
- ## PRODUCES ## SystemTable
- ## CONSUMES ## HOB
- gEfiDebugAgentGuid
- ## SOMETIMES_CONSUMES ## SystemTable
- ## SOMETIMES_PRODUCES ## SystemTable
- gEfiVectorHandoffTableGuid
-
-[Ppis]
- gEfiVectorHandoffInfoPpiGuid ## UNDEFINED
-
-[Protocols]
- gEfiSerialIoProtocolGuid ## SOMETIMES_PRODUCES
- gEfiDevicePathProtocolGuid ## SOMETIMES_PRODUCES
-
-[Pcd]
- gEfiMdePkgTokenSpaceGuid.PcdFSBClock ## SOMETIMES_CONSUMES
- gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdExceptionsIgnoredByDebugger ## SOMETIMES_CONSUMES
- gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdDebugPortHandleBufferSize ## CONSUMES
- gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdTransferProtocolRevision ## CONSUMES
-
+## @file +# Debug Agent library instance for Dxe Core and Dxe modules. +# +# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DxeDebugAgentLib + MODULE_UNI_FILE = DxeDebugAgentLib.uni + FILE_GUID = BA6BAD25-B814-4747-B0B0-0FBB61D40B90 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 0.8 + LIBRARY_CLASS = DebugAgentLib|DXE_CORE DXE_DRIVER + + CONSTRUCTOR = DxeDebugAgentLibConstructor + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources.common] + DxeDebugAgent/DxeDebugAgentLib.c + DxeDebugAgent/DxeDebugAgentLib.h + DxeDebugAgent/SerialIo.c + DebugAgentCommon/DebugAgent.c + DebugAgentCommon/DebugAgent.h + DebugAgentCommon/DebugTimer.c + DebugAgentCommon/DebugTimer.h + DebugAgentCommon/DebugMp.c + DebugAgentCommon/DebugMp.h + +[Sources.Ia32] + DebugAgentCommon/Ia32/AsmFuncs.nasm + DebugAgentCommon/Ia32/ArchDebugSupport.h + DebugAgentCommon/Ia32/ArchDebugSupport.c + DebugAgentCommon/Ia32/DebugException.h + +[Sources.X64] + DebugAgentCommon/X64/AsmFuncs.nasm + DebugAgentCommon/X64/ArchDebugSupport.h + DebugAgentCommon/X64/ArchDebugSupport.c + DebugAgentCommon/X64/DebugException.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + SourceLevelDebugPkg/SourceLevelDebugPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + ResetSystemLib + IoLib + HobLib + DebugCommunicationLib + UefiBootServicesTableLib + UefiLib + PcdLib + SynchronizationLib + MemoryAllocationLib + LocalApicLib + TimerLib + PrintLib + PeCoffGetEntryPointLib + PeCoffExtraActionLib + MemoryAllocationLib + +[Guids] + ## PRODUCES ## SystemTable + ## CONSUMES ## HOB + gEfiDebugAgentGuid + ## SOMETIMES_CONSUMES ## SystemTable + ## SOMETIMES_PRODUCES ## SystemTable + gEfiVectorHandoffTableGuid + +[Ppis] + gEfiVectorHandoffInfoPpiGuid ## UNDEFINED + +[Protocols] + gEfiSerialIoProtocolGuid ## SOMETIMES_PRODUCES + gEfiDevicePathProtocolGuid ## SOMETIMES_PRODUCES + +[Pcd] + gEfiMdePkgTokenSpaceGuid.PcdFSBClock ## SOMETIMES_CONSUMES + gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdExceptionsIgnoredByDebugger ## SOMETIMES_CONSUMES + gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdDebugPortHandleBufferSize ## CONSUMES + gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdTransferProtocolRevision ## CONSUMES + diff --git a/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.uni b/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.uni index fef8dafd1c..b8444d1eef 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.uni +++ b/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.uni @@ -1,16 +1,16 @@ -// /** @file
-// Debug Agent library instance for Dxe Core and Dxe modules.
-//
-// Debug Agent library instance for DXE Core and DXE modules.
-//
-// Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
-//
-// SPDX-License-Identifier: BSD-2-Clause-Patent
-//
-// **/
-
-
-#string STR_MODULE_ABSTRACT #language en-US "Debug Agent library instance for DXE Core and DXE modules"
-
-#string STR_MODULE_DESCRIPTION #language en-US "Debug Agent library instance for DXE Core and DXE modules."
-
+// /** @file +// Debug Agent library instance for Dxe Core and Dxe modules. +// +// Debug Agent library instance for DXE Core and DXE modules. +// +// Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR> +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Debug Agent library instance for DXE Core and DXE modules" + +#string STR_MODULE_DESCRIPTION #language en-US "Debug Agent library instance for DXE Core and DXE modules." + diff --git a/SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgent/SecPeiDebugAgentLib.c b/SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgent/SecPeiDebugAgentLib.c index b32754fc2a..17bc21309c 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgent/SecPeiDebugAgentLib.c +++ b/SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgent/SecPeiDebugAgentLib.c @@ -1,721 +1,721 @@ -/** @file
- SEC Core Debug Agent Library instance implementation.
-
- Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "SecPeiDebugAgentLib.h"
-
-GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mSkipBreakpoint = FALSE;
-
-GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_VECTOR_HANDOFF_INFO_PPI mVectorHandoffInfoPpi = {
- &mVectorHandoffInfoDebugAgent[0]
-};
-
-//
-// Ppis to be installed
-//
-GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_PPI_DESCRIPTOR mVectorHandoffInfoPpiList[] = {
- {
- (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
- &gEfiVectorHandoffInfoPpiGuid,
- &mVectorHandoffInfoPpi
- }
-};
-
-GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_NOTIFY_DESCRIPTOR mDebugAgentMemoryDiscoveredNotifyList[1] = {
- {
- (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
- &gEfiPeiMemoryDiscoveredPpiGuid,
- DebugAgentCallbackMemoryDiscoveredPpi
- }
-};
-
-/**
- Check if debug agent support multi-processor.
-
- @retval TRUE Multi-processor is supported.
- @retval FALSE Multi-processor is not supported.
-
-**/
-BOOLEAN
-MultiProcessorDebugSupport (
- VOID
- )
-{
- return FALSE;
-}
-
-/**
- Read the Attach/Break-in symbols from the debug port.
-
- @param[in] Handle Pointer to Debug Port handle.
- @param[out] BreakSymbol Returned break symbol.
-
- @retval EFI_SUCCESS Read the symbol in BreakSymbol.
- @retval EFI_NOT_FOUND No read the break symbol.
-
-**/
-EFI_STATUS
-DebugReadBreakSymbol (
- IN DEBUG_PORT_HANDLE Handle,
- OUT UINT8 *BreakSymbol
- )
-{
- EFI_STATUS Status;
- DEBUG_PACKET_HEADER DebugHeader;
- UINT8 *Data8;
-
- *BreakSymbol = 0;
- //
- // If Debug Port buffer has data, read it till it was break symbol or Debug Port buffer empty.
- //
- Data8 = (UINT8 *)&DebugHeader;
- while (TRUE) {
- //
- // If start symbol is not received
- //
- if (!DebugPortPollBuffer (Handle)) {
- //
- // If no data in Debug Port, exit
- //
- break;
- }
-
- //
- // Try to read the start symbol
- //
- DebugAgentReadBuffer (Handle, Data8, 1, 0);
- if (*Data8 == DEBUG_STARTING_SYMBOL_ATTACH) {
- *BreakSymbol = *Data8;
- DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Debug Timer attach symbol received %x", *BreakSymbol);
- return EFI_SUCCESS;
- }
-
- if (*Data8 == DEBUG_STARTING_SYMBOL_NORMAL) {
- Status = ReadRemainingBreakPacket (Handle, &DebugHeader);
- if (Status == EFI_SUCCESS) {
- *BreakSymbol = DebugHeader.Command;
- DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Debug Timer break symbol received %x", *BreakSymbol);
- return EFI_SUCCESS;
- }
-
- if (Status == EFI_TIMEOUT) {
- break;
- }
- }
- }
-
- return EFI_NOT_FOUND;
-}
-
-/**
- Get the pointer to location saved Mailbox pointer from IDT entry.
-
-**/
-VOID *
-GetLocationSavedMailboxPointerInIdtEntry (
- VOID
- )
-{
- UINTN *MailboxLocation;
-
- MailboxLocation = (UINTN *)GetExceptionHandlerInIdtEntry (DEBUG_MAILBOX_VECTOR);
- //
- // *MailboxLocation is the pointer to Mailbox
- //
- VerifyMailboxChecksum ((DEBUG_AGENT_MAILBOX *)(*MailboxLocation));
- return MailboxLocation;
-}
-
-/**
- Set the pointer of Mailbox into IDT entry before memory is ready.
-
- @param[in] MailboxLocation Pointer to location saved Mailbox pointer.
-
-**/
-VOID
-SetLocationSavedMailboxPointerInIdtEntry (
- IN VOID *MailboxLocation
- )
-{
- SetExceptionHandlerInIdtEntry (DEBUG_MAILBOX_VECTOR, MailboxLocation);
-}
-
-/**
- Get the location of Mailbox pointer from the GUIDed HOB.
-
- @return Pointer to the location saved Mailbox pointer.
-
-**/
-UINT64 *
-GetMailboxLocationFromHob (
- VOID
- )
-{
- EFI_HOB_GUID_TYPE *GuidHob;
-
- GuidHob = GetFirstGuidHob (&gEfiDebugAgentGuid);
- if (GuidHob == NULL) {
- return NULL;
- }
-
- return (UINT64 *)(GET_GUID_HOB_DATA (GuidHob));
-}
-
-/**
- Get Debug Agent Mailbox pointer.
-
- @return Mailbox pointer.
-
-**/
-DEBUG_AGENT_MAILBOX *
-GetMailboxPointer (
- VOID
- )
-{
- UINT64 DebugPortHandle;
- UINT64 *MailboxLocationInIdt;
- UINT64 *MailboxLocationInHob;
- DEBUG_AGENT_MAILBOX *Mailbox;
-
- //
- // Get mailbox from IDT entry firstly
- //
- MailboxLocationInIdt = GetLocationSavedMailboxPointerInIdtEntry ();
- Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocationInIdt);
- //
- // Cannot used GetDebugFlag() to get Debug Flag to avoid GetMailboxPointer() nested
- //
- if ((Mailbox->DebugFlag.Bits.CheckMailboxInHob != 1) ||
- (Mailbox->DebugFlag.Bits.InitArch != DEBUG_ARCH_SYMBOL))
- {
- //
- // If mailbox was setup in SEC or the current CPU arch is different from the init arch
- // Debug Agent initialized, return the mailbox from IDT entry directly.
- // Otherwise, we need to check the mailbox location saved in GUIDed HOB further.
- //
- return Mailbox;
- }
-
- MailboxLocationInHob = GetMailboxLocationFromHob ();
- //
- // Compare mailbox in IDT entry with mailbox in HOB,
- // need to fix mailbox location if HOB moved by PEI CORE
- //
- if ((MailboxLocationInHob != MailboxLocationInIdt) && (MailboxLocationInHob != NULL)) {
- Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocationInHob);
- //
- // Fix up Debug Port handler and save new mailbox in IDT entry
- //
- Mailbox = (DEBUG_AGENT_MAILBOX *)((UINTN)Mailbox + ((UINTN)(MailboxLocationInHob) - (UINTN)MailboxLocationInIdt));
- DebugPortHandle = (UINTN)Mailbox->DebugPortHandle + ((UINTN)(MailboxLocationInHob) - (UINTN)MailboxLocationInIdt);
- UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle);
- *MailboxLocationInHob = (UINT64)(UINTN)Mailbox;
- SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationInHob);
- //
- // Clean CheckMailboxInHob flag
- //
- Mailbox->DebugFlag.Bits.CheckMailboxInHob = 0;
- UpdateMailboxChecksum (Mailbox);
- }
-
- return Mailbox;
-}
-
-/**
- Get debug port handle.
-
- @return Debug port handle.
-
-**/
-DEBUG_PORT_HANDLE
-GetDebugPortHandle (
- VOID
- )
-{
- DEBUG_AGENT_MAILBOX *DebugAgentMailbox;
-
- DebugAgentMailbox = GetMailboxPointer ();
-
- return (DEBUG_PORT_HANDLE)(UINTN)(DebugAgentMailbox->DebugPortHandle);
-}
-
-/**
- Debug Agent provided notify callback function on Memory Discovered PPI.
-
- @param[in] PeiServices Indirect reference to the PEI Services Table.
- @param[in] NotifyDescriptor Address of the notification descriptor data structure.
- @param[in] Ppi Address of the PPI that was installed.
-
- @retval EFI_SUCCESS If the function completed successfully.
-
-**/
-EFI_STATUS
-EFIAPI
-DebugAgentCallbackMemoryDiscoveredPpi (
- IN EFI_PEI_SERVICES **PeiServices,
- IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
- IN VOID *Ppi
- )
-{
- EFI_STATUS Status;
- DEBUG_AGENT_MAILBOX *Mailbox;
- BOOLEAN InterruptStatus;
- EFI_PHYSICAL_ADDRESS Address;
- DEBUG_AGENT_MAILBOX *NewMailbox;
- UINT64 *MailboxLocationInHob;
-
- //
- // Save and disable original interrupt status
- //
- InterruptStatus = SaveAndDisableInterrupts ();
-
- //
- // 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
- );
- ASSERT_EFI_ERROR (Status);
- 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.
- //
- Mailbox = GetMailboxPointer ();
- CopyMem (NewMailbox, Mailbox, sizeof (DEBUG_AGENT_MAILBOX));
- CopyMem (NewMailbox + 1, (VOID *)(UINTN)Mailbox->DebugPortHandle, PcdGet16 (PcdDebugPortHandleBufferSize));
- //
- // Update Mailbox Location pointer in GUIDed HOB and IDT entry with new one
- //
- MailboxLocationInHob = GetMailboxLocationFromHob ();
- ASSERT (MailboxLocationInHob != NULL);
- *MailboxLocationInHob = (UINT64)(UINTN)NewMailbox;
- SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationInHob);
- //
- // Update Debug Port Handle in new Mailbox
- //
- UpdateMailboxContent (NewMailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, (UINT64)(UINTN)(NewMailbox + 1));
- //
- // Set physical memory ready flag
- //
- SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1);
-
- if (IsHostAttached ()) {
- //
- // Trigger one software interrupt to inform HOST
- //
- TriggerSoftInterrupt (MEMORY_READY_SIGNATURE);
- }
-
- //
- // Restore interrupt state.
- //
- SetInterruptState (InterruptStatus);
-
- return EFI_SUCCESS;
-}
-
-/**
- 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 override 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 ((DEBUG_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 ((DEBUG_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 ((DEBUG_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 ((DEBUG_ERROR, "DebugAgent: Input parameter Context cannot be NULL!\n"));
- CpuDeadLoop ();
- }
-
- //
- // Check if Debug Agent has initialized before
- //
- if (IsDebugAgentInitialzed ()) {
- DEBUG ((DEBUG_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 ((DEBUG_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 ((DEBUG_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 memory has been ready, the callback function will be invoked immediately
- //
- Status = PeiServicesNotifyPpi (&mDebugAgentMemoryDiscoveredNotifyList[0]);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_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 ((DEBUG_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 +
- ((UINTN)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 ((DEBUG_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 successfully 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;
- }
-}
-
-/**
- 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);
- }
-}
+/** @file + SEC Core Debug Agent Library instance implementation. + + Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "SecPeiDebugAgentLib.h" + +GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mSkipBreakpoint = FALSE; + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_VECTOR_HANDOFF_INFO_PPI mVectorHandoffInfoPpi = { + &mVectorHandoffInfoDebugAgent[0] +}; + +// +// Ppis to be installed +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_PPI_DESCRIPTOR mVectorHandoffInfoPpiList[] = { + { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiVectorHandoffInfoPpiGuid, + &mVectorHandoffInfoPpi + } +}; + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_NOTIFY_DESCRIPTOR mDebugAgentMemoryDiscoveredNotifyList[1] = { + { + (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiPeiMemoryDiscoveredPpiGuid, + DebugAgentCallbackMemoryDiscoveredPpi + } +}; + +/** + Check if debug agent support multi-processor. + + @retval TRUE Multi-processor is supported. + @retval FALSE Multi-processor is not supported. + +**/ +BOOLEAN +MultiProcessorDebugSupport ( + VOID + ) +{ + return FALSE; +} + +/** + Read the Attach/Break-in symbols from the debug port. + + @param[in] Handle Pointer to Debug Port handle. + @param[out] BreakSymbol Returned break symbol. + + @retval EFI_SUCCESS Read the symbol in BreakSymbol. + @retval EFI_NOT_FOUND No read the break symbol. + +**/ +EFI_STATUS +DebugReadBreakSymbol ( + IN DEBUG_PORT_HANDLE Handle, + OUT UINT8 *BreakSymbol + ) +{ + EFI_STATUS Status; + DEBUG_PACKET_HEADER DebugHeader; + UINT8 *Data8; + + *BreakSymbol = 0; + // + // If Debug Port buffer has data, read it till it was break symbol or Debug Port buffer empty. + // + Data8 = (UINT8 *)&DebugHeader; + while (TRUE) { + // + // If start symbol is not received + // + if (!DebugPortPollBuffer (Handle)) { + // + // If no data in Debug Port, exit + // + break; + } + + // + // Try to read the start symbol + // + DebugAgentReadBuffer (Handle, Data8, 1, 0); + if (*Data8 == DEBUG_STARTING_SYMBOL_ATTACH) { + *BreakSymbol = *Data8; + DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Debug Timer attach symbol received %x", *BreakSymbol); + return EFI_SUCCESS; + } + + if (*Data8 == DEBUG_STARTING_SYMBOL_NORMAL) { + Status = ReadRemainingBreakPacket (Handle, &DebugHeader); + if (Status == EFI_SUCCESS) { + *BreakSymbol = DebugHeader.Command; + DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Debug Timer break symbol received %x", *BreakSymbol); + return EFI_SUCCESS; + } + + if (Status == EFI_TIMEOUT) { + break; + } + } + } + + return EFI_NOT_FOUND; +} + +/** + Get the pointer to location saved Mailbox pointer from IDT entry. + +**/ +VOID * +GetLocationSavedMailboxPointerInIdtEntry ( + VOID + ) +{ + UINTN *MailboxLocation; + + MailboxLocation = (UINTN *)GetExceptionHandlerInIdtEntry (DEBUG_MAILBOX_VECTOR); + // + // *MailboxLocation is the pointer to Mailbox + // + VerifyMailboxChecksum ((DEBUG_AGENT_MAILBOX *)(*MailboxLocation)); + return MailboxLocation; +} + +/** + Set the pointer of Mailbox into IDT entry before memory is ready. + + @param[in] MailboxLocation Pointer to location saved Mailbox pointer. + +**/ +VOID +SetLocationSavedMailboxPointerInIdtEntry ( + IN VOID *MailboxLocation + ) +{ + SetExceptionHandlerInIdtEntry (DEBUG_MAILBOX_VECTOR, MailboxLocation); +} + +/** + Get the location of Mailbox pointer from the GUIDed HOB. + + @return Pointer to the location saved Mailbox pointer. + +**/ +UINT64 * +GetMailboxLocationFromHob ( + VOID + ) +{ + EFI_HOB_GUID_TYPE *GuidHob; + + GuidHob = GetFirstGuidHob (&gEfiDebugAgentGuid); + if (GuidHob == NULL) { + return NULL; + } + + return (UINT64 *)(GET_GUID_HOB_DATA (GuidHob)); +} + +/** + Get Debug Agent Mailbox pointer. + + @return Mailbox pointer. + +**/ +DEBUG_AGENT_MAILBOX * +GetMailboxPointer ( + VOID + ) +{ + UINT64 DebugPortHandle; + UINT64 *MailboxLocationInIdt; + UINT64 *MailboxLocationInHob; + DEBUG_AGENT_MAILBOX *Mailbox; + + // + // Get mailbox from IDT entry firstly + // + MailboxLocationInIdt = GetLocationSavedMailboxPointerInIdtEntry (); + Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocationInIdt); + // + // Cannot used GetDebugFlag() to get Debug Flag to avoid GetMailboxPointer() nested + // + if ((Mailbox->DebugFlag.Bits.CheckMailboxInHob != 1) || + (Mailbox->DebugFlag.Bits.InitArch != DEBUG_ARCH_SYMBOL)) + { + // + // If mailbox was setup in SEC or the current CPU arch is different from the init arch + // Debug Agent initialized, return the mailbox from IDT entry directly. + // Otherwise, we need to check the mailbox location saved in GUIDed HOB further. + // + return Mailbox; + } + + MailboxLocationInHob = GetMailboxLocationFromHob (); + // + // Compare mailbox in IDT entry with mailbox in HOB, + // need to fix mailbox location if HOB moved by PEI CORE + // + if ((MailboxLocationInHob != MailboxLocationInIdt) && (MailboxLocationInHob != NULL)) { + Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocationInHob); + // + // Fix up Debug Port handler and save new mailbox in IDT entry + // + Mailbox = (DEBUG_AGENT_MAILBOX *)((UINTN)Mailbox + ((UINTN)(MailboxLocationInHob) - (UINTN)MailboxLocationInIdt)); + DebugPortHandle = (UINTN)Mailbox->DebugPortHandle + ((UINTN)(MailboxLocationInHob) - (UINTN)MailboxLocationInIdt); + UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle); + *MailboxLocationInHob = (UINT64)(UINTN)Mailbox; + SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationInHob); + // + // Clean CheckMailboxInHob flag + // + Mailbox->DebugFlag.Bits.CheckMailboxInHob = 0; + UpdateMailboxChecksum (Mailbox); + } + + return Mailbox; +} + +/** + Get debug port handle. + + @return Debug port handle. + +**/ +DEBUG_PORT_HANDLE +GetDebugPortHandle ( + VOID + ) +{ + DEBUG_AGENT_MAILBOX *DebugAgentMailbox; + + DebugAgentMailbox = GetMailboxPointer (); + + return (DEBUG_PORT_HANDLE)(UINTN)(DebugAgentMailbox->DebugPortHandle); +} + +/** + Debug Agent provided notify callback function on Memory Discovered PPI. + + @param[in] PeiServices Indirect reference to the PEI Services Table. + @param[in] NotifyDescriptor Address of the notification descriptor data structure. + @param[in] Ppi Address of the PPI that was installed. + + @retval EFI_SUCCESS If the function completed successfully. + +**/ +EFI_STATUS +EFIAPI +DebugAgentCallbackMemoryDiscoveredPpi ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ) +{ + EFI_STATUS Status; + DEBUG_AGENT_MAILBOX *Mailbox; + BOOLEAN InterruptStatus; + EFI_PHYSICAL_ADDRESS Address; + DEBUG_AGENT_MAILBOX *NewMailbox; + UINT64 *MailboxLocationInHob; + + // + // Save and disable original interrupt status + // + InterruptStatus = SaveAndDisableInterrupts (); + + // + // 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 + ); + ASSERT_EFI_ERROR (Status); + 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. + // + Mailbox = GetMailboxPointer (); + CopyMem (NewMailbox, Mailbox, sizeof (DEBUG_AGENT_MAILBOX)); + CopyMem (NewMailbox + 1, (VOID *)(UINTN)Mailbox->DebugPortHandle, PcdGet16 (PcdDebugPortHandleBufferSize)); + // + // Update Mailbox Location pointer in GUIDed HOB and IDT entry with new one + // + MailboxLocationInHob = GetMailboxLocationFromHob (); + ASSERT (MailboxLocationInHob != NULL); + *MailboxLocationInHob = (UINT64)(UINTN)NewMailbox; + SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationInHob); + // + // Update Debug Port Handle in new Mailbox + // + UpdateMailboxContent (NewMailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, (UINT64)(UINTN)(NewMailbox + 1)); + // + // Set physical memory ready flag + // + SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1); + + if (IsHostAttached ()) { + // + // Trigger one software interrupt to inform HOST + // + TriggerSoftInterrupt (MEMORY_READY_SIGNATURE); + } + + // + // Restore interrupt state. + // + SetInterruptState (InterruptStatus); + + return EFI_SUCCESS; +} + +/** + 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 override 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 ((DEBUG_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 ((DEBUG_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 ((DEBUG_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 ((DEBUG_ERROR, "DebugAgent: Input parameter Context cannot be NULL!\n")); + CpuDeadLoop (); + } + + // + // Check if Debug Agent has initialized before + // + if (IsDebugAgentInitialzed ()) { + DEBUG ((DEBUG_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 ((DEBUG_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 ((DEBUG_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 memory has been ready, the callback function will be invoked immediately + // + Status = PeiServicesNotifyPpi (&mDebugAgentMemoryDiscoveredNotifyList[0]); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_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 ((DEBUG_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 + + ((UINTN)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 ((DEBUG_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 successfully 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; + } +} + +/** + 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); + } +} diff --git a/SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgent/SecPeiDebugAgentLib.h b/SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgent/SecPeiDebugAgentLib.h index 969348843a..8f5335e22c 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgent/SecPeiDebugAgentLib.h +++ b/SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgent/SecPeiDebugAgentLib.h @@ -1,58 +1,58 @@ -/** @file
- Header file for Sec Core Debug Agent Library instance.
-
- Copyright (c) 2010 - 2013, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _SEC_CORE_DEBUG_AGENT_LIB_H_
-#define _SEC_CORE_DEBUG_AGENT_LIB_H_
-
-#include <PiPei.h>
-#include <Ppi/MemoryDiscovered.h>
-#include <Library/PeiServicesLib.h>
-#include <Library/MemoryAllocationLib.h>
-#include "DebugAgent.h"
-
-typedef struct {
- UINT32 InitFlag;
- VOID *Context;
- DEBUG_AGENT_CONTINUE Function;
-} DEBUG_AGENT_PHASE2_CONTEXT;
-
-/**
- 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 provided notify callback function on Memory Discovered PPI.
-
- @param[in] PeiServices Indirect reference to the PEI Services Table.
- @param[in] NotifyDescriptor Address of the notification descriptor data structure.
- @param[in] Ppi Address of the PPI that was installed.
-
- @retval EFI_SUCCESS If the function completed successfully.
-
-**/
-EFI_STATUS
-EFIAPI
-DebugAgentCallbackMemoryDiscoveredPpi (
- IN EFI_PEI_SERVICES **PeiServices,
- IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
- IN VOID *Ppi
- );
-
-#endif
+/** @file + Header file for Sec Core Debug Agent Library instance. + + Copyright (c) 2010 - 2013, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _SEC_CORE_DEBUG_AGENT_LIB_H_ +#define _SEC_CORE_DEBUG_AGENT_LIB_H_ + +#include <PiPei.h> +#include <Ppi/MemoryDiscovered.h> +#include <Library/PeiServicesLib.h> +#include <Library/MemoryAllocationLib.h> +#include "DebugAgent.h" + +typedef struct { + UINT32 InitFlag; + VOID *Context; + DEBUG_AGENT_CONTINUE Function; +} DEBUG_AGENT_PHASE2_CONTEXT; + +/** + 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 provided notify callback function on Memory Discovered PPI. + + @param[in] PeiServices Indirect reference to the PEI Services Table. + @param[in] NotifyDescriptor Address of the notification descriptor data structure. + @param[in] Ppi Address of the PPI that was installed. + + @retval EFI_SUCCESS If the function completed successfully. + +**/ +EFI_STATUS +EFIAPI +DebugAgentCallbackMemoryDiscoveredPpi ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ); + +#endif diff --git a/SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgentLib.inf b/SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgentLib.inf index f91e2d01ad..423e276332 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgentLib.inf +++ b/SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgentLib.inf @@ -1,86 +1,86 @@ -## @file
-# Debug Agent library instance for SEC Core and PEI modules.
-#
-# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-#
-##
-
-[Defines]
- INF_VERSION = 0x00010005
- BASE_NAME = SecPeiDebugAgentLib
- MODULE_UNI_FILE = SecPeiDebugAgentLib.uni
- FILE_GUID = 508B7D59-CD4E-4a6b-A45B-6D3B2D90111E
- MODULE_TYPE = PEIM
- VERSION_STRING = 0.8
- LIBRARY_CLASS = DebugAgentLib|SEC PEIM
-
-#
-# The following information is for reference only and not required by the build tools.
-#
-# VALID_ARCHITECTURES = IA32 X64
-#
-
-[Sources.common]
- SecPeiDebugAgent/SecPeiDebugAgentLib.c
- SecPeiDebugAgent/SecPeiDebugAgentLib.h
- DebugAgentCommon/DebugAgent.c
- DebugAgentCommon/DebugAgent.h
- DebugAgentCommon/DebugTimer.c
- DebugAgentCommon/DebugTimer.h
- DebugAgentCommon/DebugMp.c
- DebugAgentCommon/DebugMp.h
-
-[Sources.Ia32]
- DebugAgentCommon/Ia32/AsmFuncs.nasm
- DebugAgentCommon/Ia32/ArchDebugSupport.h
- DebugAgentCommon/Ia32/ArchDebugSupport.c
- DebugAgentCommon/Ia32/DebugException.h
-
-[Sources.X64]
- DebugAgentCommon/X64/AsmFuncs.nasm
- DebugAgentCommon/X64/ArchDebugSupport.h
- DebugAgentCommon/X64/ArchDebugSupport.c
- DebugAgentCommon/X64/DebugException.h
-
-[Packages]
- MdePkg/MdePkg.dec
- MdeModulePkg/MdeModulePkg.dec
- UefiCpuPkg/UefiCpuPkg.dec
- SourceLevelDebugPkg/SourceLevelDebugPkg.dec
-
-[LibraryClasses]
- BaseLib
- BaseMemoryLib
- ResetSystemLib
- IoLib
- HobLib
- PcdLib
- DebugCommunicationLib
- SynchronizationLib
- LocalApicLib
- DebugLib
- TimerLib
- PrintLib
- PeiServicesLib
- MemoryAllocationLib
- PeCoffGetEntryPointLib
- PeCoffExtraActionLib
-
-[Ppis]
- gEfiPeiMemoryDiscoveredPpiGuid ## NOTIFY
- gEfiVectorHandoffInfoPpiGuid ## PRODUCES
-
-[Guids]
- ## PRODUCES ## HOB
- ## CONSUMES ## HOB
- gEfiDebugAgentGuid
-
-[Pcd]
- gEfiMdePkgTokenSpaceGuid.PcdFSBClock ## SOMETIMES_CONSUMES
- gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdExceptionsIgnoredByDebugger ## SOMETIMES_CONSUMES
- gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdDebugPortHandleBufferSize ## SOMETIMES_CONSUMES
- gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdTransferProtocolRevision ## CONSUMES
-
+## @file +# Debug Agent library instance for SEC Core and PEI modules. +# +# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SecPeiDebugAgentLib + MODULE_UNI_FILE = SecPeiDebugAgentLib.uni + FILE_GUID = 508B7D59-CD4E-4a6b-A45B-6D3B2D90111E + MODULE_TYPE = PEIM + VERSION_STRING = 0.8 + LIBRARY_CLASS = DebugAgentLib|SEC PEIM + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources.common] + SecPeiDebugAgent/SecPeiDebugAgentLib.c + SecPeiDebugAgent/SecPeiDebugAgentLib.h + DebugAgentCommon/DebugAgent.c + DebugAgentCommon/DebugAgent.h + DebugAgentCommon/DebugTimer.c + DebugAgentCommon/DebugTimer.h + DebugAgentCommon/DebugMp.c + DebugAgentCommon/DebugMp.h + +[Sources.Ia32] + DebugAgentCommon/Ia32/AsmFuncs.nasm + DebugAgentCommon/Ia32/ArchDebugSupport.h + DebugAgentCommon/Ia32/ArchDebugSupport.c + DebugAgentCommon/Ia32/DebugException.h + +[Sources.X64] + DebugAgentCommon/X64/AsmFuncs.nasm + DebugAgentCommon/X64/ArchDebugSupport.h + DebugAgentCommon/X64/ArchDebugSupport.c + DebugAgentCommon/X64/DebugException.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + SourceLevelDebugPkg/SourceLevelDebugPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + ResetSystemLib + IoLib + HobLib + PcdLib + DebugCommunicationLib + SynchronizationLib + LocalApicLib + DebugLib + TimerLib + PrintLib + PeiServicesLib + MemoryAllocationLib + PeCoffGetEntryPointLib + PeCoffExtraActionLib + +[Ppis] + gEfiPeiMemoryDiscoveredPpiGuid ## NOTIFY + gEfiVectorHandoffInfoPpiGuid ## PRODUCES + +[Guids] + ## PRODUCES ## HOB + ## CONSUMES ## HOB + gEfiDebugAgentGuid + +[Pcd] + gEfiMdePkgTokenSpaceGuid.PcdFSBClock ## SOMETIMES_CONSUMES + gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdExceptionsIgnoredByDebugger ## SOMETIMES_CONSUMES + gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdDebugPortHandleBufferSize ## SOMETIMES_CONSUMES + gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdTransferProtocolRevision ## CONSUMES + diff --git a/SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgentLib.uni b/SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgentLib.uni index bc56e3cb06..bdcf5b58fa 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgentLib.uni +++ b/SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgentLib.uni @@ -1,16 +1,16 @@ -// /** @file
-// Debug Agent library instance for SEC Core and PEI modules.
-//
-// Debug Agent library instance for SEC Core and PEI modules.
-//
-// Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
-//
-// SPDX-License-Identifier: BSD-2-Clause-Patent
-//
-// **/
-
-
-#string STR_MODULE_ABSTRACT #language en-US "Debug Agent library instance for SEC Core and PEI modules"
-
-#string STR_MODULE_DESCRIPTION #language en-US "Debug Agent library instance for SEC Core and PEI modules."
-
+// /** @file +// Debug Agent library instance for SEC Core and PEI modules. +// +// Debug Agent library instance for SEC Core and PEI modules. +// +// Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR> +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Debug Agent library instance for SEC Core and PEI modules" + +#string STR_MODULE_DESCRIPTION #language en-US "Debug Agent library instance for SEC Core and PEI modules." + diff --git a/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgent/SmmDebugAgentLib.c b/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgent/SmmDebugAgentLib.c index cc5bb957f7..1cbba43b20 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgent/SmmDebugAgentLib.c +++ b/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgent/SmmDebugAgentLib.c @@ -1,414 +1,414 @@ -/** @file
- Debug Agent library implementation.
-
- Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "SmmDebugAgentLib.h"
-
-DEBUG_AGENT_MAILBOX *mMailboxPointer = NULL;
-DEBUG_AGENT_MAILBOX mLocalMailbox;
-UINTN mSavedDebugRegisters[6];
-IA32_IDT_GATE_DESCRIPTOR mIdtEntryTable[33];
-BOOLEAN mSkipBreakpoint = FALSE;
-BOOLEAN mSmmDebugIdtInitFlag = FALSE;
-BOOLEAN mApicTimerRestore = FALSE;
-BOOLEAN mPeriodicMode;
-UINT32 mTimerCycle;
-UINTN mApicTimerDivisor;
-UINT8 mVector;
-
-CHAR8 mWarningMsgIgnoreSmmEntryBreak[] = "Ignore smmentrybreak setting for SMI issued during DXE debugging!\r\n";
-
-/**
- Check if debug agent support multi-processor.
-
- @retval TRUE Multi-processor is supported.
- @retval FALSE Multi-processor is not supported.
-
-**/
-BOOLEAN
-MultiProcessorDebugSupport (
- VOID
- )
-{
- return FALSE;
-}
-
-/**
- Read the Attach/Break-in symbols from the debug port.
-
- @param[in] Handle Pointer to Debug Port handle.
- @param[out] BreakSymbol Returned break symbol.
-
- @retval EFI_SUCCESS Read the symbol in BreakSymbol.
- @retval EFI_NOT_FOUND No read the break symbol.
-
-**/
-EFI_STATUS
-DebugReadBreakSymbol (
- IN DEBUG_PORT_HANDLE Handle,
- OUT UINT8 *BreakSymbol
- )
-{
- //
- // Smm instance has no debug timer to poll break symbol.
- //
- return EFI_NOT_FOUND;
-}
-
-/**
- Get the pointer to Mailbox from the GUIDed HOB.
-
- @return Pointer to Mailbox.
-
-**/
-DEBUG_AGENT_MAILBOX *
-GetMailboxFromHob (
- VOID
- )
-{
- EFI_HOB_GUID_TYPE *GuidHob;
- UINT64 *MailboxLocation;
- DEBUG_AGENT_MAILBOX *Mailbox;
-
- GuidHob = GetFirstGuidHob (&gEfiDebugAgentGuid);
- if (GuidHob == NULL) {
- return NULL;
- }
-
- MailboxLocation = (UINT64 *)(GET_GUID_HOB_DATA (GuidHob));
- Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation);
- VerifyMailboxChecksum (Mailbox);
-
- return Mailbox;
-}
-
-/**
- Get Debug Agent Mailbox pointer.
-
- @return Mailbox pointer.
-
-**/
-DEBUG_AGENT_MAILBOX *
-GetMailboxPointer (
- VOID
- )
-{
- VerifyMailboxChecksum (mMailboxPointer);
- return mMailboxPointer;
-}
-
-/**
- Get debug port handle.
-
- @return Debug port handle.
-
-**/
-DEBUG_PORT_HANDLE
-GetDebugPortHandle (
- VOID
- )
-{
- return (DEBUG_PORT_HANDLE)(UINTN)(GetMailboxPointer ()->DebugPortHandle);
-}
-
-/**
- Store debug register when SMI exit.
-
-**/
-VOID
-SaveDebugRegister (
- VOID
- )
-{
- mSavedDebugRegisters[0] = AsmReadDr0 ();
- mSavedDebugRegisters[1] = AsmReadDr1 ();
- mSavedDebugRegisters[2] = AsmReadDr2 ();
- mSavedDebugRegisters[3] = AsmReadDr3 ();
- mSavedDebugRegisters[4] = AsmReadDr6 ();
- mSavedDebugRegisters[5] = AsmReadDr7 ();
-}
-
-/**
- Restore debug register when SMI exit.
-
-**/
-VOID
-RestoreDebugRegister (
- VOID
- )
-{
- AsmWriteDr7 (0);
- AsmWriteDr0 (mSavedDebugRegisters[0]);
- AsmWriteDr1 (mSavedDebugRegisters[1]);
- AsmWriteDr2 (mSavedDebugRegisters[2]);
- AsmWriteDr3 (mSavedDebugRegisters[3]);
- AsmWriteDr6 (mSavedDebugRegisters[4]);
- AsmWriteDr7 (mSavedDebugRegisters[5]);
-}
-
-/**
- Initialize debug agent.
-
- This function is used to set up debug environment for source level debug
- in SMM code.
-
- If InitFlag is DEBUG_AGENT_INIT_SMM, it will override 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 override IDT table entries and initialize debug port. Context must
- point to a BOOLEAN if it's not NULL, which indicates SMM Debug Agent supported
- or not.
- 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;
-
- 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 ((DEBUG_ERROR, "DebugAgent: Cannot install configuration table for persisted vector handoff info!\n"));
- if (Context != NULL) {
- *(BOOLEAN *)Context = FALSE;
- }
-
- CpuDeadLoop ();
- }
-
- //
- // Check if Debug Agent initialized in DXE phase
- //
- Status = EfiGetSystemConfigurationTable (&gEfiDebugAgentGuid, (VOID **)&Mailbox);
- if ((Status == EFI_SUCCESS) && (Mailbox != NULL)) {
- VerifyMailboxChecksum (Mailbox);
- mMailboxPointer = Mailbox;
- if (Context != NULL) {
- *(BOOLEAN *)Context = TRUE;
- }
-
- break;
- }
-
- //
- // Check if Debug Agent initialized in SEC/PEI phase
- //
- Mailbox = GetMailboxFromHob ();
- if (Mailbox != NULL) {
- mMailboxPointer = Mailbox;
- if (Context != NULL) {
- *(BOOLEAN *)Context = TRUE;
- }
-
- 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));
-
- if (Context != NULL) {
- *(BOOLEAN *)Context = TRUE;
- }
-
- 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 (&mApicTimerDivisor, &mPeriodicMode, &mVector);
- mTimerCycle = GetApicTimerInitCount ();
- if (!mPeriodicMode || (mTimerCycle == 0)) {
- mApicTimerRestore = TRUE;
- InitializeDebugTimer (NULL, FALSE);
- }
-
- Mailbox = GetMailboxPointer ();
- if (GetDebugFlag (DEBUG_AGENT_FLAG_AGENT_IN_PROGRESS) == 1) {
- //
- // If Debug Agent has been communication 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 ();
- //
- // Restore APIC Timer
- //
- if (mApicTimerRestore) {
- InitializeApicTimer (mApicTimerDivisor, mTimerCycle, mPeriodicMode, mVector);
- mApicTimerRestore = FALSE;
- }
-
- break;
-
- case DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64:
- if (Context == NULL) {
- DEBUG ((DEBUG_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 +
- ((UINTN)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 ((DEBUG_ERROR, "Debug Agent: The InitFlag value is not allowed!\n"));
- CpuDeadLoop ();
- break;
- }
-}
+/** @file + Debug Agent library implementation. + + Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "SmmDebugAgentLib.h" + +DEBUG_AGENT_MAILBOX *mMailboxPointer = NULL; +DEBUG_AGENT_MAILBOX mLocalMailbox; +UINTN mSavedDebugRegisters[6]; +IA32_IDT_GATE_DESCRIPTOR mIdtEntryTable[33]; +BOOLEAN mSkipBreakpoint = FALSE; +BOOLEAN mSmmDebugIdtInitFlag = FALSE; +BOOLEAN mApicTimerRestore = FALSE; +BOOLEAN mPeriodicMode; +UINT32 mTimerCycle; +UINTN mApicTimerDivisor; +UINT8 mVector; + +CHAR8 mWarningMsgIgnoreSmmEntryBreak[] = "Ignore smmentrybreak setting for SMI issued during DXE debugging!\r\n"; + +/** + Check if debug agent support multi-processor. + + @retval TRUE Multi-processor is supported. + @retval FALSE Multi-processor is not supported. + +**/ +BOOLEAN +MultiProcessorDebugSupport ( + VOID + ) +{ + return FALSE; +} + +/** + Read the Attach/Break-in symbols from the debug port. + + @param[in] Handle Pointer to Debug Port handle. + @param[out] BreakSymbol Returned break symbol. + + @retval EFI_SUCCESS Read the symbol in BreakSymbol. + @retval EFI_NOT_FOUND No read the break symbol. + +**/ +EFI_STATUS +DebugReadBreakSymbol ( + IN DEBUG_PORT_HANDLE Handle, + OUT UINT8 *BreakSymbol + ) +{ + // + // Smm instance has no debug timer to poll break symbol. + // + return EFI_NOT_FOUND; +} + +/** + Get the pointer to Mailbox from the GUIDed HOB. + + @return Pointer to Mailbox. + +**/ +DEBUG_AGENT_MAILBOX * +GetMailboxFromHob ( + VOID + ) +{ + EFI_HOB_GUID_TYPE *GuidHob; + UINT64 *MailboxLocation; + DEBUG_AGENT_MAILBOX *Mailbox; + + GuidHob = GetFirstGuidHob (&gEfiDebugAgentGuid); + if (GuidHob == NULL) { + return NULL; + } + + MailboxLocation = (UINT64 *)(GET_GUID_HOB_DATA (GuidHob)); + Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation); + VerifyMailboxChecksum (Mailbox); + + return Mailbox; +} + +/** + Get Debug Agent Mailbox pointer. + + @return Mailbox pointer. + +**/ +DEBUG_AGENT_MAILBOX * +GetMailboxPointer ( + VOID + ) +{ + VerifyMailboxChecksum (mMailboxPointer); + return mMailboxPointer; +} + +/** + Get debug port handle. + + @return Debug port handle. + +**/ +DEBUG_PORT_HANDLE +GetDebugPortHandle ( + VOID + ) +{ + return (DEBUG_PORT_HANDLE)(UINTN)(GetMailboxPointer ()->DebugPortHandle); +} + +/** + Store debug register when SMI exit. + +**/ +VOID +SaveDebugRegister ( + VOID + ) +{ + mSavedDebugRegisters[0] = AsmReadDr0 (); + mSavedDebugRegisters[1] = AsmReadDr1 (); + mSavedDebugRegisters[2] = AsmReadDr2 (); + mSavedDebugRegisters[3] = AsmReadDr3 (); + mSavedDebugRegisters[4] = AsmReadDr6 (); + mSavedDebugRegisters[5] = AsmReadDr7 (); +} + +/** + Restore debug register when SMI exit. + +**/ +VOID +RestoreDebugRegister ( + VOID + ) +{ + AsmWriteDr7 (0); + AsmWriteDr0 (mSavedDebugRegisters[0]); + AsmWriteDr1 (mSavedDebugRegisters[1]); + AsmWriteDr2 (mSavedDebugRegisters[2]); + AsmWriteDr3 (mSavedDebugRegisters[3]); + AsmWriteDr6 (mSavedDebugRegisters[4]); + AsmWriteDr7 (mSavedDebugRegisters[5]); +} + +/** + Initialize debug agent. + + This function is used to set up debug environment for source level debug + in SMM code. + + If InitFlag is DEBUG_AGENT_INIT_SMM, it will override 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 override IDT table entries and initialize debug port. Context must + point to a BOOLEAN if it's not NULL, which indicates SMM Debug Agent supported + or not. + 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; + + 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 ((DEBUG_ERROR, "DebugAgent: Cannot install configuration table for persisted vector handoff info!\n")); + if (Context != NULL) { + *(BOOLEAN *)Context = FALSE; + } + + CpuDeadLoop (); + } + + // + // Check if Debug Agent initialized in DXE phase + // + Status = EfiGetSystemConfigurationTable (&gEfiDebugAgentGuid, (VOID **)&Mailbox); + if ((Status == EFI_SUCCESS) && (Mailbox != NULL)) { + VerifyMailboxChecksum (Mailbox); + mMailboxPointer = Mailbox; + if (Context != NULL) { + *(BOOLEAN *)Context = TRUE; + } + + break; + } + + // + // Check if Debug Agent initialized in SEC/PEI phase + // + Mailbox = GetMailboxFromHob (); + if (Mailbox != NULL) { + mMailboxPointer = Mailbox; + if (Context != NULL) { + *(BOOLEAN *)Context = TRUE; + } + + 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)); + + if (Context != NULL) { + *(BOOLEAN *)Context = TRUE; + } + + 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 (&mApicTimerDivisor, &mPeriodicMode, &mVector); + mTimerCycle = GetApicTimerInitCount (); + if (!mPeriodicMode || (mTimerCycle == 0)) { + mApicTimerRestore = TRUE; + InitializeDebugTimer (NULL, FALSE); + } + + Mailbox = GetMailboxPointer (); + if (GetDebugFlag (DEBUG_AGENT_FLAG_AGENT_IN_PROGRESS) == 1) { + // + // If Debug Agent has been communication 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 (); + // + // Restore APIC Timer + // + if (mApicTimerRestore) { + InitializeApicTimer (mApicTimerDivisor, mTimerCycle, mPeriodicMode, mVector); + mApicTimerRestore = FALSE; + } + + break; + + case DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64: + if (Context == NULL) { + DEBUG ((DEBUG_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 + + ((UINTN)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 ((DEBUG_ERROR, "Debug Agent: The InitFlag value is not allowed!\n")); + CpuDeadLoop (); + break; + } +} diff --git a/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgent/SmmDebugAgentLib.h b/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgent/SmmDebugAgentLib.h index 67f37b634d..00a8a37bc6 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgent/SmmDebugAgentLib.h +++ b/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgent/SmmDebugAgentLib.h @@ -1,19 +1,19 @@ -/** @file
- Header file for Smm Debug Agent Library instance.
-
- Copyright (c) 2010 - 2013, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _SMM_DEBUG_AGENT_LIB_H_
-#define _SMM_DEBUG_AGENT_LIB_H_
-
-#include <PiDxe.h>
-
-#include <Library/UefiLib.h>
-#include <Library/SmmServicesTableLib.h>
-
-#include "DebugAgent.h"
-
-#endif
+/** @file + Header file for Smm Debug Agent Library instance. + + Copyright (c) 2010 - 2013, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _SMM_DEBUG_AGENT_LIB_H_ +#define _SMM_DEBUG_AGENT_LIB_H_ + +#include <PiDxe.h> + +#include <Library/UefiLib.h> +#include <Library/SmmServicesTableLib.h> + +#include "DebugAgent.h" + +#endif diff --git a/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgentLib.inf b/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgentLib.inf index 2084b34a85..436862eadf 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgentLib.inf +++ b/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgentLib.inf @@ -1,81 +1,81 @@ -## @file
-# Debug Agent library instance for SMM modules.
-#
-# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-#
-##
-
-[Defines]
- INF_VERSION = 0x00010005
- BASE_NAME = SmmDebugAgentLib
- MODULE_UNI_FILE = SmmDebugAgentLib.uni
- FILE_GUID = CB07D74C-598F-4268-A5D1-644FB4A481E8
- MODULE_TYPE = DXE_SMM_DRIVER
- VERSION_STRING = 0.8
- LIBRARY_CLASS = DebugAgentLib|DXE_SMM_DRIVER
-
-#
-# The following information is for reference only and not required by the build tools.
-#
-# VALID_ARCHITECTURES = IA32 X64
-#
-
-[Sources.common]
- SmmDebugAgent/SmmDebugAgentLib.c
- SmmDebugAgent/SmmDebugAgentLib.h
- DebugAgentCommon/DebugAgent.c
- DebugAgentCommon/DebugAgent.h
- DebugAgentCommon/DebugTimer.c
- DebugAgentCommon/DebugTimer.h
- DebugAgentCommon/DebugMp.c
- DebugAgentCommon/DebugMp.h
-
-[Sources.Ia32]
- DebugAgentCommon/Ia32/AsmFuncs.nasm
- DebugAgentCommon/Ia32/ArchDebugSupport.h
- DebugAgentCommon/Ia32/ArchDebugSupport.c
- DebugAgentCommon/Ia32/DebugException.h
-
-[Sources.X64]
- DebugAgentCommon/X64/AsmFuncs.nasm
- DebugAgentCommon/X64/ArchDebugSupport.h
- DebugAgentCommon/X64/ArchDebugSupport.c
- DebugAgentCommon/X64/DebugException.h
-
-[Packages]
- MdePkg/MdePkg.dec
- MdeModulePkg/MdeModulePkg.dec
- UefiCpuPkg/UefiCpuPkg.dec
- SourceLevelDebugPkg/SourceLevelDebugPkg.dec
-
-[LibraryClasses]
- BaseLib
- BaseMemoryLib
- ResetSystemLib
- IoLib
- DebugCommunicationLib
- UefiLib
- PcdLib
- SynchronizationLib
- LocalApicLib
- TimerLib
- PrintLib
- PeCoffExtraActionLib
- PeCoffGetEntryPointLib
- SmmServicesTableLib
-
-[Guids]
- ## CONSUMES ## SystemTable
- ## CONSUMES ## HOB
- gEfiDebugAgentGuid
- gEfiVectorHandoffTableGuid ## PRODUCES ## GUID # SMM Configuration Table
-
-[Pcd]
- gEfiMdePkgTokenSpaceGuid.PcdFSBClock ## SOMETIMES_CONSUMES
- # Skip Page Fault exception (14) by default in SMM
- gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdExceptionsIgnoredByDebugger|0x00004000 ## SOMETIMES_CONSUMES
- gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdTransferProtocolRevision ## CONSUMES
-
+## @file +# Debug Agent library instance for SMM modules. +# +# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SmmDebugAgentLib + MODULE_UNI_FILE = SmmDebugAgentLib.uni + FILE_GUID = CB07D74C-598F-4268-A5D1-644FB4A481E8 + MODULE_TYPE = DXE_SMM_DRIVER + VERSION_STRING = 0.8 + LIBRARY_CLASS = DebugAgentLib|DXE_SMM_DRIVER + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources.common] + SmmDebugAgent/SmmDebugAgentLib.c + SmmDebugAgent/SmmDebugAgentLib.h + DebugAgentCommon/DebugAgent.c + DebugAgentCommon/DebugAgent.h + DebugAgentCommon/DebugTimer.c + DebugAgentCommon/DebugTimer.h + DebugAgentCommon/DebugMp.c + DebugAgentCommon/DebugMp.h + +[Sources.Ia32] + DebugAgentCommon/Ia32/AsmFuncs.nasm + DebugAgentCommon/Ia32/ArchDebugSupport.h + DebugAgentCommon/Ia32/ArchDebugSupport.c + DebugAgentCommon/Ia32/DebugException.h + +[Sources.X64] + DebugAgentCommon/X64/AsmFuncs.nasm + DebugAgentCommon/X64/ArchDebugSupport.h + DebugAgentCommon/X64/ArchDebugSupport.c + DebugAgentCommon/X64/DebugException.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + SourceLevelDebugPkg/SourceLevelDebugPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + ResetSystemLib + IoLib + DebugCommunicationLib + UefiLib + PcdLib + SynchronizationLib + LocalApicLib + TimerLib + PrintLib + PeCoffExtraActionLib + PeCoffGetEntryPointLib + SmmServicesTableLib + +[Guids] + ## CONSUMES ## SystemTable + ## CONSUMES ## HOB + gEfiDebugAgentGuid + gEfiVectorHandoffTableGuid ## PRODUCES ## GUID # SMM Configuration Table + +[Pcd] + gEfiMdePkgTokenSpaceGuid.PcdFSBClock ## SOMETIMES_CONSUMES + # Skip Page Fault exception (14) by default in SMM + gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdExceptionsIgnoredByDebugger|0x00004000 ## SOMETIMES_CONSUMES + gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdTransferProtocolRevision ## CONSUMES + diff --git a/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgentLib.uni b/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgentLib.uni index 74770a3066..e93ed68d9e 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgentLib.uni +++ b/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgentLib.uni @@ -1,16 +1,16 @@ -// /** @file
-// Debug Agent library instance for SMM modules.
-//
-// Debug Agent library instance for SMM modules.
-//
-// Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
-//
-// SPDX-License-Identifier: BSD-2-Clause-Patent
-//
-// **/
-
-
-#string STR_MODULE_ABSTRACT #language en-US "Debug Agent library instance for SMM modules"
-
-#string STR_MODULE_DESCRIPTION #language en-US "Debug Agent library instance for SMM modules."
-
+// /** @file +// Debug Agent library instance for SMM modules. +// +// Debug Agent library instance for SMM modules. +// +// Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR> +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Debug Agent library instance for SMM modules" + +#string STR_MODULE_DESCRIPTION #language en-US "Debug Agent library instance for SMM modules." + diff --git a/SourceLevelDebugPkg/Library/DebugCommunicationLibSerialPort/DebugCommunicationLibSerialPort.c b/SourceLevelDebugPkg/Library/DebugCommunicationLibSerialPort/DebugCommunicationLibSerialPort.c index 9953904725..c7794ee031 100644 --- a/SourceLevelDebugPkg/Library/DebugCommunicationLibSerialPort/DebugCommunicationLibSerialPort.c +++ b/SourceLevelDebugPkg/Library/DebugCommunicationLibSerialPort/DebugCommunicationLibSerialPort.c @@ -1,153 +1,153 @@ -/** @file
- Debug Port Library implementation based on serial port.
-
- Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include <Base.h>
-
-#include <Library/DebugCommunicationLib.h>
-#include <Library/SerialPortLib.h>
-#include <Library/DebugLib.h>
-
-/**
- Initialize the debug port.
-
- This function will initialize debug port to get it ready for data transmission. If
- certain Debug Communication 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 DebugPortInitialize() into one
- function and pass it into DebugPortInitialize(). DebugPortInitialize() is
- responsible to invoke the passing-in function at the end of DebugPortInitialize().
-
- If the parameter Function is not NULL, Debug Communication Library instance will
- invoke it by passing in the Context to be the first parameter. Debug Communication
- Library instance could create one debug port handle to be the second parameter
- passing into the Function. Debug Communication Library instance also could pass
- NULL to be the second parameter if it doesn't create the debug port handle.
-
- If the parameter Function is NULL, and Context is not NULL. At this time, Context
- is the debug port handle created by the previous Debug Communication Library
- instance.
- a) If the instance can understand and continue use the private data of the previous
- instance, it could return the same handle as passed in (as Context parameter).
- b) If the instance does not understand, or does not want to continue use the
- private data of the previous instance, it could ignore the input Context parameter
- and create the new handle to be returned.
-
- If Function() is NULL and Context is NULL, Debug Communication Library could create a
- new handle and return it. NULL is also a valid handle to be returned.
-
- @param[in] Context Context needed by callback function; it was optional.
- @param[in] Function Continue function called by Debug Communication library;
- it was optional.
-
- @return The debug port handle created by Debug Communication Library if Function
- is not NULL.
-
-**/
-DEBUG_PORT_HANDLE
-EFIAPI
-DebugPortInitialize (
- IN VOID *Context,
- IN DEBUG_PORT_CONTINUE Function
- )
-{
- RETURN_STATUS Status;
-
- Status = SerialPortInitialize ();
- if (RETURN_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "Debug Serial Port: Initialization failed!\n"));
- }
-
- if (Function != NULL) {
- Function (Context, NULL);
- }
-
- return NULL;
-}
-
-/**
- Read data from debug device and save the data in a buffer.
-
- Reads NumberOfBytes data bytes from a debug device into the buffer
- specified by Buffer. The number of bytes actually read is returned.
- If the return value is less than NumberOfBytes, then the rest operation failed.
- If NumberOfBytes is zero, then return 0.
-
- @param Handle Debug port handle.
- @param Buffer Pointer to the data buffer to store the data read from the debug device.
- @param NumberOfBytes Number of bytes which will be read.
- @param Timeout Timeout value for reading from debug device. It unit is Microsecond.
-
- @retval 0 Read data failed, no data is to be read.
- @retval >0 Actual number of bytes read from debug device.
-
-**/
-UINTN
-EFIAPI
-DebugPortReadBuffer (
- IN DEBUG_PORT_HANDLE Handle,
- IN UINT8 *Buffer,
- IN UINTN NumberOfBytes,
- IN UINTN Timeout
- )
-{
- if ((NumberOfBytes != 1) || (Buffer == NULL) || (Timeout != 0)) {
- return 0;
- }
-
- return SerialPortRead (Buffer, 1);
-}
-
-/**
- Write data from buffer to debug device.
-
- Writes NumberOfBytes data bytes from Buffer to the debug device.
- The number of bytes actually written to the debug device is returned.
- If the return value is less than NumberOfBytes, then the write operation failed.
- If NumberOfBytes is zero, then return 0.
-
- @param Handle Debug port handle.
- @param Buffer Pointer to the data buffer to be written.
- @param NumberOfBytes Number of bytes to written to the debug device.
-
- @retval 0 NumberOfBytes is 0.
- @retval >0 The number of bytes written to the debug device.
- If this value is less than NumberOfBytes, then the read operation failed.
-
-**/
-UINTN
-EFIAPI
-DebugPortWriteBuffer (
- IN DEBUG_PORT_HANDLE Handle,
- IN UINT8 *Buffer,
- IN UINTN NumberOfBytes
- )
-{
- return SerialPortWrite (Buffer, NumberOfBytes);
-}
-
-/**
- Polls a debug device to see if there is any data waiting to be read.
-
- Polls a debug device to see if there is any data waiting to be read.
- If there is data waiting to be read from the debug device, then TRUE is returned.
- If there is no data waiting to be read from the debug device, then FALSE is returned.
-
- @param Handle Debug port handle.
-
- @retval TRUE Data is waiting to be read from the debug device.
- @retval FALSE There is no data waiting to be read from the serial device.
-
-**/
-BOOLEAN
-EFIAPI
-DebugPortPollBuffer (
- IN DEBUG_PORT_HANDLE Handle
- )
-{
- return SerialPortPoll ();
-}
+/** @file + Debug Port Library implementation based on serial port. + + Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Base.h> + +#include <Library/DebugCommunicationLib.h> +#include <Library/SerialPortLib.h> +#include <Library/DebugLib.h> + +/** + Initialize the debug port. + + This function will initialize debug port to get it ready for data transmission. If + certain Debug Communication 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 DebugPortInitialize() into one + function and pass it into DebugPortInitialize(). DebugPortInitialize() is + responsible to invoke the passing-in function at the end of DebugPortInitialize(). + + If the parameter Function is not NULL, Debug Communication Library instance will + invoke it by passing in the Context to be the first parameter. Debug Communication + Library instance could create one debug port handle to be the second parameter + passing into the Function. Debug Communication Library instance also could pass + NULL to be the second parameter if it doesn't create the debug port handle. + + If the parameter Function is NULL, and Context is not NULL. At this time, Context + is the debug port handle created by the previous Debug Communication Library + instance. + a) If the instance can understand and continue use the private data of the previous + instance, it could return the same handle as passed in (as Context parameter). + b) If the instance does not understand, or does not want to continue use the + private data of the previous instance, it could ignore the input Context parameter + and create the new handle to be returned. + + If Function() is NULL and Context is NULL, Debug Communication Library could create a + new handle and return it. NULL is also a valid handle to be returned. + + @param[in] Context Context needed by callback function; it was optional. + @param[in] Function Continue function called by Debug Communication library; + it was optional. + + @return The debug port handle created by Debug Communication Library if Function + is not NULL. + +**/ +DEBUG_PORT_HANDLE +EFIAPI +DebugPortInitialize ( + IN VOID *Context, + IN DEBUG_PORT_CONTINUE Function + ) +{ + RETURN_STATUS Status; + + Status = SerialPortInitialize (); + if (RETURN_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Debug Serial Port: Initialization failed!\n")); + } + + if (Function != NULL) { + Function (Context, NULL); + } + + return NULL; +} + +/** + Read data from debug device and save the data in a buffer. + + Reads NumberOfBytes data bytes from a debug device into the buffer + specified by Buffer. The number of bytes actually read is returned. + If the return value is less than NumberOfBytes, then the rest operation failed. + If NumberOfBytes is zero, then return 0. + + @param Handle Debug port handle. + @param Buffer Pointer to the data buffer to store the data read from the debug device. + @param NumberOfBytes Number of bytes which will be read. + @param Timeout Timeout value for reading from debug device. It unit is Microsecond. + + @retval 0 Read data failed, no data is to be read. + @retval >0 Actual number of bytes read from debug device. + +**/ +UINTN +EFIAPI +DebugPortReadBuffer ( + IN DEBUG_PORT_HANDLE Handle, + IN UINT8 *Buffer, + IN UINTN NumberOfBytes, + IN UINTN Timeout + ) +{ + if ((NumberOfBytes != 1) || (Buffer == NULL) || (Timeout != 0)) { + return 0; + } + + return SerialPortRead (Buffer, 1); +} + +/** + Write data from buffer to debug device. + + Writes NumberOfBytes data bytes from Buffer to the debug device. + The number of bytes actually written to the debug device is returned. + If the return value is less than NumberOfBytes, then the write operation failed. + If NumberOfBytes is zero, then return 0. + + @param Handle Debug port handle. + @param Buffer Pointer to the data buffer to be written. + @param NumberOfBytes Number of bytes to written to the debug device. + + @retval 0 NumberOfBytes is 0. + @retval >0 The number of bytes written to the debug device. + If this value is less than NumberOfBytes, then the read operation failed. + +**/ +UINTN +EFIAPI +DebugPortWriteBuffer ( + IN DEBUG_PORT_HANDLE Handle, + IN UINT8 *Buffer, + IN UINTN NumberOfBytes + ) +{ + return SerialPortWrite (Buffer, NumberOfBytes); +} + +/** + Polls a debug device to see if there is any data waiting to be read. + + Polls a debug device to see if there is any data waiting to be read. + If there is data waiting to be read from the debug device, then TRUE is returned. + If there is no data waiting to be read from the debug device, then FALSE is returned. + + @param Handle Debug port handle. + + @retval TRUE Data is waiting to be read from the debug device. + @retval FALSE There is no data waiting to be read from the serial device. + +**/ +BOOLEAN +EFIAPI +DebugPortPollBuffer ( + IN DEBUG_PORT_HANDLE Handle + ) +{ + return SerialPortPoll (); +} diff --git a/SourceLevelDebugPkg/Library/DebugCommunicationLibSerialPort/DebugCommunicationLibSerialPort.inf b/SourceLevelDebugPkg/Library/DebugCommunicationLibSerialPort/DebugCommunicationLibSerialPort.inf index 21af18cfb0..143fa2eef4 100644 --- a/SourceLevelDebugPkg/Library/DebugCommunicationLibSerialPort/DebugCommunicationLibSerialPort.inf +++ b/SourceLevelDebugPkg/Library/DebugCommunicationLibSerialPort/DebugCommunicationLibSerialPort.inf @@ -1,33 +1,33 @@ -## @file
-# Debug Communication Library instance based on serial port.
-#
-# Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-#
-##
-
-[Defines]
- INF_VERSION = 0x00010005
- BASE_NAME = DebugCommunicationLibSerialPort
- MODULE_UNI_FILE = DebugCommunicationLibSerialPort.uni
- FILE_GUID = 8CC435C5-6330-4269-B0C3-E3BD05C86FB8
- MODULE_TYPE = BASE
- VERSION_STRING = 0.7
- LIBRARY_CLASS = DebugCommunicationLib
-
-#
-# VALID_ARCHITECTURES = IA32 X64
-#
-
-[Sources.common]
- DebugCommunicationLibSerialPort.c
-
-[Packages]
- MdePkg/MdePkg.dec
- SourceLevelDebugPkg/SourceLevelDebugPkg.dec
-
-[LibraryClasses]
- SerialPortLib
- DebugLib
+## @file +# Debug Communication Library instance based on serial port. +# +# Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DebugCommunicationLibSerialPort + MODULE_UNI_FILE = DebugCommunicationLibSerialPort.uni + FILE_GUID = 8CC435C5-6330-4269-B0C3-E3BD05C86FB8 + MODULE_TYPE = BASE + VERSION_STRING = 0.7 + LIBRARY_CLASS = DebugCommunicationLib + +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources.common] + DebugCommunicationLibSerialPort.c + +[Packages] + MdePkg/MdePkg.dec + SourceLevelDebugPkg/SourceLevelDebugPkg.dec + +[LibraryClasses] + SerialPortLib + DebugLib diff --git a/SourceLevelDebugPkg/Library/DebugCommunicationLibSerialPort/DebugCommunicationLibSerialPort.uni b/SourceLevelDebugPkg/Library/DebugCommunicationLibSerialPort/DebugCommunicationLibSerialPort.uni index 4bea6d51e0..cf56ff28bd 100644 --- a/SourceLevelDebugPkg/Library/DebugCommunicationLibSerialPort/DebugCommunicationLibSerialPort.uni +++ b/SourceLevelDebugPkg/Library/DebugCommunicationLibSerialPort/DebugCommunicationLibSerialPort.uni @@ -1,16 +1,16 @@ -// /** @file
-// Debug Communication Library instance based on serial port.
-//
-// Debug Communication Library instance based on serial port.
-//
-// Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
-//
-// SPDX-License-Identifier: BSD-2-Clause-Patent
-//
-// **/
-
-
-#string STR_MODULE_ABSTRACT #language en-US "Debug Communication Library instance based on serial port"
-
-#string STR_MODULE_DESCRIPTION #language en-US "Debug Communication Library instance based on serial port."
-
+// /** @file +// Debug Communication Library instance based on serial port. +// +// Debug Communication Library instance based on serial port. +// +// Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR> +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Debug Communication Library instance based on serial port" + +#string STR_MODULE_DESCRIPTION #language en-US "Debug Communication Library instance based on serial port." + diff --git a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb/DebugCommunicationLibUsb.c b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb/DebugCommunicationLibUsb.c index da55f3e69e..3b34e3e23c 100644 --- a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb/DebugCommunicationLibUsb.c +++ b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb/DebugCommunicationLibUsb.c @@ -1,1127 +1,1127 @@ -/** @file
- Debug Port Library implementation based on usb debug port.
-
- Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include <Base.h>
-#include <IndustryStandard/Pci.h>
-#include <IndustryStandard/Usb.h>
-#include <Library/IoLib.h>
-#include <Library/PciLib.h>
-#include <Library/PcdLib.h>
-#include <Library/TimerLib.h>
-#include <Library/DebugCommunicationLib.h>
-#include <Library/BaseMemoryLib.h>
-#include <Library/BaseLib.h>
-#include <Library/DebugLib.h>
-
-#define SETUP_PID 0x2D
-#define INPUT_PID 0x69
-#define OUTPUT_PID 0xE1
-#define ERROR_PID 0x55
-#define DATA0_PID 0xC3
-#define DATA1_PID 0x4B
-#define DATA2_PID 0x87
-#define MDATA_PID 0x0F
-#define ACK_PID 0xD2
-#define NAK_PID 0x5A
-#define STALL_PID 0x1E
-#define NYET_PID 0x96
-
-#define PCI_CAPABILITY_ID_DEBUG_PORT 0x0A
-#define USB_DEBUG_PORT_MAX_PACKET_SIZE 0x08
-
-#define USB_DEBUG_PORT_IN_USE BIT10
-#define USB_DEBUG_PORT_ENABLE BIT28
-#define USB_DEBUG_PORT_OWNER BIT30
-
-#define USB_PORT_LINE_STATUS_LS 0x400
-#define USB_PORT_LINE_STATUS_MASK 0xC00
-
-//
-// Usb debug device descriptor, which is defined at
-// USB2 Debug Device Specification.
-//
-typedef struct _USB_DEBUG_PORT_DESCRIPTOR {
- UINT8 Length;
- UINT8 DescriptorType;
- UINT8 DebugInEndpoint;
- UINT8 DebugOutEndpoint;
-} USB_DEBUG_PORT_DESCRIPTOR;
-
-USB_DEVICE_REQUEST mDebugCommunicationLibUsbGetDebugDescriptor = {
- 0x80,
- USB_REQ_GET_DESCRIPTOR,
- (UINT16)(0x0A << 8),
- 0x0000,
- sizeof (USB_DEBUG_PORT_DESCRIPTOR)
-};
-
-USB_DEVICE_REQUEST mDebugCommunicationLibUsbSetDebugFeature = {
- 0x0,
- USB_REQ_SET_FEATURE,
- (UINT16)(0x06),
- 0x0000,
- 0x0
-};
-
-USB_DEVICE_REQUEST mDebugCommunicationLibUsbSetDebugAddress = {
- 0x0,
- USB_REQ_SET_ADDRESS,
- (UINT16)(0x7F),
- 0x0000,
- 0x0
-};
-
-//
-// Usb debug port register file, which is defined at
-// EHCI Specification.
-//
-typedef struct _USB_DEBUG_PORT_REGISTER {
- UINT32 ControlStatus;
- UINT8 TokenPid;
- UINT8 SendPid;
- UINT8 ReceivedPid;
- UINT8 Reserved1;
- UINT8 DataBuffer[8];
- UINT8 UsbEndPoint;
- UINT8 UsbAddress;
- UINT8 Reserved2;
- UINT8 Reserved3;
-} USB_DEBUG_PORT_REGISTER;
-
-//
-// The state machine of usb debug port
-//
-#define USBDBG_NO_DEV 0 // No device present at debug port
-#define USBDBG_NO_DBG_CAB 1 // The device attached is not usb debug cable
-#define USBDBG_DBG_CAB 2 // The device attached is usb debug cable
-#define USBDBG_INIT_DONE 4 // The usb debug cable device is initialized
-#define USBDBG_RESET 8 // The system is reset
-
-#pragma pack(1)
-//
-// The internal data structure of DEBUG_PORT_HANDLE, which stores some
-// important datum which are used across various phases.
-//
-typedef struct _USB_DEBUG_PORT_HANDLE {
- //
- // The usb debug port memory BAR number in EHCI configuration space.
- //
- UINT8 DebugPortBarNumber;
- UINT8 Initialized;
- //
- // The offset of usb debug port registers in EHCI memory range.
- //
- UINT16 DebugPortOffset;
- //
- // The usb debug port memory BAR address.
- //
- UINT32 UsbDebugPortMemoryBase;
- //
- // The EHCI memory BAR address.
- //
- UINT32 EhciMemoryBase;
- //
- // The usb debug device In endpoint.
- //
- UINT8 InEndpoint;
- //
- // The usb debug device Out endpoint.
- //
- UINT8 OutEndpoint;
- //
- // The Bulk In endpoint toggle bit.
- //
- UINT8 BulkInToggle;
- //
- // The Bulk Out endpoint toggle bit.
- //
- UINT8 BulkOutToggle;
- //
- // The available data length in the following data buffer.
- //
- UINT8 DataCount;
- //
- // The data buffer. Maximum length is 8 bytes.
- //
- UINT8 Data[8];
-} USB_DEBUG_PORT_HANDLE;
-#pragma pack()
-
-//
-// The global variable which can be used after memory is ready.
-//
-USB_DEBUG_PORT_HANDLE mDebugCommunicationLibUsbDebugPortHandle;
-
-/**
- Calculate the usb debug port bar address.
-
- @param DebugPortOffset Get usb debug port offset in the usb debug port memory space.
- @param DebugPortBarNumbar Get the bar number at which usb debug port is located.
-
- @retval RETURN_UNSUPPORTED The usb host controller does not supported usb debug port capability.
- @retval RETURN_SUCCESS Get bar and offset successfully.
-
-**/
-RETURN_STATUS
-EFIAPI
-CalculateUsbDebugPortBar (
- OUT UINT16 *DebugPortOffset,
- OUT UINT8 *DebugPortBarNumbar
- )
-{
- UINT16 PciStatus;
- UINT16 VendorId;
- UINT16 DeviceId;
- UINT8 ProgInterface;
- UINT8 SubClassCode;
- UINT8 BaseCode;
- UINT8 CapabilityPtr;
- UINT8 CapabilityId;
-
- VendorId = PciRead16 (PcdGet32 (PcdUsbEhciPciAddress) + PCI_VENDOR_ID_OFFSET);
- DeviceId = PciRead16 (PcdGet32 (PcdUsbEhciPciAddress) + PCI_DEVICE_ID_OFFSET);
-
- if ((VendorId == 0xFFFF) || (DeviceId == 0xFFFF)) {
- return RETURN_UNSUPPORTED;
- }
-
- ProgInterface = PciRead8 (PcdGet32 (PcdUsbEhciPciAddress) + PCI_CLASSCODE_OFFSET);
- SubClassCode = PciRead8 (PcdGet32 (PcdUsbEhciPciAddress) + PCI_CLASSCODE_OFFSET + 1);
- BaseCode = PciRead8 (PcdGet32 (PcdUsbEhciPciAddress) + PCI_CLASSCODE_OFFSET + 2);
-
- if ((ProgInterface != PCI_IF_EHCI) || (SubClassCode != PCI_CLASS_SERIAL_USB) || (BaseCode != PCI_CLASS_SERIAL)) {
- return RETURN_UNSUPPORTED;
- }
-
- //
- // Enable Ehci Host Controller MMIO Space.
- //
- PciStatus = PciRead16 (PcdGet32 (PcdUsbEhciPciAddress) + PCI_PRIMARY_STATUS_OFFSET);
-
- if ((PciStatus & EFI_PCI_STATUS_CAPABILITY) == 0) {
- //
- // The Pci Device Doesn't Support Capability Pointer.
- //
- return RETURN_UNSUPPORTED;
- }
-
- //
- // Get Pointer To Capability List
- //
- CapabilityPtr = PciRead8 (PcdGet32 (PcdUsbEhciPciAddress) + PCI_CAPBILITY_POINTER_OFFSET);
-
- //
- // Find Capability ID 0xA, Which Is For Debug Port
- //
- while (CapabilityPtr != 0) {
- CapabilityId = PciRead8 (PcdGet32 (PcdUsbEhciPciAddress) + CapabilityPtr);
- if (CapabilityId == PCI_CAPABILITY_ID_DEBUG_PORT) {
- break;
- }
-
- CapabilityPtr = PciRead8 (PcdGet32 (PcdUsbEhciPciAddress) + CapabilityPtr + 1);
- }
-
- //
- // No Debug Port Capability Found
- //
- if (CapabilityPtr == 0) {
- return RETURN_UNSUPPORTED;
- }
-
- //
- // Get The Base Address Of Debug Port Register In Debug Port Capability Register
- //
- *DebugPortOffset = (UINT16)(PciRead16 (PcdGet32 (PcdUsbEhciPciAddress) + CapabilityPtr + 2) & 0x1FFF);
- *DebugPortBarNumbar = (UINT8)((PciRead16 (PcdGet32 (PcdUsbEhciPciAddress) + CapabilityPtr + 2) >> 13) - 1);
-
- return RETURN_SUCCESS;
-}
-
-/**
- Do a usb IN transaction by usb debug port.
-
- @param DebugPortRegister Pointer to the base address of usb debug port register interface.
- @param Buffer Pointer to the buffer receiving data.
- @param Length Number of bytes of the received data.
- @param Token The token PID for each USB transaction.
- @param Addr The usb device address for usb transaction.
- @param Ep The endpoint for usb transaction.
- @param DataToggle The toggle bit used at usb transaction.
-
- @retval RETURN_SUCCESS The IN transaction is executed successfully.
- @retval RETURN_INVALID_PARAMETER The parameters passed in are invalid.
- @retval RETURN_DEVICE_ERROR The IN transaction comes across error.
-
-**/
-RETURN_STATUS
-EFIAPI
-UsbDebugPortIn (
- IN USB_DEBUG_PORT_REGISTER *DebugPortRegister,
- IN OUT UINT8 *Buffer,
- OUT UINT8 *Length,
- IN UINT8 Token,
- IN UINT8 Addr,
- IN UINT8 Ep,
- IN UINT8 DataToggle
- )
-{
- UINTN Index;
-
- if (Length == NULL) {
- return RETURN_INVALID_PARAMETER;
- }
-
- *Length = 0;
-
- DebugPortRegister->TokenPid = Token;
- if (DataToggle != 0) {
- DebugPortRegister->SendPid = DATA1_PID;
- } else {
- DebugPortRegister->SendPid = DATA0_PID;
- }
-
- DebugPortRegister->UsbAddress = (UINT8)(Addr & 0x7F);
- DebugPortRegister->UsbEndPoint = (UINT8)(Ep & 0xF);
-
- //
- // Clearing W/R bit to indicate it's a READ operation
- //
- MmioAnd32 ((UINTN)&DebugPortRegister->ControlStatus, (UINT32) ~BIT4);
-
- //
- // Setting GO bit as well as clearing DONE bit
- //
- MmioOr32 ((UINTN)&DebugPortRegister->ControlStatus, (UINT32)BIT5);
-
- //
- // Wait for completing the request
- //
- while ((MmioRead32 ((UINTN)&DebugPortRegister->ControlStatus) & (UINT32)BIT16) == 0) {
- if ((MmioRead32 ((UINTN)&DebugPortRegister->ControlStatus) & (USB_DEBUG_PORT_OWNER | USB_DEBUG_PORT_IN_USE | USB_DEBUG_PORT_ENABLE))
- != (USB_DEBUG_PORT_OWNER | USB_DEBUG_PORT_IN_USE | USB_DEBUG_PORT_ENABLE))
- {
- return RETURN_DEVICE_ERROR;
- }
- }
-
- //
- // Clearing DONE bit by writing 1
- //
- MmioOr32 ((UINTN)&DebugPortRegister->ControlStatus, BIT16);
-
- //
- // Check if the request is executed successfully or not.
- //
- if ((MmioRead32 ((UINTN)&DebugPortRegister->ControlStatus)) & BIT6) {
- return RETURN_DEVICE_ERROR;
- }
-
- //
- // Make sure the received data are not beyond the allowable maximum length - 8 byte
- //
- if (((MmioRead32 ((UINTN)&DebugPortRegister->ControlStatus)) & 0xF) > USB_DEBUG_PORT_MAX_PACKET_SIZE) {
- return RETURN_DEVICE_ERROR;
- }
-
- *Length = (UINT8)(MmioRead32 ((UINTN)&DebugPortRegister->ControlStatus) & 0xF);
- if (*Length > 8) {
- return RETURN_DEVICE_ERROR;
- }
-
- for (Index = 0; Index < *Length; Index++) {
- Buffer[Index] = DebugPortRegister->DataBuffer[Index];
- }
-
- return RETURN_SUCCESS;
-}
-
-/**
- Do a usb SETUP/OUT transaction by usb debug port.
-
- @param DebugPortRegister Pointer to the base address of usb debug port register interface.
- @param Buffer Pointer to the buffer receiving data.
- @param Length Number of bytes of the received data.
- @param Token The token PID for each USB transaction.
- @param Addr The usb device address for usb transaction.
- @param Ep The endpoint for usb transaction.
- @param DataToggle The toggle bit used at usb transaction.
-
- @retval RETURN_SUCCESS The IN transaction is executed successfully.
- @retval RETURN_INVALID_PARAMETER The parameters passed in are invalid.
- @retval RETURN_DEVICE_ERROR The IN transaction comes across error.
-
-**/
-RETURN_STATUS
-EFIAPI
-UsbDebugPortOut (
- IN USB_DEBUG_PORT_REGISTER *DebugPortRegister,
- IN UINT8 *Buffer,
- IN UINT8 Length,
- IN UINT8 Token,
- IN UINT8 Addr,
- IN UINT8 Ep,
- IN UINT8 DataToggle
- )
-{
- UINT8 Index;
-
- if (Length > 8) {
- return RETURN_INVALID_PARAMETER;
- }
-
- DebugPortRegister->TokenPid = Token;
- if (DataToggle != 0) {
- DebugPortRegister->SendPid = DATA1_PID;
- } else {
- DebugPortRegister->SendPid = DATA0_PID;
- }
-
- DebugPortRegister->UsbAddress = (UINT8)(Addr & 0x7F);
- DebugPortRegister->UsbEndPoint = (UINT8)(Ep & 0xF);
-
- //
- // Fill in the data length and corresponding data.
- //
- MmioAnd32 ((UINTN)&DebugPortRegister->ControlStatus, (UINT32) ~0xF);
- MmioOr32 ((UINTN)&DebugPortRegister->ControlStatus, Length & 0xF);
- for (Index = 0; Index < Length; Index++) {
- DebugPortRegister->DataBuffer[Index] = Buffer[Index];
- }
-
- //
- // Setting W/R bit to indicate it's a WRITE operation
- //
- MmioOr32 ((UINTN)&DebugPortRegister->ControlStatus, BIT4);
- //
- // Setting GO bit as well as clearing DONE bit
- //
- MmioOr32 ((UINTN)&DebugPortRegister->ControlStatus, BIT5);
-
- //
- // Wait for completing the request
- //
- while ((MmioRead32 ((UINTN)&DebugPortRegister->ControlStatus) & BIT16) == 0) {
- if ((MmioRead32 ((UINTN)&DebugPortRegister->ControlStatus) & (USB_DEBUG_PORT_OWNER | USB_DEBUG_PORT_IN_USE | USB_DEBUG_PORT_ENABLE))
- != (USB_DEBUG_PORT_OWNER | USB_DEBUG_PORT_IN_USE | USB_DEBUG_PORT_ENABLE))
- {
- return RETURN_DEVICE_ERROR;
- }
- }
-
- //
- // Clearing DONE bit by writing 1
- //
- MmioOr32 ((UINTN)&DebugPortRegister->ControlStatus, BIT16);
-
- //
- // Check if the request is executed successfully or not.
- //
- if ((MmioRead32 ((UINTN)&DebugPortRegister->ControlStatus)) & BIT6) {
- return RETURN_DEVICE_ERROR;
- }
-
- //
- // Make sure the sent data are not beyond the allowable maximum length - 8 byte
- //
- if (((MmioRead32 ((UINTN)&DebugPortRegister->ControlStatus)) & 0xF) > USB_DEBUG_PORT_MAX_PACKET_SIZE) {
- return RETURN_DEVICE_ERROR;
- }
-
- return RETURN_SUCCESS;
-}
-
-/**
- Do a usb control transfer by usb debug port.
-
- @param DebugPortRegister Pointer to the base address of usb debug port register interface.
- @param SetupPacket The token PID for each USB transaction.
- @param Addr The usb device address for usb transaction.
- @param Ep The endpoint for usb transaction.
- @param Data Pointer to the buffer receiving data.
- @param DataLength Number of bytes of the received data.
-
- @retval RETURN_SUCCESS The IN transaction is executed successfully.
- @retval RETURN_INVALID_PARAMETER The parameters passed in are invalid.
- @retval RETURN_DEVICE_ERROR The IN transaction comes across error.
-
-**/
-RETURN_STATUS
-EFIAPI
-UsbDebugPortControlTransfer (
- IN USB_DEBUG_PORT_REGISTER *DebugPortRegister,
- IN USB_DEVICE_REQUEST *SetupPacket,
- IN UINT8 Addr,
- IN UINT8 Ep,
- OUT UINT8 *Data,
- IN OUT UINT8 *DataLength
- )
-{
- RETURN_STATUS Status;
- UINT8 Temp;
- UINT8 ReturnStatus[8];
-
- //
- // Setup Phase
- //
- Status = UsbDebugPortOut (DebugPortRegister, (UINT8 *)SetupPacket, (UINT8)sizeof (USB_DEVICE_REQUEST), SETUP_PID, Addr, Ep, 0);
- if (RETURN_ERROR (Status)) {
- return Status;
- }
-
- //
- // Data Phase
- //
- if (DataLength != 0) {
- if ((SetupPacket->RequestType & BIT7) != 0) {
- //
- // Get Data From Device
- //
- Status = UsbDebugPortIn (DebugPortRegister, Data, DataLength, INPUT_PID, Addr, Ep, 1);
- if (RETURN_ERROR (Status)) {
- return Status;
- }
- } else {
- //
- // Send Data To Device
- //
- Status = UsbDebugPortOut (DebugPortRegister, Data, *DataLength, OUTPUT_PID, Addr, Ep, 1);
- if (RETURN_ERROR (Status)) {
- return Status;
- }
- }
- }
-
- //
- // Status Phase
- //
- if ((SetupPacket->RequestType & BIT7) != 0) {
- //
- // For READ operation, Data Toggle in Status Phase Should be 1.
- //
- Status = UsbDebugPortOut (DebugPortRegister, NULL, 0, OUTPUT_PID, Addr, Ep, 1);
- } else {
- //
- // For WRITE operation, Data Toggle in Status Phase Should be 1.
- //
- Status = UsbDebugPortIn (DebugPortRegister, ReturnStatus, &Temp, INPUT_PID, Addr, Ep, 1);
- }
-
- return Status;
-}
-
-/**
- Check if it needs to re-initialize usb debug port hardware.
-
- During different phases switch, such as SEC to PEI or PEI to DXE or DXE to SMM, we should check
- whether the usb debug port hardware configuration is changed. Such case can be triggered by
- Pci bus resource allocation and so on.
-
- @param Handle Debug port handle.
-
- @retval TRUE The usb debug port hardware configuration is changed.
- @retval FALSE The usb debug port hardware configuration is not changed.
-
-**/
-BOOLEAN
-EFIAPI
-NeedReinitializeHardware (
- IN USB_DEBUG_PORT_HANDLE *Handle
- )
-{
- UINT16 PciCmd;
- UINT32 UsbDebugPortMemoryBase;
- UINT32 EhciMemoryBase;
- BOOLEAN Status;
- USB_DEBUG_PORT_REGISTER *UsbDebugPortRegister;
-
- Status = FALSE;
-
- EhciMemoryBase = 0xFFFFFC00 & PciRead32 (PcdGet32 (PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET);
- if (EhciMemoryBase != Handle->EhciMemoryBase) {
- Handle->EhciMemoryBase = EhciMemoryBase;
- Status = TRUE;
- }
-
- UsbDebugPortMemoryBase = 0xFFFFFC00 & PciRead32 (PcdGet32 (PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET + Handle->DebugPortBarNumber * 4);
- if (UsbDebugPortMemoryBase != Handle->UsbDebugPortMemoryBase) {
- Handle->UsbDebugPortMemoryBase = UsbDebugPortMemoryBase;
- Status = TRUE;
- }
-
- //
- // Enable Ehci Memory Space Access
- //
- PciCmd = PciRead16 (PcdGet32 (PcdUsbEhciPciAddress) + PCI_COMMAND_OFFSET);
- if (((PciCmd & EFI_PCI_COMMAND_MEMORY_SPACE) == 0) || ((PciCmd & EFI_PCI_COMMAND_BUS_MASTER) == 0)) {
- PciCmd |= EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_BUS_MASTER;
- PciWrite16 (PcdGet32 (PcdUsbEhciPciAddress) + PCI_COMMAND_OFFSET, PciCmd);
- Status = TRUE;
- }
-
- //
- // If the owner and in_use bit is not set, it means system is doing cold/warm boot or EHCI host controller is reset by system software.
- //
- UsbDebugPortRegister = (USB_DEBUG_PORT_REGISTER *)((UINTN)Handle->UsbDebugPortMemoryBase + Handle->DebugPortOffset);
- if ((MmioRead32 ((UINTN)&UsbDebugPortRegister->ControlStatus) & (USB_DEBUG_PORT_OWNER | USB_DEBUG_PORT_ENABLE | USB_DEBUG_PORT_IN_USE))
- != (USB_DEBUG_PORT_OWNER | USB_DEBUG_PORT_ENABLE | USB_DEBUG_PORT_IN_USE))
- {
- Status = TRUE;
- }
-
- if (Handle->Initialized == USBDBG_RESET) {
- Status = TRUE;
- } else if (Handle->Initialized != USBDBG_INIT_DONE) {
- Status = TRUE;
- }
-
- return Status;
-}
-
-/**
- Initialize usb debug port hardware.
-
- 1. reset ehci host controller.
- 2. set right port to debug port.
- 3. find a usb debug device is attached by getting debug device descriptor.
- 4. set address for the usb debug device.
- 5. configure the usb debug device to debug mode.
-
- @param Handle Debug port handle.
-
- @retval TRUE The usb debug port hardware configuration is changed.
- @retval FALSE The usb debug port hardware configuration is not changed.
-
-**/
-RETURN_STATUS
-EFIAPI
-InitializeUsbDebugHardware (
- IN USB_DEBUG_PORT_HANDLE *Handle
- )
-{
- RETURN_STATUS Status;
- USB_DEBUG_PORT_REGISTER *UsbDebugPortRegister;
- USB_DEBUG_PORT_DESCRIPTOR UsbDebugPortDescriptor;
- UINT32 *PortStatus;
- UINT32 *UsbCmd;
- UINT32 *UsbStatus;
- UINT32 *UsbHCSParam;
- UINT8 DebugPortNumber;
- UINT8 Length;
-
- UsbDebugPortRegister = (USB_DEBUG_PORT_REGISTER *)((UINTN)Handle->UsbDebugPortMemoryBase + Handle->DebugPortOffset);
- UsbHCSParam = (UINT32 *)((UINTN)Handle->EhciMemoryBase + 0x04);
- UsbCmd = (UINT32 *)((UINTN)Handle->EhciMemoryBase + 0x20);
- UsbStatus = (UINT32 *)((UINTN)Handle->EhciMemoryBase + 0x24);
-
- //
- // Check if the debug port is enabled and owned by myself.
- //
- if (((MmioRead32 ((UINTN)&UsbDebugPortRegister->ControlStatus) & (USB_DEBUG_PORT_OWNER | USB_DEBUG_PORT_IN_USE))
- != (USB_DEBUG_PORT_OWNER | USB_DEBUG_PORT_IN_USE)) || (Handle->Initialized == USBDBG_RESET))
- {
- DEBUG ((
- DEBUG_INFO,
- "UsbDbg: Need to reset the host controller. ControlStatus = %08x\n",
- MmioRead32 ((UINTN)&UsbDebugPortRegister->ControlStatus)
- ));
- //
- // If the host controller is halted, then reset and restart it.
- //
- if ((MmioRead32 ((UINTN)UsbStatus) & BIT12) != 0) {
- DEBUG ((DEBUG_INFO, "UsbDbg: Reset the host controller.\n"));
- //
- // reset the host controller.
- //
- MmioOr32 ((UINTN)UsbCmd, BIT1);
- //
- // ensure that the host controller is reset.
- //
- while ((MmioRead32 ((UINTN)UsbCmd) & BIT1) != 0) {
- }
-
- MmioOr32 ((UINTN)UsbCmd, BIT0);
- // ensure that the host controller is started (HALTED bit must be cleared)
- while ((MmioRead32 ((UINTN)UsbStatus) & BIT12) != 0) {
- }
- }
-
- //
- // First get the ownership of port 0.
- //
- MmioOr32 ((UINTN)&UsbDebugPortRegister->ControlStatus, USB_DEBUG_PORT_OWNER | USB_DEBUG_PORT_IN_USE);
-
- MicroSecondDelay (200000);
- }
-
- //
- // Find out which port is used as debug port.
- //
- DebugPortNumber = (UINT8)((MmioRead32 ((UINTN)UsbHCSParam) & 0x00F00000) >> 20);
- //
- // Should find a device is connected at debug port
- //
- PortStatus = (UINT32 *)((UINTN)Handle->EhciMemoryBase + 0x64 + (DebugPortNumber - 1) * 4);
- if (!(MmioRead32 ((UINTN)PortStatus) & BIT0)) {
- Handle->Initialized = USBDBG_NO_DEV;
- return RETURN_NOT_FOUND;
- }
-
- if ((Handle->Initialized != USBDBG_INIT_DONE) ||
- ((MmioRead32 ((UINTN)&UsbDebugPortRegister->ControlStatus) & USB_DEBUG_PORT_ENABLE) == 0))
- {
- DEBUG ((DEBUG_INFO, "UsbDbg: Reset the debug port.\n"));
- //
- // Reset the debug port
- //
- MmioOr32 ((UINTN)PortStatus, BIT8);
- MicroSecondDelay (500000);
- MmioAnd32 ((UINTN)PortStatus, (UINT32) ~BIT8);
- while (MmioRead32 ((UINTN)PortStatus) & BIT8) {
- }
-
- //
- // The port enabled bit should be set by HW.
- //
- if ((MmioRead32 ((UINTN)PortStatus) & BIT2) == 0) {
- Handle->Initialized = USBDBG_NO_DBG_CAB;
- return RETURN_DEVICE_ERROR;
- }
-
- //
- // Enable Usb Debug Port Capability
- //
- MmioOr32 ((UINTN)&UsbDebugPortRegister->ControlStatus, USB_DEBUG_PORT_ENABLE);
-
- //
- // initialize the data toggle used by bulk in/out endpoint.
- //
- Handle->BulkInToggle = 0;
- Handle->BulkOutToggle = 0;
-
- //
- // set usb debug device address as 0x7F.
- //
- Status = UsbDebugPortControlTransfer (UsbDebugPortRegister, &mDebugCommunicationLibUsbSetDebugAddress, 0x0, 0x0, NULL, NULL);
- if (RETURN_ERROR (Status)) {
- //
- // The device can not work well.
- //
- Handle->Initialized = USBDBG_NO_DBG_CAB;
- return Status;
- }
-
- //
- // Start to communicate with Usb Debug Device to see if the attached device is usb debug device or not.
- //
- Length = (UINT8)sizeof (USB_DEBUG_PORT_DESCRIPTOR);
-
- //
- // Get debug descriptor.
- //
- Status = UsbDebugPortControlTransfer (UsbDebugPortRegister, &mDebugCommunicationLibUsbGetDebugDescriptor, 0x7F, 0x0, (UINT8 *)&UsbDebugPortDescriptor, &Length);
- if (RETURN_ERROR (Status)) {
- //
- // The device is not a usb debug device.
- //
- Handle->Initialized = USBDBG_NO_DBG_CAB;
- return Status;
- }
-
- if (Length != sizeof (USB_DEBUG_PORT_DESCRIPTOR)) {
- Handle->Initialized = USBDBG_NO_DBG_CAB;
- return RETURN_DEVICE_ERROR;
- }
-
- //
- // Determine the usb debug device endpoints.
- //
- Handle->InEndpoint = UsbDebugPortDescriptor.DebugInEndpoint;
- Handle->OutEndpoint = UsbDebugPortDescriptor.DebugOutEndpoint;
-
- //
- // enable the usb debug feature.
- //
- Status = UsbDebugPortControlTransfer (UsbDebugPortRegister, &mDebugCommunicationLibUsbSetDebugFeature, 0x7F, 0x0, NULL, NULL);
- if (RETURN_ERROR (Status)) {
- //
- // The device can not work well.
- //
- Handle->Initialized = USBDBG_NO_DBG_CAB;
- return Status;
- }
-
- Handle->Initialized = USBDBG_DBG_CAB;
- }
-
- //
- // Set initialized flag
- //
- Handle->Initialized = USBDBG_INIT_DONE;
-
- return RETURN_SUCCESS;
-}
-
-/**
- Read data from debug device and save the data in a buffer.
-
- Reads NumberOfBytes data bytes from a debug device into the buffer
- specified by Buffer. The number of bytes actually read is returned.
- If the return value is less than NumberOfBytes, then the rest operation failed.
- If NumberOfBytes is zero, then return 0.
-
- @param Handle Debug port handle.
- @param Buffer Pointer to the data buffer to store the data read from the debug device.
- @param NumberOfBytes Number of bytes which will be read.
- @param Timeout Timeout value for reading from debug device. It unit is Microsecond.
-
- @retval 0 Read data failed, no data is to be read.
- @retval >0 Actual number of bytes read from debug device.
-
-**/
-UINTN
-EFIAPI
-DebugPortReadBuffer (
- IN DEBUG_PORT_HANDLE Handle,
- IN UINT8 *Buffer,
- IN UINTN NumberOfBytes,
- IN UINTN Timeout
- )
-{
- USB_DEBUG_PORT_HANDLE *UsbDebugPortHandle;
- RETURN_STATUS Status;
- UINT8 Index;
-
- if ((NumberOfBytes != 1) || (Buffer == NULL) || (Timeout != 0)) {
- return 0;
- }
-
- //
- // If Handle is NULL, it means memory is ready for use.
- // Use global variable to store handle value.
- //
- if (Handle == NULL) {
- UsbDebugPortHandle = &mDebugCommunicationLibUsbDebugPortHandle;
- } else {
- UsbDebugPortHandle = (USB_DEBUG_PORT_HANDLE *)Handle;
- }
-
- if (NeedReinitializeHardware (UsbDebugPortHandle)) {
- Status = InitializeUsbDebugHardware (UsbDebugPortHandle);
- if (RETURN_ERROR (Status)) {
- return 0;
- }
- }
-
- //
- // Read data from buffer
- //
- if (UsbDebugPortHandle->DataCount < 1) {
- return 0;
- } else {
- *Buffer = UsbDebugPortHandle->Data[0];
- for (Index = 0; Index < UsbDebugPortHandle->DataCount - 1; Index++) {
- if ((Index + 1) >= USB_DEBUG_PORT_MAX_PACKET_SIZE) {
- return 0;
- }
-
- UsbDebugPortHandle->Data[Index] = UsbDebugPortHandle->Data[Index + 1];
- }
-
- UsbDebugPortHandle->DataCount = (UINT8)(UsbDebugPortHandle->DataCount - 1);
- return 1;
- }
-}
-
-/**
- Write data from buffer to debug device.
-
- Writes NumberOfBytes data bytes from Buffer to the debug device.
- The number of bytes actually written to the debug device is returned.
- If the return value is less than NumberOfBytes, then the write operation failed.
- If NumberOfBytes is zero, then return 0.
-
- @param Handle Debug port handle.
- @param Buffer Pointer to the data buffer to be written.
- @param NumberOfBytes Number of bytes to written to the debug device.
-
- @retval 0 NumberOfBytes is 0.
- @retval >0 The number of bytes written to the debug device.
- If this value is less than NumberOfBytes, then the read operation failed.
-
-**/
-UINTN
-EFIAPI
-DebugPortWriteBuffer (
- IN DEBUG_PORT_HANDLE Handle,
- IN UINT8 *Buffer,
- IN UINTN NumberOfBytes
- )
-{
- USB_DEBUG_PORT_HANDLE *UsbDebugPortHandle;
- USB_DEBUG_PORT_REGISTER *UsbDebugPortRegister;
- RETURN_STATUS Status;
- UINT8 Sent;
- UINTN Total;
- UINT8 ReceivedPid;
-
- if ((NumberOfBytes == 0) || (Buffer == NULL)) {
- return 0;
- }
-
- Sent = 0;
- Total = 0;
-
- //
- // If Handle is NULL, it means memory is ready for use.
- // Use global variable to store handle value.
- //
- if (Handle == NULL) {
- UsbDebugPortHandle = &mDebugCommunicationLibUsbDebugPortHandle;
- } else {
- UsbDebugPortHandle = (USB_DEBUG_PORT_HANDLE *)Handle;
- }
-
- if (NeedReinitializeHardware (UsbDebugPortHandle)) {
- Status = InitializeUsbDebugHardware (UsbDebugPortHandle);
- if (RETURN_ERROR (Status)) {
- return 0;
- }
- }
-
- UsbDebugPortRegister = (USB_DEBUG_PORT_REGISTER *)((UINTN)UsbDebugPortHandle->UsbDebugPortMemoryBase + UsbDebugPortHandle->DebugPortOffset);
-
- while ((Total < NumberOfBytes)) {
- if (NumberOfBytes - Total > USB_DEBUG_PORT_MAX_PACKET_SIZE) {
- Sent = USB_DEBUG_PORT_MAX_PACKET_SIZE;
- } else {
- Sent = (UINT8)(NumberOfBytes - Total);
- }
-
- Status = UsbDebugPortOut (UsbDebugPortRegister, Buffer + Total, Sent, OUTPUT_PID, 0x7F, UsbDebugPortHandle->OutEndpoint, UsbDebugPortHandle->BulkOutToggle);
-
- if (RETURN_ERROR (Status)) {
- return Total;
- }
-
- ReceivedPid = (MmioRead8 ((UINTN)&UsbDebugPortRegister->ReceivedPid));
- //
- // If received a NAK_PID on write transaction, it means the usb debug device is busy and can not handle this transaction.
- // should send the packet again.
- //
- if (ReceivedPid == NAK_PID) {
- Sent = 0;
- } else {
- UsbDebugPortHandle->BulkOutToggle ^= 1;
- }
-
- Total += Sent;
- }
-
- return Total;
-}
-
-/**
- Polls a debug device to see if there is any data waiting to be read.
-
- Polls a debug device to see if there is any data waiting to be read.
- If there is data waiting to be read from the debug device, then TRUE is returned.
- If there is no data waiting to be read from the debug device, then FALSE is returned.
-
- @param Handle Debug port handle.
-
- @retval TRUE Data is waiting to be read from the debug device.
- @retval FALSE There is no data waiting to be read from the serial device.
-
-**/
-BOOLEAN
-EFIAPI
-DebugPortPollBuffer (
- IN DEBUG_PORT_HANDLE Handle
- )
-{
- USB_DEBUG_PORT_HANDLE *UsbDebugPortHandle;
- USB_DEBUG_PORT_REGISTER *UsbDebugPortRegister;
- UINT8 Length;
- UINT8 Index;
- RETURN_STATUS Status;
-
- //
- // If Handle is NULL, it means memory is ready for use.
- // Use global variable to store handle value.
- //
- if (Handle == NULL) {
- UsbDebugPortHandle = &mDebugCommunicationLibUsbDebugPortHandle;
- } else {
- UsbDebugPortHandle = (USB_DEBUG_PORT_HANDLE *)Handle;
- }
-
- if (NeedReinitializeHardware (UsbDebugPortHandle)) {
- Status = InitializeUsbDebugHardware (UsbDebugPortHandle);
- if (RETURN_ERROR (Status)) {
- return FALSE;
- }
- }
-
- //
- // If the data buffer is not empty, then return TRUE directly.
- // else initialize a usb read transaction and read data to the data buffer.
- //
- if (UsbDebugPortHandle->DataCount != 0) {
- return TRUE;
- }
-
- UsbDebugPortRegister = (USB_DEBUG_PORT_REGISTER *)((UINTN)UsbDebugPortHandle->UsbDebugPortMemoryBase + UsbDebugPortHandle->DebugPortOffset);
-
- UsbDebugPortRegister->TokenPid = INPUT_PID;
- if (UsbDebugPortHandle->BulkInToggle == 0) {
- UsbDebugPortRegister->SendPid = DATA0_PID;
- } else {
- UsbDebugPortRegister->SendPid = DATA1_PID;
- }
-
- UsbDebugPortRegister->UsbAddress = 0x7F;
- UsbDebugPortRegister->UsbEndPoint = UsbDebugPortHandle->InEndpoint & 0x0F;
-
- //
- // Clearing W/R bit to indicate it's a READ operation
- //
- MmioAnd32 ((UINTN)&UsbDebugPortRegister->ControlStatus, (UINT32) ~BIT4);
- //
- // Setting GO bit as well as clearing DONE bit
- //
- MmioOr32 ((UINTN)&UsbDebugPortRegister->ControlStatus, (UINT32)BIT5);
-
- //
- // Wait for completing the request
- //
- while ((MmioRead32 ((UINTN)&UsbDebugPortRegister->ControlStatus) & (UINT32)BIT16) == 0) {
- if ((MmioRead32 ((UINTN)&UsbDebugPortRegister->ControlStatus) & (USB_DEBUG_PORT_OWNER | USB_DEBUG_PORT_IN_USE | USB_DEBUG_PORT_ENABLE))
- != (USB_DEBUG_PORT_OWNER | USB_DEBUG_PORT_IN_USE | USB_DEBUG_PORT_ENABLE))
- {
- return FALSE;
- }
- }
-
- if ((MmioRead32 ((UINTN)&UsbDebugPortRegister->ControlStatus)) & BIT6) {
- return FALSE;
- }
-
- Length = (UINT8)(MmioRead32 ((UINTN)&UsbDebugPortRegister->ControlStatus) & 0xF);
-
- if (Length > 8) {
- return FALSE;
- }
-
- UsbDebugPortHandle->BulkInToggle ^= 1;
-
- if (Length == 0) {
- return FALSE;
- }
-
- for (Index = 0; Index < Length; Index++) {
- UsbDebugPortHandle->Data[Index] = UsbDebugPortRegister->DataBuffer[Index];
- }
-
- UsbDebugPortHandle->DataCount = Length;
-
- return TRUE;
-}
-
-/**
- Initialize the debug port.
-
- If Function is not NULL, Debug Communication Library will call this function
- by passing in the Context to be the first parameter. If needed, Debug Communication
- Library will create one debug port handle to be the second argument passing in
- calling the Function, otherwise it will pass NULL to be the second argument of
- Function.
-
- If Function is NULL, and Context is not NULL, the Debug Communication Library could
- a) Return the same handle as passed in (as Context parameter).
- b) Ignore the input Context parameter and create new handle to be returned.
-
- If parameter Function is NULL and Context is NULL, Debug Communication Library could
- created a new handle if needed and return it, otherwise it will return NULL.
-
- @param[in] Context Context needed by callback function; it was optional.
- @param[in] Function Continue function called by Debug Communication library;
- it was optional.
-
- @return The debug port handle created by Debug Communication Library if Function
- is not NULL.
-
-**/
-DEBUG_PORT_HANDLE
-EFIAPI
-DebugPortInitialize (
- IN VOID *Context,
- IN DEBUG_PORT_CONTINUE Function
- )
-{
- RETURN_STATUS Status;
- USB_DEBUG_PORT_HANDLE Handle;
-
- //
- // Validate the PCD PcdDebugPortHandleBufferSize value
- //
- ASSERT (PcdGet16 (PcdDebugPortHandleBufferSize) == sizeof (USB_DEBUG_PORT_HANDLE));
-
- if ((Function == NULL) && (Context != NULL)) {
- return (DEBUG_PORT_HANDLE *)Context;
- }
-
- ZeroMem (&Handle, sizeof (USB_DEBUG_PORT_HANDLE));
-
- Status = CalculateUsbDebugPortBar (&Handle.DebugPortOffset, &Handle.DebugPortBarNumber);
- if (RETURN_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "UsbDbg: the pci device pointed by PcdUsbEhciPciAddress is not EHCI host controller or does not support debug port capability!\n"));
- goto Exit;
- }
-
- Handle.EhciMemoryBase = 0xFFFFFC00 & PciRead32 (PcdGet32 (PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET);
-
- if (Handle.EhciMemoryBase == 0) {
- //
- // Usb Debug Port MMIO Space Is Not Enabled. Assumption here that DebugPortBase is zero
- //
- PciWrite32 (PcdGet32 (PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET, PcdGet32 (PcdUsbEhciMemorySpaceBase));
- Handle.EhciMemoryBase = 0xFFFFFC00 & PciRead32 (PcdGet32 (PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET);
- }
-
- Handle.UsbDebugPortMemoryBase = 0xFFFFFC00 & PciRead32 (PcdGet32 (PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET + Handle.DebugPortBarNumber * 4);
-
- if (Handle.UsbDebugPortMemoryBase == 0) {
- //
- // Usb Debug Port MMIO Space Is Not Enabled. Assumption here that DebugPortBase is zero
- //
- PciWrite32 (PcdGet32 (PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET + Handle.DebugPortBarNumber * 4, PcdGet32 (PcdUsbDebugPortMemorySpaceBase));
- Handle.UsbDebugPortMemoryBase = 0xFFFFFC00 & PciRead32 (PcdGet32 (PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET + Handle.DebugPortBarNumber * 4);
- }
-
- Handle.Initialized = USBDBG_RESET;
-
- if (NeedReinitializeHardware (&Handle)) {
- DEBUG ((DEBUG_ERROR, "UsbDbg: Start EHCI debug port initialization!\n"));
- Status = InitializeUsbDebugHardware (&Handle);
- if (RETURN_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "UsbDbg: Failed, please check if USB debug cable is plugged into EHCI debug port correctly!\n"));
- goto Exit;
- }
- }
-
-Exit:
-
- if (Function != NULL) {
- Function (Context, &Handle);
- } else {
- CopyMem (&mDebugCommunicationLibUsbDebugPortHandle, &Handle, sizeof (USB_DEBUG_PORT_HANDLE));
- }
-
- return (DEBUG_PORT_HANDLE)(UINTN)&mDebugCommunicationLibUsbDebugPortHandle;
-}
+/** @file + Debug Port Library implementation based on usb debug port. + + Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Base.h> +#include <IndustryStandard/Pci.h> +#include <IndustryStandard/Usb.h> +#include <Library/IoLib.h> +#include <Library/PciLib.h> +#include <Library/PcdLib.h> +#include <Library/TimerLib.h> +#include <Library/DebugCommunicationLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> + +#define SETUP_PID 0x2D +#define INPUT_PID 0x69 +#define OUTPUT_PID 0xE1 +#define ERROR_PID 0x55 +#define DATA0_PID 0xC3 +#define DATA1_PID 0x4B +#define DATA2_PID 0x87 +#define MDATA_PID 0x0F +#define ACK_PID 0xD2 +#define NAK_PID 0x5A +#define STALL_PID 0x1E +#define NYET_PID 0x96 + +#define PCI_CAPABILITY_ID_DEBUG_PORT 0x0A +#define USB_DEBUG_PORT_MAX_PACKET_SIZE 0x08 + +#define USB_DEBUG_PORT_IN_USE BIT10 +#define USB_DEBUG_PORT_ENABLE BIT28 +#define USB_DEBUG_PORT_OWNER BIT30 + +#define USB_PORT_LINE_STATUS_LS 0x400 +#define USB_PORT_LINE_STATUS_MASK 0xC00 + +// +// Usb debug device descriptor, which is defined at +// USB2 Debug Device Specification. +// +typedef struct _USB_DEBUG_PORT_DESCRIPTOR { + UINT8 Length; + UINT8 DescriptorType; + UINT8 DebugInEndpoint; + UINT8 DebugOutEndpoint; +} USB_DEBUG_PORT_DESCRIPTOR; + +USB_DEVICE_REQUEST mDebugCommunicationLibUsbGetDebugDescriptor = { + 0x80, + USB_REQ_GET_DESCRIPTOR, + (UINT16)(0x0A << 8), + 0x0000, + sizeof (USB_DEBUG_PORT_DESCRIPTOR) +}; + +USB_DEVICE_REQUEST mDebugCommunicationLibUsbSetDebugFeature = { + 0x0, + USB_REQ_SET_FEATURE, + (UINT16)(0x06), + 0x0000, + 0x0 +}; + +USB_DEVICE_REQUEST mDebugCommunicationLibUsbSetDebugAddress = { + 0x0, + USB_REQ_SET_ADDRESS, + (UINT16)(0x7F), + 0x0000, + 0x0 +}; + +// +// Usb debug port register file, which is defined at +// EHCI Specification. +// +typedef struct _USB_DEBUG_PORT_REGISTER { + UINT32 ControlStatus; + UINT8 TokenPid; + UINT8 SendPid; + UINT8 ReceivedPid; + UINT8 Reserved1; + UINT8 DataBuffer[8]; + UINT8 UsbEndPoint; + UINT8 UsbAddress; + UINT8 Reserved2; + UINT8 Reserved3; +} USB_DEBUG_PORT_REGISTER; + +// +// The state machine of usb debug port +// +#define USBDBG_NO_DEV 0 // No device present at debug port +#define USBDBG_NO_DBG_CAB 1 // The device attached is not usb debug cable +#define USBDBG_DBG_CAB 2 // The device attached is usb debug cable +#define USBDBG_INIT_DONE 4 // The usb debug cable device is initialized +#define USBDBG_RESET 8 // The system is reset + +#pragma pack(1) +// +// The internal data structure of DEBUG_PORT_HANDLE, which stores some +// important datum which are used across various phases. +// +typedef struct _USB_DEBUG_PORT_HANDLE { + // + // The usb debug port memory BAR number in EHCI configuration space. + // + UINT8 DebugPortBarNumber; + UINT8 Initialized; + // + // The offset of usb debug port registers in EHCI memory range. + // + UINT16 DebugPortOffset; + // + // The usb debug port memory BAR address. + // + UINT32 UsbDebugPortMemoryBase; + // + // The EHCI memory BAR address. + // + UINT32 EhciMemoryBase; + // + // The usb debug device In endpoint. + // + UINT8 InEndpoint; + // + // The usb debug device Out endpoint. + // + UINT8 OutEndpoint; + // + // The Bulk In endpoint toggle bit. + // + UINT8 BulkInToggle; + // + // The Bulk Out endpoint toggle bit. + // + UINT8 BulkOutToggle; + // + // The available data length in the following data buffer. + // + UINT8 DataCount; + // + // The data buffer. Maximum length is 8 bytes. + // + UINT8 Data[8]; +} USB_DEBUG_PORT_HANDLE; +#pragma pack() + +// +// The global variable which can be used after memory is ready. +// +USB_DEBUG_PORT_HANDLE mDebugCommunicationLibUsbDebugPortHandle; + +/** + Calculate the usb debug port bar address. + + @param DebugPortOffset Get usb debug port offset in the usb debug port memory space. + @param DebugPortBarNumbar Get the bar number at which usb debug port is located. + + @retval RETURN_UNSUPPORTED The usb host controller does not supported usb debug port capability. + @retval RETURN_SUCCESS Get bar and offset successfully. + +**/ +RETURN_STATUS +EFIAPI +CalculateUsbDebugPortBar ( + OUT UINT16 *DebugPortOffset, + OUT UINT8 *DebugPortBarNumbar + ) +{ + UINT16 PciStatus; + UINT16 VendorId; + UINT16 DeviceId; + UINT8 ProgInterface; + UINT8 SubClassCode; + UINT8 BaseCode; + UINT8 CapabilityPtr; + UINT8 CapabilityId; + + VendorId = PciRead16 (PcdGet32 (PcdUsbEhciPciAddress) + PCI_VENDOR_ID_OFFSET); + DeviceId = PciRead16 (PcdGet32 (PcdUsbEhciPciAddress) + PCI_DEVICE_ID_OFFSET); + + if ((VendorId == 0xFFFF) || (DeviceId == 0xFFFF)) { + return RETURN_UNSUPPORTED; + } + + ProgInterface = PciRead8 (PcdGet32 (PcdUsbEhciPciAddress) + PCI_CLASSCODE_OFFSET); + SubClassCode = PciRead8 (PcdGet32 (PcdUsbEhciPciAddress) + PCI_CLASSCODE_OFFSET + 1); + BaseCode = PciRead8 (PcdGet32 (PcdUsbEhciPciAddress) + PCI_CLASSCODE_OFFSET + 2); + + if ((ProgInterface != PCI_IF_EHCI) || (SubClassCode != PCI_CLASS_SERIAL_USB) || (BaseCode != PCI_CLASS_SERIAL)) { + return RETURN_UNSUPPORTED; + } + + // + // Enable Ehci Host Controller MMIO Space. + // + PciStatus = PciRead16 (PcdGet32 (PcdUsbEhciPciAddress) + PCI_PRIMARY_STATUS_OFFSET); + + if ((PciStatus & EFI_PCI_STATUS_CAPABILITY) == 0) { + // + // The Pci Device Doesn't Support Capability Pointer. + // + return RETURN_UNSUPPORTED; + } + + // + // Get Pointer To Capability List + // + CapabilityPtr = PciRead8 (PcdGet32 (PcdUsbEhciPciAddress) + PCI_CAPBILITY_POINTER_OFFSET); + + // + // Find Capability ID 0xA, Which Is For Debug Port + // + while (CapabilityPtr != 0) { + CapabilityId = PciRead8 (PcdGet32 (PcdUsbEhciPciAddress) + CapabilityPtr); + if (CapabilityId == PCI_CAPABILITY_ID_DEBUG_PORT) { + break; + } + + CapabilityPtr = PciRead8 (PcdGet32 (PcdUsbEhciPciAddress) + CapabilityPtr + 1); + } + + // + // No Debug Port Capability Found + // + if (CapabilityPtr == 0) { + return RETURN_UNSUPPORTED; + } + + // + // Get The Base Address Of Debug Port Register In Debug Port Capability Register + // + *DebugPortOffset = (UINT16)(PciRead16 (PcdGet32 (PcdUsbEhciPciAddress) + CapabilityPtr + 2) & 0x1FFF); + *DebugPortBarNumbar = (UINT8)((PciRead16 (PcdGet32 (PcdUsbEhciPciAddress) + CapabilityPtr + 2) >> 13) - 1); + + return RETURN_SUCCESS; +} + +/** + Do a usb IN transaction by usb debug port. + + @param DebugPortRegister Pointer to the base address of usb debug port register interface. + @param Buffer Pointer to the buffer receiving data. + @param Length Number of bytes of the received data. + @param Token The token PID for each USB transaction. + @param Addr The usb device address for usb transaction. + @param Ep The endpoint for usb transaction. + @param DataToggle The toggle bit used at usb transaction. + + @retval RETURN_SUCCESS The IN transaction is executed successfully. + @retval RETURN_INVALID_PARAMETER The parameters passed in are invalid. + @retval RETURN_DEVICE_ERROR The IN transaction comes across error. + +**/ +RETURN_STATUS +EFIAPI +UsbDebugPortIn ( + IN USB_DEBUG_PORT_REGISTER *DebugPortRegister, + IN OUT UINT8 *Buffer, + OUT UINT8 *Length, + IN UINT8 Token, + IN UINT8 Addr, + IN UINT8 Ep, + IN UINT8 DataToggle + ) +{ + UINTN Index; + + if (Length == NULL) { + return RETURN_INVALID_PARAMETER; + } + + *Length = 0; + + DebugPortRegister->TokenPid = Token; + if (DataToggle != 0) { + DebugPortRegister->SendPid = DATA1_PID; + } else { + DebugPortRegister->SendPid = DATA0_PID; + } + + DebugPortRegister->UsbAddress = (UINT8)(Addr & 0x7F); + DebugPortRegister->UsbEndPoint = (UINT8)(Ep & 0xF); + + // + // Clearing W/R bit to indicate it's a READ operation + // + MmioAnd32 ((UINTN)&DebugPortRegister->ControlStatus, (UINT32) ~BIT4); + + // + // Setting GO bit as well as clearing DONE bit + // + MmioOr32 ((UINTN)&DebugPortRegister->ControlStatus, (UINT32)BIT5); + + // + // Wait for completing the request + // + while ((MmioRead32 ((UINTN)&DebugPortRegister->ControlStatus) & (UINT32)BIT16) == 0) { + if ((MmioRead32 ((UINTN)&DebugPortRegister->ControlStatus) & (USB_DEBUG_PORT_OWNER | USB_DEBUG_PORT_IN_USE | USB_DEBUG_PORT_ENABLE)) + != (USB_DEBUG_PORT_OWNER | USB_DEBUG_PORT_IN_USE | USB_DEBUG_PORT_ENABLE)) + { + return RETURN_DEVICE_ERROR; + } + } + + // + // Clearing DONE bit by writing 1 + // + MmioOr32 ((UINTN)&DebugPortRegister->ControlStatus, BIT16); + + // + // Check if the request is executed successfully or not. + // + if ((MmioRead32 ((UINTN)&DebugPortRegister->ControlStatus)) & BIT6) { + return RETURN_DEVICE_ERROR; + } + + // + // Make sure the received data are not beyond the allowable maximum length - 8 byte + // + if (((MmioRead32 ((UINTN)&DebugPortRegister->ControlStatus)) & 0xF) > USB_DEBUG_PORT_MAX_PACKET_SIZE) { + return RETURN_DEVICE_ERROR; + } + + *Length = (UINT8)(MmioRead32 ((UINTN)&DebugPortRegister->ControlStatus) & 0xF); + if (*Length > 8) { + return RETURN_DEVICE_ERROR; + } + + for (Index = 0; Index < *Length; Index++) { + Buffer[Index] = DebugPortRegister->DataBuffer[Index]; + } + + return RETURN_SUCCESS; +} + +/** + Do a usb SETUP/OUT transaction by usb debug port. + + @param DebugPortRegister Pointer to the base address of usb debug port register interface. + @param Buffer Pointer to the buffer receiving data. + @param Length Number of bytes of the received data. + @param Token The token PID for each USB transaction. + @param Addr The usb device address for usb transaction. + @param Ep The endpoint for usb transaction. + @param DataToggle The toggle bit used at usb transaction. + + @retval RETURN_SUCCESS The IN transaction is executed successfully. + @retval RETURN_INVALID_PARAMETER The parameters passed in are invalid. + @retval RETURN_DEVICE_ERROR The IN transaction comes across error. + +**/ +RETURN_STATUS +EFIAPI +UsbDebugPortOut ( + IN USB_DEBUG_PORT_REGISTER *DebugPortRegister, + IN UINT8 *Buffer, + IN UINT8 Length, + IN UINT8 Token, + IN UINT8 Addr, + IN UINT8 Ep, + IN UINT8 DataToggle + ) +{ + UINT8 Index; + + if (Length > 8) { + return RETURN_INVALID_PARAMETER; + } + + DebugPortRegister->TokenPid = Token; + if (DataToggle != 0) { + DebugPortRegister->SendPid = DATA1_PID; + } else { + DebugPortRegister->SendPid = DATA0_PID; + } + + DebugPortRegister->UsbAddress = (UINT8)(Addr & 0x7F); + DebugPortRegister->UsbEndPoint = (UINT8)(Ep & 0xF); + + // + // Fill in the data length and corresponding data. + // + MmioAnd32 ((UINTN)&DebugPortRegister->ControlStatus, (UINT32) ~0xF); + MmioOr32 ((UINTN)&DebugPortRegister->ControlStatus, Length & 0xF); + for (Index = 0; Index < Length; Index++) { + DebugPortRegister->DataBuffer[Index] = Buffer[Index]; + } + + // + // Setting W/R bit to indicate it's a WRITE operation + // + MmioOr32 ((UINTN)&DebugPortRegister->ControlStatus, BIT4); + // + // Setting GO bit as well as clearing DONE bit + // + MmioOr32 ((UINTN)&DebugPortRegister->ControlStatus, BIT5); + + // + // Wait for completing the request + // + while ((MmioRead32 ((UINTN)&DebugPortRegister->ControlStatus) & BIT16) == 0) { + if ((MmioRead32 ((UINTN)&DebugPortRegister->ControlStatus) & (USB_DEBUG_PORT_OWNER | USB_DEBUG_PORT_IN_USE | USB_DEBUG_PORT_ENABLE)) + != (USB_DEBUG_PORT_OWNER | USB_DEBUG_PORT_IN_USE | USB_DEBUG_PORT_ENABLE)) + { + return RETURN_DEVICE_ERROR; + } + } + + // + // Clearing DONE bit by writing 1 + // + MmioOr32 ((UINTN)&DebugPortRegister->ControlStatus, BIT16); + + // + // Check if the request is executed successfully or not. + // + if ((MmioRead32 ((UINTN)&DebugPortRegister->ControlStatus)) & BIT6) { + return RETURN_DEVICE_ERROR; + } + + // + // Make sure the sent data are not beyond the allowable maximum length - 8 byte + // + if (((MmioRead32 ((UINTN)&DebugPortRegister->ControlStatus)) & 0xF) > USB_DEBUG_PORT_MAX_PACKET_SIZE) { + return RETURN_DEVICE_ERROR; + } + + return RETURN_SUCCESS; +} + +/** + Do a usb control transfer by usb debug port. + + @param DebugPortRegister Pointer to the base address of usb debug port register interface. + @param SetupPacket The token PID for each USB transaction. + @param Addr The usb device address for usb transaction. + @param Ep The endpoint for usb transaction. + @param Data Pointer to the buffer receiving data. + @param DataLength Number of bytes of the received data. + + @retval RETURN_SUCCESS The IN transaction is executed successfully. + @retval RETURN_INVALID_PARAMETER The parameters passed in are invalid. + @retval RETURN_DEVICE_ERROR The IN transaction comes across error. + +**/ +RETURN_STATUS +EFIAPI +UsbDebugPortControlTransfer ( + IN USB_DEBUG_PORT_REGISTER *DebugPortRegister, + IN USB_DEVICE_REQUEST *SetupPacket, + IN UINT8 Addr, + IN UINT8 Ep, + OUT UINT8 *Data, + IN OUT UINT8 *DataLength + ) +{ + RETURN_STATUS Status; + UINT8 Temp; + UINT8 ReturnStatus[8]; + + // + // Setup Phase + // + Status = UsbDebugPortOut (DebugPortRegister, (UINT8 *)SetupPacket, (UINT8)sizeof (USB_DEVICE_REQUEST), SETUP_PID, Addr, Ep, 0); + if (RETURN_ERROR (Status)) { + return Status; + } + + // + // Data Phase + // + if (DataLength != 0) { + if ((SetupPacket->RequestType & BIT7) != 0) { + // + // Get Data From Device + // + Status = UsbDebugPortIn (DebugPortRegister, Data, DataLength, INPUT_PID, Addr, Ep, 1); + if (RETURN_ERROR (Status)) { + return Status; + } + } else { + // + // Send Data To Device + // + Status = UsbDebugPortOut (DebugPortRegister, Data, *DataLength, OUTPUT_PID, Addr, Ep, 1); + if (RETURN_ERROR (Status)) { + return Status; + } + } + } + + // + // Status Phase + // + if ((SetupPacket->RequestType & BIT7) != 0) { + // + // For READ operation, Data Toggle in Status Phase Should be 1. + // + Status = UsbDebugPortOut (DebugPortRegister, NULL, 0, OUTPUT_PID, Addr, Ep, 1); + } else { + // + // For WRITE operation, Data Toggle in Status Phase Should be 1. + // + Status = UsbDebugPortIn (DebugPortRegister, ReturnStatus, &Temp, INPUT_PID, Addr, Ep, 1); + } + + return Status; +} + +/** + Check if it needs to re-initialize usb debug port hardware. + + During different phases switch, such as SEC to PEI or PEI to DXE or DXE to SMM, we should check + whether the usb debug port hardware configuration is changed. Such case can be triggered by + Pci bus resource allocation and so on. + + @param Handle Debug port handle. + + @retval TRUE The usb debug port hardware configuration is changed. + @retval FALSE The usb debug port hardware configuration is not changed. + +**/ +BOOLEAN +EFIAPI +NeedReinitializeHardware ( + IN USB_DEBUG_PORT_HANDLE *Handle + ) +{ + UINT16 PciCmd; + UINT32 UsbDebugPortMemoryBase; + UINT32 EhciMemoryBase; + BOOLEAN Status; + USB_DEBUG_PORT_REGISTER *UsbDebugPortRegister; + + Status = FALSE; + + EhciMemoryBase = 0xFFFFFC00 & PciRead32 (PcdGet32 (PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET); + if (EhciMemoryBase != Handle->EhciMemoryBase) { + Handle->EhciMemoryBase = EhciMemoryBase; + Status = TRUE; + } + + UsbDebugPortMemoryBase = 0xFFFFFC00 & PciRead32 (PcdGet32 (PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET + Handle->DebugPortBarNumber * 4); + if (UsbDebugPortMemoryBase != Handle->UsbDebugPortMemoryBase) { + Handle->UsbDebugPortMemoryBase = UsbDebugPortMemoryBase; + Status = TRUE; + } + + // + // Enable Ehci Memory Space Access + // + PciCmd = PciRead16 (PcdGet32 (PcdUsbEhciPciAddress) + PCI_COMMAND_OFFSET); + if (((PciCmd & EFI_PCI_COMMAND_MEMORY_SPACE) == 0) || ((PciCmd & EFI_PCI_COMMAND_BUS_MASTER) == 0)) { + PciCmd |= EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_BUS_MASTER; + PciWrite16 (PcdGet32 (PcdUsbEhciPciAddress) + PCI_COMMAND_OFFSET, PciCmd); + Status = TRUE; + } + + // + // If the owner and in_use bit is not set, it means system is doing cold/warm boot or EHCI host controller is reset by system software. + // + UsbDebugPortRegister = (USB_DEBUG_PORT_REGISTER *)((UINTN)Handle->UsbDebugPortMemoryBase + Handle->DebugPortOffset); + if ((MmioRead32 ((UINTN)&UsbDebugPortRegister->ControlStatus) & (USB_DEBUG_PORT_OWNER | USB_DEBUG_PORT_ENABLE | USB_DEBUG_PORT_IN_USE)) + != (USB_DEBUG_PORT_OWNER | USB_DEBUG_PORT_ENABLE | USB_DEBUG_PORT_IN_USE)) + { + Status = TRUE; + } + + if (Handle->Initialized == USBDBG_RESET) { + Status = TRUE; + } else if (Handle->Initialized != USBDBG_INIT_DONE) { + Status = TRUE; + } + + return Status; +} + +/** + Initialize usb debug port hardware. + + 1. reset ehci host controller. + 2. set right port to debug port. + 3. find a usb debug device is attached by getting debug device descriptor. + 4. set address for the usb debug device. + 5. configure the usb debug device to debug mode. + + @param Handle Debug port handle. + + @retval TRUE The usb debug port hardware configuration is changed. + @retval FALSE The usb debug port hardware configuration is not changed. + +**/ +RETURN_STATUS +EFIAPI +InitializeUsbDebugHardware ( + IN USB_DEBUG_PORT_HANDLE *Handle + ) +{ + RETURN_STATUS Status; + USB_DEBUG_PORT_REGISTER *UsbDebugPortRegister; + USB_DEBUG_PORT_DESCRIPTOR UsbDebugPortDescriptor; + UINT32 *PortStatus; + UINT32 *UsbCmd; + UINT32 *UsbStatus; + UINT32 *UsbHCSParam; + UINT8 DebugPortNumber; + UINT8 Length; + + UsbDebugPortRegister = (USB_DEBUG_PORT_REGISTER *)((UINTN)Handle->UsbDebugPortMemoryBase + Handle->DebugPortOffset); + UsbHCSParam = (UINT32 *)((UINTN)Handle->EhciMemoryBase + 0x04); + UsbCmd = (UINT32 *)((UINTN)Handle->EhciMemoryBase + 0x20); + UsbStatus = (UINT32 *)((UINTN)Handle->EhciMemoryBase + 0x24); + + // + // Check if the debug port is enabled and owned by myself. + // + if (((MmioRead32 ((UINTN)&UsbDebugPortRegister->ControlStatus) & (USB_DEBUG_PORT_OWNER | USB_DEBUG_PORT_IN_USE)) + != (USB_DEBUG_PORT_OWNER | USB_DEBUG_PORT_IN_USE)) || (Handle->Initialized == USBDBG_RESET)) + { + DEBUG (( + DEBUG_INFO, + "UsbDbg: Need to reset the host controller. ControlStatus = %08x\n", + MmioRead32 ((UINTN)&UsbDebugPortRegister->ControlStatus) + )); + // + // If the host controller is halted, then reset and restart it. + // + if ((MmioRead32 ((UINTN)UsbStatus) & BIT12) != 0) { + DEBUG ((DEBUG_INFO, "UsbDbg: Reset the host controller.\n")); + // + // reset the host controller. + // + MmioOr32 ((UINTN)UsbCmd, BIT1); + // + // ensure that the host controller is reset. + // + while ((MmioRead32 ((UINTN)UsbCmd) & BIT1) != 0) { + } + + MmioOr32 ((UINTN)UsbCmd, BIT0); + // ensure that the host controller is started (HALTED bit must be cleared) + while ((MmioRead32 ((UINTN)UsbStatus) & BIT12) != 0) { + } + } + + // + // First get the ownership of port 0. + // + MmioOr32 ((UINTN)&UsbDebugPortRegister->ControlStatus, USB_DEBUG_PORT_OWNER | USB_DEBUG_PORT_IN_USE); + + MicroSecondDelay (200000); + } + + // + // Find out which port is used as debug port. + // + DebugPortNumber = (UINT8)((MmioRead32 ((UINTN)UsbHCSParam) & 0x00F00000) >> 20); + // + // Should find a device is connected at debug port + // + PortStatus = (UINT32 *)((UINTN)Handle->EhciMemoryBase + 0x64 + (DebugPortNumber - 1) * 4); + if (!(MmioRead32 ((UINTN)PortStatus) & BIT0)) { + Handle->Initialized = USBDBG_NO_DEV; + return RETURN_NOT_FOUND; + } + + if ((Handle->Initialized != USBDBG_INIT_DONE) || + ((MmioRead32 ((UINTN)&UsbDebugPortRegister->ControlStatus) & USB_DEBUG_PORT_ENABLE) == 0)) + { + DEBUG ((DEBUG_INFO, "UsbDbg: Reset the debug port.\n")); + // + // Reset the debug port + // + MmioOr32 ((UINTN)PortStatus, BIT8); + MicroSecondDelay (500000); + MmioAnd32 ((UINTN)PortStatus, (UINT32) ~BIT8); + while (MmioRead32 ((UINTN)PortStatus) & BIT8) { + } + + // + // The port enabled bit should be set by HW. + // + if ((MmioRead32 ((UINTN)PortStatus) & BIT2) == 0) { + Handle->Initialized = USBDBG_NO_DBG_CAB; + return RETURN_DEVICE_ERROR; + } + + // + // Enable Usb Debug Port Capability + // + MmioOr32 ((UINTN)&UsbDebugPortRegister->ControlStatus, USB_DEBUG_PORT_ENABLE); + + // + // initialize the data toggle used by bulk in/out endpoint. + // + Handle->BulkInToggle = 0; + Handle->BulkOutToggle = 0; + + // + // set usb debug device address as 0x7F. + // + Status = UsbDebugPortControlTransfer (UsbDebugPortRegister, &mDebugCommunicationLibUsbSetDebugAddress, 0x0, 0x0, NULL, NULL); + if (RETURN_ERROR (Status)) { + // + // The device can not work well. + // + Handle->Initialized = USBDBG_NO_DBG_CAB; + return Status; + } + + // + // Start to communicate with Usb Debug Device to see if the attached device is usb debug device or not. + // + Length = (UINT8)sizeof (USB_DEBUG_PORT_DESCRIPTOR); + + // + // Get debug descriptor. + // + Status = UsbDebugPortControlTransfer (UsbDebugPortRegister, &mDebugCommunicationLibUsbGetDebugDescriptor, 0x7F, 0x0, (UINT8 *)&UsbDebugPortDescriptor, &Length); + if (RETURN_ERROR (Status)) { + // + // The device is not a usb debug device. + // + Handle->Initialized = USBDBG_NO_DBG_CAB; + return Status; + } + + if (Length != sizeof (USB_DEBUG_PORT_DESCRIPTOR)) { + Handle->Initialized = USBDBG_NO_DBG_CAB; + return RETURN_DEVICE_ERROR; + } + + // + // Determine the usb debug device endpoints. + // + Handle->InEndpoint = UsbDebugPortDescriptor.DebugInEndpoint; + Handle->OutEndpoint = UsbDebugPortDescriptor.DebugOutEndpoint; + + // + // enable the usb debug feature. + // + Status = UsbDebugPortControlTransfer (UsbDebugPortRegister, &mDebugCommunicationLibUsbSetDebugFeature, 0x7F, 0x0, NULL, NULL); + if (RETURN_ERROR (Status)) { + // + // The device can not work well. + // + Handle->Initialized = USBDBG_NO_DBG_CAB; + return Status; + } + + Handle->Initialized = USBDBG_DBG_CAB; + } + + // + // Set initialized flag + // + Handle->Initialized = USBDBG_INIT_DONE; + + return RETURN_SUCCESS; +} + +/** + Read data from debug device and save the data in a buffer. + + Reads NumberOfBytes data bytes from a debug device into the buffer + specified by Buffer. The number of bytes actually read is returned. + If the return value is less than NumberOfBytes, then the rest operation failed. + If NumberOfBytes is zero, then return 0. + + @param Handle Debug port handle. + @param Buffer Pointer to the data buffer to store the data read from the debug device. + @param NumberOfBytes Number of bytes which will be read. + @param Timeout Timeout value for reading from debug device. It unit is Microsecond. + + @retval 0 Read data failed, no data is to be read. + @retval >0 Actual number of bytes read from debug device. + +**/ +UINTN +EFIAPI +DebugPortReadBuffer ( + IN DEBUG_PORT_HANDLE Handle, + IN UINT8 *Buffer, + IN UINTN NumberOfBytes, + IN UINTN Timeout + ) +{ + USB_DEBUG_PORT_HANDLE *UsbDebugPortHandle; + RETURN_STATUS Status; + UINT8 Index; + + if ((NumberOfBytes != 1) || (Buffer == NULL) || (Timeout != 0)) { + return 0; + } + + // + // If Handle is NULL, it means memory is ready for use. + // Use global variable to store handle value. + // + if (Handle == NULL) { + UsbDebugPortHandle = &mDebugCommunicationLibUsbDebugPortHandle; + } else { + UsbDebugPortHandle = (USB_DEBUG_PORT_HANDLE *)Handle; + } + + if (NeedReinitializeHardware (UsbDebugPortHandle)) { + Status = InitializeUsbDebugHardware (UsbDebugPortHandle); + if (RETURN_ERROR (Status)) { + return 0; + } + } + + // + // Read data from buffer + // + if (UsbDebugPortHandle->DataCount < 1) { + return 0; + } else { + *Buffer = UsbDebugPortHandle->Data[0]; + for (Index = 0; Index < UsbDebugPortHandle->DataCount - 1; Index++) { + if ((Index + 1) >= USB_DEBUG_PORT_MAX_PACKET_SIZE) { + return 0; + } + + UsbDebugPortHandle->Data[Index] = UsbDebugPortHandle->Data[Index + 1]; + } + + UsbDebugPortHandle->DataCount = (UINT8)(UsbDebugPortHandle->DataCount - 1); + return 1; + } +} + +/** + Write data from buffer to debug device. + + Writes NumberOfBytes data bytes from Buffer to the debug device. + The number of bytes actually written to the debug device is returned. + If the return value is less than NumberOfBytes, then the write operation failed. + If NumberOfBytes is zero, then return 0. + + @param Handle Debug port handle. + @param Buffer Pointer to the data buffer to be written. + @param NumberOfBytes Number of bytes to written to the debug device. + + @retval 0 NumberOfBytes is 0. + @retval >0 The number of bytes written to the debug device. + If this value is less than NumberOfBytes, then the read operation failed. + +**/ +UINTN +EFIAPI +DebugPortWriteBuffer ( + IN DEBUG_PORT_HANDLE Handle, + IN UINT8 *Buffer, + IN UINTN NumberOfBytes + ) +{ + USB_DEBUG_PORT_HANDLE *UsbDebugPortHandle; + USB_DEBUG_PORT_REGISTER *UsbDebugPortRegister; + RETURN_STATUS Status; + UINT8 Sent; + UINTN Total; + UINT8 ReceivedPid; + + if ((NumberOfBytes == 0) || (Buffer == NULL)) { + return 0; + } + + Sent = 0; + Total = 0; + + // + // If Handle is NULL, it means memory is ready for use. + // Use global variable to store handle value. + // + if (Handle == NULL) { + UsbDebugPortHandle = &mDebugCommunicationLibUsbDebugPortHandle; + } else { + UsbDebugPortHandle = (USB_DEBUG_PORT_HANDLE *)Handle; + } + + if (NeedReinitializeHardware (UsbDebugPortHandle)) { + Status = InitializeUsbDebugHardware (UsbDebugPortHandle); + if (RETURN_ERROR (Status)) { + return 0; + } + } + + UsbDebugPortRegister = (USB_DEBUG_PORT_REGISTER *)((UINTN)UsbDebugPortHandle->UsbDebugPortMemoryBase + UsbDebugPortHandle->DebugPortOffset); + + while ((Total < NumberOfBytes)) { + if (NumberOfBytes - Total > USB_DEBUG_PORT_MAX_PACKET_SIZE) { + Sent = USB_DEBUG_PORT_MAX_PACKET_SIZE; + } else { + Sent = (UINT8)(NumberOfBytes - Total); + } + + Status = UsbDebugPortOut (UsbDebugPortRegister, Buffer + Total, Sent, OUTPUT_PID, 0x7F, UsbDebugPortHandle->OutEndpoint, UsbDebugPortHandle->BulkOutToggle); + + if (RETURN_ERROR (Status)) { + return Total; + } + + ReceivedPid = (MmioRead8 ((UINTN)&UsbDebugPortRegister->ReceivedPid)); + // + // If received a NAK_PID on write transaction, it means the usb debug device is busy and can not handle this transaction. + // should send the packet again. + // + if (ReceivedPid == NAK_PID) { + Sent = 0; + } else { + UsbDebugPortHandle->BulkOutToggle ^= 1; + } + + Total += Sent; + } + + return Total; +} + +/** + Polls a debug device to see if there is any data waiting to be read. + + Polls a debug device to see if there is any data waiting to be read. + If there is data waiting to be read from the debug device, then TRUE is returned. + If there is no data waiting to be read from the debug device, then FALSE is returned. + + @param Handle Debug port handle. + + @retval TRUE Data is waiting to be read from the debug device. + @retval FALSE There is no data waiting to be read from the serial device. + +**/ +BOOLEAN +EFIAPI +DebugPortPollBuffer ( + IN DEBUG_PORT_HANDLE Handle + ) +{ + USB_DEBUG_PORT_HANDLE *UsbDebugPortHandle; + USB_DEBUG_PORT_REGISTER *UsbDebugPortRegister; + UINT8 Length; + UINT8 Index; + RETURN_STATUS Status; + + // + // If Handle is NULL, it means memory is ready for use. + // Use global variable to store handle value. + // + if (Handle == NULL) { + UsbDebugPortHandle = &mDebugCommunicationLibUsbDebugPortHandle; + } else { + UsbDebugPortHandle = (USB_DEBUG_PORT_HANDLE *)Handle; + } + + if (NeedReinitializeHardware (UsbDebugPortHandle)) { + Status = InitializeUsbDebugHardware (UsbDebugPortHandle); + if (RETURN_ERROR (Status)) { + return FALSE; + } + } + + // + // If the data buffer is not empty, then return TRUE directly. + // else initialize a usb read transaction and read data to the data buffer. + // + if (UsbDebugPortHandle->DataCount != 0) { + return TRUE; + } + + UsbDebugPortRegister = (USB_DEBUG_PORT_REGISTER *)((UINTN)UsbDebugPortHandle->UsbDebugPortMemoryBase + UsbDebugPortHandle->DebugPortOffset); + + UsbDebugPortRegister->TokenPid = INPUT_PID; + if (UsbDebugPortHandle->BulkInToggle == 0) { + UsbDebugPortRegister->SendPid = DATA0_PID; + } else { + UsbDebugPortRegister->SendPid = DATA1_PID; + } + + UsbDebugPortRegister->UsbAddress = 0x7F; + UsbDebugPortRegister->UsbEndPoint = UsbDebugPortHandle->InEndpoint & 0x0F; + + // + // Clearing W/R bit to indicate it's a READ operation + // + MmioAnd32 ((UINTN)&UsbDebugPortRegister->ControlStatus, (UINT32) ~BIT4); + // + // Setting GO bit as well as clearing DONE bit + // + MmioOr32 ((UINTN)&UsbDebugPortRegister->ControlStatus, (UINT32)BIT5); + + // + // Wait for completing the request + // + while ((MmioRead32 ((UINTN)&UsbDebugPortRegister->ControlStatus) & (UINT32)BIT16) == 0) { + if ((MmioRead32 ((UINTN)&UsbDebugPortRegister->ControlStatus) & (USB_DEBUG_PORT_OWNER | USB_DEBUG_PORT_IN_USE | USB_DEBUG_PORT_ENABLE)) + != (USB_DEBUG_PORT_OWNER | USB_DEBUG_PORT_IN_USE | USB_DEBUG_PORT_ENABLE)) + { + return FALSE; + } + } + + if ((MmioRead32 ((UINTN)&UsbDebugPortRegister->ControlStatus)) & BIT6) { + return FALSE; + } + + Length = (UINT8)(MmioRead32 ((UINTN)&UsbDebugPortRegister->ControlStatus) & 0xF); + + if (Length > 8) { + return FALSE; + } + + UsbDebugPortHandle->BulkInToggle ^= 1; + + if (Length == 0) { + return FALSE; + } + + for (Index = 0; Index < Length; Index++) { + UsbDebugPortHandle->Data[Index] = UsbDebugPortRegister->DataBuffer[Index]; + } + + UsbDebugPortHandle->DataCount = Length; + + return TRUE; +} + +/** + Initialize the debug port. + + If Function is not NULL, Debug Communication Library will call this function + by passing in the Context to be the first parameter. If needed, Debug Communication + Library will create one debug port handle to be the second argument passing in + calling the Function, otherwise it will pass NULL to be the second argument of + Function. + + If Function is NULL, and Context is not NULL, the Debug Communication Library could + a) Return the same handle as passed in (as Context parameter). + b) Ignore the input Context parameter and create new handle to be returned. + + If parameter Function is NULL and Context is NULL, Debug Communication Library could + created a new handle if needed and return it, otherwise it will return NULL. + + @param[in] Context Context needed by callback function; it was optional. + @param[in] Function Continue function called by Debug Communication library; + it was optional. + + @return The debug port handle created by Debug Communication Library if Function + is not NULL. + +**/ +DEBUG_PORT_HANDLE +EFIAPI +DebugPortInitialize ( + IN VOID *Context, + IN DEBUG_PORT_CONTINUE Function + ) +{ + RETURN_STATUS Status; + USB_DEBUG_PORT_HANDLE Handle; + + // + // Validate the PCD PcdDebugPortHandleBufferSize value + // + ASSERT (PcdGet16 (PcdDebugPortHandleBufferSize) == sizeof (USB_DEBUG_PORT_HANDLE)); + + if ((Function == NULL) && (Context != NULL)) { + return (DEBUG_PORT_HANDLE *)Context; + } + + ZeroMem (&Handle, sizeof (USB_DEBUG_PORT_HANDLE)); + + Status = CalculateUsbDebugPortBar (&Handle.DebugPortOffset, &Handle.DebugPortBarNumber); + if (RETURN_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "UsbDbg: the pci device pointed by PcdUsbEhciPciAddress is not EHCI host controller or does not support debug port capability!\n")); + goto Exit; + } + + Handle.EhciMemoryBase = 0xFFFFFC00 & PciRead32 (PcdGet32 (PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET); + + if (Handle.EhciMemoryBase == 0) { + // + // Usb Debug Port MMIO Space Is Not Enabled. Assumption here that DebugPortBase is zero + // + PciWrite32 (PcdGet32 (PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET, PcdGet32 (PcdUsbEhciMemorySpaceBase)); + Handle.EhciMemoryBase = 0xFFFFFC00 & PciRead32 (PcdGet32 (PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET); + } + + Handle.UsbDebugPortMemoryBase = 0xFFFFFC00 & PciRead32 (PcdGet32 (PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET + Handle.DebugPortBarNumber * 4); + + if (Handle.UsbDebugPortMemoryBase == 0) { + // + // Usb Debug Port MMIO Space Is Not Enabled. Assumption here that DebugPortBase is zero + // + PciWrite32 (PcdGet32 (PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET + Handle.DebugPortBarNumber * 4, PcdGet32 (PcdUsbDebugPortMemorySpaceBase)); + Handle.UsbDebugPortMemoryBase = 0xFFFFFC00 & PciRead32 (PcdGet32 (PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET + Handle.DebugPortBarNumber * 4); + } + + Handle.Initialized = USBDBG_RESET; + + if (NeedReinitializeHardware (&Handle)) { + DEBUG ((DEBUG_ERROR, "UsbDbg: Start EHCI debug port initialization!\n")); + Status = InitializeUsbDebugHardware (&Handle); + if (RETURN_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "UsbDbg: Failed, please check if USB debug cable is plugged into EHCI debug port correctly!\n")); + goto Exit; + } + } + +Exit: + + if (Function != NULL) { + Function (Context, &Handle); + } else { + CopyMem (&mDebugCommunicationLibUsbDebugPortHandle, &Handle, sizeof (USB_DEBUG_PORT_HANDLE)); + } + + return (DEBUG_PORT_HANDLE)(UINTN)&mDebugCommunicationLibUsbDebugPortHandle; +} diff --git a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb/DebugCommunicationLibUsb.inf b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb/DebugCommunicationLibUsb.inf index 31a0a00e37..6af0fb1b16 100644 --- a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb/DebugCommunicationLibUsb.inf +++ b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb/DebugCommunicationLibUsb.inf @@ -1,51 +1,51 @@ -## @file
-# Debug Communication Library instance based on usb debug port.
-#
-# Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-#
-##
-
-[Defines]
- INF_VERSION = 0x00010005
- BASE_NAME = DebugCommunicationLibUsb
- MODULE_UNI_FILE = DebugCommunicationLibUsb.uni
- FILE_GUID = 87438836-AD8D-4e3e-9249-895120A67240
- MODULE_TYPE = BASE
- VERSION_STRING = 0.7
- LIBRARY_CLASS = DebugCommunicationLib
-
-#
-# VALID_ARCHITECTURES = IA32 X64
-#
-
-[Sources.common]
- DebugCommunicationLibUsb.c
-
-[Packages]
- MdePkg/MdePkg.dec
- SourceLevelDebugPkg/SourceLevelDebugPkg.dec
-
-[Pcd]
- # The memory BAR of usb debug port, it may be different with the memory bar of ehci host controller.
- # Note that the memory BAR address is only used before Pci bus resource allocation.
- gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbDebugPortMemorySpaceBase ## SOMETIMES_CONSUMES
- # The memory BAR of ehci host controller, in which usb debug feature is enabled.
- # Note that the memory BAR address is only used before Pci bus resource allocation.
- gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbEhciMemorySpaceBase ## SOMETIMES_CONSUMES
- # The pci address of ehci host controller, in which usb debug feature is enabled.
- # The format of pci address please refer to SourceLevelDebugPkg.dec
- gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbEhciPciAddress ## CONSUMES
- # The value of data buffer size used for USB debug port handle.
- # It should be equal to sizeof (USB_DEBUG_PORT_HANDLE).
- gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdDebugPortHandleBufferSize|25 ## SOMETIMES_CONSUMES
-
-[LibraryClasses]
- TimerLib
- IoLib
- PciLib
- PcdLib
- DebugLib
-
+## @file +# Debug Communication Library instance based on usb debug port. +# +# Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DebugCommunicationLibUsb + MODULE_UNI_FILE = DebugCommunicationLibUsb.uni + FILE_GUID = 87438836-AD8D-4e3e-9249-895120A67240 + MODULE_TYPE = BASE + VERSION_STRING = 0.7 + LIBRARY_CLASS = DebugCommunicationLib + +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources.common] + DebugCommunicationLibUsb.c + +[Packages] + MdePkg/MdePkg.dec + SourceLevelDebugPkg/SourceLevelDebugPkg.dec + +[Pcd] + # The memory BAR of usb debug port, it may be different with the memory bar of ehci host controller. + # Note that the memory BAR address is only used before Pci bus resource allocation. + gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbDebugPortMemorySpaceBase ## SOMETIMES_CONSUMES + # The memory BAR of ehci host controller, in which usb debug feature is enabled. + # Note that the memory BAR address is only used before Pci bus resource allocation. + gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbEhciMemorySpaceBase ## SOMETIMES_CONSUMES + # The pci address of ehci host controller, in which usb debug feature is enabled. + # The format of pci address please refer to SourceLevelDebugPkg.dec + gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbEhciPciAddress ## CONSUMES + # The value of data buffer size used for USB debug port handle. + # It should be equal to sizeof (USB_DEBUG_PORT_HANDLE). + gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdDebugPortHandleBufferSize|25 ## SOMETIMES_CONSUMES + +[LibraryClasses] + TimerLib + IoLib + PciLib + PcdLib + DebugLib + diff --git a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb/DebugCommunicationLibUsb.uni b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb/DebugCommunicationLibUsb.uni index b7fb54d224..66c2a6326f 100644 --- a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb/DebugCommunicationLibUsb.uni +++ b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb/DebugCommunicationLibUsb.uni @@ -1,16 +1,16 @@ -// /** @file
-// Debug Communication Library instance based on usb debug port.
-//
-// Debug Communication Library instance based on USB debug port.
-//
-// Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
-//
-// SPDX-License-Identifier: BSD-2-Clause-Patent
-//
-// **/
-
-
-#string STR_MODULE_ABSTRACT #language en-US "Debug Communication Library instance based on USB debug port"
-
-#string STR_MODULE_DESCRIPTION #language en-US "Debug Communication Library instance based on USB debug port."
-
+// /** @file +// Debug Communication Library instance based on usb debug port. +// +// Debug Communication Library instance based on USB debug port. +// +// Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR> +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Debug Communication Library instance based on USB debug port" + +#string STR_MODULE_DESCRIPTION #language en-US "Debug Communication Library instance based on USB debug port." + diff --git a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Common.c b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Common.c index 3a3d16e4b9..cc25b2ff34 100644 --- a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Common.c +++ b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Common.c @@ -1,1151 +1,1151 @@ -/** @file
- Debug Port Library implementation based on usb3 debug port.
-
- Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DebugCommunicationLibUsb3Internal.h"
-
-UINT16 mString0Desc[] = {
- // String Descriptor Type + Length
- (USB_DESC_TYPE_STRING << 8) + STRING0_DESC_LEN,
- 0x0409
-};
-
-UINT16 mManufacturerStrDesc[] = {
- // String Descriptor Type + Length
- (USB_DESC_TYPE_STRING << 8) + MANU_DESC_LEN,
- 'I', 'n','t', 'e', 'l'
-};
-
-UINT16 mProductStrDesc[] = {
- // String Descriptor Type + Length
- (USB_DESC_TYPE_STRING << 8) + PRODUCT_DESC_LEN,
- 'U', 'S','B', ' ', '3', '.', '0', ' ', 'D', 'e', 'b', 'u', 'g', ' ', 'C', 'a', 'b', 'l', 'e'
-};
-
-UINT16 mSerialNumberStrDesc[] = {
- // String Descriptor Type + Length
- (USB_DESC_TYPE_STRING << 8) + SERIAL_DESC_LEN,
- '1'
-};
-
-/**
- Sets bits as per the enabled bit positions in the mask.
-
- @param[in, out] Register UINTN register
- @param[in] BitMask 32-bit mask
-**/
-VOID
-XhcSetR32Bit (
- IN OUT UINTN Register,
- IN UINT32 BitMask
- )
-{
- UINT32 RegisterValue;
-
- RegisterValue = MmioRead32 (Register);
- RegisterValue |= (UINT32)(BitMask);
- MmioWrite32 (Register, RegisterValue);
-}
-
-/**
- Clears bits as per the enabled bit positions in the mask.
-
- @param[in, out] Register UINTN register
- @param[in] BitMask 32-bit mask
-**/
-VOID
-XhcClearR32Bit (
- IN OUT UINTN Register,
- IN UINT32 BitMask
- )
-{
- UINT32 RegisterValue;
-
- RegisterValue = MmioRead32 (Register);
- RegisterValue &= ~BitMask;
- MmioWrite32 (Register, RegisterValue);
-}
-
-/**
- Write the data to the XHCI debug register.
-
- @param Handle Debug port handle.
- @param Offset The offset of the debug register.
- @param Data The data to write.
-
-**/
-VOID
-XhcWriteDebugReg (
- IN USB3_DEBUG_PORT_HANDLE *Handle,
- IN UINT32 Offset,
- IN UINT32 Data
- )
-{
- EFI_PHYSICAL_ADDRESS DebugCapabilityBase;
-
- DebugCapabilityBase = Handle->DebugCapabilityBase;
- MmioWrite32 ((UINTN)(DebugCapabilityBase + Offset), Data);
-
- return;
-}
-
-/**
- Read XHCI debug register.
-
- @param Handle Debug port handle.
- @param Offset The offset of the runtime register.
-
- @return The register content read
-
-**/
-UINT32
-XhcReadDebugReg (
- IN USB3_DEBUG_PORT_HANDLE *Handle,
- IN UINT32 Offset
- )
-{
- UINT32 Data;
- EFI_PHYSICAL_ADDRESS DebugCapabilityBase;
-
- DebugCapabilityBase = Handle->DebugCapabilityBase;
- Data = MmioRead32 ((UINTN)(DebugCapabilityBase + Offset));
-
- return Data;
-}
-
-/**
- Set one bit of the debug register while keeping other bits.
-
- @param Handle Debug port handle.
- @param Offset The offset of the debug register.
- @param Bit The bit mask of the register to set.
-
-**/
-VOID
-XhcSetDebugRegBit (
- IN USB3_DEBUG_PORT_HANDLE *Handle,
- IN UINT32 Offset,
- IN UINT32 Bit
- )
-{
- UINT32 Data;
-
- Data = XhcReadDebugReg (Handle, Offset);
- Data |= Bit;
- XhcWriteDebugReg (Handle, Offset, Data);
-}
-
-/**
- Clear one bit of the debug register while keeping other bits.
-
- @param Handle Debug port handle.
- @param Offset The offset of the debug register.
- @param Bit The bit mask of the register to clear.
-
-**/
-VOID
-XhcClearDebugRegBit (
- IN USB3_DEBUG_PORT_HANDLE *Handle,
- IN UINT32 Offset,
- IN UINT32 Bit
- )
-{
- UINT32 Data;
-
- Data = XhcReadDebugReg (Handle, Offset);
- Data &= ~Bit;
- XhcWriteDebugReg (Handle, Offset, Data);
-}
-
-/**
- Program and enable XHCI MMIO base address.
-
- @return XHCI MMIO base address.
-
-**/
-EFI_PHYSICAL_ADDRESS
-ProgramXhciBaseAddress (
- VOID
- )
-{
- UINT16 PciCmd;
- UINT32 Low;
- UINT32 High;
- EFI_PHYSICAL_ADDRESS XhciMmioBase;
-
- Low = PciRead32 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET);
- High = PciRead32 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET + 4);
- XhciMmioBase = (EFI_PHYSICAL_ADDRESS)(LShiftU64 ((UINT64)High, 32) | Low);
- XhciMmioBase &= XHCI_BASE_ADDRESS_64_BIT_MASK;
-
- if ((XhciMmioBase == 0) || (XhciMmioBase == XHCI_BASE_ADDRESS_64_BIT_MASK)) {
- XhciMmioBase = PcdGet64 (PcdUsbXhciMemorySpaceBase);
- PciWrite32 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET, XhciMmioBase & 0xFFFFFFFF);
- PciWrite32 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET + 4, (RShiftU64 (XhciMmioBase, 32) & 0xFFFFFFFF));
- }
-
- PciCmd = PciRead16 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_COMMAND_OFFSET);
- if (((PciCmd & EFI_PCI_COMMAND_MEMORY_SPACE) == 0) || ((PciCmd & EFI_PCI_COMMAND_BUS_MASTER) == 0)) {
- PciCmd |= EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_BUS_MASTER;
- PciWrite16 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_COMMAND_OFFSET, PciCmd);
- }
-
- return XhciMmioBase;
-}
-
-/**
- Update XHC MMIO base address when MMIO base address is changed.
-
- @param Handle Debug port handle.
- @param XhciMmioBase XHCI MMIO base address.
-
-**/
-VOID
-UpdateXhcResource (
- IN OUT USB3_DEBUG_PORT_HANDLE *Handle,
- IN EFI_PHYSICAL_ADDRESS XhciMmioBase
- )
-{
- if (Handle == NULL) {
- return;
- }
-
- //
- // Need fix Handle data according to new XHCI MMIO base address.
- //
- Handle->XhciMmioBase = XhciMmioBase;
- Handle->DebugCapabilityBase = XhciMmioBase + Handle->DebugCapabilityOffset;
- Handle->XhciOpRegister = XhciMmioBase + MmioRead8 ((UINTN)XhciMmioBase);
-}
-
-/**
- Calculate the usb debug port bar address.
-
- @param Handle Debug port handle.
-
- @retval RETURN_UNSUPPORTED The usb host controller does not support usb debug port capability.
- @retval RETURN_SUCCESS Get bar and offset successfully.
-
-**/
-RETURN_STATUS
-EFIAPI
-CalculateUsbDebugPortMmioBase (
- USB3_DEBUG_PORT_HANDLE *Handle
- )
-{
- UINT16 VendorId;
- UINT16 DeviceId;
- UINT8 ProgInterface;
- UINT8 SubClassCode;
- UINT8 BaseCode;
- BOOLEAN Flag;
- UINT32 Capability;
- EFI_PHYSICAL_ADDRESS CapabilityPointer;
- UINT8 CapLength;
-
- if (Handle->Initialized != USB3DBG_UNINITIALIZED) {
- if (Handle->Initialized == USB3DBG_NO_DBG_CAB) {
- return RETURN_UNSUPPORTED;
- } else {
- return RETURN_SUCCESS;
- }
- }
-
- VendorId = PciRead16 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_VENDOR_ID_OFFSET);
- DeviceId = PciRead16 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_DEVICE_ID_OFFSET);
-
- if ((VendorId == 0xFFFF) || (DeviceId == 0xFFFF)) {
- goto Done;
- }
-
- ProgInterface = PciRead8 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_CLASSCODE_OFFSET);
- SubClassCode = PciRead8 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_CLASSCODE_OFFSET + 1);
- BaseCode = PciRead8 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_CLASSCODE_OFFSET + 2);
-
- if ((ProgInterface != PCI_IF_XHCI) || (SubClassCode != PCI_CLASS_SERIAL_USB) || (BaseCode != PCI_CLASS_SERIAL)) {
- goto Done;
- }
-
- CapLength = MmioRead8 ((UINTN)Handle->XhciMmioBase);
-
- //
- // Get capability pointer from HCCPARAMS at offset 0x10
- //
- CapabilityPointer = Handle->XhciMmioBase + (MmioRead32 ((UINTN)(Handle->XhciMmioBase + XHC_HCCPARAMS_OFFSET)) >> 16) * 4;
-
- //
- // Search XHCI debug capability
- //
- Flag = FALSE;
- Capability = MmioRead32 ((UINTN)CapabilityPointer);
- while (TRUE) {
- if ((Capability & XHC_CAPABILITY_ID_MASK) == PCI_CAPABILITY_ID_DEBUG_PORT) {
- Flag = TRUE;
- break;
- }
-
- if ((((Capability & XHC_NEXT_CAPABILITY_MASK) >> 8) & XHC_CAPABILITY_ID_MASK) == 0) {
- //
- // Reach the end of capability list, quit
- //
- break;
- }
-
- CapabilityPointer += ((Capability & XHC_NEXT_CAPABILITY_MASK) >> 8) * 4;
- Capability = MmioRead32 ((UINTN)CapabilityPointer);
- }
-
- if (!Flag) {
- goto Done;
- }
-
- //
- // USB3 debug capability is supported.
- //
- Handle->DebugCapabilityBase = CapabilityPointer;
- Handle->DebugCapabilityOffset = CapabilityPointer - Handle->XhciMmioBase;
- Handle->XhciOpRegister = Handle->XhciMmioBase + CapLength;
- Handle->DebugSupport = TRUE;
- Handle->Initialized = USB3DBG_DBG_CAB;
- return RETURN_SUCCESS;
-
-Done:
- Handle->Initialized = USB3DBG_NO_DBG_CAB;
- return RETURN_UNSUPPORTED;
-}
-
-/**
- Check if it needs to re-initialize usb debug port hardware.
-
- During different phases switch, such as SEC to PEI or PEI to DXE or DXE to SMM, we should check
- whether the usb debug port hardware configuration is changed. Such case can be triggered by
- Pci bus resource allocation and so on.
-
- @param Handle Debug port handle.
-
- @retval TRUE The usb debug port hardware configuration is changed.
- @retval FALSE The usb debug port hardware configuration is not changed.
-
-**/
-BOOLEAN
-EFIAPI
-NeedReinitializeHardware (
- IN USB3_DEBUG_PORT_HANDLE *Handle
- )
-{
- BOOLEAN Result;
- volatile UINT32 Dcctrl;
-
- Result = FALSE;
-
- //
- // If DCE bit, it means USB3 debug is not enabled.
- //
- Dcctrl = XhcReadDebugReg (Handle, XHC_DC_DCCTRL);
- if ((Dcctrl & BIT0) == 0) {
- Result = TRUE;
- } else if (!Handle->Ready) {
- Handle->Ready = TRUE;
- Handle->Initialized = USB3DBG_ENABLED;
- }
-
- return Result;
-}
-
-/**
- Create XHCI event ring.
-
- @param Handle Debug port handle.
- @param EventRing The created event ring.
-
-**/
-EFI_STATUS
-CreateEventRing (
- IN USB3_DEBUG_PORT_HANDLE *Handle,
- OUT EVENT_RING *EventRing
- )
-{
- VOID *Buf;
- EVENT_RING_SEG_TABLE_ENTRY *ERSTBase;
-
- ASSERT (EventRing != NULL);
-
- //
- // Allocate Event Ring
- //
- Buf = AllocateAlignBuffer (sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER);
- ASSERT (Buf != NULL);
- ASSERT (((UINTN)Buf & 0x3F) == 0);
- ZeroMem (Buf, sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER);
-
- EventRing->EventRingSeg0 = (EFI_PHYSICAL_ADDRESS)(UINTN)Buf;
- EventRing->TrbNumber = EVENT_RING_TRB_NUMBER;
- EventRing->EventRingDequeue = (EFI_PHYSICAL_ADDRESS)(UINTN)EventRing->EventRingSeg0;
- EventRing->EventRingEnqueue = (EFI_PHYSICAL_ADDRESS)(UINTN)EventRing->EventRingSeg0;
-
- //
- // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'
- // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.
- //
- EventRing->EventRingCCS = 1;
-
- //
- // Allocate Event Ring Segment Table Entry 0 in Event Ring Segment Table
- //
- Buf = AllocateAlignBuffer (sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);
- ASSERT (Buf != NULL);
- ASSERT (((UINTN)Buf & 0x3F) == 0);
- ZeroMem (Buf, sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);
-
- ERSTBase = (EVENT_RING_SEG_TABLE_ENTRY *)Buf;
- EventRing->ERSTBase = (EFI_PHYSICAL_ADDRESS)(UINTN)ERSTBase;
-
- //
- // Fill Event Segment address
- //
- ERSTBase->PtrLo = XHC_LOW_32BIT (EventRing->EventRingSeg0);
- ERSTBase->PtrHi = XHC_HIGH_32BIT (EventRing->EventRingSeg0);
- ERSTBase->RingTrbSize = EVENT_RING_TRB_NUMBER;
-
- //
- // Program the Interrupter Event Ring Dequeue Pointer (DCERDP) register (7.6.4.1)
- //
- XhcWriteDebugReg (
- Handle,
- XHC_DC_DCERDP,
- XHC_LOW_32BIT ((UINT64)(UINTN)EventRing->EventRingDequeue)
- );
-
- XhcWriteDebugReg (
- Handle,
- XHC_DC_DCERDP + 4,
- XHC_HIGH_32BIT ((UINT64)(UINTN)EventRing->EventRingDequeue)
- );
-
- //
- // Program the Debug Capability Event Ring Segment Table Base Address (DCERSTBA) register(7.6.4.1)
- //
- XhcWriteDebugReg (
- Handle,
- XHC_DC_DCERSTBA,
- XHC_LOW_32BIT ((UINT64)(UINTN)ERSTBase)
- );
-
- XhcWriteDebugReg (
- Handle,
- XHC_DC_DCERSTBA + 4,
- XHC_HIGH_32BIT ((UINT64)(UINTN)ERSTBase)
- );
-
- //
- // Program the Debug Capability Event Ring Segment Table Size (DCERSTSZ) register(7.6.4.1)
- //
- XhcWriteDebugReg (
- Handle,
- XHC_DC_DCERSTSZ,
- ERST_NUMBER
- );
- return EFI_SUCCESS;
-}
-
-/**
- Create XHCI transfer ring.
-
- @param Handle Debug port handle.
- @param TrbNum The number of TRB in the ring.
- @param TransferRing The created transfer ring.
-
-**/
-VOID
-CreateTransferRing (
- IN USB3_DEBUG_PORT_HANDLE *Handle,
- IN UINT32 TrbNum,
- OUT TRANSFER_RING *TransferRing
- )
-{
- VOID *Buf;
- LINK_TRB *EndTrb;
-
- Buf = AllocateAlignBuffer (sizeof (TRB_TEMPLATE) * TrbNum);
- ASSERT (Buf != NULL);
- ASSERT (((UINTN)Buf & 0xF) == 0);
- ZeroMem (Buf, sizeof (TRB_TEMPLATE) * TrbNum);
-
- TransferRing->RingSeg0 = (EFI_PHYSICAL_ADDRESS)(UINTN)Buf;
- TransferRing->TrbNumber = TrbNum;
- TransferRing->RingEnqueue = TransferRing->RingSeg0;
- TransferRing->RingDequeue = TransferRing->RingSeg0;
- TransferRing->RingPCS = 1;
- //
- // 4.9.2 Transfer Ring Management
- // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to
- // point to the first TRB in the ring.
- //
- EndTrb = (LINK_TRB *)((UINTN)Buf + sizeof (TRB_TEMPLATE) * (TrbNum - 1));
- EndTrb->Type = TRB_TYPE_LINK;
- EndTrb->PtrLo = XHC_LOW_32BIT (Buf);
- EndTrb->PtrHi = XHC_HIGH_32BIT (Buf);
- //
- // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.
- //
- EndTrb->TC = 1;
- //
- // Set Cycle bit as other TRB PCS init value
- //
- EndTrb->CycleBit = 0;
-}
-
-/**
- Create debug capability context for XHC debug device.
-
- @param Handle Debug port handle.
-
- @retval EFI_SUCCESS The bit successfully changed by host controller.
- @retval EFI_TIMEOUT The time out occurred.
-
-**/
-EFI_STATUS
-CreateDebugCapabilityContext (
- IN USB3_DEBUG_PORT_HANDLE *Handle
- )
-{
- VOID *Buf;
- XHC_DC_CONTEXT *DebugCapabilityContext;
- UINT8 *String0Desc;
- UINT8 *ManufacturerStrDesc;
- UINT8 *ProductStrDesc;
- UINT8 *SerialNumberStrDesc;
-
- //
- // Allocate debug device context
- //
- Buf = AllocateAlignBuffer (sizeof (XHC_DC_CONTEXT));
- ASSERT (Buf != NULL);
- ASSERT (((UINTN)Buf & 0xF) == 0);
- ZeroMem (Buf, sizeof (XHC_DC_CONTEXT));
-
- DebugCapabilityContext = (XHC_DC_CONTEXT *)(UINTN)Buf;
- Handle->DebugCapabilityContext = (EFI_PHYSICAL_ADDRESS)(UINTN)DebugCapabilityContext;
-
- //
- // Initialize DbcInfoContext.
- //
- DebugCapabilityContext->DbcInfoContext.String0Length = STRING0_DESC_LEN;
- DebugCapabilityContext->DbcInfoContext.ManufacturerStrLength = MANU_DESC_LEN;
- DebugCapabilityContext->DbcInfoContext.ProductStrLength = PRODUCT_DESC_LEN;
- DebugCapabilityContext->DbcInfoContext.SerialNumberStrLength = SERIAL_DESC_LEN;
-
- //
- // Initialize EpOutContext.
- //
- DebugCapabilityContext->EpOutContext.CErr = 0x3;
- DebugCapabilityContext->EpOutContext.EPType = ED_BULK_OUT;
- DebugCapabilityContext->EpOutContext.MaxPacketSize = XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE;
- DebugCapabilityContext->EpOutContext.AverageTRBLength = 0x1000;
-
- //
- // Initialize EpInContext.
- //
- DebugCapabilityContext->EpInContext.CErr = 0x3;
- DebugCapabilityContext->EpInContext.EPType = ED_BULK_IN;
- DebugCapabilityContext->EpInContext.MaxPacketSize = XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE;
- DebugCapabilityContext->EpInContext.AverageTRBLength = 0x1000;
-
- //
- // Update string descriptor address
- //
- String0Desc = (UINT8 *)AllocateAlignBuffer (STRING0_DESC_LEN + MANU_DESC_LEN + PRODUCT_DESC_LEN + SERIAL_DESC_LEN);
- ASSERT (String0Desc != NULL);
- ZeroMem (String0Desc, STRING0_DESC_LEN + MANU_DESC_LEN + PRODUCT_DESC_LEN + SERIAL_DESC_LEN);
- CopyMem (String0Desc, mString0Desc, STRING0_DESC_LEN);
- DebugCapabilityContext->DbcInfoContext.String0DescAddress = (UINT64)(UINTN)String0Desc;
-
- ManufacturerStrDesc = String0Desc + STRING0_DESC_LEN;
- CopyMem (ManufacturerStrDesc, mManufacturerStrDesc, MANU_DESC_LEN);
- DebugCapabilityContext->DbcInfoContext.ManufacturerStrDescAddress = (UINT64)(UINTN)ManufacturerStrDesc;
-
- ProductStrDesc = ManufacturerStrDesc + MANU_DESC_LEN;
- CopyMem (ProductStrDesc, mProductStrDesc, PRODUCT_DESC_LEN);
- DebugCapabilityContext->DbcInfoContext.ProductStrDescAddress = (UINT64)(UINTN)ProductStrDesc;
-
- SerialNumberStrDesc = ProductStrDesc + PRODUCT_DESC_LEN;
- CopyMem (SerialNumberStrDesc, mSerialNumberStrDesc, SERIAL_DESC_LEN);
- DebugCapabilityContext->DbcInfoContext.SerialNumberStrDescAddress = (UINT64)(UINTN)SerialNumberStrDesc;
-
- //
- // Allocate and initialize the Transfer Ring for the Input Endpoint Context.
- //
- ZeroMem (&Handle->TransferRingIn, sizeof (TRANSFER_RING));
- CreateTransferRing (Handle, TR_RING_TRB_NUMBER, &Handle->TransferRingIn);
- DebugCapabilityContext->EpInContext.PtrLo = XHC_LOW_32BIT (Handle->TransferRingIn.RingSeg0) | BIT0;
- DebugCapabilityContext->EpInContext.PtrHi = XHC_HIGH_32BIT (Handle->TransferRingIn.RingSeg0);
-
- //
- // Allocate and initialize the Transfer Ring for the Output Endpoint Context.
- //
- ZeroMem (&Handle->TransferRingOut, sizeof (TRANSFER_RING));
- CreateTransferRing (Handle, TR_RING_TRB_NUMBER, &Handle->TransferRingOut);
- DebugCapabilityContext->EpOutContext.PtrLo = XHC_LOW_32BIT (Handle->TransferRingOut.RingSeg0) | BIT0;
- DebugCapabilityContext->EpOutContext.PtrHi = XHC_HIGH_32BIT (Handle->TransferRingOut.RingSeg0);
-
- //
- // Program the Debug Capability Context Pointer (DCCP) register(7.6.8.7)
- //
- XhcWriteDebugReg (
- Handle,
- XHC_DC_DCCP,
- XHC_LOW_32BIT ((UINT64)(UINTN)DebugCapabilityContext)
- );
- XhcWriteDebugReg (
- Handle,
- XHC_DC_DCCP + 4,
- XHC_HIGH_32BIT ((UINT64)(UINTN)DebugCapabilityContext)
- );
- return EFI_SUCCESS;
-}
-
-/**
- Check if debug device is running.
-
- @param Handle Debug port handle.
-
-**/
-VOID
-XhcDetectDebugCapabilityReady (
- IN USB3_DEBUG_PORT_HANDLE *Handle
- )
-{
- UINT64 TimeOut;
- volatile UINT32 Dcctrl;
-
- TimeOut = 1;
- if (Handle->Initialized == USB3DBG_DBG_CAB) {
- //
- // As detection is slow in seconds, wait for longer timeout for the first time.
- // If first initialization is failed, we will try to enable debug device in the
- // Poll function invoked by timer.
- //
- TimeOut = DivU64x32 (PcdGet64 (PcdUsbXhciDebugDetectTimeout), XHC_POLL_DELAY) + 1;
- }
-
- do {
- //
- // Check if debug device is in configured state
- //
- Dcctrl = XhcReadDebugReg (Handle, XHC_DC_DCCTRL);
- if ((Dcctrl & BIT0) != 0) {
- //
- // Set the flag to indicate debug device is in configured state
- //
- Handle->Ready = TRUE;
- break;
- }
-
- MicroSecondDelay (XHC_POLL_DELAY);
- TimeOut--;
- } while (TimeOut != 0);
-}
-
-/**
- Initialize usb debug port hardware.
-
- @param Handle Debug port handle.
-
- @retval TRUE The usb debug port hardware configuration is changed.
- @retval FALSE The usb debug port hardware configuration is not changed.
-
-**/
-RETURN_STATUS
-EFIAPI
-InitializeUsbDebugHardware (
- IN USB3_DEBUG_PORT_HANDLE *Handle
- )
-{
- RETURN_STATUS Status;
- UINT8 *Buffer;
- UINTN Index;
- UINT8 TotalUsb3Port;
- EFI_PHYSICAL_ADDRESS XhciOpRegister;
- UINT32 Dcddi1;
-
- XhciOpRegister = Handle->XhciOpRegister;
- TotalUsb3Port = MmioRead32 (((UINTN)Handle->XhciMmioBase + XHC_HCSPARAMS1_OFFSET)) >> 24;
-
- if (Handle->Initialized == USB3DBG_NOT_ENABLED) {
- Dcddi1 = XhcReadDebugReg (Handle, XHC_DC_DCDDI1);
- if (Dcddi1 != (UINT32)((XHCI_DEBUG_DEVICE_VENDOR_ID << 16) | XHCI_DEBUG_DEVICE_PROTOCOL)) {
- //
- // The debug capability has been reset by other code, return device error.
- //
- return EFI_DEVICE_ERROR;
- }
-
- //
- // If XHCI supports debug capability, hardware resource has been allocated,
- // but it has not been enabled, try to enable again.
- //
- goto Enable;
- }
-
- //
- // Initialize for PEI phase when AllocatePages can work.
- // Allocate data buffer with max packet size for data read and data poll.
- // Allocate data buffer for data write.
- //
- Buffer = AllocateAlignBuffer (XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE * 2 + USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE);
- if (Buffer == NULL) {
- //
- // AllocatePages can not still work now, return fail and do not initialize now.
- //
- return RETURN_NOT_READY;
- }
-
- //
- // Reset port to get debug device discovered
- //
- for (Index = 0; Index < TotalUsb3Port; Index++) {
- XhcSetR32Bit ((UINTN)XhciOpRegister + XHC_PORTSC_OFFSET + Index * 0x10, BIT4);
- MicroSecondDelay (10 * 1000);
- }
-
- //
- // Clear DCE bit and LSE bit in DCCTRL
- //
- if ((XhcReadDebugReg (Handle, XHC_DC_DCCTRL) & (BIT1|BIT31)) == (BIT1|BIT31)) {
- XhcClearDebugRegBit (Handle, XHC_DC_DCCTRL, BIT1|BIT31);
- }
-
- //
- // Construct the buffer for read, poll and write.
- //
- Handle->UrbIn.Data = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer;
- Handle->Data = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer + XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE;
- Handle->UrbOut.Data = Handle->UrbIn.Data + XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE * 2;
-
- //
- // Initialize event ring
- //
- ZeroMem (&Handle->EventRing, sizeof (EVENT_RING));
- Status = CreateEventRing (Handle, &Handle->EventRing);
- ASSERT_EFI_ERROR (Status);
-
- //
- // Init IN and OUT endpoint context
- //
- Status = CreateDebugCapabilityContext (Handle);
- ASSERT_EFI_ERROR (Status);
-
- //
- // Init DCDDI1 and DCDDI2
- //
- XhcWriteDebugReg (
- Handle,
- XHC_DC_DCDDI1,
- (UINT32)((XHCI_DEBUG_DEVICE_VENDOR_ID << 16) | XHCI_DEBUG_DEVICE_PROTOCOL)
- );
-
- XhcWriteDebugReg (
- Handle,
- XHC_DC_DCDDI2,
- (UINT32)((XHCI_DEBUG_DEVICE_REVISION << 16) | XHCI_DEBUG_DEVICE_PRODUCT_ID)
- );
-
-Enable:
- if ((Handle->Initialized == USB3DBG_NOT_ENABLED) && (!Handle->ChangePortPower)) {
- //
- // If the first time detection is failed, turn port power off and on in order to
- // reset port status this time, then try to check if debug device is ready again.
- //
- for (Index = 0; Index < TotalUsb3Port; Index++) {
- XhcClearR32Bit ((UINTN)XhciOpRegister + XHC_PORTSC_OFFSET + Index * 0x10, BIT9);
- MicroSecondDelay (XHC_DEBUG_PORT_ON_OFF_DELAY);
- XhcSetR32Bit ((UINTN)XhciOpRegister + XHC_PORTSC_OFFSET + Index * 0x10, BIT9);
- MicroSecondDelay (XHC_DEBUG_PORT_ON_OFF_DELAY);
- Handle->ChangePortPower = TRUE;
- }
- }
-
- //
- // Set DCE bit and LSE bit to "1" in DCCTRL in first initialization
- //
- XhcSetDebugRegBit (Handle, XHC_DC_DCCTRL, BIT1|BIT31);
-
- XhcDetectDebugCapabilityReady (Handle);
-
- Status = RETURN_SUCCESS;
- if (!Handle->Ready) {
- Handle->Initialized = USB3DBG_NOT_ENABLED;
- Status = RETURN_NOT_READY;
- } else {
- Handle->Initialized = USB3DBG_ENABLED;
- }
-
- return Status;
-}
-
-/**
- Discover and initialize usb debug port.
-
- @param Handle Debug port handle.
-
-**/
-VOID
-DiscoverInitializeUsbDebugPort (
- IN USB3_DEBUG_PORT_HANDLE *Handle
- )
-{
- EFI_STATUS Status;
- EFI_PHYSICAL_ADDRESS XhciMmioBase;
-
- //
- // Read 64-bit MMIO base address
- //
- XhciMmioBase = ProgramXhciBaseAddress ();
- Handle->XhciMmioBase = XhciMmioBase;
-
- Status = CalculateUsbDebugPortMmioBase (Handle);
- if (!RETURN_ERROR (Status)) {
- UpdateXhcResource (Handle, XhciMmioBase);
- if (NeedReinitializeHardware (Handle)) {
- InitializeUsbDebugHardware (Handle);
- }
- }
-}
-
-/**
- Set USB3 debug instance address.
-
- @param[in] Instance Debug port instance.
-
-**/
-VOID
-SetUsb3DebugPortInstance (
- IN USB3_DEBUG_PORT_HANDLE *Instance
- )
-{
- EFI_PHYSICAL_ADDRESS *AddrPtr;
-
- AddrPtr = GetUsb3DebugPortInstanceAddrPtr ();
- ASSERT (AddrPtr != NULL);
- *AddrPtr = (EFI_PHYSICAL_ADDRESS)(UINTN)Instance;
-}
-
-/**
- Return USB3 debug instance address.
-
-**/
-USB3_DEBUG_PORT_HANDLE *
-GetUsb3DebugPortInstance (
- VOID
- )
-{
- EFI_PHYSICAL_ADDRESS *AddrPtr;
- USB3_DEBUG_PORT_HANDLE *Instance;
-
- AddrPtr = GetUsb3DebugPortInstanceAddrPtr ();
- ASSERT (AddrPtr != NULL);
-
- Instance = (USB3_DEBUG_PORT_HANDLE *)(UINTN)*AddrPtr;
-
- return Instance;
-}
-
-/**
- Read data from debug device and save the data in buffer.
-
- Reads NumberOfBytes data bytes from a debug device into the buffer
- specified by Buffer. The number of bytes actually read is returned.
- If the return value is less than NumberOfBytes, then the rest operation failed.
- If NumberOfBytes is zero, then return 0.
-
- @param Handle Debug port handle.
- @param Buffer Pointer to the data buffer to store the data read from the debug device.
- @param NumberOfBytes Number of bytes which will be read.
- @param Timeout Timeout value for reading from debug device. Its unit is Microsecond.
-
- @retval 0 Read data failed, no data is to be read.
- @retval >0 Actual number of bytes read from debug device.
-
-**/
-UINTN
-EFIAPI
-DebugPortReadBuffer (
- IN DEBUG_PORT_HANDLE Handle,
- IN UINT8 *Buffer,
- IN UINTN NumberOfBytes,
- IN UINTN Timeout
- )
-{
- USB3_DEBUG_PORT_HANDLE *UsbDebugPortHandle;
- UINT8 Index;
- UINT8 *Data;
-
- if ((NumberOfBytes != 1) || (Buffer == NULL) || (Timeout != 0)) {
- return 0;
- }
-
- //
- // If Handle is NULL, get own instance.
- // If Handle is not NULL, use it and set the instance.
- //
- if (Handle != NULL) {
- UsbDebugPortHandle = (USB3_DEBUG_PORT_HANDLE *)Handle;
- SetUsb3DebugPortInstance (UsbDebugPortHandle);
- } else {
- UsbDebugPortHandle = GetUsb3DebugPortInstance ();
- }
-
- if (UsbDebugPortHandle == NULL) {
- return 0;
- }
-
- if (UsbDebugPortHandle->InNotify) {
- return 0;
- }
-
- DiscoverInitializeUsbDebugPort (UsbDebugPortHandle);
-
- if (UsbDebugPortHandle->Initialized != USB3DBG_ENABLED) {
- return 0;
- }
-
- Data = (UINT8 *)(UINTN)UsbDebugPortHandle->Data;
-
- //
- // Read data from buffer
- //
- if (UsbDebugPortHandle->DataCount < 1) {
- return 0;
- } else {
- *Buffer = Data[0];
-
- for (Index = 0; Index < UsbDebugPortHandle->DataCount - 1; Index++) {
- if ((Index + 1) >= XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE) {
- return 0;
- }
-
- Data[Index] = Data[Index + 1];
- }
-
- UsbDebugPortHandle->DataCount = (UINT8)(UsbDebugPortHandle->DataCount - 1);
- return 1;
- }
-}
-
-/**
- Write data from buffer to debug device.
-
- Writes NumberOfBytes data bytes from Buffer to the debug device.
- The number of bytes actually written to the debug device is returned.
- If the return value is less than NumberOfBytes, then the write operation failed.
- If NumberOfBytes is zero, then return 0.
-
- @param Handle Debug port handle.
- @param Buffer Pointer to the data buffer to be written.
- @param NumberOfBytes Number of bytes to written to the debug device.
-
- @retval 0 NumberOfBytes is 0.
- @retval >0 The number of bytes written to the debug device.
- If this value is less than NumberOfBytes, then the write operation failed.
-
-**/
-UINTN
-EFIAPI
-DebugPortWriteBuffer (
- IN DEBUG_PORT_HANDLE Handle,
- IN UINT8 *Buffer,
- IN UINTN NumberOfBytes
- )
-{
- USB3_DEBUG_PORT_HANDLE *UsbDebugPortHandle;
- UINTN Sent;
- UINTN Total;
-
- if ((NumberOfBytes == 0) || (Buffer == NULL)) {
- return 0;
- }
-
- Sent = 0;
- Total = 0;
-
- //
- // If Handle is NULL, get own instance.
- // If Handle is not NULL, use it and set the instance.
- //
- if (Handle != NULL) {
- UsbDebugPortHandle = (USB3_DEBUG_PORT_HANDLE *)Handle;
- SetUsb3DebugPortInstance (UsbDebugPortHandle);
- } else {
- UsbDebugPortHandle = GetUsb3DebugPortInstance ();
- }
-
- if (UsbDebugPortHandle == NULL) {
- return 0;
- }
-
- if (UsbDebugPortHandle->InNotify) {
- return 0;
- }
-
- DiscoverInitializeUsbDebugPort (UsbDebugPortHandle);
-
- if (UsbDebugPortHandle->Initialized != USB3DBG_ENABLED) {
- return 0;
- }
-
- //
- // When host is trying to send data, write will be blocked.
- // Poll to see if there is any data sent by host at first.
- //
- DebugPortPollBuffer (UsbDebugPortHandle);
-
- while ((Total < NumberOfBytes)) {
- if (NumberOfBytes - Total > USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE) {
- Sent = USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE;
- } else {
- Sent = (UINT8)(NumberOfBytes - Total);
- }
-
- XhcDataTransfer (UsbDebugPortHandle, EfiUsbDataOut, Buffer + Total, &Sent, DATA_TRANSFER_WRITE_TIMEOUT);
- Total += Sent;
- }
-
- return Total;
-}
-
-/**
- Polls a debug device to see if there is any data waiting to be read.
-
- Polls a debug device to see if there is any data waiting to be read.
- If there is data waiting to be read from the debug device, then TRUE is returned.
- If there is no data waiting to be read from the debug device, then FALSE is returned.
-
- @param Handle Debug port handle.
-
- @retval TRUE Data is waiting to be read from the debug device.
- @retval FALSE There is no data waiting to be read from the debug device.
-
-**/
-BOOLEAN
-EFIAPI
-DebugPortPollBuffer (
- IN DEBUG_PORT_HANDLE Handle
- )
-{
- USB3_DEBUG_PORT_HANDLE *UsbDebugPortHandle;
- UINTN Length;
-
- //
- // If Handle is NULL, get own instance.
- // If Handle is not NULL, use it and set the instance.
- //
- if (Handle != NULL) {
- UsbDebugPortHandle = (USB3_DEBUG_PORT_HANDLE *)Handle;
- SetUsb3DebugPortInstance (UsbDebugPortHandle);
- } else {
- UsbDebugPortHandle = GetUsb3DebugPortInstance ();
- }
-
- if (UsbDebugPortHandle == NULL) {
- return FALSE;
- }
-
- if (UsbDebugPortHandle->InNotify) {
- return FALSE;
- }
-
- DiscoverInitializeUsbDebugPort (UsbDebugPortHandle);
-
- if (UsbDebugPortHandle->Initialized != USB3DBG_ENABLED) {
- return FALSE;
- }
-
- //
- // If the data buffer is not empty, then return TRUE directly.
- // Otherwise initialize a usb read transaction and read data to internal data buffer.
- //
- if (UsbDebugPortHandle->DataCount != 0) {
- return TRUE;
- }
-
- //
- // Read data as much as we can
- //
- Length = XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE;
- XhcDataTransfer (UsbDebugPortHandle, EfiUsbDataIn, (VOID *)(UINTN)UsbDebugPortHandle->Data, &Length, DATA_TRANSFER_POLL_TIMEOUT);
-
- if (Length > XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE) {
- return FALSE;
- }
-
- if (Length == 0) {
- return FALSE;
- }
-
- //
- // Store data into internal buffer for use later
- //
- UsbDebugPortHandle->DataCount = (UINT8)Length;
- return TRUE;
-}
-
-/**
- Initialize the debug port.
-
- If Function is not NULL, Debug Communication Library will call this function
- by passing in the Context to be the first parameter. If needed, Debug Communication
- Library will create one debug port handle to be the second argument passing in
- calling the Function, otherwise it will pass NULL to be the second argument of
- Function.
-
- If Function is NULL, and Context is not NULL, the Debug Communication Library could
- a) Return the same handle as passed in (as Context parameter).
- b) Ignore the input Context parameter and create new handle to be returned.
-
- If parameter Function is NULL and Context is NULL, Debug Communication Library could
- created a new handle if needed and return it, otherwise it will return NULL.
-
- @param[in] Context Context needed by callback function; it was optional.
- @param[in] Function Continue function called by Debug Communication library;
- it was optional.
-
- @return The debug port handle created by Debug Communication Library if Function
- is not NULL.
-
-**/
-DEBUG_PORT_HANDLE
-EFIAPI
-DebugPortInitialize (
- IN VOID *Context,
- IN DEBUG_PORT_CONTINUE Function
- )
-{
- USB3_DEBUG_PORT_HANDLE *UsbDebugPortHandle;
-
- //
- // Validate the PCD PcdDebugPortHandleBufferSize value
- //
- ASSERT (PcdGet16 (PcdDebugPortHandleBufferSize) == sizeof (USB3_DEBUG_PORT_HANDLE));
-
- if ((Function == NULL) && (Context != NULL)) {
- SetUsb3DebugPortInstance ((USB3_DEBUG_PORT_HANDLE *)Context);
- return (DEBUG_PORT_HANDLE)Context;
- }
-
- UsbDebugPortHandle = GetUsb3DebugPortInstance ();
- if (UsbDebugPortHandle == NULL) {
- return NULL;
- }
-
- DiscoverInitializeUsbDebugPort (UsbDebugPortHandle);
-
- if (Function != NULL) {
- Function (Context, (DEBUG_PORT_HANDLE)UsbDebugPortHandle);
- }
-
- return (DEBUG_PORT_HANDLE)UsbDebugPortHandle;
-}
+/** @file + Debug Port Library implementation based on usb3 debug port. + + Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "DebugCommunicationLibUsb3Internal.h" + +UINT16 mString0Desc[] = { + // String Descriptor Type + Length + (USB_DESC_TYPE_STRING << 8) + STRING0_DESC_LEN, + 0x0409 +}; + +UINT16 mManufacturerStrDesc[] = { + // String Descriptor Type + Length + (USB_DESC_TYPE_STRING << 8) + MANU_DESC_LEN, + 'I', 'n','t', 'e', 'l' +}; + +UINT16 mProductStrDesc[] = { + // String Descriptor Type + Length + (USB_DESC_TYPE_STRING << 8) + PRODUCT_DESC_LEN, + 'U', 'S','B', ' ', '3', '.', '0', ' ', 'D', 'e', 'b', 'u', 'g', ' ', 'C', 'a', 'b', 'l', 'e' +}; + +UINT16 mSerialNumberStrDesc[] = { + // String Descriptor Type + Length + (USB_DESC_TYPE_STRING << 8) + SERIAL_DESC_LEN, + '1' +}; + +/** + Sets bits as per the enabled bit positions in the mask. + + @param[in, out] Register UINTN register + @param[in] BitMask 32-bit mask +**/ +VOID +XhcSetR32Bit ( + IN OUT UINTN Register, + IN UINT32 BitMask + ) +{ + UINT32 RegisterValue; + + RegisterValue = MmioRead32 (Register); + RegisterValue |= (UINT32)(BitMask); + MmioWrite32 (Register, RegisterValue); +} + +/** + Clears bits as per the enabled bit positions in the mask. + + @param[in, out] Register UINTN register + @param[in] BitMask 32-bit mask +**/ +VOID +XhcClearR32Bit ( + IN OUT UINTN Register, + IN UINT32 BitMask + ) +{ + UINT32 RegisterValue; + + RegisterValue = MmioRead32 (Register); + RegisterValue &= ~BitMask; + MmioWrite32 (Register, RegisterValue); +} + +/** + Write the data to the XHCI debug register. + + @param Handle Debug port handle. + @param Offset The offset of the debug register. + @param Data The data to write. + +**/ +VOID +XhcWriteDebugReg ( + IN USB3_DEBUG_PORT_HANDLE *Handle, + IN UINT32 Offset, + IN UINT32 Data + ) +{ + EFI_PHYSICAL_ADDRESS DebugCapabilityBase; + + DebugCapabilityBase = Handle->DebugCapabilityBase; + MmioWrite32 ((UINTN)(DebugCapabilityBase + Offset), Data); + + return; +} + +/** + Read XHCI debug register. + + @param Handle Debug port handle. + @param Offset The offset of the runtime register. + + @return The register content read + +**/ +UINT32 +XhcReadDebugReg ( + IN USB3_DEBUG_PORT_HANDLE *Handle, + IN UINT32 Offset + ) +{ + UINT32 Data; + EFI_PHYSICAL_ADDRESS DebugCapabilityBase; + + DebugCapabilityBase = Handle->DebugCapabilityBase; + Data = MmioRead32 ((UINTN)(DebugCapabilityBase + Offset)); + + return Data; +} + +/** + Set one bit of the debug register while keeping other bits. + + @param Handle Debug port handle. + @param Offset The offset of the debug register. + @param Bit The bit mask of the register to set. + +**/ +VOID +XhcSetDebugRegBit ( + IN USB3_DEBUG_PORT_HANDLE *Handle, + IN UINT32 Offset, + IN UINT32 Bit + ) +{ + UINT32 Data; + + Data = XhcReadDebugReg (Handle, Offset); + Data |= Bit; + XhcWriteDebugReg (Handle, Offset, Data); +} + +/** + Clear one bit of the debug register while keeping other bits. + + @param Handle Debug port handle. + @param Offset The offset of the debug register. + @param Bit The bit mask of the register to clear. + +**/ +VOID +XhcClearDebugRegBit ( + IN USB3_DEBUG_PORT_HANDLE *Handle, + IN UINT32 Offset, + IN UINT32 Bit + ) +{ + UINT32 Data; + + Data = XhcReadDebugReg (Handle, Offset); + Data &= ~Bit; + XhcWriteDebugReg (Handle, Offset, Data); +} + +/** + Program and enable XHCI MMIO base address. + + @return XHCI MMIO base address. + +**/ +EFI_PHYSICAL_ADDRESS +ProgramXhciBaseAddress ( + VOID + ) +{ + UINT16 PciCmd; + UINT32 Low; + UINT32 High; + EFI_PHYSICAL_ADDRESS XhciMmioBase; + + Low = PciRead32 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET); + High = PciRead32 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET + 4); + XhciMmioBase = (EFI_PHYSICAL_ADDRESS)(LShiftU64 ((UINT64)High, 32) | Low); + XhciMmioBase &= XHCI_BASE_ADDRESS_64_BIT_MASK; + + if ((XhciMmioBase == 0) || (XhciMmioBase == XHCI_BASE_ADDRESS_64_BIT_MASK)) { + XhciMmioBase = PcdGet64 (PcdUsbXhciMemorySpaceBase); + PciWrite32 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET, XhciMmioBase & 0xFFFFFFFF); + PciWrite32 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET + 4, (RShiftU64 (XhciMmioBase, 32) & 0xFFFFFFFF)); + } + + PciCmd = PciRead16 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_COMMAND_OFFSET); + if (((PciCmd & EFI_PCI_COMMAND_MEMORY_SPACE) == 0) || ((PciCmd & EFI_PCI_COMMAND_BUS_MASTER) == 0)) { + PciCmd |= EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_BUS_MASTER; + PciWrite16 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_COMMAND_OFFSET, PciCmd); + } + + return XhciMmioBase; +} + +/** + Update XHC MMIO base address when MMIO base address is changed. + + @param Handle Debug port handle. + @param XhciMmioBase XHCI MMIO base address. + +**/ +VOID +UpdateXhcResource ( + IN OUT USB3_DEBUG_PORT_HANDLE *Handle, + IN EFI_PHYSICAL_ADDRESS XhciMmioBase + ) +{ + if (Handle == NULL) { + return; + } + + // + // Need fix Handle data according to new XHCI MMIO base address. + // + Handle->XhciMmioBase = XhciMmioBase; + Handle->DebugCapabilityBase = XhciMmioBase + Handle->DebugCapabilityOffset; + Handle->XhciOpRegister = XhciMmioBase + MmioRead8 ((UINTN)XhciMmioBase); +} + +/** + Calculate the usb debug port bar address. + + @param Handle Debug port handle. + + @retval RETURN_UNSUPPORTED The usb host controller does not support usb debug port capability. + @retval RETURN_SUCCESS Get bar and offset successfully. + +**/ +RETURN_STATUS +EFIAPI +CalculateUsbDebugPortMmioBase ( + USB3_DEBUG_PORT_HANDLE *Handle + ) +{ + UINT16 VendorId; + UINT16 DeviceId; + UINT8 ProgInterface; + UINT8 SubClassCode; + UINT8 BaseCode; + BOOLEAN Flag; + UINT32 Capability; + EFI_PHYSICAL_ADDRESS CapabilityPointer; + UINT8 CapLength; + + if (Handle->Initialized != USB3DBG_UNINITIALIZED) { + if (Handle->Initialized == USB3DBG_NO_DBG_CAB) { + return RETURN_UNSUPPORTED; + } else { + return RETURN_SUCCESS; + } + } + + VendorId = PciRead16 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_VENDOR_ID_OFFSET); + DeviceId = PciRead16 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_DEVICE_ID_OFFSET); + + if ((VendorId == 0xFFFF) || (DeviceId == 0xFFFF)) { + goto Done; + } + + ProgInterface = PciRead8 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_CLASSCODE_OFFSET); + SubClassCode = PciRead8 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_CLASSCODE_OFFSET + 1); + BaseCode = PciRead8 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_CLASSCODE_OFFSET + 2); + + if ((ProgInterface != PCI_IF_XHCI) || (SubClassCode != PCI_CLASS_SERIAL_USB) || (BaseCode != PCI_CLASS_SERIAL)) { + goto Done; + } + + CapLength = MmioRead8 ((UINTN)Handle->XhciMmioBase); + + // + // Get capability pointer from HCCPARAMS at offset 0x10 + // + CapabilityPointer = Handle->XhciMmioBase + (MmioRead32 ((UINTN)(Handle->XhciMmioBase + XHC_HCCPARAMS_OFFSET)) >> 16) * 4; + + // + // Search XHCI debug capability + // + Flag = FALSE; + Capability = MmioRead32 ((UINTN)CapabilityPointer); + while (TRUE) { + if ((Capability & XHC_CAPABILITY_ID_MASK) == PCI_CAPABILITY_ID_DEBUG_PORT) { + Flag = TRUE; + break; + } + + if ((((Capability & XHC_NEXT_CAPABILITY_MASK) >> 8) & XHC_CAPABILITY_ID_MASK) == 0) { + // + // Reach the end of capability list, quit + // + break; + } + + CapabilityPointer += ((Capability & XHC_NEXT_CAPABILITY_MASK) >> 8) * 4; + Capability = MmioRead32 ((UINTN)CapabilityPointer); + } + + if (!Flag) { + goto Done; + } + + // + // USB3 debug capability is supported. + // + Handle->DebugCapabilityBase = CapabilityPointer; + Handle->DebugCapabilityOffset = CapabilityPointer - Handle->XhciMmioBase; + Handle->XhciOpRegister = Handle->XhciMmioBase + CapLength; + Handle->DebugSupport = TRUE; + Handle->Initialized = USB3DBG_DBG_CAB; + return RETURN_SUCCESS; + +Done: + Handle->Initialized = USB3DBG_NO_DBG_CAB; + return RETURN_UNSUPPORTED; +} + +/** + Check if it needs to re-initialize usb debug port hardware. + + During different phases switch, such as SEC to PEI or PEI to DXE or DXE to SMM, we should check + whether the usb debug port hardware configuration is changed. Such case can be triggered by + Pci bus resource allocation and so on. + + @param Handle Debug port handle. + + @retval TRUE The usb debug port hardware configuration is changed. + @retval FALSE The usb debug port hardware configuration is not changed. + +**/ +BOOLEAN +EFIAPI +NeedReinitializeHardware ( + IN USB3_DEBUG_PORT_HANDLE *Handle + ) +{ + BOOLEAN Result; + volatile UINT32 Dcctrl; + + Result = FALSE; + + // + // If DCE bit, it means USB3 debug is not enabled. + // + Dcctrl = XhcReadDebugReg (Handle, XHC_DC_DCCTRL); + if ((Dcctrl & BIT0) == 0) { + Result = TRUE; + } else if (!Handle->Ready) { + Handle->Ready = TRUE; + Handle->Initialized = USB3DBG_ENABLED; + } + + return Result; +} + +/** + Create XHCI event ring. + + @param Handle Debug port handle. + @param EventRing The created event ring. + +**/ +EFI_STATUS +CreateEventRing ( + IN USB3_DEBUG_PORT_HANDLE *Handle, + OUT EVENT_RING *EventRing + ) +{ + VOID *Buf; + EVENT_RING_SEG_TABLE_ENTRY *ERSTBase; + + ASSERT (EventRing != NULL); + + // + // Allocate Event Ring + // + Buf = AllocateAlignBuffer (sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER); + ASSERT (Buf != NULL); + ASSERT (((UINTN)Buf & 0x3F) == 0); + ZeroMem (Buf, sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER); + + EventRing->EventRingSeg0 = (EFI_PHYSICAL_ADDRESS)(UINTN)Buf; + EventRing->TrbNumber = EVENT_RING_TRB_NUMBER; + EventRing->EventRingDequeue = (EFI_PHYSICAL_ADDRESS)(UINTN)EventRing->EventRingSeg0; + EventRing->EventRingEnqueue = (EFI_PHYSICAL_ADDRESS)(UINTN)EventRing->EventRingSeg0; + + // + // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1' + // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring. + // + EventRing->EventRingCCS = 1; + + // + // Allocate Event Ring Segment Table Entry 0 in Event Ring Segment Table + // + Buf = AllocateAlignBuffer (sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER); + ASSERT (Buf != NULL); + ASSERT (((UINTN)Buf & 0x3F) == 0); + ZeroMem (Buf, sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER); + + ERSTBase = (EVENT_RING_SEG_TABLE_ENTRY *)Buf; + EventRing->ERSTBase = (EFI_PHYSICAL_ADDRESS)(UINTN)ERSTBase; + + // + // Fill Event Segment address + // + ERSTBase->PtrLo = XHC_LOW_32BIT (EventRing->EventRingSeg0); + ERSTBase->PtrHi = XHC_HIGH_32BIT (EventRing->EventRingSeg0); + ERSTBase->RingTrbSize = EVENT_RING_TRB_NUMBER; + + // + // Program the Interrupter Event Ring Dequeue Pointer (DCERDP) register (7.6.4.1) + // + XhcWriteDebugReg ( + Handle, + XHC_DC_DCERDP, + XHC_LOW_32BIT ((UINT64)(UINTN)EventRing->EventRingDequeue) + ); + + XhcWriteDebugReg ( + Handle, + XHC_DC_DCERDP + 4, + XHC_HIGH_32BIT ((UINT64)(UINTN)EventRing->EventRingDequeue) + ); + + // + // Program the Debug Capability Event Ring Segment Table Base Address (DCERSTBA) register(7.6.4.1) + // + XhcWriteDebugReg ( + Handle, + XHC_DC_DCERSTBA, + XHC_LOW_32BIT ((UINT64)(UINTN)ERSTBase) + ); + + XhcWriteDebugReg ( + Handle, + XHC_DC_DCERSTBA + 4, + XHC_HIGH_32BIT ((UINT64)(UINTN)ERSTBase) + ); + + // + // Program the Debug Capability Event Ring Segment Table Size (DCERSTSZ) register(7.6.4.1) + // + XhcWriteDebugReg ( + Handle, + XHC_DC_DCERSTSZ, + ERST_NUMBER + ); + return EFI_SUCCESS; +} + +/** + Create XHCI transfer ring. + + @param Handle Debug port handle. + @param TrbNum The number of TRB in the ring. + @param TransferRing The created transfer ring. + +**/ +VOID +CreateTransferRing ( + IN USB3_DEBUG_PORT_HANDLE *Handle, + IN UINT32 TrbNum, + OUT TRANSFER_RING *TransferRing + ) +{ + VOID *Buf; + LINK_TRB *EndTrb; + + Buf = AllocateAlignBuffer (sizeof (TRB_TEMPLATE) * TrbNum); + ASSERT (Buf != NULL); + ASSERT (((UINTN)Buf & 0xF) == 0); + ZeroMem (Buf, sizeof (TRB_TEMPLATE) * TrbNum); + + TransferRing->RingSeg0 = (EFI_PHYSICAL_ADDRESS)(UINTN)Buf; + TransferRing->TrbNumber = TrbNum; + TransferRing->RingEnqueue = TransferRing->RingSeg0; + TransferRing->RingDequeue = TransferRing->RingSeg0; + TransferRing->RingPCS = 1; + // + // 4.9.2 Transfer Ring Management + // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to + // point to the first TRB in the ring. + // + EndTrb = (LINK_TRB *)((UINTN)Buf + sizeof (TRB_TEMPLATE) * (TrbNum - 1)); + EndTrb->Type = TRB_TYPE_LINK; + EndTrb->PtrLo = XHC_LOW_32BIT (Buf); + EndTrb->PtrHi = XHC_HIGH_32BIT (Buf); + // + // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit. + // + EndTrb->TC = 1; + // + // Set Cycle bit as other TRB PCS init value + // + EndTrb->CycleBit = 0; +} + +/** + Create debug capability context for XHC debug device. + + @param Handle Debug port handle. + + @retval EFI_SUCCESS The bit successfully changed by host controller. + @retval EFI_TIMEOUT The time out occurred. + +**/ +EFI_STATUS +CreateDebugCapabilityContext ( + IN USB3_DEBUG_PORT_HANDLE *Handle + ) +{ + VOID *Buf; + XHC_DC_CONTEXT *DebugCapabilityContext; + UINT8 *String0Desc; + UINT8 *ManufacturerStrDesc; + UINT8 *ProductStrDesc; + UINT8 *SerialNumberStrDesc; + + // + // Allocate debug device context + // + Buf = AllocateAlignBuffer (sizeof (XHC_DC_CONTEXT)); + ASSERT (Buf != NULL); + ASSERT (((UINTN)Buf & 0xF) == 0); + ZeroMem (Buf, sizeof (XHC_DC_CONTEXT)); + + DebugCapabilityContext = (XHC_DC_CONTEXT *)(UINTN)Buf; + Handle->DebugCapabilityContext = (EFI_PHYSICAL_ADDRESS)(UINTN)DebugCapabilityContext; + + // + // Initialize DbcInfoContext. + // + DebugCapabilityContext->DbcInfoContext.String0Length = STRING0_DESC_LEN; + DebugCapabilityContext->DbcInfoContext.ManufacturerStrLength = MANU_DESC_LEN; + DebugCapabilityContext->DbcInfoContext.ProductStrLength = PRODUCT_DESC_LEN; + DebugCapabilityContext->DbcInfoContext.SerialNumberStrLength = SERIAL_DESC_LEN; + + // + // Initialize EpOutContext. + // + DebugCapabilityContext->EpOutContext.CErr = 0x3; + DebugCapabilityContext->EpOutContext.EPType = ED_BULK_OUT; + DebugCapabilityContext->EpOutContext.MaxPacketSize = XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE; + DebugCapabilityContext->EpOutContext.AverageTRBLength = 0x1000; + + // + // Initialize EpInContext. + // + DebugCapabilityContext->EpInContext.CErr = 0x3; + DebugCapabilityContext->EpInContext.EPType = ED_BULK_IN; + DebugCapabilityContext->EpInContext.MaxPacketSize = XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE; + DebugCapabilityContext->EpInContext.AverageTRBLength = 0x1000; + + // + // Update string descriptor address + // + String0Desc = (UINT8 *)AllocateAlignBuffer (STRING0_DESC_LEN + MANU_DESC_LEN + PRODUCT_DESC_LEN + SERIAL_DESC_LEN); + ASSERT (String0Desc != NULL); + ZeroMem (String0Desc, STRING0_DESC_LEN + MANU_DESC_LEN + PRODUCT_DESC_LEN + SERIAL_DESC_LEN); + CopyMem (String0Desc, mString0Desc, STRING0_DESC_LEN); + DebugCapabilityContext->DbcInfoContext.String0DescAddress = (UINT64)(UINTN)String0Desc; + + ManufacturerStrDesc = String0Desc + STRING0_DESC_LEN; + CopyMem (ManufacturerStrDesc, mManufacturerStrDesc, MANU_DESC_LEN); + DebugCapabilityContext->DbcInfoContext.ManufacturerStrDescAddress = (UINT64)(UINTN)ManufacturerStrDesc; + + ProductStrDesc = ManufacturerStrDesc + MANU_DESC_LEN; + CopyMem (ProductStrDesc, mProductStrDesc, PRODUCT_DESC_LEN); + DebugCapabilityContext->DbcInfoContext.ProductStrDescAddress = (UINT64)(UINTN)ProductStrDesc; + + SerialNumberStrDesc = ProductStrDesc + PRODUCT_DESC_LEN; + CopyMem (SerialNumberStrDesc, mSerialNumberStrDesc, SERIAL_DESC_LEN); + DebugCapabilityContext->DbcInfoContext.SerialNumberStrDescAddress = (UINT64)(UINTN)SerialNumberStrDesc; + + // + // Allocate and initialize the Transfer Ring for the Input Endpoint Context. + // + ZeroMem (&Handle->TransferRingIn, sizeof (TRANSFER_RING)); + CreateTransferRing (Handle, TR_RING_TRB_NUMBER, &Handle->TransferRingIn); + DebugCapabilityContext->EpInContext.PtrLo = XHC_LOW_32BIT (Handle->TransferRingIn.RingSeg0) | BIT0; + DebugCapabilityContext->EpInContext.PtrHi = XHC_HIGH_32BIT (Handle->TransferRingIn.RingSeg0); + + // + // Allocate and initialize the Transfer Ring for the Output Endpoint Context. + // + ZeroMem (&Handle->TransferRingOut, sizeof (TRANSFER_RING)); + CreateTransferRing (Handle, TR_RING_TRB_NUMBER, &Handle->TransferRingOut); + DebugCapabilityContext->EpOutContext.PtrLo = XHC_LOW_32BIT (Handle->TransferRingOut.RingSeg0) | BIT0; + DebugCapabilityContext->EpOutContext.PtrHi = XHC_HIGH_32BIT (Handle->TransferRingOut.RingSeg0); + + // + // Program the Debug Capability Context Pointer (DCCP) register(7.6.8.7) + // + XhcWriteDebugReg ( + Handle, + XHC_DC_DCCP, + XHC_LOW_32BIT ((UINT64)(UINTN)DebugCapabilityContext) + ); + XhcWriteDebugReg ( + Handle, + XHC_DC_DCCP + 4, + XHC_HIGH_32BIT ((UINT64)(UINTN)DebugCapabilityContext) + ); + return EFI_SUCCESS; +} + +/** + Check if debug device is running. + + @param Handle Debug port handle. + +**/ +VOID +XhcDetectDebugCapabilityReady ( + IN USB3_DEBUG_PORT_HANDLE *Handle + ) +{ + UINT64 TimeOut; + volatile UINT32 Dcctrl; + + TimeOut = 1; + if (Handle->Initialized == USB3DBG_DBG_CAB) { + // + // As detection is slow in seconds, wait for longer timeout for the first time. + // If first initialization is failed, we will try to enable debug device in the + // Poll function invoked by timer. + // + TimeOut = DivU64x32 (PcdGet64 (PcdUsbXhciDebugDetectTimeout), XHC_POLL_DELAY) + 1; + } + + do { + // + // Check if debug device is in configured state + // + Dcctrl = XhcReadDebugReg (Handle, XHC_DC_DCCTRL); + if ((Dcctrl & BIT0) != 0) { + // + // Set the flag to indicate debug device is in configured state + // + Handle->Ready = TRUE; + break; + } + + MicroSecondDelay (XHC_POLL_DELAY); + TimeOut--; + } while (TimeOut != 0); +} + +/** + Initialize usb debug port hardware. + + @param Handle Debug port handle. + + @retval TRUE The usb debug port hardware configuration is changed. + @retval FALSE The usb debug port hardware configuration is not changed. + +**/ +RETURN_STATUS +EFIAPI +InitializeUsbDebugHardware ( + IN USB3_DEBUG_PORT_HANDLE *Handle + ) +{ + RETURN_STATUS Status; + UINT8 *Buffer; + UINTN Index; + UINT8 TotalUsb3Port; + EFI_PHYSICAL_ADDRESS XhciOpRegister; + UINT32 Dcddi1; + + XhciOpRegister = Handle->XhciOpRegister; + TotalUsb3Port = MmioRead32 (((UINTN)Handle->XhciMmioBase + XHC_HCSPARAMS1_OFFSET)) >> 24; + + if (Handle->Initialized == USB3DBG_NOT_ENABLED) { + Dcddi1 = XhcReadDebugReg (Handle, XHC_DC_DCDDI1); + if (Dcddi1 != (UINT32)((XHCI_DEBUG_DEVICE_VENDOR_ID << 16) | XHCI_DEBUG_DEVICE_PROTOCOL)) { + // + // The debug capability has been reset by other code, return device error. + // + return EFI_DEVICE_ERROR; + } + + // + // If XHCI supports debug capability, hardware resource has been allocated, + // but it has not been enabled, try to enable again. + // + goto Enable; + } + + // + // Initialize for PEI phase when AllocatePages can work. + // Allocate data buffer with max packet size for data read and data poll. + // Allocate data buffer for data write. + // + Buffer = AllocateAlignBuffer (XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE * 2 + USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE); + if (Buffer == NULL) { + // + // AllocatePages can not still work now, return fail and do not initialize now. + // + return RETURN_NOT_READY; + } + + // + // Reset port to get debug device discovered + // + for (Index = 0; Index < TotalUsb3Port; Index++) { + XhcSetR32Bit ((UINTN)XhciOpRegister + XHC_PORTSC_OFFSET + Index * 0x10, BIT4); + MicroSecondDelay (10 * 1000); + } + + // + // Clear DCE bit and LSE bit in DCCTRL + // + if ((XhcReadDebugReg (Handle, XHC_DC_DCCTRL) & (BIT1|BIT31)) == (BIT1|BIT31)) { + XhcClearDebugRegBit (Handle, XHC_DC_DCCTRL, BIT1|BIT31); + } + + // + // Construct the buffer for read, poll and write. + // + Handle->UrbIn.Data = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer; + Handle->Data = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer + XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE; + Handle->UrbOut.Data = Handle->UrbIn.Data + XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE * 2; + + // + // Initialize event ring + // + ZeroMem (&Handle->EventRing, sizeof (EVENT_RING)); + Status = CreateEventRing (Handle, &Handle->EventRing); + ASSERT_EFI_ERROR (Status); + + // + // Init IN and OUT endpoint context + // + Status = CreateDebugCapabilityContext (Handle); + ASSERT_EFI_ERROR (Status); + + // + // Init DCDDI1 and DCDDI2 + // + XhcWriteDebugReg ( + Handle, + XHC_DC_DCDDI1, + (UINT32)((XHCI_DEBUG_DEVICE_VENDOR_ID << 16) | XHCI_DEBUG_DEVICE_PROTOCOL) + ); + + XhcWriteDebugReg ( + Handle, + XHC_DC_DCDDI2, + (UINT32)((XHCI_DEBUG_DEVICE_REVISION << 16) | XHCI_DEBUG_DEVICE_PRODUCT_ID) + ); + +Enable: + if ((Handle->Initialized == USB3DBG_NOT_ENABLED) && (!Handle->ChangePortPower)) { + // + // If the first time detection is failed, turn port power off and on in order to + // reset port status this time, then try to check if debug device is ready again. + // + for (Index = 0; Index < TotalUsb3Port; Index++) { + XhcClearR32Bit ((UINTN)XhciOpRegister + XHC_PORTSC_OFFSET + Index * 0x10, BIT9); + MicroSecondDelay (XHC_DEBUG_PORT_ON_OFF_DELAY); + XhcSetR32Bit ((UINTN)XhciOpRegister + XHC_PORTSC_OFFSET + Index * 0x10, BIT9); + MicroSecondDelay (XHC_DEBUG_PORT_ON_OFF_DELAY); + Handle->ChangePortPower = TRUE; + } + } + + // + // Set DCE bit and LSE bit to "1" in DCCTRL in first initialization + // + XhcSetDebugRegBit (Handle, XHC_DC_DCCTRL, BIT1|BIT31); + + XhcDetectDebugCapabilityReady (Handle); + + Status = RETURN_SUCCESS; + if (!Handle->Ready) { + Handle->Initialized = USB3DBG_NOT_ENABLED; + Status = RETURN_NOT_READY; + } else { + Handle->Initialized = USB3DBG_ENABLED; + } + + return Status; +} + +/** + Discover and initialize usb debug port. + + @param Handle Debug port handle. + +**/ +VOID +DiscoverInitializeUsbDebugPort ( + IN USB3_DEBUG_PORT_HANDLE *Handle + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS XhciMmioBase; + + // + // Read 64-bit MMIO base address + // + XhciMmioBase = ProgramXhciBaseAddress (); + Handle->XhciMmioBase = XhciMmioBase; + + Status = CalculateUsbDebugPortMmioBase (Handle); + if (!RETURN_ERROR (Status)) { + UpdateXhcResource (Handle, XhciMmioBase); + if (NeedReinitializeHardware (Handle)) { + InitializeUsbDebugHardware (Handle); + } + } +} + +/** + Set USB3 debug instance address. + + @param[in] Instance Debug port instance. + +**/ +VOID +SetUsb3DebugPortInstance ( + IN USB3_DEBUG_PORT_HANDLE *Instance + ) +{ + EFI_PHYSICAL_ADDRESS *AddrPtr; + + AddrPtr = GetUsb3DebugPortInstanceAddrPtr (); + ASSERT (AddrPtr != NULL); + *AddrPtr = (EFI_PHYSICAL_ADDRESS)(UINTN)Instance; +} + +/** + Return USB3 debug instance address. + +**/ +USB3_DEBUG_PORT_HANDLE * +GetUsb3DebugPortInstance ( + VOID + ) +{ + EFI_PHYSICAL_ADDRESS *AddrPtr; + USB3_DEBUG_PORT_HANDLE *Instance; + + AddrPtr = GetUsb3DebugPortInstanceAddrPtr (); + ASSERT (AddrPtr != NULL); + + Instance = (USB3_DEBUG_PORT_HANDLE *)(UINTN)*AddrPtr; + + return Instance; +} + +/** + Read data from debug device and save the data in buffer. + + Reads NumberOfBytes data bytes from a debug device into the buffer + specified by Buffer. The number of bytes actually read is returned. + If the return value is less than NumberOfBytes, then the rest operation failed. + If NumberOfBytes is zero, then return 0. + + @param Handle Debug port handle. + @param Buffer Pointer to the data buffer to store the data read from the debug device. + @param NumberOfBytes Number of bytes which will be read. + @param Timeout Timeout value for reading from debug device. Its unit is Microsecond. + + @retval 0 Read data failed, no data is to be read. + @retval >0 Actual number of bytes read from debug device. + +**/ +UINTN +EFIAPI +DebugPortReadBuffer ( + IN DEBUG_PORT_HANDLE Handle, + IN UINT8 *Buffer, + IN UINTN NumberOfBytes, + IN UINTN Timeout + ) +{ + USB3_DEBUG_PORT_HANDLE *UsbDebugPortHandle; + UINT8 Index; + UINT8 *Data; + + if ((NumberOfBytes != 1) || (Buffer == NULL) || (Timeout != 0)) { + return 0; + } + + // + // If Handle is NULL, get own instance. + // If Handle is not NULL, use it and set the instance. + // + if (Handle != NULL) { + UsbDebugPortHandle = (USB3_DEBUG_PORT_HANDLE *)Handle; + SetUsb3DebugPortInstance (UsbDebugPortHandle); + } else { + UsbDebugPortHandle = GetUsb3DebugPortInstance (); + } + + if (UsbDebugPortHandle == NULL) { + return 0; + } + + if (UsbDebugPortHandle->InNotify) { + return 0; + } + + DiscoverInitializeUsbDebugPort (UsbDebugPortHandle); + + if (UsbDebugPortHandle->Initialized != USB3DBG_ENABLED) { + return 0; + } + + Data = (UINT8 *)(UINTN)UsbDebugPortHandle->Data; + + // + // Read data from buffer + // + if (UsbDebugPortHandle->DataCount < 1) { + return 0; + } else { + *Buffer = Data[0]; + + for (Index = 0; Index < UsbDebugPortHandle->DataCount - 1; Index++) { + if ((Index + 1) >= XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE) { + return 0; + } + + Data[Index] = Data[Index + 1]; + } + + UsbDebugPortHandle->DataCount = (UINT8)(UsbDebugPortHandle->DataCount - 1); + return 1; + } +} + +/** + Write data from buffer to debug device. + + Writes NumberOfBytes data bytes from Buffer to the debug device. + The number of bytes actually written to the debug device is returned. + If the return value is less than NumberOfBytes, then the write operation failed. + If NumberOfBytes is zero, then return 0. + + @param Handle Debug port handle. + @param Buffer Pointer to the data buffer to be written. + @param NumberOfBytes Number of bytes to written to the debug device. + + @retval 0 NumberOfBytes is 0. + @retval >0 The number of bytes written to the debug device. + If this value is less than NumberOfBytes, then the write operation failed. + +**/ +UINTN +EFIAPI +DebugPortWriteBuffer ( + IN DEBUG_PORT_HANDLE Handle, + IN UINT8 *Buffer, + IN UINTN NumberOfBytes + ) +{ + USB3_DEBUG_PORT_HANDLE *UsbDebugPortHandle; + UINTN Sent; + UINTN Total; + + if ((NumberOfBytes == 0) || (Buffer == NULL)) { + return 0; + } + + Sent = 0; + Total = 0; + + // + // If Handle is NULL, get own instance. + // If Handle is not NULL, use it and set the instance. + // + if (Handle != NULL) { + UsbDebugPortHandle = (USB3_DEBUG_PORT_HANDLE *)Handle; + SetUsb3DebugPortInstance (UsbDebugPortHandle); + } else { + UsbDebugPortHandle = GetUsb3DebugPortInstance (); + } + + if (UsbDebugPortHandle == NULL) { + return 0; + } + + if (UsbDebugPortHandle->InNotify) { + return 0; + } + + DiscoverInitializeUsbDebugPort (UsbDebugPortHandle); + + if (UsbDebugPortHandle->Initialized != USB3DBG_ENABLED) { + return 0; + } + + // + // When host is trying to send data, write will be blocked. + // Poll to see if there is any data sent by host at first. + // + DebugPortPollBuffer (UsbDebugPortHandle); + + while ((Total < NumberOfBytes)) { + if (NumberOfBytes - Total > USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE) { + Sent = USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE; + } else { + Sent = (UINT8)(NumberOfBytes - Total); + } + + XhcDataTransfer (UsbDebugPortHandle, EfiUsbDataOut, Buffer + Total, &Sent, DATA_TRANSFER_WRITE_TIMEOUT); + Total += Sent; + } + + return Total; +} + +/** + Polls a debug device to see if there is any data waiting to be read. + + Polls a debug device to see if there is any data waiting to be read. + If there is data waiting to be read from the debug device, then TRUE is returned. + If there is no data waiting to be read from the debug device, then FALSE is returned. + + @param Handle Debug port handle. + + @retval TRUE Data is waiting to be read from the debug device. + @retval FALSE There is no data waiting to be read from the debug device. + +**/ +BOOLEAN +EFIAPI +DebugPortPollBuffer ( + IN DEBUG_PORT_HANDLE Handle + ) +{ + USB3_DEBUG_PORT_HANDLE *UsbDebugPortHandle; + UINTN Length; + + // + // If Handle is NULL, get own instance. + // If Handle is not NULL, use it and set the instance. + // + if (Handle != NULL) { + UsbDebugPortHandle = (USB3_DEBUG_PORT_HANDLE *)Handle; + SetUsb3DebugPortInstance (UsbDebugPortHandle); + } else { + UsbDebugPortHandle = GetUsb3DebugPortInstance (); + } + + if (UsbDebugPortHandle == NULL) { + return FALSE; + } + + if (UsbDebugPortHandle->InNotify) { + return FALSE; + } + + DiscoverInitializeUsbDebugPort (UsbDebugPortHandle); + + if (UsbDebugPortHandle->Initialized != USB3DBG_ENABLED) { + return FALSE; + } + + // + // If the data buffer is not empty, then return TRUE directly. + // Otherwise initialize a usb read transaction and read data to internal data buffer. + // + if (UsbDebugPortHandle->DataCount != 0) { + return TRUE; + } + + // + // Read data as much as we can + // + Length = XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE; + XhcDataTransfer (UsbDebugPortHandle, EfiUsbDataIn, (VOID *)(UINTN)UsbDebugPortHandle->Data, &Length, DATA_TRANSFER_POLL_TIMEOUT); + + if (Length > XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE) { + return FALSE; + } + + if (Length == 0) { + return FALSE; + } + + // + // Store data into internal buffer for use later + // + UsbDebugPortHandle->DataCount = (UINT8)Length; + return TRUE; +} + +/** + Initialize the debug port. + + If Function is not NULL, Debug Communication Library will call this function + by passing in the Context to be the first parameter. If needed, Debug Communication + Library will create one debug port handle to be the second argument passing in + calling the Function, otherwise it will pass NULL to be the second argument of + Function. + + If Function is NULL, and Context is not NULL, the Debug Communication Library could + a) Return the same handle as passed in (as Context parameter). + b) Ignore the input Context parameter and create new handle to be returned. + + If parameter Function is NULL and Context is NULL, Debug Communication Library could + created a new handle if needed and return it, otherwise it will return NULL. + + @param[in] Context Context needed by callback function; it was optional. + @param[in] Function Continue function called by Debug Communication library; + it was optional. + + @return The debug port handle created by Debug Communication Library if Function + is not NULL. + +**/ +DEBUG_PORT_HANDLE +EFIAPI +DebugPortInitialize ( + IN VOID *Context, + IN DEBUG_PORT_CONTINUE Function + ) +{ + USB3_DEBUG_PORT_HANDLE *UsbDebugPortHandle; + + // + // Validate the PCD PcdDebugPortHandleBufferSize value + // + ASSERT (PcdGet16 (PcdDebugPortHandleBufferSize) == sizeof (USB3_DEBUG_PORT_HANDLE)); + + if ((Function == NULL) && (Context != NULL)) { + SetUsb3DebugPortInstance ((USB3_DEBUG_PORT_HANDLE *)Context); + return (DEBUG_PORT_HANDLE)Context; + } + + UsbDebugPortHandle = GetUsb3DebugPortInstance (); + if (UsbDebugPortHandle == NULL) { + return NULL; + } + + DiscoverInitializeUsbDebugPort (UsbDebugPortHandle); + + if (Function != NULL) { + Function (Context, (DEBUG_PORT_HANDLE)UsbDebugPortHandle); + } + + return (DEBUG_PORT_HANDLE)UsbDebugPortHandle; +} diff --git a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.c b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.c index d37fb991f1..6f86ace58c 100644 --- a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.c +++ b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.c @@ -1,536 +1,536 @@ -/** @file
- Debug Port Library implementation based on usb3 debug port.
-
- Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include <Base.h>
-#include <PiDxe.h>
-#include <Library/UefiBootServicesTableLib.h>
-#include <Library/HobLib.h>
-#include <Protocol/PciIo.h>
-#include <Protocol/IoMmu.h>
-#include <Protocol/DxeSmmReadyToLock.h>
-#include "DebugCommunicationLibUsb3Internal.h"
-
-GUID gUsb3DbgGuid = USB3_DBG_GUID;
-
-USB3_DEBUG_PORT_HANDLE mUsb3Instance = { USB3DBG_UNINITIALIZED };
-EFI_PHYSICAL_ADDRESS mUsb3InstanceAddr = 0;
-EFI_PHYSICAL_ADDRESS *mUsb3InstanceAddrPtr = NULL;
-EFI_PCI_IO_PROTOCOL *mUsb3PciIo = NULL;
-
-/**
- Creates a named event that can be signaled.
-
- This function creates an event using NotifyTpl, NotifyFunction.
- If Name is NULL, then ASSERT().
- If NotifyTpl is not a legal TPL value, then ASSERT().
- If NotifyFunction is NULL, then ASSERT().
-
- @param Name Supplies the GUID name of the event.
- @param NotifyTpl Supplies the task priority level of the event notifications.
- @param NotifyFunction Supplies the function to notify when the event is signaled.
- @param Event A pointer to the event created.
-
- @retval EFI_SUCCESS A named event was created.
- @retval EFI_OUT_OF_RESOURCES There are not enough resource to create the named event.
-
-**/
-EFI_STATUS
-EFIAPI
-Usb3NamedEventListen (
- IN CONST EFI_GUID *Name,
- IN EFI_TPL NotifyTpl,
- IN EFI_EVENT_NOTIFY NotifyFunction,
- IN EFI_EVENT *Event
- )
-{
- EFI_STATUS Status;
- VOID *RegistrationLocal;
-
- ASSERT (Name != NULL);
- ASSERT (NotifyFunction != NULL);
- ASSERT (NotifyTpl <= TPL_HIGH_LEVEL);
-
- //
- // Create event
- //
- Status = gBS->CreateEvent (
- EVT_NOTIFY_SIGNAL,
- NotifyTpl,
- NotifyFunction,
- NULL,
- Event
- );
- ASSERT_EFI_ERROR (Status);
-
- //
- // Register for an installation of protocol interface
- //
- Status = gBS->RegisterProtocolNotify (
- (EFI_GUID *)Name,
- *Event,
- &RegistrationLocal
- );
- ASSERT_EFI_ERROR (Status);
-
- return Status;
-}
-
-/**
- USB3 map one DMA buffer.
-
- @param PciIo Pointer to PciIo for USB3 debug port.
- @param Address DMA buffer address to be mapped.
- @param NumberOfBytes Number of bytes to be mapped.
-
-**/
-VOID
-Usb3MapOneDmaBuffer (
- IN EFI_PCI_IO_PROTOCOL *PciIo,
- IN EFI_PHYSICAL_ADDRESS Address,
- IN UINTN NumberOfBytes
- )
-{
- EFI_STATUS Status;
- VOID *HostAddress;
- EFI_PHYSICAL_ADDRESS DeviceAddress;
- VOID *Mapping;
-
- HostAddress = (VOID *)(UINTN)Address;
- Status = PciIo->Map (
- PciIo,
- EfiPciIoOperationBusMasterCommonBuffer,
- HostAddress,
- &NumberOfBytes,
- &DeviceAddress,
- &Mapping
- );
- ASSERT_EFI_ERROR (Status);
- ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress));
-}
-
-/**
- USB3 map DMA buffers.
-
- @param Instance Pointer to USB3 debug port instance.
- @param PciIo Pointer to PciIo for USB3 debug port.
-
-**/
-VOID
-Usb3MapDmaBuffers (
- IN USB3_DEBUG_PORT_HANDLE *Instance,
- IN EFI_PCI_IO_PROTOCOL *PciIo
- )
-{
- Usb3MapOneDmaBuffer (
- PciIo,
- Instance->UrbIn.Data,
- XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE * 2 + USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE
- );
-
- Usb3MapOneDmaBuffer (
- PciIo,
- Instance->TransferRingIn.RingSeg0,
- sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
- );
-
- Usb3MapOneDmaBuffer (
- PciIo,
- Instance->TransferRingOut.RingSeg0,
- sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
- );
-
- Usb3MapOneDmaBuffer (
- PciIo,
- Instance->EventRing.EventRingSeg0,
- sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER
- );
-
- Usb3MapOneDmaBuffer (
- PciIo,
- Instance->EventRing.ERSTBase,
- sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER
- );
-
- Usb3MapOneDmaBuffer (
- PciIo,
- Instance->DebugCapabilityContext,
- sizeof (XHC_DC_CONTEXT)
- );
-
- Usb3MapOneDmaBuffer (
- PciIo,
- ((XHC_DC_CONTEXT *)(UINTN)Instance->DebugCapabilityContext)->DbcInfoContext.String0DescAddress,
- STRING0_DESC_LEN + MANU_DESC_LEN + PRODUCT_DESC_LEN + SERIAL_DESC_LEN
- );
-}
-
-/**
- Invoke a notification event
-
- @param[in] Event Event whose notification function is being invoked.
- @param[in] Context The pointer to the notification function's context,
- which is implementation-dependent.
-
-**/
-VOID
-EFIAPI
-Usb3DxeSmmReadyToLockNotify (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- USB3_DEBUG_PORT_HANDLE *Instance;
-
- DEBUG ((DEBUG_INFO, "%a()\n", __func__));
-
- Instance = GetUsb3DebugPortInstance ();
- ASSERT (Instance != NULL);
-
- Instance->InNotify = TRUE;
-
- //
- // For the case that the USB3 debug port instance and DMA buffers are
- // from PEI HOB with IOMMU enabled.
- // Reinitialize USB3 debug port with granted DXE DMA buffer accessible
- // by SMM environment.
- //
- InitializeUsbDebugHardware (Instance);
-
- //
- // Wait some time for host to be ready after re-initialization.
- //
- MicroSecondDelay (1000000);
-
- Instance->InNotify = FALSE;
- gBS->CloseEvent (Event);
-}
-
-/**
- USB3 get IOMMU protocol.
-
- @return Pointer to IOMMU protocol.
-
-**/
-EDKII_IOMMU_PROTOCOL *
-Usb3GetIoMmu (
- VOID
- )
-{
- EFI_STATUS Status;
- EDKII_IOMMU_PROTOCOL *IoMmu;
-
- IoMmu = NULL;
- Status = gBS->LocateProtocol (
- &gEdkiiIoMmuProtocolGuid,
- NULL,
- (VOID **)&IoMmu
- );
- if (!EFI_ERROR (Status) && (IoMmu != NULL)) {
- return IoMmu;
- }
-
- return NULL;
-}
-
-/**
- Invoke a notification event
-
- @param[in] Event Event whose notification function is being invoked.
- @param[in] Context The pointer to the notification function's context,
- which is implementation-dependent.
-
-**/
-VOID
-EFIAPI
-Usb3PciIoNotify (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- EFI_STATUS Status;
- UINTN PciIoHandleCount;
- EFI_HANDLE *PciIoHandleBuffer;
- UINTN Index;
- EFI_PCI_IO_PROTOCOL *PciIo;
- UINTN PciSegment;
- UINTN PciBusNumber;
- UINTN PciDeviceNumber;
- UINTN PciFunctionNumber;
- UINT32 PciAddress;
- USB3_DEBUG_PORT_HANDLE *Instance;
- EFI_EVENT SmmReadyToLockEvent;
-
- Status = gBS->LocateHandleBuffer (
- ByProtocol,
- &gEfiPciIoProtocolGuid,
- NULL,
- &PciIoHandleCount,
- &PciIoHandleBuffer
- );
- if (!EFI_ERROR (Status) &&
- (PciIoHandleBuffer != NULL) &&
- (PciIoHandleCount != 0))
- {
- for (Index = 0; Index < PciIoHandleCount; Index++) {
- Status = gBS->HandleProtocol (
- PciIoHandleBuffer[Index],
- &gEfiPciIoProtocolGuid,
- (VOID **)&PciIo
- );
- ASSERT_EFI_ERROR (Status);
- Status = PciIo->GetLocation (PciIo, &PciSegment, &PciBusNumber, &PciDeviceNumber, &PciFunctionNumber);
- ASSERT_EFI_ERROR (Status);
- PciAddress = (UINT32)((PciBusNumber << 20) | (PciDeviceNumber << 15) | (PciFunctionNumber << 12));
- if (PciAddress == PcdGet32 (PcdUsbXhciPciAddress)) {
- //
- // Found the PciIo for USB3 debug port.
- //
- DEBUG ((DEBUG_INFO, "%a()\n", __func__));
- if (Usb3GetIoMmu () != NULL) {
- Instance = GetUsb3DebugPortInstance ();
- ASSERT (Instance != NULL);
- if (Instance->Ready) {
- Instance->InNotify = TRUE;
- Usb3MapDmaBuffers (Instance, PciIo);
- Instance->InNotify = FALSE;
-
- if (Instance->FromHob) {
- mUsb3PciIo = PciIo;
- Usb3NamedEventListen (
- &gEfiDxeSmmReadyToLockProtocolGuid,
- TPL_NOTIFY,
- Usb3DxeSmmReadyToLockNotify,
- &SmmReadyToLockEvent
- );
- }
- }
- }
-
- gBS->CloseEvent (Event);
- break;
- }
- }
-
- gBS->FreePool (PciIoHandleBuffer);
- }
-}
-
-/**
- Return USB3 debug instance address pointer.
-
-**/
-EFI_PHYSICAL_ADDRESS *
-GetUsb3DebugPortInstanceAddrPtr (
- VOID
- )
-{
- if (mUsb3InstanceAddrPtr == NULL) {
- //
- // Use the local variables temporarily.
- //
- mUsb3InstanceAddr = (EFI_PHYSICAL_ADDRESS)(UINTN)&mUsb3Instance;
- mUsb3InstanceAddrPtr = &mUsb3InstanceAddr;
- }
-
- return mUsb3InstanceAddrPtr;
-}
-
-/**
- Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
- OperationBusMasterCommonBuffer64 mapping.
-
- @param PciIo Pointer to PciIo for USB3 debug port.
- @param Pages The number of pages to allocate.
- @param Address A pointer to store the base system memory address of the
- allocated range.
-
- @retval EFI_SUCCESS The requested memory pages were allocated.
- @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
- MEMORY_WRITE_COMBINE and MEMORY_CACHED.
- @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
- @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
-
-**/
-EFI_STATUS
-Usb3AllocateDmaBuffer (
- IN EFI_PCI_IO_PROTOCOL *PciIo,
- IN UINTN Pages,
- OUT VOID **Address
- )
-{
- EFI_STATUS Status;
-
- *Address = NULL;
- Status = PciIo->AllocateBuffer (
- PciIo,
- AllocateAnyPages,
- EfiRuntimeServicesData,
- Pages,
- Address,
- 0
- );
- if (!EFI_ERROR (Status)) {
- Usb3MapOneDmaBuffer (
- PciIo,
- (EFI_PHYSICAL_ADDRESS)(UINTN)*Address,
- EFI_PAGES_TO_SIZE (Pages)
- );
- }
-
- return Status;
-}
-
-/**
- Allocate aligned memory for XHC's usage.
-
- @param BufferSize The size, in bytes, of the Buffer.
-
- @return A pointer to the allocated buffer or NULL if allocation fails.
-
-**/
-VOID *
-AllocateAlignBuffer (
- IN UINTN BufferSize
- )
-{
- EFI_PHYSICAL_ADDRESS TmpAddr;
- EFI_STATUS Status;
- VOID *Buf;
-
- Buf = NULL;
-
- if (gBS != NULL) {
- if (mUsb3PciIo != NULL) {
- Usb3AllocateDmaBuffer (
- mUsb3PciIo,
- EFI_SIZE_TO_PAGES (BufferSize),
- &Buf
- );
- } else {
- TmpAddr = 0xFFFFFFFF;
- Status = gBS->AllocatePages (
- AllocateMaxAddress,
- EfiACPIMemoryNVS,
- EFI_SIZE_TO_PAGES (BufferSize),
- &TmpAddr
- );
- if (!EFI_ERROR (Status)) {
- Buf = (VOID *)(UINTN)TmpAddr;
- }
- }
- }
-
- return Buf;
-}
-
-/**
- The constructor function initialize USB3 debug port.
-
- @param ImageHandle The firmware allocated handle for the EFI image.
- @param SystemTable A pointer to the EFI System Table.
-
- @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
-
-**/
-EFI_STATUS
-EFIAPI
-DebugCommunicationUsb3DxeConstructor (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
-{
- EFI_PHYSICAL_ADDRESS *AddrPtr;
- USB3_DEBUG_PORT_HANDLE *Instance;
- EFI_PHYSICAL_ADDRESS Address;
- EFI_STATUS Status;
- EFI_EVENT Event;
-
- Status = EfiGetSystemConfigurationTable (&gUsb3DbgGuid, (VOID **)&AddrPtr);
- if (EFI_ERROR (Status) || (AddrPtr == NULL)) {
- //
- // Instead of using local variables, install system configuration table for
- // the local instance and the buffer to save instance address pointer.
- //
- Address = SIZE_4GB;
- Status = gBS->AllocatePages (
- AllocateMaxAddress,
- EfiACPIMemoryNVS,
- EFI_SIZE_TO_PAGES (sizeof (EFI_PHYSICAL_ADDRESS) + sizeof (USB3_DEBUG_PORT_HANDLE)),
- &Address
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- AddrPtr = (EFI_PHYSICAL_ADDRESS *)(UINTN)Address;
- ZeroMem (AddrPtr, sizeof (EFI_PHYSICAL_ADDRESS) + sizeof (USB3_DEBUG_PORT_HANDLE));
- Instance = (USB3_DEBUG_PORT_HANDLE *)(AddrPtr + 1);
- CopyMem (Instance, &mUsb3Instance, sizeof (USB3_DEBUG_PORT_HANDLE));
- *AddrPtr = (EFI_PHYSICAL_ADDRESS)(UINTN)Instance;
-
- Status = gBS->InstallConfigurationTable (&gUsb3DbgGuid, AddrPtr);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- }
-
- if (mUsb3InstanceAddrPtr != NULL) {
- *AddrPtr = *mUsb3InstanceAddrPtr;
- }
-
- mUsb3InstanceAddrPtr = AddrPtr;
-
- Instance = GetUsb3DebugPortInstance ();
- ASSERT (Instance != NULL);
-
- if (Instance->PciIoEvent == 0) {
- Status = Usb3NamedEventListen (
- &gEfiPciIoProtocolGuid,
- TPL_NOTIFY,
- Usb3PciIoNotify,
- &Event
- );
- if (!EFI_ERROR (Status)) {
- Instance->PciIoEvent = (EFI_PHYSICAL_ADDRESS)(UINTN)Event;
- }
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- The destructor function.
-
- @param ImageHandle The firmware allocated handle for the EFI image.
- @param SystemTable A pointer to the EFI System Table.
-
- @retval EFI_SUCCESS The destructor always returns EFI_SUCCESS.
-
-**/
-EFI_STATUS
-EFIAPI
-DebugCommunicationUsb3DxeDestructor (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
-{
- USB3_DEBUG_PORT_HANDLE *Instance;
-
- Instance = GetUsb3DebugPortInstance ();
- ASSERT (Instance != NULL);
-
- if (Instance->PciIoEvent != 0) {
- //
- // Close the event created.
- //
- gBS->CloseEvent ((EFI_EVENT)(UINTN)Instance->PciIoEvent);
- Instance->PciIoEvent = 0;
- }
-
- return EFI_SUCCESS;
-}
+/** @file + Debug Port Library implementation based on usb3 debug port. + + Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Base.h> +#include <PiDxe.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/HobLib.h> +#include <Protocol/PciIo.h> +#include <Protocol/IoMmu.h> +#include <Protocol/DxeSmmReadyToLock.h> +#include "DebugCommunicationLibUsb3Internal.h" + +GUID gUsb3DbgGuid = USB3_DBG_GUID; + +USB3_DEBUG_PORT_HANDLE mUsb3Instance = { USB3DBG_UNINITIALIZED }; +EFI_PHYSICAL_ADDRESS mUsb3InstanceAddr = 0; +EFI_PHYSICAL_ADDRESS *mUsb3InstanceAddrPtr = NULL; +EFI_PCI_IO_PROTOCOL *mUsb3PciIo = NULL; + +/** + Creates a named event that can be signaled. + + This function creates an event using NotifyTpl, NotifyFunction. + If Name is NULL, then ASSERT(). + If NotifyTpl is not a legal TPL value, then ASSERT(). + If NotifyFunction is NULL, then ASSERT(). + + @param Name Supplies the GUID name of the event. + @param NotifyTpl Supplies the task priority level of the event notifications. + @param NotifyFunction Supplies the function to notify when the event is signaled. + @param Event A pointer to the event created. + + @retval EFI_SUCCESS A named event was created. + @retval EFI_OUT_OF_RESOURCES There are not enough resource to create the named event. + +**/ +EFI_STATUS +EFIAPI +Usb3NamedEventListen ( + IN CONST EFI_GUID *Name, + IN EFI_TPL NotifyTpl, + IN EFI_EVENT_NOTIFY NotifyFunction, + IN EFI_EVENT *Event + ) +{ + EFI_STATUS Status; + VOID *RegistrationLocal; + + ASSERT (Name != NULL); + ASSERT (NotifyFunction != NULL); + ASSERT (NotifyTpl <= TPL_HIGH_LEVEL); + + // + // Create event + // + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + NotifyTpl, + NotifyFunction, + NULL, + Event + ); + ASSERT_EFI_ERROR (Status); + + // + // Register for an installation of protocol interface + // + Status = gBS->RegisterProtocolNotify ( + (EFI_GUID *)Name, + *Event, + &RegistrationLocal + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + +/** + USB3 map one DMA buffer. + + @param PciIo Pointer to PciIo for USB3 debug port. + @param Address DMA buffer address to be mapped. + @param NumberOfBytes Number of bytes to be mapped. + +**/ +VOID +Usb3MapOneDmaBuffer ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN EFI_PHYSICAL_ADDRESS Address, + IN UINTN NumberOfBytes + ) +{ + EFI_STATUS Status; + VOID *HostAddress; + EFI_PHYSICAL_ADDRESS DeviceAddress; + VOID *Mapping; + + HostAddress = (VOID *)(UINTN)Address; + Status = PciIo->Map ( + PciIo, + EfiPciIoOperationBusMasterCommonBuffer, + HostAddress, + &NumberOfBytes, + &DeviceAddress, + &Mapping + ); + ASSERT_EFI_ERROR (Status); + ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress)); +} + +/** + USB3 map DMA buffers. + + @param Instance Pointer to USB3 debug port instance. + @param PciIo Pointer to PciIo for USB3 debug port. + +**/ +VOID +Usb3MapDmaBuffers ( + IN USB3_DEBUG_PORT_HANDLE *Instance, + IN EFI_PCI_IO_PROTOCOL *PciIo + ) +{ + Usb3MapOneDmaBuffer ( + PciIo, + Instance->UrbIn.Data, + XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE * 2 + USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE + ); + + Usb3MapOneDmaBuffer ( + PciIo, + Instance->TransferRingIn.RingSeg0, + sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER + ); + + Usb3MapOneDmaBuffer ( + PciIo, + Instance->TransferRingOut.RingSeg0, + sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER + ); + + Usb3MapOneDmaBuffer ( + PciIo, + Instance->EventRing.EventRingSeg0, + sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER + ); + + Usb3MapOneDmaBuffer ( + PciIo, + Instance->EventRing.ERSTBase, + sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER + ); + + Usb3MapOneDmaBuffer ( + PciIo, + Instance->DebugCapabilityContext, + sizeof (XHC_DC_CONTEXT) + ); + + Usb3MapOneDmaBuffer ( + PciIo, + ((XHC_DC_CONTEXT *)(UINTN)Instance->DebugCapabilityContext)->DbcInfoContext.String0DescAddress, + STRING0_DESC_LEN + MANU_DESC_LEN + PRODUCT_DESC_LEN + SERIAL_DESC_LEN + ); +} + +/** + Invoke a notification event + + @param[in] Event Event whose notification function is being invoked. + @param[in] Context The pointer to the notification function's context, + which is implementation-dependent. + +**/ +VOID +EFIAPI +Usb3DxeSmmReadyToLockNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + USB3_DEBUG_PORT_HANDLE *Instance; + + DEBUG ((DEBUG_INFO, "%a()\n", __func__)); + + Instance = GetUsb3DebugPortInstance (); + ASSERT (Instance != NULL); + + Instance->InNotify = TRUE; + + // + // For the case that the USB3 debug port instance and DMA buffers are + // from PEI HOB with IOMMU enabled. + // Reinitialize USB3 debug port with granted DXE DMA buffer accessible + // by SMM environment. + // + InitializeUsbDebugHardware (Instance); + + // + // Wait some time for host to be ready after re-initialization. + // + MicroSecondDelay (1000000); + + Instance->InNotify = FALSE; + gBS->CloseEvent (Event); +} + +/** + USB3 get IOMMU protocol. + + @return Pointer to IOMMU protocol. + +**/ +EDKII_IOMMU_PROTOCOL * +Usb3GetIoMmu ( + VOID + ) +{ + EFI_STATUS Status; + EDKII_IOMMU_PROTOCOL *IoMmu; + + IoMmu = NULL; + Status = gBS->LocateProtocol ( + &gEdkiiIoMmuProtocolGuid, + NULL, + (VOID **)&IoMmu + ); + if (!EFI_ERROR (Status) && (IoMmu != NULL)) { + return IoMmu; + } + + return NULL; +} + +/** + Invoke a notification event + + @param[in] Event Event whose notification function is being invoked. + @param[in] Context The pointer to the notification function's context, + which is implementation-dependent. + +**/ +VOID +EFIAPI +Usb3PciIoNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + UINTN PciIoHandleCount; + EFI_HANDLE *PciIoHandleBuffer; + UINTN Index; + EFI_PCI_IO_PROTOCOL *PciIo; + UINTN PciSegment; + UINTN PciBusNumber; + UINTN PciDeviceNumber; + UINTN PciFunctionNumber; + UINT32 PciAddress; + USB3_DEBUG_PORT_HANDLE *Instance; + EFI_EVENT SmmReadyToLockEvent; + + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiPciIoProtocolGuid, + NULL, + &PciIoHandleCount, + &PciIoHandleBuffer + ); + if (!EFI_ERROR (Status) && + (PciIoHandleBuffer != NULL) && + (PciIoHandleCount != 0)) + { + for (Index = 0; Index < PciIoHandleCount; Index++) { + Status = gBS->HandleProtocol ( + PciIoHandleBuffer[Index], + &gEfiPciIoProtocolGuid, + (VOID **)&PciIo + ); + ASSERT_EFI_ERROR (Status); + Status = PciIo->GetLocation (PciIo, &PciSegment, &PciBusNumber, &PciDeviceNumber, &PciFunctionNumber); + ASSERT_EFI_ERROR (Status); + PciAddress = (UINT32)((PciBusNumber << 20) | (PciDeviceNumber << 15) | (PciFunctionNumber << 12)); + if (PciAddress == PcdGet32 (PcdUsbXhciPciAddress)) { + // + // Found the PciIo for USB3 debug port. + // + DEBUG ((DEBUG_INFO, "%a()\n", __func__)); + if (Usb3GetIoMmu () != NULL) { + Instance = GetUsb3DebugPortInstance (); + ASSERT (Instance != NULL); + if (Instance->Ready) { + Instance->InNotify = TRUE; + Usb3MapDmaBuffers (Instance, PciIo); + Instance->InNotify = FALSE; + + if (Instance->FromHob) { + mUsb3PciIo = PciIo; + Usb3NamedEventListen ( + &gEfiDxeSmmReadyToLockProtocolGuid, + TPL_NOTIFY, + Usb3DxeSmmReadyToLockNotify, + &SmmReadyToLockEvent + ); + } + } + } + + gBS->CloseEvent (Event); + break; + } + } + + gBS->FreePool (PciIoHandleBuffer); + } +} + +/** + Return USB3 debug instance address pointer. + +**/ +EFI_PHYSICAL_ADDRESS * +GetUsb3DebugPortInstanceAddrPtr ( + VOID + ) +{ + if (mUsb3InstanceAddrPtr == NULL) { + // + // Use the local variables temporarily. + // + mUsb3InstanceAddr = (EFI_PHYSICAL_ADDRESS)(UINTN)&mUsb3Instance; + mUsb3InstanceAddrPtr = &mUsb3InstanceAddr; + } + + return mUsb3InstanceAddrPtr; +} + +/** + Allocates pages that are suitable for an OperationBusMasterCommonBuffer or + OperationBusMasterCommonBuffer64 mapping. + + @param PciIo Pointer to PciIo for USB3 debug port. + @param Pages The number of pages to allocate. + @param Address A pointer to store the base system memory address of the + allocated range. + + @retval EFI_SUCCESS The requested memory pages were allocated. + @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are + MEMORY_WRITE_COMBINE and MEMORY_CACHED. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. + +**/ +EFI_STATUS +Usb3AllocateDmaBuffer ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINTN Pages, + OUT VOID **Address + ) +{ + EFI_STATUS Status; + + *Address = NULL; + Status = PciIo->AllocateBuffer ( + PciIo, + AllocateAnyPages, + EfiRuntimeServicesData, + Pages, + Address, + 0 + ); + if (!EFI_ERROR (Status)) { + Usb3MapOneDmaBuffer ( + PciIo, + (EFI_PHYSICAL_ADDRESS)(UINTN)*Address, + EFI_PAGES_TO_SIZE (Pages) + ); + } + + return Status; +} + +/** + Allocate aligned memory for XHC's usage. + + @param BufferSize The size, in bytes, of the Buffer. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +AllocateAlignBuffer ( + IN UINTN BufferSize + ) +{ + EFI_PHYSICAL_ADDRESS TmpAddr; + EFI_STATUS Status; + VOID *Buf; + + Buf = NULL; + + if (gBS != NULL) { + if (mUsb3PciIo != NULL) { + Usb3AllocateDmaBuffer ( + mUsb3PciIo, + EFI_SIZE_TO_PAGES (BufferSize), + &Buf + ); + } else { + TmpAddr = 0xFFFFFFFF; + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiACPIMemoryNVS, + EFI_SIZE_TO_PAGES (BufferSize), + &TmpAddr + ); + if (!EFI_ERROR (Status)) { + Buf = (VOID *)(UINTN)TmpAddr; + } + } + } + + return Buf; +} + +/** + The constructor function initialize USB3 debug port. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS. + +**/ +EFI_STATUS +EFIAPI +DebugCommunicationUsb3DxeConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_PHYSICAL_ADDRESS *AddrPtr; + USB3_DEBUG_PORT_HANDLE *Instance; + EFI_PHYSICAL_ADDRESS Address; + EFI_STATUS Status; + EFI_EVENT Event; + + Status = EfiGetSystemConfigurationTable (&gUsb3DbgGuid, (VOID **)&AddrPtr); + if (EFI_ERROR (Status) || (AddrPtr == NULL)) { + // + // Instead of using local variables, install system configuration table for + // the local instance and the buffer to save instance address pointer. + // + Address = SIZE_4GB; + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiACPIMemoryNVS, + EFI_SIZE_TO_PAGES (sizeof (EFI_PHYSICAL_ADDRESS) + sizeof (USB3_DEBUG_PORT_HANDLE)), + &Address + ); + if (EFI_ERROR (Status)) { + return Status; + } + + AddrPtr = (EFI_PHYSICAL_ADDRESS *)(UINTN)Address; + ZeroMem (AddrPtr, sizeof (EFI_PHYSICAL_ADDRESS) + sizeof (USB3_DEBUG_PORT_HANDLE)); + Instance = (USB3_DEBUG_PORT_HANDLE *)(AddrPtr + 1); + CopyMem (Instance, &mUsb3Instance, sizeof (USB3_DEBUG_PORT_HANDLE)); + *AddrPtr = (EFI_PHYSICAL_ADDRESS)(UINTN)Instance; + + Status = gBS->InstallConfigurationTable (&gUsb3DbgGuid, AddrPtr); + if (EFI_ERROR (Status)) { + return Status; + } + } + + if (mUsb3InstanceAddrPtr != NULL) { + *AddrPtr = *mUsb3InstanceAddrPtr; + } + + mUsb3InstanceAddrPtr = AddrPtr; + + Instance = GetUsb3DebugPortInstance (); + ASSERT (Instance != NULL); + + if (Instance->PciIoEvent == 0) { + Status = Usb3NamedEventListen ( + &gEfiPciIoProtocolGuid, + TPL_NOTIFY, + Usb3PciIoNotify, + &Event + ); + if (!EFI_ERROR (Status)) { + Instance->PciIoEvent = (EFI_PHYSICAL_ADDRESS)(UINTN)Event; + } + } + + return EFI_SUCCESS; +} + +/** + The destructor function. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The destructor always returns EFI_SUCCESS. + +**/ +EFI_STATUS +EFIAPI +DebugCommunicationUsb3DxeDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + USB3_DEBUG_PORT_HANDLE *Instance; + + Instance = GetUsb3DebugPortInstance (); + ASSERT (Instance != NULL); + + if (Instance->PciIoEvent != 0) { + // + // Close the event created. + // + gBS->CloseEvent ((EFI_EVENT)(UINTN)Instance->PciIoEvent); + Instance->PciIoEvent = 0; + } + + return EFI_SUCCESS; +} diff --git a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.inf b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.inf index 8f351fb2bc..abe37acfef 100644 --- a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.inf +++ b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.inf @@ -1,74 +1,74 @@ -## @file
-# Debug Communication Library instance based on usb3 debug port.
-#
-# Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-#
-##
-
-[Defines]
- INF_VERSION = 0x00010005
- BASE_NAME = DebugCommunicationLibUsb3Dxe
- MODULE_UNI_FILE = DebugCommunicationLibUsb3Dxe.uni
- FILE_GUID = C41F8C82-B3E6-47e0-A61D-0F9E429E6996
- MODULE_TYPE = DXE_DRIVER
- VERSION_STRING = 1.0
- LIBRARY_CLASS = DebugCommunicationLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER SMM_CORE
- CONSTRUCTOR = DebugCommunicationUsb3DxeConstructor
- DESTRUCTOR = DebugCommunicationUsb3DxeDestructor
-
-#
-# The following information is for reference only and not required by the build tools.
-#
-# VALID_ARCHITECTURES = IA32 X64
-#
-
-[Sources]
- DebugCommunicationLibUsb3Dxe.c
- DebugCommunicationLibUsb3Transfer.c
- DebugCommunicationLibUsb3Common.c
- DebugCommunicationLibUsb3Internal.h
-
-[Packages]
- MdePkg/MdePkg.dec
- MdeModulePkg/MdeModulePkg.dec
- SourceLevelDebugPkg/SourceLevelDebugPkg.dec
-
-[Pcd]
- # The memory BAR of ehci host controller, in which usb debug feature is enabled.
- # Note that the memory BAR address is only used before Pci bus resource allocation.
- gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciMemorySpaceBase ## SOMETIMES_CONSUMES
-
- # The pci address of ehci host controller, in which usb debug feature is enabled.
- # The format of pci address please refer to SourceLevelDebugPkg.dec
- gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciPciAddress ## CONSUMES
-
- # Per XHCI spec, software shall impose a timeout between the detection of the Debug Host
- # connection and the DbC Run transition to 1. This PCD specifies the timeout value in microsecond.
- gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciDebugDetectTimeout ## SOMETIMES_CONSUMES
-
- # The value of data buffer size used for USB debug port handle.
- # It should be equal to sizeof (USB3_DEBUG_PORT_HANDLE).
- gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdDebugPortHandleBufferSize|249 ## SOMETIMES_CONSUMES
-
-[Protocols]
- ## NOTIFY
- ## SOMETIMES_CONSUMES
- gEfiPciIoProtocolGuid
- gEdkiiIoMmuProtocolGuid ## SOMETIMES_CONSUMES
- ## NOTIFY
- ## SOMETIMES_CONSUMES
- gEfiDxeSmmReadyToLockProtocolGuid
-
-[LibraryClasses]
- BaseLib
- PcdLib
- IoLib
- PciLib
- TimerLib
- UefiBootServicesTableLib
- UefiLib
- BaseMemoryLib
- HobLib
+## @file +# Debug Communication Library instance based on usb3 debug port. +# +# Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DebugCommunicationLibUsb3Dxe + MODULE_UNI_FILE = DebugCommunicationLibUsb3Dxe.uni + FILE_GUID = C41F8C82-B3E6-47e0-A61D-0F9E429E6996 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = DebugCommunicationLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER SMM_CORE + CONSTRUCTOR = DebugCommunicationUsb3DxeConstructor + DESTRUCTOR = DebugCommunicationUsb3DxeDestructor + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + DebugCommunicationLibUsb3Dxe.c + DebugCommunicationLibUsb3Transfer.c + DebugCommunicationLibUsb3Common.c + DebugCommunicationLibUsb3Internal.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SourceLevelDebugPkg/SourceLevelDebugPkg.dec + +[Pcd] + # The memory BAR of ehci host controller, in which usb debug feature is enabled. + # Note that the memory BAR address is only used before Pci bus resource allocation. + gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciMemorySpaceBase ## SOMETIMES_CONSUMES + + # The pci address of ehci host controller, in which usb debug feature is enabled. + # The format of pci address please refer to SourceLevelDebugPkg.dec + gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciPciAddress ## CONSUMES + + # Per XHCI spec, software shall impose a timeout between the detection of the Debug Host + # connection and the DbC Run transition to 1. This PCD specifies the timeout value in microsecond. + gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciDebugDetectTimeout ## SOMETIMES_CONSUMES + + # The value of data buffer size used for USB debug port handle. + # It should be equal to sizeof (USB3_DEBUG_PORT_HANDLE). + gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdDebugPortHandleBufferSize|249 ## SOMETIMES_CONSUMES + +[Protocols] + ## NOTIFY + ## SOMETIMES_CONSUMES + gEfiPciIoProtocolGuid + gEdkiiIoMmuProtocolGuid ## SOMETIMES_CONSUMES + ## NOTIFY + ## SOMETIMES_CONSUMES + gEfiDxeSmmReadyToLockProtocolGuid + +[LibraryClasses] + BaseLib + PcdLib + IoLib + PciLib + TimerLib + UefiBootServicesTableLib + UefiLib + BaseMemoryLib + HobLib diff --git a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.uni b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.uni index 244b25d771..b2cd0431cb 100644 --- a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.uni +++ b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.uni @@ -1,16 +1,16 @@ -// /** @file
-// Debug Communication Library instance based on USB3 debug port for DXE and SMM modules.
-//
-// Debug Communication Library instance based on USB3 debug port for DXE and SMM modules.
-//
-// Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
-//
-// SPDX-License-Identifier: BSD-2-Clause-Patent
-//
-// **/
-
-
-#string STR_MODULE_ABSTRACT #language en-US "Debug Communication Library instance based on USB3 debug port for DXE and SMM modules"
-
-#string STR_MODULE_DESCRIPTION #language en-US "Debug Communication Library instance based on USB3 debug port for DXE and SMM modules."
-
+// /** @file +// Debug Communication Library instance based on USB3 debug port for DXE and SMM modules. +// +// Debug Communication Library instance based on USB3 debug port for DXE and SMM modules. +// +// Copyright (c) 2014, Intel Corporation. All rights reserved.<BR> +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Debug Communication Library instance based on USB3 debug port for DXE and SMM modules" + +#string STR_MODULE_DESCRIPTION #language en-US "Debug Communication Library instance based on USB3 debug port for DXE and SMM modules." + diff --git a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Internal.h b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Internal.h index cc5f294f33..8fd9105b88 100644 --- a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Internal.h +++ b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Internal.h @@ -1,737 +1,737 @@ -/** @file
- Debug Port Library implementation based on usb3 debug port.
-
- Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef __USB3_DEBUG_PORT_LIB_INTERNAL__
-#define __USB3_DEBUG_PORT_LIB_INTERNAL__
-
-#include <Uefi.h>
-#include <Base.h>
-#include <IndustryStandard/Usb.h>
-#include <Library/IoLib.h>
-#include <IndustryStandard/Pci.h>
-#include <Library/PcdLib.h>
-#include <Library/UefiLib.h>
-#include <Library/UefiBootServicesTableLib.h>
-#include <Library/MemoryAllocationLib.h>
-#include <Library/DebugLib.h>
-#include <Library/BaseMemoryLib.h>
-#include <Library/BaseLib.h>
-#include <Library/TimerLib.h>
-#include <Library/DebugCommunicationLib.h>
-#include <Library/PciLib.h>
-
-//
-// USB Debug GUID value
-//
-#define USB3_DBG_GUID \
- { \
- 0xb2a56f4d, 0x9177, 0x4fc8, { 0xa6, 0x77, 0xdd, 0x96, 0x3e, 0xb4, 0xcb, 0x1b } \
- }
-
-//
-// The state machine of usb debug port
-//
-#define USB3DBG_NO_DBG_CAB 0 // The XHCI host controller does not support debug capability
-#define USB3DBG_DBG_CAB 1 // The XHCI host controller supports debug capability
-#define USB3DBG_ENABLED 2 // The XHCI debug device is enabled
-#define USB3DBG_NOT_ENABLED 4 // The XHCI debug device is not enabled
-#define USB3DBG_UNINITIALIZED 255 // The XHCI debug device is uninitialized
-
-#define USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE 0x08
-
-//
-// MaxPacketSize for DbC Endpoint Descriptor IN and OUT
-//
-#define XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE 0x400
-
-#define XHCI_DEBUG_DEVICE_VENDOR_ID 0x0525
-#define XHCI_DEBUG_DEVICE_PRODUCT_ID 0x127A
-#define XHCI_DEBUG_DEVICE_PROTOCOL 0xFF
-#define XHCI_DEBUG_DEVICE_REVISION 0x00
-
-#define XHCI_BASE_ADDRESS_64_BIT_MASK 0xFFFFFFFFFFFF0000ULL
-#define XHCI_BASE_ADDRESS_32_BIT_MASK 0xFFFF0000
-
-#define PCI_CAPABILITY_ID_DEBUG_PORT 0x0A
-#define XHC_HCCPARAMS_OFFSET 0x10
-#define XHC_CAPABILITY_ID_MASK 0xFF
-#define XHC_NEXT_CAPABILITY_MASK 0xFF00
-
-#define XHC_HCSPARAMS1_OFFSET 0x4 // Structural Parameters 1
-#define XHC_USBCMD_OFFSET 0x0 // USB Command Register Offset
-#define XHC_USBSTS_OFFSET 0x4 // USB Status Register Offset
-#define XHC_PORTSC_OFFSET 0x400 // Port Status and Control Register Offset
-
-#define XHC_USBCMD_RUN BIT0 // Run/Stop
-#define XHC_USBCMD_RESET BIT1 // Host Controller Reset
-
-#define XHC_USBSTS_HALT BIT0
-
-//
-// Indicate the timeout when data is transferred in microsecond. 0 means infinite timeout.
-//
-#define DATA_TRANSFER_WRITE_TIMEOUT 0
-#define DATA_TRANSFER_READ_TIMEOUT 50000
-#define DATA_TRANSFER_POLL_TIMEOUT 1000
-#define XHC_DEBUG_PORT_1_MILLISECOND 1000
-//
-// XHCI port power off/on delay
-//
-#define XHC_DEBUG_PORT_ON_OFF_DELAY 100000
-
-//
-// USB debug device string descriptor (header size + unicode string length)
-//
-#define STRING0_DESC_LEN 4
-#define MANU_DESC_LEN 12
-#define PRODUCT_DESC_LEN 40
-#define SERIAL_DESC_LEN 4
-
-//
-// Debug Capability Register Offset
-//
-#define XHC_DC_DCID 0x0
-#define XHC_DC_DCDB 0x4
-#define XHC_DC_DCERSTSZ 0x8
-#define XHC_DC_DCERSTBA 0x10
-#define XHC_DC_DCERDP 0x18
-#define XHC_DC_DCCTRL 0x20
-#define XHC_DC_DCST 0x24
-#define XHC_DC_DCPORTSC 0x28
-#define XHC_DC_DCCP 0x30
-#define XHC_DC_DCDDI1 0x38
-#define XHC_DC_DCDDI2 0x3C
-
-#define TRB_TYPE_LINK 6
-
-#define ERST_NUMBER 0x01
-#define TR_RING_TRB_NUMBER 0x100
-#define EVENT_RING_TRB_NUMBER 0x200
-
-#define ED_BULK_OUT 2
-#define ED_BULK_IN 6
-
-#define XHC_LOW_32BIT(Addr64) ((UINT32)(((UINTN)(Addr64)) & 0xFFFFFFFF))
-#define XHC_HIGH_32BIT(Addr64) ((UINT32)(RShiftU64((UINT64)(UINTN)(Addr64), 32) & 0xFFFFFFFF))
-#define XHC_BIT_IS_SET(Data, Bit) ((BOOLEAN)(((Data) & (Bit)) == (Bit)))
-
-//
-// Endpoint Type (EP Type).
-//
-#define ED_NOT_VALID 0
-#define ED_ISOCH_OUT 1
-#define ED_BULK_OUT 2
-#define ED_INTERRUPT_OUT 3
-#define ED_CONTROL_BIDIR 4
-#define ED_ISOCH_IN 5
-#define ED_BULK_IN 6
-#define ED_INTERRUPT_IN 7
-
-//
-// 6.4.5 TRB Completion Codes
-//
-#define TRB_COMPLETION_INVALID 0
-#define TRB_COMPLETION_SUCCESS 1
-#define TRB_COMPLETION_DATA_BUFFER_ERROR 2
-#define TRB_COMPLETION_BABBLE_ERROR 3
-#define TRB_COMPLETION_USB_TRANSACTION_ERROR 4
-#define TRB_COMPLETION_TRB_ERROR 5
-#define TRB_COMPLETION_STALL_ERROR 6
-#define TRB_COMPLETION_SHORT_PACKET 13
-
-//
-// 6.4.6 TRB Types
-//
-#define TRB_TYPE_NORMAL 1
-#define TRB_TYPE_SETUP_STAGE 2
-#define TRB_TYPE_DATA_STAGE 3
-#define TRB_TYPE_STATUS_STAGE 4
-#define TRB_TYPE_ISOCH 5
-#define TRB_TYPE_LINK 6
-#define TRB_TYPE_EVENT_DATA 7
-#define TRB_TYPE_NO_OP 8
-#define TRB_TYPE_EN_SLOT 9
-#define TRB_TYPE_DIS_SLOT 10
-#define TRB_TYPE_ADDRESS_DEV 11
-#define TRB_TYPE_CON_ENDPOINT 12
-#define TRB_TYPE_EVALU_CONTXT 13
-#define TRB_TYPE_RESET_ENDPOINT 14
-#define TRB_TYPE_STOP_ENDPOINT 15
-#define TRB_TYPE_SET_TR_DEQUE 16
-#define TRB_TYPE_RESET_DEV 17
-#define TRB_TYPE_GET_PORT_BANW 21
-#define TRB_TYPE_FORCE_HEADER 22
-#define TRB_TYPE_NO_OP_COMMAND 23
-#define TRB_TYPE_TRANS_EVENT 32
-#define TRB_TYPE_COMMAND_COMPLT_EVENT 33
-#define TRB_TYPE_PORT_STATUS_CHANGE_EVENT 34
-#define TRB_TYPE_HOST_CONTROLLER_EVENT 37
-#define TRB_TYPE_DEVICE_NOTIFI_EVENT 38
-#define TRB_TYPE_MFINDEX_WRAP_EVENT 39
-
-//
-// Convert millisecond to microsecond.
-//
-#define XHC_1_MILLISECOND (1000)
-#define XHC_POLL_DELAY (1000)
-#define XHC_GENERIC_TIMEOUT (10 * 1000)
-
-#define EFI_USB_SPEED_FULL 0x0000 ///< 12 Mb/s, USB 1.1 OHCI and UHCI HC.
-#define EFI_USB_SPEED_LOW 0x0001 ///< 1 Mb/s, USB 1.1 OHCI and UHCI HC.
-#define EFI_USB_SPEED_HIGH 0x0002 ///< 480 Mb/s, USB 2.0 EHCI HC.
-#define EFI_USB_SPEED_SUPER 0x0003 ///< 4.8 Gb/s, USB 3.0 XHCI HC.
-
-//
-// Transfer types, used in URB to identify the transfer type
-//
-#define XHC_CTRL_TRANSFER 0x01
-#define XHC_BULK_TRANSFER 0x02
-#define XHC_INT_TRANSFER_SYNC 0x04
-#define XHC_INT_TRANSFER_ASYNC 0x08
-#define XHC_INT_ONLY_TRANSFER_ASYNC 0x10
-
-//
-// USB Transfer Results
-//
-#define EFI_USB_NOERROR 0x00
-#define EFI_USB_ERR_NOTEXECUTE 0x01
-#define EFI_USB_ERR_STALL 0x02
-#define EFI_USB_ERR_BUFFER 0x04
-#define EFI_USB_ERR_BABBLE 0x08
-#define EFI_USB_ERR_NAK 0x10
-#define EFI_USB_ERR_CRC 0x20
-#define EFI_USB_ERR_TIMEOUT 0x40
-#define EFI_USB_ERR_BITSTUFF 0x80
-#define EFI_USB_ERR_SYSTEM 0x100
-
-#pragma pack(1)
-
-//
-// 7.6.9 OUT/IN EP Context: 64 bytes
-// 7.6.9.2 When used by the DbC it is always a 64 byte data structure
-//
-typedef struct _ENDPOINT_CONTEXT_64 {
- UINT32 EPState : 3;
- UINT32 RsvdZ1 : 5;
- UINT32 Mult : 2; // set to 0
- UINT32 MaxPStreams : 5; // set to 0
- UINT32 LSA : 1; // set to 0
- UINT32 Interval : 8; // set to 0
- UINT32 RsvdZ2 : 8;
-
- UINT32 RsvdZ3 : 1;
- UINT32 CErr : 2;
- UINT32 EPType : 3;
- UINT32 RsvdZ4 : 1;
- UINT32 HID : 1; // set to 0
- UINT32 MaxBurstSize : 8;
- UINT32 MaxPacketSize : 16;
-
- UINT32 PtrLo;
-
- UINT32 PtrHi;
-
- UINT32 AverageTRBLength : 16;
- UINT32 MaxESITPayload : 16; // set to 0
-
- UINT32 RsvdZ5; // Reserved
- UINT32 RsvdZ6;
- UINT32 RsvdZ7;
-
- UINT32 RsvdZ8;
- UINT32 RsvdZ9;
- UINT32 RsvdZ10;
- UINT32 RsvdZ11;
-
- UINT32 RsvdZ12;
- UINT32 RsvdZ13;
- UINT32 RsvdZ14;
- UINT32 RsvdZ15;
-} ENDPOINT_CONTEXT_64;
-
-//
-// 6.4.1.1 Normal TRB: 16 bytes
-// A Normal TRB is used in several ways; exclusively on Bulk and Interrupt Transfer Rings for normal and
-// Scatter/Gather operations, to define additional data buffers for Scatter/Gather operations on Isoch Transfer
-// Rings, and to define the Data stage information for Control Transfer Rings.
-//
-typedef struct _TRANSFER_TRB_NORMAL {
- UINT32 TRBPtrLo;
-
- UINT32 TRBPtrHi;
-
- UINT32 Length : 17;
- UINT32 TDSize : 5;
- UINT32 IntTarget : 10;
-
- UINT32 CycleBit : 1;
- UINT32 ENT : 1;
- UINT32 ISP : 1;
- UINT32 NS : 1;
- UINT32 CH : 1;
- UINT32 IOC : 1;
- UINT32 IDT : 1;
- UINT32 RsvdZ1 : 2;
- UINT32 BEI : 1;
- UINT32 Type : 6;
- UINT32 RsvdZ2 : 16;
-} TRANSFER_TRB_NORMAL;
-
-//
-// 6.4.2.1 Transfer Event TRB: 16 bytes
-// A Transfer Event provides the completion status associated with a Transfer TRB. Refer to section 4.11.3.1
-// for more information on the use and operation of Transfer Events.
-//
-typedef struct _EVT_TRB_TRANSFER {
- UINT32 TRBPtrLo;
-
- UINT32 TRBPtrHi;
-
- UINT32 Length : 24;
- UINT32 Completecode : 8;
-
- UINT32 CycleBit : 1;
- UINT32 RsvdZ1 : 1;
- UINT32 ED : 1;
- UINT32 RsvdZ2 : 7;
- UINT32 Type : 6;
- UINT32 EndpointId : 5;
- UINT32 RsvdZ3 : 3;
- UINT32 SlotId : 8;
-} EVT_TRB_TRANSFER;
-
-//
-// 6.4.4.1 Link TRB: 16 bytes
-// A Link TRB provides support for non-contiguous TRB Rings.
-//
-typedef struct _LINK_TRB {
- UINT32 PtrLo;
-
- UINT32 PtrHi;
-
- UINT32 RsvdZ1 : 22;
- UINT32 InterTarget : 10;
-
- UINT32 CycleBit : 1;
- UINT32 TC : 1;
- UINT32 RsvdZ2 : 2;
- UINT32 CH : 1;
- UINT32 IOC : 1;
- UINT32 RsvdZ3 : 4;
- UINT32 Type : 6;
- UINT32 RsvdZ4 : 16;
-} LINK_TRB;
-
-//
-// TRB Template: 16 bytes
-//
-typedef struct _TRB_TEMPLATE {
- UINT32 Parameter1;
-
- UINT32 Parameter2;
-
- UINT32 Status;
-
- UINT32 CycleBit : 1;
- UINT32 RsvdZ1 : 9;
- UINT32 Type : 6;
- UINT32 Control : 16;
-} TRB_TEMPLATE;
-
-//
-// Refer to XHCI 6.5 Event Ring Segment Table: 16 bytes
-//
-typedef struct _EVENT_RING_SEG_TABLE_ENTRY {
- UINT32 PtrLo;
- UINT32 PtrHi;
- UINT32 RingTrbSize : 16;
- UINT32 RsvdZ1 : 16;
- UINT32 RsvdZ2;
-} EVENT_RING_SEG_TABLE_ENTRY;
-
-//
-// Size: 40 bytes
-//
-typedef struct _EVENT_RING {
- EFI_PHYSICAL_ADDRESS ERSTBase;
- EFI_PHYSICAL_ADDRESS EventRingSeg0;
- UINT32 TrbNumber;
- EFI_PHYSICAL_ADDRESS EventRingEnqueue;
- EFI_PHYSICAL_ADDRESS EventRingDequeue;
- UINT32 EventRingCCS;
-} EVENT_RING;
-
-// Size: 32 bytes
-typedef struct _TRANSFER_RING {
- EFI_PHYSICAL_ADDRESS RingSeg0;
- UINT32 TrbNumber;
- EFI_PHYSICAL_ADDRESS RingEnqueue;
- EFI_PHYSICAL_ADDRESS RingDequeue;
- UINT32 RingPCS;
-} TRANSFER_RING;
-
-//
-// Size: 64 bytes
-//
-typedef struct _DBC_INFO_CONTEXT {
- UINT64 String0DescAddress;
- UINT64 ManufacturerStrDescAddress;
- UINT64 ProductStrDescAddress;
- UINT64 SerialNumberStrDescAddress;
- UINT64 String0Length : 8;
- UINT64 ManufacturerStrLength : 8;
- UINT64 ProductStrLength : 8;
- UINT64 SerialNumberStrLength : 8;
- UINT64 RsvdZ1 : 32;
- UINT64 RsvdZ2;
- UINT64 RsvdZ3;
- UINT64 RsvdZ4;
-} DBC_INFO_CONTEXT;
-
-//
-// Debug Capability Context Data Structure: 192 bytes
-//
-typedef struct _XHC_DC_CONTEXT {
- DBC_INFO_CONTEXT DbcInfoContext;
- ENDPOINT_CONTEXT_64 EpOutContext;
- ENDPOINT_CONTEXT_64 EpInContext;
-} XHC_DC_CONTEXT;
-
-//
-// Size: 16 bytes
-//
-typedef union _TRB {
- TRB_TEMPLATE TrbTemplate;
- TRANSFER_TRB_NORMAL TrbNormal;
-} TRB;
-
-///
-/// USB data transfer direction
-///
-typedef enum {
- EfiUsbDataIn,
- EfiUsbDataOut,
- EfiUsbNoData
-} EFI_USB_DATA_DIRECTION;
-
-//
-// URB (Usb Request Block) contains information for all kinds of
-// usb requests.
-//
-typedef struct _URB {
- //
- // Transfer data buffer
- //
- EFI_PHYSICAL_ADDRESS Data;
- UINT32 DataLen;
-
- //
- // Execute result
- //
- UINT32 Result;
- //
- // Completed data length
- //
- UINT32 Completed;
- //
- // Tranfer Ring info
- //
- EFI_PHYSICAL_ADDRESS Ring;
- EFI_PHYSICAL_ADDRESS Trb;
- BOOLEAN Finished;
- EFI_USB_DATA_DIRECTION Direction;
-} URB;
-
-typedef struct _USB3_DEBUG_PORT_INSTANCE {
- UINT8 Initialized;
-
- //
- // The flag indicates debug capability is supported
- //
- BOOLEAN DebugSupport;
-
- //
- // The flag indicates debug device is ready
- //
- BOOLEAN Ready;
-
- //
- // The flag indicates the instance is from HOB
- //
- BOOLEAN FromHob;
-
- //
- // Prevent notification being interrupted by debug timer
- //
- BOOLEAN InNotify;
-
- //
- // PciIo protocol event
- //
- EFI_PHYSICAL_ADDRESS PciIoEvent;
-
- //
- // The flag indicates if USB 3.0 ports has been turn off/on power
- //
- BOOLEAN ChangePortPower;
-
- //
- // XHCI MMIO Base address
- //
- EFI_PHYSICAL_ADDRESS XhciMmioBase;
-
- //
- // XHCI OP RegisterBase address
- //
- EFI_PHYSICAL_ADDRESS XhciOpRegister;
-
- //
- // XHCI Debug Register Base Address
- //
- EFI_PHYSICAL_ADDRESS DebugCapabilityBase;
-
- //
- // XHCI Debug Capability offset
- //
- UINT64 DebugCapabilityOffset;
-
- //
- // XHCI Debug Context Address
- //
- EFI_PHYSICAL_ADDRESS DebugCapabilityContext;
-
- //
- // Transfer Ring
- //
- TRANSFER_RING TransferRingOut;
- TRANSFER_RING TransferRingIn;
-
- //
- // EventRing
- //
- EVENT_RING EventRing;
-
- //
- // URB - Read
- //
- URB UrbOut;
-
- //
- // URB - Write
- //
- URB UrbIn;
-
- //
- // The available data length in the following data buffer.
- //
- UINT8 DataCount;
- //
- // The data buffer address for data read and poll.
- //
- EFI_PHYSICAL_ADDRESS Data;
-} USB3_DEBUG_PORT_HANDLE;
-
-#pragma pack()
-
-/**
- Read XHCI debug register.
-
- @param Handle Debug port handle.
- @param Offset The offset of the debug register.
-
- @return The register content read
-
-**/
-UINT32
-XhcReadDebugReg (
- IN USB3_DEBUG_PORT_HANDLE *Handle,
- IN UINT32 Offset
- );
-
-/**
- Set one bit of the debug register while keeping other bits.
-
- @param Handle Debug port handle.
- @param Offset The offset of the debug register.
- @param Bit The bit mask of the register to set.
-
-**/
-VOID
-XhcSetDebugRegBit (
- IN USB3_DEBUG_PORT_HANDLE *Handle,
- IN UINT32 Offset,
- IN UINT32 Bit
- );
-
-/**
- Write the data to the debug register.
-
- @param Handle Debug port handle.
- @param Offset The offset of the debug register.
- @param Data The data to write.
-
-**/
-VOID
-XhcWriteDebugReg (
- IN USB3_DEBUG_PORT_HANDLE *Handle,
- IN UINT32 Offset,
- IN UINT32 Data
- );
-
-/**
- Verifies if the bit positions specified by a mask are set in a register.
-
- @param[in, out] Register UINTN register
- @param[in] BitMask 32-bit mask
-
- @return BOOLEAN - TRUE if all bits specified by the mask are enabled.
- - FALSE even if one of the bits specified by the mask
- is not enabled.
-**/
-BOOLEAN
-XhcIsBitSet (
- UINTN Register,
- UINT32 BitMask
- );
-
-/**
- Sets bits as per the enabled bit positions in the mask.
-
- @param[in, out] Register UINTN register
- @param[in] BitMask 32-bit mask
-**/
-VOID
-XhcSetR32Bit (
- UINTN Register,
- UINT32 BitMask
- );
-
-/**
- Clears bits as per the enabled bit positions in the mask.
-
- @param[in, out] Register UINTN register
- @param[in] BitMask 32-bit mask
-**/
-VOID
-XhcClearR32Bit (
- IN OUT UINTN Register,
- IN UINT32 BitMask
- );
-
-/**
- Initialize USB3 debug port.
-
- This method invokes various internal functions to facilitate
- detection and initialization of USB3 debug port.
-
- @retval RETURN_SUCCESS The serial device was initialized.
-**/
-RETURN_STATUS
-EFIAPI
-USB3Initialize (
- VOID
- );
-
-/**
- Return command register value in XHCI controller.
-
-**/
-UINT16
-GetXhciPciCommand (
- VOID
- );
-
-/**
- Allocate aligned memory for XHC's usage.
-
- @param BufferSize The size, in bytes, of the Buffer.
-
- @return A pointer to the allocated buffer or NULL if allocation fails.
-
-**/
-VOID *
-AllocateAlignBuffer (
- IN UINTN BufferSize
- );
-
-/**
- The real function to initialize USB3 debug port.
-
- This method invokes various internal functions to facilitate
- detection and initialization of USB3 debug port.
-
- @retval RETURN_SUCCESS The serial device was initialized.
-**/
-RETURN_STATUS
-EFIAPI
-USB3InitializeReal (
- VOID
- );
-
-/**
- Submits bulk transfer to a bulk endpoint of a USB device.
-
- @param Handle The instance of debug device.
- @param Direction The direction of data transfer.
- @param Data Array of pointers to the buffers of data to transmit
- from or receive into.
- @param DataLength The length of the data buffer.
- @param Timeout Indicates the maximum time, in millisecond, which
- the transfer is allowed to complete.
-
- @retval EFI_SUCCESS The transfer was completed successfully.
- @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
- @retval EFI_INVALID_PARAMETER Some parameters are invalid.
- @retval EFI_TIMEOUT The transfer failed due to timeout.
- @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
-
-**/
-EFI_STATUS
-EFIAPI
-XhcDataTransfer (
- IN USB3_DEBUG_PORT_HANDLE *Handle,
- IN EFI_USB_DATA_DIRECTION Direction,
- IN OUT VOID *Data,
- IN OUT UINTN *DataLength,
- IN UINTN Timeout
- );
-
-/**
- Initialize usb debug port hardware.
-
- @param Handle Debug port handle.
-
- @retval TRUE The usb debug port hardware configuration is changed.
- @retval FALSE The usb debug port hardware configuration is not changed.
-
-**/
-RETURN_STATUS
-EFIAPI
-InitializeUsbDebugHardware (
- IN USB3_DEBUG_PORT_HANDLE *Handle
- );
-
-/**
- Return USB3 debug instance address pointer.
-
-**/
-EFI_PHYSICAL_ADDRESS *
-GetUsb3DebugPortInstanceAddrPtr (
- VOID
- );
-
-/**
- Return USB3 debug instance address.
-
-**/
-USB3_DEBUG_PORT_HANDLE *
-GetUsb3DebugPortInstance (
- VOID
- );
-
-#endif //__SERIAL_PORT_LIB_USB__
+/** @file + Debug Port Library implementation based on usb3 debug port. + + Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __USB3_DEBUG_PORT_LIB_INTERNAL__ +#define __USB3_DEBUG_PORT_LIB_INTERNAL__ + +#include <Uefi.h> +#include <Base.h> +#include <IndustryStandard/Usb.h> +#include <Library/IoLib.h> +#include <IndustryStandard/Pci.h> +#include <Library/PcdLib.h> +#include <Library/UefiLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/DebugLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/BaseLib.h> +#include <Library/TimerLib.h> +#include <Library/DebugCommunicationLib.h> +#include <Library/PciLib.h> + +// +// USB Debug GUID value +// +#define USB3_DBG_GUID \ + { \ + 0xb2a56f4d, 0x9177, 0x4fc8, { 0xa6, 0x77, 0xdd, 0x96, 0x3e, 0xb4, 0xcb, 0x1b } \ + } + +// +// The state machine of usb debug port +// +#define USB3DBG_NO_DBG_CAB 0 // The XHCI host controller does not support debug capability +#define USB3DBG_DBG_CAB 1 // The XHCI host controller supports debug capability +#define USB3DBG_ENABLED 2 // The XHCI debug device is enabled +#define USB3DBG_NOT_ENABLED 4 // The XHCI debug device is not enabled +#define USB3DBG_UNINITIALIZED 255 // The XHCI debug device is uninitialized + +#define USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE 0x08 + +// +// MaxPacketSize for DbC Endpoint Descriptor IN and OUT +// +#define XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE 0x400 + +#define XHCI_DEBUG_DEVICE_VENDOR_ID 0x0525 +#define XHCI_DEBUG_DEVICE_PRODUCT_ID 0x127A +#define XHCI_DEBUG_DEVICE_PROTOCOL 0xFF +#define XHCI_DEBUG_DEVICE_REVISION 0x00 + +#define XHCI_BASE_ADDRESS_64_BIT_MASK 0xFFFFFFFFFFFF0000ULL +#define XHCI_BASE_ADDRESS_32_BIT_MASK 0xFFFF0000 + +#define PCI_CAPABILITY_ID_DEBUG_PORT 0x0A +#define XHC_HCCPARAMS_OFFSET 0x10 +#define XHC_CAPABILITY_ID_MASK 0xFF +#define XHC_NEXT_CAPABILITY_MASK 0xFF00 + +#define XHC_HCSPARAMS1_OFFSET 0x4 // Structural Parameters 1 +#define XHC_USBCMD_OFFSET 0x0 // USB Command Register Offset +#define XHC_USBSTS_OFFSET 0x4 // USB Status Register Offset +#define XHC_PORTSC_OFFSET 0x400 // Port Status and Control Register Offset + +#define XHC_USBCMD_RUN BIT0 // Run/Stop +#define XHC_USBCMD_RESET BIT1 // Host Controller Reset + +#define XHC_USBSTS_HALT BIT0 + +// +// Indicate the timeout when data is transferred in microsecond. 0 means infinite timeout. +// +#define DATA_TRANSFER_WRITE_TIMEOUT 0 +#define DATA_TRANSFER_READ_TIMEOUT 50000 +#define DATA_TRANSFER_POLL_TIMEOUT 1000 +#define XHC_DEBUG_PORT_1_MILLISECOND 1000 +// +// XHCI port power off/on delay +// +#define XHC_DEBUG_PORT_ON_OFF_DELAY 100000 + +// +// USB debug device string descriptor (header size + unicode string length) +// +#define STRING0_DESC_LEN 4 +#define MANU_DESC_LEN 12 +#define PRODUCT_DESC_LEN 40 +#define SERIAL_DESC_LEN 4 + +// +// Debug Capability Register Offset +// +#define XHC_DC_DCID 0x0 +#define XHC_DC_DCDB 0x4 +#define XHC_DC_DCERSTSZ 0x8 +#define XHC_DC_DCERSTBA 0x10 +#define XHC_DC_DCERDP 0x18 +#define XHC_DC_DCCTRL 0x20 +#define XHC_DC_DCST 0x24 +#define XHC_DC_DCPORTSC 0x28 +#define XHC_DC_DCCP 0x30 +#define XHC_DC_DCDDI1 0x38 +#define XHC_DC_DCDDI2 0x3C + +#define TRB_TYPE_LINK 6 + +#define ERST_NUMBER 0x01 +#define TR_RING_TRB_NUMBER 0x100 +#define EVENT_RING_TRB_NUMBER 0x200 + +#define ED_BULK_OUT 2 +#define ED_BULK_IN 6 + +#define XHC_LOW_32BIT(Addr64) ((UINT32)(((UINTN)(Addr64)) & 0xFFFFFFFF)) +#define XHC_HIGH_32BIT(Addr64) ((UINT32)(RShiftU64((UINT64)(UINTN)(Addr64), 32) & 0xFFFFFFFF)) +#define XHC_BIT_IS_SET(Data, Bit) ((BOOLEAN)(((Data) & (Bit)) == (Bit))) + +// +// Endpoint Type (EP Type). +// +#define ED_NOT_VALID 0 +#define ED_ISOCH_OUT 1 +#define ED_BULK_OUT 2 +#define ED_INTERRUPT_OUT 3 +#define ED_CONTROL_BIDIR 4 +#define ED_ISOCH_IN 5 +#define ED_BULK_IN 6 +#define ED_INTERRUPT_IN 7 + +// +// 6.4.5 TRB Completion Codes +// +#define TRB_COMPLETION_INVALID 0 +#define TRB_COMPLETION_SUCCESS 1 +#define TRB_COMPLETION_DATA_BUFFER_ERROR 2 +#define TRB_COMPLETION_BABBLE_ERROR 3 +#define TRB_COMPLETION_USB_TRANSACTION_ERROR 4 +#define TRB_COMPLETION_TRB_ERROR 5 +#define TRB_COMPLETION_STALL_ERROR 6 +#define TRB_COMPLETION_SHORT_PACKET 13 + +// +// 6.4.6 TRB Types +// +#define TRB_TYPE_NORMAL 1 +#define TRB_TYPE_SETUP_STAGE 2 +#define TRB_TYPE_DATA_STAGE 3 +#define TRB_TYPE_STATUS_STAGE 4 +#define TRB_TYPE_ISOCH 5 +#define TRB_TYPE_LINK 6 +#define TRB_TYPE_EVENT_DATA 7 +#define TRB_TYPE_NO_OP 8 +#define TRB_TYPE_EN_SLOT 9 +#define TRB_TYPE_DIS_SLOT 10 +#define TRB_TYPE_ADDRESS_DEV 11 +#define TRB_TYPE_CON_ENDPOINT 12 +#define TRB_TYPE_EVALU_CONTXT 13 +#define TRB_TYPE_RESET_ENDPOINT 14 +#define TRB_TYPE_STOP_ENDPOINT 15 +#define TRB_TYPE_SET_TR_DEQUE 16 +#define TRB_TYPE_RESET_DEV 17 +#define TRB_TYPE_GET_PORT_BANW 21 +#define TRB_TYPE_FORCE_HEADER 22 +#define TRB_TYPE_NO_OP_COMMAND 23 +#define TRB_TYPE_TRANS_EVENT 32 +#define TRB_TYPE_COMMAND_COMPLT_EVENT 33 +#define TRB_TYPE_PORT_STATUS_CHANGE_EVENT 34 +#define TRB_TYPE_HOST_CONTROLLER_EVENT 37 +#define TRB_TYPE_DEVICE_NOTIFI_EVENT 38 +#define TRB_TYPE_MFINDEX_WRAP_EVENT 39 + +// +// Convert millisecond to microsecond. +// +#define XHC_1_MILLISECOND (1000) +#define XHC_POLL_DELAY (1000) +#define XHC_GENERIC_TIMEOUT (10 * 1000) + +#define EFI_USB_SPEED_FULL 0x0000 ///< 12 Mb/s, USB 1.1 OHCI and UHCI HC. +#define EFI_USB_SPEED_LOW 0x0001 ///< 1 Mb/s, USB 1.1 OHCI and UHCI HC. +#define EFI_USB_SPEED_HIGH 0x0002 ///< 480 Mb/s, USB 2.0 EHCI HC. +#define EFI_USB_SPEED_SUPER 0x0003 ///< 4.8 Gb/s, USB 3.0 XHCI HC. + +// +// Transfer types, used in URB to identify the transfer type +// +#define XHC_CTRL_TRANSFER 0x01 +#define XHC_BULK_TRANSFER 0x02 +#define XHC_INT_TRANSFER_SYNC 0x04 +#define XHC_INT_TRANSFER_ASYNC 0x08 +#define XHC_INT_ONLY_TRANSFER_ASYNC 0x10 + +// +// USB Transfer Results +// +#define EFI_USB_NOERROR 0x00 +#define EFI_USB_ERR_NOTEXECUTE 0x01 +#define EFI_USB_ERR_STALL 0x02 +#define EFI_USB_ERR_BUFFER 0x04 +#define EFI_USB_ERR_BABBLE 0x08 +#define EFI_USB_ERR_NAK 0x10 +#define EFI_USB_ERR_CRC 0x20 +#define EFI_USB_ERR_TIMEOUT 0x40 +#define EFI_USB_ERR_BITSTUFF 0x80 +#define EFI_USB_ERR_SYSTEM 0x100 + +#pragma pack(1) + +// +// 7.6.9 OUT/IN EP Context: 64 bytes +// 7.6.9.2 When used by the DbC it is always a 64 byte data structure +// +typedef struct _ENDPOINT_CONTEXT_64 { + UINT32 EPState : 3; + UINT32 RsvdZ1 : 5; + UINT32 Mult : 2; // set to 0 + UINT32 MaxPStreams : 5; // set to 0 + UINT32 LSA : 1; // set to 0 + UINT32 Interval : 8; // set to 0 + UINT32 RsvdZ2 : 8; + + UINT32 RsvdZ3 : 1; + UINT32 CErr : 2; + UINT32 EPType : 3; + UINT32 RsvdZ4 : 1; + UINT32 HID : 1; // set to 0 + UINT32 MaxBurstSize : 8; + UINT32 MaxPacketSize : 16; + + UINT32 PtrLo; + + UINT32 PtrHi; + + UINT32 AverageTRBLength : 16; + UINT32 MaxESITPayload : 16; // set to 0 + + UINT32 RsvdZ5; // Reserved + UINT32 RsvdZ6; + UINT32 RsvdZ7; + + UINT32 RsvdZ8; + UINT32 RsvdZ9; + UINT32 RsvdZ10; + UINT32 RsvdZ11; + + UINT32 RsvdZ12; + UINT32 RsvdZ13; + UINT32 RsvdZ14; + UINT32 RsvdZ15; +} ENDPOINT_CONTEXT_64; + +// +// 6.4.1.1 Normal TRB: 16 bytes +// A Normal TRB is used in several ways; exclusively on Bulk and Interrupt Transfer Rings for normal and +// Scatter/Gather operations, to define additional data buffers for Scatter/Gather operations on Isoch Transfer +// Rings, and to define the Data stage information for Control Transfer Rings. +// +typedef struct _TRANSFER_TRB_NORMAL { + UINT32 TRBPtrLo; + + UINT32 TRBPtrHi; + + UINT32 Length : 17; + UINT32 TDSize : 5; + UINT32 IntTarget : 10; + + UINT32 CycleBit : 1; + UINT32 ENT : 1; + UINT32 ISP : 1; + UINT32 NS : 1; + UINT32 CH : 1; + UINT32 IOC : 1; + UINT32 IDT : 1; + UINT32 RsvdZ1 : 2; + UINT32 BEI : 1; + UINT32 Type : 6; + UINT32 RsvdZ2 : 16; +} TRANSFER_TRB_NORMAL; + +// +// 6.4.2.1 Transfer Event TRB: 16 bytes +// A Transfer Event provides the completion status associated with a Transfer TRB. Refer to section 4.11.3.1 +// for more information on the use and operation of Transfer Events. +// +typedef struct _EVT_TRB_TRANSFER { + UINT32 TRBPtrLo; + + UINT32 TRBPtrHi; + + UINT32 Length : 24; + UINT32 Completecode : 8; + + UINT32 CycleBit : 1; + UINT32 RsvdZ1 : 1; + UINT32 ED : 1; + UINT32 RsvdZ2 : 7; + UINT32 Type : 6; + UINT32 EndpointId : 5; + UINT32 RsvdZ3 : 3; + UINT32 SlotId : 8; +} EVT_TRB_TRANSFER; + +// +// 6.4.4.1 Link TRB: 16 bytes +// A Link TRB provides support for non-contiguous TRB Rings. +// +typedef struct _LINK_TRB { + UINT32 PtrLo; + + UINT32 PtrHi; + + UINT32 RsvdZ1 : 22; + UINT32 InterTarget : 10; + + UINT32 CycleBit : 1; + UINT32 TC : 1; + UINT32 RsvdZ2 : 2; + UINT32 CH : 1; + UINT32 IOC : 1; + UINT32 RsvdZ3 : 4; + UINT32 Type : 6; + UINT32 RsvdZ4 : 16; +} LINK_TRB; + +// +// TRB Template: 16 bytes +// +typedef struct _TRB_TEMPLATE { + UINT32 Parameter1; + + UINT32 Parameter2; + + UINT32 Status; + + UINT32 CycleBit : 1; + UINT32 RsvdZ1 : 9; + UINT32 Type : 6; + UINT32 Control : 16; +} TRB_TEMPLATE; + +// +// Refer to XHCI 6.5 Event Ring Segment Table: 16 bytes +// +typedef struct _EVENT_RING_SEG_TABLE_ENTRY { + UINT32 PtrLo; + UINT32 PtrHi; + UINT32 RingTrbSize : 16; + UINT32 RsvdZ1 : 16; + UINT32 RsvdZ2; +} EVENT_RING_SEG_TABLE_ENTRY; + +// +// Size: 40 bytes +// +typedef struct _EVENT_RING { + EFI_PHYSICAL_ADDRESS ERSTBase; + EFI_PHYSICAL_ADDRESS EventRingSeg0; + UINT32 TrbNumber; + EFI_PHYSICAL_ADDRESS EventRingEnqueue; + EFI_PHYSICAL_ADDRESS EventRingDequeue; + UINT32 EventRingCCS; +} EVENT_RING; + +// Size: 32 bytes +typedef struct _TRANSFER_RING { + EFI_PHYSICAL_ADDRESS RingSeg0; + UINT32 TrbNumber; + EFI_PHYSICAL_ADDRESS RingEnqueue; + EFI_PHYSICAL_ADDRESS RingDequeue; + UINT32 RingPCS; +} TRANSFER_RING; + +// +// Size: 64 bytes +// +typedef struct _DBC_INFO_CONTEXT { + UINT64 String0DescAddress; + UINT64 ManufacturerStrDescAddress; + UINT64 ProductStrDescAddress; + UINT64 SerialNumberStrDescAddress; + UINT64 String0Length : 8; + UINT64 ManufacturerStrLength : 8; + UINT64 ProductStrLength : 8; + UINT64 SerialNumberStrLength : 8; + UINT64 RsvdZ1 : 32; + UINT64 RsvdZ2; + UINT64 RsvdZ3; + UINT64 RsvdZ4; +} DBC_INFO_CONTEXT; + +// +// Debug Capability Context Data Structure: 192 bytes +// +typedef struct _XHC_DC_CONTEXT { + DBC_INFO_CONTEXT DbcInfoContext; + ENDPOINT_CONTEXT_64 EpOutContext; + ENDPOINT_CONTEXT_64 EpInContext; +} XHC_DC_CONTEXT; + +// +// Size: 16 bytes +// +typedef union _TRB { + TRB_TEMPLATE TrbTemplate; + TRANSFER_TRB_NORMAL TrbNormal; +} TRB; + +/// +/// USB data transfer direction +/// +typedef enum { + EfiUsbDataIn, + EfiUsbDataOut, + EfiUsbNoData +} EFI_USB_DATA_DIRECTION; + +// +// URB (Usb Request Block) contains information for all kinds of +// usb requests. +// +typedef struct _URB { + // + // Transfer data buffer + // + EFI_PHYSICAL_ADDRESS Data; + UINT32 DataLen; + + // + // Execute result + // + UINT32 Result; + // + // Completed data length + // + UINT32 Completed; + // + // Tranfer Ring info + // + EFI_PHYSICAL_ADDRESS Ring; + EFI_PHYSICAL_ADDRESS Trb; + BOOLEAN Finished; + EFI_USB_DATA_DIRECTION Direction; +} URB; + +typedef struct _USB3_DEBUG_PORT_INSTANCE { + UINT8 Initialized; + + // + // The flag indicates debug capability is supported + // + BOOLEAN DebugSupport; + + // + // The flag indicates debug device is ready + // + BOOLEAN Ready; + + // + // The flag indicates the instance is from HOB + // + BOOLEAN FromHob; + + // + // Prevent notification being interrupted by debug timer + // + BOOLEAN InNotify; + + // + // PciIo protocol event + // + EFI_PHYSICAL_ADDRESS PciIoEvent; + + // + // The flag indicates if USB 3.0 ports has been turn off/on power + // + BOOLEAN ChangePortPower; + + // + // XHCI MMIO Base address + // + EFI_PHYSICAL_ADDRESS XhciMmioBase; + + // + // XHCI OP RegisterBase address + // + EFI_PHYSICAL_ADDRESS XhciOpRegister; + + // + // XHCI Debug Register Base Address + // + EFI_PHYSICAL_ADDRESS DebugCapabilityBase; + + // + // XHCI Debug Capability offset + // + UINT64 DebugCapabilityOffset; + + // + // XHCI Debug Context Address + // + EFI_PHYSICAL_ADDRESS DebugCapabilityContext; + + // + // Transfer Ring + // + TRANSFER_RING TransferRingOut; + TRANSFER_RING TransferRingIn; + + // + // EventRing + // + EVENT_RING EventRing; + + // + // URB - Read + // + URB UrbOut; + + // + // URB - Write + // + URB UrbIn; + + // + // The available data length in the following data buffer. + // + UINT8 DataCount; + // + // The data buffer address for data read and poll. + // + EFI_PHYSICAL_ADDRESS Data; +} USB3_DEBUG_PORT_HANDLE; + +#pragma pack() + +/** + Read XHCI debug register. + + @param Handle Debug port handle. + @param Offset The offset of the debug register. + + @return The register content read + +**/ +UINT32 +XhcReadDebugReg ( + IN USB3_DEBUG_PORT_HANDLE *Handle, + IN UINT32 Offset + ); + +/** + Set one bit of the debug register while keeping other bits. + + @param Handle Debug port handle. + @param Offset The offset of the debug register. + @param Bit The bit mask of the register to set. + +**/ +VOID +XhcSetDebugRegBit ( + IN USB3_DEBUG_PORT_HANDLE *Handle, + IN UINT32 Offset, + IN UINT32 Bit + ); + +/** + Write the data to the debug register. + + @param Handle Debug port handle. + @param Offset The offset of the debug register. + @param Data The data to write. + +**/ +VOID +XhcWriteDebugReg ( + IN USB3_DEBUG_PORT_HANDLE *Handle, + IN UINT32 Offset, + IN UINT32 Data + ); + +/** + Verifies if the bit positions specified by a mask are set in a register. + + @param[in, out] Register UINTN register + @param[in] BitMask 32-bit mask + + @return BOOLEAN - TRUE if all bits specified by the mask are enabled. + - FALSE even if one of the bits specified by the mask + is not enabled. +**/ +BOOLEAN +XhcIsBitSet ( + UINTN Register, + UINT32 BitMask + ); + +/** + Sets bits as per the enabled bit positions in the mask. + + @param[in, out] Register UINTN register + @param[in] BitMask 32-bit mask +**/ +VOID +XhcSetR32Bit ( + UINTN Register, + UINT32 BitMask + ); + +/** + Clears bits as per the enabled bit positions in the mask. + + @param[in, out] Register UINTN register + @param[in] BitMask 32-bit mask +**/ +VOID +XhcClearR32Bit ( + IN OUT UINTN Register, + IN UINT32 BitMask + ); + +/** + Initialize USB3 debug port. + + This method invokes various internal functions to facilitate + detection and initialization of USB3 debug port. + + @retval RETURN_SUCCESS The serial device was initialized. +**/ +RETURN_STATUS +EFIAPI +USB3Initialize ( + VOID + ); + +/** + Return command register value in XHCI controller. + +**/ +UINT16 +GetXhciPciCommand ( + VOID + ); + +/** + Allocate aligned memory for XHC's usage. + + @param BufferSize The size, in bytes, of the Buffer. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +AllocateAlignBuffer ( + IN UINTN BufferSize + ); + +/** + The real function to initialize USB3 debug port. + + This method invokes various internal functions to facilitate + detection and initialization of USB3 debug port. + + @retval RETURN_SUCCESS The serial device was initialized. +**/ +RETURN_STATUS +EFIAPI +USB3InitializeReal ( + VOID + ); + +/** + Submits bulk transfer to a bulk endpoint of a USB device. + + @param Handle The instance of debug device. + @param Direction The direction of data transfer. + @param Data Array of pointers to the buffers of data to transmit + from or receive into. + @param DataLength The length of the data buffer. + @param Timeout Indicates the maximum time, in millisecond, which + the transfer is allowed to complete. + + @retval EFI_SUCCESS The transfer was completed successfully. + @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource. + @retval EFI_INVALID_PARAMETER Some parameters are invalid. + @retval EFI_TIMEOUT The transfer failed due to timeout. + @retval EFI_DEVICE_ERROR The transfer failed due to host controller error. + +**/ +EFI_STATUS +EFIAPI +XhcDataTransfer ( + IN USB3_DEBUG_PORT_HANDLE *Handle, + IN EFI_USB_DATA_DIRECTION Direction, + IN OUT VOID *Data, + IN OUT UINTN *DataLength, + IN UINTN Timeout + ); + +/** + Initialize usb debug port hardware. + + @param Handle Debug port handle. + + @retval TRUE The usb debug port hardware configuration is changed. + @retval FALSE The usb debug port hardware configuration is not changed. + +**/ +RETURN_STATUS +EFIAPI +InitializeUsbDebugHardware ( + IN USB3_DEBUG_PORT_HANDLE *Handle + ); + +/** + Return USB3 debug instance address pointer. + +**/ +EFI_PHYSICAL_ADDRESS * +GetUsb3DebugPortInstanceAddrPtr ( + VOID + ); + +/** + Return USB3 debug instance address. + +**/ +USB3_DEBUG_PORT_HANDLE * +GetUsb3DebugPortInstance ( + VOID + ); + +#endif //__SERIAL_PORT_LIB_USB__ diff --git a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.c b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.c index aa04442918..876be20f25 100644 --- a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.c +++ b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.c @@ -1,274 +1,274 @@ -/** @file
- Debug Port Library implementation based on usb3 debug port.
-
- Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include <PiPei.h>
-#include <Library/PeiServicesLib.h>
-#include <Library/HobLib.h>
-#include <Ppi/MemoryDiscovered.h>
-#include <Ppi/IoMmu.h>
-#include "DebugCommunicationLibUsb3Internal.h"
-
-GUID gUsb3DbgGuid = USB3_DBG_GUID;
-
-/**
- USB3 IOMMU PPI notify.
-
- @param[in] PeiServices Pointer to PEI Services Table.
- @param[in] NotifyDesc Pointer to the descriptor for the Notification event that
- caused this function to execute.
- @param[in] Ppi Pointer to the PPI data associated with this function.
-
- @retval EFI_STATUS Always return EFI_SUCCESS
-**/
-EFI_STATUS
-EFIAPI
-Usb3IoMmuPpiNotify (
- IN EFI_PEI_SERVICES **PeiServices,
- IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
- IN VOID *Ppi
- )
-{
- USB3_DEBUG_PORT_HANDLE *Instance;
-
- DEBUG ((DEBUG_INFO, "%a()\n", __func__));
-
- Instance = GetUsb3DebugPortInstance ();
- ASSERT (Instance != NULL);
- if (!Instance->Ready) {
- return EFI_SUCCESS;
- }
-
- Instance->InNotify = TRUE;
-
- //
- // Reinitialize USB3 debug port with granted DMA buffer from IOMMU PPI.
- //
- InitializeUsbDebugHardware (Instance);
-
- //
- // Wait some time for host to be ready after re-initialization.
- //
- MicroSecondDelay (1000000);
-
- Instance->InNotify = FALSE;
-
- return EFI_SUCCESS;
-}
-
-EFI_PEI_NOTIFY_DESCRIPTOR mUsb3IoMmuPpiNotifyDesc = {
- (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
- &gEdkiiIoMmuPpiGuid,
- Usb3IoMmuPpiNotify
-};
-
-/**
- Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
- OperationBusMasterCommonBuffer64 mapping.
-
- @param IoMmu Pointer to IOMMU PPI.
- @param Pages The number of pages to allocate.
- @param HostAddress A pointer to store the base system memory address of the
- allocated range.
- @param DeviceAddress The resulting map address for the bus master PCI controller to use to
- access the hosts HostAddress.
- @param Mapping A resulting value to pass to Unmap().
-
- @retval EFI_SUCCESS The requested memory pages were allocated.
- @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
- MEMORY_WRITE_COMBINE and MEMORY_CACHED.
- @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
- @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
-
-**/
-EFI_STATUS
-IoMmuAllocateBuffer (
- IN EDKII_IOMMU_PPI *IoMmu,
- IN UINTN Pages,
- OUT VOID **HostAddress,
- OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
- OUT VOID **Mapping
- )
-{
- EFI_STATUS Status;
- UINTN NumberOfBytes;
-
- *HostAddress = NULL;
- *DeviceAddress = 0;
- *Mapping = NULL;
-
- Status = IoMmu->AllocateBuffer (
- IoMmu,
- EfiRuntimeServicesData,
- Pages,
- HostAddress,
- 0
- );
- if (EFI_ERROR (Status)) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- NumberOfBytes = EFI_PAGES_TO_SIZE (Pages);
- Status = IoMmu->Map (
- IoMmu,
- EdkiiIoMmuOperationBusMasterCommonBuffer,
- *HostAddress,
- &NumberOfBytes,
- DeviceAddress,
- Mapping
- );
- if (EFI_ERROR (Status)) {
- IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress);
- *HostAddress = NULL;
- return EFI_OUT_OF_RESOURCES;
- }
-
- Status = IoMmu->SetAttribute (
- IoMmu,
- *Mapping,
- EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE
- );
- if (EFI_ERROR (Status)) {
- IoMmu->Unmap (IoMmu, *Mapping);
- IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress);
- *Mapping = NULL;
- *HostAddress = NULL;
- return Status;
- }
-
- return Status;
-}
-
-/**
- USB3 get IOMMU PPI.
-
- @return Pointer to IOMMU PPI.
-
-**/
-EDKII_IOMMU_PPI *
-Usb3GetIoMmu (
- VOID
- )
-{
- EFI_STATUS Status;
- EDKII_IOMMU_PPI *IoMmu;
-
- IoMmu = NULL;
- Status = PeiServicesLocatePpi (
- &gEdkiiIoMmuPpiGuid,
- 0,
- NULL,
- (VOID **)&IoMmu
- );
- if (!EFI_ERROR (Status) && (IoMmu != NULL)) {
- return IoMmu;
- }
-
- return NULL;
-}
-
-/**
- Return USB3 debug instance address pointer.
-
-**/
-EFI_PHYSICAL_ADDRESS *
-GetUsb3DebugPortInstanceAddrPtr (
- VOID
- )
-{
- USB3_DEBUG_PORT_HANDLE *Instance;
- EFI_PHYSICAL_ADDRESS *AddrPtr;
- EFI_PEI_HOB_POINTERS Hob;
- EFI_STATUS Status;
-
- Hob.Raw = GetFirstGuidHob (&gUsb3DbgGuid);
- if (Hob.Raw == NULL) {
- //
- // Build HOB for the local instance and the buffer to save instance address pointer.
- // Use the local instance in HOB temporarily.
- //
- AddrPtr = BuildGuidHob (
- &gUsb3DbgGuid,
- sizeof (EFI_PHYSICAL_ADDRESS) + sizeof (USB3_DEBUG_PORT_HANDLE)
- );
- ASSERT (AddrPtr != NULL);
- ZeroMem (AddrPtr, sizeof (EFI_PHYSICAL_ADDRESS) + sizeof (USB3_DEBUG_PORT_HANDLE));
- Instance = (USB3_DEBUG_PORT_HANDLE *)(AddrPtr + 1);
- *AddrPtr = (EFI_PHYSICAL_ADDRESS)(UINTN)Instance;
- Instance->FromHob = TRUE;
- Instance->Initialized = USB3DBG_UNINITIALIZED;
- if (Usb3GetIoMmu () == NULL) {
- Status = PeiServicesNotifyPpi (&mUsb3IoMmuPpiNotifyDesc);
- ASSERT_EFI_ERROR (Status);
- }
- } else {
- AddrPtr = GET_GUID_HOB_DATA (Hob.Guid);
- }
-
- return AddrPtr;
-}
-
-/**
- Allocate aligned memory for XHC's usage.
-
- @param BufferSize The size, in bytes, of the Buffer.
-
- @return A pointer to the allocated buffer or NULL if allocation fails.
-
-**/
-VOID *
-AllocateAlignBuffer (
- IN UINTN BufferSize
- )
-{
- VOID *Buf;
- EFI_PHYSICAL_ADDRESS Address;
- EFI_STATUS Status;
- VOID *MemoryDiscoveredPpi;
- EDKII_IOMMU_PPI *IoMmu;
- VOID *HostAddress;
- VOID *Mapping;
-
- Buf = NULL;
-
- //
- // Make sure the allocated memory is physical memory.
- //
- Status = PeiServicesLocatePpi (
- &gEfiPeiMemoryDiscoveredPpiGuid,
- 0,
- NULL,
- (VOID **)&MemoryDiscoveredPpi
- );
- if (!EFI_ERROR (Status)) {
- IoMmu = Usb3GetIoMmu ();
- if (IoMmu != NULL) {
- Status = IoMmuAllocateBuffer (
- IoMmu,
- EFI_SIZE_TO_PAGES (BufferSize),
- &HostAddress,
- &Address,
- &Mapping
- );
- if (!EFI_ERROR (Status)) {
- ASSERT (Address == ((EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress));
- Buf = (VOID *)(UINTN)Address;
- }
- } else {
- Status = PeiServicesAllocatePages (
- EfiACPIMemoryNVS,
- EFI_SIZE_TO_PAGES (BufferSize),
- &Address
- );
- if (!EFI_ERROR (Status)) {
- Buf = (VOID *)(UINTN)Address;
- }
- }
- }
-
- return Buf;
-}
+/** @file + Debug Port Library implementation based on usb3 debug port. + + Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiPei.h> +#include <Library/PeiServicesLib.h> +#include <Library/HobLib.h> +#include <Ppi/MemoryDiscovered.h> +#include <Ppi/IoMmu.h> +#include "DebugCommunicationLibUsb3Internal.h" + +GUID gUsb3DbgGuid = USB3_DBG_GUID; + +/** + USB3 IOMMU PPI notify. + + @param[in] PeiServices Pointer to PEI Services Table. + @param[in] NotifyDesc Pointer to the descriptor for the Notification event that + caused this function to execute. + @param[in] Ppi Pointer to the PPI data associated with this function. + + @retval EFI_STATUS Always return EFI_SUCCESS +**/ +EFI_STATUS +EFIAPI +Usb3IoMmuPpiNotify ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc, + IN VOID *Ppi + ) +{ + USB3_DEBUG_PORT_HANDLE *Instance; + + DEBUG ((DEBUG_INFO, "%a()\n", __func__)); + + Instance = GetUsb3DebugPortInstance (); + ASSERT (Instance != NULL); + if (!Instance->Ready) { + return EFI_SUCCESS; + } + + Instance->InNotify = TRUE; + + // + // Reinitialize USB3 debug port with granted DMA buffer from IOMMU PPI. + // + InitializeUsbDebugHardware (Instance); + + // + // Wait some time for host to be ready after re-initialization. + // + MicroSecondDelay (1000000); + + Instance->InNotify = FALSE; + + return EFI_SUCCESS; +} + +EFI_PEI_NOTIFY_DESCRIPTOR mUsb3IoMmuPpiNotifyDesc = { + (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEdkiiIoMmuPpiGuid, + Usb3IoMmuPpiNotify +}; + +/** + Allocates pages that are suitable for an OperationBusMasterCommonBuffer or + OperationBusMasterCommonBuffer64 mapping. + + @param IoMmu Pointer to IOMMU PPI. + @param Pages The number of pages to allocate. + @param HostAddress A pointer to store the base system memory address of the + allocated range. + @param DeviceAddress The resulting map address for the bus master PCI controller to use to + access the hosts HostAddress. + @param Mapping A resulting value to pass to Unmap(). + + @retval EFI_SUCCESS The requested memory pages were allocated. + @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are + MEMORY_WRITE_COMBINE and MEMORY_CACHED. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. + +**/ +EFI_STATUS +IoMmuAllocateBuffer ( + IN EDKII_IOMMU_PPI *IoMmu, + IN UINTN Pages, + OUT VOID **HostAddress, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ) +{ + EFI_STATUS Status; + UINTN NumberOfBytes; + + *HostAddress = NULL; + *DeviceAddress = 0; + *Mapping = NULL; + + Status = IoMmu->AllocateBuffer ( + IoMmu, + EfiRuntimeServicesData, + Pages, + HostAddress, + 0 + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + NumberOfBytes = EFI_PAGES_TO_SIZE (Pages); + Status = IoMmu->Map ( + IoMmu, + EdkiiIoMmuOperationBusMasterCommonBuffer, + *HostAddress, + &NumberOfBytes, + DeviceAddress, + Mapping + ); + if (EFI_ERROR (Status)) { + IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress); + *HostAddress = NULL; + return EFI_OUT_OF_RESOURCES; + } + + Status = IoMmu->SetAttribute ( + IoMmu, + *Mapping, + EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE + ); + if (EFI_ERROR (Status)) { + IoMmu->Unmap (IoMmu, *Mapping); + IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress); + *Mapping = NULL; + *HostAddress = NULL; + return Status; + } + + return Status; +} + +/** + USB3 get IOMMU PPI. + + @return Pointer to IOMMU PPI. + +**/ +EDKII_IOMMU_PPI * +Usb3GetIoMmu ( + VOID + ) +{ + EFI_STATUS Status; + EDKII_IOMMU_PPI *IoMmu; + + IoMmu = NULL; + Status = PeiServicesLocatePpi ( + &gEdkiiIoMmuPpiGuid, + 0, + NULL, + (VOID **)&IoMmu + ); + if (!EFI_ERROR (Status) && (IoMmu != NULL)) { + return IoMmu; + } + + return NULL; +} + +/** + Return USB3 debug instance address pointer. + +**/ +EFI_PHYSICAL_ADDRESS * +GetUsb3DebugPortInstanceAddrPtr ( + VOID + ) +{ + USB3_DEBUG_PORT_HANDLE *Instance; + EFI_PHYSICAL_ADDRESS *AddrPtr; + EFI_PEI_HOB_POINTERS Hob; + EFI_STATUS Status; + + Hob.Raw = GetFirstGuidHob (&gUsb3DbgGuid); + if (Hob.Raw == NULL) { + // + // Build HOB for the local instance and the buffer to save instance address pointer. + // Use the local instance in HOB temporarily. + // + AddrPtr = BuildGuidHob ( + &gUsb3DbgGuid, + sizeof (EFI_PHYSICAL_ADDRESS) + sizeof (USB3_DEBUG_PORT_HANDLE) + ); + ASSERT (AddrPtr != NULL); + ZeroMem (AddrPtr, sizeof (EFI_PHYSICAL_ADDRESS) + sizeof (USB3_DEBUG_PORT_HANDLE)); + Instance = (USB3_DEBUG_PORT_HANDLE *)(AddrPtr + 1); + *AddrPtr = (EFI_PHYSICAL_ADDRESS)(UINTN)Instance; + Instance->FromHob = TRUE; + Instance->Initialized = USB3DBG_UNINITIALIZED; + if (Usb3GetIoMmu () == NULL) { + Status = PeiServicesNotifyPpi (&mUsb3IoMmuPpiNotifyDesc); + ASSERT_EFI_ERROR (Status); + } + } else { + AddrPtr = GET_GUID_HOB_DATA (Hob.Guid); + } + + return AddrPtr; +} + +/** + Allocate aligned memory for XHC's usage. + + @param BufferSize The size, in bytes, of the Buffer. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +AllocateAlignBuffer ( + IN UINTN BufferSize + ) +{ + VOID *Buf; + EFI_PHYSICAL_ADDRESS Address; + EFI_STATUS Status; + VOID *MemoryDiscoveredPpi; + EDKII_IOMMU_PPI *IoMmu; + VOID *HostAddress; + VOID *Mapping; + + Buf = NULL; + + // + // Make sure the allocated memory is physical memory. + // + Status = PeiServicesLocatePpi ( + &gEfiPeiMemoryDiscoveredPpiGuid, + 0, + NULL, + (VOID **)&MemoryDiscoveredPpi + ); + if (!EFI_ERROR (Status)) { + IoMmu = Usb3GetIoMmu (); + if (IoMmu != NULL) { + Status = IoMmuAllocateBuffer ( + IoMmu, + EFI_SIZE_TO_PAGES (BufferSize), + &HostAddress, + &Address, + &Mapping + ); + if (!EFI_ERROR (Status)) { + ASSERT (Address == ((EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress)); + Buf = (VOID *)(UINTN)Address; + } + } else { + Status = PeiServicesAllocatePages ( + EfiACPIMemoryNVS, + EFI_SIZE_TO_PAGES (BufferSize), + &Address + ); + if (!EFI_ERROR (Status)) { + Buf = (VOID *)(UINTN)Address; + } + } + } + + return Buf; +} diff --git a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.inf b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.inf index 89a7cfcd00..02638804af 100644 --- a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.inf +++ b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.inf @@ -1,69 +1,69 @@ -## @file
-# Debug Communication Library instance based on usb3 debug port.
-#
-# Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-#
-##
-
-[Defines]
- INF_VERSION = 0x00010005
- BASE_NAME = DebugCommunicationLibUsb3Pei
- MODULE_UNI_FILE = DebugCommunicationLibUsb3Pei.uni
- FILE_GUID = 106C877F-C2BA-4c46-876C-BDFE6171CD7E
- MODULE_TYPE = PEIM
- VERSION_STRING = 1.0
- LIBRARY_CLASS = DebugCommunicationLib|PEIM PEI_CORE
-
-#
-# The following information is for reference only and not required by the build tools.
-#
-# VALID_ARCHITECTURES = IA32 X64
-#
-
-[Sources]
- DebugCommunicationLibUsb3Pei.c
- DebugCommunicationLibUsb3Transfer.c
- DebugCommunicationLibUsb3Common.c
- DebugCommunicationLibUsb3Internal.h
-
-[Packages]
- MdePkg/MdePkg.dec
- MdeModulePkg/MdeModulePkg.dec
- SourceLevelDebugPkg/SourceLevelDebugPkg.dec
-
-[Ppis]
- gEfiPeiMemoryDiscoveredPpiGuid ## CONSUMES
- gEdkiiIoMmuPpiGuid ## SOMETIMES_CONSUMES
-
-[Pcd]
- # The memory BAR of ehci host controller, in which usb debug feature is enabled.
- # Note that the memory BAR address is only used before Pci bus resource allocation.
- gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciMemorySpaceBase ## SOMETIMES_CONSUMES
-
- # The pci address of ehci host controller, in which usb debug feature is enabled.
- # The format of pci address please refer to SourceLevelDebugPkg.dec
- gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciPciAddress ## CONSUMES
-
- # Per XHCI spec, software shall impose a timeout between the detection of the Debug Host
- # connection and the DbC Run transition to 1. This PCD specifies the timeout value in microsecond.
- gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciDebugDetectTimeout ## SOMETIMES_CONSUMES
-
- # The value of data buffer size used for USB debug port handle.
- # It should be equal to sizeof (USB3_DEBUG_PORT_HANDLE).
- gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdDebugPortHandleBufferSize|249 ## SOMETIMES_CONSUMES
-
-[LibraryClasses]
- BaseLib
- PcdLib
- IoLib
- PciLib
- TimerLib
- BaseMemoryLib
- PeiServicesLib
- HobLib
-
-[Depex.common.PEIM]
- gEfiPeiMemoryDiscoveredPpiGuid
+## @file +# Debug Communication Library instance based on usb3 debug port. +# +# Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DebugCommunicationLibUsb3Pei + MODULE_UNI_FILE = DebugCommunicationLibUsb3Pei.uni + FILE_GUID = 106C877F-C2BA-4c46-876C-BDFE6171CD7E + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + LIBRARY_CLASS = DebugCommunicationLib|PEIM PEI_CORE + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + DebugCommunicationLibUsb3Pei.c + DebugCommunicationLibUsb3Transfer.c + DebugCommunicationLibUsb3Common.c + DebugCommunicationLibUsb3Internal.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SourceLevelDebugPkg/SourceLevelDebugPkg.dec + +[Ppis] + gEfiPeiMemoryDiscoveredPpiGuid ## CONSUMES + gEdkiiIoMmuPpiGuid ## SOMETIMES_CONSUMES + +[Pcd] + # The memory BAR of ehci host controller, in which usb debug feature is enabled. + # Note that the memory BAR address is only used before Pci bus resource allocation. + gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciMemorySpaceBase ## SOMETIMES_CONSUMES + + # The pci address of ehci host controller, in which usb debug feature is enabled. + # The format of pci address please refer to SourceLevelDebugPkg.dec + gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciPciAddress ## CONSUMES + + # Per XHCI spec, software shall impose a timeout between the detection of the Debug Host + # connection and the DbC Run transition to 1. This PCD specifies the timeout value in microsecond. + gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciDebugDetectTimeout ## SOMETIMES_CONSUMES + + # The value of data buffer size used for USB debug port handle. + # It should be equal to sizeof (USB3_DEBUG_PORT_HANDLE). + gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdDebugPortHandleBufferSize|249 ## SOMETIMES_CONSUMES + +[LibraryClasses] + BaseLib + PcdLib + IoLib + PciLib + TimerLib + BaseMemoryLib + PeiServicesLib + HobLib + +[Depex.common.PEIM] + gEfiPeiMemoryDiscoveredPpiGuid diff --git a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.uni b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.uni index 8252b660b6..3511de6788 100644 --- a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.uni +++ b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.uni @@ -1,16 +1,16 @@ -// /** @file
-// Debug Communication Library instance based on USB3 debug port for PEI modules.
-//
-// Debug Communication Library instance based on USB3 debug port for PEI modules.
-//
-// Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
-//
-// SPDX-License-Identifier: BSD-2-Clause-Patent
-//
-// **/
-
-
-#string STR_MODULE_ABSTRACT #language en-US "Debug Communication Library instance based on USB3 debug port for PEI modules"
-
-#string STR_MODULE_DESCRIPTION #language en-US "Debug Communication Library instance based on USB3 debug port for PEI modules."
-
+// /** @file +// Debug Communication Library instance based on USB3 debug port for PEI modules. +// +// Debug Communication Library instance based on USB3 debug port for PEI modules. +// +// Copyright (c) 2014, Intel Corporation. All rights reserved.<BR> +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Debug Communication Library instance based on USB3 debug port for PEI modules" + +#string STR_MODULE_DESCRIPTION #language en-US "Debug Communication Library instance based on USB3 debug port for PEI modules." + diff --git a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Transfer.c b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Transfer.c index a651e88271..eadc8f5164 100644 --- a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Transfer.c +++ b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Transfer.c @@ -1,584 +1,584 @@ -/** @file
- Debug Port Library implementation based on usb3 debug port.
-
- Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-#include "DebugCommunicationLibUsb3Internal.h"
-
-/**
- Synchronize the specified transfer ring to update the enqueue and dequeue pointer.
-
- @param Handle Debug port handle.
- @param TrsRing The transfer ring to sync.
-
- @retval EFI_SUCCESS The transfer ring is synchronized successfully.
-
-**/
-EFI_STATUS
-EFIAPI
-XhcSyncTrsRing (
- IN USB3_DEBUG_PORT_HANDLE *Handle,
- IN TRANSFER_RING *TrsRing
- )
-{
- UINTN Index;
- TRB_TEMPLATE *TrsTrb;
- UINT32 CycleBit;
-
- ASSERT (TrsRing != NULL);
-
- //
- // Calculate the latest RingEnqueue and RingPCS
- //
- TrsTrb = (TRB_TEMPLATE *)(UINTN)TrsRing->RingEnqueue;
-
- ASSERT (TrsTrb != NULL);
-
- for (Index = 0; Index < TrsRing->TrbNumber; Index++) {
- if (TrsTrb->CycleBit != (TrsRing->RingPCS & BIT0)) {
- break;
- }
-
- TrsTrb++;
- if ((UINT8)TrsTrb->Type == TRB_TYPE_LINK) {
- ASSERT (((LINK_TRB *)TrsTrb)->TC != 0);
- //
- // set cycle bit in Link TRB as normal
- //
- ((LINK_TRB *)TrsTrb)->CycleBit = TrsRing->RingPCS & BIT0;
- //
- // Toggle PCS maintained by software
- //
- TrsRing->RingPCS = (TrsRing->RingPCS & BIT0) ? 0 : 1;
- TrsTrb = (TRB_TEMPLATE *)(UINTN)((TrsTrb->Parameter1 | LShiftU64 ((UINT64)TrsTrb->Parameter2, 32)) & ~0x0F);
- }
- }
-
- ASSERT (Index != TrsRing->TrbNumber);
-
- if ((EFI_PHYSICAL_ADDRESS)(UINTN)TrsTrb != TrsRing->RingEnqueue) {
- TrsRing->RingEnqueue = (EFI_PHYSICAL_ADDRESS)(UINTN)TrsTrb;
- }
-
- //
- // Clear the Trb context for enqueue, but reserve the PCS bit which indicates free Trb.
- //
- CycleBit = TrsTrb->CycleBit;
- ZeroMem (TrsTrb, sizeof (TRB_TEMPLATE));
- TrsTrb->CycleBit = CycleBit;
-
- return EFI_SUCCESS;
-}
-
-/**
- Synchronize the specified event ring to update the enqueue and dequeue pointer.
-
- @param Handle Debug port handle.
- @param EvtRing The event ring to sync.
-
- @retval EFI_SUCCESS The event ring is synchronized successfully.
-
-**/
-EFI_STATUS
-EFIAPI
-XhcSyncEventRing (
- IN USB3_DEBUG_PORT_HANDLE *Handle,
- IN EVENT_RING *EvtRing
- )
-{
- UINTN Index;
- TRB_TEMPLATE *EvtTrb1;
-
- ASSERT (EvtRing != NULL);
-
- //
- // Calculate the EventRingEnqueue and EventRingCCS.
- // Note: only support single Segment
- //
- EvtTrb1 = (TRB_TEMPLATE *)(UINTN)EvtRing->EventRingDequeue;
-
- for (Index = 0; Index < EvtRing->TrbNumber; Index++) {
- if (EvtTrb1->CycleBit != EvtRing->EventRingCCS) {
- break;
- }
-
- EvtTrb1++;
-
- if ((UINTN)EvtTrb1 >= ((UINTN)EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {
- EvtTrb1 = (TRB_TEMPLATE *)(UINTN)EvtRing->EventRingSeg0;
- EvtRing->EventRingCCS = (EvtRing->EventRingCCS) ? 0 : 1;
- }
- }
-
- if (Index < EvtRing->TrbNumber) {
- EvtRing->EventRingEnqueue = (EFI_PHYSICAL_ADDRESS)(UINTN)EvtTrb1;
- } else {
- ASSERT (FALSE);
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Check if there is a new generated event.
-
- @param Handle Debug port handle.
- @param EvtRing The event ring to check.
- @param NewEvtTrb The new event TRB found.
-
- @retval EFI_SUCCESS Found a new event TRB at the event ring.
- @retval EFI_NOT_READY The event ring has no new event.
-
-**/
-EFI_STATUS
-EFIAPI
-XhcCheckNewEvent (
- IN USB3_DEBUG_PORT_HANDLE *Handle,
- IN EVENT_RING *EvtRing,
- OUT TRB_TEMPLATE **NewEvtTrb
- )
-{
- EFI_STATUS Status;
-
- ASSERT (EvtRing != NULL);
-
- *NewEvtTrb = (TRB_TEMPLATE *)(UINTN)EvtRing->EventRingDequeue;
-
- if (EvtRing->EventRingDequeue == EvtRing->EventRingEnqueue) {
- return EFI_NOT_READY;
- }
-
- Status = EFI_SUCCESS;
-
- EvtRing->EventRingDequeue += sizeof (TRB_TEMPLATE);
- //
- // If the dequeue pointer is beyond the ring, then roll-back it to the beginning of the ring.
- //
- if ((UINTN)EvtRing->EventRingDequeue >= ((UINTN)EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {
- EvtRing->EventRingDequeue = EvtRing->EventRingSeg0;
- }
-
- return Status;
-}
-
-/**
- Check if the Trb is a transaction of the URB.
-
- @param Ring The transfer ring to be checked.
- @param Trb The TRB to be checked.
-
- @retval TRUE It is a transaction of the URB.
- @retval FALSE It is not any transaction of the URB.
-
-**/
-BOOLEAN
-IsTrbInTrsRing (
- IN TRANSFER_RING *Ring,
- IN TRB_TEMPLATE *Trb
- )
-{
- TRB_TEMPLATE *CheckedTrb;
- UINTN Index;
-
- CheckedTrb = (TRB_TEMPLATE *)(UINTN)Ring->RingSeg0;
-
- ASSERT (Ring->TrbNumber == TR_RING_TRB_NUMBER);
-
- for (Index = 0; Index < Ring->TrbNumber; Index++) {
- if (Trb == CheckedTrb) {
- return TRUE;
- }
-
- CheckedTrb++;
- }
-
- return FALSE;
-}
-
-/**
- Check the URB's execution result and update the URB's
- result accordingly.
-
- @param Handle Debug port handle.
- @param Urb The URB to check result.
-
-**/
-VOID
-XhcCheckUrbResult (
- IN USB3_DEBUG_PORT_HANDLE *Handle,
- IN URB *Urb
- )
-{
- EVT_TRB_TRANSFER *EvtTrb;
- TRB_TEMPLATE *TRBPtr;
- UINTN Index;
- EFI_STATUS Status;
- URB *CheckedUrb;
- UINT64 XhcDequeue;
- UINT32 High;
- UINT32 Low;
-
- ASSERT ((Handle != NULL) && (Urb != NULL));
-
- if (Urb->Finished) {
- goto EXIT;
- }
-
- EvtTrb = NULL;
-
- //
- // Traverse the event ring to find out all new events from the previous check.
- //
- XhcSyncEventRing (Handle, &Handle->EventRing);
-
- for (Index = 0; Index < Handle->EventRing.TrbNumber; Index++) {
- Status = XhcCheckNewEvent (Handle, &Handle->EventRing, ((TRB_TEMPLATE **)&EvtTrb));
- if (Status == EFI_NOT_READY) {
- //
- // All new events are handled, return directly.
- //
- goto EXIT;
- }
-
- if ((EvtTrb->Type != TRB_TYPE_COMMAND_COMPLT_EVENT) && (EvtTrb->Type != TRB_TYPE_TRANS_EVENT)) {
- continue;
- }
-
- TRBPtr = (TRB_TEMPLATE *)(UINTN)(EvtTrb->TRBPtrLo | LShiftU64 ((UINT64)EvtTrb->TRBPtrHi, 32));
-
- if (IsTrbInTrsRing ((TRANSFER_RING *)(UINTN)(Urb->Ring), TRBPtr)) {
- CheckedUrb = Urb;
- } else if (IsTrbInTrsRing ((TRANSFER_RING *)(UINTN)(Handle->UrbIn.Ring), TRBPtr)) {
- //
- // If it is read event and it should be generated by poll, and current operation is write, we need save data into internal buffer.
- // Internal buffer is used by next read.
- //
- Handle->DataCount = (UINT8)(Handle->UrbIn.DataLen - EvtTrb->Length);
- CopyMem ((VOID *)(UINTN)Handle->Data, (VOID *)(UINTN)Handle->UrbIn.Data, Handle->DataCount);
- //
- // Fill this TRB complete with CycleBit, otherwise next read will fail with old TRB.
- //
- TRBPtr->CycleBit = (TRBPtr->CycleBit & BIT0) ? 0 : 1;
- continue;
- } else {
- continue;
- }
-
- if ((EvtTrb->Completecode == TRB_COMPLETION_SHORT_PACKET) ||
- (EvtTrb->Completecode == TRB_COMPLETION_SUCCESS))
- {
- //
- // The length of data which were transferred.
- //
- CheckedUrb->Completed += (((TRANSFER_TRB_NORMAL *)TRBPtr)->Length - EvtTrb->Length);
- } else {
- CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT;
- }
-
- //
- // This Urb has been processed
- //
- CheckedUrb->Finished = TRUE;
- }
-
-EXIT:
- //
- // Advance event ring to last available entry
- //
- // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
- // So divide it to two 32-bytes width register access.
- //
- Low = XhcReadDebugReg (Handle, XHC_DC_DCERDP);
- High = XhcReadDebugReg (Handle, XHC_DC_DCERDP + 4);
- XhcDequeue = (UINT64)(LShiftU64 ((UINT64)High, 32) | Low);
-
- if ((XhcDequeue & (~0x0F)) != ((UINT64)(UINTN)Handle->EventRing.EventRingDequeue & (~0x0F))) {
- //
- // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
- // So divide it to two 32-bytes width register access.
- //
- XhcWriteDebugReg (Handle, XHC_DC_DCERDP, XHC_LOW_32BIT (Handle->EventRing.EventRingDequeue));
- XhcWriteDebugReg (Handle, XHC_DC_DCERDP + 4, XHC_HIGH_32BIT (Handle->EventRing.EventRingDequeue));
- }
-}
-
-/**
- Ring the door bell to notify XHCI there is a transaction to be executed.
-
- @param Handle Debug port handle.
- @param Urb The pointer to URB.
-
- @retval EFI_SUCCESS Successfully ring the door bell.
-
-**/
-EFI_STATUS
-EFIAPI
-XhcRingDoorBell (
- IN USB3_DEBUG_PORT_HANDLE *Handle,
- IN URB *Urb
- )
-{
- UINT32 Dcdb;
-
- //
- // 7.6.8.2 DCDB Register
- //
- Dcdb = (Urb->Direction == EfiUsbDataIn) ? 0x100 : 0x0;
-
- XhcWriteDebugReg (
- Handle,
- XHC_DC_DCDB,
- Dcdb
- );
-
- return EFI_SUCCESS;
-}
-
-/**
- Execute the transfer by polling the URB. This is a synchronous operation.
-
- @param Handle Debug port handle.
- @param Urb The URB to execute.
- @param Timeout The time to wait before abort, in microsecond.
-
-**/
-VOID
-XhcExecTransfer (
- IN USB3_DEBUG_PORT_HANDLE *Handle,
- IN URB *Urb,
- IN UINTN Timeout
- )
-{
- TRANSFER_RING *Ring;
- TRB_TEMPLATE *Trb;
- UINTN Loop;
- UINTN Index;
-
- Loop = Timeout / XHC_DEBUG_PORT_1_MILLISECOND;
- if (Timeout == 0) {
- Loop = 0xFFFFFFFF;
- }
-
- XhcRingDoorBell (Handle, Urb);
- //
- // Event Ring Not Empty bit can only be set to 1 by XHC after ringing door bell with some delay.
- //
- for (Index = 0; Index < Loop; Index++) {
- XhcCheckUrbResult (Handle, Urb);
- if (Urb->Finished) {
- break;
- }
-
- MicroSecondDelay (XHC_DEBUG_PORT_1_MILLISECOND);
- }
-
- if (Index == Loop) {
- //
- // If time out occurs.
- //
- Urb->Result |= EFI_USB_ERR_TIMEOUT;
- }
-
- //
- // If URB transfer is error, restore transfer ring to original value before URB transfer
- // This will make the current transfer TRB is always at the latest unused one in transfer ring.
- //
- Ring = (TRANSFER_RING *)(UINTN)Urb->Ring;
- if ((Urb->Result != EFI_USB_NOERROR) && (Urb->Direction == EfiUsbDataIn)) {
- //
- // Adjust Enqueue pointer
- //
- Ring->RingEnqueue = Urb->Trb;
- //
- // Clear CCS flag for next use
- //
- Trb = (TRB_TEMPLATE *)(UINTN)Urb->Trb;
- Trb->CycleBit = ((~Ring->RingPCS) & BIT0);
- } else {
- //
- // Update transfer ring for next transfer.
- //
- XhcSyncTrsRing (Handle, Ring);
- }
-}
-
-/**
- Create a transfer TRB.
-
- @param Handle Debug port handle.
- @param Urb The urb used to construct the transfer TRB.
-
- @return Created TRB or NULL
-
-**/
-EFI_STATUS
-XhcCreateTransferTrb (
- IN USB3_DEBUG_PORT_HANDLE *Handle,
- IN URB *Urb
- )
-{
- TRANSFER_RING *EPRing;
- TRB *Trb;
-
- if (Urb->Direction == EfiUsbDataIn) {
- EPRing = &Handle->TransferRingIn;
- } else {
- EPRing = &Handle->TransferRingOut;
- }
-
- Urb->Ring = (EFI_PHYSICAL_ADDRESS)(UINTN)EPRing;
- XhcSyncTrsRing (Handle, EPRing);
-
- Urb->Trb = EPRing->RingEnqueue;
- Trb = (TRB *)(UINTN)EPRing->RingEnqueue;
- Trb->TrbNormal.TRBPtrLo = XHC_LOW_32BIT (Urb->Data);
- Trb->TrbNormal.TRBPtrHi = XHC_HIGH_32BIT (Urb->Data);
- Trb->TrbNormal.Length = Urb->DataLen;
- Trb->TrbNormal.TDSize = 0;
- Trb->TrbNormal.IntTarget = 0;
- Trb->TrbNormal.ISP = 1;
- Trb->TrbNormal.IOC = 1;
- Trb->TrbNormal.Type = TRB_TYPE_NORMAL;
-
- //
- // Update the cycle bit to indicate this TRB has been consumed.
- //
- Trb->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;
-
- return EFI_SUCCESS;
-}
-
-/**
- Create a new URB for a new transaction.
-
- @param Handle Debug port handle.
- @param Direction The direction of data flow.
- @param Data The user data to transfer
- @param DataLen The length of data buffer
-
- @return Created URB or NULL
-
-**/
-URB *
-XhcCreateUrb (
- IN USB3_DEBUG_PORT_HANDLE *Handle,
- IN EFI_USB_DATA_DIRECTION Direction,
- IN VOID *Data,
- IN UINTN DataLen
- )
-{
- EFI_STATUS Status;
- URB *Urb;
- EFI_PHYSICAL_ADDRESS UrbData;
-
- if (Direction == EfiUsbDataIn) {
- Urb = &Handle->UrbIn;
- } else {
- Urb = &Handle->UrbOut;
- }
-
- UrbData = Urb->Data;
-
- ZeroMem (Urb, sizeof (URB));
- Urb->Direction = Direction;
-
- //
- // Allocate memory to move data from CAR or SMRAM to normal memory
- // to make XHCI DMA successfully
- // re-use the pre-allocate buffer in PEI to avoid DXE memory service or gBS are not ready
- //
- Urb->Data = UrbData;
-
- if (Direction == EfiUsbDataIn) {
- //
- // Do not break URB data in buffer as it may contain the data which were just put in via DMA by XHC
- //
- Urb->DataLen = (UINT32)DataLen;
- } else {
- //
- // Put data into URB data out buffer which will create TRBs
- //
- ZeroMem ((VOID *)(UINTN)Urb->Data, DataLen);
- CopyMem ((VOID *)(UINTN)Urb->Data, Data, DataLen);
- Urb->DataLen = (UINT32)DataLen;
- }
-
- Status = XhcCreateTransferTrb (Handle, Urb);
- ASSERT_EFI_ERROR (Status);
-
- return Urb;
-}
-
-/**
- Submits bulk transfer to a bulk endpoint of a USB device.
-
- @param Handle Debug port handle.
- @param Direction The direction of data transfer.
- @param Data Array of pointers to the buffers of data to transmit
- from or receive into.
- @param DataLength The length of the data buffer.
- @param Timeout Indicates the maximum time, in microsecond, which
- the transfer is allowed to complete.
-
- @retval EFI_SUCCESS The transfer was completed successfully.
- @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
- @retval EFI_INVALID_PARAMETER Some parameters are invalid.
- @retval EFI_TIMEOUT The transfer failed due to timeout.
- @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
-
-**/
-EFI_STATUS
-EFIAPI
-XhcDataTransfer (
- IN USB3_DEBUG_PORT_HANDLE *Handle,
- IN EFI_USB_DATA_DIRECTION Direction,
- IN OUT VOID *Data,
- IN OUT UINTN *DataLength,
- IN UINTN Timeout
- )
-{
- URB *Urb;
- EFI_STATUS Status;
-
- //
- // Validate the parameters
- //
- if ((DataLength == NULL) || (*DataLength == 0) || (Data == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // Create a new URB, insert it into the asynchronous
- // schedule list, then poll the execution status.
- //
- Urb = XhcCreateUrb (Handle, Direction, Data, *DataLength);
- ASSERT (Urb != NULL);
-
- XhcExecTransfer (Handle, Urb, Timeout);
-
- //
- // Make sure the data received from HW can fit in the received buffer.
- //
- if (Urb->Completed > *DataLength) {
- return EFI_DEVICE_ERROR;
- }
-
- *DataLength = Urb->Completed;
-
- Status = EFI_TIMEOUT;
- if (Urb->Result == EFI_USB_NOERROR) {
- Status = EFI_SUCCESS;
- }
-
- if (Direction == EfiUsbDataIn) {
- //
- // Move data from internal buffer to outside buffer (outside buffer may be in SMRAM...)
- // SMRAM does not allow to do DMA, so we create an internal buffer.
- //
- CopyMem (Data, (VOID *)(UINTN)Urb->Data, *DataLength);
- }
-
- return Status;
-}
+/** @file + Debug Port Library implementation based on usb3 debug port. + + Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include "DebugCommunicationLibUsb3Internal.h" + +/** + Synchronize the specified transfer ring to update the enqueue and dequeue pointer. + + @param Handle Debug port handle. + @param TrsRing The transfer ring to sync. + + @retval EFI_SUCCESS The transfer ring is synchronized successfully. + +**/ +EFI_STATUS +EFIAPI +XhcSyncTrsRing ( + IN USB3_DEBUG_PORT_HANDLE *Handle, + IN TRANSFER_RING *TrsRing + ) +{ + UINTN Index; + TRB_TEMPLATE *TrsTrb; + UINT32 CycleBit; + + ASSERT (TrsRing != NULL); + + // + // Calculate the latest RingEnqueue and RingPCS + // + TrsTrb = (TRB_TEMPLATE *)(UINTN)TrsRing->RingEnqueue; + + ASSERT (TrsTrb != NULL); + + for (Index = 0; Index < TrsRing->TrbNumber; Index++) { + if (TrsTrb->CycleBit != (TrsRing->RingPCS & BIT0)) { + break; + } + + TrsTrb++; + if ((UINT8)TrsTrb->Type == TRB_TYPE_LINK) { + ASSERT (((LINK_TRB *)TrsTrb)->TC != 0); + // + // set cycle bit in Link TRB as normal + // + ((LINK_TRB *)TrsTrb)->CycleBit = TrsRing->RingPCS & BIT0; + // + // Toggle PCS maintained by software + // + TrsRing->RingPCS = (TrsRing->RingPCS & BIT0) ? 0 : 1; + TrsTrb = (TRB_TEMPLATE *)(UINTN)((TrsTrb->Parameter1 | LShiftU64 ((UINT64)TrsTrb->Parameter2, 32)) & ~0x0F); + } + } + + ASSERT (Index != TrsRing->TrbNumber); + + if ((EFI_PHYSICAL_ADDRESS)(UINTN)TrsTrb != TrsRing->RingEnqueue) { + TrsRing->RingEnqueue = (EFI_PHYSICAL_ADDRESS)(UINTN)TrsTrb; + } + + // + // Clear the Trb context for enqueue, but reserve the PCS bit which indicates free Trb. + // + CycleBit = TrsTrb->CycleBit; + ZeroMem (TrsTrb, sizeof (TRB_TEMPLATE)); + TrsTrb->CycleBit = CycleBit; + + return EFI_SUCCESS; +} + +/** + Synchronize the specified event ring to update the enqueue and dequeue pointer. + + @param Handle Debug port handle. + @param EvtRing The event ring to sync. + + @retval EFI_SUCCESS The event ring is synchronized successfully. + +**/ +EFI_STATUS +EFIAPI +XhcSyncEventRing ( + IN USB3_DEBUG_PORT_HANDLE *Handle, + IN EVENT_RING *EvtRing + ) +{ + UINTN Index; + TRB_TEMPLATE *EvtTrb1; + + ASSERT (EvtRing != NULL); + + // + // Calculate the EventRingEnqueue and EventRingCCS. + // Note: only support single Segment + // + EvtTrb1 = (TRB_TEMPLATE *)(UINTN)EvtRing->EventRingDequeue; + + for (Index = 0; Index < EvtRing->TrbNumber; Index++) { + if (EvtTrb1->CycleBit != EvtRing->EventRingCCS) { + break; + } + + EvtTrb1++; + + if ((UINTN)EvtTrb1 >= ((UINTN)EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) { + EvtTrb1 = (TRB_TEMPLATE *)(UINTN)EvtRing->EventRingSeg0; + EvtRing->EventRingCCS = (EvtRing->EventRingCCS) ? 0 : 1; + } + } + + if (Index < EvtRing->TrbNumber) { + EvtRing->EventRingEnqueue = (EFI_PHYSICAL_ADDRESS)(UINTN)EvtTrb1; + } else { + ASSERT (FALSE); + } + + return EFI_SUCCESS; +} + +/** + Check if there is a new generated event. + + @param Handle Debug port handle. + @param EvtRing The event ring to check. + @param NewEvtTrb The new event TRB found. + + @retval EFI_SUCCESS Found a new event TRB at the event ring. + @retval EFI_NOT_READY The event ring has no new event. + +**/ +EFI_STATUS +EFIAPI +XhcCheckNewEvent ( + IN USB3_DEBUG_PORT_HANDLE *Handle, + IN EVENT_RING *EvtRing, + OUT TRB_TEMPLATE **NewEvtTrb + ) +{ + EFI_STATUS Status; + + ASSERT (EvtRing != NULL); + + *NewEvtTrb = (TRB_TEMPLATE *)(UINTN)EvtRing->EventRingDequeue; + + if (EvtRing->EventRingDequeue == EvtRing->EventRingEnqueue) { + return EFI_NOT_READY; + } + + Status = EFI_SUCCESS; + + EvtRing->EventRingDequeue += sizeof (TRB_TEMPLATE); + // + // If the dequeue pointer is beyond the ring, then roll-back it to the beginning of the ring. + // + if ((UINTN)EvtRing->EventRingDequeue >= ((UINTN)EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) { + EvtRing->EventRingDequeue = EvtRing->EventRingSeg0; + } + + return Status; +} + +/** + Check if the Trb is a transaction of the URB. + + @param Ring The transfer ring to be checked. + @param Trb The TRB to be checked. + + @retval TRUE It is a transaction of the URB. + @retval FALSE It is not any transaction of the URB. + +**/ +BOOLEAN +IsTrbInTrsRing ( + IN TRANSFER_RING *Ring, + IN TRB_TEMPLATE *Trb + ) +{ + TRB_TEMPLATE *CheckedTrb; + UINTN Index; + + CheckedTrb = (TRB_TEMPLATE *)(UINTN)Ring->RingSeg0; + + ASSERT (Ring->TrbNumber == TR_RING_TRB_NUMBER); + + for (Index = 0; Index < Ring->TrbNumber; Index++) { + if (Trb == CheckedTrb) { + return TRUE; + } + + CheckedTrb++; + } + + return FALSE; +} + +/** + Check the URB's execution result and update the URB's + result accordingly. + + @param Handle Debug port handle. + @param Urb The URB to check result. + +**/ +VOID +XhcCheckUrbResult ( + IN USB3_DEBUG_PORT_HANDLE *Handle, + IN URB *Urb + ) +{ + EVT_TRB_TRANSFER *EvtTrb; + TRB_TEMPLATE *TRBPtr; + UINTN Index; + EFI_STATUS Status; + URB *CheckedUrb; + UINT64 XhcDequeue; + UINT32 High; + UINT32 Low; + + ASSERT ((Handle != NULL) && (Urb != NULL)); + + if (Urb->Finished) { + goto EXIT; + } + + EvtTrb = NULL; + + // + // Traverse the event ring to find out all new events from the previous check. + // + XhcSyncEventRing (Handle, &Handle->EventRing); + + for (Index = 0; Index < Handle->EventRing.TrbNumber; Index++) { + Status = XhcCheckNewEvent (Handle, &Handle->EventRing, ((TRB_TEMPLATE **)&EvtTrb)); + if (Status == EFI_NOT_READY) { + // + // All new events are handled, return directly. + // + goto EXIT; + } + + if ((EvtTrb->Type != TRB_TYPE_COMMAND_COMPLT_EVENT) && (EvtTrb->Type != TRB_TYPE_TRANS_EVENT)) { + continue; + } + + TRBPtr = (TRB_TEMPLATE *)(UINTN)(EvtTrb->TRBPtrLo | LShiftU64 ((UINT64)EvtTrb->TRBPtrHi, 32)); + + if (IsTrbInTrsRing ((TRANSFER_RING *)(UINTN)(Urb->Ring), TRBPtr)) { + CheckedUrb = Urb; + } else if (IsTrbInTrsRing ((TRANSFER_RING *)(UINTN)(Handle->UrbIn.Ring), TRBPtr)) { + // + // If it is read event and it should be generated by poll, and current operation is write, we need save data into internal buffer. + // Internal buffer is used by next read. + // + Handle->DataCount = (UINT8)(Handle->UrbIn.DataLen - EvtTrb->Length); + CopyMem ((VOID *)(UINTN)Handle->Data, (VOID *)(UINTN)Handle->UrbIn.Data, Handle->DataCount); + // + // Fill this TRB complete with CycleBit, otherwise next read will fail with old TRB. + // + TRBPtr->CycleBit = (TRBPtr->CycleBit & BIT0) ? 0 : 1; + continue; + } else { + continue; + } + + if ((EvtTrb->Completecode == TRB_COMPLETION_SHORT_PACKET) || + (EvtTrb->Completecode == TRB_COMPLETION_SUCCESS)) + { + // + // The length of data which were transferred. + // + CheckedUrb->Completed += (((TRANSFER_TRB_NORMAL *)TRBPtr)->Length - EvtTrb->Length); + } else { + CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT; + } + + // + // This Urb has been processed + // + CheckedUrb->Finished = TRUE; + } + +EXIT: + // + // Advance event ring to last available entry + // + // Some 3rd party XHCI external cards don't support single 64-bytes width register access, + // So divide it to two 32-bytes width register access. + // + Low = XhcReadDebugReg (Handle, XHC_DC_DCERDP); + High = XhcReadDebugReg (Handle, XHC_DC_DCERDP + 4); + XhcDequeue = (UINT64)(LShiftU64 ((UINT64)High, 32) | Low); + + if ((XhcDequeue & (~0x0F)) != ((UINT64)(UINTN)Handle->EventRing.EventRingDequeue & (~0x0F))) { + // + // Some 3rd party XHCI external cards don't support single 64-bytes width register access, + // So divide it to two 32-bytes width register access. + // + XhcWriteDebugReg (Handle, XHC_DC_DCERDP, XHC_LOW_32BIT (Handle->EventRing.EventRingDequeue)); + XhcWriteDebugReg (Handle, XHC_DC_DCERDP + 4, XHC_HIGH_32BIT (Handle->EventRing.EventRingDequeue)); + } +} + +/** + Ring the door bell to notify XHCI there is a transaction to be executed. + + @param Handle Debug port handle. + @param Urb The pointer to URB. + + @retval EFI_SUCCESS Successfully ring the door bell. + +**/ +EFI_STATUS +EFIAPI +XhcRingDoorBell ( + IN USB3_DEBUG_PORT_HANDLE *Handle, + IN URB *Urb + ) +{ + UINT32 Dcdb; + + // + // 7.6.8.2 DCDB Register + // + Dcdb = (Urb->Direction == EfiUsbDataIn) ? 0x100 : 0x0; + + XhcWriteDebugReg ( + Handle, + XHC_DC_DCDB, + Dcdb + ); + + return EFI_SUCCESS; +} + +/** + Execute the transfer by polling the URB. This is a synchronous operation. + + @param Handle Debug port handle. + @param Urb The URB to execute. + @param Timeout The time to wait before abort, in microsecond. + +**/ +VOID +XhcExecTransfer ( + IN USB3_DEBUG_PORT_HANDLE *Handle, + IN URB *Urb, + IN UINTN Timeout + ) +{ + TRANSFER_RING *Ring; + TRB_TEMPLATE *Trb; + UINTN Loop; + UINTN Index; + + Loop = Timeout / XHC_DEBUG_PORT_1_MILLISECOND; + if (Timeout == 0) { + Loop = 0xFFFFFFFF; + } + + XhcRingDoorBell (Handle, Urb); + // + // Event Ring Not Empty bit can only be set to 1 by XHC after ringing door bell with some delay. + // + for (Index = 0; Index < Loop; Index++) { + XhcCheckUrbResult (Handle, Urb); + if (Urb->Finished) { + break; + } + + MicroSecondDelay (XHC_DEBUG_PORT_1_MILLISECOND); + } + + if (Index == Loop) { + // + // If time out occurs. + // + Urb->Result |= EFI_USB_ERR_TIMEOUT; + } + + // + // If URB transfer is error, restore transfer ring to original value before URB transfer + // This will make the current transfer TRB is always at the latest unused one in transfer ring. + // + Ring = (TRANSFER_RING *)(UINTN)Urb->Ring; + if ((Urb->Result != EFI_USB_NOERROR) && (Urb->Direction == EfiUsbDataIn)) { + // + // Adjust Enqueue pointer + // + Ring->RingEnqueue = Urb->Trb; + // + // Clear CCS flag for next use + // + Trb = (TRB_TEMPLATE *)(UINTN)Urb->Trb; + Trb->CycleBit = ((~Ring->RingPCS) & BIT0); + } else { + // + // Update transfer ring for next transfer. + // + XhcSyncTrsRing (Handle, Ring); + } +} + +/** + Create a transfer TRB. + + @param Handle Debug port handle. + @param Urb The urb used to construct the transfer TRB. + + @return Created TRB or NULL + +**/ +EFI_STATUS +XhcCreateTransferTrb ( + IN USB3_DEBUG_PORT_HANDLE *Handle, + IN URB *Urb + ) +{ + TRANSFER_RING *EPRing; + TRB *Trb; + + if (Urb->Direction == EfiUsbDataIn) { + EPRing = &Handle->TransferRingIn; + } else { + EPRing = &Handle->TransferRingOut; + } + + Urb->Ring = (EFI_PHYSICAL_ADDRESS)(UINTN)EPRing; + XhcSyncTrsRing (Handle, EPRing); + + Urb->Trb = EPRing->RingEnqueue; + Trb = (TRB *)(UINTN)EPRing->RingEnqueue; + Trb->TrbNormal.TRBPtrLo = XHC_LOW_32BIT (Urb->Data); + Trb->TrbNormal.TRBPtrHi = XHC_HIGH_32BIT (Urb->Data); + Trb->TrbNormal.Length = Urb->DataLen; + Trb->TrbNormal.TDSize = 0; + Trb->TrbNormal.IntTarget = 0; + Trb->TrbNormal.ISP = 1; + Trb->TrbNormal.IOC = 1; + Trb->TrbNormal.Type = TRB_TYPE_NORMAL; + + // + // Update the cycle bit to indicate this TRB has been consumed. + // + Trb->TrbNormal.CycleBit = EPRing->RingPCS & BIT0; + + return EFI_SUCCESS; +} + +/** + Create a new URB for a new transaction. + + @param Handle Debug port handle. + @param Direction The direction of data flow. + @param Data The user data to transfer + @param DataLen The length of data buffer + + @return Created URB or NULL + +**/ +URB * +XhcCreateUrb ( + IN USB3_DEBUG_PORT_HANDLE *Handle, + IN EFI_USB_DATA_DIRECTION Direction, + IN VOID *Data, + IN UINTN DataLen + ) +{ + EFI_STATUS Status; + URB *Urb; + EFI_PHYSICAL_ADDRESS UrbData; + + if (Direction == EfiUsbDataIn) { + Urb = &Handle->UrbIn; + } else { + Urb = &Handle->UrbOut; + } + + UrbData = Urb->Data; + + ZeroMem (Urb, sizeof (URB)); + Urb->Direction = Direction; + + // + // Allocate memory to move data from CAR or SMRAM to normal memory + // to make XHCI DMA successfully + // re-use the pre-allocate buffer in PEI to avoid DXE memory service or gBS are not ready + // + Urb->Data = UrbData; + + if (Direction == EfiUsbDataIn) { + // + // Do not break URB data in buffer as it may contain the data which were just put in via DMA by XHC + // + Urb->DataLen = (UINT32)DataLen; + } else { + // + // Put data into URB data out buffer which will create TRBs + // + ZeroMem ((VOID *)(UINTN)Urb->Data, DataLen); + CopyMem ((VOID *)(UINTN)Urb->Data, Data, DataLen); + Urb->DataLen = (UINT32)DataLen; + } + + Status = XhcCreateTransferTrb (Handle, Urb); + ASSERT_EFI_ERROR (Status); + + return Urb; +} + +/** + Submits bulk transfer to a bulk endpoint of a USB device. + + @param Handle Debug port handle. + @param Direction The direction of data transfer. + @param Data Array of pointers to the buffers of data to transmit + from or receive into. + @param DataLength The length of the data buffer. + @param Timeout Indicates the maximum time, in microsecond, which + the transfer is allowed to complete. + + @retval EFI_SUCCESS The transfer was completed successfully. + @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource. + @retval EFI_INVALID_PARAMETER Some parameters are invalid. + @retval EFI_TIMEOUT The transfer failed due to timeout. + @retval EFI_DEVICE_ERROR The transfer failed due to host controller error. + +**/ +EFI_STATUS +EFIAPI +XhcDataTransfer ( + IN USB3_DEBUG_PORT_HANDLE *Handle, + IN EFI_USB_DATA_DIRECTION Direction, + IN OUT VOID *Data, + IN OUT UINTN *DataLength, + IN UINTN Timeout + ) +{ + URB *Urb; + EFI_STATUS Status; + + // + // Validate the parameters + // + if ((DataLength == NULL) || (*DataLength == 0) || (Data == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // + // Create a new URB, insert it into the asynchronous + // schedule list, then poll the execution status. + // + Urb = XhcCreateUrb (Handle, Direction, Data, *DataLength); + ASSERT (Urb != NULL); + + XhcExecTransfer (Handle, Urb, Timeout); + + // + // Make sure the data received from HW can fit in the received buffer. + // + if (Urb->Completed > *DataLength) { + return EFI_DEVICE_ERROR; + } + + *DataLength = Urb->Completed; + + Status = EFI_TIMEOUT; + if (Urb->Result == EFI_USB_NOERROR) { + Status = EFI_SUCCESS; + } + + if (Direction == EfiUsbDataIn) { + // + // Move data from internal buffer to outside buffer (outside buffer may be in SMRAM...) + // SMRAM does not allow to do DMA, so we create an internal buffer. + // + CopyMem (Data, (VOID *)(UINTN)Urb->Data, *DataLength); + } + + return Status; +} diff --git a/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/Ia32/IntHandler.nasm b/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/Ia32/IntHandler.nasm index 9442d3adc5..3ef8b4d804 100644 --- a/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/Ia32/IntHandler.nasm +++ b/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/Ia32/IntHandler.nasm @@ -1,22 +1,22 @@ -;------------------------------------------------------------------------------
-;
-; Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
-; SPDX-License-Identifier: BSD-2-Clause-Patent
-;
-; Module Name:
-;
-; IntHandler.nasm
-;
-; Abstract:
-;
-; Assembly interrupt handler function.
-;
-;------------------------------------------------------------------------------
-
-global ASM_PFX(AsmInterruptHandle)
-
-SECTION .text
-ASM_PFX(AsmInterruptHandle):
- cli
- mov al, 1
- iretd
+;------------------------------------------------------------------------------ +; +; Copyright (c) 2016, Intel Corporation. All rights reserved.<BR> +; SPDX-License-Identifier: BSD-2-Clause-Patent +; +; Module Name: +; +; IntHandler.nasm +; +; Abstract: +; +; Assembly interrupt handler function. +; +;------------------------------------------------------------------------------ + +global ASM_PFX(AsmInterruptHandle) + +SECTION .text +ASM_PFX(AsmInterruptHandle): + cli + mov al, 1 + iretd diff --git a/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/Ia32/IntHandlerFuncs.c b/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/Ia32/IntHandlerFuncs.c index 3e6db0db86..a0795b0751 100644 --- a/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/Ia32/IntHandlerFuncs.c +++ b/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/Ia32/IntHandlerFuncs.c @@ -1,93 +1,93 @@ -/** @file
- Ia32 arch functions to access IDT vector.
-
- Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include <PeCoffExtraActionLib.h>
-
-/**
- Read IDT entry to check if IDT entries are setup by Debug Agent.
-
- @param[in] IdtDescriptor Pointer to IDT Descriptor.
- @param[in] InterruptType Interrupt type.
-
- @retval TRUE IDT entries were setup by Debug Agent.
- @retval FALSE IDT entries were not setup by Debug Agent.
-
-**/
-BOOLEAN
-CheckDebugAgentHandler (
- IN IA32_DESCRIPTOR *IdtDescriptor,
- IN UINTN InterruptType
- )
-{
- IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
- UINTN InterruptHandler;
-
- IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)IdtDescriptor->Base;
- if (IdtEntry == NULL) {
- return FALSE;
- }
-
- InterruptHandler = IdtEntry[InterruptType].Bits.OffsetLow +
- (IdtEntry[InterruptType].Bits.OffsetHigh << 16);
- if ((InterruptHandler >= sizeof (UINT32)) && (*(UINT32 *)(InterruptHandler - sizeof (UINT32)) == AGENT_HANDLER_SIGNATURE)) {
- return TRUE;
- } else {
- return FALSE;
- }
-}
-
-/**
- Save IDT entry for INT1 and update it.
-
- @param[in] IdtDescriptor Pointer to IDT Descriptor.
- @param[out] SavedIdtEntry Original IDT entry returned.
-
-**/
-VOID
-SaveAndUpdateIdtEntry1 (
- IN IA32_DESCRIPTOR *IdtDescriptor,
- OUT IA32_IDT_GATE_DESCRIPTOR *SavedIdtEntry
- )
-{
- IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
- UINT16 CodeSegment;
- UINTN InterruptHandler;
-
- IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)IdtDescriptor->Base;
- CopyMem (SavedIdtEntry, &IdtEntry[1], sizeof (IA32_IDT_GATE_DESCRIPTOR));
-
- //
- // Use current CS as the segment selector of interrupt gate in IDT
- //
- CodeSegment = AsmReadCs ();
-
- InterruptHandler = (UINTN)&AsmInterruptHandle;
- IdtEntry[1].Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler;
- IdtEntry[1].Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16);
- IdtEntry[1].Bits.Selector = CodeSegment;
- IdtEntry[1].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
-}
-
-/**
- Restore IDT entry for INT1.
-
- @param[in] IdtDescriptor Pointer to IDT Descriptor.
- @param[in] RestoredIdtEntry IDT entry to be restored.
-
-**/
-VOID
-RestoreIdtEntry1 (
- IN IA32_DESCRIPTOR *IdtDescriptor,
- IN IA32_IDT_GATE_DESCRIPTOR *RestoredIdtEntry
- )
-{
- IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
-
- IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)IdtDescriptor->Base;
- CopyMem (&IdtEntry[1], RestoredIdtEntry, sizeof (IA32_IDT_GATE_DESCRIPTOR));
-}
+/** @file + Ia32 arch functions to access IDT vector. + + Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PeCoffExtraActionLib.h> + +/** + Read IDT entry to check if IDT entries are setup by Debug Agent. + + @param[in] IdtDescriptor Pointer to IDT Descriptor. + @param[in] InterruptType Interrupt type. + + @retval TRUE IDT entries were setup by Debug Agent. + @retval FALSE IDT entries were not setup by Debug Agent. + +**/ +BOOLEAN +CheckDebugAgentHandler ( + IN IA32_DESCRIPTOR *IdtDescriptor, + IN UINTN InterruptType + ) +{ + IA32_IDT_GATE_DESCRIPTOR *IdtEntry; + UINTN InterruptHandler; + + IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)IdtDescriptor->Base; + if (IdtEntry == NULL) { + return FALSE; + } + + InterruptHandler = IdtEntry[InterruptType].Bits.OffsetLow + + (IdtEntry[InterruptType].Bits.OffsetHigh << 16); + if ((InterruptHandler >= sizeof (UINT32)) && (*(UINT32 *)(InterruptHandler - sizeof (UINT32)) == AGENT_HANDLER_SIGNATURE)) { + return TRUE; + } else { + return FALSE; + } +} + +/** + Save IDT entry for INT1 and update it. + + @param[in] IdtDescriptor Pointer to IDT Descriptor. + @param[out] SavedIdtEntry Original IDT entry returned. + +**/ +VOID +SaveAndUpdateIdtEntry1 ( + IN IA32_DESCRIPTOR *IdtDescriptor, + OUT IA32_IDT_GATE_DESCRIPTOR *SavedIdtEntry + ) +{ + IA32_IDT_GATE_DESCRIPTOR *IdtEntry; + UINT16 CodeSegment; + UINTN InterruptHandler; + + IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)IdtDescriptor->Base; + CopyMem (SavedIdtEntry, &IdtEntry[1], sizeof (IA32_IDT_GATE_DESCRIPTOR)); + + // + // Use current CS as the segment selector of interrupt gate in IDT + // + CodeSegment = AsmReadCs (); + + InterruptHandler = (UINTN)&AsmInterruptHandle; + IdtEntry[1].Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler; + IdtEntry[1].Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16); + IdtEntry[1].Bits.Selector = CodeSegment; + IdtEntry[1].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32; +} + +/** + Restore IDT entry for INT1. + + @param[in] IdtDescriptor Pointer to IDT Descriptor. + @param[in] RestoredIdtEntry IDT entry to be restored. + +**/ +VOID +RestoreIdtEntry1 ( + IN IA32_DESCRIPTOR *IdtDescriptor, + IN IA32_IDT_GATE_DESCRIPTOR *RestoredIdtEntry + ) +{ + IA32_IDT_GATE_DESCRIPTOR *IdtEntry; + + IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)IdtDescriptor->Base; + CopyMem (&IdtEntry[1], RestoredIdtEntry, sizeof (IA32_IDT_GATE_DESCRIPTOR)); +} diff --git a/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLib.c b/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLib.c index 2c80f7e22d..755de384d3 100644 --- a/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLib.c +++ b/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLib.c @@ -1,231 +1,231 @@ -/** @file
- PE/Coff Extra Action library instances.
-
- Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include <PeCoffExtraActionLib.h>
-
-/**
- Check if the hardware breakpoint in Drx is enabled by checking the Lx and Gx bit in Dr7.
-
- It assumes that DebugAgent will set both Lx and Gx bit when setting up the hardware breakpoint.
-
-
- @param RegisterIndex Index of Dr register. The value range is from 0 to 3.
- @param Dr7 Value of Dr7 register.
-
- @return TRUE The hardware breakpoint specified in the Drx is enabled.
- @return FALSE The hardware breakpoint specified in the Drx is disabled.
-
-**/
-BOOLEAN
-IsDrxEnabled (
- IN UINT8 RegisterIndex,
- IN UINTN Dr7
- )
-{
- return (BOOLEAN)(((Dr7 >> (RegisterIndex * 2)) & (BIT0 | BIT1)) == (BIT0 | BIT1));
-}
-
-/**
- Common routine to report the PE/COFF image loading/relocating or unloading event.
-
- If ImageContext is NULL, then ASSERT().
-
- @param ImageContext Pointer to the image context structure that describes the
- PE/COFF image.
- @param Signature IMAGE_LOAD_SIGNATURE or IMAGE_UNLOAD_SIGNATURE.
-
-**/
-VOID
-PeCoffLoaderExtraActionCommon (
- IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
- IN UINTN Signature
- )
-{
- BOOLEAN InterruptState;
- UINTN Dr0;
- UINTN Dr1;
- UINTN Dr2;
- UINTN Dr3;
- UINTN Dr7;
- UINTN Cr4;
- UINTN NewDr7;
- UINT8 LoadImageMethod;
- UINT8 DebugAgentStatus;
- IA32_DESCRIPTOR IdtDescriptor;
- IA32_IDT_GATE_DESCRIPTOR OriginalIdtEntry;
- BOOLEAN IdtEntryHooked;
- UINT32 RegEdx;
-
- ASSERT (ImageContext != NULL);
-
- if (ImageContext->PdbPointer != NULL) {
- DEBUG ((DEBUG_ERROR, " PDB = %a\n", ImageContext->PdbPointer));
- }
-
- //
- // Disable interrupts and save the current interrupt state
- //
- InterruptState = SaveAndDisableInterrupts ();
-
- IdtEntryHooked = FALSE;
- LoadImageMethod = PcdGet8 (PcdDebugLoadImageMethod);
- if (LoadImageMethod == DEBUG_LOAD_IMAGE_METHOD_IO_HW_BREAKPOINT) {
- //
- // If the CPU does not support Debug Extensions(CPUID:01 EDX:BIT2)
- // then force use of DEBUG_LOAD_IMAGE_METHOD_SOFT_INT3
- //
- AsmCpuid (1, NULL, NULL, NULL, &RegEdx);
- if ((RegEdx & BIT2) == 0) {
- LoadImageMethod = DEBUG_LOAD_IMAGE_METHOD_SOFT_INT3;
- }
- }
-
- AsmReadIdtr (&IdtDescriptor);
- if (LoadImageMethod == DEBUG_LOAD_IMAGE_METHOD_SOFT_INT3) {
- if (!CheckDebugAgentHandler (&IdtDescriptor, SOFT_INT_VECTOR_NUM)) {
- //
- // Do not trigger INT3 if Debug Agent did not setup IDT entries.
- //
- return;
- }
- } else {
- if (!CheckDebugAgentHandler (&IdtDescriptor, IO_HW_BREAKPOINT_VECTOR_NUM)) {
- //
- // Save and update IDT entry for INT1
- //
- SaveAndUpdateIdtEntry1 (&IdtDescriptor, &OriginalIdtEntry);
- IdtEntryHooked = TRUE;
- }
- }
-
- //
- // Save Debug Register State
- //
- Dr0 = AsmReadDr0 ();
- Dr1 = AsmReadDr1 ();
- Dr2 = AsmReadDr2 ();
- Dr3 = AsmReadDr3 ();
- Dr7 = AsmReadDr7 () | BIT10; // H/w sets bit 10, some simulators don't
- Cr4 = AsmReadCr4 ();
-
- //
- // DR0 = Signature
- // DR1 = The address of the Null-terminated ASCII string for the PE/COFF image's PDB file name
- // DR2 = The pointer to the ImageContext structure
- // DR3 = IO_PORT_BREAKPOINT_ADDRESS
- // DR7 = Disables all HW breakpoints except for DR3 I/O port access of length 1 byte
- // CR4 = Make sure DE(BIT3) is set
- //
- AsmWriteDr7 (BIT10);
- AsmWriteDr0 (Signature);
- AsmWriteDr1 ((UINTN)ImageContext->PdbPointer);
- AsmWriteDr2 ((UINTN)ImageContext);
- AsmWriteDr3 (IO_PORT_BREAKPOINT_ADDRESS);
-
- if (LoadImageMethod == DEBUG_LOAD_IMAGE_METHOD_IO_HW_BREAKPOINT) {
- AsmWriteDr7 (0x20000480);
- AsmWriteCr4 (Cr4 | BIT3);
- //
- // Do an IN from IO_PORT_BREAKPOINT_ADDRESS to generate a HW breakpoint until the port
- // returns a read value other than DEBUG_AGENT_IMAGE_WAIT
- //
- do {
- DebugAgentStatus = IoRead8 (IO_PORT_BREAKPOINT_ADDRESS);
- } while (DebugAgentStatus == DEBUG_AGENT_IMAGE_WAIT);
- } else if (LoadImageMethod == DEBUG_LOAD_IMAGE_METHOD_SOFT_INT3) {
- //
- // Generate a software break point.
- //
- CpuBreakpoint ();
- }
-
- //
- // Restore Debug Register State only when Host didn't change it inside exception handler.
- // E.g.: User halts the target and sets the HW breakpoint while target is
- // in the above exception handler
- //
- NewDr7 = AsmReadDr7 () | BIT10; // H/w sets bit 10, some simulators don't
- if (!IsDrxEnabled (0, NewDr7) && ((AsmReadDr0 () == 0) || (AsmReadDr0 () == Signature))) {
- //
- // If user changed Dr3 (by setting HW bp in the above exception handler,
- // we will not set Dr0 to 0 in GO/STEP handler because the break cause is not IMAGE_LOAD/_UNLOAD.
- //
- AsmWriteDr0 (Dr0);
- }
-
- if (!IsDrxEnabled (1, NewDr7) && (AsmReadDr1 () == (UINTN)ImageContext->PdbPointer)) {
- AsmWriteDr1 (Dr1);
- }
-
- if (!IsDrxEnabled (2, NewDr7) && (AsmReadDr2 () == (UINTN)ImageContext)) {
- AsmWriteDr2 (Dr2);
- }
-
- if (!IsDrxEnabled (3, NewDr7) && (AsmReadDr3 () == IO_PORT_BREAKPOINT_ADDRESS)) {
- AsmWriteDr3 (Dr3);
- }
-
- if (LoadImageMethod == DEBUG_LOAD_IMAGE_METHOD_IO_HW_BREAKPOINT) {
- if (AsmReadCr4 () == (Cr4 | BIT3)) {
- AsmWriteCr4 (Cr4);
- }
-
- if (NewDr7 == 0x20000480) {
- AsmWriteDr7 (Dr7);
- }
- } else if (LoadImageMethod == DEBUG_LOAD_IMAGE_METHOD_SOFT_INT3) {
- if (NewDr7 == BIT10) {
- AsmWriteDr7 (Dr7);
- }
- }
-
- //
- // Restore original IDT entry for INT1 if it was hooked.
- //
- if (IdtEntryHooked) {
- RestoreIdtEntry1 (&IdtDescriptor, &OriginalIdtEntry);
- }
-
- //
- // Restore the interrupt state
- //
- SetInterruptState (InterruptState);
-}
-
-/**
- Performs additional actions after a PE/COFF image has been loaded and relocated.
-
- @param ImageContext Pointer to the image context structure that describes the
- PE/COFF image that has already been loaded and relocated.
-
-**/
-VOID
-EFIAPI
-PeCoffLoaderRelocateImageExtraAction (
- IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
- )
-{
- PeCoffLoaderExtraActionCommon (ImageContext, IMAGE_LOAD_SIGNATURE);
-}
-
-/**
- Performs additional actions just before a PE/COFF image is unloaded. Any resources
- that were allocated by PeCoffLoaderRelocateImageExtraAction() must be freed.
-
- @param ImageContext Pointer to the image context structure that describes the
- PE/COFF image that is being unloaded.
-
-**/
-VOID
-EFIAPI
-PeCoffLoaderUnloadImageExtraAction (
- IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
- )
-{
- PeCoffLoaderExtraActionCommon (ImageContext, IMAGE_UNLOAD_SIGNATURE);
-}
+/** @file + PE/Coff Extra Action library instances. + + Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PeCoffExtraActionLib.h> + +/** + Check if the hardware breakpoint in Drx is enabled by checking the Lx and Gx bit in Dr7. + + It assumes that DebugAgent will set both Lx and Gx bit when setting up the hardware breakpoint. + + + @param RegisterIndex Index of Dr register. The value range is from 0 to 3. + @param Dr7 Value of Dr7 register. + + @return TRUE The hardware breakpoint specified in the Drx is enabled. + @return FALSE The hardware breakpoint specified in the Drx is disabled. + +**/ +BOOLEAN +IsDrxEnabled ( + IN UINT8 RegisterIndex, + IN UINTN Dr7 + ) +{ + return (BOOLEAN)(((Dr7 >> (RegisterIndex * 2)) & (BIT0 | BIT1)) == (BIT0 | BIT1)); +} + +/** + Common routine to report the PE/COFF image loading/relocating or unloading event. + + If ImageContext is NULL, then ASSERT(). + + @param ImageContext Pointer to the image context structure that describes the + PE/COFF image. + @param Signature IMAGE_LOAD_SIGNATURE or IMAGE_UNLOAD_SIGNATURE. + +**/ +VOID +PeCoffLoaderExtraActionCommon ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, + IN UINTN Signature + ) +{ + BOOLEAN InterruptState; + UINTN Dr0; + UINTN Dr1; + UINTN Dr2; + UINTN Dr3; + UINTN Dr7; + UINTN Cr4; + UINTN NewDr7; + UINT8 LoadImageMethod; + UINT8 DebugAgentStatus; + IA32_DESCRIPTOR IdtDescriptor; + IA32_IDT_GATE_DESCRIPTOR OriginalIdtEntry; + BOOLEAN IdtEntryHooked; + UINT32 RegEdx; + + ASSERT (ImageContext != NULL); + + if (ImageContext->PdbPointer != NULL) { + DEBUG ((DEBUG_ERROR, " PDB = %a\n", ImageContext->PdbPointer)); + } + + // + // Disable interrupts and save the current interrupt state + // + InterruptState = SaveAndDisableInterrupts (); + + IdtEntryHooked = FALSE; + LoadImageMethod = PcdGet8 (PcdDebugLoadImageMethod); + if (LoadImageMethod == DEBUG_LOAD_IMAGE_METHOD_IO_HW_BREAKPOINT) { + // + // If the CPU does not support Debug Extensions(CPUID:01 EDX:BIT2) + // then force use of DEBUG_LOAD_IMAGE_METHOD_SOFT_INT3 + // + AsmCpuid (1, NULL, NULL, NULL, &RegEdx); + if ((RegEdx & BIT2) == 0) { + LoadImageMethod = DEBUG_LOAD_IMAGE_METHOD_SOFT_INT3; + } + } + + AsmReadIdtr (&IdtDescriptor); + if (LoadImageMethod == DEBUG_LOAD_IMAGE_METHOD_SOFT_INT3) { + if (!CheckDebugAgentHandler (&IdtDescriptor, SOFT_INT_VECTOR_NUM)) { + // + // Do not trigger INT3 if Debug Agent did not setup IDT entries. + // + return; + } + } else { + if (!CheckDebugAgentHandler (&IdtDescriptor, IO_HW_BREAKPOINT_VECTOR_NUM)) { + // + // Save and update IDT entry for INT1 + // + SaveAndUpdateIdtEntry1 (&IdtDescriptor, &OriginalIdtEntry); + IdtEntryHooked = TRUE; + } + } + + // + // Save Debug Register State + // + Dr0 = AsmReadDr0 (); + Dr1 = AsmReadDr1 (); + Dr2 = AsmReadDr2 (); + Dr3 = AsmReadDr3 (); + Dr7 = AsmReadDr7 () | BIT10; // H/w sets bit 10, some simulators don't + Cr4 = AsmReadCr4 (); + + // + // DR0 = Signature + // DR1 = The address of the Null-terminated ASCII string for the PE/COFF image's PDB file name + // DR2 = The pointer to the ImageContext structure + // DR3 = IO_PORT_BREAKPOINT_ADDRESS + // DR7 = Disables all HW breakpoints except for DR3 I/O port access of length 1 byte + // CR4 = Make sure DE(BIT3) is set + // + AsmWriteDr7 (BIT10); + AsmWriteDr0 (Signature); + AsmWriteDr1 ((UINTN)ImageContext->PdbPointer); + AsmWriteDr2 ((UINTN)ImageContext); + AsmWriteDr3 (IO_PORT_BREAKPOINT_ADDRESS); + + if (LoadImageMethod == DEBUG_LOAD_IMAGE_METHOD_IO_HW_BREAKPOINT) { + AsmWriteDr7 (0x20000480); + AsmWriteCr4 (Cr4 | BIT3); + // + // Do an IN from IO_PORT_BREAKPOINT_ADDRESS to generate a HW breakpoint until the port + // returns a read value other than DEBUG_AGENT_IMAGE_WAIT + // + do { + DebugAgentStatus = IoRead8 (IO_PORT_BREAKPOINT_ADDRESS); + } while (DebugAgentStatus == DEBUG_AGENT_IMAGE_WAIT); + } else if (LoadImageMethod == DEBUG_LOAD_IMAGE_METHOD_SOFT_INT3) { + // + // Generate a software break point. + // + CpuBreakpoint (); + } + + // + // Restore Debug Register State only when Host didn't change it inside exception handler. + // E.g.: User halts the target and sets the HW breakpoint while target is + // in the above exception handler + // + NewDr7 = AsmReadDr7 () | BIT10; // H/w sets bit 10, some simulators don't + if (!IsDrxEnabled (0, NewDr7) && ((AsmReadDr0 () == 0) || (AsmReadDr0 () == Signature))) { + // + // If user changed Dr3 (by setting HW bp in the above exception handler, + // we will not set Dr0 to 0 in GO/STEP handler because the break cause is not IMAGE_LOAD/_UNLOAD. + // + AsmWriteDr0 (Dr0); + } + + if (!IsDrxEnabled (1, NewDr7) && (AsmReadDr1 () == (UINTN)ImageContext->PdbPointer)) { + AsmWriteDr1 (Dr1); + } + + if (!IsDrxEnabled (2, NewDr7) && (AsmReadDr2 () == (UINTN)ImageContext)) { + AsmWriteDr2 (Dr2); + } + + if (!IsDrxEnabled (3, NewDr7) && (AsmReadDr3 () == IO_PORT_BREAKPOINT_ADDRESS)) { + AsmWriteDr3 (Dr3); + } + + if (LoadImageMethod == DEBUG_LOAD_IMAGE_METHOD_IO_HW_BREAKPOINT) { + if (AsmReadCr4 () == (Cr4 | BIT3)) { + AsmWriteCr4 (Cr4); + } + + if (NewDr7 == 0x20000480) { + AsmWriteDr7 (Dr7); + } + } else if (LoadImageMethod == DEBUG_LOAD_IMAGE_METHOD_SOFT_INT3) { + if (NewDr7 == BIT10) { + AsmWriteDr7 (Dr7); + } + } + + // + // Restore original IDT entry for INT1 if it was hooked. + // + if (IdtEntryHooked) { + RestoreIdtEntry1 (&IdtDescriptor, &OriginalIdtEntry); + } + + // + // Restore the interrupt state + // + SetInterruptState (InterruptState); +} + +/** + Performs additional actions after a PE/COFF image has been loaded and relocated. + + @param ImageContext Pointer to the image context structure that describes the + PE/COFF image that has already been loaded and relocated. + +**/ +VOID +EFIAPI +PeCoffLoaderRelocateImageExtraAction ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + PeCoffLoaderExtraActionCommon (ImageContext, IMAGE_LOAD_SIGNATURE); +} + +/** + Performs additional actions just before a PE/COFF image is unloaded. Any resources + that were allocated by PeCoffLoaderRelocateImageExtraAction() must be freed. + + @param ImageContext Pointer to the image context structure that describes the + PE/COFF image that is being unloaded. + +**/ +VOID +EFIAPI +PeCoffLoaderUnloadImageExtraAction ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + PeCoffLoaderExtraActionCommon (ImageContext, IMAGE_UNLOAD_SIGNATURE); +} diff --git a/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLib.h b/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLib.h index f428af9632..141493dbbc 100644 --- a/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLib.h +++ b/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLib.h @@ -1,72 +1,72 @@ -/** @file
- PE/Coff Extra Action library instances, it will report image debug info.
-
- Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _PE_COFF_EXTRA_ACTION_LIB_H_
-#define _PE_COFF_EXTRA_ACTION_LIB_H_
-
-#include <Base.h>
-#include <Library/PeCoffExtraActionLib.h>
-#include <Library/DebugLib.h>
-#include <Library/BaseLib.h>
-#include <Library/IoLib.h>
-#include <Library/PcdLib.h>
-#include <Library/BaseMemoryLib.h>
-
-#include <ImageDebugSupport.h>
-
-#define DEBUG_LOAD_IMAGE_METHOD_IO_HW_BREAKPOINT 1
-#define DEBUG_LOAD_IMAGE_METHOD_SOFT_INT3 2
-
-#define IO_HW_BREAKPOINT_VECTOR_NUM 1
-#define SOFT_INT_VECTOR_NUM 3
-
-extern UINTN AsmInterruptHandle;
-
-/**
- Read IDT entry to check if IDT entries are setup by Debug Agent.
-
- @param[in] IdtDescriptor Pointer to IDT Descriptor.
- @param[in] InterruptType Interrupt type.
-
- @retval TRUE IDT entries were setup by Debug Agent.
- @retval FALSE IDT entries were not setup by Debug Agent.
-
-**/
-BOOLEAN
-CheckDebugAgentHandler (
- IN IA32_DESCRIPTOR *IdtDescriptor,
- IN UINTN InterruptType
- );
-
-/**
- Save IDT entry for INT1 and update it.
-
- @param[in] IdtDescriptor Pointer to IDT Descriptor.
- @param[out] SavedIdtEntry Original IDT entry returned.
-
-**/
-VOID
-SaveAndUpdateIdtEntry1 (
- IN IA32_DESCRIPTOR *IdtDescriptor,
- OUT IA32_IDT_GATE_DESCRIPTOR *SavedIdtEntry
- );
-
-/**
- Restore IDT entry for INT1.
-
- @param[in] IdtDescriptor Pointer to IDT Descriptor.
- @param[in] RestoredIdtEntry IDT entry to be restored.
-
-**/
-VOID
-RestoreIdtEntry1 (
- IN IA32_DESCRIPTOR *IdtDescriptor,
- IN IA32_IDT_GATE_DESCRIPTOR *RestoredIdtEntry
- );
-
-#endif
+/** @file + PE/Coff Extra Action library instances, it will report image debug info. + + Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _PE_COFF_EXTRA_ACTION_LIB_H_ +#define _PE_COFF_EXTRA_ACTION_LIB_H_ + +#include <Base.h> +#include <Library/PeCoffExtraActionLib.h> +#include <Library/DebugLib.h> +#include <Library/BaseLib.h> +#include <Library/IoLib.h> +#include <Library/PcdLib.h> +#include <Library/BaseMemoryLib.h> + +#include <ImageDebugSupport.h> + +#define DEBUG_LOAD_IMAGE_METHOD_IO_HW_BREAKPOINT 1 +#define DEBUG_LOAD_IMAGE_METHOD_SOFT_INT3 2 + +#define IO_HW_BREAKPOINT_VECTOR_NUM 1 +#define SOFT_INT_VECTOR_NUM 3 + +extern UINTN AsmInterruptHandle; + +/** + Read IDT entry to check if IDT entries are setup by Debug Agent. + + @param[in] IdtDescriptor Pointer to IDT Descriptor. + @param[in] InterruptType Interrupt type. + + @retval TRUE IDT entries were setup by Debug Agent. + @retval FALSE IDT entries were not setup by Debug Agent. + +**/ +BOOLEAN +CheckDebugAgentHandler ( + IN IA32_DESCRIPTOR *IdtDescriptor, + IN UINTN InterruptType + ); + +/** + Save IDT entry for INT1 and update it. + + @param[in] IdtDescriptor Pointer to IDT Descriptor. + @param[out] SavedIdtEntry Original IDT entry returned. + +**/ +VOID +SaveAndUpdateIdtEntry1 ( + IN IA32_DESCRIPTOR *IdtDescriptor, + OUT IA32_IDT_GATE_DESCRIPTOR *SavedIdtEntry + ); + +/** + Restore IDT entry for INT1. + + @param[in] IdtDescriptor Pointer to IDT Descriptor. + @param[in] RestoredIdtEntry IDT entry to be restored. + +**/ +VOID +RestoreIdtEntry1 ( + IN IA32_DESCRIPTOR *IdtDescriptor, + IN IA32_IDT_GATE_DESCRIPTOR *RestoredIdtEntry + ); + +#endif diff --git a/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLib.uni b/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLib.uni index 965aa644ab..b86a5fc4c7 100644 --- a/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLib.uni +++ b/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLib.uni @@ -1,16 +1,16 @@ -// /** @file
-// PeCoffExtraAction Library to support source level debug.
-//
-// PeCoffExtraAction Library to support source level debug.
-//
-// Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
-//
-// SPDX-License-Identifier: BSD-2-Clause-Patent
-//
-// **/
-
-
-#string STR_MODULE_ABSTRACT #language en-US "PeCoffExtraAction Library to support source level debug"
-
-#string STR_MODULE_DESCRIPTION #language en-US "PeCoffExtraAction Library to support source level debug."
-
+// /** @file +// PeCoffExtraAction Library to support source level debug. +// +// PeCoffExtraAction Library to support source level debug. +// +// Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR> +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "PeCoffExtraAction Library to support source level debug" + +#string STR_MODULE_DESCRIPTION #language en-US "PeCoffExtraAction Library to support source level debug." + diff --git a/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLibDebug.inf b/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLibDebug.inf index 1feed2c3c8..06a8ae1a6c 100644 --- a/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLibDebug.inf +++ b/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLibDebug.inf @@ -1,50 +1,50 @@ -## @file
-# PeCoffExtraAction Library to support source level debug.
-#
-# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-#
-##
-
-[Defines]
- INF_VERSION = 0x00010005
- BASE_NAME = PeCoffExtraActionLib
- MODULE_UNI_FILE = PeCoffExtraActionLib.uni
- FILE_GUID = 8F01CBD5-E069-44d7-90C9-35F0318603AD
- MODULE_TYPE = BASE
- VERSION_STRING = 0.8
- LIBRARY_CLASS = PeCoffExtraActionLib
-
-#
-# The following information is for reference only and not required by the build tools.
-#
-# VALID_ARCHITECTURES = IA32 X64
-#
-
-[Sources.common]
- PeCoffExtraActionLib.h
- PeCoffExtraActionLib.c
-
-[Sources.IA32]
- Ia32/IntHandlerFuncs.c
- Ia32/IntHandler.nasm
-
-[Sources.X64]
- X64/IntHandlerFuncs.c
- X64/IntHandler.nasm
-
-[Packages]
- MdePkg/MdePkg.dec
- SourceLevelDebugPkg/SourceLevelDebugPkg.dec
-
-[LibraryClasses]
- BaseLib
- DebugLib
- IoLib
- PcdLib
-
-[Pcd]
- gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdDebugLoadImageMethod ## CONSUMES
-
+## @file +# PeCoffExtraAction Library to support source level debug. +# +# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PeCoffExtraActionLib + MODULE_UNI_FILE = PeCoffExtraActionLib.uni + FILE_GUID = 8F01CBD5-E069-44d7-90C9-35F0318603AD + MODULE_TYPE = BASE + VERSION_STRING = 0.8 + LIBRARY_CLASS = PeCoffExtraActionLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources.common] + PeCoffExtraActionLib.h + PeCoffExtraActionLib.c + +[Sources.IA32] + Ia32/IntHandlerFuncs.c + Ia32/IntHandler.nasm + +[Sources.X64] + X64/IntHandlerFuncs.c + X64/IntHandler.nasm + +[Packages] + MdePkg/MdePkg.dec + SourceLevelDebugPkg/SourceLevelDebugPkg.dec + +[LibraryClasses] + BaseLib + DebugLib + IoLib + PcdLib + +[Pcd] + gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdDebugLoadImageMethod ## CONSUMES + diff --git a/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/X64/IntHandler.nasm b/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/X64/IntHandler.nasm index 6b3a7a526f..4e63774975 100644 --- a/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/X64/IntHandler.nasm +++ b/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/X64/IntHandler.nasm @@ -1,23 +1,23 @@ -;------------------------------------------------------------------------------
-;
-; Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
-; SPDX-License-Identifier: BSD-2-Clause-Patent
-;
-; Module Name:
-;
-; IntHandler.nasm
-;
-; Abstract:
-;
-; Assembly interrupt handler function.
-;
-;------------------------------------------------------------------------------
-
-global ASM_PFX(AsmInterruptHandle)
-
-DEFAULT REL
-SECTION .text
-ASM_PFX(AsmInterruptHandle):
- cli
- mov al, 1
- iretq
+;------------------------------------------------------------------------------ +; +; Copyright (c) 2016, Intel Corporation. All rights reserved.<BR> +; SPDX-License-Identifier: BSD-2-Clause-Patent +; +; Module Name: +; +; IntHandler.nasm +; +; Abstract: +; +; Assembly interrupt handler function. +; +;------------------------------------------------------------------------------ + +global ASM_PFX(AsmInterruptHandle) + +DEFAULT REL +SECTION .text +ASM_PFX(AsmInterruptHandle): + cli + mov al, 1 + iretq diff --git a/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/X64/IntHandlerFuncs.c b/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/X64/IntHandlerFuncs.c index 1baa88206b..a4e7b88f2d 100644 --- a/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/X64/IntHandlerFuncs.c +++ b/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/X64/IntHandlerFuncs.c @@ -1,95 +1,95 @@ -/** @file
- X64 arch function to access IDT vector.
-
- Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include <PeCoffExtraActionLib.h>
-
-/**
- Read IDT entry to check if IDT entries are setup by Debug Agent.
-
- @param[in] IdtDescriptor Pointer to IDT Descriptor.
- @param[in] InterruptType Interrupt type.
-
- @retval TRUE IDT entries were setup by Debug Agent.
- @retval FALSE IDT entries were not setup by Debug Agent.
-
-**/
-BOOLEAN
-CheckDebugAgentHandler (
- IN IA32_DESCRIPTOR *IdtDescriptor,
- IN UINTN InterruptType
- )
-{
- IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
- UINTN InterruptHandler;
-
- IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)IdtDescriptor->Base;
- if (IdtEntry == NULL) {
- return FALSE;
- }
-
- InterruptHandler = IdtEntry[InterruptType].Bits.OffsetLow +
- (((UINTN)IdtEntry[InterruptType].Bits.OffsetHigh) << 16) +
- (((UINTN)IdtEntry[InterruptType].Bits.OffsetUpper) << 32);
- if ((InterruptHandler >= sizeof (UINT32)) && (*(UINT32 *)(InterruptHandler - sizeof (UINT32)) == AGENT_HANDLER_SIGNATURE)) {
- return TRUE;
- } else {
- return FALSE;
- }
-}
-
-/**
- Save IDT entry for INT1 and update it.
-
- @param[in] IdtDescriptor Pointer to IDT Descriptor.
- @param[out] SavedIdtEntry Original IDT entry returned.
-
-**/
-VOID
-SaveAndUpdateIdtEntry1 (
- IN IA32_DESCRIPTOR *IdtDescriptor,
- OUT IA32_IDT_GATE_DESCRIPTOR *SavedIdtEntry
- )
-{
- IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
- UINT16 CodeSegment;
- UINTN InterruptHandler;
-
- IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)IdtDescriptor->Base;
- CopyMem (SavedIdtEntry, &IdtEntry[1], sizeof (IA32_IDT_GATE_DESCRIPTOR));
-
- //
- // Use current CS as the segment selector of interrupt gate in IDT
- //
- CodeSegment = AsmReadCs ();
-
- InterruptHandler = (UINTN)&AsmInterruptHandle;
- IdtEntry[1].Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler;
- IdtEntry[1].Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16);
- IdtEntry[1].Bits.OffsetUpper = (UINT32)((UINTN)InterruptHandler >> 32);
- IdtEntry[1].Bits.Selector = CodeSegment;
- IdtEntry[1].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
-}
-
-/**
- Restore IDT entry for INT1.
-
- @param[in] IdtDescriptor Pointer to IDT Descriptor.
- @param[in] RestoredIdtEntry IDT entry to be restored.
-
-**/
-VOID
-RestoreIdtEntry1 (
- IN IA32_DESCRIPTOR *IdtDescriptor,
- IN IA32_IDT_GATE_DESCRIPTOR *RestoredIdtEntry
- )
-{
- IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
-
- IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)IdtDescriptor->Base;
- CopyMem (&IdtEntry[1], RestoredIdtEntry, sizeof (IA32_IDT_GATE_DESCRIPTOR));
-}
+/** @file + X64 arch function to access IDT vector. + + Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PeCoffExtraActionLib.h> + +/** + Read IDT entry to check if IDT entries are setup by Debug Agent. + + @param[in] IdtDescriptor Pointer to IDT Descriptor. + @param[in] InterruptType Interrupt type. + + @retval TRUE IDT entries were setup by Debug Agent. + @retval FALSE IDT entries were not setup by Debug Agent. + +**/ +BOOLEAN +CheckDebugAgentHandler ( + IN IA32_DESCRIPTOR *IdtDescriptor, + IN UINTN InterruptType + ) +{ + IA32_IDT_GATE_DESCRIPTOR *IdtEntry; + UINTN InterruptHandler; + + IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)IdtDescriptor->Base; + if (IdtEntry == NULL) { + return FALSE; + } + + InterruptHandler = IdtEntry[InterruptType].Bits.OffsetLow + + (((UINTN)IdtEntry[InterruptType].Bits.OffsetHigh) << 16) + + (((UINTN)IdtEntry[InterruptType].Bits.OffsetUpper) << 32); + if ((InterruptHandler >= sizeof (UINT32)) && (*(UINT32 *)(InterruptHandler - sizeof (UINT32)) == AGENT_HANDLER_SIGNATURE)) { + return TRUE; + } else { + return FALSE; + } +} + +/** + Save IDT entry for INT1 and update it. + + @param[in] IdtDescriptor Pointer to IDT Descriptor. + @param[out] SavedIdtEntry Original IDT entry returned. + +**/ +VOID +SaveAndUpdateIdtEntry1 ( + IN IA32_DESCRIPTOR *IdtDescriptor, + OUT IA32_IDT_GATE_DESCRIPTOR *SavedIdtEntry + ) +{ + IA32_IDT_GATE_DESCRIPTOR *IdtEntry; + UINT16 CodeSegment; + UINTN InterruptHandler; + + IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)IdtDescriptor->Base; + CopyMem (SavedIdtEntry, &IdtEntry[1], sizeof (IA32_IDT_GATE_DESCRIPTOR)); + + // + // Use current CS as the segment selector of interrupt gate in IDT + // + CodeSegment = AsmReadCs (); + + InterruptHandler = (UINTN)&AsmInterruptHandle; + IdtEntry[1].Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler; + IdtEntry[1].Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16); + IdtEntry[1].Bits.OffsetUpper = (UINT32)((UINTN)InterruptHandler >> 32); + IdtEntry[1].Bits.Selector = CodeSegment; + IdtEntry[1].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32; +} + +/** + Restore IDT entry for INT1. + + @param[in] IdtDescriptor Pointer to IDT Descriptor. + @param[in] RestoredIdtEntry IDT entry to be restored. + +**/ +VOID +RestoreIdtEntry1 ( + IN IA32_DESCRIPTOR *IdtDescriptor, + IN IA32_IDT_GATE_DESCRIPTOR *RestoredIdtEntry + ) +{ + IA32_IDT_GATE_DESCRIPTOR *IdtEntry; + + IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)IdtDescriptor->Base; + CopyMem (&IdtEntry[1], RestoredIdtEntry, sizeof (IA32_IDT_GATE_DESCRIPTOR)); +} |
