2 Install Serial IO Protocol that layers on top of a Debug Communication Library instance.
4 Copyright (c) 2012, 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
,
153 SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH
,
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
,
190 (UINT8
) (sizeof (VENDOR_DEVICE_PATH
)),
191 (UINT8
) ((sizeof (VENDOR_DEVICE_PATH
)) >> 8)
193 EFI_DEBUG_AGENT_GUID
,
197 MESSAGING_DEVICE_PATH
,
199 (UINT8
) (sizeof (UART_DEVICE_PATH
)),
200 (UINT8
) ((sizeof (UART_DEVICE_PATH
)) >> 8)
209 END_DEVICE_PATH_TYPE
,
210 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
212 END_DEVICE_PATH_LENGTH
,
218 #define DEBGU_SERIAL_IO_FIFO_DEPTH 10
220 // Data buffer for Terminal input character and Debug Symbols.
221 // The depth is DEBGU_SERIAL_IO_FIFO_DEPTH.
223 // First UINT8: The index of the first data in array Data[].
224 // Last UINT8: The index, which you can put a new data into array Data[].
225 // Surplus UINT8: Identify how many data you can put into array Data[].
226 // Data[] UINT8: An array, which used to store data.
232 UINT8 Data
[DEBGU_SERIAL_IO_FIFO_DEPTH
];
238 EFI_HANDLE mSerialIoHandle
= NULL
;
239 UINTN mLoopbackBuffer
= 0;
240 DEBUG_SERIAL_FIFO mSerialFifoForTerminal
= {0, 0, DEBGU_SERIAL_IO_FIFO_DEPTH
, { 0 }};
241 DEBUG_SERIAL_FIFO mSerialFifoForDebug
= {0, 0, DEBGU_SERIAL_IO_FIFO_DEPTH
, { 0 }};
244 Detect whether specific FIFO is empty or not.
246 @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO.
248 @return whether specific FIFO is empty or not.
252 IsDebugTermianlFifoEmpty (
253 IN DEBUG_SERIAL_FIFO
*Fifo
256 if (Fifo
->Surplus
== DEBGU_SERIAL_IO_FIFO_DEPTH
) {
264 Detect whether specific FIFO is full or not.
266 @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO.
268 @return whether specific FIFO is full or not.
272 IsDebugTerminalFifoFull (
273 IN DEBUG_SERIAL_FIFO
*Fifo
277 if (Fifo
->Surplus
== 0) {
285 Add data to specific FIFO.
287 @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO.
288 @param[in] Data The data added to FIFO.
290 @retval EFI_SUCCESS Add data to specific FIFO successfully.
291 @retval EFI_OUT_OF_RESOURCE Failed to add data because FIFO is already full.
295 DebugTerminalFifoAdd (
296 IN DEBUG_SERIAL_FIFO
*Fifo
,
302 // if FIFO full can not add data
304 if (IsDebugTerminalFifoFull (Fifo
)) {
305 return EFI_OUT_OF_RESOURCES
;
308 // FIFO is not full can add data
310 Fifo
->Data
[Fifo
->Last
] = Data
;
313 if (Fifo
->Last
== DEBGU_SERIAL_IO_FIFO_DEPTH
) {
321 Remove data from specific FIFO.
323 @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO.
324 @param[out] Data The data removed from FIFO.
326 @retval EFI_SUCCESS Remove data from specific FIFO successfully.
327 @retval EFI_OUT_OF_RESOURCE Failed to remove data because FIFO is empty.
331 DebugTerminalFifoRemove (
332 IN DEBUG_SERIAL_FIFO
*Fifo
,
337 // if FIFO is empty, no data can remove
339 if (IsDebugTermianlFifoEmpty (Fifo
)) {
340 return EFI_OUT_OF_RESOURCES
;
343 // FIFO is not empty, can remove data
345 *Data
= Fifo
->Data
[Fifo
->First
];
348 if (Fifo
->First
== DEBGU_SERIAL_IO_FIFO_DEPTH
) {
356 Notification function on EFI PCD protocol to install EFI Serial IO protocol based
357 on Debug Communication Library.
359 @param[in] Event The event of notify protocol.
360 @param[in] Context Notify event context.
365 InstallSerialIoNotification (
373 // Get Debug Port parameters from PCDs
375 mSerialIoDevicePath
.UartDevicePath
.BaudRate
= PcdGet64 (PcdUartDefaultBaudRate
);
376 mSerialIoDevicePath
.UartDevicePath
.DataBits
= PcdGet8 (PcdUartDefaultDataBits
);
377 mSerialIoDevicePath
.UartDevicePath
.Parity
= PcdGet8 (PcdUartDefaultParity
);
378 mSerialIoDevicePath
.UartDevicePath
.StopBits
= PcdGet8 (PcdUartDefaultStopBits
);
380 mSerialIoMode
.BaudRate
= mSerialIoDevicePath
.UartDevicePath
.BaudRate
;
381 mSerialIoMode
.DataBits
= mSerialIoDevicePath
.UartDevicePath
.DataBits
;
382 mSerialIoMode
.Parity
= mSerialIoDevicePath
.UartDevicePath
.Parity
;
383 mSerialIoMode
.StopBits
= mSerialIoDevicePath
.UartDevicePath
.StopBits
;
385 Status
= gBS
->InstallMultipleProtocolInterfaces (
387 &gEfiDevicePathProtocolGuid
, &mSerialIoDevicePath
,
388 &gEfiSerialIoProtocolGuid
, &mSerialIo
,
391 if (EFI_ERROR (Status
)) {
392 DEBUG ((EFI_D_ERROR
, "Debug Agent: Failed to install EFI Serial IO Protocol on Debug Port!\n"));
399 @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
401 @retval EFI_SUCCESS Reset successfully.
407 IN EFI_SERIAL_IO_PROTOCOL
*This
410 mSerialIoMode
.ControlMask
= SERIAL_PORT_DEFAULT_CONTROL_MASK
;
413 // Not reset serial devcie hardware indeed.
419 Set new attributes to a serial device.
421 @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
422 @param[in] BaudRate The baudrate of the serial device.
423 @param[in] ReceiveFifoDepth The depth of receive FIFO buffer.
424 @param[in] Timeout The request timeout for a single char.
425 @param[in] Parity The type of parity used in serial device.
426 @param[in] DataBits Number of databits used in serial device.
427 @param[in] StopBits Number of stopbits used in serial device.
429 @retval EFI_SUCCESS The new attributes were set.
430 @retval EFI_INVALID_PARAMETER One or more attributes have an unsupported value.
431 @retval EFI_DEVICE_ERROR The serial device is not functioning correctly (no return).
436 SerialSetAttributes (
437 IN EFI_SERIAL_IO_PROTOCOL
*This
,
439 IN UINT32 ReceiveFifoDepth
,
441 IN EFI_PARITY_TYPE Parity
,
443 IN EFI_STOP_BITS_TYPE StopBits
447 // The Debug Communication Library does not support changing communications parameters, so unless
448 // the request is to use the default value or the value the Debug Communication Library is already
449 // using, then return EFI_INVALID_PARAMETER.
451 if (BaudRate
!= 0 && BaudRate
!= PcdGet64 (PcdUartDefaultBaudRate
)) {
452 return EFI_INVALID_PARAMETER
;
454 if (Parity
!= DefaultParity
&& Parity
!= PcdGet8 (PcdUartDefaultParity
)) {
455 return EFI_INVALID_PARAMETER
;
457 if (DataBits
!= 0 && DataBits
!= PcdGet8 (PcdUartDefaultDataBits
)) {
458 return EFI_INVALID_PARAMETER
;
460 if (StopBits
!= DefaultStopBits
&& StopBits
!= PcdGet8 (PcdUartDefaultStopBits
)) {
461 return EFI_INVALID_PARAMETER
;
465 // Update the Timeout value in the mode structure based on the request.
466 // The Debug Communication Library can not support a timeout on writes, but the timeout on
467 // reads can be provided by this module.
470 mSerialIoMode
.Timeout
= SERIAL_PORT_DEFAULT_TIMEOUT
;
472 mSerialIoMode
.Timeout
= Timeout
;
476 // Update the ReceiveFifoDepth value in the mode structure based on the request.
477 // This module assumes that the Debug Communication Library uses a FIFO depth of
478 // SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH. The Debug Communication Library may actually be
479 // using a larger FIFO, but there is no way to tell.
481 if (ReceiveFifoDepth
== 0 || ReceiveFifoDepth
>= SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH
) {
482 mSerialIoMode
.ReceiveFifoDepth
= SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH
;
484 return EFI_INVALID_PARAMETER
;
493 @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
494 @param[in] Control Control bits that can be settable.
496 @retval EFI_SUCCESS New Control bits were set successfully.
497 @retval EFI_UNSUPPORTED The Control bits wanted to set are not supported.
503 IN EFI_SERIAL_IO_PROTOCOL
*This
,
508 // The only control bit supported by this module is software loopback.
509 // If any other bit is set, then return an error
511 if ((Control
& (~EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE
)) != 0) {
512 return EFI_UNSUPPORTED
;
514 mSerialIoMode
.ControlMask
= Control
;
521 @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
522 @param[out] Control Control signals of the serial device.
524 @retval EFI_SUCCESS Get Control signals successfully.
530 IN EFI_SERIAL_IO_PROTOCOL
*This
,
534 DEBUG_PORT_HANDLE Handle
;
536 Handle
= GetDebugPortHandle ();
539 // Always assume the output buffer is empty and the Debug Communication Library can process
540 // more write requests.
542 *Control
= mSerialIoMode
.ControlMask
| EFI_SERIAL_OUTPUT_BUFFER_EMPTY
;
545 // Check to see if the Terminal FIFO is empty and
546 // check to see if the input buffer in the Debug Communication Library is empty
548 if (!IsDebugTermianlFifoEmpty (&mSerialFifoForTerminal
) || DebugPortPollBuffer (Handle
)) {
549 *Control
&= ~EFI_SERIAL_INPUT_BUFFER_EMPTY
;
555 Write the specified number of bytes to serial device.
557 @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
558 @param[in, out] BufferSize On input the size of Buffer, on output the amount of
559 data actually written.
560 @param[in] Buffer The buffer of data to write.
562 @retval EFI_SUCCESS The data were written successfully.
563 @retval EFI_DEVICE_ERROR The device reported an error.
564 @retval EFI_TIMEOUT The write operation was stopped due to timeout.
570 IN EFI_SERIAL_IO_PROTOCOL
*This
,
571 IN OUT UINTN
*BufferSize
,
575 DEBUG_PORT_HANDLE Handle
;
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
);
596 Read the specified number of bytes from serial device.
598 @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
599 @param[in, out] BufferSize On input the size of Buffer, on output the amount of
600 data returned in buffer.
601 @param[out] Buffer The buffer to return the data into.
603 @retval EFI_SUCCESS The data were read successfully.
604 @retval EFI_DEVICE_ERROR The device reported an error.
605 @retval EFI_TIMEOUT The read operation was stopped due to timeout.
611 IN EFI_SERIAL_IO_PROTOCOL
*This
,
612 IN OUT UINTN
*BufferSize
,
619 BOOLEAN OldInterruptState
;
620 DEBUG_PORT_HANDLE Handle
;
623 Handle
= GetDebugPortHandle ();
626 // Save and disable Debug Timer interrupt to avoid it to access Debug Port
628 OldInterruptState
= SaveAndSetDebugTimerInterrupt (FALSE
);
630 Uint8Buffer
= (UINT8
*)Buffer
;
631 if ((mSerialIoMode
.ControlMask
& EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE
) != 0) {
632 if ((mLoopbackBuffer
& SERIAL_PORT_LOOPBACK_BUFFER_FULL
) == 0) {
635 *Uint8Buffer
= (UINT8
)(mLoopbackBuffer
& 0xff);
639 for (Index
= 0; Index
< *BufferSize
; Index
++) {
641 // Read input character from terminal FIFO firstly
643 Status
= DebugTerminalFifoRemove (&mSerialFifoForTerminal
, &Data
);
644 if (Status
== EFI_SUCCESS
) {
650 // Read the input character from Debug Port
652 if (!DebugPortPollBuffer (Handle
)) {
655 DebugPortReadBuffer (Handle
, &Data
, 1, 0);
657 if (Data
== DEBUG_STARTING_SYMBOL_ATTACH
||
658 Data
== DEBUG_STARTING_SYMBOL_BREAK
) {
660 // Add the debug symbol into Debug FIFO
662 DebugTerminalFifoAdd (&mSerialFifoForDebug
, Data
);
668 *BufferSize
= (UINTN
)Uint8Buffer
- (UINTN
)Buffer
;
672 // Restore Debug Timer interrupt
674 SaveAndSetDebugTimerInterrupt (OldInterruptState
);
680 Read the Attach/Break-in symbols from the debug port.
682 @param[in] Handle Pointer to Debug Port handle.
683 @param[out] BreakSymbol Returned break symbol.
685 @retval EFI_SUCCESS Read the symbol in BreakSymbol.
686 @retval EFI_NOT_FOUND No read the break symbol.
690 DebugReadBreakSymbol (
691 IN DEBUG_PORT_HANDLE Handle
,
692 OUT UINT8
*BreakSymbol
698 Status
= DebugTerminalFifoRemove (&mSerialFifoForDebug
, &Data
);
699 if (Status
!= EFI_SUCCESS
) {
700 if (!DebugPortPollBuffer (Handle
)) {
702 // No data in Debug Port buffer.
704 return EFI_NOT_FOUND
;
707 // Read one character from Debug Port.
709 DebugPortReadBuffer (Handle
, &Data
, 1, 0);
710 if ((Data
!= DEBUG_STARTING_SYMBOL_ATTACH
) && (Data
!= DEBUG_STARTING_SYMBOL_BREAK
)) {
712 // If the data is not Break symbol, add it into Terminal FIFO
714 DebugTerminalFifoAdd (&mSerialFifoForTerminal
, Data
);
715 return EFI_NOT_FOUND
;