TianoCore EDK2 master
Loading...
Searching...
No Matches
VirtioSerialPort.c
Go to the documentation of this file.
1
13#include <Library/DebugLib.h>
16#include <Library/PrintLib.h>
18#include <Library/UefiLib.h>
19#include <Library/VirtioLib.h>
20
21#include "VirtioSerial.h"
22
23ACPI_HID_DEVICE_PATH mAcpiSerialDevNode = {
24 {
26 ACPI_DP,
27 {
28 (UINT8)(sizeof (ACPI_HID_DEVICE_PATH)),
29 (UINT8)((sizeof (ACPI_HID_DEVICE_PATH)) >> 8)
30 },
31 },
32 EISA_PNP_ID (0x0501),
33 0
34};
35
36UART_DEVICE_PATH mUartDevNode = {
37 {
40 {
41 (UINT8)(sizeof (UART_DEVICE_PATH)),
42 (UINT8)((sizeof (UART_DEVICE_PATH)) >> 8)
43 }
44 },
45 0, // Reserved
46 115200, // Speed
47 8, 1, 1 // 8n1
48};
49
51UINT16
52PortRx (
53 IN UINT32 PortId
54 )
55{
56 ASSERT (PortId < MAX_PORTS);
57
58 if (PortId >= 1) {
59 return (UINT16)(VIRTIO_SERIAL_Q_RX_BASE + (PortId - 1) * 2);
60 }
61
62 return VIRTIO_SERIAL_Q_RX_PORT0;
63}
64
66UINT16
67PortTx (
68 IN UINT32 PortId
69 )
70{
71 ASSERT (PortId < MAX_PORTS);
72
73 if (PortId >= 1) {
74 return (UINT16)(VIRTIO_SERIAL_Q_TX_BASE + (PortId - 1) * 2);
75 }
76
77 return VIRTIO_SERIAL_Q_TX_PORT0;
78}
79
82EFIAPI
83VirtioSerialIoReset (
85 )
86{
87 DEBUG ((DEBUG_VERBOSE, "%a:%d:\n", __func__, __LINE__));
88 return EFI_SUCCESS;
89}
90
93EFIAPI
94VirtioSerialIoSetAttributes (
96 IN UINT64 BaudRate,
97 IN UINT32 ReceiveFifoDepth,
98 IN UINT32 Timeout,
99 IN EFI_PARITY_TYPE Parity,
100 IN UINT8 DataBits,
101 IN EFI_STOP_BITS_TYPE StopBits
102 )
103{
104 DEBUG ((
105 DEBUG_VERBOSE,
106 "%a:%d: Rate %ld, Fifo %d, Bits %d\n",
107 __func__,
108 __LINE__,
109 BaudRate,
110 ReceiveFifoDepth,
111 DataBits
112 ));
113 return EFI_SUCCESS;
114}
115
116STATIC
118EFIAPI
119VirtioSerialIoSetControl (
121 IN UINT32 Control
122 )
123{
124 DEBUG ((DEBUG_INFO, "%a:%d: Control 0x%x\n", __func__, __LINE__, Control));
125 return EFI_SUCCESS;
126}
127
128STATIC
130EFIAPI
131VirtioSerialIoGetControl (
133 OUT UINT32 *Control
134 )
135{
136 DEBUG ((DEBUG_VERBOSE, "%a:%d: Control 0x%x\n", __func__, __LINE__, *Control));
137 return EFI_SUCCESS;
138}
139
140STATIC
142EFIAPI
143VirtioSerialIoWrite (
145 IN OUT UINTN *BufferSize,
146 IN VOID *Buffer
147 )
148{
150 VIRTIO_SERIAL_PORT *Port = SerialIo->Dev->Ports + SerialIo->PortId;
151 UINT32 Length;
152 EFI_TPL OldTpl;
153
154 if (!Port->DeviceOpen) {
155 *BufferSize = 0;
156 return EFI_SUCCESS;
157 }
158
159 VirtioSerialRingClearTx (SerialIo->Dev, PortTx (SerialIo->PortId));
160
161 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
162 if (SerialIo->WriteOffset &&
163 (SerialIo->WriteOffset + *BufferSize > PORT_TX_BUFSIZE))
164 {
165 DEBUG ((DEBUG_VERBOSE, "%a:%d: WriteFlush %d\n", __func__, __LINE__, SerialIo->WriteOffset));
166 VirtioSerialRingSendBuffer (
167 SerialIo->Dev,
168 PortTx (SerialIo->PortId),
169 SerialIo->WriteBuffer,
170 SerialIo->WriteOffset,
171 TRUE
172 );
173 SerialIo->WriteOffset = 0;
174 }
175
176 Length = MIN ((UINT32)(*BufferSize), PORT_TX_BUFSIZE - SerialIo->WriteOffset);
177 CopyMem (SerialIo->WriteBuffer + SerialIo->WriteOffset, Buffer, Length);
178 SerialIo->WriteOffset += Length;
179 *BufferSize = Length;
180 gBS->RestoreTPL (OldTpl);
181
182 return EFI_SUCCESS;
183}
184
185STATIC
187EFIAPI
188VirtioSerialIoRead (
190 IN OUT UINTN *BufferSize,
191 OUT VOID *Buffer
192 )
193{
195 VIRTIO_SERIAL_PORT *Port = SerialIo->Dev->Ports + SerialIo->PortId;
196 BOOLEAN HasData;
197 UINT32 Length;
198 EFI_TPL OldTpl;
199
200 if (!Port->DeviceOpen) {
201 goto NoData;
202 }
203
204 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
205 if (SerialIo->WriteOffset) {
206 DEBUG ((DEBUG_VERBOSE, "%a:%d: WriteFlush %d\n", __func__, __LINE__, SerialIo->WriteOffset));
207 VirtioSerialRingSendBuffer (
208 SerialIo->Dev,
209 PortTx (SerialIo->PortId),
210 SerialIo->WriteBuffer,
211 SerialIo->WriteOffset,
212 TRUE
213 );
214 SerialIo->WriteOffset = 0;
215 }
216
217 gBS->RestoreTPL (OldTpl);
218
219 if (SerialIo->ReadOffset == SerialIo->ReadSize) {
220 HasData = VirtioSerialRingGetBuffer (
221 SerialIo->Dev,
222 PortRx (SerialIo->PortId),
223 &SerialIo->ReadBuffer,
224 &SerialIo->ReadSize
225 );
226 if (!HasData) {
227 goto NoData;
228 }
229
230 SerialIo->ReadOffset = 0;
231 }
232
233 if (SerialIo->ReadOffset < SerialIo->ReadSize) {
234 Length = SerialIo->ReadSize - SerialIo->ReadOffset;
235 if (Length > *BufferSize) {
236 Length = (UINT32)(*BufferSize);
237 }
238
239 CopyMem (Buffer, SerialIo->ReadBuffer + SerialIo->ReadOffset, Length);
240 SerialIo->ReadOffset += Length;
241 *BufferSize = Length;
242 return EFI_SUCCESS;
243 }
244
245NoData:
246 *BufferSize = 0;
247 return EFI_SUCCESS;
248}
249
250STATIC
252EFIAPI
253VirtioSerialIoInit (
255 IN UINT32 PortId
256 )
257{
258 VIRTIO_SERIAL_PORT *Port = Dev->Ports + PortId;
260 EFI_STATUS Status;
261
262 SerialIo = (VIRTIO_SERIAL_IO_PROTOCOL *)AllocateZeroPool (sizeof *SerialIo);
263 Port->SerialIo = SerialIo;
264
265 SerialIo->SerialIo.Revision = EFI_SERIAL_IO_PROTOCOL_REVISION;
266 SerialIo->SerialIo.Reset = VirtioSerialIoReset;
267 SerialIo->SerialIo.SetAttributes = VirtioSerialIoSetAttributes;
268 SerialIo->SerialIo.SetControl = VirtioSerialIoSetControl;
269 SerialIo->SerialIo.GetControl = VirtioSerialIoGetControl;
270 SerialIo->SerialIo.Write = VirtioSerialIoWrite;
271 SerialIo->SerialIo.Read = VirtioSerialIoRead;
272 SerialIo->SerialIo.Mode = &SerialIo->SerialIoMode;
273 SerialIo->Dev = Dev;
274 SerialIo->PortId = PortId;
275
276 SerialIo->DevicePath = DuplicateDevicePath (Dev->DevicePath);
277 mAcpiSerialDevNode.UID = PortId;
278 SerialIo->DevicePath = AppendDevicePathNode (
279 SerialIo->DevicePath,
280 (EFI_DEVICE_PATH_PROTOCOL *)&mAcpiSerialDevNode
281 );
282 SerialIo->DevicePath = AppendDevicePathNode (
283 SerialIo->DevicePath,
284 (EFI_DEVICE_PATH_PROTOCOL *)&mUartDevNode
285 );
286
287 LogDevicePath (DEBUG_INFO, __func__, L"UART", SerialIo->DevicePath);
288
289 Status = gBS->InstallMultipleProtocolInterfaces (
290 &SerialIo->DeviceHandle,
291 &gEfiDevicePathProtocolGuid,
292 SerialIo->DevicePath,
293 &gEfiSerialIoProtocolGuid,
294 &SerialIo->SerialIo,
295 NULL
296 );
297 if (EFI_ERROR (Status)) {
298 DEBUG ((DEBUG_INFO, "%a:%d: ERROR: %r\n", __func__, __LINE__, Status));
299 goto FreeSerialIo;
300 }
301
302 Status = gBS->OpenProtocol (
303 Dev->DeviceHandle,
304 &gVirtioDeviceProtocolGuid,
305 (VOID **)&Dev->VirtIo,
306 Dev->DriverBindingHandle,
307 SerialIo->DeviceHandle,
308 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
309 );
310 if (EFI_ERROR (Status)) {
311 DEBUG ((DEBUG_INFO, "%a:%d: ERROR: %r\n", __func__, __LINE__, Status));
312 goto UninstallProtocol;
313 }
314
315 return EFI_SUCCESS;
316
317UninstallProtocol:
318 gBS->UninstallMultipleProtocolInterfaces (
319 SerialIo->DeviceHandle,
320 &gEfiDevicePathProtocolGuid,
321 SerialIo->DevicePath,
322 &gEfiSerialIoProtocolGuid,
323 &SerialIo->SerialIo,
324 NULL
325 );
326
327FreeSerialIo:
328 FreePool (Port->SerialIo);
329 Port->SerialIo = NULL;
330 return Status;
331}
332
333STATIC
334VOID
335EFIAPI
336VirtioSerialIoUninit (
338 )
339{
340 VIRTIO_SERIAL_DEV *Dev = SerialIo->Dev;
341 VIRTIO_SERIAL_PORT *Port = Dev->Ports + SerialIo->PortId;
342
343 DEBUG ((DEBUG_INFO, "%a:%d: %s\n", __func__, __LINE__, Port->Name));
344
345 gBS->CloseProtocol (
346 Dev->DeviceHandle,
347 &gVirtioDeviceProtocolGuid,
348 Dev->DriverBindingHandle,
349 SerialIo->DeviceHandle
350 );
351
352 gBS->UninstallMultipleProtocolInterfaces (
353 SerialIo->DeviceHandle,
354 &gEfiDevicePathProtocolGuid,
355 SerialIo->DevicePath,
356 &gEfiSerialIoProtocolGuid,
357 &SerialIo->SerialIo,
358 NULL
359 );
360
361 FreePool (SerialIo);
362 Port->SerialIo = NULL;
363}
364
366EFIAPI
367VirtioSerialPortAdd (
369 IN UINT32 PortId
370 )
371{
372 VIRTIO_SERIAL_PORT *Port = Dev->Ports + PortId;
373 EFI_STATUS Status;
374
375 if (Port->Ready) {
376 return EFI_SUCCESS;
377 }
378
379 Status = VirtioSerialInitRing (Dev, PortRx (PortId), PORT_RX_BUFSIZE);
380 if (EFI_ERROR (Status)) {
381 goto Failed;
382 }
383
384 Status = VirtioSerialInitRing (Dev, PortTx (PortId), PORT_TX_BUFSIZE);
385 if (EFI_ERROR (Status)) {
386 goto Failed;
387 }
388
389 UnicodeSPrint (Port->Name, sizeof (Port->Name), L"Port #%d", PortId);
390 VirtioSerialRingFillRx (Dev, PortRx (PortId));
391 Port->Ready = TRUE;
392
393 return EFI_SUCCESS;
394
395Failed:
396 VirtioSerialUninitRing (Dev, PortRx (PortId));
397 return Status;
398}
399
400VOID
401EFIAPI
402VirtioSerialPortSetConsole (
404 IN UINT32 PortId
405 )
406{
407 VIRTIO_SERIAL_PORT *Port = Dev->Ports + PortId;
408
409 Port->Console = TRUE;
410 UnicodeSPrint (Port->Name, sizeof (Port->Name), L"Console #%d", PortId);
411 VirtioSerialIoInit (Dev, PortId);
412}
413
414VOID
415EFIAPI
416VirtioSerialPortSetName (
418 IN UINT32 PortId,
419 IN UINT8 *Name
420 )
421{
422 VIRTIO_SERIAL_PORT *Port = Dev->Ports + PortId;
423
424 DEBUG ((DEBUG_INFO, "%a:%d: \"%a\"\n", __func__, __LINE__, Name));
425 UnicodeSPrint (Port->Name, sizeof (Port->Name), L"NamedPort #%d (%a)", PortId, Name);
426}
427
428VOID
429EFIAPI
430VirtioSerialPortSetDeviceOpen (
432 IN UINT32 PortId,
433 IN UINT16 Value
434 )
435{
436 VIRTIO_SERIAL_PORT *Port = Dev->Ports + PortId;
437
438 Port->DeviceOpen = (BOOLEAN)Value;
439 if (Port->DeviceOpen) {
440 VirtioSerialTxControl (Dev, PortId, VIRTIO_SERIAL_PORT_OPEN, 1);
441 }
442}
443
444VOID
445EFIAPI
446VirtioSerialPortRemove (
448 IN UINT32 PortId
449 )
450{
451 VIRTIO_SERIAL_PORT *Port = Dev->Ports + PortId;
452
453 if (!Port->Ready) {
454 return;
455 }
456
457 if (Port->SerialIo) {
458 VirtioSerialIoUninit (Port->SerialIo);
459 Port->SerialIo = NULL;
460 }
461
462 VirtioSerialUninitRing (Dev, PortRx (PortId));
463 VirtioSerialUninitRing (Dev, PortTx (PortId));
464 Port->Ready = FALSE;
465}
UINT64 UINTN
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
#define ACPI_DEVICE_PATH
Definition: DevicePath.h:190
#define ACPI_DP
Definition: DevicePath.h:195
#define MSG_UART_DP
Definition: DevicePath.h:692
#define MESSAGING_DEVICE_PATH
Definition: DevicePath.h:321
EFI_DEVICE_PATH_PROTOCOL *EFIAPI AppendDevicePathNode(IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL, IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePathNode OPTIONAL)
EFI_DEVICE_PATH_PROTOCOL *EFIAPI DuplicateDevicePath(IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath)
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
VOID EFIAPI FreePool(IN VOID *Buffer)
UINTN EFIAPI UnicodeSPrint(OUT CHAR16 *StartOfBuffer, IN UINTN BufferSize, IN CONST CHAR16 *FormatString,...)
Definition: PrintLib.c:408
#define NULL
Definition: Base.h:319
#define STATIC
Definition: Base.h:264
#define MIN(a, b)
Definition: Base.h:1007
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define DEBUG(Expression)
Definition: DebugLib.h:434
EFI_STOP_BITS_TYPE
Definition: SerialIo.h:53
EFI_PARITY_TYPE
Definition: SerialIo.h:41
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
UINTN EFI_TPL
Definition: UefiBaseType.h:41
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_BOOT_SERVICES * gBS
EFI_SERIAL_IO_MODE * Mode
Definition: SerialIo.h:295