2 Install Serial IO Protocol that layers on top of a Debug Communication Library instance.
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.
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.
15 #include "DxeDebugAgentLib.h"
18 // Serial I/O Protocol Interface defintions.
24 @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
26 @retval EFI_SUCCESS Reset successfully.
32 IN EFI_SERIAL_IO_PROTOCOL
*This
36 Set new attributes to a serial device.
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.
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).
54 IN EFI_SERIAL_IO_PROTOCOL
*This
,
56 IN UINT32 ReceiveFifoDepth
,
58 IN EFI_PARITY_TYPE Parity
,
60 IN EFI_STOP_BITS_TYPE StopBits
66 @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
67 @param[in] Control Control bits that can be settable.
69 @retval EFI_SUCCESS New Control bits were set successfully.
70 @retval EFI_UNSUPPORTED The Control bits wanted to set are not supported.
76 IN EFI_SERIAL_IO_PROTOCOL
*This
,
83 @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
84 @param[out] Control Control signals of the serial device.
86 @retval EFI_SUCCESS Get Control signals successfully.
92 IN EFI_SERIAL_IO_PROTOCOL
*This
,
97 Write the specified number of bytes to serial device.
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.
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.
112 IN EFI_SERIAL_IO_PROTOCOL
*This
,
113 IN OUT UINTN
*BufferSize
,
118 Read the specified number of bytes from serial device.
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.
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.
133 IN EFI_SERIAL_IO_PROTOCOL
*This
,
134 IN OUT UINTN
*BufferSize
,
139 // Serial Driver Defaults
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
147 // EFI_SERIAL_IO_MODE instance
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
156 0 // default StopBits
160 // EFI_SERIAL_IO_PROTOCOL instance
162 EFI_SERIAL_IO_PROTOCOL mSerialIo
= {
163 SERIAL_IO_INTERFACE_REVISION
,
174 // Serial IO Device Path definition
177 VENDOR_DEVICE_PATH VendorDevicePath
;
178 UART_DEVICE_PATH UartDevicePath
;
179 EFI_DEVICE_PATH_PROTOCOL EndDevicePath
;
180 } SERIAL_IO_DEVICE_PATH
;
183 // Serial IO Device Patch instance
185 SERIAL_IO_DEVICE_PATH mSerialIoDevicePath
= {
188 HARDWARE_DEVICE_PATH
,
191 (UINT8
) (sizeof (VENDOR_DEVICE_PATH
)),
192 (UINT8
) ((sizeof (VENDOR_DEVICE_PATH
)) >> 8)
195 EFI_DEBUG_AGENT_GUID
,
199 MESSAGING_DEVICE_PATH
,
202 (UINT8
) (sizeof (UART_DEVICE_PATH
)),
203 (UINT8
) ((sizeof (UART_DEVICE_PATH
)) >> 8)
207 0, // default BaudRate
208 0, // default DataBits
210 0, // default StopBits
213 END_DEVICE_PATH_TYPE
,
214 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
216 END_DEVICE_PATH_LENGTH
,
222 #define DEBGU_SERIAL_IO_FIFO_DEPTH 10
224 // Data buffer for Terminal input character and Debug Symbols.
225 // The depth is DEBGU_SERIAL_IO_FIFO_DEPTH.
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.
236 UINT8 Data
[DEBGU_SERIAL_IO_FIFO_DEPTH
];
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 }};
248 Detect whether specific FIFO is empty or not.
250 @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO.
252 @return whether specific FIFO is empty or not.
256 IsDebugTermianlFifoEmpty (
257 IN DEBUG_SERIAL_FIFO
*Fifo
260 if (Fifo
->Surplus
== DEBGU_SERIAL_IO_FIFO_DEPTH
) {
268 Detect whether specific FIFO is full or not.
270 @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO.
272 @return whether specific FIFO is full or not.
276 IsDebugTerminalFifoFull (
277 IN DEBUG_SERIAL_FIFO
*Fifo
281 if (Fifo
->Surplus
== 0) {
289 Add data to specific FIFO.
291 @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO.
292 @param[in] Data The data added to FIFO.
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.
299 DebugTerminalFifoAdd (
300 IN DEBUG_SERIAL_FIFO
*Fifo
,
306 // if FIFO full can not add data
308 if (IsDebugTerminalFifoFull (Fifo
)) {
309 return EFI_OUT_OF_RESOURCES
;
312 // FIFO is not full can add data
314 Fifo
->Data
[Fifo
->Last
] = Data
;
317 if (Fifo
->Last
== DEBGU_SERIAL_IO_FIFO_DEPTH
) {
325 Remove data from specific FIFO.
327 @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO.
328 @param[out] Data The data removed from FIFO.
330 @retval EFI_SUCCESS Remove data from specific FIFO successfully.
331 @retval EFI_OUT_OF_RESOURCE Failed to remove data because FIFO is empty.
335 DebugTerminalFifoRemove (
336 IN DEBUG_SERIAL_FIFO
*Fifo
,
341 // if FIFO is empty, no data can remove
343 if (IsDebugTermianlFifoEmpty (Fifo
)) {
344 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
, &mSerialIoDevicePath
,
373 &gEfiSerialIoProtocolGuid
, &mSerialIo
,
376 if (EFI_ERROR (Status
)) {
377 DEBUG ((EFI_D_ERROR
, "Debug Agent: Failed to install EFI Serial IO Protocol on Debug Port!\n"));
384 @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
386 @retval EFI_SUCCESS Reset successfully.
392 IN EFI_SERIAL_IO_PROTOCOL
*This
395 mSerialIoMode
.ControlMask
= SERIAL_PORT_DEFAULT_CONTROL_MASK
;
398 // Not reset serial devcie hardware indeed.
404 Set new attributes to a serial device.
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.
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).
421 SerialSetAttributes (
422 IN EFI_SERIAL_IO_PROTOCOL
*This
,
424 IN UINT32 ReceiveFifoDepth
,
426 IN EFI_PARITY_TYPE Parity
,
428 IN EFI_STOP_BITS_TYPE StopBits
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).
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.
443 mSerialIoMode
.Timeout
= SERIAL_PORT_DEFAULT_TIMEOUT
;
445 mSerialIoMode
.Timeout
= Timeout
;
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.
454 if (ReceiveFifoDepth
== 0 || ReceiveFifoDepth
>= SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH
) {
455 mSerialIoMode
.ReceiveFifoDepth
= SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH
;
457 return EFI_INVALID_PARAMETER
;
466 @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
467 @param[in] Control Control bits that can be settable.
469 @retval EFI_SUCCESS New Control bits were set successfully.
470 @retval EFI_UNSUPPORTED The Control bits wanted to set are not supported.
476 IN EFI_SERIAL_IO_PROTOCOL
*This
,
481 // The only control bit supported by this module is software loopback.
482 // If any other bit is set, then return an error
484 if ((Control
& (~EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE
)) != 0) {
485 return EFI_UNSUPPORTED
;
487 mSerialIoMode
.ControlMask
= Control
;
494 @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
495 @param[out] Control Control signals of the serial device.
497 @retval EFI_SUCCESS Get Control signals successfully.
503 IN EFI_SERIAL_IO_PROTOCOL
*This
,
507 DEBUG_PORT_HANDLE Handle
;
508 BOOLEAN DebugTimerInterruptState
;
512 // Raise TPL to prevent recursion from EFI timer interrupts
514 Tpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
517 // Save and disable Debug Timer interrupt to avoid it to access Debug Port
519 DebugTimerInterruptState
= SaveAndSetDebugTimerInterrupt (FALSE
);
520 Handle
= GetDebugPortHandle ();
523 // Always assume the output buffer is empty and the Debug Communication Library can process
524 // more write requests.
526 *Control
= mSerialIoMode
.ControlMask
| EFI_SERIAL_OUTPUT_BUFFER_EMPTY
;
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
532 if (!IsDebugTermianlFifoEmpty (&mSerialFifoForTerminal
) || DebugPortPollBuffer (Handle
)) {
533 *Control
&= ~EFI_SERIAL_INPUT_BUFFER_EMPTY
;
537 // Restore Debug Timer interrupt
539 SaveAndSetDebugTimerInterrupt (DebugTimerInterruptState
);
542 // Restore to original TPL
544 gBS
->RestoreTPL (Tpl
);
550 Write the specified number of bytes to serial device.
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.
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.
565 IN EFI_SERIAL_IO_PROTOCOL
*This
,
566 IN OUT UINTN
*BufferSize
,
570 DEBUG_PORT_HANDLE Handle
;
571 BOOLEAN DebugTimerInterruptState
;
575 // Raise TPL to prevent recursion from EFI timer interrupts
577 Tpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
580 // Save and disable Debug Timer interrupt to avoid it to access Debug Port
582 DebugTimerInterruptState
= SaveAndSetDebugTimerInterrupt (FALSE
);
583 Handle
= GetDebugPortHandle ();
585 if ((mSerialIoMode
.ControlMask
& EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE
) != 0) {
586 if (*BufferSize
== 0) {
589 if ((mLoopbackBuffer
& SERIAL_PORT_LOOPBACK_BUFFER_FULL
) != 0) {
593 mLoopbackBuffer
= SERIAL_PORT_LOOPBACK_BUFFER_FULL
| *(UINT8
*)Buffer
;
596 *BufferSize
= DebugPortWriteBuffer (Handle
, Buffer
, *BufferSize
);
600 // Restore Debug Timer interrupt
602 SaveAndSetDebugTimerInterrupt (DebugTimerInterruptState
);
605 // Restore to original TPL
607 gBS
->RestoreTPL (Tpl
);
613 Read the specified number of bytes from serial device.
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.
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.
628 IN EFI_SERIAL_IO_PROTOCOL
*This
,
629 IN OUT UINTN
*BufferSize
,
636 BOOLEAN DebugTimerInterruptState
;
638 DEBUG_PORT_HANDLE Handle
;
639 DEBUG_PACKET_HEADER DebugHeader
;
643 // Raise TPL to prevent recursion from EFI timer interrupts
645 Tpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
648 // Save and disable Debug Timer interrupt to avoid it to access Debug Port
650 DebugTimerInterruptState
= SaveAndSetDebugTimerInterrupt (FALSE
);
651 Handle
= GetDebugPortHandle ();
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) {
659 *Uint8Buffer
= (UINT8
)(mLoopbackBuffer
& 0xff);
663 for (Index
= 0; Index
< *BufferSize
; Index
++) {
665 // Read input character from terminal FIFO firstly
667 Status
= DebugTerminalFifoRemove (&mSerialFifoForTerminal
, Data8
);
668 if (Status
== EFI_SUCCESS
) {
669 *Uint8Buffer
= *Data8
;
674 // Read the input character from Debug Port
676 if (!DebugPortPollBuffer (Handle
)) {
679 DebugAgentReadBuffer (Handle
, Data8
, 1, 0);
681 if (*Data8
== DEBUG_STARTING_SYMBOL_ATTACH
) {
683 // Add the debug symbol into Debug FIFO
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
);
693 if (Status
== EFI_TIMEOUT
) {
697 *Uint8Buffer
= *Data8
;
701 *BufferSize
= (UINTN
)Uint8Buffer
- (UINTN
)Buffer
;
705 // Restore Debug Timer interrupt
707 SaveAndSetDebugTimerInterrupt (DebugTimerInterruptState
);
710 // Restore to original TPL
712 gBS
->RestoreTPL (Tpl
);
718 Read the Attach/Break-in symbols from the debug port.
720 @param[in] Handle Pointer to Debug Port handle.
721 @param[out] BreakSymbol Returned break symbol.
723 @retval EFI_SUCCESS Read the symbol in BreakSymbol.
724 @retval EFI_NOT_FOUND No read the break symbol.
728 DebugReadBreakFromDebugPort (
729 IN DEBUG_PORT_HANDLE Handle
,
730 OUT UINT8
*BreakSymbol
734 DEBUG_PACKET_HEADER DebugHeader
;
739 // If Debug Port buffer has data, read it till it was break symbol or Debug Port buffer empty.
741 Data8
= (UINT8
*) &DebugHeader
;
744 // If start symbol is not received
746 if (!DebugPortPollBuffer (Handle
)) {
748 // If no data in Debug Port, exit
753 // Try to read the start symbol
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
;
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
;
768 if (Status
== EFI_TIMEOUT
) {
773 // Add to Terminal FIFO
775 DebugTerminalFifoAdd (&mSerialFifoForTerminal
, *Data8
);
779 return EFI_NOT_FOUND
;
783 Read the Attach/Break-in symbols.
785 @param[in] Handle Pointer to Debug Port handle.
786 @param[out] BreakSymbol Returned break symbol.
788 @retval EFI_SUCCESS Read the symbol in BreakSymbol.
789 @retval EFI_NOT_FOUND No read the break symbol.
793 DebugReadBreakSymbol (
794 IN DEBUG_PORT_HANDLE Handle
,
795 OUT UINT8
*BreakSymbol
802 // Read break symbol from debug FIFO firstly
804 Status
= DebugTerminalFifoRemove (&mSerialFifoForDebug
, &Data8
);
805 if (Status
== EFI_SUCCESS
) {
806 *BreakSymbol
= Data8
;
810 // Read Break symbol from debug port
812 return DebugReadBreakFromDebugPort (Handle
, BreakSymbol
);