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