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
IsDebugTermianlFifoEmpty(IN DEBUG_SERIAL_FIFO * Fifo)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
IsDebugTerminalFifoFull(IN DEBUG_SERIAL_FIFO * Fifo)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
DebugTerminalFifoAdd(IN DEBUG_SERIAL_FIFO * Fifo,IN UINT8 Data)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
DebugTerminalFifoRemove(IN DEBUG_SERIAL_FIFO * Fifo,OUT UINT8 * Data)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
InstallSerialIo(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
SerialReset(IN EFI_SERIAL_IO_PROTOCOL * This)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
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)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
SerialSetControl(IN EFI_SERIAL_IO_PROTOCOL * This,IN UINT32 Control)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
SerialGetControl(IN EFI_SERIAL_IO_PROTOCOL * This,OUT UINT32 * Control)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
SerialWrite(IN EFI_SERIAL_IO_PROTOCOL * This,IN OUT UINTN * BufferSize,IN VOID * Buffer)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
SerialRead(IN EFI_SERIAL_IO_PROTOCOL * This,IN OUT UINTN * BufferSize,OUT VOID * Buffer)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
DebugReadBreakFromDebugPort(IN DEBUG_PORT_HANDLE Handle,OUT UINT8 * BreakSymbol)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
DebugReadBreakSymbol(IN DEBUG_PORT_HANDLE Handle,OUT UINT8 * BreakSymbol)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