VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/OvmfPkg/VirtioSerialDxe/VirtioSerialPort.c@ 105681

最後變更 在這個檔案從105681是 101291,由 vboxsync 提交於 18 月 前

EFI/FirmwareNew: Make edk2-stable202308 build on all supported platforms (using gcc at least, msvc not tested yet), bugref:4643

  • 屬性 svn:eol-style 設為 native
檔案大小: 10.9 KB
 
1/** @file
2
3 Driver for virtio-serial devices.
4
5 Helper functions to manage virtio serial ports.
6 Console ports will be registered as SerialIo UARTs.
7
8 SPDX-License-Identifier: BSD-2-Clause-Patent
9
10**/
11
12#include <Library/BaseMemoryLib.h>
13#include <Library/DebugLib.h>
14#include <Library/DevicePathLib.h>
15#include <Library/MemoryAllocationLib.h>
16#include <Library/PrintLib.h>
17#include <Library/UefiBootServicesTableLib.h>
18#include <Library/UefiLib.h>
19#include <Library/VirtioLib.h>
20
21#include "VirtioSerial.h"
22
23ACPI_HID_DEVICE_PATH mAcpiSerialDevNode = {
24 {
25 ACPI_DEVICE_PATH,
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 {
38 MESSAGING_DEVICE_PATH,
39 MSG_UART_DP,
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
50STATIC
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
65STATIC
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
80STATIC
81EFI_STATUS
82EFIAPI
83VirtioSerialIoReset (
84 IN EFI_SERIAL_IO_PROTOCOL *This
85 )
86{
87 DEBUG ((DEBUG_VERBOSE, "%a:%d:\n", __func__, __LINE__));
88 return EFI_SUCCESS;
89}
90
91STATIC
92EFI_STATUS
93EFIAPI
94VirtioSerialIoSetAttributes (
95 IN EFI_SERIAL_IO_PROTOCOL *This,
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
117EFI_STATUS
118EFIAPI
119VirtioSerialIoSetControl (
120 IN EFI_SERIAL_IO_PROTOCOL *This,
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
129EFI_STATUS
130EFIAPI
131VirtioSerialIoGetControl (
132 IN EFI_SERIAL_IO_PROTOCOL *This,
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
141EFI_STATUS
142EFIAPI
143VirtioSerialIoWrite (
144 IN EFI_SERIAL_IO_PROTOCOL *This,
145 IN OUT UINTN *BufferSize,
146 IN VOID *Buffer
147 )
148{
149 VIRTIO_SERIAL_IO_PROTOCOL *SerialIo = (VIRTIO_SERIAL_IO_PROTOCOL *)This;
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
186EFI_STATUS
187EFIAPI
188VirtioSerialIoRead (
189 IN EFI_SERIAL_IO_PROTOCOL *This,
190 IN OUT UINTN *BufferSize,
191 OUT VOID *Buffer
192 )
193{
194 VIRTIO_SERIAL_IO_PROTOCOL *SerialIo = (VIRTIO_SERIAL_IO_PROTOCOL *)This;
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
251EFI_STATUS
252EFIAPI
253VirtioSerialIoInit (
254 IN OUT VIRTIO_SERIAL_DEV *Dev,
255 IN UINT32 PortId
256 )
257{
258 VIRTIO_SERIAL_PORT *Port = Dev->Ports + PortId;
259 VIRTIO_SERIAL_IO_PROTOCOL *SerialIo;
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 (
337 VIRTIO_SERIAL_IO_PROTOCOL *SerialIo
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
365EFI_STATUS
366EFIAPI
367VirtioSerialPortAdd (
368 IN OUT VIRTIO_SERIAL_DEV *Dev,
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 (
403 IN OUT VIRTIO_SERIAL_DEV *Dev,
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 (
417 IN OUT VIRTIO_SERIAL_DEV *Dev,
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 (
431 IN OUT VIRTIO_SERIAL_DEV *Dev,
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 (
447 IN OUT VIRTIO_SERIAL_DEV *Dev,
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}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette