]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/SerialDxe/SerialIo.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Universal / SerialDxe / SerialIo.c
1 /** @file
2 Serial driver that layers on top of a Serial Port Library instance.
3
4 Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
5 Copyright (c) 2013-2014, ARM Ltd. All rights reserved.<BR>
6 Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
7
8 SPDX-License-Identifier: BSD-2-Clause-Patent
9
10 **/
11
12 #include <Library/UefiBootServicesTableLib.h>
13 #include <Library/SerialPortLib.h>
14 #include <Library/DebugLib.h>
15 #include <Library/PcdLib.h>
16
17 #include <Protocol/SerialIo.h>
18 #include <Protocol/DevicePath.h>
19 #include <Guid/SerialPortLibVendor.h>
20
21 typedef struct {
22 VENDOR_DEVICE_PATH Guid;
23 UART_DEVICE_PATH Uart;
24 EFI_DEVICE_PATH_PROTOCOL End;
25 } SERIAL_DEVICE_PATH;
26
27 /**
28 Reset the serial device.
29
30 @param This Protocol instance pointer.
31
32 @retval EFI_SUCCESS The device was reset.
33 @retval EFI_DEVICE_ERROR The serial device could not be reset.
34
35 **/
36 EFI_STATUS
37 EFIAPI
38 SerialReset (
39 IN EFI_SERIAL_IO_PROTOCOL *This
40 );
41
42 /**
43 Sets the baud rate, receive FIFO depth, transmit/receive time out, parity,
44 data bits, and stop bits on a serial device.
45
46 @param This Protocol instance pointer.
47 @param BaudRate The requested baud rate. A BaudRate value of 0 will use the the
48 device's default interface speed.
49 @param ReceiveFifoDepth The requested depth of the FIFO on the receive side of the
50 serial interface. A ReceiveFifoDepth value of 0 will use
51 the device's default FIFO depth.
52 @param Timeout The requested time out for a single character in microseconds.
53 This timeout applies to both the transmit and receive side of the
54 interface. A Timeout value of 0 will use the device's default time
55 out value.
56 @param Parity The type of parity to use on this serial device. A Parity value of
57 DefaultParity will use the device's default parity value.
58 @param DataBits The number of data bits to use on the serial device. A DataBits
59 value of 0 will use the device's default data bit setting.
60 @param StopBits The number of stop bits to use on this serial device. A StopBits
61 value of DefaultStopBits will use the device's default number of
62 stop bits.
63
64 @retval EFI_SUCCESS The device was reset.
65 @retval EFI_INVALID_PARAMETER One or more attributes has an unsupported value.
66 @retval EFI_DEVICE_ERROR The serial device is not functioning correctly.
67
68 **/
69 EFI_STATUS
70 EFIAPI
71 SerialSetAttributes (
72 IN EFI_SERIAL_IO_PROTOCOL *This,
73 IN UINT64 BaudRate,
74 IN UINT32 ReceiveFifoDepth,
75 IN UINT32 Timeout,
76 IN EFI_PARITY_TYPE Parity,
77 IN UINT8 DataBits,
78 IN EFI_STOP_BITS_TYPE StopBits
79 );
80
81 /**
82 Set the control bits on a serial device
83
84 @param This Protocol instance pointer.
85 @param Control Set the bits of Control that are settable.
86
87 @retval EFI_SUCCESS The new control bits were set on the serial device.
88 @retval EFI_UNSUPPORTED The serial device does not support this operation.
89 @retval EFI_DEVICE_ERROR The serial device is not functioning correctly.
90
91 **/
92 EFI_STATUS
93 EFIAPI
94 SerialSetControl (
95 IN EFI_SERIAL_IO_PROTOCOL *This,
96 IN UINT32 Control
97 );
98
99 /**
100 Retrieves the status of the control bits on a serial device
101
102 @param This Protocol instance pointer.
103 @param Control A pointer to return the current Control signals from the serial device.
104
105 @retval EFI_SUCCESS The control bits were read from the serial device.
106 @retval EFI_DEVICE_ERROR The serial device is not functioning correctly.
107
108 **/
109 EFI_STATUS
110 EFIAPI
111 SerialGetControl (
112 IN EFI_SERIAL_IO_PROTOCOL *This,
113 OUT UINT32 *Control
114 );
115
116 /**
117 Writes data to a serial device.
118
119 @param This Protocol instance pointer.
120 @param BufferSize On input, the size of the Buffer. On output, the amount of
121 data actually written.
122 @param Buffer The buffer of data to write
123
124 @retval EFI_SUCCESS The data was written.
125 @retval EFI_DEVICE_ERROR The device reported an error.
126 @retval EFI_TIMEOUT The data write was stopped due to a timeout.
127
128 **/
129 EFI_STATUS
130 EFIAPI
131 SerialWrite (
132 IN EFI_SERIAL_IO_PROTOCOL *This,
133 IN OUT UINTN *BufferSize,
134 IN VOID *Buffer
135 );
136
137 /**
138 Reads data from a serial device.
139
140 @param This Protocol instance pointer.
141 @param BufferSize On input, the size of the Buffer. On output, the amount of
142 data returned in Buffer.
143 @param Buffer The buffer to return the data into.
144
145 @retval EFI_SUCCESS The data was read.
146 @retval EFI_DEVICE_ERROR The device reported an error.
147 @retval EFI_TIMEOUT The data write was stopped due to a timeout.
148
149 **/
150 EFI_STATUS
151 EFIAPI
152 SerialRead (
153 IN EFI_SERIAL_IO_PROTOCOL *This,
154 IN OUT UINTN *BufferSize,
155 OUT VOID *Buffer
156 );
157
158 EFI_HANDLE mSerialHandle = NULL;
159
160 SERIAL_DEVICE_PATH mSerialDevicePath = {
161 {
162 { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { sizeof (VENDOR_DEVICE_PATH), 0} },
163 EDKII_SERIAL_PORT_LIB_VENDOR_GUID
164 },
165 {
166 { MESSAGING_DEVICE_PATH, MSG_UART_DP, { sizeof (UART_DEVICE_PATH), 0} },
167 0, // Reserved
168 0, // BaudRate
169 0, // DataBits
170 0, // Parity
171 0 // StopBits
172 },
173 { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 } }
174 };
175
176 //
177 // Template used to initialize the Serial IO protocols.
178 //
179 EFI_SERIAL_IO_MODE mSerialIoMode = {
180 //
181 // value field set in SerialDxeInitialize()?
182 //--------- ------------------- -----------------------------
183 0, // ControlMask
184 1000 * 1000, // Timeout
185 0, // BaudRate yes
186 1, // ReceiveFifoDepth
187 0, // DataBits yes
188 0, // Parity yes
189 0 // StopBits yes
190 };
191
192 EFI_SERIAL_IO_PROTOCOL mSerialIoTemplate = {
193 SERIAL_IO_INTERFACE_REVISION,
194 SerialReset,
195 SerialSetAttributes,
196 SerialSetControl,
197 SerialGetControl,
198 SerialWrite,
199 SerialRead,
200 &mSerialIoMode
201 };
202
203 /**
204 Reset the serial device.
205
206 @param This Protocol instance pointer.
207
208 @retval EFI_SUCCESS The device was reset.
209 @retval EFI_DEVICE_ERROR The serial device could not be reset.
210
211 **/
212 EFI_STATUS
213 EFIAPI
214 SerialReset (
215 IN EFI_SERIAL_IO_PROTOCOL *This
216 )
217 {
218 EFI_STATUS Status;
219
220 Status = SerialPortInitialize ();
221 if (EFI_ERROR (Status)) {
222 return Status;
223 }
224
225 //
226 // Go set the current attributes
227 //
228 Status = This->SetAttributes (
229 This,
230 This->Mode->BaudRate,
231 This->Mode->ReceiveFifoDepth,
232 This->Mode->Timeout,
233 (EFI_PARITY_TYPE) This->Mode->Parity,
234 (UINT8) This->Mode->DataBits,
235 (EFI_STOP_BITS_TYPE) This->Mode->StopBits
236 );
237
238 //
239 // The serial device may not support some of the attributes. To prevent
240 // later failure, always return EFI_SUCCESS when SetAttributes is returning
241 // EFI_INVALID_PARAMETER.
242 //
243 if (Status == EFI_INVALID_PARAMETER) {
244 return EFI_SUCCESS;
245 }
246
247 return Status;
248 }
249
250 /**
251 Sets the baud rate, receive FIFO depth, transmit/receive time out, parity,
252 data bits, and stop bits on a serial device.
253
254 @param This Protocol instance pointer.
255 @param BaudRate The requested baud rate. A BaudRate value of 0 will use the the
256 device's default interface speed.
257 @param ReceiveFifoDepth The requested depth of the FIFO on the receive side of the
258 serial interface. A ReceiveFifoDepth value of 0 will use
259 the device's default FIFO depth.
260 @param Timeout The requested time out for a single character in microseconds.
261 This timeout applies to both the transmit and receive side of the
262 interface. A Timeout value of 0 will use the device's default time
263 out value.
264 @param Parity The type of parity to use on this serial device. A Parity value of
265 DefaultParity will use the device's default parity value.
266 @param DataBits The number of data bits to use on the serial device. A DataBits
267 value of 0 will use the device's default data bit setting.
268 @param StopBits The number of stop bits to use on this serial device. A StopBits
269 value of DefaultStopBits will use the device's default number of
270 stop bits.
271
272 @retval EFI_SUCCESS The device was reset.
273 @retval EFI_INVALID_PARAMETER One or more attributes has an unsupported value.
274 @retval EFI_DEVICE_ERROR The serial device is not functioning correctly.
275
276 **/
277 EFI_STATUS
278 EFIAPI
279 SerialSetAttributes (
280 IN EFI_SERIAL_IO_PROTOCOL *This,
281 IN UINT64 BaudRate,
282 IN UINT32 ReceiveFifoDepth,
283 IN UINT32 Timeout,
284 IN EFI_PARITY_TYPE Parity,
285 IN UINT8 DataBits,
286 IN EFI_STOP_BITS_TYPE StopBits
287 )
288 {
289 EFI_STATUS Status;
290 EFI_TPL Tpl;
291 UINT64 OriginalBaudRate;
292 UINT32 OriginalReceiveFifoDepth;
293 UINT32 OriginalTimeout;
294 EFI_PARITY_TYPE OriginalParity;
295 UINT8 OriginalDataBits;
296 EFI_STOP_BITS_TYPE OriginalStopBits;
297
298 //
299 // Preserve the original input values in case
300 // SerialPortSetAttributes() updates the input/output
301 // parameters even on error.
302 //
303 OriginalBaudRate = BaudRate;
304 OriginalReceiveFifoDepth = ReceiveFifoDepth;
305 OriginalTimeout = Timeout;
306 OriginalParity = Parity;
307 OriginalDataBits = DataBits;
308 OriginalStopBits = StopBits;
309 Status = SerialPortSetAttributes (&BaudRate, &ReceiveFifoDepth, &Timeout, &Parity, &DataBits, &StopBits);
310 if (EFI_ERROR (Status)) {
311 //
312 // If it is just to set Timeout value and unsupported is returned,
313 // do not return error.
314 //
315 if ((Status == EFI_UNSUPPORTED) &&
316 (This->Mode->Timeout != OriginalTimeout) &&
317 (This->Mode->ReceiveFifoDepth == OriginalReceiveFifoDepth) &&
318 (This->Mode->BaudRate == OriginalBaudRate) &&
319 (This->Mode->DataBits == (UINT32) OriginalDataBits) &&
320 (This->Mode->Parity == (UINT32) OriginalParity) &&
321 (This->Mode->StopBits == (UINT32) OriginalStopBits)) {
322 //
323 // Restore to the original input values.
324 //
325 BaudRate = OriginalBaudRate;
326 ReceiveFifoDepth = OriginalReceiveFifoDepth;
327 Timeout = OriginalTimeout;
328 Parity = OriginalParity;
329 DataBits = OriginalDataBits;
330 StopBits = OriginalStopBits;
331 Status = EFI_SUCCESS;
332 } else if (Status == EFI_INVALID_PARAMETER || Status == EFI_UNSUPPORTED) {
333 return EFI_INVALID_PARAMETER;
334 } else {
335 return EFI_DEVICE_ERROR;
336 }
337 }
338
339 //
340 // Set the Serial I/O mode and update the device path
341 //
342
343 Tpl = gBS->RaiseTPL (TPL_NOTIFY);
344
345 //
346 // Set the Serial I/O mode
347 //
348 This->Mode->ReceiveFifoDepth = ReceiveFifoDepth;
349 This->Mode->Timeout = Timeout;
350 This->Mode->BaudRate = BaudRate;
351 This->Mode->DataBits = (UINT32) DataBits;
352 This->Mode->Parity = (UINT32) Parity;
353 This->Mode->StopBits = (UINT32) StopBits;
354
355 //
356 // Check if the device path has actually changed
357 //
358 if (mSerialDevicePath.Uart.BaudRate == BaudRate &&
359 mSerialDevicePath.Uart.DataBits == DataBits &&
360 mSerialDevicePath.Uart.Parity == (UINT8) Parity &&
361 mSerialDevicePath.Uart.StopBits == (UINT8) StopBits
362 ) {
363 gBS->RestoreTPL (Tpl);
364 return EFI_SUCCESS;
365 }
366
367 //
368 // Update the device path
369 //
370 mSerialDevicePath.Uart.BaudRate = BaudRate;
371 mSerialDevicePath.Uart.DataBits = DataBits;
372 mSerialDevicePath.Uart.Parity = (UINT8) Parity;
373 mSerialDevicePath.Uart.StopBits = (UINT8) StopBits;
374
375 Status = gBS->ReinstallProtocolInterface (
376 mSerialHandle,
377 &gEfiDevicePathProtocolGuid,
378 &mSerialDevicePath,
379 &mSerialDevicePath
380 );
381
382 gBS->RestoreTPL (Tpl);
383
384 return Status;
385 }
386
387 /**
388 Set the control bits on a serial device
389
390 @param This Protocol instance pointer.
391 @param Control Set the bits of Control that are settable.
392
393 @retval EFI_SUCCESS The new control bits were set on the serial device.
394 @retval EFI_UNSUPPORTED The serial device does not support this operation.
395 @retval EFI_DEVICE_ERROR The serial device is not functioning correctly.
396
397 **/
398 EFI_STATUS
399 EFIAPI
400 SerialSetControl (
401 IN EFI_SERIAL_IO_PROTOCOL *This,
402 IN UINT32 Control
403 )
404 {
405 return SerialPortSetControl (Control);
406 }
407
408 /**
409 Retrieves the status of the control bits on a serial device
410
411 @param This Protocol instance pointer.
412 @param Control A pointer to return the current Control signals from the serial device.
413
414 @retval EFI_SUCCESS The control bits were read from the serial device.
415 @retval EFI_DEVICE_ERROR The serial device is not functioning correctly.
416
417 **/
418 EFI_STATUS
419 EFIAPI
420 SerialGetControl (
421 IN EFI_SERIAL_IO_PROTOCOL *This,
422 OUT UINT32 *Control
423 )
424 {
425 return SerialPortGetControl (Control);
426 }
427
428 /**
429 Writes data to a serial device.
430
431 @param This Protocol instance pointer.
432 @param BufferSize On input, the size of the Buffer. On output, the amount of
433 data actually written.
434 @param Buffer The buffer of data to write
435
436 @retval EFI_SUCCESS The data was written.
437 @retval EFI_DEVICE_ERROR The device reported an error.
438 @retval EFI_TIMEOUT The data write was stopped due to a timeout.
439
440 **/
441 EFI_STATUS
442 EFIAPI
443 SerialWrite (
444 IN EFI_SERIAL_IO_PROTOCOL *This,
445 IN OUT UINTN *BufferSize,
446 IN VOID *Buffer
447 )
448 {
449 UINTN Count;
450
451 Count = SerialPortWrite (Buffer, *BufferSize);
452
453 if (Count != *BufferSize) {
454 *BufferSize = Count;
455 return EFI_TIMEOUT;
456 }
457
458 return EFI_SUCCESS;
459 }
460
461 /**
462 Reads data from a serial device.
463
464 @param This Protocol instance pointer.
465 @param BufferSize On input, the size of the Buffer. On output, the amount of
466 data returned in Buffer.
467 @param Buffer The buffer to return the data into.
468
469 @retval EFI_SUCCESS The data was read.
470 @retval EFI_DEVICE_ERROR The device reported an error.
471 @retval EFI_TIMEOUT The data write was stopped due to a timeout.
472
473 **/
474 EFI_STATUS
475 EFIAPI
476 SerialRead (
477 IN EFI_SERIAL_IO_PROTOCOL *This,
478 IN OUT UINTN *BufferSize,
479 OUT VOID *Buffer
480 )
481 {
482 UINTN Count;
483 UINTN TimeOut;
484
485 Count = 0;
486
487 while (Count < *BufferSize) {
488 TimeOut = 0;
489 while (TimeOut < mSerialIoMode.Timeout) {
490 if (SerialPortPoll ()) {
491 break;
492 }
493 gBS->Stall (10);
494 TimeOut += 10;
495 }
496 if (TimeOut >= mSerialIoMode.Timeout) {
497 break;
498 }
499 SerialPortRead (Buffer, 1);
500 Count++;
501 Buffer = (VOID *) ((UINT8 *) Buffer + 1);
502 }
503
504 if (Count != *BufferSize) {
505 *BufferSize = Count;
506 return EFI_TIMEOUT;
507 }
508
509 return EFI_SUCCESS;
510 }
511
512 /**
513 Initialization for the Serial Io Protocol.
514
515 @param[in] ImageHandle The firmware allocated handle for the EFI image.
516 @param[in] SystemTable A pointer to the EFI System Table.
517
518 @retval EFI_SUCCESS The entry point is executed successfully.
519 @retval other Some error occurs when executing this entry point.
520
521 **/
522 EFI_STATUS
523 EFIAPI
524 SerialDxeInitialize (
525 IN EFI_HANDLE ImageHandle,
526 IN EFI_SYSTEM_TABLE *SystemTable
527 )
528 {
529 EFI_STATUS Status;
530
531 mSerialIoMode.BaudRate = PcdGet64 (PcdUartDefaultBaudRate);
532 mSerialIoMode.DataBits = (UINT32) PcdGet8 (PcdUartDefaultDataBits);
533 mSerialIoMode.Parity = (UINT32) PcdGet8 (PcdUartDefaultParity);
534 mSerialIoMode.StopBits = (UINT32) PcdGet8 (PcdUartDefaultStopBits);
535 mSerialIoMode.ReceiveFifoDepth = PcdGet16 (PcdUartDefaultReceiveFifoDepth);
536 mSerialDevicePath.Uart.BaudRate = PcdGet64 (PcdUartDefaultBaudRate);
537 mSerialDevicePath.Uart.DataBits = PcdGet8 (PcdUartDefaultDataBits);
538 mSerialDevicePath.Uart.Parity = PcdGet8 (PcdUartDefaultParity);
539 mSerialDevicePath.Uart.StopBits = PcdGet8 (PcdUartDefaultStopBits);
540
541 //
542 // Issue a reset to initialize the Serial Port
543 //
544 Status = mSerialIoTemplate.Reset (&mSerialIoTemplate);
545 if (EFI_ERROR (Status)) {
546 return Status;
547 }
548
549 //
550 // Make a new handle with Serial IO protocol and its device path on it.
551 //
552 Status = gBS->InstallMultipleProtocolInterfaces (
553 &mSerialHandle,
554 &gEfiSerialIoProtocolGuid, &mSerialIoTemplate,
555 &gEfiDevicePathProtocolGuid, &mSerialDevicePath,
556 NULL
557 );
558 ASSERT_EFI_ERROR (Status);
559
560 return Status;
561 }
562