1762fd208STycho Nightingale /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3ebc3c37cSMarcelo Araujo *
4762fd208STycho Nightingale * Copyright (c) 2014 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
5762fd208STycho Nightingale * All rights reserved.
6762fd208STycho Nightingale *
7762fd208STycho Nightingale * Redistribution and use in source and binary forms, with or without
8762fd208STycho Nightingale * modification, are permitted provided that the following conditions
9762fd208STycho Nightingale * are met:
10762fd208STycho Nightingale * 1. Redistributions of source code must retain the above copyright
11762fd208STycho Nightingale * notice, this list of conditions and the following disclaimer.
12762fd208STycho Nightingale * 2. Redistributions in binary form must reproduce the above copyright
13762fd208STycho Nightingale * notice, this list of conditions and the following disclaimer in the
14762fd208STycho Nightingale * documentation and/or other materials provided with the distribution.
15762fd208STycho Nightingale *
16762fd208STycho Nightingale * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
17762fd208STycho Nightingale * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18762fd208STycho Nightingale * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19762fd208STycho Nightingale * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20762fd208STycho Nightingale * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21762fd208STycho Nightingale * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22762fd208STycho Nightingale * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23762fd208STycho Nightingale * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24762fd208STycho Nightingale * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25762fd208STycho Nightingale * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26762fd208STycho Nightingale * SUCH DAMAGE.
27762fd208STycho Nightingale */
28762fd208STycho Nightingale
29762fd208STycho Nightingale #include <sys/param.h>
30762fd208STycho Nightingale #include <sys/systm.h>
31762fd208STycho Nightingale
32762fd208STycho Nightingale #include <machine/vmm.h>
33e813a873SNeel Natu #include <machine/vmm_instruction_emul.h>
34762fd208STycho Nightingale
353ccb0233SMark Johnston #include <dev/vmm/vmm_ktr.h>
363ccb0233SMark Johnston
37762fd208STycho Nightingale #include "vatpic.h"
38e883c9bbSTycho Nightingale #include "vatpit.h"
39160ef77aSNeel Natu #include "vpmtmr.h"
400dafa5cdSNeel Natu #include "vrtc.h"
41762fd208STycho Nightingale #include "vmm_ioport.h"
42762fd208STycho Nightingale
43762fd208STycho Nightingale #define MAX_IOPORTS 1280
44762fd208STycho Nightingale
45762fd208STycho Nightingale ioport_handler_func_t ioport_handler[MAX_IOPORTS] = {
46e883c9bbSTycho Nightingale [TIMER_MODE] = vatpit_handler,
47e883c9bbSTycho Nightingale [TIMER_CNTR0] = vatpit_handler,
48e883c9bbSTycho Nightingale [TIMER_CNTR1] = vatpit_handler,
49e883c9bbSTycho Nightingale [TIMER_CNTR2] = vatpit_handler,
5079d6ca33STycho Nightingale [NMISC_PORT] = vatpit_nmisc_handler,
51762fd208STycho Nightingale [IO_ICU1] = vatpic_master_handler,
52762fd208STycho Nightingale [IO_ICU1 + ICU_IMR_OFFSET] = vatpic_master_handler,
53762fd208STycho Nightingale [IO_ICU2] = vatpic_slave_handler,
54762fd208STycho Nightingale [IO_ICU2 + ICU_IMR_OFFSET] = vatpic_slave_handler,
55762fd208STycho Nightingale [IO_ELCR1] = vatpic_elc_handler,
56762fd208STycho Nightingale [IO_ELCR2] = vatpic_elc_handler,
57160ef77aSNeel Natu [IO_PMTMR] = vpmtmr_handler,
580dafa5cdSNeel Natu [IO_RTC] = vrtc_addr_handler,
590dafa5cdSNeel Natu [IO_RTC + 1] = vrtc_data_handler,
60762fd208STycho Nightingale };
61762fd208STycho Nightingale
62d17b5104SNeel Natu #ifdef KTR
63d17b5104SNeel Natu static const char *
inout_instruction(struct vm_exit * vmexit)64d17b5104SNeel Natu inout_instruction(struct vm_exit *vmexit)
65d17b5104SNeel Natu {
66d17b5104SNeel Natu int index;
67d17b5104SNeel Natu
68d17b5104SNeel Natu static const char *iodesc[] = {
69d17b5104SNeel Natu "outb", "outw", "outl",
70d17b5104SNeel Natu "inb", "inw", "inl",
7107820b4bSNeel Natu "outsb", "outsw", "outsd",
72d17b5104SNeel Natu "insb", "insw", "insd",
73d17b5104SNeel Natu };
74d17b5104SNeel Natu
75d17b5104SNeel Natu switch (vmexit->u.inout.bytes) {
76d17b5104SNeel Natu case 1:
77d17b5104SNeel Natu index = 0;
78d17b5104SNeel Natu break;
79d17b5104SNeel Natu case 2:
80d17b5104SNeel Natu index = 1;
81d17b5104SNeel Natu break;
82d17b5104SNeel Natu default:
83d17b5104SNeel Natu index = 2;
84d17b5104SNeel Natu break;
85d17b5104SNeel Natu }
86d17b5104SNeel Natu
87d17b5104SNeel Natu if (vmexit->u.inout.in)
88d17b5104SNeel Natu index += 3;
89d17b5104SNeel Natu
90d17b5104SNeel Natu if (vmexit->u.inout.string)
91d17b5104SNeel Natu index += 6;
92d17b5104SNeel Natu
93d17b5104SNeel Natu KASSERT(index < nitems(iodesc), ("%s: invalid index %d",
94d17b5104SNeel Natu __func__, index));
95d17b5104SNeel Natu
96d17b5104SNeel Natu return (iodesc[index]);
97d17b5104SNeel Natu }
98d17b5104SNeel Natu #endif /* KTR */
99d17b5104SNeel Natu
100d17b5104SNeel Natu static int
emulate_inout_port(struct vcpu * vcpu,struct vm_exit * vmexit,bool * retu)1013f0f4b15SJohn Baldwin emulate_inout_port(struct vcpu *vcpu, struct vm_exit *vmexit, bool *retu)
102762fd208STycho Nightingale {
103762fd208STycho Nightingale ioport_handler_func_t handler;
104*94693ec7SPierre Pronchery uint32_t mask, val = 0;
105d6aa08c3STycho Nightingale int error;
106762fd208STycho Nightingale
10731b117beSNeel Natu /*
10831b117beSNeel Natu * If there is no handler for the I/O port then punt to userspace.
10931b117beSNeel Natu */
11031b117beSNeel Natu if (vmexit->u.inout.port >= MAX_IOPORTS ||
11131b117beSNeel Natu (handler = ioport_handler[vmexit->u.inout.port]) == NULL) {
112d17b5104SNeel Natu *retu = true;
11331b117beSNeel Natu return (0);
11431b117beSNeel Natu }
115762fd208STycho Nightingale
116d17b5104SNeel Natu mask = vie_size2mask(vmexit->u.inout.bytes);
11782c2c890STycho Nightingale
11882c2c890STycho Nightingale if (!vmexit->u.inout.in) {
119d6aa08c3STycho Nightingale val = vmexit->u.inout.eax & mask;
120d6aa08c3STycho Nightingale }
121d6aa08c3STycho Nightingale
1223f0f4b15SJohn Baldwin error = (*handler)(vcpu_vm(vcpu), vmexit->u.inout.in,
1233f0f4b15SJohn Baldwin vmexit->u.inout.port, vmexit->u.inout.bytes, &val);
12431b117beSNeel Natu if (error) {
12531b117beSNeel Natu /*
12631b117beSNeel Natu * The value returned by this function is also the return value
12731b117beSNeel Natu * of vm_run(). This needs to be a positive number otherwise it
12831b117beSNeel Natu * can be interpreted as a "pseudo-error" like ERESTART.
12931b117beSNeel Natu *
13031b117beSNeel Natu * Enforce this by mapping all errors to EIO.
13131b117beSNeel Natu */
13231b117beSNeel Natu return (EIO);
13331b117beSNeel Natu }
134d6aa08c3STycho Nightingale
135d17b5104SNeel Natu if (vmexit->u.inout.in) {
136d6aa08c3STycho Nightingale vmexit->u.inout.eax &= ~mask;
137d6aa08c3STycho Nightingale vmexit->u.inout.eax |= val & mask;
1383f0f4b15SJohn Baldwin error = vm_set_register(vcpu, VM_REG_GUEST_RAX,
13931b117beSNeel Natu vmexit->u.inout.eax);
14031b117beSNeel Natu KASSERT(error == 0, ("emulate_ioport: error %d setting guest "
14131b117beSNeel Natu "rax register", error));
142d6aa08c3STycho Nightingale }
14331b117beSNeel Natu *retu = false;
14431b117beSNeel Natu return (0);
145d17b5104SNeel Natu }
146d17b5104SNeel Natu
147d17b5104SNeel Natu static int
emulate_inout_str(struct vcpu * vcpu,struct vm_exit * vmexit,bool * retu)1483f0f4b15SJohn Baldwin emulate_inout_str(struct vcpu *vcpu, struct vm_exit *vmexit, bool *retu)
149d17b5104SNeel Natu {
150d17b5104SNeel Natu *retu = true;
151d17b5104SNeel Natu return (0); /* Return to userspace to finish emulation */
152d17b5104SNeel Natu }
153d17b5104SNeel Natu
154d17b5104SNeel Natu int
vm_handle_inout(struct vcpu * vcpu,struct vm_exit * vmexit,bool * retu)1553f0f4b15SJohn Baldwin vm_handle_inout(struct vcpu *vcpu, struct vm_exit *vmexit, bool *retu)
156d17b5104SNeel Natu {
1575a17f489SRobert Wing int bytes __diagused, error;
158d17b5104SNeel Natu
159d17b5104SNeel Natu bytes = vmexit->u.inout.bytes;
160d17b5104SNeel Natu KASSERT(bytes == 1 || bytes == 2 || bytes == 4,
161d17b5104SNeel Natu ("vm_handle_inout: invalid operand size %d", bytes));
162d17b5104SNeel Natu
163d17b5104SNeel Natu if (vmexit->u.inout.string)
1643f0f4b15SJohn Baldwin error = emulate_inout_str(vcpu, vmexit, retu);
165d17b5104SNeel Natu else
1663f0f4b15SJohn Baldwin error = emulate_inout_port(vcpu, vmexit, retu);
167d17b5104SNeel Natu
1683f0f4b15SJohn Baldwin VCPU_CTR4(vcpu_vm(vcpu), vcpu_vcpuid(vcpu), "%s%s 0x%04x: %s",
169d17b5104SNeel Natu vmexit->u.inout.rep ? "rep " : "",
170d17b5104SNeel Natu inout_instruction(vmexit),
171d17b5104SNeel Natu vmexit->u.inout.port,
172d17b5104SNeel Natu error ? "error" : (*retu ? "userspace" : "handled"));
173d6aa08c3STycho Nightingale
174d6aa08c3STycho Nightingale return (error);
175762fd208STycho Nightingale }
176