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