]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Library/XenConsoleSerialPortLib/XenConsoleSerialPortLib.c
OvmfPkg: replace strict XenHypercallLib construction with explicit query
[mirror_edk2.git] / OvmfPkg / Library / XenConsoleSerialPortLib / XenConsoleSerialPortLib.c
1 /** @file
2 Xen console SerialPortLib instance
3
4 Copyright (c) 2015, Linaro Ltd. All rights reserved.<BR>
5
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include <Base.h>
17 #include <Uefi/UefiBaseType.h>
18
19 #include <Library/BaseLib.h>
20 #include <Library/SerialPortLib.h>
21 #include <Library/XenHypercallLib.h>
22
23 #include <IndustryStandard/Xen/io/console.h>
24 #include <IndustryStandard/Xen/hvm/params.h>
25 #include <IndustryStandard/Xen/event_channel.h>
26
27 //
28 // The code below expects these global variables to be mutable, even in the case
29 // that we have been incorporated into SEC or PEIM phase modules (which is
30 // allowed by our INF description). While this is a dangerous assumption to make
31 // in general, it is actually fine for the Xen domU (guest) environment that
32 // this module is intended for, as UEFI always executes from DRAM in that case.
33 //
34 STATIC evtchn_send_t mXenConsoleEventChain;
35 STATIC struct xencons_interface *mXenConsoleInterface;
36
37 RETURN_STATUS
38 EFIAPI
39 SerialPortInitialize (
40 VOID
41 )
42 {
43 if (! XenHypercallIsAvailable ()) {
44 return RETURN_NOT_FOUND;
45 }
46
47 if (!mXenConsoleInterface) {
48 mXenConsoleEventChain.port = (UINT32)XenHypercallHvmGetParam (HVM_PARAM_CONSOLE_EVTCHN);
49 mXenConsoleInterface = (struct xencons_interface *)(UINTN)
50 (XenHypercallHvmGetParam (HVM_PARAM_CONSOLE_PFN) << EFI_PAGE_SHIFT);
51
52 //
53 // No point in ASSERT'ing here as we won't be seeing the output
54 //
55 }
56 return RETURN_SUCCESS;
57 }
58
59 /**
60 Write data to serial device.
61
62 @param Buffer Point of data buffer which need to be written.
63 @param NumberOfBytes Number of output bytes which are cached in Buffer.
64
65 @retval 0 Write data failed.
66 @retval !0 Actual number of bytes written to serial device.
67
68 **/
69 UINTN
70 EFIAPI
71 SerialPortWrite (
72 IN UINT8 *Buffer,
73 IN UINTN NumberOfBytes
74 )
75 {
76 XENCONS_RING_IDX Consumer, Producer;
77 UINTN Sent;
78
79 if (!mXenConsoleInterface) {
80 return 0;
81 }
82
83 Consumer = mXenConsoleInterface->out_cons;
84 Producer = mXenConsoleInterface->out_prod;
85
86 MemoryFence ();
87
88 Sent = 0;
89 while (Sent < NumberOfBytes && ((Producer - Consumer) < sizeof (mXenConsoleInterface->out)))
90 mXenConsoleInterface->out[MASK_XENCONS_IDX(Producer++, mXenConsoleInterface->out)] = Buffer[Sent++];
91
92 MemoryFence ();
93
94 mXenConsoleInterface->out_prod = Producer;
95
96 if (Sent > 0) {
97 XenHypercallEventChannelOp (EVTCHNOP_send, &mXenConsoleEventChain);
98 }
99
100 return Sent;
101 }
102
103 /**
104 Read data from serial device and save the data in buffer.
105
106 @param Buffer Point of data buffer which need to be written.
107 @param NumberOfBytes Size of Buffer[].
108
109 @retval 0 Read data failed.
110 @retval !0 Actual number of bytes read from serial device.
111
112 **/
113 UINTN
114 EFIAPI
115 SerialPortRead (
116 OUT UINT8 *Buffer,
117 IN UINTN NumberOfBytes
118 )
119 {
120 XENCONS_RING_IDX Consumer, Producer;
121 UINTN Received;
122
123 if (!mXenConsoleInterface) {
124 return 0;
125 }
126
127 Consumer = mXenConsoleInterface->in_cons;
128 Producer = mXenConsoleInterface->in_prod;
129
130 MemoryFence ();
131
132 Received = 0;
133 while (Received < NumberOfBytes && Consumer < Producer)
134 Buffer[Received++] = mXenConsoleInterface->in[MASK_XENCONS_IDX(Consumer++, mXenConsoleInterface->in)];
135
136 MemoryFence ();
137
138 mXenConsoleInterface->in_cons = Consumer;
139
140 XenHypercallEventChannelOp (EVTCHNOP_send, &mXenConsoleEventChain);
141
142 return Received;
143 }
144
145 /**
146 Check to see if any data is available to be read from the debug device.
147
148 @retval TRUE At least one byte of data is available to be read
149 @retval FALSE No data is available to be read
150
151 **/
152 BOOLEAN
153 EFIAPI
154 SerialPortPoll (
155 VOID
156 )
157 {
158 return mXenConsoleInterface &&
159 mXenConsoleInterface->in_cons != mXenConsoleInterface->in_prod;
160 }