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