2 Install Serial IO Protocol that layers on top of a Debug Communication Library instance.
4 Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include "DxeDebugAgentLib.h"
12 // Serial I/O Protocol Interface definitions.
18 @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
20 @retval EFI_SUCCESS Reset successfully.
26 IN EFI_SERIAL_IO_PROTOCOL
*This
30 Set new attributes to a serial device.
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.
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).
48 IN EFI_SERIAL_IO_PROTOCOL
*This
,
50 IN UINT32 ReceiveFifoDepth
,
52 IN EFI_PARITY_TYPE Parity
,
54 IN EFI_STOP_BITS_TYPE StopBits
60 @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
61 @param[in] Control Control bits that can be settable.
63 @retval EFI_SUCCESS New Control bits were set successfully.
64 @retval EFI_UNSUPPORTED The Control bits wanted to set are not supported.
70 IN EFI_SERIAL_IO_PROTOCOL
*This
,
77 @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
78 @param[out] Control Control signals of the serial device.
80 @retval EFI_SUCCESS Get Control signals successfully.
86 IN EFI_SERIAL_IO_PROTOCOL
*This
,
91 Write the specified number of bytes to serial device.
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.
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.
106 IN EFI_SERIAL_IO_PROTOCOL
*This
,
107 IN OUT UINTN
*BufferSize
,
112 Read the specified number of bytes from serial device.
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.
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.
127 IN EFI_SERIAL_IO_PROTOCOL
*This
,
128 IN OUT UINTN
*BufferSize
,
133 // Serial Driver Defaults
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
141 // EFI_SERIAL_IO_MODE instance
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
150 0 // default StopBits
154 // EFI_SERIAL_IO_PROTOCOL instance
156 EFI_SERIAL_IO_PROTOCOL mSerialIo
= {
157 SERIAL_IO_INTERFACE_REVISION
,
168 // Serial IO Device Path definition
171 VENDOR_DEVICE_PATH VendorDevicePath
;
172 UART_DEVICE_PATH UartDevicePath
;
173 EFI_DEVICE_PATH_PROTOCOL EndDevicePath
;
174 } SERIAL_IO_DEVICE_PATH
;
177 // Serial IO Device Patch instance
179 SERIAL_IO_DEVICE_PATH mSerialIoDevicePath
= {
182 HARDWARE_DEVICE_PATH
,
185 (UINT8
)(sizeof (VENDOR_DEVICE_PATH
)),
186 (UINT8
)((sizeof (VENDOR_DEVICE_PATH
)) >> 8)
189 EFI_DEBUG_AGENT_GUID
,
193 MESSAGING_DEVICE_PATH
,
196 (UINT8
)(sizeof (UART_DEVICE_PATH
)),
197 (UINT8
)((sizeof (UART_DEVICE_PATH
)) >> 8)
201 0, // default BaudRate
202 0, // default DataBits
204 0, // default StopBits
207 END_DEVICE_PATH_TYPE
,
208 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
210 END_DEVICE_PATH_LENGTH
,
216 #define DEBGU_SERIAL_IO_FIFO_DEPTH 10
218 // Data buffer for Terminal input character and Debug Symbols.
219 // The depth is DEBGU_SERIAL_IO_FIFO_DEPTH.
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.
230 UINT8 Data
[DEBGU_SERIAL_IO_FIFO_DEPTH
];
236 EFI_HANDLE mSerialIoHandle
= NULL
;
237 UINTN mLoopbackBuffer
= 0;
238 DEBUG_SERIAL_FIFO mSerialFifoForTerminal
= {
239 0, 0, DEBGU_SERIAL_IO_FIFO_DEPTH
, { 0 }
241 DEBUG_SERIAL_FIFO mSerialFifoForDebug
= {
242 0, 0, DEBGU_SERIAL_IO_FIFO_DEPTH
, { 0 }
246 Detect whether specific FIFO is empty or not.
248 @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO.
250 @return whether specific FIFO is empty or not.
254 IsDebugTermianlFifoEmpty (
255 IN DEBUG_SERIAL_FIFO
*Fifo
258 if (Fifo
->Surplus
== DEBGU_SERIAL_IO_FIFO_DEPTH
) {
266 Detect whether specific FIFO is full or not.
268 @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO.
270 @return whether specific FIFO is full or not.
274 IsDebugTerminalFifoFull (
275 IN DEBUG_SERIAL_FIFO
*Fifo
279 if (Fifo
->Surplus
== 0) {
287 Add data to specific FIFO.
289 @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO.
290 @param[in] Data The data added to FIFO.
292 @retval EFI_SUCCESS Add data to specific FIFO successfully.
293 @retval EFI_OUT_OF_RESOURCE Failed to add data because FIFO is already full.
297 DebugTerminalFifoAdd (
298 IN DEBUG_SERIAL_FIFO
*Fifo
,
304 // if FIFO full can not add data
306 if (IsDebugTerminalFifoFull (Fifo
)) {
307 return EFI_OUT_OF_RESOURCES
;
311 // FIFO is not full can add data
313 Fifo
->Data
[Fifo
->Last
] = Data
;
316 if (Fifo
->Last
== DEBGU_SERIAL_IO_FIFO_DEPTH
) {
324 Remove data from specific FIFO.
326 @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO.
327 @param[out] Data The data removed from FIFO.
329 @retval EFI_SUCCESS Remove data from specific FIFO successfully.
330 @retval EFI_OUT_OF_RESOURCE Failed to remove data because FIFO is empty.
334 DebugTerminalFifoRemove (
335 IN DEBUG_SERIAL_FIFO
*Fifo
,
340 // if FIFO is empty, no data can remove
342 if (IsDebugTermianlFifoEmpty (Fifo
)) {
343 return EFI_OUT_OF_RESOURCES
;
347 // FIFO is not empty, can remove data
349 *Data
= Fifo
->Data
[Fifo
->First
];
352 if (Fifo
->First
== DEBGU_SERIAL_IO_FIFO_DEPTH
) {
360 Install EFI Serial IO protocol based on Debug Communication Library.
370 Status
= gBS
->InstallMultipleProtocolInterfaces (
372 &gEfiDevicePathProtocolGuid
,
373 &mSerialIoDevicePath
,
374 &gEfiSerialIoProtocolGuid
,
378 if (EFI_ERROR (Status
)) {
379 DEBUG ((DEBUG_ERROR
, "Debug Agent: Failed to install EFI Serial IO Protocol on Debug Port!\n"));
386 @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
388 @retval EFI_SUCCESS Reset successfully.
394 IN EFI_SERIAL_IO_PROTOCOL
*This
397 mSerialIoMode
.ControlMask
= SERIAL_PORT_DEFAULT_CONTROL_MASK
;
400 // Not reset serial device hardware indeed.
406 Set new attributes to a serial device.
408 @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
409 @param[in] BaudRate The baudrate of the serial device.
410 @param[in] ReceiveFifoDepth The depth of receive FIFO buffer.
411 @param[in] Timeout The request timeout for a single char.
412 @param[in] Parity The type of parity used in serial device.
413 @param[in] DataBits Number of databits used in serial device.
414 @param[in] StopBits Number of stopbits used in serial device.
416 @retval EFI_SUCCESS The new attributes were set.
417 @retval EFI_INVALID_PARAMETER One or more attributes have an unsupported value.
418 @retval EFI_DEVICE_ERROR The serial device is not functioning correctly (no return).
423 SerialSetAttributes (
424 IN EFI_SERIAL_IO_PROTOCOL
*This
,
426 IN UINT32 ReceiveFifoDepth
,
428 IN EFI_PARITY_TYPE Parity
,
430 IN EFI_STOP_BITS_TYPE StopBits
434 // The Debug Communication Library CAN NOT change communications parameters (if it has)
435 // actually. Because it also has no any idea on what parameters are based on, we cannot
436 // check the input parameters (like BaudRate, Parity, DataBits and StopBits).
440 // Update the Timeout value in the mode structure based on the request.
441 // The Debug Communication Library can not support a timeout on writes, but the timeout on
442 // reads can be provided by this module.
445 mSerialIoMode
.Timeout
= SERIAL_PORT_DEFAULT_TIMEOUT
;
447 mSerialIoMode
.Timeout
= Timeout
;
451 // Update the ReceiveFifoDepth value in the mode structure based on the request.
452 // This module assumes that the Debug Communication Library uses a FIFO depth of
453 // SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH. The Debug Communication Library may actually be
454 // using a larger FIFO, but there is no way to tell.
456 if ((ReceiveFifoDepth
== 0) || (ReceiveFifoDepth
>= SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH
)) {
457 mSerialIoMode
.ReceiveFifoDepth
= SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH
;
459 return EFI_INVALID_PARAMETER
;
468 @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
469 @param[in] Control Control bits that can be settable.
471 @retval EFI_SUCCESS New Control bits were set successfully.
472 @retval EFI_UNSUPPORTED The Control bits wanted to set are not supported.
478 IN EFI_SERIAL_IO_PROTOCOL
*This
,
483 // The only control bit supported by this module is software loopback.
484 // If any other bit is set, then return an error
486 if ((Control
& (~EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE
)) != 0) {
487 return EFI_UNSUPPORTED
;
490 mSerialIoMode
.ControlMask
= Control
;
497 @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
498 @param[out] Control Control signals of the serial device.
500 @retval EFI_SUCCESS Get Control signals successfully.
506 IN EFI_SERIAL_IO_PROTOCOL
*This
,
510 DEBUG_PORT_HANDLE Handle
;
511 BOOLEAN DebugTimerInterruptState
;
515 // Raise TPL to prevent recursion from EFI timer interrupts
517 Tpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
520 // Save and disable Debug Timer interrupt to avoid it to access Debug Port
522 DebugTimerInterruptState
= SaveAndSetDebugTimerInterrupt (FALSE
);
523 Handle
= GetDebugPortHandle ();
526 // Always assume the output buffer is empty and the Debug Communication Library can process
527 // more write requests.
529 *Control
= mSerialIoMode
.ControlMask
| EFI_SERIAL_OUTPUT_BUFFER_EMPTY
;
532 // Check to see if the Terminal FIFO is empty and
533 // check to see if the input buffer in the Debug Communication Library is empty
535 if (!IsDebugTermianlFifoEmpty (&mSerialFifoForTerminal
) || DebugPortPollBuffer (Handle
)) {
536 *Control
&= ~EFI_SERIAL_INPUT_BUFFER_EMPTY
;
540 // Restore Debug Timer interrupt
542 SaveAndSetDebugTimerInterrupt (DebugTimerInterruptState
);
545 // Restore to original TPL
547 gBS
->RestoreTPL (Tpl
);
553 Write the specified number of bytes to serial device.
555 @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
556 @param[in, out] BufferSize On input the size of Buffer, on output the amount of
557 data actually written.
558 @param[in] Buffer The buffer of data to write.
560 @retval EFI_SUCCESS The data were written successfully.
561 @retval EFI_DEVICE_ERROR The device reported an error.
562 @retval EFI_TIMEOUT The write operation was stopped due to timeout.
568 IN EFI_SERIAL_IO_PROTOCOL
*This
,
569 IN OUT UINTN
*BufferSize
,
573 DEBUG_PORT_HANDLE Handle
;
574 BOOLEAN DebugTimerInterruptState
;
578 // Raise TPL to prevent recursion from EFI timer interrupts
580 Tpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
583 // Save and disable Debug Timer interrupt to avoid it to access Debug Port
585 DebugTimerInterruptState
= SaveAndSetDebugTimerInterrupt (FALSE
);
586 Handle
= GetDebugPortHandle ();
588 if ((mSerialIoMode
.ControlMask
& EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE
) != 0) {
589 if (*BufferSize
== 0) {
593 if ((mLoopbackBuffer
& SERIAL_PORT_LOOPBACK_BUFFER_FULL
) != 0) {
598 mLoopbackBuffer
= SERIAL_PORT_LOOPBACK_BUFFER_FULL
| *(UINT8
*)Buffer
;
601 *BufferSize
= DebugPortWriteBuffer (Handle
, Buffer
, *BufferSize
);
605 // Restore Debug Timer interrupt
607 SaveAndSetDebugTimerInterrupt (DebugTimerInterruptState
);
610 // Restore to original TPL
612 gBS
->RestoreTPL (Tpl
);
618 Read the specified number of bytes from serial device.
620 @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
621 @param[in, out] BufferSize On input the size of Buffer, on output the amount of
622 data returned in buffer.
623 @param[out] Buffer The buffer to return the data into.
625 @retval EFI_SUCCESS The data were read successfully.
626 @retval EFI_DEVICE_ERROR The device reported an error.
627 @retval EFI_TIMEOUT The read operation was stopped due to timeout.
633 IN EFI_SERIAL_IO_PROTOCOL
*This
,
634 IN OUT UINTN
*BufferSize
,
641 BOOLEAN DebugTimerInterruptState
;
643 DEBUG_PORT_HANDLE Handle
;
644 DEBUG_PACKET_HEADER DebugHeader
;
648 // Raise TPL to prevent recursion from EFI timer interrupts
650 Tpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
653 // Save and disable Debug Timer interrupt to avoid it to access Debug Port
655 DebugTimerInterruptState
= SaveAndSetDebugTimerInterrupt (FALSE
);
656 Handle
= GetDebugPortHandle ();
658 Data8
= (UINT8
*)&DebugHeader
;
659 Uint8Buffer
= (UINT8
*)Buffer
;
660 if ((mSerialIoMode
.ControlMask
& EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE
) != 0) {
661 if ((mLoopbackBuffer
& SERIAL_PORT_LOOPBACK_BUFFER_FULL
) == 0) {
665 *Uint8Buffer
= (UINT8
)(mLoopbackBuffer
& 0xff);
669 for (Index
= 0; Index
< *BufferSize
; Index
++) {
671 // Read input character from terminal FIFO firstly
673 Status
= DebugTerminalFifoRemove (&mSerialFifoForTerminal
, Data8
);
674 if (Status
== EFI_SUCCESS
) {
675 *Uint8Buffer
= *Data8
;
681 // Read the input character from Debug Port
683 if (!DebugPortPollBuffer (Handle
)) {
687 DebugAgentReadBuffer (Handle
, Data8
, 1, 0);
689 if (*Data8
== DEBUG_STARTING_SYMBOL_ATTACH
) {
691 // Add the debug symbol into Debug FIFO
693 DebugAgentMsgPrint (DEBUG_AGENT_INFO
, "Terminal Timer attach symbol received %x", *Data8
);
694 DebugTerminalFifoAdd (&mSerialFifoForDebug
, *Data8
);
695 } else if (*Data8
== DEBUG_STARTING_SYMBOL_NORMAL
) {
696 Status
= ReadRemainingBreakPacket (Handle
, &DebugHeader
);
697 if (Status
== EFI_SUCCESS
) {
698 DebugAgentMsgPrint (DEBUG_AGENT_INFO
, "Terminal Timer break symbol received %x", DebugHeader
.Command
);
699 DebugTerminalFifoAdd (&mSerialFifoForDebug
, DebugHeader
.Command
);
702 if (Status
== EFI_TIMEOUT
) {
706 *Uint8Buffer
= *Data8
;
711 *BufferSize
= (UINTN
)Uint8Buffer
- (UINTN
)Buffer
;
715 // Restore Debug Timer interrupt
717 SaveAndSetDebugTimerInterrupt (DebugTimerInterruptState
);
720 // Restore to original TPL
722 gBS
->RestoreTPL (Tpl
);
728 Read the Attach/Break-in symbols from the debug port.
730 @param[in] Handle Pointer to Debug Port handle.
731 @param[out] BreakSymbol Returned break symbol.
733 @retval EFI_SUCCESS Read the symbol in BreakSymbol.
734 @retval EFI_NOT_FOUND No read the break symbol.
738 DebugReadBreakFromDebugPort (
739 IN DEBUG_PORT_HANDLE Handle
,
740 OUT UINT8
*BreakSymbol
744 DEBUG_PACKET_HEADER DebugHeader
;
749 // If Debug Port buffer has data, read it till it was break symbol or Debug Port buffer empty.
751 Data8
= (UINT8
*)&DebugHeader
;
754 // If start symbol is not received
756 if (!DebugPortPollBuffer (Handle
)) {
758 // If no data in Debug Port, exit
764 // Try to read the start symbol
766 DebugAgentReadBuffer (Handle
, Data8
, 1, 0);
767 if (*Data8
== DEBUG_STARTING_SYMBOL_ATTACH
) {
768 DebugAgentMsgPrint (DEBUG_AGENT_INFO
, "Debug Timer attach symbol received %x", *Data8
);
769 *BreakSymbol
= *Data8
;
773 if (*Data8
== DEBUG_STARTING_SYMBOL_NORMAL
) {
774 Status
= ReadRemainingBreakPacket (Handle
, &DebugHeader
);
775 if (Status
== EFI_SUCCESS
) {
776 DebugAgentMsgPrint (DEBUG_AGENT_INFO
, "Debug Timer break symbol received %x", DebugHeader
.Command
);
777 *BreakSymbol
= DebugHeader
.Command
;
781 if (Status
== EFI_TIMEOUT
) {
786 // Add to Terminal FIFO
788 DebugTerminalFifoAdd (&mSerialFifoForTerminal
, *Data8
);
792 return EFI_NOT_FOUND
;
796 Read the Attach/Break-in symbols.
798 @param[in] Handle Pointer to Debug Port handle.
799 @param[out] BreakSymbol Returned break symbol.
801 @retval EFI_SUCCESS Read the symbol in BreakSymbol.
802 @retval EFI_NOT_FOUND No read the break symbol.
806 DebugReadBreakSymbol (
807 IN DEBUG_PORT_HANDLE Handle
,
808 OUT UINT8
*BreakSymbol
815 // Read break symbol from debug FIFO firstly
817 Status
= DebugTerminalFifoRemove (&mSerialFifoForDebug
, &Data8
);
818 if (Status
== EFI_SUCCESS
) {
819 *BreakSymbol
= Data8
;
823 // Read Break symbol from debug port
825 return DebugReadBreakFromDebugPort (Handle
, BreakSymbol
);