3 Copyright (c) 2020, Rebecca Cran <rebecca@bsdio.com>
4 Copyright (c) 2011 - 2013, Intel Corporation. All rights reserved.<BR>
5 Copyright (C) 2013, Red Hat, Inc.
6 Copyright (c) 2015, Nahanni Systems.
8 SPDX-License-Identifier: BSD-2-Clause-Patent
13 #include <Library/BaseLib.h>
14 #include <Library/BaseMemoryLib.h>
15 #include <Library/DebugLib.h>
16 #include <Library/IoLib.h>
17 #include <Library/BhyveFwCtlLib.h>
18 #include <Library/MemoryAllocationLib.h>
19 #include <Library/UefiBootServicesTableLib.h>
22 #define FW_IPORT 0x511
24 /* Transport protocol basic operations */
31 /* Transport protocol error returns */
37 #define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y))
39 STATIC CONST CHAR8 mBhyveSig
[4] = { 'B', 'H', 'Y', 'V' };
41 STATIC BOOLEAN mBhyveFwCtlSupported
= FALSE
;
43 STATIC INT32 mBhyveFwCtlTxid
= 0xa5;
45 /* XXX Maybe a better inbuilt version of this ? */
69 Status
= RETURN_SUCCESS
;
72 Status
= RETURN_NOT_FOUND
;
75 Status
= RETURN_INVALID_PARAMETER
;
78 Status
= RETURN_BUFFER_TOO_SMALL
;
81 Status
= RETURN_PROTOCOL_ERROR
;
101 for (i
= 0; b
[i
].Base
!= NULL
; i
++)
102 tLen
+= ROUNDUP (b
[i
].Len
, sizeof(UINT32
));
109 Utility to send 1-3 bytes of input as a 4-byte value
110 with trailing zeroes.
126 cdata
= (UINT8
*)Data
;
129 for (i
= 0; i
< Len
; i
++)
136 Send a block of data out the i/o port as 4-byte quantities,
137 appending trailing zeroes on the last if required.
148 LData
= (UINT32
*)Data
;
150 while (Len
> sizeof(UINT32
)) {
151 IoWrite32 (FW_PORT
, *LData
++);
152 Len
-= sizeof(UINT32
);
156 IoWrite32 (FW_PORT
, BIov_Send_Rem (LData
, Len
));
161 Send data described by an array of iovecs out the i/o port.
172 for (i
= 0; b
[i
].Base
; i
++) {
173 BIov_Send (b
[i
].Base
, b
[i
].Len
);
179 Prepend the transport header to a block of data and send.
186 IN
struct BIoVec Data
[]
189 struct BIoVec hIov
[4];
193 /* Set up header as an iovec */
194 for (i
= 0; i
< 3; i
++) {
195 hIov
[i
].Base
= &Hdr
[i
];
196 hIov
[i
].Len
= sizeof(Hdr
[0]);
201 /* Initialize header */
202 Hdr
[0] = BIov_WLen (hIov
) + BIov_WLen (Data
);
203 Hdr
[1] = (UINT32
)OpCode
;
204 Hdr
[2] = mBhyveFwCtlTxid
;
206 /* Send header and data */
212 Read a transport response and optional data from the i/o port.
218 OUT
struct MsgRxHdr
*Rhdr
,
219 OUT
struct BIoVec Data
[]
222 RETURN_STATUS Status
;
228 Rd
= IoRead32 (FW_PORT
);
229 if (Rd
< sizeof(struct MsgRxHdr
)) {
233 /* Read in header and setup initial error */
235 Rhdr
->Op
= IoRead32 (FW_PORT
);
236 Rhdr
->TxId
= IoRead32 (FW_PORT
);
237 Rhdr
->Err
= IoRead32 (FW_PORT
);
239 /* Convert transport errno into UEFI error status */
240 Status
= BhyveFwCtl_CvtErr(Rhdr
->Err
);
242 remLen
= Rd
- sizeof(struct MsgRxHdr
);
246 * A few cases to handle:
247 * - the user didn't supply a read buffer
248 * - the buffer is too small for the response
249 * - the response is zero-length
252 Dp
= (UINT32
*)Data
[0].Base
;
254 if (remLen
> Data
[0].Len
) {
255 Status
= RETURN_BUFFER_TOO_SMALL
;
256 xLen
= remLen
- Data
[0].Len
;
257 oLen
= remLen
= Data
[0].Len
;
260 *Dp
++ = IoRead32 (FW_PORT
);
261 remLen
-= sizeof(UINT32
);
265 /* No user data, but data returned - drop */
267 Status
= RETURN_BUFFER_TOO_SMALL
;
272 /* Drop additional data */
274 (void) IoRead32 (FW_PORT
);
275 xLen
-= sizeof(UINT32
);
287 IN
struct BIoVec Sdata
[],
288 OUT
struct BIoVec Rdata
[]
292 RETURN_STATUS Status
;
294 Status
= RETURN_SUCCESS
;
296 BhyveFwCtl_MsgSend (OpCode
, Sdata
);
297 Status
= BhyveFwCtl_MsgRecv (&Rh
, Rdata
);
308 IN CONST CHAR8
*Name
,
312 struct BIoVec Req
[2], Resp
[2];
313 RETURN_STATUS Status
;
315 Req
[0].Base
= (VOID
*)Name
;
316 Req
[0].Len
= (UINT32
)AsciiStrLen (Name
) + 1;
320 Resp
[0].Len
= sizeof(UINT32
);
323 Status
= BhyveFwCtl_Msg (OP_GET_LEN
, Req
, Resp
);
331 UINT32 fData
[FMAXSZ
];
338 IN CONST CHAR8
*Name
,
343 struct BIoVec Req
[2], Resp
[2];
344 RETURN_STATUS Status
;
346 /* Make sure temp buffer is larger than passed-in size */
347 if (*Size
> sizeof(FwGetvalBuf
.fData
))
348 return RETURN_INVALID_PARAMETER
;
350 Req
[0].Base
= (VOID
*)Name
;
351 Req
[0].Len
= (UINT32
)AsciiStrLen(Name
) + 1;
354 Resp
[0].Base
= &FwGetvalBuf
;
355 Resp
[0].Len
= sizeof(UINT64
) + *Size
;
358 Status
= BhyveFwCtl_Msg (OP_GET
, Req
, Resp
);
361 * Copy out data on success (or on a truncated message).
362 * XXX This step can be eliminted with Msg() supporting
365 if ((Status
== RETURN_SUCCESS
) || (Status
== RETURN_BUFFER_TOO_SMALL
)) {
366 *Size
= (UINT32
)FwGetvalBuf
.fSize
;
367 CopyMem (Item
, FwGetvalBuf
.fData
, *Size
);
374 Front end to the internal GET_LEN and GET protocols
379 IN CONST CHAR8
*Name
,
384 RETURN_STATUS Status
;
386 if (mBhyveFwCtlSupported
== FALSE
)
387 return RETURN_UNSUPPORTED
;
390 Status
= BhyveFwCtlGetLen (Name
, (UINT32
*)Size
);
392 Status
= BhyveFwCtlGetVal (Name
, Item
, (UINT32
*)Size
);
400 Library initialization. Probe the host to see if the f/w ctl
401 interface is supported.
405 BhyveFwCtlInitialize (
412 DEBUG ((DEBUG_INFO
, "FwCtlInitialize\n"));
414 IoWrite16 (FW_PORT
, 0x0000);
415 for (i
= 0; i
< 4; i
++) {
416 ch
= IoRead8 (FW_IPORT
);
417 if (ch
!= mBhyveSig
[i
]) {
418 DEBUG ((DEBUG_INFO
, "Host f/w sig mismatch %c/%c\n", ch
, mBhyveSig
[i
]));
419 return RETURN_SUCCESS
;
423 mBhyveFwCtlSupported
= TRUE
;
425 return RETURN_SUCCESS
;