]>
Commit | Line | Data |
---|---|---|
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 | 39 | STATIC CONST CHAR8 mBhyveSig[4] = { 'B', 'H', 'Y', 'V' };\r |
656419f9 | 40 | \r |
ac0a286f | 41 | STATIC BOOLEAN mBhyveFwCtlSupported = FALSE;\r |
656419f9 | 42 | \r |
ac0a286f | 43 | STATIC INT32 mBhyveFwCtlTxid = 0xa5;\r |
656419f9 RC |
44 | \r |
45 | /* XXX Maybe a better inbuilt version of this ? */\r | |
f2d262e4 | 46 | typedef struct {\r |
ac0a286f | 47 | VOID *Base;\r |
f2d262e4 RC |
48 | UINT32 Len;\r |
49 | } BIO_VEC;\r | |
656419f9 | 50 | \r |
f2d262e4 | 51 | typedef 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 |
58 | STATIC\r | |
59 | RETURN_STATUS\r | |
60 | EFIAPI\r | |
61 | BhyveFwCtl_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 | |
88 | STATIC\r | |
66692335 | 89 | UINT32\r |
656419f9 RC |
90 | EFIAPI\r |
91 | BIov_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 | |
113 | STATIC\r | |
114 | UINT32\r | |
115 | BIov_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 | |
141 | STATIC\r | |
142 | VOID\r | |
143 | BIov_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 | |
165 | STATIC\r | |
166 | VOID\r | |
167 | BIov_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 | |
183 | STATIC\r | |
184 | VOID\r | |
185 | EFIAPI\r | |
ac0a286f MK |
186 | BhyveFwCtl_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 | |
217 | STATIC\r | |
218 | RETURN_STATUS\r | |
219 | EFIAPI\r | |
ac0a286f MK |
220 | BhyveFwCtl_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 |
286 | STATIC\r |
287 | RETURN_STATUS\r | |
288 | EFIAPI\r | |
ac0a286f MK |
289 | BhyveFwCtl_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 | |
308 | STATIC\r | |
309 | RETURN_STATUS\r | |
310 | EFIAPI\r | |
311 | BhyveFwCtlGetLen (\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 |
333 | STATIC struct {\r |
334 | UINT64 fSize;\r | |
335 | UINT32 fData[FMAXSZ];\r | |
336 | } FwGetvalBuf;\r | |
337 | \r | |
338 | STATIC\r | |
339 | RETURN_STATUS\r | |
340 | EFIAPI\r | |
341 | BhyveFwCtlGetVal (\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 | |
382 | RETURN_STATUS\r | |
383 | EFIAPI\r | |
384 | BhyveFwCtlGet (\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 | |
409 | RETURN_STATUS\r | |
410 | EFIAPI\r | |
411 | BhyveFwCtlInitialize (\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 |