15325 bhyve upstream sync 2023 January
[illumos-gate.git] / usr / src / cmd / bhyve / inout.c
blobb4add9da7a42134d4e16ddc1b2e4f18adf699fc0
1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2011 NetApp, Inc.
5 * All rights reserved.
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.
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.
28 * $FreeBSD$
31 * This file and its contents are supplied under the terms of the
32 * Common Development and Distribution License ("CDDL"), version 1.0.
33 * You may only use this file in accordance with the terms of version
34 * 1.0 of the CDDL.
36 * A full copy of the text of the CDDL should have accompanied this
37 * source. A copy of the CDDL is also available via the Internet at
38 * http://www.illumos.org/license/CDDL.
40 * Copyright 2020 Oxide Computer Company
43 #include <sys/cdefs.h>
44 __FBSDID("$FreeBSD$");
46 #include <sys/param.h>
47 #include <sys/linker_set.h>
48 #include <sys/_iovec.h>
49 #include <sys/mman.h>
51 #include <x86/psl.h>
52 #include <x86/segments.h>
54 #include <machine/vmm.h>
55 #include <vmmapi.h>
57 #include <stdio.h>
58 #include <string.h>
59 #include <assert.h>
61 #include "bhyverun.h"
62 #include "config.h"
63 #include "inout.h"
65 SET_DECLARE(inout_port_set, struct inout_port);
67 #define MAX_IOPORTS (1 << 16)
69 #define VERIFY_IOPORT(port, size) \
70 assert((port) >= 0 && (size) > 0 && ((port) + (size)) <= MAX_IOPORTS)
72 struct inout_handler {
73 const char *name;
74 int flags;
75 inout_func_t handler;
76 void *arg;
79 static struct inout_handler inout_handlers[MAX_IOPORTS];
81 static int
82 default_inout(struct vmctx *ctx __unused, int in,
83 int port __unused, int bytes, uint32_t *eax, void *arg __unused)
85 if (in) {
86 switch (bytes) {
87 case 4:
88 *eax = 0xffffffff;
89 break;
90 case 2:
91 *eax = 0xffff;
92 break;
93 case 1:
94 *eax = 0xff;
95 break;
99 return (0);
102 static void
103 register_default_iohandler(int start, int size)
105 struct inout_port iop;
107 VERIFY_IOPORT(start, size);
109 bzero(&iop, sizeof(iop));
110 iop.name = "default";
111 iop.port = start;
112 iop.size = size;
113 iop.flags = IOPORT_F_INOUT | IOPORT_F_DEFAULT;
114 iop.handler = default_inout;
116 register_inout(&iop);
120 emulate_inout(struct vmctx *ctx, int vcpu, struct vm_inout *inout)
122 struct inout_handler handler;
123 inout_func_t hfunc;
124 void *harg;
125 int error;
126 uint8_t bytes;
127 bool in;
129 bytes = inout->bytes;
130 in = (inout->flags & INOUT_IN) != 0;
132 assert(bytes == 1 || bytes == 2 || bytes == 4);
134 handler = inout_handlers[inout->port];
135 hfunc = handler.handler;
136 harg = handler.arg;
138 if (hfunc == default_inout &&
139 get_config_bool_default("x86.strictio", false))
140 return (-1);
142 if (in) {
143 if (!(handler.flags & IOPORT_F_IN))
144 return (-1);
145 } else {
146 if (!(handler.flags & IOPORT_F_OUT))
147 return (-1);
150 error = hfunc(ctx, in, inout->port, bytes, &inout->eax, harg);
151 return (error);
154 void
155 init_inout(void)
157 struct inout_port **iopp, *iop;
160 * Set up the default handler for all ports
162 register_default_iohandler(0, MAX_IOPORTS);
165 * Overwrite with specified handlers
167 SET_FOREACH(iopp, inout_port_set) {
168 iop = *iopp;
169 assert(iop->port < MAX_IOPORTS);
170 inout_handlers[iop->port].name = iop->name;
171 inout_handlers[iop->port].flags = iop->flags;
172 inout_handlers[iop->port].handler = iop->handler;
173 inout_handlers[iop->port].arg = NULL;
178 register_inout(struct inout_port *iop)
180 int i;
182 VERIFY_IOPORT(iop->port, iop->size);
185 * Verify that the new registration is not overwriting an already
186 * allocated i/o range.
188 if ((iop->flags & IOPORT_F_DEFAULT) == 0) {
189 for (i = iop->port; i < iop->port + iop->size; i++) {
190 if ((inout_handlers[i].flags & IOPORT_F_DEFAULT) == 0)
191 return (-1);
195 for (i = iop->port; i < iop->port + iop->size; i++) {
196 inout_handlers[i].name = iop->name;
197 inout_handlers[i].flags = iop->flags;
198 inout_handlers[i].handler = iop->handler;
199 inout_handlers[i].arg = iop->arg;
202 return (0);
206 unregister_inout(struct inout_port *iop)
209 VERIFY_IOPORT(iop->port, iop->size);
210 assert(inout_handlers[iop->port].name == iop->name);
212 register_default_iohandler(iop->port, iop->size);
214 return (0);