2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2011 NetApp, Inc.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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
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>
52 #include <x86/segments.h>
54 #include <machine/vmm.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
{
79 static struct inout_handler inout_handlers
[MAX_IOPORTS
];
82 default_inout(struct vmctx
*ctx __unused
, int in
,
83 int port __unused
, int bytes
, uint32_t *eax
, void *arg __unused
)
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";
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
;
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
;
138 if (hfunc
== default_inout
&&
139 get_config_bool_default("x86.strictio", false))
143 if (!(handler
.flags
& IOPORT_F_IN
))
146 if (!(handler
.flags
& IOPORT_F_OUT
))
150 error
= hfunc(ctx
, in
, inout
->port
, bytes
, &inout
->eax
, harg
);
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
) {
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
)
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)
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
;
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
);