]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/Library/BhyveFwCtlLib/BhyveFwCtlLib.c
OvmfPkg: Fix BhyveFwCtlLib build with VS2019
[mirror_edk2.git] / OvmfPkg / Library / BhyveFwCtlLib / BhyveFwCtlLib.c
CommitLineData
656419f9
RC
1/** @file\r
2\r
3 Copyright (c) 2020, Rebecca Cran <rebecca@bsdio.com>\r
4 Copyright (c) 2011 - 2013, Intel Corporation. All rights reserved.<BR>\r
5 Copyright (C) 2013, Red Hat, Inc.\r
6 Copyright (c) 2015, Nahanni Systems.\r
7\r
8 SPDX-License-Identifier: BSD-2-Clause-Patent\r
9\r
10**/\r
11\r
12#include "Uefi.h"\r
13#include <Library/BaseLib.h>\r
14#include <Library/BaseMemoryLib.h>\r
15#include <Library/DebugLib.h>\r
16#include <Library/IoLib.h>\r
17#include <Library/BhyveFwCtlLib.h>\r
18#include <Library/MemoryAllocationLib.h>\r
19#include <Library/UefiBootServicesTableLib.h>\r
20\r
21#define FW_PORT 0x510\r
22#define FW_IPORT 0x511\r
23\r
24/* Transport protocol basic operations */\r
25#define OP_NULL 1\r
26#define OP_ECHO 2\r
27#define OP_GET 3\r
28#define OP_GET_LEN 4\r
29#define OP_SET 5\r
30\r
31/* Transport protocol error returns */\r
32#define T_ESUCCESS 0\r
33#define T_ENOENT 2\r
34#define T_E2BIG 7\r
35#define T_EMSGSIZE 40\r
36\r
37#define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y))\r
38\r
39STATIC CONST CHAR8 mBhyveSig[4] = { 'B', 'H', 'Y', 'V' };\r
40\r
41STATIC BOOLEAN mBhyveFwCtlSupported = FALSE;\r
42\r
66692335 43STATIC INT32 mBhyveFwCtlTxid = 0xa5;\r
656419f9
RC
44\r
45/* XXX Maybe a better inbuilt version of this ? */\r
46struct BIoVec {\r
47 VOID *Base;\r
66692335 48 UINT32 Len;\r
656419f9
RC
49};\r
50\r
51struct MsgRxHdr {\r
52 UINT32 Sz;\r
53 UINT32 Op;\r
54 UINT32 TxId;\r
55 UINT32 Err;\r
56};\r
57\r
58STATIC\r
59RETURN_STATUS\r
60EFIAPI\r
61BhyveFwCtl_CvtErr (\r
62 IN UINT32 errno\r
63 )\r
64{\r
65 RETURN_STATUS Status;\r
66\r
67 switch (errno) {\r
68 case T_ESUCCESS:\r
69 Status = RETURN_SUCCESS;\r
70 break;\r
71 case T_ENOENT:\r
72 Status = RETURN_NOT_FOUND;\r
73 break;\r
74 case T_E2BIG:\r
75 Status = RETURN_INVALID_PARAMETER;\r
76 break;\r
77 case T_EMSGSIZE:\r
78 Status = RETURN_BUFFER_TOO_SMALL;\r
79 break;\r
80 default:\r
81 Status = RETURN_PROTOCOL_ERROR;\r
82 break;\r
83 }\r
84\r
85 return Status;\r
86}\r
87\r
88STATIC\r
66692335 89UINT32\r
656419f9
RC
90EFIAPI\r
91BIov_WLen (\r
92 IN struct BIoVec b[]\r
93 )\r
94{\r
66692335
RC
95 UINT32 i;\r
96 UINT32 tLen;\r
656419f9
RC
97\r
98 tLen = 0;\r
99\r
100 if (b != NULL) {\r
101 for (i = 0; b[i].Base != NULL; i++)\r
102 tLen += ROUNDUP (b[i].Len, sizeof(UINT32));\r
103 }\r
104\r
105 return tLen;\r
106}\r
107\r
108/**\r
66692335 109 Utility to send 1-3 bytes of input as a 4-byte value\r
656419f9
RC
110 with trailing zeroes.\r
111 **/\r
112STATIC\r
113UINT32\r
114BIov_Send_Rem (\r
115 IN UINT32 *Data,\r
66692335 116 IN UINT32 Len\r
656419f9
RC
117 )\r
118{\r
119 union {\r
120 UINT8 c[4];\r
121 UINT32 w;\r
122 } u;\r
123 UINT8 *cdata;\r
66692335 124 UINT32 i;\r
656419f9
RC
125\r
126 cdata = (UINT8 *)Data;\r
127 u.w = 0;\r
128\r
129 for (i = 0; i < Len; i++)\r
130 u.c[i] = *cdata++;\r
131\r
132 return u.w;\r
133}\r
134\r
135/**\r
136 Send a block of data out the i/o port as 4-byte quantities,\r
137 appending trailing zeroes on the last if required.\r
138 **/\r
139STATIC\r
140VOID\r
141BIov_Send (\r
142 IN char *Data,\r
66692335 143 IN UINT32 Len\r
656419f9
RC
144 )\r
145{\r
146 UINT32 *LData;\r
147\r
148 LData = (UINT32 *)Data;\r
149\r
150 while (Len > sizeof(UINT32)) {\r
151 IoWrite32 (FW_PORT, *LData++);\r
152 Len -= sizeof(UINT32);\r
153 }\r
154\r
155 if (Len > 0) {\r
156 IoWrite32 (FW_PORT, BIov_Send_Rem (LData, Len));\r
157 }\r
158}\r
159\r
160/**\r
161 Send data described by an array of iovecs out the i/o port.\r
162 **/\r
163STATIC\r
164VOID\r
165BIov_SendAll (\r
166 IN struct BIoVec b[]\r
167 )\r
168{\r
66692335 169 INT32 i;\r
656419f9
RC
170\r
171 if (b != NULL) {\r
172 for (i = 0; b[i].Base; i++) {\r
173 BIov_Send (b[i].Base, b[i].Len);\r
174 }\r
175 }\r
176}\r
177\r
178/**\r
179 Prepend the transport header to a block of data and send.\r
180 **/\r
181STATIC\r
182VOID\r
183EFIAPI\r
184BhyveFwCtl_MsgSend(\r
66692335 185 IN UINT32 OpCode,\r
656419f9
RC
186 IN struct BIoVec Data[]\r
187 )\r
188{\r
189 struct BIoVec hIov[4];\r
190 UINT32 Hdr[3];\r
66692335 191 UINT32 i;\r
656419f9
RC
192\r
193 /* Set up header as an iovec */\r
194 for (i = 0; i < 3; i++) {\r
195 hIov[i].Base = &Hdr[i];\r
196 hIov[i].Len = sizeof(Hdr[0]);\r
197 }\r
198 hIov[i].Base = NULL;\r
199 hIov[i].Len = 0;\r
200\r
201 /* Initialize header */\r
202 Hdr[0] = BIov_WLen (hIov) + BIov_WLen (Data);\r
66692335 203 Hdr[1] = (UINT32)OpCode;\r
656419f9
RC
204 Hdr[2] = mBhyveFwCtlTxid;\r
205\r
206 /* Send header and data */\r
207 BIov_SendAll (hIov);\r
208 BIov_SendAll (Data);\r
209}\r
210\r
211/**\r
212 Read a transport response and optional data from the i/o port.\r
213 **/\r
214STATIC\r
215RETURN_STATUS\r
216EFIAPI\r
217BhyveFwCtl_MsgRecv(\r
218 OUT struct MsgRxHdr *Rhdr,\r
219 OUT struct BIoVec Data[]\r
220 )\r
221{\r
222 RETURN_STATUS Status;\r
223 UINT32 *Dp;\r
224 UINT32 Rd;\r
66692335
RC
225 UINT32 remLen;\r
226 INT32 oLen, xLen;\r
656419f9
RC
227\r
228 Rd = IoRead32 (FW_PORT);\r
229 if (Rd < sizeof(struct MsgRxHdr)) {\r
230 ;\r
231 }\r
232\r
233 /* Read in header and setup initial error */\r
234 Rhdr->Sz = Rd;\r
235 Rhdr->Op = IoRead32 (FW_PORT);\r
236 Rhdr->TxId = IoRead32 (FW_PORT);\r
237 Rhdr->Err = IoRead32 (FW_PORT);\r
238\r
239 /* Convert transport errno into UEFI error status */\r
240 Status = BhyveFwCtl_CvtErr(Rhdr->Err);\r
241\r
242 remLen = Rd - sizeof(struct MsgRxHdr);\r
243 xLen = 0;\r
244\r
245 /*\r
246 * A few cases to handle:\r
247 * - the user didn't supply a read buffer\r
248 * - the buffer is too small for the response\r
249 * - the response is zero-length\r
250 */\r
251 if (Data != NULL) {\r
252 Dp = (UINT32 *)Data[0].Base;\r
253 oLen = remLen;\r
254 if (remLen > Data[0].Len) {\r
255 Status = RETURN_BUFFER_TOO_SMALL;\r
256 xLen = remLen - Data[0].Len;\r
257 oLen = remLen = Data[0].Len;\r
258 }\r
259 while (remLen > 0) {\r
260 *Dp++ = IoRead32 (FW_PORT);\r
261 remLen -= sizeof(UINT32);\r
262 }\r
263 Data[0].Len = oLen;\r
264 } else {\r
265 /* No user data, but data returned - drop */\r
266 if (remLen > 0) {\r
267 Status = RETURN_BUFFER_TOO_SMALL;\r
268 xLen = remLen;\r
269 }\r
270 }\r
271\r
272 /* Drop additional data */\r
273 while (xLen > 0) {\r
274 (void) IoRead32 (FW_PORT);\r
275 xLen -= sizeof(UINT32);\r
276 }\r
277\r
278 return Status;\r
279}\r
280\r
281\r
282STATIC\r
283RETURN_STATUS\r
284EFIAPI\r
285BhyveFwCtl_Msg(\r
66692335 286 IN UINT32 OpCode,\r
656419f9
RC
287 IN struct BIoVec Sdata[],\r
288 OUT struct BIoVec Rdata[]\r
289 )\r
290{\r
291 struct MsgRxHdr Rh;\r
292 RETURN_STATUS Status;\r
293\r
294 Status = RETURN_SUCCESS;\r
295\r
296 BhyveFwCtl_MsgSend (OpCode, Sdata);\r
297 Status = BhyveFwCtl_MsgRecv (&Rh, Rdata);\r
298\r
299 mBhyveFwCtlTxid++;\r
300\r
301 return Status;\r
302}\r
303\r
304STATIC\r
305RETURN_STATUS\r
306EFIAPI\r
307BhyveFwCtlGetLen (\r
308 IN CONST CHAR8 *Name,\r
66692335 309 IN OUT UINT32 *Size\r
656419f9
RC
310 )\r
311{\r
312 struct BIoVec Req[2], Resp[2];\r
313 RETURN_STATUS Status;\r
314\r
315 Req[0].Base = (VOID *)Name;\r
66692335 316 Req[0].Len = (UINT32)AsciiStrLen (Name) + 1;\r
656419f9
RC
317 Req[1].Base = NULL;\r
318\r
319 Resp[0].Base = Size;\r
66692335 320 Resp[0].Len = sizeof(UINT32);\r
656419f9
RC
321 Resp[1].Base = NULL;\r
322\r
323 Status = BhyveFwCtl_Msg (OP_GET_LEN, Req, Resp);\r
324\r
325 return Status;\r
326}\r
327\r
328#define FMAXSZ 1024\r
329STATIC struct {\r
330 UINT64 fSize;\r
331 UINT32 fData[FMAXSZ];\r
332} FwGetvalBuf;\r
333\r
334STATIC\r
335RETURN_STATUS\r
336EFIAPI\r
337BhyveFwCtlGetVal (\r
338 IN CONST CHAR8 *Name,\r
339 OUT VOID *Item,\r
66692335 340 IN OUT UINT32 *Size\r
656419f9
RC
341 )\r
342{\r
343 struct BIoVec Req[2], Resp[2];\r
344 RETURN_STATUS Status;\r
345\r
346 /* Make sure temp buffer is larger than passed-in size */\r
347 if (*Size > sizeof(FwGetvalBuf.fData))\r
348 return RETURN_INVALID_PARAMETER;\r
349\r
350 Req[0].Base = (VOID *)Name;\r
66692335 351 Req[0].Len = (UINT32)AsciiStrLen(Name) + 1;\r
656419f9
RC
352 Req[1].Base = NULL;\r
353\r
354 Resp[0].Base = &FwGetvalBuf;\r
355 Resp[0].Len = sizeof(UINT64) + *Size;\r
356 Resp[1].Base = NULL;\r
357\r
358 Status = BhyveFwCtl_Msg (OP_GET, Req, Resp);\r
359\r
360 /*\r
361 * Copy out data on success (or on a truncated message).\r
362 * XXX This step can be eliminted with Msg() supporting\r
363 * multiple iovecs.\r
364 */\r
365 if ((Status == RETURN_SUCCESS) || (Status == RETURN_BUFFER_TOO_SMALL)) {\r
66692335 366 *Size = (UINT32)FwGetvalBuf.fSize;\r
656419f9
RC
367 CopyMem (Item, FwGetvalBuf.fData, *Size);\r
368 }\r
369\r
370 return Status;\r
371}\r
372\r
373/**\r
374 Front end to the internal GET_LEN and GET protocols\r
375 **/\r
376RETURN_STATUS\r
377EFIAPI\r
378BhyveFwCtlGet (\r
379 IN CONST CHAR8 *Name,\r
380 OUT VOID *Item,\r
381 IN OUT UINTN *Size\r
382 )\r
383{\r
384 RETURN_STATUS Status;\r
385\r
386 if (mBhyveFwCtlSupported == FALSE)\r
387 return RETURN_UNSUPPORTED;\r
388\r
389 if (Item == NULL) {\r
66692335 390 Status = BhyveFwCtlGetLen (Name, (UINT32*)Size);\r
656419f9 391 } else {\r
66692335 392 Status = BhyveFwCtlGetVal (Name, Item, (UINT32*)Size);\r
656419f9
RC
393 }\r
394\r
395 return Status;\r
396}\r
397\r
398\r
399/**\r
400 Library initialization. Probe the host to see if the f/w ctl\r
401 interface is supported.\r
402 **/\r
403RETURN_STATUS\r
404EFIAPI\r
405BhyveFwCtlInitialize (\r
406 VOID\r
407 )\r
408{\r
66692335 409 UINT32 i;\r
656419f9
RC
410 UINT8 ch;\r
411\r
412 DEBUG ((DEBUG_INFO, "FwCtlInitialize\n"));\r
413\r
414 IoWrite16 (FW_PORT, 0x0000);\r
415 for (i = 0; i < 4; i++) {\r
416 ch = IoRead8 (FW_IPORT);\r
417 if (ch != mBhyveSig[i]) {\r
418 DEBUG ((DEBUG_INFO, "Host f/w sig mismatch %c/%c\n", ch, mBhyveSig[i]));\r
419 return RETURN_SUCCESS;\r
420 }\r
421 }\r
422\r
423 mBhyveFwCtlSupported = TRUE;\r
424\r
425 return RETURN_SUCCESS;\r
426}\r