]> git.proxmox.com Git - mirror_edk2.git/blame - SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/SerialIo.c
SourceLevelDebugPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / SourceLevelDebugPkg / Library / DebugAgent / DxeDebugAgent / SerialIo.c
CommitLineData
93c0bdec 1/** @file\r
2 Install Serial IO Protocol that layers on top of a Debug Communication Library instance.\r
3\r
77695f4d 4 Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR>\r
85f7e110 5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
93c0bdec 6\r
7**/\r
8\r
9#include "DxeDebugAgentLib.h"\r
10\r
11//\r
12// Serial I/O Protocol Interface defintions.\r
13//\r
14\r
15/**\r
16 Reset serial device.\r
17\r
18 @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.\r
19\r
20 @retval EFI_SUCCESS Reset successfully.\r
21\r
22**/\r
23EFI_STATUS\r
24EFIAPI\r
25SerialReset (\r
26 IN EFI_SERIAL_IO_PROTOCOL *This\r
27 );\r
77695f4d 28\r
93c0bdec 29/**\r
30 Set new attributes to a serial device.\r
31\r
32 @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.\r
33 @param[in] BaudRate The baudrate of the serial device.\r
34 @param[in] ReceiveFifoDepth The depth of receive FIFO buffer.\r
35 @param[in] Timeout The request timeout for a single char.\r
36 @param[in] Parity The type of parity used in serial device.\r
37 @param[in] DataBits Number of databits used in serial device.\r
38 @param[in] StopBits Number of stopbits used in serial device.\r
39\r
40 @retval EFI_SUCCESS The new attributes were set.\r
41 @retval EFI_INVALID_PARAMETER One or more attributes have an unsupported value.\r
42 @retval EFI_DEVICE_ERROR The serial device is not functioning correctly (no return).\r
43\r
44**/\r
45EFI_STATUS\r
46EFIAPI\r
47SerialSetAttributes (\r
48 IN EFI_SERIAL_IO_PROTOCOL *This,\r
49 IN UINT64 BaudRate,\r
50 IN UINT32 ReceiveFifoDepth,\r
51 IN UINT32 Timeout,\r
52 IN EFI_PARITY_TYPE Parity,\r
53 IN UINT8 DataBits,\r
54 IN EFI_STOP_BITS_TYPE StopBits\r
55 );\r
56\r
57/**\r
58 Set Control Bits.\r
59\r
60 @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.\r
61 @param[in] Control Control bits that can be settable.\r
62\r
63 @retval EFI_SUCCESS New Control bits were set successfully.\r
64 @retval EFI_UNSUPPORTED The Control bits wanted to set are not supported.\r
65\r
66**/\r
67EFI_STATUS\r
68EFIAPI\r
69SerialSetControl (\r
70 IN EFI_SERIAL_IO_PROTOCOL *This,\r
71 IN UINT32 Control\r
72 );\r
73\r
74/**\r
75 Get ControlBits.\r
76\r
77 @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.\r
78 @param[out] Control Control signals of the serial device.\r
79\r
80 @retval EFI_SUCCESS Get Control signals successfully.\r
81\r
82**/\r
83EFI_STATUS\r
84EFIAPI\r
85SerialGetControl (\r
86 IN EFI_SERIAL_IO_PROTOCOL *This,\r
87 OUT UINT32 *Control\r
88 );\r
89\r
90/**\r
91 Write the specified number of bytes to serial device.\r
92\r
93 @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.\r
94 @param[in, out] BufferSize On input the size of Buffer, on output the amount of\r
95 data actually written.\r
96 @param[in] Buffer The buffer of data to write.\r
97\r
98 @retval EFI_SUCCESS The data were written successfully.\r
99 @retval EFI_DEVICE_ERROR The device reported an error.\r
100 @retval EFI_TIMEOUT The write operation was stopped due to timeout.\r
101\r
102**/\r
103EFI_STATUS\r
104EFIAPI\r
105SerialWrite (\r
106 IN EFI_SERIAL_IO_PROTOCOL *This,\r
107 IN OUT UINTN *BufferSize,\r
108 IN VOID *Buffer\r
109 );\r
110\r
111/**\r
112 Read the specified number of bytes from serial device.\r
113\r
114 @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.\r
115 @param[in, out] BufferSize On input the size of Buffer, on output the amount of\r
116 data returned in buffer.\r
117 @param[out] Buffer The buffer to return the data into.\r
118\r
119 @retval EFI_SUCCESS The data were read successfully.\r
120 @retval EFI_DEVICE_ERROR The device reported an error.\r
121 @retval EFI_TIMEOUT The read operation was stopped due to timeout.\r
122\r
123**/\r
124EFI_STATUS\r
125EFIAPI\r
126SerialRead (\r
127 IN EFI_SERIAL_IO_PROTOCOL *This,\r
128 IN OUT UINTN *BufferSize,\r
129 OUT VOID *Buffer\r
130 );\r
131\r
132//\r
133// Serial Driver Defaults\r
134//\r
135#define SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH 1\r
136#define SERIAL_PORT_DEFAULT_TIMEOUT 1000000\r
137#define SERIAL_PORT_DEFAULT_CONTROL_MASK 0\r
138#define SERIAL_PORT_LOOPBACK_BUFFER_FULL BIT8\r
139\r
140//\r
141// EFI_SERIAL_IO_MODE instance\r
142//\r
143EFI_SERIAL_IO_MODE mSerialIoMode = {\r
144 SERIAL_PORT_DEFAULT_CONTROL_MASK,\r
145 SERIAL_PORT_DEFAULT_TIMEOUT,\r
b422b62c 146 0, // default BaudRate\r
93c0bdec 147 SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH,\r
b422b62c 148 0, // default DataBits\r
149 0, // default Parity\r
150 0 // default StopBits\r
93c0bdec 151};\r
152\r
153//\r
154// EFI_SERIAL_IO_PROTOCOL instance\r
155//\r
156EFI_SERIAL_IO_PROTOCOL mSerialIo = {\r
157 SERIAL_IO_INTERFACE_REVISION,\r
158 SerialReset,\r
159 SerialSetAttributes,\r
160 SerialSetControl,\r
161 SerialGetControl,\r
162 SerialWrite,\r
163 SerialRead,\r
164 &mSerialIoMode\r
165};\r
166\r
167//\r
168// Serial IO Device Path definition\r
169//\r
170typedef struct {\r
171 VENDOR_DEVICE_PATH VendorDevicePath;\r
172 UART_DEVICE_PATH UartDevicePath;\r
173 EFI_DEVICE_PATH_PROTOCOL EndDevicePath;\r
174} SERIAL_IO_DEVICE_PATH;\r
175\r
176//\r
177// Serial IO Device Patch instance\r
178//\r
179SERIAL_IO_DEVICE_PATH mSerialIoDevicePath = {\r
180 {\r
181 {\r
182 HARDWARE_DEVICE_PATH,\r
183 HW_VENDOR_DP,\r
ce68d3bc
SZ
184 {\r
185 (UINT8) (sizeof (VENDOR_DEVICE_PATH)),\r
186 (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)\r
187 }\r
93c0bdec 188 },\r
189 EFI_DEBUG_AGENT_GUID,\r
190 },\r
191 {\r
192 {\r
193 MESSAGING_DEVICE_PATH,\r
194 MSG_UART_DP,\r
ce68d3bc
SZ
195 {\r
196 (UINT8) (sizeof (UART_DEVICE_PATH)),\r
197 (UINT8) ((sizeof (UART_DEVICE_PATH)) >> 8)\r
198 }\r
93c0bdec 199 },\r
200 0,\r
b422b62c 201 0, // default BaudRate\r
202 0, // default DataBits\r
203 0, // default Parity\r
204 0, // default StopBits\r
93c0bdec 205 },\r
206 {\r
207 END_DEVICE_PATH_TYPE,\r
208 END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
209 {\r
210 END_DEVICE_PATH_LENGTH,\r
211 0\r
212 }\r
213 }\r
214};\r
215\r
216#define DEBGU_SERIAL_IO_FIFO_DEPTH 10\r
217//\r
218// Data buffer for Terminal input character and Debug Symbols.\r
219// The depth is DEBGU_SERIAL_IO_FIFO_DEPTH.\r
220// Fields:\r
221// First UINT8: The index of the first data in array Data[].\r
222// Last UINT8: The index, which you can put a new data into array Data[].\r
223// Surplus UINT8: Identify how many data you can put into array Data[].\r
224// Data[] UINT8: An array, which used to store data.\r
225//\r
226typedef struct {\r
227 UINT8 First;\r
228 UINT8 Last;\r
229 UINT8 Surplus;\r
230 UINT8 Data[DEBGU_SERIAL_IO_FIFO_DEPTH];\r
231} DEBUG_SERIAL_FIFO;\r
232\r
233//\r
234// Global Varibles\r
235//\r
236EFI_HANDLE mSerialIoHandle = NULL;\r
237UINTN mLoopbackBuffer = 0;\r
238DEBUG_SERIAL_FIFO mSerialFifoForTerminal = {0, 0, DEBGU_SERIAL_IO_FIFO_DEPTH, { 0 }};\r
239DEBUG_SERIAL_FIFO mSerialFifoForDebug = {0, 0, DEBGU_SERIAL_IO_FIFO_DEPTH, { 0 }};\r
240\r
241/**\r
242 Detect whether specific FIFO is empty or not.\r
77695f4d 243\r
93c0bdec 244 @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO.\r
245\r
246 @return whether specific FIFO is empty or not.\r
247\r
248**/\r
249BOOLEAN\r
250IsDebugTermianlFifoEmpty (\r
251 IN DEBUG_SERIAL_FIFO *Fifo\r
252 )\r
253{\r
254 if (Fifo->Surplus == DEBGU_SERIAL_IO_FIFO_DEPTH) {\r
255 return TRUE;\r
256 }\r
257\r
258 return FALSE;\r
259}\r
260\r
261/**\r
262 Detect whether specific FIFO is full or not.\r
263\r
264 @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO.\r
265\r
266 @return whether specific FIFO is full or not.\r
267\r
268**/\r
269BOOLEAN\r
270IsDebugTerminalFifoFull (\r
271 IN DEBUG_SERIAL_FIFO *Fifo\r
272 )\r
273\r
274{\r
275 if (Fifo->Surplus == 0) {\r
276 return TRUE;\r
277 }\r
278\r
279 return FALSE;\r
280}\r
281\r
282/**\r
283 Add data to specific FIFO.\r
284\r
285 @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO.\r
286 @param[in] Data The data added to FIFO.\r
287\r
288 @retval EFI_SUCCESS Add data to specific FIFO successfully.\r
289 @retval EFI_OUT_OF_RESOURCE Failed to add data because FIFO is already full.\r
290\r
291**/\r
292EFI_STATUS\r
293DebugTerminalFifoAdd (\r
294 IN DEBUG_SERIAL_FIFO *Fifo,\r
295 IN UINT8 Data\r
296 )\r
297\r
298{\r
299 //\r
300 // if FIFO full can not add data\r
301 //\r
302 if (IsDebugTerminalFifoFull (Fifo)) {\r
303 return EFI_OUT_OF_RESOURCES;\r
304 }\r
305 //\r
306 // FIFO is not full can add data\r
307 //\r
308 Fifo->Data[Fifo->Last] = Data;\r
309 Fifo->Surplus--;\r
310 Fifo->Last++;\r
311 if (Fifo->Last == DEBGU_SERIAL_IO_FIFO_DEPTH) {\r
312 Fifo->Last = 0;\r
313 }\r
314\r
315 return EFI_SUCCESS;\r
316}\r
317\r
318/**\r
319 Remove data from specific FIFO.\r
320\r
321 @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO.\r
322 @param[out] Data The data removed from FIFO.\r
323\r
324 @retval EFI_SUCCESS Remove data from specific FIFO successfully.\r
325 @retval EFI_OUT_OF_RESOURCE Failed to remove data because FIFO is empty.\r
326\r
327**/\r
328EFI_STATUS\r
329DebugTerminalFifoRemove (\r
330 IN DEBUG_SERIAL_FIFO *Fifo,\r
331 OUT UINT8 *Data\r
332 )\r
333{\r
334 //\r
335 // if FIFO is empty, no data can remove\r
336 //\r
337 if (IsDebugTermianlFifoEmpty (Fifo)) {\r
338 return EFI_OUT_OF_RESOURCES;\r
339 }\r
340 //\r
341 // FIFO is not empty, can remove data\r
342 //\r
343 *Data = Fifo->Data[Fifo->First];\r
344 Fifo->Surplus++;\r
345 Fifo->First++;\r
346 if (Fifo->First == DEBGU_SERIAL_IO_FIFO_DEPTH) {\r
347 Fifo->First = 0;\r
348 }\r
349\r
350 return EFI_SUCCESS;\r
351}\r
352\r
353/**\r
77695f4d 354 Install EFI Serial IO protocol based on Debug Communication Library.\r
93c0bdec 355\r
356**/\r
357VOID\r
b422b62c 358InstallSerialIo (\r
359 VOID\r
93c0bdec 360 )\r
361{\r
b422b62c 362 EFI_STATUS Status;\r
93c0bdec 363\r
364 Status = gBS->InstallMultipleProtocolInterfaces (\r
365 &mSerialIoHandle,\r
366 &gEfiDevicePathProtocolGuid, &mSerialIoDevicePath,\r
367 &gEfiSerialIoProtocolGuid, &mSerialIo,\r
368 NULL\r
369 );\r
370 if (EFI_ERROR (Status)) {\r
371 DEBUG ((EFI_D_ERROR, "Debug Agent: Failed to install EFI Serial IO Protocol on Debug Port!\n"));\r
372 }\r
373}\r
374\r
375/**\r
376 Reset serial device.\r
377\r
378 @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.\r
379\r
380 @retval EFI_SUCCESS Reset successfully.\r
381\r
382**/\r
383EFI_STATUS\r
384EFIAPI\r
385SerialReset (\r
386 IN EFI_SERIAL_IO_PROTOCOL *This\r
387 )\r
388{\r
389 mSerialIoMode.ControlMask = SERIAL_PORT_DEFAULT_CONTROL_MASK;\r
390 mLoopbackBuffer = 0;\r
391 //\r
392 // Not reset serial devcie hardware indeed.\r
393 //\r
394 return EFI_SUCCESS;\r
395}\r
396\r
397/**\r
398 Set new attributes to a serial device.\r
399\r
400 @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.\r
401 @param[in] BaudRate The baudrate of the serial device.\r
402 @param[in] ReceiveFifoDepth The depth of receive FIFO buffer.\r
403 @param[in] Timeout The request timeout for a single char.\r
404 @param[in] Parity The type of parity used in serial device.\r
405 @param[in] DataBits Number of databits used in serial device.\r
406 @param[in] StopBits Number of stopbits used in serial device.\r
407\r
408 @retval EFI_SUCCESS The new attributes were set.\r
409 @retval EFI_INVALID_PARAMETER One or more attributes have an unsupported value.\r
410 @retval EFI_DEVICE_ERROR The serial device is not functioning correctly (no return).\r
411\r
412**/\r
413EFI_STATUS\r
414EFIAPI\r
415SerialSetAttributes (\r
416 IN EFI_SERIAL_IO_PROTOCOL *This,\r
417 IN UINT64 BaudRate,\r
418 IN UINT32 ReceiveFifoDepth,\r
419 IN UINT32 Timeout,\r
420 IN EFI_PARITY_TYPE Parity,\r
421 IN UINT8 DataBits,\r
422 IN EFI_STOP_BITS_TYPE StopBits\r
423 )\r
424{\r
425 //\r
b422b62c 426 // The Debug Communication Library CAN NOT change communications parameters (if it has)\r
427 // actually. Because it also has no any idea on what parameters are based on, we cannot\r
77695f4d 428 // check the input parameters (like BaudRate, Parity, DataBits and StopBits).\r
93c0bdec 429 //\r
77695f4d 430\r
93c0bdec 431 //\r
432 // Update the Timeout value in the mode structure based on the request.\r
77695f4d 433 // The Debug Communication Library can not support a timeout on writes, but the timeout on\r
93c0bdec 434 // reads can be provided by this module.\r
435 //\r
436 if (Timeout == 0) {\r
437 mSerialIoMode.Timeout = SERIAL_PORT_DEFAULT_TIMEOUT;\r
438 } else {\r
439 mSerialIoMode.Timeout = Timeout;\r
440 }\r
77695f4d 441\r
93c0bdec 442 //\r
443 // Update the ReceiveFifoDepth value in the mode structure based on the request.\r
77695f4d
LG
444 // This module assumes that the Debug Communication Library uses a FIFO depth of\r
445 // SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH. The Debug Communication Library may actually be\r
93c0bdec 446 // using a larger FIFO, but there is no way to tell.\r
447 //\r
448 if (ReceiveFifoDepth == 0 || ReceiveFifoDepth >= SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH) {\r
449 mSerialIoMode.ReceiveFifoDepth = SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH;\r
450 } else {\r
451 return EFI_INVALID_PARAMETER;\r
452 }\r
453\r
454 return EFI_SUCCESS;\r
455}\r
456\r
457/**\r
458 Set Control Bits.\r
459\r
460 @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.\r
461 @param[in] Control Control bits that can be settable.\r
462\r
463 @retval EFI_SUCCESS New Control bits were set successfully.\r
464 @retval EFI_UNSUPPORTED The Control bits wanted to set are not supported.\r
465\r
466**/\r
467EFI_STATUS\r
468EFIAPI\r
469SerialSetControl (\r
470 IN EFI_SERIAL_IO_PROTOCOL *This,\r
471 IN UINT32 Control\r
472 )\r
473{\r
474 //\r
475 // The only control bit supported by this module is software loopback.\r
476 // If any other bit is set, then return an error\r
477 //\r
478 if ((Control & (~EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE)) != 0) {\r
479 return EFI_UNSUPPORTED;\r
480 }\r
481 mSerialIoMode.ControlMask = Control;\r
482 return EFI_SUCCESS;\r
483}\r
484\r
485/**\r
486 Get ControlBits.\r
487\r
488 @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.\r
489 @param[out] Control Control signals of the serial device.\r
490\r
491 @retval EFI_SUCCESS Get Control signals successfully.\r
492\r
493**/\r
494EFI_STATUS\r
495EFIAPI\r
496SerialGetControl (\r
497 IN EFI_SERIAL_IO_PROTOCOL *This,\r
498 OUT UINT32 *Control\r
499 )\r
500{\r
501 DEBUG_PORT_HANDLE Handle;\r
b422b62c 502 BOOLEAN DebugTimerInterruptState;\r
503 EFI_TPL Tpl;\r
93c0bdec 504\r
b422b62c 505 //\r
506 // Raise TPL to prevent recursion from EFI timer interrupts\r
507 //\r
508 Tpl = gBS->RaiseTPL (TPL_NOTIFY);\r
77695f4d 509\r
b422b62c 510 //\r
511 // Save and disable Debug Timer interrupt to avoid it to access Debug Port\r
512 //\r
513 DebugTimerInterruptState = SaveAndSetDebugTimerInterrupt (FALSE);\r
93c0bdec 514 Handle = GetDebugPortHandle ();\r
77695f4d 515\r
93c0bdec 516 //\r
517 // Always assume the output buffer is empty and the Debug Communication Library can process\r
518 // more write requests.\r
519 //\r
520 *Control = mSerialIoMode.ControlMask | EFI_SERIAL_OUTPUT_BUFFER_EMPTY;\r
77695f4d 521\r
93c0bdec 522 //\r
77695f4d 523 // Check to see if the Terminal FIFO is empty and\r
93c0bdec 524 // check to see if the input buffer in the Debug Communication Library is empty\r
525 //\r
526 if (!IsDebugTermianlFifoEmpty (&mSerialFifoForTerminal) || DebugPortPollBuffer (Handle)) {\r
527 *Control &= ~EFI_SERIAL_INPUT_BUFFER_EMPTY;\r
528 }\r
b422b62c 529\r
530 //\r
531 // Restore Debug Timer interrupt\r
77695f4d 532 //\r
b422b62c 533 SaveAndSetDebugTimerInterrupt (DebugTimerInterruptState);\r
77695f4d 534\r
b422b62c 535 //\r
536 // Restore to original TPL\r
537 //\r
538 gBS->RestoreTPL (Tpl);\r
77695f4d 539\r
93c0bdec 540 return EFI_SUCCESS;\r
541}\r
542\r
543/**\r
544 Write the specified number of bytes to serial device.\r
545\r
546 @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.\r
547 @param[in, out] BufferSize On input the size of Buffer, on output the amount of\r
548 data actually written.\r
549 @param[in] Buffer The buffer of data to write.\r
550\r
551 @retval EFI_SUCCESS The data were written successfully.\r
552 @retval EFI_DEVICE_ERROR The device reported an error.\r
553 @retval EFI_TIMEOUT The write operation was stopped due to timeout.\r
554\r
555**/\r
556EFI_STATUS\r
557EFIAPI\r
558SerialWrite (\r
559 IN EFI_SERIAL_IO_PROTOCOL *This,\r
560 IN OUT UINTN *BufferSize,\r
561 IN VOID *Buffer\r
562 )\r
563{\r
564 DEBUG_PORT_HANDLE Handle;\r
b422b62c 565 BOOLEAN DebugTimerInterruptState;\r
566 EFI_TPL Tpl;\r
93c0bdec 567\r
b422b62c 568 //\r
569 // Raise TPL to prevent recursion from EFI timer interrupts\r
570 //\r
571 Tpl = gBS->RaiseTPL (TPL_NOTIFY);\r
77695f4d 572\r
b422b62c 573 //\r
574 // Save and disable Debug Timer interrupt to avoid it to access Debug Port\r
575 //\r
576 DebugTimerInterruptState = SaveAndSetDebugTimerInterrupt (FALSE);\r
93c0bdec 577 Handle = GetDebugPortHandle ();\r
77695f4d 578\r
93c0bdec 579 if ((mSerialIoMode.ControlMask & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) != 0) {\r
580 if (*BufferSize == 0) {\r
581 return EFI_SUCCESS;\r
582 }\r
583 if ((mLoopbackBuffer & SERIAL_PORT_LOOPBACK_BUFFER_FULL) != 0) {\r
584 *BufferSize = 0;\r
585 return EFI_TIMEOUT;\r
586 }\r
587 mLoopbackBuffer = SERIAL_PORT_LOOPBACK_BUFFER_FULL | *(UINT8 *)Buffer;\r
588 *BufferSize = 1;\r
589 } else {\r
590 *BufferSize = DebugPortWriteBuffer (Handle, Buffer, *BufferSize);\r
591 }\r
b422b62c 592\r
593 //\r
594 // Restore Debug Timer interrupt\r
77695f4d 595 //\r
b422b62c 596 SaveAndSetDebugTimerInterrupt (DebugTimerInterruptState);\r
77695f4d 597\r
b422b62c 598 //\r
599 // Restore to original TPL\r
600 //\r
601 gBS->RestoreTPL (Tpl);\r
77695f4d 602\r
93c0bdec 603 return EFI_SUCCESS;\r
604}\r
605\r
606/**\r
607 Read the specified number of bytes from serial device.\r
608\r
609 @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.\r
610 @param[in, out] BufferSize On input the size of Buffer, on output the amount of\r
611 data returned in buffer.\r
612 @param[out] Buffer The buffer to return the data into.\r
613\r
614 @retval EFI_SUCCESS The data were read successfully.\r
615 @retval EFI_DEVICE_ERROR The device reported an error.\r
616 @retval EFI_TIMEOUT The read operation was stopped due to timeout.\r
617\r
618**/\r
619EFI_STATUS\r
620EFIAPI\r
621SerialRead (\r
622 IN EFI_SERIAL_IO_PROTOCOL *This,\r
623 IN OUT UINTN *BufferSize,\r
624 OUT VOID *Buffer\r
625 )\r
626{\r
627 EFI_STATUS Status;\r
628 UINTN Index;\r
629 UINT8 *Uint8Buffer;\r
b422b62c 630 BOOLEAN DebugTimerInterruptState;\r
631 EFI_TPL Tpl;\r
93c0bdec 632 DEBUG_PORT_HANDLE Handle;\r
b422b62c 633 DEBUG_PACKET_HEADER DebugHeader;\r
634 UINT8 *Data8;\r
93c0bdec 635\r
636 //\r
b422b62c 637 // Raise TPL to prevent recursion from EFI timer interrupts\r
93c0bdec 638 //\r
b422b62c 639 Tpl = gBS->RaiseTPL (TPL_NOTIFY);\r
77695f4d 640\r
b422b62c 641 //\r
642 // Save and disable Debug Timer interrupt to avoid it to access Debug Port\r
643 //\r
644 DebugTimerInterruptState = SaveAndSetDebugTimerInterrupt (FALSE);\r
645 Handle = GetDebugPortHandle ();\r
77695f4d 646\r
b422b62c 647 Data8 = (UINT8 *) &DebugHeader;\r
93c0bdec 648 Uint8Buffer = (UINT8 *)Buffer;\r
649 if ((mSerialIoMode.ControlMask & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) != 0) {\r
650 if ((mLoopbackBuffer & SERIAL_PORT_LOOPBACK_BUFFER_FULL) == 0) {\r
651 return EFI_TIMEOUT;\r
652 }\r
653 *Uint8Buffer = (UINT8)(mLoopbackBuffer & 0xff);\r
654 mLoopbackBuffer = 0;\r
655 *BufferSize = 1;\r
656 } else {\r
657 for (Index = 0; Index < *BufferSize; Index++) {\r
658 //\r
659 // Read input character from terminal FIFO firstly\r
660 //\r
b422b62c 661 Status = DebugTerminalFifoRemove (&mSerialFifoForTerminal, Data8);\r
93c0bdec 662 if (Status == EFI_SUCCESS) {\r
b422b62c 663 *Uint8Buffer = *Data8;\r
93c0bdec 664 Uint8Buffer ++;\r
665 continue;\r
666 }\r
667 //\r
77695f4d 668 // Read the input character from Debug Port\r
93c0bdec 669 //\r
670 if (!DebugPortPollBuffer (Handle)) {\r
671 break;\r
672 }\r
08021523 673 DebugAgentReadBuffer (Handle, Data8, 1, 0);\r
93c0bdec 674\r
b422b62c 675 if (*Data8 == DEBUG_STARTING_SYMBOL_ATTACH) {\r
93c0bdec 676 //\r
677 // Add the debug symbol into Debug FIFO\r
678 //\r
b422b62c 679 DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Terminal Timer attach symbol received %x", *Data8);\r
680 DebugTerminalFifoAdd (&mSerialFifoForDebug, *Data8);\r
681 } else if (*Data8 == DEBUG_STARTING_SYMBOL_NORMAL) {\r
682 Status = ReadRemainingBreakPacket (Handle, &DebugHeader);\r
683 if (Status == EFI_SUCCESS) {\r
684 DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Terminal Timer break symbol received %x", DebugHeader.Command);\r
685 DebugTerminalFifoAdd (&mSerialFifoForDebug, DebugHeader.Command);\r
686 }\r
687 if (Status == EFI_TIMEOUT) {\r
688 continue;\r
689 }\r
93c0bdec 690 } else {\r
b422b62c 691 *Uint8Buffer = *Data8;\r
93c0bdec 692 Uint8Buffer ++;\r
693 }\r
694 }\r
695 *BufferSize = (UINTN)Uint8Buffer - (UINTN)Buffer;\r
696 }\r
697\r
698 //\r
699 // Restore Debug Timer interrupt\r
77695f4d 700 //\r
b422b62c 701 SaveAndSetDebugTimerInterrupt (DebugTimerInterruptState);\r
77695f4d 702\r
b422b62c 703 //\r
704 // Restore to original TPL\r
705 //\r
706 gBS->RestoreTPL (Tpl);\r
77695f4d 707\r
93c0bdec 708 return EFI_SUCCESS;\r
709}\r
710\r
711/**\r
712 Read the Attach/Break-in symbols from the debug port.\r
713\r
714 @param[in] Handle Pointer to Debug Port handle.\r
715 @param[out] BreakSymbol Returned break symbol.\r
716\r
717 @retval EFI_SUCCESS Read the symbol in BreakSymbol.\r
718 @retval EFI_NOT_FOUND No read the break symbol.\r
719\r
720**/\r
721EFI_STATUS\r
b422b62c 722DebugReadBreakFromDebugPort (\r
93c0bdec 723 IN DEBUG_PORT_HANDLE Handle,\r
724 OUT UINT8 *BreakSymbol\r
725 )\r
726{\r
b422b62c 727 EFI_STATUS Status;\r
728 DEBUG_PACKET_HEADER DebugHeader;\r
729 UINT8 *Data8;\r
93c0bdec 730\r
b422b62c 731 *BreakSymbol = 0;\r
732 //\r
733 // If Debug Port buffer has data, read it till it was break symbol or Debug Port buffer empty.\r
734 //\r
735 Data8 = (UINT8 *) &DebugHeader;\r
736 while (TRUE) {\r
737 //\r
738 // If start symbol is not received\r
739 //\r
93c0bdec 740 if (!DebugPortPollBuffer (Handle)) {\r
741 //\r
b422b62c 742 // If no data in Debug Port, exit\r
93c0bdec 743 //\r
b422b62c 744 break;\r
745 }\r
746 //\r
747 // Try to read the start symbol\r
748 //\r
08021523 749 DebugAgentReadBuffer (Handle, Data8, 1, 0);\r
b422b62c 750 if (*Data8 == DEBUG_STARTING_SYMBOL_ATTACH) {\r
751 DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Debug Timer attach symbol received %x", *Data8);\r
752 *BreakSymbol = *Data8;\r
753 return EFI_SUCCESS;\r
77695f4d 754 }\r
b422b62c 755 if (*Data8 == DEBUG_STARTING_SYMBOL_NORMAL) {\r
756 Status = ReadRemainingBreakPacket (Handle, &DebugHeader);\r
757 if (Status == EFI_SUCCESS) {\r
758 DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Debug Timer break symbol received %x", DebugHeader.Command);\r
759 *BreakSymbol = DebugHeader.Command;\r
760 return EFI_SUCCESS;\r
761 }\r
762 if (Status == EFI_TIMEOUT) {\r
763 break;\r
764 }\r
93c0bdec 765 } else {\r
766 //\r
b422b62c 767 // Add to Terminal FIFO\r
93c0bdec 768 //\r
b422b62c 769 DebugTerminalFifoAdd (&mSerialFifoForTerminal, *Data8);\r
93c0bdec 770 }\r
771 }\r
77695f4d 772\r
b422b62c 773 return EFI_NOT_FOUND;\r
774}\r
775\r
776/**\r
777 Read the Attach/Break-in symbols.\r
778\r
779 @param[in] Handle Pointer to Debug Port handle.\r
780 @param[out] BreakSymbol Returned break symbol.\r
781\r
782 @retval EFI_SUCCESS Read the symbol in BreakSymbol.\r
783 @retval EFI_NOT_FOUND No read the break symbol.\r
784\r
785**/\r
786EFI_STATUS\r
787DebugReadBreakSymbol (\r
788 IN DEBUG_PORT_HANDLE Handle,\r
789 OUT UINT8 *BreakSymbol\r
790 )\r
791{\r
792 EFI_STATUS Status;\r
793 UINT8 Data8;\r
794\r
795 //\r
796 // Read break symbol from debug FIFO firstly\r
797 //\r
798 Status = DebugTerminalFifoRemove (&mSerialFifoForDebug, &Data8);\r
799 if (Status == EFI_SUCCESS) {\r
800 *BreakSymbol = Data8;\r
801 return EFI_SUCCESS;\r
802 } else {\r
803 //\r
804 // Read Break symbol from debug port\r
805 //\r
806 return DebugReadBreakFromDebugPort (Handle, BreakSymbol);\r
807 }\r
93c0bdec 808}\r