]>
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 | |
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 | |
39 | STATIC CONST CHAR8 mBhyveSig[4] = { 'B', 'H', 'Y', 'V' };\r | |
40 | \r | |
41 | STATIC BOOLEAN mBhyveFwCtlSupported = FALSE;\r | |
42 | \r | |
66692335 | 43 | STATIC INT32 mBhyveFwCtlTxid = 0xa5;\r |
656419f9 RC |
44 | \r |
45 | /* XXX Maybe a better inbuilt version of this ? */\r | |
46 | struct BIoVec {\r | |
47 | VOID *Base;\r | |
66692335 | 48 | UINT32 Len;\r |
656419f9 RC |
49 | };\r |
50 | \r | |
51 | struct MsgRxHdr {\r | |
52 | UINT32 Sz;\r | |
53 | UINT32 Op;\r | |
54 | UINT32 TxId;\r | |
55 | UINT32 Err;\r | |
56 | };\r | |
57 | \r | |
58 | STATIC\r | |
59 | RETURN_STATUS\r | |
60 | EFIAPI\r | |
61 | BhyveFwCtl_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 | |
88 | STATIC\r | |
66692335 | 89 | UINT32\r |
656419f9 RC |
90 | EFIAPI\r |
91 | BIov_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 | |
112 | STATIC\r | |
113 | UINT32\r | |
114 | BIov_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 | |
139 | STATIC\r | |
140 | VOID\r | |
141 | BIov_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 | |
163 | STATIC\r | |
164 | VOID\r | |
165 | BIov_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 | |
181 | STATIC\r | |
182 | VOID\r | |
183 | EFIAPI\r | |
184 | BhyveFwCtl_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 | |
214 | STATIC\r | |
215 | RETURN_STATUS\r | |
216 | EFIAPI\r | |
217 | BhyveFwCtl_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 | |
282 | STATIC\r | |
283 | RETURN_STATUS\r | |
284 | EFIAPI\r | |
285 | BhyveFwCtl_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 | |
304 | STATIC\r | |
305 | RETURN_STATUS\r | |
306 | EFIAPI\r | |
307 | BhyveFwCtlGetLen (\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 | |
329 | STATIC struct {\r | |
330 | UINT64 fSize;\r | |
331 | UINT32 fData[FMAXSZ];\r | |
332 | } FwGetvalBuf;\r | |
333 | \r | |
334 | STATIC\r | |
335 | RETURN_STATUS\r | |
336 | EFIAPI\r | |
337 | BhyveFwCtlGetVal (\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 | |
376 | RETURN_STATUS\r | |
377 | EFIAPI\r | |
378 | BhyveFwCtlGet (\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 | |
403 | RETURN_STATUS\r | |
404 | EFIAPI\r | |
405 | BhyveFwCtlInitialize (\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 |