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 defintions.
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
= {0, 0, DEBGU_SERIAL_IO_FIFO_DEPTH
, { 0 }};
239 DEBUG_SERIAL_FIFO mSerialFifoForDebug
= {0, 0, DEBGU_SERIAL_IO_FIFO_DEPTH
, { 0 }};
242 Detect whether specific FIFO is empty or not.
244 @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO.
246 @return whether specific FIFO is empty or not.
250 IsDebugTermianlFifoEmpty (
251 IN DEBUG_SERIAL_FIFO
*Fifo
254 if (Fifo
->Surplus
== DEBGU_SERIAL_IO_FIFO_DEPTH
) {
262 Detect whether specific FIFO is full or not.
264 @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO.
266 @return whether specific FIFO is full or not.
270 IsDebugTerminalFifoFull (
271 IN DEBUG_SERIAL_FIFO
*Fifo
275 if (Fifo
->Surplus
== 0) {
283 Add data to specific FIFO.
285 @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO.
286 @param[in] Data The data added to FIFO.
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.
293 DebugTerminalFifoAdd (
294 IN DEBUG_SERIAL_FIFO
*Fifo
,
300 // if FIFO full can not add data
302 if (IsDebugTerminalFifoFull (Fifo
)) {
303 return EFI_OUT_OF_RESOURCES
;
306 // FIFO is not full can add data
308 Fifo
->Data
[Fifo
->Last
] = Data
;
311 if (Fifo
->Last
== DEBGU_SERIAL_IO_FIFO_DEPTH
) {
319 Remove data from specific FIFO.
321 @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO.
322 @param[out] Data The data removed from FIFO.
324 @retval EFI_SUCCESS Remove data from specific FIFO successfully.
325 @retval EFI_OUT_OF_RESOURCE Failed to remove data because FIFO is empty.
329 DebugTerminalFifoRemove (
330 IN DEBUG_SERIAL_FIFO
*Fifo
,
335 // if FIFO is empty, no data can remove
337 if (IsDebugTermianlFifoEmpty (Fifo
)) {
338 return EFI_OUT_OF_RESOURCES
;
341 // FIFO is not empty, can remove data
343 *Data
= Fifo
->Data
[Fifo
->First
];
346 if (Fifo
->First
== DEBGU_SERIAL_IO_FIFO_DEPTH
) {
354 Install EFI Serial IO protocol based on Debug Communication Library.
364 Status
= gBS
->InstallMultipleProtocolInterfaces (
366 &gEfiDevicePathProtocolGuid
, &mSerialIoDevicePath
,
367 &gEfiSerialIoProtocolGuid
, &mSerialIo
,
370 if (EFI_ERROR (Status
)) {
371 DEBUG ((EFI_D_ERROR
, "Debug Agent: Failed to install EFI Serial IO Protocol on Debug Port!\n"));
378 @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
380 @retval EFI_SUCCESS Reset successfully.
386 IN EFI_SERIAL_IO_PROTOCOL
*This
389 mSerialIoMode
.ControlMask
= SERIAL_PORT_DEFAULT_CONTROL_MASK
;
392 // Not reset serial devcie hardware indeed.
398 Set new attributes to a serial device.
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.
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).
415 SerialSetAttributes (
416 IN EFI_SERIAL_IO_PROTOCOL
*This
,
418 IN UINT32 ReceiveFifoDepth
,
420 IN EFI_PARITY_TYPE Parity
,
422 IN EFI_STOP_BITS_TYPE StopBits
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).
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.
437 mSerialIoMode
.Timeout
= SERIAL_PORT_DEFAULT_TIMEOUT
;
439 mSerialIoMode
.Timeout
= Timeout
;
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.
448 if (ReceiveFifoDepth
== 0 || ReceiveFifoDepth
>= SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH
) {
449 mSerialIoMode
.ReceiveFifoDepth
= SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH
;
451 return EFI_INVALID_PARAMETER
;
460 @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
461 @param[in] Control Control bits that can be settable.
463 @retval EFI_SUCCESS New Control bits were set successfully.
464 @retval EFI_UNSUPPORTED The Control bits wanted to set are not supported.
470 IN EFI_SERIAL_IO_PROTOCOL
*This
,
475 // The only control bit supported by this module is software loopback.
476 // If any other bit is set, then return an error
478 if ((Control
& (~EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE
)) != 0) {
479 return EFI_UNSUPPORTED
;
481 mSerialIoMode
.ControlMask
= Control
;
488 @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
489 @param[out] Control Control signals of the serial device.
491 @retval EFI_SUCCESS Get Control signals successfully.
497 IN EFI_SERIAL_IO_PROTOCOL
*This
,
501 DEBUG_PORT_HANDLE Handle
;
502 BOOLEAN DebugTimerInterruptState
;
506 // Raise TPL to prevent recursion from EFI timer interrupts
508 Tpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
511 // Save and disable Debug Timer interrupt to avoid it to access Debug Port
513 DebugTimerInterruptState
= SaveAndSetDebugTimerInterrupt (FALSE
);
514 Handle
= GetDebugPortHandle ();
517 // Always assume the output buffer is empty and the Debug Communication Library can process
518 // more write requests.
520 *Control
= mSerialIoMode
.ControlMask
| EFI_SERIAL_OUTPUT_BUFFER_EMPTY
;
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
526 if (!IsDebugTermianlFifoEmpty (&mSerialFifoForTerminal
) || DebugPortPollBuffer (Handle
)) {
527 *Control
&= ~EFI_SERIAL_INPUT_BUFFER_EMPTY
;
531 // Restore Debug Timer interrupt
533 SaveAndSetDebugTimerInterrupt (DebugTimerInterruptState
);
536 // Restore to original TPL
538 gBS
->RestoreTPL (Tpl
);
544 Write the specified number of bytes to serial device.
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.
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.
559 IN EFI_SERIAL_IO_PROTOCOL
*This
,
560 IN OUT UINTN
*BufferSize
,
564 DEBUG_PORT_HANDLE Handle
;
565 BOOLEAN DebugTimerInterruptState
;
569 // Raise TPL to prevent recursion from EFI timer interrupts
571 Tpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
574 // Save and disable Debug Timer interrupt to avoid it to access Debug Port
576 DebugTimerInterruptState
= SaveAndSetDebugTimerInterrupt (FALSE
);
577 Handle
= GetDebugPortHandle ();
579 if ((mSerialIoMode
.ControlMask
& EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE
) != 0) {
580 if (*BufferSize
== 0) {
583 if ((mLoopbackBuffer
& SERIAL_PORT_LOOPBACK_BUFFER_FULL
) != 0) {
587 mLoopbackBuffer
= SERIAL_PORT_LOOPBACK_BUFFER_FULL
| *(UINT8
*)Buffer
;
590 *BufferSize
= DebugPortWriteBuffer (Handle
, Buffer
, *BufferSize
);
594 // Restore Debug Timer interrupt
596 SaveAndSetDebugTimerInterrupt (DebugTimerInterruptState
);
599 // Restore to original TPL
601 gBS
->RestoreTPL (Tpl
);
607 Read the specified number of bytes from serial device.
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.
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.
622 IN EFI_SERIAL_IO_PROTOCOL
*This
,
623 IN OUT UINTN
*BufferSize
,
630 BOOLEAN DebugTimerInterruptState
;
632 DEBUG_PORT_HANDLE Handle
;
633 DEBUG_PACKET_HEADER DebugHeader
;
637 // Raise TPL to prevent recursion from EFI timer interrupts
639 Tpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
642 // Save and disable Debug Timer interrupt to avoid it to access Debug Port
644 DebugTimerInterruptState
= SaveAndSetDebugTimerInterrupt (FALSE
);
645 Handle
= GetDebugPortHandle ();
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) {
653 *Uint8Buffer
= (UINT8
)(mLoopbackBuffer
& 0xff);
657 for (Index
= 0; Index
< *BufferSize
; Index
++) {
659 // Read input character from terminal FIFO firstly
661 Status
= DebugTerminalFifoRemove (&mSerialFifoForTerminal
, Data8
);
662 if (Status
== EFI_SUCCESS
) {
663 *Uint8Buffer
= *Data8
;
668 // Read the input character from Debug Port
670 if (!DebugPortPollBuffer (Handle
)) {
673 DebugAgentReadBuffer (Handle
, Data8
, 1, 0);
675 if (*Data8
== DEBUG_STARTING_SYMBOL_ATTACH
) {
677 // Add the debug symbol into Debug FIFO
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
);
687 if (Status
== EFI_TIMEOUT
) {
691 *Uint8Buffer
= *Data8
;
695 *BufferSize
= (UINTN
)Uint8Buffer
- (UINTN
)Buffer
;
699 // Restore Debug Timer interrupt
701 SaveAndSetDebugTimerInterrupt (DebugTimerInterruptState
);
704 // Restore to original TPL
706 gBS
->RestoreTPL (Tpl
);
712 Read the Attach/Break-in symbols from the debug port.
714 @param[in] Handle Pointer to Debug Port handle.
715 @param[out] BreakSymbol Returned break symbol.
717 @retval EFI_SUCCESS Read the symbol in BreakSymbol.
718 @retval EFI_NOT_FOUND No read the break symbol.
722 DebugReadBreakFromDebugPort (
723 IN DEBUG_PORT_HANDLE Handle
,
724 OUT UINT8
*BreakSymbol
728 DEBUG_PACKET_HEADER DebugHeader
;
733 // If Debug Port buffer has data, read it till it was break symbol or Debug Port buffer empty.
735 Data8
= (UINT8
*) &DebugHeader
;
738 // If start symbol is not received
740 if (!DebugPortPollBuffer (Handle
)) {
742 // If no data in Debug Port, exit
747 // Try to read the start symbol
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
;
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
;
762 if (Status
== EFI_TIMEOUT
) {
767 // Add to Terminal FIFO
769 DebugTerminalFifoAdd (&mSerialFifoForTerminal
, *Data8
);
773 return EFI_NOT_FOUND
;
777 Read the Attach/Break-in symbols.
779 @param[in] Handle Pointer to Debug Port handle.
780 @param[out] BreakSymbol Returned break symbol.
782 @retval EFI_SUCCESS Read the symbol in BreakSymbol.
783 @retval EFI_NOT_FOUND No read the break symbol.
787 DebugReadBreakSymbol (
788 IN DEBUG_PORT_HANDLE Handle
,
789 OUT UINT8
*BreakSymbol
796 // Read break symbol from debug FIFO firstly
798 Status
= DebugTerminalFifoRemove (&mSerialFifoForDebug
, &Data8
);
799 if (Status
== EFI_SUCCESS
) {
800 *BreakSymbol
= Data8
;
804 // Read Break symbol from debug port
806 return DebugReadBreakFromDebugPort (Handle
, BreakSymbol
);