inout.c revision 268953
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 268953 2014-07-21 19:08:02Z jhb $ 27 */ 28 29#include <sys/cdefs.h> 30__FBSDID("$FreeBSD: stable/10/usr.sbin/bhyve/inout.c 268953 2014-07-21 19:08:02Z 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 switch (bytes) { 111 case 1: 112 mask = 0xff; 113 break; 114 case 2: 115 mask = 0xffff; 116 break; 117 default: 118 mask = 0xffffffff; 119 break; 120 } 121 122 if (!in) { 123 val = *eax & mask; 124 } 125 126 flags = inout_handlers[port].flags; 127 arg = inout_handlers[port].arg; 128 129 if ((in && (flags & IOPORT_F_IN)) || (!in && (flags & IOPORT_F_OUT))) 130 error = (*handler)(ctx, vcpu, in, port, bytes, &val, arg); 131 else 132 error = -1; 133 134 if (!error && in) { 135 *eax &= ~mask; 136 *eax |= val & mask; 137 } 138 139 return (error); 140} 141 142void 143init_inout(void) 144{ 145 struct inout_port **iopp, *iop; 146 147 /* 148 * Set up the default handler for all ports 149 */ 150 register_default_iohandler(0, MAX_IOPORTS); 151 152 /* 153 * Overwrite with specified handlers 154 */ 155 SET_FOREACH(iopp, inout_port_set) { 156 iop = *iopp; 157 assert(iop->port < MAX_IOPORTS); 158 inout_handlers[iop->port].name = iop->name; 159 inout_handlers[iop->port].flags = iop->flags; 160 inout_handlers[iop->port].handler = iop->handler; 161 inout_handlers[iop->port].arg = NULL; 162 } 163} 164 165int 166register_inout(struct inout_port *iop) 167{ 168 int i; 169 170 VERIFY_IOPORT(iop->port, iop->size); 171 172 /* 173 * Verify that the new registration is not overwriting an already 174 * allocated i/o range. 175 */ 176 if ((iop->flags & IOPORT_F_DEFAULT) == 0) { 177 for (i = iop->port; i < iop->port + iop->size; i++) { 178 if ((inout_handlers[i].flags & IOPORT_F_DEFAULT) == 0) 179 return (-1); 180 } 181 } 182 183 for (i = iop->port; i < iop->port + iop->size; i++) { 184 inout_handlers[i].name = iop->name; 185 inout_handlers[i].flags = iop->flags; 186 inout_handlers[i].handler = iop->handler; 187 inout_handlers[i].arg = iop->arg; 188 } 189 190 return (0); 191} 192 193int 194unregister_inout(struct inout_port *iop) 195{ 196 197 VERIFY_IOPORT(iop->port, iop->size); 198 assert(inout_handlers[iop->port].name == iop->name); 199 200 register_default_iohandler(iop->port, iop->size); 201 202 return (0); 203} 204