xref: /illumos-gate/usr/src/cmd/bhyve/fwctl.c (revision 6dc983494b0ffef2565cc4d91371ee345425ffab)
14c87aefeSPatrick Mooney /*-
24c87aefeSPatrick Mooney  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
34c87aefeSPatrick Mooney  *
44c87aefeSPatrick Mooney  * Copyright (c) 2015  Peter Grehan <grehan@freebsd.org>
54c87aefeSPatrick Mooney  * All rights reserved.
64c87aefeSPatrick Mooney  *
74c87aefeSPatrick Mooney  * Redistribution and use in source and binary forms, with or without
84c87aefeSPatrick Mooney  * modification, are permitted provided that the following conditions
94c87aefeSPatrick Mooney  * are met:
104c87aefeSPatrick Mooney  * 1. Redistributions of source code must retain the above copyright
114c87aefeSPatrick Mooney  *    notice, this list of conditions and the following disclaimer.
124c87aefeSPatrick Mooney  * 2. Redistributions in binary form must reproduce the above copyright
134c87aefeSPatrick Mooney  *    notice, this list of conditions and the following disclaimer in the
144c87aefeSPatrick Mooney  *    documentation and/or other materials provided with the distribution.
154c87aefeSPatrick Mooney  *
164c87aefeSPatrick Mooney  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
174c87aefeSPatrick Mooney  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
184c87aefeSPatrick Mooney  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
194c87aefeSPatrick Mooney  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
204c87aefeSPatrick Mooney  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
214c87aefeSPatrick Mooney  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
224c87aefeSPatrick Mooney  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
234c87aefeSPatrick Mooney  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
244c87aefeSPatrick Mooney  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
254c87aefeSPatrick Mooney  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
264c87aefeSPatrick Mooney  * SUCH DAMAGE.
274c87aefeSPatrick Mooney  *
284c87aefeSPatrick Mooney  * $FreeBSD$
294c87aefeSPatrick Mooney  */
304c87aefeSPatrick Mooney 
314c87aefeSPatrick Mooney /*
324c87aefeSPatrick Mooney  * Guest firmware interface. Uses i/o ports x510/x511 as Qemu does,
334c87aefeSPatrick Mooney  * but with a request/response messaging protocol.
344c87aefeSPatrick Mooney  */
354c87aefeSPatrick Mooney #include <sys/cdefs.h>
364c87aefeSPatrick Mooney __FBSDID("$FreeBSD$");
374c87aefeSPatrick Mooney 
384c87aefeSPatrick Mooney #include <sys/param.h>
394c87aefeSPatrick Mooney #include <sys/types.h>
404c87aefeSPatrick Mooney #include <sys/errno.h>
414c87aefeSPatrick Mooney #include <sys/uio.h>
424c87aefeSPatrick Mooney 
434c87aefeSPatrick Mooney #include <assert.h>
444c87aefeSPatrick Mooney #include <stdio.h>
454c87aefeSPatrick Mooney #include <stdlib.h>
464c87aefeSPatrick Mooney #include <string.h>
474c87aefeSPatrick Mooney 
484c87aefeSPatrick Mooney #include "bhyverun.h"
494c87aefeSPatrick Mooney #include "inout.h"
504c87aefeSPatrick Mooney #include "fwctl.h"
514c87aefeSPatrick Mooney 
524c87aefeSPatrick Mooney /*
534c87aefeSPatrick Mooney  * Messaging protocol base operations
544c87aefeSPatrick Mooney  */
554c87aefeSPatrick Mooney #define	OP_NULL		1
564c87aefeSPatrick Mooney #define	OP_ECHO		2
574c87aefeSPatrick Mooney #define	OP_GET		3
584c87aefeSPatrick Mooney #define	OP_GET_LEN	4
594c87aefeSPatrick Mooney #define	OP_SET		5
604c87aefeSPatrick Mooney #define	OP_MAX		OP_SET
614c87aefeSPatrick Mooney 
624c87aefeSPatrick Mooney /* I/O ports */
634c87aefeSPatrick Mooney #define	FWCTL_OUT	0x510
644c87aefeSPatrick Mooney #define	FWCTL_IN	0x511
654c87aefeSPatrick Mooney 
664c87aefeSPatrick Mooney /*
674c87aefeSPatrick Mooney  * Back-end state-machine
684c87aefeSPatrick Mooney  */
694c87aefeSPatrick Mooney enum state {
704c87aefeSPatrick Mooney 	DORMANT,
714c87aefeSPatrick Mooney 	IDENT_WAIT,
724c87aefeSPatrick Mooney 	IDENT_SEND,
734c87aefeSPatrick Mooney 	REQ,
744c87aefeSPatrick Mooney 	RESP
754c87aefeSPatrick Mooney } be_state = DORMANT;
764c87aefeSPatrick Mooney 
774c87aefeSPatrick Mooney static uint8_t sig[] = { 'B', 'H', 'Y', 'V' };
784c87aefeSPatrick Mooney static u_int ident_idx;
794c87aefeSPatrick Mooney 
804c87aefeSPatrick Mooney struct op_info {
814c87aefeSPatrick Mooney 	int op;
824c87aefeSPatrick Mooney 	int  (*op_start)(uint32_t len);
834c87aefeSPatrick Mooney 	void (*op_data)(uint32_t data, uint32_t len);
844c87aefeSPatrick Mooney 	int  (*op_result)(struct iovec **data);
854c87aefeSPatrick Mooney 	void (*op_done)(struct iovec *data);
864c87aefeSPatrick Mooney };
874c87aefeSPatrick Mooney static struct op_info *ops[OP_MAX+1];
884c87aefeSPatrick Mooney 
894c87aefeSPatrick Mooney /* Return 0-padded uint32_t */
904c87aefeSPatrick Mooney static uint32_t
914c87aefeSPatrick Mooney fwctl_send_rest(uint32_t *data, size_t len)
924c87aefeSPatrick Mooney {
934c87aefeSPatrick Mooney 	union {
944c87aefeSPatrick Mooney 		uint8_t c[4];
954c87aefeSPatrick Mooney 		uint32_t w;
964c87aefeSPatrick Mooney 	} u;
974c87aefeSPatrick Mooney 	uint8_t *cdata;
984c87aefeSPatrick Mooney 	int i;
994c87aefeSPatrick Mooney 
1004c87aefeSPatrick Mooney 	cdata = (uint8_t *) data;
1014c87aefeSPatrick Mooney 	u.w = 0;
1024c87aefeSPatrick Mooney 
1034c87aefeSPatrick Mooney 	for (i = 0, u.w = 0; i < len; i++)
1044c87aefeSPatrick Mooney 		u.c[i] = *cdata++;
1054c87aefeSPatrick Mooney 
1064c87aefeSPatrick Mooney 	return (u.w);
1074c87aefeSPatrick Mooney }
1084c87aefeSPatrick Mooney 
1094c87aefeSPatrick Mooney /*
1104c87aefeSPatrick Mooney  * error op dummy proto - drop all data sent and return an error
1114c87aefeSPatrick Mooney */
1124c87aefeSPatrick Mooney static int errop_code;
1134c87aefeSPatrick Mooney 
1144c87aefeSPatrick Mooney static void
1154c87aefeSPatrick Mooney errop_set(int err)
1164c87aefeSPatrick Mooney {
1174c87aefeSPatrick Mooney 
1184c87aefeSPatrick Mooney 	errop_code = err;
1194c87aefeSPatrick Mooney }
1204c87aefeSPatrick Mooney 
1214c87aefeSPatrick Mooney static int
1224c87aefeSPatrick Mooney errop_start(uint32_t len)
1234c87aefeSPatrick Mooney {
1244c87aefeSPatrick Mooney 	errop_code = ENOENT;
1254c87aefeSPatrick Mooney 
1264c87aefeSPatrick Mooney 	/* accept any length */
1274c87aefeSPatrick Mooney 	return (errop_code);
1284c87aefeSPatrick Mooney }
1294c87aefeSPatrick Mooney 
1304c87aefeSPatrick Mooney static void
1314c87aefeSPatrick Mooney errop_data(uint32_t data, uint32_t len)
1324c87aefeSPatrick Mooney {
1334c87aefeSPatrick Mooney 
1344c87aefeSPatrick Mooney 	/* ignore */
1354c87aefeSPatrick Mooney }
1364c87aefeSPatrick Mooney 
1374c87aefeSPatrick Mooney static int
1384c87aefeSPatrick Mooney errop_result(struct iovec **data)
1394c87aefeSPatrick Mooney {
1404c87aefeSPatrick Mooney 
1414c87aefeSPatrick Mooney 	/* no data to send back; always successful */
1424c87aefeSPatrick Mooney 	*data = NULL;
1434c87aefeSPatrick Mooney 	return (errop_code);
1444c87aefeSPatrick Mooney }
1454c87aefeSPatrick Mooney 
1464c87aefeSPatrick Mooney static void
1474c87aefeSPatrick Mooney errop_done(struct iovec *data)
1484c87aefeSPatrick Mooney {
1494c87aefeSPatrick Mooney 
1504c87aefeSPatrick Mooney 	/* assert data is NULL */
1514c87aefeSPatrick Mooney }
1524c87aefeSPatrick Mooney 
1534c87aefeSPatrick Mooney static struct op_info errop_info = {
1544c87aefeSPatrick Mooney 	.op_start  = errop_start,
1554c87aefeSPatrick Mooney 	.op_data   = errop_data,
1564c87aefeSPatrick Mooney 	.op_result = errop_result,
1574c87aefeSPatrick Mooney 	.op_done   = errop_done
1584c87aefeSPatrick Mooney };
1594c87aefeSPatrick Mooney 
1604c87aefeSPatrick Mooney /* OID search */
1614c87aefeSPatrick Mooney SET_DECLARE(ctl_set, struct ctl);
1624c87aefeSPatrick Mooney 
1634c87aefeSPatrick Mooney CTL_NODE("hw.ncpu", &guest_ncpus, sizeof(guest_ncpus));
1644c87aefeSPatrick Mooney 
1654c87aefeSPatrick Mooney static struct ctl *
1664c87aefeSPatrick Mooney ctl_locate(const char *str, int maxlen)
1674c87aefeSPatrick Mooney {
1684c87aefeSPatrick Mooney 	struct ctl *cp, **cpp;
1694c87aefeSPatrick Mooney 
1704c87aefeSPatrick Mooney 	SET_FOREACH(cpp, ctl_set)  {
1714c87aefeSPatrick Mooney 		cp = *cpp;
1724c87aefeSPatrick Mooney 		if (!strncmp(str, cp->c_oid, maxlen))
1734c87aefeSPatrick Mooney 			return (cp);
1744c87aefeSPatrick Mooney 	}
1754c87aefeSPatrick Mooney 
1764c87aefeSPatrick Mooney 	return (NULL);
1774c87aefeSPatrick Mooney }
1784c87aefeSPatrick Mooney 
1794c87aefeSPatrick Mooney /* uefi-sysctl get-len */
1804c87aefeSPatrick Mooney #define FGET_STRSZ	80
1814c87aefeSPatrick Mooney static struct iovec fget_biov[2];
1824c87aefeSPatrick Mooney static char fget_str[FGET_STRSZ];
1834c87aefeSPatrick Mooney static struct {
1844c87aefeSPatrick Mooney 	size_t f_sz;
1854c87aefeSPatrick Mooney 	uint32_t f_data[1024];
1864c87aefeSPatrick Mooney } fget_buf;
1874c87aefeSPatrick Mooney static int fget_cnt;
1884c87aefeSPatrick Mooney static size_t fget_size;
1894c87aefeSPatrick Mooney 
1904c87aefeSPatrick Mooney static int
1914c87aefeSPatrick Mooney fget_start(uint32_t len)
1924c87aefeSPatrick Mooney {
1934c87aefeSPatrick Mooney 
1944c87aefeSPatrick Mooney 	if (len > FGET_STRSZ)
1954c87aefeSPatrick Mooney 		return(E2BIG);
1964c87aefeSPatrick Mooney 
1974c87aefeSPatrick Mooney 	fget_cnt = 0;
1984c87aefeSPatrick Mooney 
1994c87aefeSPatrick Mooney 	return (0);
2004c87aefeSPatrick Mooney }
2014c87aefeSPatrick Mooney 
2024c87aefeSPatrick Mooney static void
2034c87aefeSPatrick Mooney fget_data(uint32_t data, uint32_t len)
2044c87aefeSPatrick Mooney {
2054c87aefeSPatrick Mooney 
2064c87aefeSPatrick Mooney 	*((uint32_t *) &fget_str[fget_cnt]) = data;
2074c87aefeSPatrick Mooney 	fget_cnt += sizeof(uint32_t);
2084c87aefeSPatrick Mooney }
2094c87aefeSPatrick Mooney 
2104c87aefeSPatrick Mooney static int
2114c87aefeSPatrick Mooney fget_result(struct iovec **data, int val)
2124c87aefeSPatrick Mooney {
2134c87aefeSPatrick Mooney 	struct ctl *cp;
2144c87aefeSPatrick Mooney 	int err;
2154c87aefeSPatrick Mooney 
2164c87aefeSPatrick Mooney 	err = 0;
2174c87aefeSPatrick Mooney 
2184c87aefeSPatrick Mooney 	/* Locate the OID */
2194c87aefeSPatrick Mooney 	cp = ctl_locate(fget_str, fget_cnt);
2204c87aefeSPatrick Mooney 	if (cp == NULL) {
2214c87aefeSPatrick Mooney 		*data = NULL;
2224c87aefeSPatrick Mooney 		err = ENOENT;
2234c87aefeSPatrick Mooney 	} else {
2244c87aefeSPatrick Mooney 		if (val) {
2254c87aefeSPatrick Mooney 			/* For now, copy the len/data into a buffer */
2264c87aefeSPatrick Mooney 			memset(&fget_buf, 0, sizeof(fget_buf));
2274c87aefeSPatrick Mooney 			fget_buf.f_sz = cp->c_len;
2284c87aefeSPatrick Mooney 			memcpy(fget_buf.f_data, cp->c_data, cp->c_len);
2294c87aefeSPatrick Mooney 			fget_biov[0].iov_base = (char *)&fget_buf;
2304c87aefeSPatrick Mooney 			fget_biov[0].iov_len  = sizeof(fget_buf.f_sz) +
2314c87aefeSPatrick Mooney 				cp->c_len;
2324c87aefeSPatrick Mooney 		} else {
2334c87aefeSPatrick Mooney 			fget_size = cp->c_len;
2344c87aefeSPatrick Mooney 			fget_biov[0].iov_base = (char *)&fget_size;
2354c87aefeSPatrick Mooney 			fget_biov[0].iov_len  = sizeof(fget_size);
2364c87aefeSPatrick Mooney 		}
2374c87aefeSPatrick Mooney 
2384c87aefeSPatrick Mooney 		fget_biov[1].iov_base = NULL;
2394c87aefeSPatrick Mooney 		fget_biov[1].iov_len  = 0;
2404c87aefeSPatrick Mooney 		*data = fget_biov;
2414c87aefeSPatrick Mooney 	}
2424c87aefeSPatrick Mooney 
2434c87aefeSPatrick Mooney 	return (err);
2444c87aefeSPatrick Mooney }
2454c87aefeSPatrick Mooney 
2464c87aefeSPatrick Mooney static void
2474c87aefeSPatrick Mooney fget_done(struct iovec *data)
2484c87aefeSPatrick Mooney {
2494c87aefeSPatrick Mooney 
2504c87aefeSPatrick Mooney 	/* nothing needs to be freed */
2514c87aefeSPatrick Mooney }
2524c87aefeSPatrick Mooney 
2534c87aefeSPatrick Mooney static int
2544c87aefeSPatrick Mooney fget_len_result(struct iovec **data)
2554c87aefeSPatrick Mooney {
2564c87aefeSPatrick Mooney 	return (fget_result(data, 0));
2574c87aefeSPatrick Mooney }
2584c87aefeSPatrick Mooney 
2594c87aefeSPatrick Mooney static int
2604c87aefeSPatrick Mooney fget_val_result(struct iovec **data)
2614c87aefeSPatrick Mooney {
2624c87aefeSPatrick Mooney 	return (fget_result(data, 1));
2634c87aefeSPatrick Mooney }
2644c87aefeSPatrick Mooney 
2654c87aefeSPatrick Mooney static struct op_info fgetlen_info = {
2664c87aefeSPatrick Mooney 	.op_start  = fget_start,
2674c87aefeSPatrick Mooney 	.op_data   = fget_data,
2684c87aefeSPatrick Mooney 	.op_result = fget_len_result,
2694c87aefeSPatrick Mooney 	.op_done   = fget_done
2704c87aefeSPatrick Mooney };
2714c87aefeSPatrick Mooney 
2724c87aefeSPatrick Mooney static struct op_info fgetval_info = {
2734c87aefeSPatrick Mooney 	.op_start  = fget_start,
2744c87aefeSPatrick Mooney 	.op_data   = fget_data,
2754c87aefeSPatrick Mooney 	.op_result = fget_val_result,
2764c87aefeSPatrick Mooney 	.op_done   = fget_done
2774c87aefeSPatrick Mooney };
2784c87aefeSPatrick Mooney 
2794c87aefeSPatrick Mooney static struct req_info {
2804c87aefeSPatrick Mooney 	int      req_error;
2814c87aefeSPatrick Mooney 	u_int    req_count;
2824c87aefeSPatrick Mooney 	uint32_t req_size;
2834c87aefeSPatrick Mooney 	uint32_t req_type;
2844c87aefeSPatrick Mooney 	uint32_t req_txid;
2854c87aefeSPatrick Mooney 	struct op_info *req_op;
2864c87aefeSPatrick Mooney 	int	 resp_error;
2874c87aefeSPatrick Mooney 	int	 resp_count;
2884c87aefeSPatrick Mooney 	size_t	 resp_size;
2894c87aefeSPatrick Mooney 	size_t	 resp_off;
2904c87aefeSPatrick Mooney 	struct iovec *resp_biov;
2914c87aefeSPatrick Mooney } rinfo;
2924c87aefeSPatrick Mooney 
2934c87aefeSPatrick Mooney static void
2944c87aefeSPatrick Mooney fwctl_response_done(void)
2954c87aefeSPatrick Mooney {
2964c87aefeSPatrick Mooney 
2974c87aefeSPatrick Mooney 	(*rinfo.req_op->op_done)(rinfo.resp_biov);
2984c87aefeSPatrick Mooney 
2994c87aefeSPatrick Mooney 	/* reinit the req data struct */
3004c87aefeSPatrick Mooney 	memset(&rinfo, 0, sizeof(rinfo));
3014c87aefeSPatrick Mooney }
3024c87aefeSPatrick Mooney 
3034c87aefeSPatrick Mooney static void
3044c87aefeSPatrick Mooney fwctl_request_done(void)
3054c87aefeSPatrick Mooney {
3064c87aefeSPatrick Mooney 
3074c87aefeSPatrick Mooney 	rinfo.resp_error = (*rinfo.req_op->op_result)(&rinfo.resp_biov);
3084c87aefeSPatrick Mooney 
3094c87aefeSPatrick Mooney 	/* XXX only a single vector supported at the moment */
3104c87aefeSPatrick Mooney 	rinfo.resp_off = 0;
3114c87aefeSPatrick Mooney 	if (rinfo.resp_biov == NULL) {
3124c87aefeSPatrick Mooney 		rinfo.resp_size = 0;
3134c87aefeSPatrick Mooney 	} else {
3144c87aefeSPatrick Mooney 		rinfo.resp_size = rinfo.resp_biov[0].iov_len;
3154c87aefeSPatrick Mooney 	}
3164c87aefeSPatrick Mooney }
3174c87aefeSPatrick Mooney 
3184c87aefeSPatrick Mooney static int
3194c87aefeSPatrick Mooney fwctl_request_start(void)
3204c87aefeSPatrick Mooney {
3214c87aefeSPatrick Mooney 	int err;
3224c87aefeSPatrick Mooney 
3234c87aefeSPatrick Mooney 	/* Data size doesn't include header */
3244c87aefeSPatrick Mooney 	rinfo.req_size -= 12;
3254c87aefeSPatrick Mooney 
3264c87aefeSPatrick Mooney 	rinfo.req_op = &errop_info;
3274c87aefeSPatrick Mooney 	if (rinfo.req_type <= OP_MAX && ops[rinfo.req_type] != NULL)
3284c87aefeSPatrick Mooney 		rinfo.req_op = ops[rinfo.req_type];
3294c87aefeSPatrick Mooney 
3304c87aefeSPatrick Mooney 	err = (*rinfo.req_op->op_start)(rinfo.req_size);
3314c87aefeSPatrick Mooney 
3324c87aefeSPatrick Mooney 	if (err) {
3334c87aefeSPatrick Mooney 		errop_set(err);
3344c87aefeSPatrick Mooney 		rinfo.req_op = &errop_info;
3354c87aefeSPatrick Mooney 	}
3364c87aefeSPatrick Mooney 
3374c87aefeSPatrick Mooney 	/* Catch case of zero-length message here */
3384c87aefeSPatrick Mooney 	if (rinfo.req_size == 0) {
3394c87aefeSPatrick Mooney 		fwctl_request_done();
3404c87aefeSPatrick Mooney 		return (1);
3414c87aefeSPatrick Mooney 	}
3424c87aefeSPatrick Mooney 
3434c87aefeSPatrick Mooney 	return (0);
3444c87aefeSPatrick Mooney }
3454c87aefeSPatrick Mooney 
3464c87aefeSPatrick Mooney static int
3474c87aefeSPatrick Mooney fwctl_request_data(uint32_t value)
3484c87aefeSPatrick Mooney {
3494c87aefeSPatrick Mooney 
3504c87aefeSPatrick Mooney 	/* Make sure remaining size is >= 0 */
3514c87aefeSPatrick Mooney 	if (rinfo.req_size <= sizeof(uint32_t))
3524c87aefeSPatrick Mooney 		rinfo.req_size = 0;
3534c87aefeSPatrick Mooney 	else
3544c87aefeSPatrick Mooney 		rinfo.req_size -= sizeof(uint32_t);
3554c87aefeSPatrick Mooney 
3564c87aefeSPatrick Mooney 	(*rinfo.req_op->op_data)(value, rinfo.req_size);
3574c87aefeSPatrick Mooney 
3584c87aefeSPatrick Mooney 	if (rinfo.req_size < sizeof(uint32_t)) {
3594c87aefeSPatrick Mooney 		fwctl_request_done();
3604c87aefeSPatrick Mooney 		return (1);
3614c87aefeSPatrick Mooney 	}
3624c87aefeSPatrick Mooney 
3634c87aefeSPatrick Mooney 	return (0);
3644c87aefeSPatrick Mooney }
3654c87aefeSPatrick Mooney 
3664c87aefeSPatrick Mooney static int
3674c87aefeSPatrick Mooney fwctl_request(uint32_t value)
3684c87aefeSPatrick Mooney {
3694c87aefeSPatrick Mooney 
3704c87aefeSPatrick Mooney 	int ret;
3714c87aefeSPatrick Mooney 
3724c87aefeSPatrick Mooney 	ret = 0;
3734c87aefeSPatrick Mooney 
3744c87aefeSPatrick Mooney 	switch (rinfo.req_count) {
3754c87aefeSPatrick Mooney 	case 0:
3764c87aefeSPatrick Mooney 		/* Verify size */
3774c87aefeSPatrick Mooney 		if (value < 12) {
3784c87aefeSPatrick Mooney 			printf("msg size error");
3794c87aefeSPatrick Mooney 			exit(4);
3804c87aefeSPatrick Mooney 		}
3814c87aefeSPatrick Mooney 		rinfo.req_size = value;
3824c87aefeSPatrick Mooney 		rinfo.req_count = 1;
3834c87aefeSPatrick Mooney 		break;
3844c87aefeSPatrick Mooney 	case 1:
3854c87aefeSPatrick Mooney 		rinfo.req_type = value;
3864c87aefeSPatrick Mooney 		rinfo.req_count++;
3874c87aefeSPatrick Mooney 		break;
3884c87aefeSPatrick Mooney 	case 2:
3894c87aefeSPatrick Mooney 		rinfo.req_txid = value;
3904c87aefeSPatrick Mooney 		rinfo.req_count++;
3914c87aefeSPatrick Mooney 		ret = fwctl_request_start();
3924c87aefeSPatrick Mooney 		break;
3934c87aefeSPatrick Mooney 	default:
3944c87aefeSPatrick Mooney 		ret = fwctl_request_data(value);
3954c87aefeSPatrick Mooney 		break;
3964c87aefeSPatrick Mooney 	}
3974c87aefeSPatrick Mooney 
3984c87aefeSPatrick Mooney 	return (ret);
3994c87aefeSPatrick Mooney }
4004c87aefeSPatrick Mooney 
4014c87aefeSPatrick Mooney static int
4024c87aefeSPatrick Mooney fwctl_response(uint32_t *retval)
4034c87aefeSPatrick Mooney {
4044c87aefeSPatrick Mooney 	uint32_t *dp;
4054c87aefeSPatrick Mooney 	ssize_t remlen;
4064c87aefeSPatrick Mooney 
4074c87aefeSPatrick Mooney 	switch(rinfo.resp_count) {
4084c87aefeSPatrick Mooney 	case 0:
4094c87aefeSPatrick Mooney 		/* 4 x u32 header len + data */
4104c87aefeSPatrick Mooney 		*retval = 4*sizeof(uint32_t) +
4114c87aefeSPatrick Mooney 		    roundup(rinfo.resp_size, sizeof(uint32_t));
4124c87aefeSPatrick Mooney 		rinfo.resp_count++;
4134c87aefeSPatrick Mooney 		break;
4144c87aefeSPatrick Mooney 	case 1:
4154c87aefeSPatrick Mooney 		*retval = rinfo.req_type;
4164c87aefeSPatrick Mooney 		rinfo.resp_count++;
4174c87aefeSPatrick Mooney 		break;
4184c87aefeSPatrick Mooney 	case 2:
4194c87aefeSPatrick Mooney 		*retval = rinfo.req_txid;
4204c87aefeSPatrick Mooney 		rinfo.resp_count++;
4214c87aefeSPatrick Mooney 		break;
4224c87aefeSPatrick Mooney 	case 3:
4234c87aefeSPatrick Mooney 		*retval = rinfo.resp_error;
4244c87aefeSPatrick Mooney 		rinfo.resp_count++;
4254c87aefeSPatrick Mooney 		break;
4264c87aefeSPatrick Mooney 	default:
4274c87aefeSPatrick Mooney 		remlen = rinfo.resp_size - rinfo.resp_off;
4284c87aefeSPatrick Mooney 		dp = (uint32_t *)
4294c87aefeSPatrick Mooney 		    ((uint8_t *)rinfo.resp_biov->iov_base + rinfo.resp_off);
4304c87aefeSPatrick Mooney 		if (remlen >= sizeof(uint32_t)) {
4314c87aefeSPatrick Mooney 			*retval = *dp;
4324c87aefeSPatrick Mooney 		} else if (remlen > 0) {
4334c87aefeSPatrick Mooney 			*retval = fwctl_send_rest(dp, remlen);
4344c87aefeSPatrick Mooney 		}
4354c87aefeSPatrick Mooney 		rinfo.resp_off += sizeof(uint32_t);
4364c87aefeSPatrick Mooney 		break;
4374c87aefeSPatrick Mooney 	}
4384c87aefeSPatrick Mooney 
4394c87aefeSPatrick Mooney 	if (rinfo.resp_count > 3 &&
4404c87aefeSPatrick Mooney 	    rinfo.resp_off >= rinfo.resp_size) {
4414c87aefeSPatrick Mooney 		fwctl_response_done();
4424c87aefeSPatrick Mooney 		return (1);
4434c87aefeSPatrick Mooney 	}
4444c87aefeSPatrick Mooney 
4454c87aefeSPatrick Mooney 	return (0);
4464c87aefeSPatrick Mooney }
4474c87aefeSPatrick Mooney 
4484c87aefeSPatrick Mooney 
4494c87aefeSPatrick Mooney /*
4504c87aefeSPatrick Mooney  * i/o port handling.
4514c87aefeSPatrick Mooney  */
4524c87aefeSPatrick Mooney static uint8_t
4534c87aefeSPatrick Mooney fwctl_inb(void)
4544c87aefeSPatrick Mooney {
4554c87aefeSPatrick Mooney 	uint8_t retval;
4564c87aefeSPatrick Mooney 
4574c87aefeSPatrick Mooney 	retval = 0xff;
4584c87aefeSPatrick Mooney 
4594c87aefeSPatrick Mooney 	switch (be_state) {
4604c87aefeSPatrick Mooney 	case IDENT_SEND:
4614c87aefeSPatrick Mooney 		retval = sig[ident_idx++];
4624c87aefeSPatrick Mooney 		if (ident_idx >= sizeof(sig))
4634c87aefeSPatrick Mooney 			be_state = REQ;
4644c87aefeSPatrick Mooney 		break;
4654c87aefeSPatrick Mooney 	default:
4664c87aefeSPatrick Mooney 		break;
4674c87aefeSPatrick Mooney 	}
4684c87aefeSPatrick Mooney 
4694c87aefeSPatrick Mooney 	return (retval);
4704c87aefeSPatrick Mooney }
4714c87aefeSPatrick Mooney 
4724c87aefeSPatrick Mooney static void
4734c87aefeSPatrick Mooney fwctl_outw(uint16_t val)
4744c87aefeSPatrick Mooney {
475*6dc98349SAndy Fiddaman 	if (be_state == DORMANT) {
476*6dc98349SAndy Fiddaman 		return;
477*6dc98349SAndy Fiddaman 	}
478*6dc98349SAndy Fiddaman 
4794c87aefeSPatrick Mooney 	if (val == 0) {
480*6dc98349SAndy Fiddaman 		/*
481*6dc98349SAndy Fiddaman 		 * The guest wants to read the signature. It's possible that the
482*6dc98349SAndy Fiddaman 		 * guest is unaware of the fwctl state at this moment. For that
483*6dc98349SAndy Fiddaman 		 * reason, reset the state machine unconditionally.
484*6dc98349SAndy Fiddaman 		 */
4854c87aefeSPatrick Mooney 		be_state = IDENT_SEND;
4864c87aefeSPatrick Mooney 		ident_idx = 0;
4874c87aefeSPatrick Mooney 	}
4884c87aefeSPatrick Mooney }
4894c87aefeSPatrick Mooney 
4904c87aefeSPatrick Mooney static uint32_t
4914c87aefeSPatrick Mooney fwctl_inl(void)
4924c87aefeSPatrick Mooney {
4934c87aefeSPatrick Mooney 	uint32_t retval;
4944c87aefeSPatrick Mooney 
4954c87aefeSPatrick Mooney 	switch (be_state) {
4964c87aefeSPatrick Mooney 	case RESP:
4974c87aefeSPatrick Mooney 		if (fwctl_response(&retval))
4984c87aefeSPatrick Mooney 			be_state = REQ;
4994c87aefeSPatrick Mooney 		break;
5004c87aefeSPatrick Mooney 	default:
5014c87aefeSPatrick Mooney 		retval = 0xffffffff;
5024c87aefeSPatrick Mooney 		break;
5034c87aefeSPatrick Mooney 	}
5044c87aefeSPatrick Mooney 
5054c87aefeSPatrick Mooney 	return (retval);
5064c87aefeSPatrick Mooney }
5074c87aefeSPatrick Mooney 
5084c87aefeSPatrick Mooney static void
5094c87aefeSPatrick Mooney fwctl_outl(uint32_t val)
5104c87aefeSPatrick Mooney {
5114c87aefeSPatrick Mooney 
5124c87aefeSPatrick Mooney 	switch (be_state) {
5134c87aefeSPatrick Mooney 	case REQ:
5144c87aefeSPatrick Mooney 		if (fwctl_request(val))
5154c87aefeSPatrick Mooney 			be_state = RESP;
5164c87aefeSPatrick Mooney 	default:
5174c87aefeSPatrick Mooney 		break;
5184c87aefeSPatrick Mooney 	}
5194c87aefeSPatrick Mooney 
5204c87aefeSPatrick Mooney }
5214c87aefeSPatrick Mooney 
5224c87aefeSPatrick Mooney static int
5234c87aefeSPatrick Mooney fwctl_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
5244c87aefeSPatrick Mooney     uint32_t *eax, void *arg)
5254c87aefeSPatrick Mooney {
5264c87aefeSPatrick Mooney 
5274c87aefeSPatrick Mooney 	if (in) {
5284c87aefeSPatrick Mooney 		if (bytes == 1)
5294c87aefeSPatrick Mooney 			*eax = fwctl_inb();
5304c87aefeSPatrick Mooney 		else if (bytes == 4)
5314c87aefeSPatrick Mooney 			*eax = fwctl_inl();
5324c87aefeSPatrick Mooney 		else
5334c87aefeSPatrick Mooney 			*eax = 0xffff;
5344c87aefeSPatrick Mooney 	} else {
5354c87aefeSPatrick Mooney 		if (bytes == 2)
5364c87aefeSPatrick Mooney 			fwctl_outw(*eax);
5374c87aefeSPatrick Mooney 		else if (bytes == 4)
5384c87aefeSPatrick Mooney 			fwctl_outl(*eax);
5394c87aefeSPatrick Mooney 	}
5404c87aefeSPatrick Mooney 
5414c87aefeSPatrick Mooney 	return (0);
5424c87aefeSPatrick Mooney }
5434c87aefeSPatrick Mooney 
5444c87aefeSPatrick Mooney void
5454c87aefeSPatrick Mooney fwctl_init(void)
5464c87aefeSPatrick Mooney {
547*6dc98349SAndy Fiddaman 	struct inout_port iop;
548*6dc98349SAndy Fiddaman 	int error;
549*6dc98349SAndy Fiddaman 
550*6dc98349SAndy Fiddaman 	bzero(&iop, sizeof(iop));
551*6dc98349SAndy Fiddaman 	iop.name = "fwctl_wreg";
552*6dc98349SAndy Fiddaman 	iop.port = FWCTL_OUT;
553*6dc98349SAndy Fiddaman 	iop.size = 1;
554*6dc98349SAndy Fiddaman 	iop.flags = IOPORT_F_INOUT;
555*6dc98349SAndy Fiddaman 	iop.handler = fwctl_handler;
556*6dc98349SAndy Fiddaman 
557*6dc98349SAndy Fiddaman 	error = register_inout(&iop);
558*6dc98349SAndy Fiddaman 	assert(error == 0);
559*6dc98349SAndy Fiddaman 
560*6dc98349SAndy Fiddaman 	bzero(&iop, sizeof(iop));
561*6dc98349SAndy Fiddaman 	iop.name = "fwctl_rreg";
562*6dc98349SAndy Fiddaman 	iop.port = FWCTL_IN;
563*6dc98349SAndy Fiddaman 	iop.size = 1;
564*6dc98349SAndy Fiddaman 	iop.flags = IOPORT_F_IN;
565*6dc98349SAndy Fiddaman 	iop.handler = fwctl_handler;
566*6dc98349SAndy Fiddaman 
567*6dc98349SAndy Fiddaman 	error = register_inout(&iop);
568*6dc98349SAndy Fiddaman 	assert(error == 0);
5694c87aefeSPatrick Mooney 
5704c87aefeSPatrick Mooney 	ops[OP_GET_LEN] = &fgetlen_info;
5714c87aefeSPatrick Mooney 	ops[OP_GET]     = &fgetval_info;
5724c87aefeSPatrick Mooney 
5734c87aefeSPatrick Mooney 	be_state = IDENT_WAIT;
5744c87aefeSPatrick Mooney }
575