2 * Copyright (c) 2011 NetApp, Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
32 #include <sys/param.h>
33 #include <sys/linker_set.h>
34 #include <sys/_iovec.h>
38 #include <x86/segments.h>
40 #include <machine/vmm.h>
41 #include <machine/vmm_instruction_emul.h>
51 SET_DECLARE(inout_port_set
, struct inout_port
);
53 #define MAX_IOPORTS (1 << 16)
55 #define VERIFY_IOPORT(port, size) \
56 assert((port) >= 0 && (size) > 0 && ((port) + (size)) <= MAX_IOPORTS)
63 } inout_handlers
[MAX_IOPORTS
];
66 default_inout(struct vmctx
*ctx
, int vcpu
, int in
, int port
, int bytes
,
67 uint32_t *eax
, void *arg
)
87 register_default_iohandler(int start
, int size
)
89 struct inout_port iop
;
91 VERIFY_IOPORT(start
, size
);
93 bzero(&iop
, sizeof(iop
));
97 iop
.flags
= IOPORT_F_INOUT
| IOPORT_F_DEFAULT
;
98 iop
.handler
= default_inout
;
100 register_inout(&iop
);
104 emulate_inout(struct vmctx
*ctx
, int vcpu
, struct vm_exit
*vmexit
, int strict
)
106 int addrsize
, bytes
, flags
, in
, port
, prot
, rep
;
108 inout_func_t handler
;
110 int error
, fault
, retval
;
111 enum vm_reg_name idxreg
;
112 uint64_t gla
, index
, iterations
, count
;
113 struct vm_inout_str
*vis
;
116 bytes
= vmexit
->u
.inout
.bytes
;
117 in
= vmexit
->u
.inout
.in
;
118 port
= vmexit
->u
.inout
.port
;
120 assert(port
< MAX_IOPORTS
);
121 assert(bytes
== 1 || bytes
== 2 || bytes
== 4);
123 handler
= inout_handlers
[port
].handler
;
125 if (strict
&& handler
== default_inout
)
128 flags
= inout_handlers
[port
].flags
;
129 arg
= inout_handlers
[port
].arg
;
132 if (!(flags
& IOPORT_F_IN
))
135 if (!(flags
& IOPORT_F_OUT
))
140 if (vmexit
->u
.inout
.string
) {
141 vis
= &vmexit
->u
.inout_str
;
142 rep
= vis
->inout
.rep
;
143 addrsize
= vis
->addrsize
;
144 prot
= in
? PROT_WRITE
: PROT_READ
;
145 assert(addrsize
== 2 || addrsize
== 4 || addrsize
== 8);
148 idxreg
= in
? VM_REG_GUEST_RDI
: VM_REG_GUEST_RSI
;
149 index
= vis
->index
& vie_size2mask(addrsize
);
152 count
= vis
->count
& vie_size2mask(addrsize
);
154 /* Limit number of back-to-back in/out emulations to 16 */
155 iterations
= MIN(count
, 16);
156 while (iterations
> 0) {
158 if (vie_calculate_gla(vis
->paging
.cpu_mode
,
159 vis
->seg_name
, &vis
->seg_desc
, index
, bytes
,
160 addrsize
, prot
, &gla
)) {
161 vm_inject_gp(ctx
, vcpu
);
165 error
= vm_copy_setup(ctx
, vcpu
, &vis
->paging
, gla
,
166 bytes
, prot
, iov
, nitems(iov
), &fault
);
168 retval
= -1; /* Unrecoverable error */
171 retval
= 0; /* Resume guest to handle fault */
175 if (vie_alignment_check(vis
->paging
.cpl
, bytes
,
176 vis
->cr0
, vis
->rflags
, gla
)) {
177 vm_inject_ac(ctx
, vcpu
, 0);
183 vm_copyin(ctx
, vcpu
, iov
, &val
, bytes
);
185 retval
= handler(ctx
, vcpu
, in
, port
, bytes
, &val
, arg
);
190 vm_copyout(ctx
, vcpu
, &val
, iov
, bytes
);
193 if (vis
->rflags
& PSL_D
)
202 /* Update index register */
203 error
= vie_update_register(ctx
, vcpu
, idxreg
, index
, addrsize
);
207 * Update count register only if the instruction had a repeat
211 error
= vie_update_register(ctx
, vcpu
, VM_REG_GUEST_RCX
,
216 /* Restart the instruction if more iterations remain */
217 if (retval
== 0 && count
!= 0) {
218 error
= vm_restart_instruction(ctx
, vcpu
);
222 eax
= vmexit
->u
.inout
.eax
;
223 val
= eax
& vie_size2mask(bytes
);
224 retval
= handler(ctx
, vcpu
, in
, port
, bytes
, &val
, arg
);
225 if (retval
== 0 && in
) {
226 eax
&= ~vie_size2mask(bytes
);
227 eax
|= val
& vie_size2mask(bytes
);
228 error
= vm_set_register(ctx
, vcpu
, VM_REG_GUEST_RAX
,
239 struct inout_port
**iopp
, *iop
;
242 * Set up the default handler for all ports
244 register_default_iohandler(0, MAX_IOPORTS
);
247 * Overwrite with specified handlers
249 SET_FOREACH(iopp
, inout_port_set
) {
251 assert(iop
->port
< MAX_IOPORTS
);
252 inout_handlers
[iop
->port
].name
= iop
->name
;
253 inout_handlers
[iop
->port
].flags
= iop
->flags
;
254 inout_handlers
[iop
->port
].handler
= iop
->handler
;
255 inout_handlers
[iop
->port
].arg
= NULL
;
260 register_inout(struct inout_port
*iop
)
264 VERIFY_IOPORT(iop
->port
, iop
->size
);
267 * Verify that the new registration is not overwriting an already
268 * allocated i/o range.
270 if ((iop
->flags
& IOPORT_F_DEFAULT
) == 0) {
271 for (i
= iop
->port
; i
< iop
->port
+ iop
->size
; i
++) {
272 if ((inout_handlers
[i
].flags
& IOPORT_F_DEFAULT
) == 0)
277 for (i
= iop
->port
; i
< iop
->port
+ iop
->size
; i
++) {
278 inout_handlers
[i
].name
= iop
->name
;
279 inout_handlers
[i
].flags
= iop
->flags
;
280 inout_handlers
[i
].handler
= iop
->handler
;
281 inout_handlers
[i
].arg
= iop
->arg
;
288 unregister_inout(struct inout_port
*iop
)
291 VERIFY_IOPORT(iop
->port
, iop
->size
);
292 assert(inout_handlers
[iop
->port
].name
== iop
->name
);
294 register_default_iohandler(iop
->port
, iop
->size
);