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