Home | History | Annotate | Download | only in DxeDebugAgent
      1 /** @file
      2   Install Serial IO Protocol that layers on top of a Debug Communication Library instance.
      3 
      4   Copyright (c) 2012 - 2015, Intel Corporation. All rights reserved.<BR>
      5   This program and the accompanying materials
      6   are licensed and made available under the terms and conditions of the BSD License
      7   which accompanies this distribution.  The full text of the license may be found at
      8   http://opensource.org/licenses/bsd-license.php.
      9 
     10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "DxeDebugAgentLib.h"
     16 
     17 //
     18 // Serial I/O Protocol Interface defintions.
     19 //
     20 
     21 /**
     22   Reset serial device.
     23 
     24   @param[in] This           Pointer to EFI_SERIAL_IO_PROTOCOL.
     25 
     26   @retval EFI_SUCCESS       Reset successfully.
     27 
     28 **/
     29 EFI_STATUS
     30 EFIAPI
     31 SerialReset (
     32   IN EFI_SERIAL_IO_PROTOCOL  *This
     33   );
     34 
     35 /**
     36   Set new attributes to a serial device.
     37 
     38   @param[in]  This                Pointer to EFI_SERIAL_IO_PROTOCOL.
     39   @param[in]  BaudRate            The baudrate of the serial device.
     40   @param[in]  ReceiveFifoDepth    The depth of receive FIFO buffer.
     41   @param[in]  Timeout             The request timeout for a single char.
     42   @param[in]  Parity              The type of parity used in serial device.
     43   @param[in]  DataBits            Number of databits used in serial device.
     44   @param[in]  StopBits            Number of stopbits used in serial device.
     45 
     46   @retval EFI_SUCCESS             The new attributes were set.
     47   @retval EFI_INVALID_PARAMETER   One or more attributes have an unsupported value.
     48   @retval EFI_DEVICE_ERROR        The serial device is not functioning correctly (no return).
     49 
     50 **/
     51 EFI_STATUS
     52 EFIAPI
     53 SerialSetAttributes (
     54   IN EFI_SERIAL_IO_PROTOCOL  *This,
     55   IN UINT64                  BaudRate,
     56   IN UINT32                  ReceiveFifoDepth,
     57   IN UINT32                  Timeout,
     58   IN EFI_PARITY_TYPE         Parity,
     59   IN UINT8                   DataBits,
     60   IN EFI_STOP_BITS_TYPE      StopBits
     61   );
     62 
     63 /**
     64   Set Control Bits.
     65 
     66   @param[in] This            Pointer to EFI_SERIAL_IO_PROTOCOL.
     67   @param[in] Control         Control bits that can be settable.
     68 
     69   @retval EFI_SUCCESS        New Control bits were set successfully.
     70   @retval EFI_UNSUPPORTED    The Control bits wanted to set are not supported.
     71 
     72 **/
     73 EFI_STATUS
     74 EFIAPI
     75 SerialSetControl (
     76   IN EFI_SERIAL_IO_PROTOCOL  *This,
     77   IN UINT32                  Control
     78   );
     79 
     80 /**
     81   Get ControlBits.
     82 
     83   @param[in]  This         Pointer to EFI_SERIAL_IO_PROTOCOL.
     84   @param[out] Control      Control signals of the serial device.
     85 
     86   @retval EFI_SUCCESS  Get Control signals successfully.
     87 
     88 **/
     89 EFI_STATUS
     90 EFIAPI
     91 SerialGetControl (
     92   IN EFI_SERIAL_IO_PROTOCOL  *This,
     93   OUT UINT32                 *Control
     94   );
     95 
     96 /**
     97   Write the specified number of bytes to serial device.
     98 
     99   @param[in]      This       Pointer to EFI_SERIAL_IO_PROTOCOL.
    100   @param[in, out] BufferSize On input the size of Buffer, on output the amount of
    101                              data actually written.
    102   @param[in]      Buffer     The buffer of data to write.
    103 
    104   @retval EFI_SUCCESS        The data were written successfully.
    105   @retval EFI_DEVICE_ERROR   The device reported an error.
    106   @retval EFI_TIMEOUT        The write operation was stopped due to timeout.
    107 
    108 **/
    109 EFI_STATUS
    110 EFIAPI
    111 SerialWrite (
    112   IN EFI_SERIAL_IO_PROTOCOL  *This,
    113   IN OUT UINTN               *BufferSize,
    114   IN VOID                    *Buffer
    115   );
    116 
    117 /**
    118   Read the specified number of bytes from serial device.
    119 
    120   @param[in] This            Pointer to EFI_SERIAL_IO_PROTOCOL.
    121   @param[in, out] BufferSize On input the size of Buffer, on output the amount of
    122                              data returned in buffer.
    123   @param[out] Buffer         The buffer to return the data into.
    124 
    125   @retval EFI_SUCCESS        The data were read successfully.
    126   @retval EFI_DEVICE_ERROR   The device reported an error.
    127   @retval EFI_TIMEOUT        The read operation was stopped due to timeout.
    128 
    129 **/
    130 EFI_STATUS
    131 EFIAPI
    132 SerialRead (
    133   IN EFI_SERIAL_IO_PROTOCOL  *This,
    134   IN OUT UINTN               *BufferSize,
    135   OUT VOID                   *Buffer
    136   );
    137 
    138 //
    139 // Serial Driver Defaults
    140 //
    141 #define SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH  1
    142 #define SERIAL_PORT_DEFAULT_TIMEOUT             1000000
    143 #define SERIAL_PORT_DEFAULT_CONTROL_MASK        0
    144 #define SERIAL_PORT_LOOPBACK_BUFFER_FULL        BIT8
    145 
    146 //
    147 // EFI_SERIAL_IO_MODE instance
    148 //
    149 EFI_SERIAL_IO_MODE  mSerialIoMode = {
    150   SERIAL_PORT_DEFAULT_CONTROL_MASK,
    151   SERIAL_PORT_DEFAULT_TIMEOUT,
    152   0,  // default BaudRate
    153   SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH,
    154   0,  // default DataBits
    155   0,  // default Parity
    156   0   // default StopBits
    157 };
    158 
    159 //
    160 // EFI_SERIAL_IO_PROTOCOL instance
    161 //
    162 EFI_SERIAL_IO_PROTOCOL mSerialIo = {
    163   SERIAL_IO_INTERFACE_REVISION,
    164   SerialReset,
    165   SerialSetAttributes,
    166   SerialSetControl,
    167   SerialGetControl,
    168   SerialWrite,
    169   SerialRead,
    170   &mSerialIoMode
    171 };
    172 
    173 //
    174 // Serial IO Device Path definition
    175 //
    176 typedef struct {
    177   VENDOR_DEVICE_PATH        VendorDevicePath;
    178   UART_DEVICE_PATH          UartDevicePath;
    179   EFI_DEVICE_PATH_PROTOCOL  EndDevicePath;
    180 } SERIAL_IO_DEVICE_PATH;
    181 
    182 //
    183 // Serial IO Device Patch instance
    184 //
    185 SERIAL_IO_DEVICE_PATH mSerialIoDevicePath = {
    186   {
    187     {
    188       HARDWARE_DEVICE_PATH,
    189       HW_VENDOR_DP,
    190       {
    191         (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
    192         (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
    193       }
    194     },
    195     EFI_DEBUG_AGENT_GUID,
    196   },
    197   {
    198     {
    199       MESSAGING_DEVICE_PATH,
    200       MSG_UART_DP,
    201       {
    202         (UINT8) (sizeof (UART_DEVICE_PATH)),
    203         (UINT8) ((sizeof (UART_DEVICE_PATH)) >> 8)
    204       }
    205     },
    206     0,
    207     0,  // default BaudRate
    208     0,  // default DataBits
    209     0,  // default Parity
    210     0,  // default StopBits
    211   },
    212   {
    213     END_DEVICE_PATH_TYPE,
    214     END_ENTIRE_DEVICE_PATH_SUBTYPE,
    215     {
    216       END_DEVICE_PATH_LENGTH,
    217       0
    218     }
    219   }
    220 };
    221 
    222 #define DEBGU_SERIAL_IO_FIFO_DEPTH      10
    223 //
    224 //  Data buffer for Terminal input character and Debug Symbols.
    225 //  The depth is DEBGU_SERIAL_IO_FIFO_DEPTH.
    226 //  Fields:
    227 //      First   UINT8: The index of the first data in array Data[].
    228 //      Last    UINT8: The index, which you can put a new data into array Data[].
    229 //      Surplus UINT8: Identify how many data you can put into array Data[].
    230 //      Data[]  UINT8: An array, which used to store data.
    231 //
    232 typedef struct {
    233   UINT8  First;
    234   UINT8  Last;
    235   UINT8  Surplus;
    236   UINT8  Data[DEBGU_SERIAL_IO_FIFO_DEPTH];
    237 } DEBUG_SERIAL_FIFO;
    238 
    239 //
    240 // Global Varibles
    241 //
    242 EFI_HANDLE                   mSerialIoHandle        = NULL;
    243 UINTN                        mLoopbackBuffer        = 0;
    244 DEBUG_SERIAL_FIFO            mSerialFifoForTerminal = {0, 0, DEBGU_SERIAL_IO_FIFO_DEPTH, { 0 }};
    245 DEBUG_SERIAL_FIFO            mSerialFifoForDebug    = {0, 0, DEBGU_SERIAL_IO_FIFO_DEPTH, { 0 }};
    246 
    247 /**
    248   Detect whether specific FIFO is empty or not.
    249 
    250   @param[in]  Fifo    A pointer to the Data Structure DEBUG_SERIAL_FIFO.
    251 
    252   @return whether specific FIFO is empty or not.
    253 
    254 **/
    255 BOOLEAN
    256 IsDebugTermianlFifoEmpty (
    257   IN DEBUG_SERIAL_FIFO    *Fifo
    258   )
    259 {
    260   if (Fifo->Surplus == DEBGU_SERIAL_IO_FIFO_DEPTH) {
    261     return TRUE;
    262   }
    263 
    264   return FALSE;
    265 }
    266 
    267 /**
    268   Detect whether specific FIFO is full or not.
    269 
    270   @param[in] Fifo    A pointer to the Data Structure DEBUG_SERIAL_FIFO.
    271 
    272   @return whether specific FIFO is full or not.
    273 
    274 **/
    275 BOOLEAN
    276 IsDebugTerminalFifoFull (
    277   IN DEBUG_SERIAL_FIFO    *Fifo
    278   )
    279 
    280 {
    281   if (Fifo->Surplus == 0) {
    282     return TRUE;
    283   }
    284 
    285   return FALSE;
    286 }
    287 
    288 /**
    289   Add data to specific FIFO.
    290 
    291   @param[in] Fifo               A pointer to the Data Structure DEBUG_SERIAL_FIFO.
    292   @param[in] Data               The data added to FIFO.
    293 
    294   @retval EFI_SUCCESS           Add data to specific FIFO successfully.
    295   @retval EFI_OUT_OF_RESOURCE   Failed to add data because FIFO is already full.
    296 
    297 **/
    298 EFI_STATUS
    299 DebugTerminalFifoAdd (
    300   IN DEBUG_SERIAL_FIFO   *Fifo,
    301   IN UINT8               Data
    302   )
    303 
    304 {
    305   //
    306   // if FIFO full can not add data
    307   //
    308   if (IsDebugTerminalFifoFull (Fifo)) {
    309     return EFI_OUT_OF_RESOURCES;
    310   }
    311   //
    312   // FIFO is not full can add data
    313   //
    314   Fifo->Data[Fifo->Last] = Data;
    315   Fifo->Surplus--;
    316   Fifo->Last++;
    317   if (Fifo->Last == DEBGU_SERIAL_IO_FIFO_DEPTH) {
    318     Fifo->Last = 0;
    319   }
    320 
    321   return EFI_SUCCESS;
    322 }
    323 
    324 /**
    325   Remove data from specific FIFO.
    326 
    327   @param[in]  Fifo              A pointer to the Data Structure DEBUG_SERIAL_FIFO.
    328   @param[out] Data              The data removed from FIFO.
    329 
    330   @retval EFI_SUCCESS           Remove data from specific FIFO successfully.
    331   @retval EFI_OUT_OF_RESOURCE   Failed to remove data because FIFO is empty.
    332 
    333 **/
    334 EFI_STATUS
    335 DebugTerminalFifoRemove (
    336   IN  DEBUG_SERIAL_FIFO   *Fifo,
    337   OUT UINT8               *Data
    338   )
    339 {
    340   //
    341   // if FIFO is empty, no data can remove
    342   //
    343   if (IsDebugTermianlFifoEmpty (Fifo)) {
    344     return EFI_OUT_OF_RESOURCES;
    345   }
    346   //
    347   // FIFO is not empty, can remove data
    348   //
    349   *Data = Fifo->Data[Fifo->First];
    350   Fifo->Surplus++;
    351   Fifo->First++;
    352   if (Fifo->First == DEBGU_SERIAL_IO_FIFO_DEPTH) {
    353     Fifo->First = 0;
    354   }
    355 
    356   return EFI_SUCCESS;
    357 }
    358 
    359 /**
    360   Install EFI Serial IO protocol based on Debug Communication Library.
    361 
    362 **/
    363 VOID
    364 InstallSerialIo (
    365   VOID
    366   )
    367 {
    368   EFI_STATUS       Status;
    369 
    370   Status = gBS->InstallMultipleProtocolInterfaces (
    371                   &mSerialIoHandle,
    372                   &gEfiDevicePathProtocolGuid, &mSerialIoDevicePath,
    373                   &gEfiSerialIoProtocolGuid,   &mSerialIo,
    374                   NULL
    375                   );
    376   if (EFI_ERROR (Status)) {
    377     DEBUG ((EFI_D_ERROR, "Debug Agent: Failed to install EFI Serial IO Protocol on Debug Port!\n"));
    378   }
    379 }
    380 
    381 /**
    382   Reset serial device.
    383 
    384   @param[in] This           Pointer to EFI_SERIAL_IO_PROTOCOL.
    385 
    386   @retval EFI_SUCCESS       Reset successfully.
    387 
    388 **/
    389 EFI_STATUS
    390 EFIAPI
    391 SerialReset (
    392   IN EFI_SERIAL_IO_PROTOCOL  *This
    393   )
    394 {
    395   mSerialIoMode.ControlMask = SERIAL_PORT_DEFAULT_CONTROL_MASK;
    396   mLoopbackBuffer = 0;
    397   //
    398   // Not reset serial devcie hardware indeed.
    399   //
    400   return EFI_SUCCESS;
    401 }
    402 
    403 /**
    404   Set new attributes to a serial device.
    405 
    406   @param[in]  This                Pointer to EFI_SERIAL_IO_PROTOCOL.
    407   @param[in]  BaudRate            The baudrate of the serial device.
    408   @param[in]  ReceiveFifoDepth    The depth of receive FIFO buffer.
    409   @param[in]  Timeout             The request timeout for a single char.
    410   @param[in]  Parity              The type of parity used in serial device.
    411   @param[in]  DataBits            Number of databits used in serial device.
    412   @param[in]  StopBits            Number of stopbits used in serial device.
    413 
    414   @retval EFI_SUCCESS             The new attributes were set.
    415   @retval EFI_INVALID_PARAMETER   One or more attributes have an unsupported value.
    416   @retval EFI_DEVICE_ERROR        The serial device is not functioning correctly (no return).
    417 
    418 **/
    419 EFI_STATUS
    420 EFIAPI
    421 SerialSetAttributes (
    422   IN EFI_SERIAL_IO_PROTOCOL  *This,
    423   IN UINT64                  BaudRate,
    424   IN UINT32                  ReceiveFifoDepth,
    425   IN UINT32                  Timeout,
    426   IN EFI_PARITY_TYPE         Parity,
    427   IN UINT8                   DataBits,
    428   IN EFI_STOP_BITS_TYPE      StopBits
    429   )
    430 {
    431   //
    432   // The Debug Communication Library CAN NOT change communications parameters (if it has)
    433   // actually. Because it also has no any idea on what parameters are based on, we cannot
    434   // check the input parameters (like BaudRate, Parity, DataBits and StopBits).
    435   //
    436 
    437   //
    438   // Update the Timeout value in the mode structure based on the request.
    439   // The Debug Communication Library can not support a timeout on writes, but the timeout on
    440   // reads can be provided by this module.
    441   //
    442   if (Timeout == 0) {
    443     mSerialIoMode.Timeout = SERIAL_PORT_DEFAULT_TIMEOUT;
    444   } else {
    445     mSerialIoMode.Timeout = Timeout;
    446   }
    447 
    448   //
    449   // Update the ReceiveFifoDepth value in the mode structure based on the request.
    450   // This module assumes that the Debug Communication Library uses a FIFO depth of
    451   // SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH.  The Debug Communication Library may actually be
    452   // using a larger FIFO, but there is no way to tell.
    453   //
    454   if (ReceiveFifoDepth == 0 || ReceiveFifoDepth >= SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH) {
    455     mSerialIoMode.ReceiveFifoDepth = SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH;
    456   } else {
    457     return EFI_INVALID_PARAMETER;
    458   }
    459 
    460   return EFI_SUCCESS;
    461 }
    462 
    463 /**
    464   Set Control Bits.
    465 
    466   @param[in] This            Pointer to EFI_SERIAL_IO_PROTOCOL.
    467   @param[in] Control         Control bits that can be settable.
    468 
    469   @retval EFI_SUCCESS        New Control bits were set successfully.
    470   @retval EFI_UNSUPPORTED    The Control bits wanted to set are not supported.
    471 
    472 **/
    473 EFI_STATUS
    474 EFIAPI
    475 SerialSetControl (
    476   IN EFI_SERIAL_IO_PROTOCOL  *This,
    477   IN UINT32                  Control
    478   )
    479 {
    480   //
    481   // The only control bit supported by this module is software loopback.
    482   // If any other bit is set, then return an error
    483   //
    484   if ((Control & (~EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE)) != 0) {
    485     return EFI_UNSUPPORTED;
    486   }
    487   mSerialIoMode.ControlMask = Control;
    488   return EFI_SUCCESS;
    489 }
    490 
    491 /**
    492   Get ControlBits.
    493 
    494   @param[in]  This         Pointer to EFI_SERIAL_IO_PROTOCOL.
    495   @param[out] Control      Control signals of the serial device.
    496 
    497   @retval EFI_SUCCESS  Get Control signals successfully.
    498 
    499 **/
    500 EFI_STATUS
    501 EFIAPI
    502 SerialGetControl (
    503   IN EFI_SERIAL_IO_PROTOCOL  *This,
    504   OUT UINT32                 *Control
    505   )
    506 {
    507   DEBUG_PORT_HANDLE                Handle;
    508   BOOLEAN                          DebugTimerInterruptState;
    509   EFI_TPL                          Tpl;
    510 
    511   //
    512   // Raise TPL to prevent recursion from EFI timer interrupts
    513   //
    514   Tpl = gBS->RaiseTPL (TPL_NOTIFY);
    515 
    516   //
    517   // Save and disable Debug Timer interrupt to avoid it to access Debug Port
    518   //
    519   DebugTimerInterruptState = SaveAndSetDebugTimerInterrupt (FALSE);
    520   Handle = GetDebugPortHandle ();
    521 
    522   //
    523   // Always assume the output buffer is empty and the Debug Communication Library can process
    524   // more write requests.
    525   //
    526   *Control = mSerialIoMode.ControlMask | EFI_SERIAL_OUTPUT_BUFFER_EMPTY;
    527 
    528   //
    529   // Check to see if the Terminal FIFO is empty and
    530   // check to see if the input buffer in the Debug Communication Library is empty
    531   //
    532   if (!IsDebugTermianlFifoEmpty (&mSerialFifoForTerminal) || DebugPortPollBuffer (Handle)) {
    533     *Control &= ~EFI_SERIAL_INPUT_BUFFER_EMPTY;
    534   }
    535 
    536   //
    537   // Restore Debug Timer interrupt
    538   //
    539   SaveAndSetDebugTimerInterrupt (DebugTimerInterruptState);
    540 
    541   //
    542   // Restore to original TPL
    543   //
    544   gBS->RestoreTPL (Tpl);
    545 
    546   return EFI_SUCCESS;
    547 }
    548 
    549 /**
    550   Write the specified number of bytes to serial device.
    551 
    552   @param[in]      This       Pointer to EFI_SERIAL_IO_PROTOCOL.
    553   @param[in, out] BufferSize On input the size of Buffer, on output the amount of
    554                              data actually written.
    555   @param[in]      Buffer     The buffer of data to write.
    556 
    557   @retval EFI_SUCCESS        The data were written successfully.
    558   @retval EFI_DEVICE_ERROR   The device reported an error.
    559   @retval EFI_TIMEOUT        The write operation was stopped due to timeout.
    560 
    561 **/
    562 EFI_STATUS
    563 EFIAPI
    564 SerialWrite (
    565   IN EFI_SERIAL_IO_PROTOCOL  *This,
    566   IN OUT UINTN               *BufferSize,
    567   IN VOID                    *Buffer
    568   )
    569 {
    570   DEBUG_PORT_HANDLE                Handle;
    571   BOOLEAN                          DebugTimerInterruptState;
    572   EFI_TPL                          Tpl;
    573 
    574   //
    575   // Raise TPL to prevent recursion from EFI timer interrupts
    576   //
    577   Tpl = gBS->RaiseTPL (TPL_NOTIFY);
    578 
    579   //
    580   // Save and disable Debug Timer interrupt to avoid it to access Debug Port
    581   //
    582   DebugTimerInterruptState = SaveAndSetDebugTimerInterrupt (FALSE);
    583   Handle = GetDebugPortHandle ();
    584 
    585   if ((mSerialIoMode.ControlMask & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) != 0)  {
    586     if (*BufferSize == 0) {
    587       return EFI_SUCCESS;
    588     }
    589     if ((mLoopbackBuffer & SERIAL_PORT_LOOPBACK_BUFFER_FULL) != 0) {
    590       *BufferSize = 0;
    591       return EFI_TIMEOUT;
    592     }
    593     mLoopbackBuffer = SERIAL_PORT_LOOPBACK_BUFFER_FULL | *(UINT8 *)Buffer;
    594     *BufferSize = 1;
    595   } else {
    596     *BufferSize = DebugPortWriteBuffer (Handle, Buffer, *BufferSize);
    597   }
    598 
    599   //
    600   // Restore Debug Timer interrupt
    601   //
    602   SaveAndSetDebugTimerInterrupt (DebugTimerInterruptState);
    603 
    604   //
    605   // Restore to original TPL
    606   //
    607   gBS->RestoreTPL (Tpl);
    608 
    609   return EFI_SUCCESS;
    610 }
    611 
    612 /**
    613   Read the specified number of bytes from serial device.
    614 
    615   @param[in] This            Pointer to EFI_SERIAL_IO_PROTOCOL.
    616   @param[in, out] BufferSize On input the size of Buffer, on output the amount of
    617                              data returned in buffer.
    618   @param[out] Buffer         The buffer to return the data into.
    619 
    620   @retval EFI_SUCCESS        The data were read successfully.
    621   @retval EFI_DEVICE_ERROR   The device reported an error.
    622   @retval EFI_TIMEOUT        The read operation was stopped due to timeout.
    623 
    624 **/
    625 EFI_STATUS
    626 EFIAPI
    627 SerialRead (
    628   IN EFI_SERIAL_IO_PROTOCOL  *This,
    629   IN OUT UINTN               *BufferSize,
    630   OUT VOID                   *Buffer
    631   )
    632 {
    633   EFI_STATUS                  Status;
    634   UINTN                       Index;
    635   UINT8                       *Uint8Buffer;
    636   BOOLEAN                     DebugTimerInterruptState;
    637   EFI_TPL                     Tpl;
    638   DEBUG_PORT_HANDLE           Handle;
    639   DEBUG_PACKET_HEADER         DebugHeader;
    640   UINT8                       *Data8;
    641 
    642   //
    643   // Raise TPL to prevent recursion from EFI timer interrupts
    644   //
    645   Tpl = gBS->RaiseTPL (TPL_NOTIFY);
    646 
    647   //
    648   // Save and disable Debug Timer interrupt to avoid it to access Debug Port
    649   //
    650   DebugTimerInterruptState = SaveAndSetDebugTimerInterrupt (FALSE);
    651   Handle = GetDebugPortHandle ();
    652 
    653   Data8 = (UINT8 *) &DebugHeader;
    654   Uint8Buffer = (UINT8 *)Buffer;
    655   if ((mSerialIoMode.ControlMask & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) != 0)  {
    656     if ((mLoopbackBuffer & SERIAL_PORT_LOOPBACK_BUFFER_FULL) == 0) {
    657       return EFI_TIMEOUT;
    658     }
    659     *Uint8Buffer = (UINT8)(mLoopbackBuffer & 0xff);
    660     mLoopbackBuffer = 0;
    661     *BufferSize = 1;
    662   } else {
    663     for (Index = 0; Index < *BufferSize; Index++) {
    664       //
    665       // Read input character from terminal FIFO firstly
    666       //
    667       Status = DebugTerminalFifoRemove (&mSerialFifoForTerminal, Data8);
    668       if (Status == EFI_SUCCESS) {
    669         *Uint8Buffer = *Data8;
    670         Uint8Buffer ++;
    671         continue;
    672       }
    673       //
    674       // Read the input character from Debug Port
    675       //
    676       if (!DebugPortPollBuffer (Handle)) {
    677         break;
    678       }
    679       DebugAgentReadBuffer (Handle, Data8, 1, 0);
    680 
    681       if (*Data8 == DEBUG_STARTING_SYMBOL_ATTACH) {
    682         //
    683         // Add the debug symbol into Debug FIFO
    684         //
    685         DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Terminal Timer attach symbol received %x", *Data8);
    686         DebugTerminalFifoAdd (&mSerialFifoForDebug, *Data8);
    687       } else if (*Data8 == DEBUG_STARTING_SYMBOL_NORMAL) {
    688         Status = ReadRemainingBreakPacket (Handle, &DebugHeader);
    689         if (Status == EFI_SUCCESS) {
    690           DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Terminal Timer break symbol received %x", DebugHeader.Command);
    691           DebugTerminalFifoAdd (&mSerialFifoForDebug, DebugHeader.Command);
    692         }
    693         if (Status == EFI_TIMEOUT) {
    694           continue;
    695         }
    696       } else {
    697         *Uint8Buffer = *Data8;
    698         Uint8Buffer ++;
    699       }
    700     }
    701     *BufferSize = (UINTN)Uint8Buffer - (UINTN)Buffer;
    702   }
    703 
    704   //
    705   // Restore Debug Timer interrupt
    706   //
    707   SaveAndSetDebugTimerInterrupt (DebugTimerInterruptState);
    708 
    709   //
    710   // Restore to original TPL
    711   //
    712   gBS->RestoreTPL (Tpl);
    713 
    714   return EFI_SUCCESS;
    715 }
    716 
    717 /**
    718   Read the Attach/Break-in symbols from the debug port.
    719 
    720   @param[in]  Handle         Pointer to Debug Port handle.
    721   @param[out] BreakSymbol    Returned break symbol.
    722 
    723   @retval EFI_SUCCESS        Read the symbol in BreakSymbol.
    724   @retval EFI_NOT_FOUND      No read the break symbol.
    725 
    726 **/
    727 EFI_STATUS
    728 DebugReadBreakFromDebugPort (
    729   IN  DEBUG_PORT_HANDLE      Handle,
    730   OUT UINT8                  *BreakSymbol
    731   )
    732 {
    733   EFI_STATUS                 Status;
    734   DEBUG_PACKET_HEADER        DebugHeader;
    735   UINT8                      *Data8;
    736 
    737   *BreakSymbol = 0;
    738   //
    739   // If Debug Port buffer has data, read it till it was break symbol or Debug Port buffer empty.
    740   //
    741   Data8 = (UINT8 *) &DebugHeader;
    742   while (TRUE) {
    743     //
    744     // If start symbol is not received
    745     //
    746     if (!DebugPortPollBuffer (Handle)) {
    747       //
    748       // If no data in Debug Port, exit
    749       //
    750       break;
    751     }
    752     //
    753     // Try to read the start symbol
    754     //
    755     DebugAgentReadBuffer (Handle, Data8, 1, 0);
    756     if (*Data8 == DEBUG_STARTING_SYMBOL_ATTACH) {
    757       DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Debug Timer attach symbol received %x", *Data8);
    758       *BreakSymbol = *Data8;
    759       return EFI_SUCCESS;
    760     }
    761     if (*Data8 == DEBUG_STARTING_SYMBOL_NORMAL) {
    762       Status = ReadRemainingBreakPacket (Handle, &DebugHeader);
    763       if (Status == EFI_SUCCESS) {
    764         DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Debug Timer break symbol received %x", DebugHeader.Command);
    765         *BreakSymbol = DebugHeader.Command;
    766         return EFI_SUCCESS;
    767       }
    768       if (Status == EFI_TIMEOUT) {
    769         break;
    770       }
    771     } else {
    772       //
    773       // Add to Terminal FIFO
    774       //
    775       DebugTerminalFifoAdd (&mSerialFifoForTerminal, *Data8);
    776     }
    777   }
    778 
    779   return EFI_NOT_FOUND;
    780 }
    781 
    782 /**
    783   Read the Attach/Break-in symbols.
    784 
    785   @param[in]  Handle         Pointer to Debug Port handle.
    786   @param[out] BreakSymbol    Returned break symbol.
    787 
    788   @retval EFI_SUCCESS        Read the symbol in BreakSymbol.
    789   @retval EFI_NOT_FOUND      No read the break symbol.
    790 
    791 **/
    792 EFI_STATUS
    793 DebugReadBreakSymbol (
    794   IN  DEBUG_PORT_HANDLE      Handle,
    795   OUT UINT8                  *BreakSymbol
    796   )
    797 {
    798   EFI_STATUS               Status;
    799   UINT8                    Data8;
    800 
    801   //
    802   // Read break symbol from debug FIFO firstly
    803   //
    804   Status = DebugTerminalFifoRemove (&mSerialFifoForDebug, &Data8);
    805   if (Status == EFI_SUCCESS) {
    806     *BreakSymbol = Data8;
    807     return EFI_SUCCESS;
    808   } else {
    809     //
    810     // Read Break symbol from debug port
    811     //
    812     return DebugReadBreakFromDebugPort (Handle, BreakSymbol);
    813   }
    814 }
    815