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