xref: /illumos-gate/usr/src/cmd/bhyve/fwctl.c (revision 32640292)
14c87aefeSPatrick Mooney /*-
2*32640292SAndy Fiddaman  * SPDX-License-Identifier: BSD-2-Clause
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 
294c87aefeSPatrick Mooney /*
304c87aefeSPatrick Mooney  * Guest firmware interface. Uses i/o ports x510/x511 as Qemu does,
314c87aefeSPatrick Mooney  * but with a request/response messaging protocol.
324c87aefeSPatrick Mooney  */
334c87aefeSPatrick Mooney #include <sys/cdefs.h>
344c87aefeSPatrick Mooney 
354c87aefeSPatrick Mooney #include <sys/param.h>
364c87aefeSPatrick Mooney #include <sys/types.h>
374c87aefeSPatrick Mooney #include <sys/errno.h>
384c87aefeSPatrick Mooney #include <sys/uio.h>
394c87aefeSPatrick Mooney 
404c87aefeSPatrick Mooney #include <assert.h>
414c87aefeSPatrick Mooney #include <stdio.h>
424c87aefeSPatrick Mooney #include <stdlib.h>
434c87aefeSPatrick Mooney #include <string.h>
444c87aefeSPatrick Mooney 
454c87aefeSPatrick Mooney #include "bhyverun.h"
464c87aefeSPatrick Mooney #include "inout.h"
474c87aefeSPatrick Mooney #include "fwctl.h"
484c87aefeSPatrick Mooney 
494c87aefeSPatrick Mooney /*
504c87aefeSPatrick Mooney  * Messaging protocol base operations
514c87aefeSPatrick Mooney  */
524c87aefeSPatrick Mooney #define	OP_NULL		1
534c87aefeSPatrick Mooney #define	OP_ECHO		2
544c87aefeSPatrick Mooney #define	OP_GET		3
554c87aefeSPatrick Mooney #define	OP_GET_LEN	4
564c87aefeSPatrick Mooney #define	OP_SET		5
574c87aefeSPatrick Mooney #define	OP_MAX		OP_SET
584c87aefeSPatrick Mooney 
594c87aefeSPatrick Mooney /* I/O ports */
604c87aefeSPatrick Mooney #define	FWCTL_OUT	0x510
614c87aefeSPatrick Mooney #define	FWCTL_IN	0x511
624c87aefeSPatrick Mooney 
634c87aefeSPatrick Mooney /*
644c87aefeSPatrick Mooney  * Back-end state-machine
654c87aefeSPatrick Mooney  */
664f3f3e9aSAndy Fiddaman static enum state {
674c87aefeSPatrick Mooney 	IDENT_WAIT,
684c87aefeSPatrick Mooney 	IDENT_SEND,
694c87aefeSPatrick Mooney 	REQ,
704c87aefeSPatrick Mooney 	RESP
71d35aa001SJohn Baldwin } be_state;
724c87aefeSPatrick Mooney 
734c87aefeSPatrick Mooney static uint8_t sig[] = { 'B', 'H', 'Y', 'V' };
744c87aefeSPatrick Mooney static u_int ident_idx;
754c87aefeSPatrick Mooney 
764c87aefeSPatrick Mooney struct op_info {
774c87aefeSPatrick Mooney 	int op;
784c87aefeSPatrick Mooney 	int  (*op_start)(uint32_t len);
794c87aefeSPatrick Mooney 	void (*op_data)(uint32_t data, uint32_t len);
804c87aefeSPatrick Mooney 	int  (*op_result)(struct iovec **data);
814c87aefeSPatrick Mooney 	void (*op_done)(struct iovec *data);
824c87aefeSPatrick Mooney };
834c87aefeSPatrick Mooney static struct op_info *ops[OP_MAX+1];
844c87aefeSPatrick Mooney 
854c87aefeSPatrick Mooney /* Return 0-padded uint32_t */
864c87aefeSPatrick Mooney static uint32_t
fwctl_send_rest(uint8_t * data,size_t len)8759d65d31SAndy Fiddaman fwctl_send_rest(uint8_t *data, size_t len)
884c87aefeSPatrick Mooney {
894c87aefeSPatrick Mooney 	union {
904c87aefeSPatrick Mooney 		uint8_t c[4];
914c87aefeSPatrick Mooney 		uint32_t w;
924c87aefeSPatrick Mooney 	} u;
9359d65d31SAndy Fiddaman 	size_t i;
944c87aefeSPatrick Mooney 
956dc98349SAndy Fiddaman 	u.w = 0;
9659d65d31SAndy Fiddaman 	for (i = 0; i < len; i++)
9759d65d31SAndy Fiddaman 		u.c[i] = *data++;
984c87aefeSPatrick Mooney 
994c87aefeSPatrick Mooney 	return (u.w);
1004c87aefeSPatrick Mooney }
1014c87aefeSPatrick Mooney 
1024c87aefeSPatrick Mooney /*
1034c87aefeSPatrick Mooney  * error op dummy proto - drop all data sent and return an error
1044c87aefeSPatrick Mooney */
1054c87aefeSPatrick Mooney static int errop_code;
1064c87aefeSPatrick Mooney 
1074c87aefeSPatrick Mooney static void
errop_set(int err)1084c87aefeSPatrick Mooney errop_set(int err)
1094c87aefeSPatrick Mooney {
1104c87aefeSPatrick Mooney 
1114c87aefeSPatrick Mooney 	errop_code = err;
1124c87aefeSPatrick Mooney }
1134c87aefeSPatrick Mooney 
1144c87aefeSPatrick Mooney static int
errop_start(uint32_t len __unused)11559d65d31SAndy Fiddaman errop_start(uint32_t len __unused)
1164c87aefeSPatrick Mooney {
1174c87aefeSPatrick Mooney 	errop_code = ENOENT;
1184c87aefeSPatrick Mooney 
1194c87aefeSPatrick Mooney 	/* accept any length */
1204c87aefeSPatrick Mooney 	return (errop_code);
1214c87aefeSPatrick Mooney }
1224c87aefeSPatrick Mooney 
1234c87aefeSPatrick Mooney static void
errop_data(uint32_t data __unused,uint32_t len __unused)12459d65d31SAndy Fiddaman errop_data(uint32_t data __unused, uint32_t len __unused)
1254c87aefeSPatrick Mooney {
1264c87aefeSPatrick Mooney 
1274c87aefeSPatrick Mooney 	/* ignore */
1284c87aefeSPatrick Mooney }
1294c87aefeSPatrick Mooney 
1304c87aefeSPatrick Mooney static int
errop_result(struct iovec ** data)1314c87aefeSPatrick Mooney errop_result(struct iovec **data)
1324c87aefeSPatrick Mooney {
1334c87aefeSPatrick Mooney 
1344c87aefeSPatrick Mooney 	/* no data to send back; always successful */
1354c87aefeSPatrick Mooney 	*data = NULL;
1364c87aefeSPatrick Mooney 	return (errop_code);
1374c87aefeSPatrick Mooney }
1384c87aefeSPatrick Mooney 
1394c87aefeSPatrick Mooney static void
errop_done(struct iovec * data __unused)14059d65d31SAndy Fiddaman errop_done(struct iovec *data __unused)
1414c87aefeSPatrick Mooney {
1424c87aefeSPatrick Mooney 
1434c87aefeSPatrick Mooney 	/* assert data is NULL */
1444c87aefeSPatrick Mooney }
1454c87aefeSPatrick Mooney 
1464c87aefeSPatrick Mooney static struct op_info errop_info = {
1474c87aefeSPatrick Mooney 	.op_start  = errop_start,
1484c87aefeSPatrick Mooney 	.op_data   = errop_data,
1494c87aefeSPatrick Mooney 	.op_result = errop_result,
1504c87aefeSPatrick Mooney 	.op_done   = errop_done
1514c87aefeSPatrick Mooney };
1524c87aefeSPatrick Mooney 
1534c87aefeSPatrick Mooney /* OID search */
1544c87aefeSPatrick Mooney SET_DECLARE(ctl_set, struct ctl);
1554c87aefeSPatrick Mooney 
1564c87aefeSPatrick Mooney CTL_NODE("hw.ncpu", &guest_ncpus, sizeof(guest_ncpus));
1574c87aefeSPatrick Mooney 
1584c87aefeSPatrick Mooney static struct ctl *
ctl_locate(const char * str,int maxlen)1594c87aefeSPatrick Mooney ctl_locate(const char *str, int maxlen)
1604c87aefeSPatrick Mooney {
1614c87aefeSPatrick Mooney 	struct ctl *cp, **cpp;
1624c87aefeSPatrick Mooney 
1634c87aefeSPatrick Mooney 	SET_FOREACH(cpp, ctl_set)  {
1644c87aefeSPatrick Mooney 		cp = *cpp;
1654c87aefeSPatrick Mooney 		if (!strncmp(str, cp->c_oid, maxlen))
1664c87aefeSPatrick Mooney 			return (cp);
1674c87aefeSPatrick Mooney 	}
1684c87aefeSPatrick Mooney 
1694c87aefeSPatrick Mooney 	return (NULL);
1704c87aefeSPatrick Mooney }
1714c87aefeSPatrick Mooney 
1724c87aefeSPatrick Mooney /* uefi-sysctl get-len */
1734c87aefeSPatrick Mooney #define FGET_STRSZ	80
1744c87aefeSPatrick Mooney static struct iovec fget_biov[2];
1754c87aefeSPatrick Mooney static char fget_str[FGET_STRSZ];
1764c87aefeSPatrick Mooney static struct {
1774c87aefeSPatrick Mooney 	size_t f_sz;
1784c87aefeSPatrick Mooney 	uint32_t f_data[1024];
1794c87aefeSPatrick Mooney } fget_buf;
1804c87aefeSPatrick Mooney static int fget_cnt;
1814c87aefeSPatrick Mooney static size_t fget_size;
1824c87aefeSPatrick Mooney 
1834c87aefeSPatrick Mooney static int
fget_start(uint32_t len)1844c87aefeSPatrick Mooney fget_start(uint32_t len)
1854c87aefeSPatrick Mooney {
1864c87aefeSPatrick Mooney 
1874c87aefeSPatrick Mooney 	if (len > FGET_STRSZ)
1884c87aefeSPatrick Mooney 		return(E2BIG);
1894c87aefeSPatrick Mooney 
1904c87aefeSPatrick Mooney 	fget_cnt = 0;
1914c87aefeSPatrick Mooney 
1924c87aefeSPatrick Mooney 	return (0);
1934c87aefeSPatrick Mooney }
1944c87aefeSPatrick Mooney 
1954c87aefeSPatrick Mooney static void
fget_data(uint32_t data,uint32_t len __unused)19659d65d31SAndy Fiddaman fget_data(uint32_t data, uint32_t len __unused)
1974c87aefeSPatrick Mooney {
1984c87aefeSPatrick Mooney 
199d35aa001SJohn Baldwin 	assert(fget_cnt + sizeof(uint32_t) <= sizeof(fget_str));
20059d65d31SAndy Fiddaman 	memcpy(&fget_str[fget_cnt], &data, sizeof(data));
2014c87aefeSPatrick Mooney 	fget_cnt += sizeof(uint32_t);
2024c87aefeSPatrick Mooney }
2034c87aefeSPatrick Mooney 
2044c87aefeSPatrick Mooney static int
fget_result(struct iovec ** data,int val)2054c87aefeSPatrick Mooney fget_result(struct iovec **data, int val)
2064c87aefeSPatrick Mooney {
2074c87aefeSPatrick Mooney 	struct ctl *cp;
2084c87aefeSPatrick Mooney 	int err;
2094c87aefeSPatrick Mooney 
2104c87aefeSPatrick Mooney 	err = 0;
2114c87aefeSPatrick Mooney 
2124c87aefeSPatrick Mooney 	/* Locate the OID */
2134c87aefeSPatrick Mooney 	cp = ctl_locate(fget_str, fget_cnt);
2144c87aefeSPatrick Mooney 	if (cp == NULL) {
2154c87aefeSPatrick Mooney 		*data = NULL;
2164c87aefeSPatrick Mooney 		err = ENOENT;
2174c87aefeSPatrick Mooney 	} else {
2184c87aefeSPatrick Mooney 		if (val) {
2194c87aefeSPatrick Mooney 			/* For now, copy the len/data into a buffer */
2204c87aefeSPatrick Mooney 			memset(&fget_buf, 0, sizeof(fget_buf));
2214c87aefeSPatrick Mooney 			fget_buf.f_sz = cp->c_len;
2224c87aefeSPatrick Mooney 			memcpy(fget_buf.f_data, cp->c_data, cp->c_len);
2234c87aefeSPatrick Mooney 			fget_biov[0].iov_base = (char *)&fget_buf;
2244c87aefeSPatrick Mooney 			fget_biov[0].iov_len  = sizeof(fget_buf.f_sz) +
2254c87aefeSPatrick Mooney 				cp->c_len;
2264c87aefeSPatrick Mooney 		} else {
2274c87aefeSPatrick Mooney 			fget_size = cp->c_len;
2284c87aefeSPatrick Mooney 			fget_biov[0].iov_base = (char *)&fget_size;
2294c87aefeSPatrick Mooney 			fget_biov[0].iov_len  = sizeof(fget_size);
2304c87aefeSPatrick Mooney 		}
2314c87aefeSPatrick Mooney 
2324c87aefeSPatrick Mooney 		fget_biov[1].iov_base = NULL;
2334c87aefeSPatrick Mooney 		fget_biov[1].iov_len  = 0;
2344c87aefeSPatrick Mooney 		*data = fget_biov;
2354c87aefeSPatrick Mooney 	}
2364c87aefeSPatrick Mooney 
2374c87aefeSPatrick Mooney 	return (err);
2384c87aefeSPatrick Mooney }
2394c87aefeSPatrick Mooney 
2404c87aefeSPatrick Mooney static void
fget_done(struct iovec * data __unused)24159d65d31SAndy Fiddaman fget_done(struct iovec *data __unused)
2424c87aefeSPatrick Mooney {
2434c87aefeSPatrick Mooney 
2444c87aefeSPatrick Mooney 	/* nothing needs to be freed */
2454c87aefeSPatrick Mooney }
2464c87aefeSPatrick Mooney 
2474c87aefeSPatrick Mooney static int
fget_len_result(struct iovec ** data)2484c87aefeSPatrick Mooney fget_len_result(struct iovec **data)
2494c87aefeSPatrick Mooney {
2504c87aefeSPatrick Mooney 	return (fget_result(data, 0));
2514c87aefeSPatrick Mooney }
2524c87aefeSPatrick Mooney 
2534c87aefeSPatrick Mooney static int
fget_val_result(struct iovec ** data)2544c87aefeSPatrick Mooney fget_val_result(struct iovec **data)
2554c87aefeSPatrick Mooney {
2564c87aefeSPatrick Mooney 	return (fget_result(data, 1));
2574c87aefeSPatrick Mooney }
2584c87aefeSPatrick Mooney 
2594c87aefeSPatrick Mooney static struct op_info fgetlen_info = {
2604c87aefeSPatrick Mooney 	.op_start  = fget_start,
2614c87aefeSPatrick Mooney 	.op_data   = fget_data,
2624c87aefeSPatrick Mooney 	.op_result = fget_len_result,
2634c87aefeSPatrick Mooney 	.op_done   = fget_done
2644c87aefeSPatrick Mooney };
2654c87aefeSPatrick Mooney 
2664c87aefeSPatrick Mooney static struct op_info fgetval_info = {
2674c87aefeSPatrick Mooney 	.op_start  = fget_start,
2684c87aefeSPatrick Mooney 	.op_data   = fget_data,
2694c87aefeSPatrick Mooney 	.op_result = fget_val_result,
2704c87aefeSPatrick Mooney 	.op_done   = fget_done
2714c87aefeSPatrick Mooney };
2724c87aefeSPatrick Mooney 
2734c87aefeSPatrick Mooney static struct req_info {
2744c87aefeSPatrick Mooney 	int      req_error;
2754c87aefeSPatrick Mooney 	u_int    req_count;
2764c87aefeSPatrick Mooney 	uint32_t req_size;
2774c87aefeSPatrick Mooney 	uint32_t req_type;
2784c87aefeSPatrick Mooney 	uint32_t req_txid;
2794c87aefeSPatrick Mooney 	struct op_info *req_op;
2804c87aefeSPatrick Mooney 	int	 resp_error;
2814c87aefeSPatrick Mooney 	int	 resp_count;
2824c87aefeSPatrick Mooney 	size_t	 resp_size;
2834c87aefeSPatrick Mooney 	size_t	 resp_off;
2844c87aefeSPatrick Mooney 	struct iovec *resp_biov;
2854c87aefeSPatrick Mooney } rinfo;
2864c87aefeSPatrick Mooney 
2874c87aefeSPatrick Mooney static void
fwctl_response_done(void)2884c87aefeSPatrick Mooney fwctl_response_done(void)
2894c87aefeSPatrick Mooney {
2904c87aefeSPatrick Mooney 
2914c87aefeSPatrick Mooney 	(*rinfo.req_op->op_done)(rinfo.resp_biov);
2924c87aefeSPatrick Mooney 
2934c87aefeSPatrick Mooney 	/* reinit the req data struct */
2944c87aefeSPatrick Mooney 	memset(&rinfo, 0, sizeof(rinfo));
2954c87aefeSPatrick Mooney }
2964c87aefeSPatrick Mooney 
2974c87aefeSPatrick Mooney static void
fwctl_request_done(void)2984c87aefeSPatrick Mooney fwctl_request_done(void)
2994c87aefeSPatrick Mooney {
3004c87aefeSPatrick Mooney 
3014c87aefeSPatrick Mooney 	rinfo.resp_error = (*rinfo.req_op->op_result)(&rinfo.resp_biov);
3024c87aefeSPatrick Mooney 
3034c87aefeSPatrick Mooney 	/* XXX only a single vector supported at the moment */
3044c87aefeSPatrick Mooney 	rinfo.resp_off = 0;
3054c87aefeSPatrick Mooney 	if (rinfo.resp_biov == NULL) {
3064c87aefeSPatrick Mooney 		rinfo.resp_size = 0;
3074c87aefeSPatrick Mooney 	} else {
3084c87aefeSPatrick Mooney 		rinfo.resp_size = rinfo.resp_biov[0].iov_len;
3094c87aefeSPatrick Mooney 	}
3104c87aefeSPatrick Mooney }
3114c87aefeSPatrick Mooney 
3124c87aefeSPatrick Mooney static int
fwctl_request_start(void)3134c87aefeSPatrick Mooney fwctl_request_start(void)
3144c87aefeSPatrick Mooney {
3154c87aefeSPatrick Mooney 	int err;
3164c87aefeSPatrick Mooney 
3174c87aefeSPatrick Mooney 	/* Data size doesn't include header */
3184c87aefeSPatrick Mooney 	rinfo.req_size -= 12;
3194c87aefeSPatrick Mooney 
3204c87aefeSPatrick Mooney 	rinfo.req_op = &errop_info;
3214c87aefeSPatrick Mooney 	if (rinfo.req_type <= OP_MAX && ops[rinfo.req_type] != NULL)
3224c87aefeSPatrick Mooney 		rinfo.req_op = ops[rinfo.req_type];
3234c87aefeSPatrick Mooney 
3244c87aefeSPatrick Mooney 	err = (*rinfo.req_op->op_start)(rinfo.req_size);
3254c87aefeSPatrick Mooney 
3264c87aefeSPatrick Mooney 	if (err) {
3274c87aefeSPatrick Mooney 		errop_set(err);
3284c87aefeSPatrick Mooney 		rinfo.req_op = &errop_info;
3294c87aefeSPatrick Mooney 	}
3304c87aefeSPatrick Mooney 
3314c87aefeSPatrick Mooney 	/* Catch case of zero-length message here */
3324c87aefeSPatrick Mooney 	if (rinfo.req_size == 0) {
3334c87aefeSPatrick Mooney 		fwctl_request_done();
3344c87aefeSPatrick Mooney 		return (1);
3354c87aefeSPatrick Mooney 	}
3364c87aefeSPatrick Mooney 
3374c87aefeSPatrick Mooney 	return (0);
3384c87aefeSPatrick Mooney }
3394c87aefeSPatrick Mooney 
3404c87aefeSPatrick Mooney static int
fwctl_request_data(uint32_t value)3414c87aefeSPatrick Mooney fwctl_request_data(uint32_t value)
3424c87aefeSPatrick Mooney {
3434c87aefeSPatrick Mooney 
344d35aa001SJohn Baldwin 	/* Make sure remaining size is > 0 */
345d35aa001SJohn Baldwin 	assert(rinfo.req_size > 0);
3464c87aefeSPatrick Mooney 	if (rinfo.req_size <= sizeof(uint32_t))
3474c87aefeSPatrick Mooney 		rinfo.req_size = 0;
3484c87aefeSPatrick Mooney 	else
3494c87aefeSPatrick Mooney 		rinfo.req_size -= sizeof(uint32_t);
3504c87aefeSPatrick Mooney 
3514c87aefeSPatrick Mooney 	(*rinfo.req_op->op_data)(value, rinfo.req_size);
3524c87aefeSPatrick Mooney 
3534c87aefeSPatrick Mooney 	if (rinfo.req_size < sizeof(uint32_t)) {
3544c87aefeSPatrick Mooney 		fwctl_request_done();
3554c87aefeSPatrick Mooney 		return (1);
3564c87aefeSPatrick Mooney 	}
3574c87aefeSPatrick Mooney 
3584c87aefeSPatrick Mooney 	return (0);
3594c87aefeSPatrick Mooney }
3604c87aefeSPatrick Mooney 
3614c87aefeSPatrick Mooney static int
fwctl_request(uint32_t value)3624c87aefeSPatrick Mooney fwctl_request(uint32_t value)
3634c87aefeSPatrick Mooney {
3644c87aefeSPatrick Mooney 
3654c87aefeSPatrick Mooney 	int ret;
3664c87aefeSPatrick Mooney 
3674c87aefeSPatrick Mooney 	ret = 0;
3684c87aefeSPatrick Mooney 
3694c87aefeSPatrick Mooney 	switch (rinfo.req_count) {
3704c87aefeSPatrick Mooney 	case 0:
3714c87aefeSPatrick Mooney 		/* Verify size */
3724c87aefeSPatrick Mooney 		if (value < 12) {
3734c87aefeSPatrick Mooney 			printf("msg size error");
3744c87aefeSPatrick Mooney 			exit(4);
3754c87aefeSPatrick Mooney 		}
3764c87aefeSPatrick Mooney 		rinfo.req_size = value;
3774c87aefeSPatrick Mooney 		rinfo.req_count = 1;
3784c87aefeSPatrick Mooney 		break;
3794c87aefeSPatrick Mooney 	case 1:
3804c87aefeSPatrick Mooney 		rinfo.req_type = value;
3814c87aefeSPatrick Mooney 		rinfo.req_count++;
3824c87aefeSPatrick Mooney 		break;
3834c87aefeSPatrick Mooney 	case 2:
3844c87aefeSPatrick Mooney 		rinfo.req_txid = value;
3854c87aefeSPatrick Mooney 		rinfo.req_count++;
3864c87aefeSPatrick Mooney 		ret = fwctl_request_start();
3874c87aefeSPatrick Mooney 		break;
3884c87aefeSPatrick Mooney 	default:
3894c87aefeSPatrick Mooney 		ret = fwctl_request_data(value);
3904c87aefeSPatrick Mooney 		break;
3914c87aefeSPatrick Mooney 	}
3924c87aefeSPatrick Mooney 
3934c87aefeSPatrick Mooney 	return (ret);
3944c87aefeSPatrick Mooney }
3954c87aefeSPatrick Mooney 
3964c87aefeSPatrick Mooney static int
fwctl_response(uint32_t * retval)3974c87aefeSPatrick Mooney fwctl_response(uint32_t *retval)
3984c87aefeSPatrick Mooney {
39959d65d31SAndy Fiddaman 	uint8_t *dp;
4004c87aefeSPatrick Mooney 	ssize_t remlen;
4014c87aefeSPatrick Mooney 
4024c87aefeSPatrick Mooney 	switch(rinfo.resp_count) {
4034c87aefeSPatrick Mooney 	case 0:
4044c87aefeSPatrick Mooney 		/* 4 x u32 header len + data */
4054c87aefeSPatrick Mooney 		*retval = 4*sizeof(uint32_t) +
4064c87aefeSPatrick Mooney 		    roundup(rinfo.resp_size, sizeof(uint32_t));
4074c87aefeSPatrick Mooney 		rinfo.resp_count++;
4084c87aefeSPatrick Mooney 		break;
4094c87aefeSPatrick Mooney 	case 1:
4104c87aefeSPatrick Mooney 		*retval = rinfo.req_type;
4114c87aefeSPatrick Mooney 		rinfo.resp_count++;
4124c87aefeSPatrick Mooney 		break;
4134c87aefeSPatrick Mooney 	case 2:
4144c87aefeSPatrick Mooney 		*retval = rinfo.req_txid;
4154c87aefeSPatrick Mooney 		rinfo.resp_count++;
4164c87aefeSPatrick Mooney 		break;
4174c87aefeSPatrick Mooney 	case 3:
4184c87aefeSPatrick Mooney 		*retval = rinfo.resp_error;
4194c87aefeSPatrick Mooney 		rinfo.resp_count++;
4204c87aefeSPatrick Mooney 		break;
4214c87aefeSPatrick Mooney 	default:
4224c87aefeSPatrick Mooney 		remlen = rinfo.resp_size - rinfo.resp_off;
42359d65d31SAndy Fiddaman 		dp = (uint8_t *)rinfo.resp_biov->iov_base + rinfo.resp_off;
42459d65d31SAndy Fiddaman 		if (remlen >= (ssize_t)sizeof(uint32_t)) {
42559d65d31SAndy Fiddaman 			memcpy(retval, dp, sizeof(uint32_t));
4264c87aefeSPatrick Mooney 		} else if (remlen > 0) {
4274c87aefeSPatrick Mooney 			*retval = fwctl_send_rest(dp, remlen);
4284c87aefeSPatrick Mooney 		}
4294c87aefeSPatrick Mooney 		rinfo.resp_off += sizeof(uint32_t);
4304c87aefeSPatrick Mooney 		break;
4314c87aefeSPatrick Mooney 	}
4324c87aefeSPatrick Mooney 
4334c87aefeSPatrick Mooney 	if (rinfo.resp_count > 3 &&
4344c87aefeSPatrick Mooney 	    rinfo.resp_off >= rinfo.resp_size) {
4354c87aefeSPatrick Mooney 		fwctl_response_done();
4364c87aefeSPatrick Mooney 		return (1);
4374c87aefeSPatrick Mooney 	}
4384c87aefeSPatrick Mooney 
4394c87aefeSPatrick Mooney 	return (0);
4404c87aefeSPatrick Mooney }
4414c87aefeSPatrick Mooney 
442d35aa001SJohn Baldwin static void
fwctl_reset(void)443d35aa001SJohn Baldwin fwctl_reset(void)
444d35aa001SJohn Baldwin {
445d35aa001SJohn Baldwin 
446d35aa001SJohn Baldwin 	switch (be_state) {
447d35aa001SJohn Baldwin 	case RESP:
448d35aa001SJohn Baldwin 		/* If a response was generated but not fully read, discard it. */
449d35aa001SJohn Baldwin 		fwctl_response_done();
450d35aa001SJohn Baldwin 		break;
451d35aa001SJohn Baldwin 	case REQ:
452d35aa001SJohn Baldwin 		/* Discard partially-received request. */
453d35aa001SJohn Baldwin 		memset(&rinfo, 0, sizeof(rinfo));
454d35aa001SJohn Baldwin 		break;
455d35aa001SJohn Baldwin 	case IDENT_WAIT:
456d35aa001SJohn Baldwin 	case IDENT_SEND:
457d35aa001SJohn Baldwin 		break;
458d35aa001SJohn Baldwin 	}
459d35aa001SJohn Baldwin 
460d35aa001SJohn Baldwin 	be_state = IDENT_SEND;
461d35aa001SJohn Baldwin 	ident_idx = 0;
462d35aa001SJohn Baldwin }
463d35aa001SJohn Baldwin 
4644c87aefeSPatrick Mooney 
4654c87aefeSPatrick Mooney /*
4664c87aefeSPatrick Mooney  * i/o port handling.
4674c87aefeSPatrick Mooney  */
4684c87aefeSPatrick Mooney static uint8_t
fwctl_inb(void)4694c87aefeSPatrick Mooney fwctl_inb(void)
4704c87aefeSPatrick Mooney {
4714c87aefeSPatrick Mooney 	uint8_t retval;
4724c87aefeSPatrick Mooney 
4734c87aefeSPatrick Mooney 	retval = 0xff;
4744c87aefeSPatrick Mooney 
4754c87aefeSPatrick Mooney 	switch (be_state) {
4764c87aefeSPatrick Mooney 	case IDENT_SEND:
4774c87aefeSPatrick Mooney 		retval = sig[ident_idx++];
4784c87aefeSPatrick Mooney 		if (ident_idx >= sizeof(sig))
4794c87aefeSPatrick Mooney 			be_state = REQ;
4804c87aefeSPatrick Mooney 		break;
4814c87aefeSPatrick Mooney 	default:
4824c87aefeSPatrick Mooney 		break;
4834c87aefeSPatrick Mooney 	}
4844c87aefeSPatrick Mooney 
4854c87aefeSPatrick Mooney 	return (retval);
4864c87aefeSPatrick Mooney }
4874c87aefeSPatrick Mooney 
4884c87aefeSPatrick Mooney static void
fwctl_outw(uint16_t val)4894c87aefeSPatrick Mooney fwctl_outw(uint16_t val)
4904c87aefeSPatrick Mooney {
4916dc98349SAndy Fiddaman 	if (val == 0) {
4926dc98349SAndy Fiddaman 		/*
4936dc98349SAndy Fiddaman 		 * The guest wants to read the signature. It's possible that the
4946dc98349SAndy Fiddaman 		 * guest is unaware of the fwctl state at this moment. For that
4956dc98349SAndy Fiddaman 		 * reason, reset the state machine unconditionally.
4966dc98349SAndy Fiddaman 		 */
497d35aa001SJohn Baldwin 		fwctl_reset();
4984c87aefeSPatrick Mooney 	}
4994c87aefeSPatrick Mooney }
5004c87aefeSPatrick Mooney 
5014c87aefeSPatrick Mooney static uint32_t
fwctl_inl(void)5024c87aefeSPatrick Mooney fwctl_inl(void)
5034c87aefeSPatrick Mooney {
5044c87aefeSPatrick Mooney 	uint32_t retval;
5054c87aefeSPatrick Mooney 
5064c87aefeSPatrick Mooney 	switch (be_state) {
5074c87aefeSPatrick Mooney 	case RESP:
5084c87aefeSPatrick Mooney 		if (fwctl_response(&retval))
5094c87aefeSPatrick Mooney 			be_state = REQ;
5104c87aefeSPatrick Mooney 		break;
5114c87aefeSPatrick Mooney 	default:
5124c87aefeSPatrick Mooney 		retval = 0xffffffff;
5134c87aefeSPatrick Mooney 		break;
5144c87aefeSPatrick Mooney 	}
5154c87aefeSPatrick Mooney 
5164c87aefeSPatrick Mooney 	return (retval);
5174c87aefeSPatrick Mooney }
5184c87aefeSPatrick Mooney 
5194c87aefeSPatrick Mooney static void
fwctl_outl(uint32_t val)5204c87aefeSPatrick Mooney fwctl_outl(uint32_t val)
5214c87aefeSPatrick Mooney {
5224c87aefeSPatrick Mooney 
5234c87aefeSPatrick Mooney 	switch (be_state) {
5244c87aefeSPatrick Mooney 	case REQ:
5254c87aefeSPatrick Mooney 		if (fwctl_request(val))
5264c87aefeSPatrick Mooney 			be_state = RESP;
5274c87aefeSPatrick Mooney 	default:
5284c87aefeSPatrick Mooney 		break;
5294c87aefeSPatrick Mooney 	}
5304c87aefeSPatrick Mooney 
5314c87aefeSPatrick Mooney }
5324c87aefeSPatrick Mooney 
5334c87aefeSPatrick Mooney static int
fwctl_handler(struct vmctx * ctx __unused,int in,int port __unused,int bytes,uint32_t * eax,void * arg __unused)53459d65d31SAndy Fiddaman fwctl_handler(struct vmctx *ctx __unused, int in,
53559d65d31SAndy Fiddaman     int port __unused, int bytes, uint32_t *eax, void *arg __unused)
5364c87aefeSPatrick Mooney {
5374c87aefeSPatrick Mooney 
5384c87aefeSPatrick Mooney 	if (in) {
5394c87aefeSPatrick Mooney 		if (bytes == 1)
5404c87aefeSPatrick Mooney 			*eax = fwctl_inb();
5414c87aefeSPatrick Mooney 		else if (bytes == 4)
5424c87aefeSPatrick Mooney 			*eax = fwctl_inl();
5434c87aefeSPatrick Mooney 		else
5444c87aefeSPatrick Mooney 			*eax = 0xffff;
5454c87aefeSPatrick Mooney 	} else {
5464c87aefeSPatrick Mooney 		if (bytes == 2)
5474c87aefeSPatrick Mooney 			fwctl_outw(*eax);
5484c87aefeSPatrick Mooney 		else if (bytes == 4)
5494c87aefeSPatrick Mooney 			fwctl_outl(*eax);
5504c87aefeSPatrick Mooney 	}
5514c87aefeSPatrick Mooney 
5524c87aefeSPatrick Mooney 	return (0);
5534c87aefeSPatrick Mooney }
5544c87aefeSPatrick Mooney 
5554c87aefeSPatrick Mooney void
fwctl_init(void)5564c87aefeSPatrick Mooney fwctl_init(void)
5574c87aefeSPatrick Mooney {
5586dc98349SAndy Fiddaman 	struct inout_port iop;
5596dc98349SAndy Fiddaman 	int error;
5606dc98349SAndy Fiddaman 
5616dc98349SAndy Fiddaman 	bzero(&iop, sizeof(iop));
5626dc98349SAndy Fiddaman 	iop.name = "fwctl_wreg";
5636dc98349SAndy Fiddaman 	iop.port = FWCTL_OUT;
5646dc98349SAndy Fiddaman 	iop.size = 1;
5656dc98349SAndy Fiddaman 	iop.flags = IOPORT_F_INOUT;
5666dc98349SAndy Fiddaman 	iop.handler = fwctl_handler;
5676dc98349SAndy Fiddaman 
5686dc98349SAndy Fiddaman 	error = register_inout(&iop);
5696dc98349SAndy Fiddaman 	assert(error == 0);
5706dc98349SAndy Fiddaman 
5716dc98349SAndy Fiddaman 	bzero(&iop, sizeof(iop));
5726dc98349SAndy Fiddaman 	iop.name = "fwctl_rreg";
5736dc98349SAndy Fiddaman 	iop.port = FWCTL_IN;
5746dc98349SAndy Fiddaman 	iop.size = 1;
5756dc98349SAndy Fiddaman 	iop.flags = IOPORT_F_IN;
5766dc98349SAndy Fiddaman 	iop.handler = fwctl_handler;
5776dc98349SAndy Fiddaman 
5786dc98349SAndy Fiddaman 	error = register_inout(&iop);
5796dc98349SAndy Fiddaman 	assert(error == 0);
5804c87aefeSPatrick Mooney 
5814c87aefeSPatrick Mooney 	ops[OP_GET_LEN] = &fgetlen_info;
5824c87aefeSPatrick Mooney 	ops[OP_GET]     = &fgetval_info;
5834c87aefeSPatrick Mooney 
5844c87aefeSPatrick Mooney 	be_state = IDENT_WAIT;
5854c87aefeSPatrick Mooney }
586