1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2011 NetApp, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 /* 29 * This file and its contents are supplied under the terms of the 30 * Common Development and Distribution License ("CDDL"), version 1.0. 31 * You may only use this file in accordance with the terms of version 32 * 1.0 of the CDDL. 33 * 34 * A full copy of the text of the CDDL should have accompanied this 35 * source. A copy of the CDDL is also available via the Internet at 36 * http://www.illumos.org/license/CDDL. 37 * 38 * Copyright 2020 Oxide Computer Company 39 */ 40 41 #include <sys/cdefs.h> 42 43 #include <sys/param.h> 44 #include <sys/linker_set.h> 45 #include <sys/_iovec.h> 46 #include <sys/mman.h> 47 48 #include <x86/psl.h> 49 #include <x86/segments.h> 50 51 #include <machine/vmm.h> 52 #include <vmmapi.h> 53 54 #include <stdio.h> 55 #include <string.h> 56 #include <assert.h> 57 58 #include "bhyverun.h" 59 #include "config.h" 60 #include "inout.h" 61 62 SET_DECLARE(inout_port_set, struct inout_port); 63 64 #define MAX_IOPORTS (1 << 16) 65 66 #define VERIFY_IOPORT(port, size) \ 67 assert((port) >= 0 && (size) > 0 && ((port) + (size)) <= MAX_IOPORTS) 68 69 struct inout_handler { 70 const char *name; 71 int flags; 72 inout_func_t handler; 73 void *arg; 74 }; 75 76 static struct inout_handler inout_handlers[MAX_IOPORTS]; 77 78 static int 79 default_inout(struct vmctx *ctx __unused, int in, 80 int port __unused, int bytes, uint32_t *eax, void *arg __unused) 81 { 82 if (in) { 83 switch (bytes) { 84 case 4: 85 *eax = 0xffffffff; 86 break; 87 case 2: 88 *eax = 0xffff; 89 break; 90 case 1: 91 *eax = 0xff; 92 break; 93 } 94 } 95 96 return (0); 97 } 98 99 static void 100 register_default_iohandler(int start, int size) 101 { 102 struct inout_port iop; 103 104 VERIFY_IOPORT(start, size); 105 106 bzero(&iop, sizeof(iop)); 107 iop.name = "default"; 108 iop.port = start; 109 iop.size = size; 110 iop.flags = IOPORT_F_INOUT | IOPORT_F_DEFAULT; 111 iop.handler = default_inout; 112 113 register_inout(&iop); 114 } 115 116 int 117 emulate_inout(struct vmctx *ctx, struct vcpu *vcpu, struct vm_inout *inout) 118 { 119 struct inout_handler handler; 120 inout_func_t hfunc; 121 void *harg; 122 int error; 123 uint8_t bytes; 124 bool in; 125 126 bytes = inout->bytes; 127 in = (inout->flags & INOUT_IN) != 0; 128 129 assert(bytes == 1 || bytes == 2 || bytes == 4); 130 131 handler = inout_handlers[inout->port]; 132 hfunc = handler.handler; 133 harg = handler.arg; 134 135 if (hfunc == default_inout && 136 get_config_bool_default("x86.strictio", false)) 137 return (-1); 138 139 if (in) { 140 if (!(handler.flags & IOPORT_F_IN)) 141 return (-1); 142 } else { 143 if (!(handler.flags & IOPORT_F_OUT)) 144 return (-1); 145 } 146 147 error = hfunc(ctx, in, inout->port, bytes, &inout->eax, harg); 148 return (error); 149 } 150 151 void 152 init_inout(void) 153 { 154 struct inout_port **iopp, *iop; 155 156 /* 157 * Set up the default handler for all ports 158 */ 159 register_default_iohandler(0, MAX_IOPORTS); 160 161 /* 162 * Overwrite with specified handlers 163 */ 164 SET_FOREACH(iopp, inout_port_set) { 165 iop = *iopp; 166 assert(iop->port < MAX_IOPORTS); 167 inout_handlers[iop->port].name = iop->name; 168 inout_handlers[iop->port].flags = iop->flags; 169 inout_handlers[iop->port].handler = iop->handler; 170 inout_handlers[iop->port].arg = NULL; 171 } 172 } 173 174 int 175 register_inout(struct inout_port *iop) 176 { 177 int i; 178 179 VERIFY_IOPORT(iop->port, iop->size); 180 181 /* 182 * Verify that the new registration is not overwriting an already 183 * allocated i/o range. 184 */ 185 if ((iop->flags & IOPORT_F_DEFAULT) == 0) { 186 for (i = iop->port; i < iop->port + iop->size; i++) { 187 if ((inout_handlers[i].flags & IOPORT_F_DEFAULT) == 0) 188 return (-1); 189 } 190 } 191 192 for (i = iop->port; i < iop->port + iop->size; i++) { 193 inout_handlers[i].name = iop->name; 194 inout_handlers[i].flags = iop->flags; 195 inout_handlers[i].handler = iop->handler; 196 inout_handlers[i].arg = iop->arg; 197 } 198 199 return (0); 200 } 201 202 int 203 unregister_inout(struct inout_port *iop) 204 { 205 206 VERIFY_IOPORT(iop->port, iop->size); 207 assert(inout_handlers[iop->port].name == iop->name); 208 209 register_default_iohandler(iop->port, iop->size); 210 211 return (0); 212 } 213