]> 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 },
164 EDKII_SERIAL_PORT_LIB_VENDOR_GUID
165 },
166 {
167 { MESSAGING_DEVICE_PATH, MSG_UART_DP, { sizeof (UART_DEVICE_PATH), 0 }
168 },
169 0, // Reserved
170 0, // BaudRate
171 0, // DataBits
172 0, // Parity
173 0 // StopBits
174 },
175 { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }
176 }
177 };
178
179 //
180 // Template used to initialize the Serial IO protocols.
181 //
182 EFI_SERIAL_IO_MODE mSerialIoMode = {
183 //
184 // value field set in SerialDxeInitialize()?
185 // --------- ------------------- -----------------------------
186 0, // ControlMask
187 1000 * 1000, // Timeout
188 0, // BaudRate yes
189 1, // ReceiveFifoDepth
190 0, // DataBits yes
191 0, // Parity yes
192 0 // StopBits yes
193 };
194
195 EFI_SERIAL_IO_PROTOCOL mSerialIoTemplate = {
196 SERIAL_IO_INTERFACE_REVISION,
197 SerialReset,
198 SerialSetAttributes,
199 SerialSetControl,
200 SerialGetControl,
201 SerialWrite,
202 SerialRead,
203 &mSerialIoMode
204 };
205
206 /**
207 Reset the serial device.
208
209 @param This Protocol instance pointer.
210
211 @retval EFI_SUCCESS The device was reset.
212 @retval EFI_DEVICE_ERROR The serial device could not be reset.
213
214 **/
215 EFI_STATUS
216 EFIAPI
217 SerialReset (
218 IN EFI_SERIAL_IO_PROTOCOL *This
219 )
220 {
221 EFI_STATUS Status;
222
223 Status = SerialPortInitialize ();
224 if (EFI_ERROR (Status)) {
225 return Status;
226 }
227
228 //
229 // Go set the current attributes
230 //
231 Status = This->SetAttributes (
232 This,
233 This->Mode->BaudRate,
234 This->Mode->ReceiveFifoDepth,
235 This->Mode->Timeout,
236 (EFI_PARITY_TYPE)This->Mode->Parity,
237 (UINT8)This->Mode->DataBits,
238 (EFI_STOP_BITS_TYPE)This->Mode->StopBits
239 );
240
241 //
242 // The serial device may not support some of the attributes. To prevent
243 // later failure, always return EFI_SUCCESS when SetAttributes is returning
244 // EFI_INVALID_PARAMETER.
245 //
246 if (Status == EFI_INVALID_PARAMETER) {
247 return EFI_SUCCESS;
248 }
249
250 return Status;
251 }
252
253 /**
254 Sets the baud rate, receive FIFO depth, transmit/receive time out, parity,
255 data bits, and stop bits on a serial device.
256
257 @param This Protocol instance pointer.
258 @param BaudRate The requested baud rate. A BaudRate value of 0 will use the the
259 device's default interface speed.
260 @param ReceiveFifoDepth The requested depth of the FIFO on the receive side of the
261 serial interface. A ReceiveFifoDepth value of 0 will use
262 the device's default FIFO depth.
263 @param Timeout The requested time out for a single character in microseconds.
264 This timeout applies to both the transmit and receive side of the
265 interface. A Timeout value of 0 will use the device's default time
266 out value.
267 @param Parity The type of parity to use on this serial device. A Parity value of
268 DefaultParity will use the device's default parity value.
269 @param DataBits The number of data bits to use on the serial device. A DataBits
270 value of 0 will use the device's default data bit setting.
271 @param StopBits The number of stop bits to use on this serial device. A StopBits
272 value of DefaultStopBits will use the device's default number of
273 stop bits.
274
275 @retval EFI_SUCCESS The device was reset.
276 @retval EFI_INVALID_PARAMETER One or more attributes has an unsupported value.
277 @retval EFI_DEVICE_ERROR The serial device is not functioning correctly.
278
279 **/
280 EFI_STATUS
281 EFIAPI
282 SerialSetAttributes (
283 IN EFI_SERIAL_IO_PROTOCOL *This,
284 IN UINT64 BaudRate,
285 IN UINT32 ReceiveFifoDepth,
286 IN UINT32 Timeout,
287 IN EFI_PARITY_TYPE Parity,
288 IN UINT8 DataBits,
289 IN EFI_STOP_BITS_TYPE StopBits
290 )
291 {
292 EFI_STATUS Status;
293 EFI_TPL Tpl;
294 UINT64 OriginalBaudRate;
295 UINT32 OriginalReceiveFifoDepth;
296 UINT32 OriginalTimeout;
297 EFI_PARITY_TYPE OriginalParity;
298 UINT8 OriginalDataBits;
299 EFI_STOP_BITS_TYPE OriginalStopBits;
300
301 //
302 // Preserve the original input values in case
303 // SerialPortSetAttributes() updates the input/output
304 // parameters even on error.
305 //
306 OriginalBaudRate = BaudRate;
307 OriginalReceiveFifoDepth = ReceiveFifoDepth;
308 OriginalTimeout = Timeout;
309 OriginalParity = Parity;
310 OriginalDataBits = DataBits;
311 OriginalStopBits = StopBits;
312 Status = SerialPortSetAttributes (&BaudRate, &ReceiveFifoDepth, &Timeout, &Parity, &DataBits, &StopBits);
313 if (EFI_ERROR (Status)) {
314 //
315 // If it is just to set Timeout value and unsupported is returned,
316 // do not return error.
317 //
318 if ((Status == EFI_UNSUPPORTED) &&
319 (This->Mode->Timeout != OriginalTimeout) &&
320 (This->Mode->ReceiveFifoDepth == OriginalReceiveFifoDepth) &&
321 (This->Mode->BaudRate == OriginalBaudRate) &&
322 (This->Mode->DataBits == (UINT32)OriginalDataBits) &&
323 (This->Mode->Parity == (UINT32)OriginalParity) &&
324 (This->Mode->StopBits == (UINT32)OriginalStopBits))
325 {
326 //
327 // Restore to the original input values.
328 //
329 BaudRate = OriginalBaudRate;
330 ReceiveFifoDepth = OriginalReceiveFifoDepth;
331 Timeout = OriginalTimeout;
332 Parity = OriginalParity;
333 DataBits = OriginalDataBits;
334 StopBits = OriginalStopBits;
335 Status = EFI_SUCCESS;
336 } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {
337 return EFI_INVALID_PARAMETER;
338 } else {
339 return EFI_DEVICE_ERROR;
340 }
341 }
342
343 //
344 // Set the Serial I/O mode and update the device path
345 //
346
347 Tpl = gBS->RaiseTPL (TPL_NOTIFY);
348
349 //
350 // Set the Serial I/O mode
351 //
352 This->Mode->ReceiveFifoDepth = ReceiveFifoDepth;
353 This->Mode->Timeout = Timeout;
354 This->Mode->BaudRate = BaudRate;
355 This->Mode->DataBits = (UINT32)DataBits;
356 This->Mode->Parity = (UINT32)Parity;
357 This->Mode->StopBits = (UINT32)StopBits;
358
359 //
360 // Check if the device path has actually changed
361 //
362 if ((mSerialDevicePath.Uart.BaudRate == BaudRate) &&
363 (mSerialDevicePath.Uart.DataBits == DataBits) &&
364 (mSerialDevicePath.Uart.Parity == (UINT8)Parity) &&
365 (mSerialDevicePath.Uart.StopBits == (UINT8)StopBits)
366 )
367 {
368 gBS->RestoreTPL (Tpl);
369 return EFI_SUCCESS;
370 }
371
372 //
373 // Update the device path
374 //
375 mSerialDevicePath.Uart.BaudRate = BaudRate;
376 mSerialDevicePath.Uart.DataBits = DataBits;
377 mSerialDevicePath.Uart.Parity = (UINT8)Parity;
378 mSerialDevicePath.Uart.StopBits = (UINT8)StopBits;
379
380 Status = gBS->ReinstallProtocolInterface (
381 mSerialHandle,
382 &gEfiDevicePathProtocolGuid,
383 &mSerialDevicePath,
384 &mSerialDevicePath
385 );
386
387 gBS->RestoreTPL (Tpl);
388
389 return Status;
390 }
391
392 /**
393 Set the control bits on a serial device
394
395 @param This Protocol instance pointer.
396 @param Control Set the bits of Control that are settable.
397
398 @retval EFI_SUCCESS The new control bits were set on the serial device.
399 @retval EFI_UNSUPPORTED The serial device does not support this operation.
400 @retval EFI_DEVICE_ERROR The serial device is not functioning correctly.
401
402 **/
403 EFI_STATUS
404 EFIAPI
405 SerialSetControl (
406 IN EFI_SERIAL_IO_PROTOCOL *This,
407 IN UINT32 Control
408 )
409 {
410 return SerialPortSetControl (Control);
411 }
412
413 /**
414 Retrieves the status of the control bits on a serial device
415
416 @param This Protocol instance pointer.
417 @param Control A pointer to return the current Control signals from the serial device.
418
419 @retval EFI_SUCCESS The control bits were read from the serial device.
420 @retval EFI_DEVICE_ERROR The serial device is not functioning correctly.
421
422 **/
423 EFI_STATUS
424 EFIAPI
425 SerialGetControl (
426 IN EFI_SERIAL_IO_PROTOCOL *This,
427 OUT UINT32 *Control
428 )
429 {
430 return SerialPortGetControl (Control);
431 }
432
433 /**
434 Writes data to a serial device.
435
436 @param This Protocol instance pointer.
437 @param BufferSize On input, the size of the Buffer. On output, the amount of
438 data actually written.
439 @param Buffer The buffer of data to write
440
441 @retval EFI_SUCCESS The data was written.
442 @retval EFI_DEVICE_ERROR The device reported an error.
443 @retval EFI_TIMEOUT The data write was stopped due to a timeout.
444
445 **/
446 EFI_STATUS
447 EFIAPI
448 SerialWrite (
449 IN EFI_SERIAL_IO_PROTOCOL *This,
450 IN OUT UINTN *BufferSize,
451 IN VOID *Buffer
452 )
453 {
454 UINTN Count;
455
456 Count = SerialPortWrite (Buffer, *BufferSize);
457
458 if (Count != *BufferSize) {
459 *BufferSize = Count;
460 return EFI_TIMEOUT;
461 }
462
463 return EFI_SUCCESS;
464 }
465
466 /**
467 Reads data from a serial device.
468
469 @param This Protocol instance pointer.
470 @param BufferSize On input, the size of the Buffer. On output, the amount of
471 data returned in Buffer.
472 @param Buffer The buffer to return the data into.
473
474 @retval EFI_SUCCESS The data was read.
475 @retval EFI_DEVICE_ERROR The device reported an error.
476 @retval EFI_TIMEOUT The data write was stopped due to a timeout.
477
478 **/
479 EFI_STATUS
480 EFIAPI
481 SerialRead (
482 IN EFI_SERIAL_IO_PROTOCOL *This,
483 IN OUT UINTN *BufferSize,
484 OUT VOID *Buffer
485 )
486 {
487 UINTN Count;
488 UINTN TimeOut;
489
490 Count = 0;
491
492 while (Count < *BufferSize) {
493 TimeOut = 0;
494 while (TimeOut < mSerialIoMode.Timeout) {
495 if (SerialPortPoll ()) {
496 break;
497 }
498
499 gBS->Stall (10);
500 TimeOut += 10;
501 }
502
503 if (TimeOut >= mSerialIoMode.Timeout) {
504 break;
505 }
506
507 SerialPortRead (Buffer, 1);
508 Count++;
509 Buffer = (VOID *)((UINT8 *)Buffer + 1);
510 }
511
512 if (Count != *BufferSize) {
513 *BufferSize = Count;
514 return EFI_TIMEOUT;
515 }
516
517 return EFI_SUCCESS;
518 }
519
520 /**
521 Initialization for the Serial Io Protocol.
522
523 @param[in] ImageHandle The firmware allocated handle for the EFI image.
524 @param[in] SystemTable A pointer to the EFI System Table.
525
526 @retval EFI_SUCCESS The entry point is executed successfully.
527 @retval other Some error occurs when executing this entry point.
528
529 **/
530 EFI_STATUS
531 EFIAPI
532 SerialDxeInitialize (
533 IN EFI_HANDLE ImageHandle,
534 IN EFI_SYSTEM_TABLE *SystemTable
535 )
536 {
537 EFI_STATUS Status;
538
539 mSerialIoMode.BaudRate = PcdGet64 (PcdUartDefaultBaudRate);
540 mSerialIoMode.DataBits = (UINT32)PcdGet8 (PcdUartDefaultDataBits);
541 mSerialIoMode.Parity = (UINT32)PcdGet8 (PcdUartDefaultParity);
542 mSerialIoMode.StopBits = (UINT32)PcdGet8 (PcdUartDefaultStopBits);
543 mSerialIoMode.ReceiveFifoDepth = PcdGet16 (PcdUartDefaultReceiveFifoDepth);
544 mSerialDevicePath.Uart.BaudRate = PcdGet64 (PcdUartDefaultBaudRate);
545 mSerialDevicePath.Uart.DataBits = PcdGet8 (PcdUartDefaultDataBits);
546 mSerialDevicePath.Uart.Parity = PcdGet8 (PcdUartDefaultParity);
547 mSerialDevicePath.Uart.StopBits = PcdGet8 (PcdUartDefaultStopBits);
548
549 //
550 // Issue a reset to initialize the Serial Port
551 //
552 Status = mSerialIoTemplate.Reset (&mSerialIoTemplate);
553 if (EFI_ERROR (Status)) {
554 return Status;
555 }
556
557 //
558 // Make a new handle with Serial IO protocol and its device path on it.
559 //
560 Status = gBS->InstallMultipleProtocolInterfaces (
561 &mSerialHandle,
562 &gEfiSerialIoProtocolGuid,
563 &mSerialIoTemplate,
564 &gEfiDevicePathProtocolGuid,
565 &mSerialDevicePath,
566 NULL
567 );
568 ASSERT_EFI_ERROR (Status);
569
570 return Status;
571 }