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