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