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