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$ 27 */ 28 29#include <sys/cdefs.h> 30__FBSDID("$FreeBSD$"); 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; 99 inout_func_t handler; 100 void *arg; 101 102 assert(port < MAX_IOPORTS); 103 104 handler = inout_handlers[port].handler; 105 106 if (strict && handler == default_inout) 107 return (-1); 108 109 if (!in) { 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 *eax = *eax & mask; 122 } 123 124 flags = inout_handlers[port].flags; 125 arg = inout_handlers[port].arg; 126 127 if ((in && (flags & IOPORT_F_IN)) || (!in && (flags & IOPORT_F_OUT))) 128 return ((*handler)(ctx, vcpu, in, port, bytes, eax, arg)); 129 else 130 return (-1); 131} 132 133void 134init_inout(void) 135{ 136 struct inout_port **iopp, *iop; 137 138 /* 139 * Set up the default handler for all ports 140 */ 141 register_default_iohandler(0, MAX_IOPORTS); 142 143 /* 144 * Overwrite with specified handlers 145 */ 146 SET_FOREACH(iopp, inout_port_set) { 147 iop = *iopp; 148 assert(iop->port < MAX_IOPORTS); 149 inout_handlers[iop->port].name = iop->name; 150 inout_handlers[iop->port].flags = iop->flags; 151 inout_handlers[iop->port].handler = iop->handler; 152 inout_handlers[iop->port].arg = NULL; 153 } 154} 155 156int 157register_inout(struct inout_port *iop) 158{ 159 int i; 160 161 VERIFY_IOPORT(iop->port, iop->size); 162 163 /* 164 * Verify that the new registration is not overwriting an already 165 * allocated i/o range. 166 */ 167 if ((iop->flags & IOPORT_F_DEFAULT) == 0) { 168 for (i = iop->port; i < iop->port + iop->size; i++) { 169 if ((inout_handlers[i].flags & IOPORT_F_DEFAULT) == 0) 170 return (-1); 171 } 172 } 173 174 for (i = iop->port; i < iop->port + iop->size; i++) { 175 inout_handlers[i].name = iop->name; 176 inout_handlers[i].flags = iop->flags; 177 inout_handlers[i].handler = iop->handler; 178 inout_handlers[i].arg = iop->arg; 179 } 180 181 return (0); 182} 183 184int 185unregister_inout(struct inout_port *iop) 186{ 187 188 VERIFY_IOPORT(iop->port, iop->size); 189 assert(inout_handlers[iop->port].name == iop->name); 190 191 register_default_iohandler(iop->port, iop->size); 192 193 return (0); 194} 195