1762fd208STycho Nightingale /*- 2ebc3c37cSMarcelo Araujo * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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/cdefs.h> 30762fd208STycho Nightingale __FBSDID("$FreeBSD$"); 31762fd208STycho Nightingale 32762fd208STycho Nightingale #include <sys/param.h> 33762fd208STycho Nightingale #include <sys/systm.h> 34762fd208STycho Nightingale 35762fd208STycho Nightingale #include <machine/vmm.h> 36e813a873SNeel Natu #include <machine/vmm_instruction_emul.h> 37762fd208STycho Nightingale 38762fd208STycho Nightingale #include "vatpic.h" 39e883c9bbSTycho Nightingale #include "vatpit.h" 40160ef77aSNeel Natu #include "vpmtmr.h" 410dafa5cdSNeel Natu #include "vrtc.h" 42762fd208STycho Nightingale #include "vmm_ioport.h" 43d17b5104SNeel Natu #include "vmm_ktr.h" 44762fd208STycho Nightingale 45762fd208STycho Nightingale #define MAX_IOPORTS 1280 46762fd208STycho Nightingale 47762fd208STycho Nightingale ioport_handler_func_t ioport_handler[MAX_IOPORTS] = { 48e883c9bbSTycho Nightingale [TIMER_MODE] = vatpit_handler, 49e883c9bbSTycho Nightingale [TIMER_CNTR0] = vatpit_handler, 50e883c9bbSTycho Nightingale [TIMER_CNTR1] = vatpit_handler, 51e883c9bbSTycho Nightingale [TIMER_CNTR2] = vatpit_handler, 5279d6ca33STycho Nightingale [NMISC_PORT] = vatpit_nmisc_handler, 53762fd208STycho Nightingale [IO_ICU1] = vatpic_master_handler, 54762fd208STycho Nightingale [IO_ICU1 + ICU_IMR_OFFSET] = vatpic_master_handler, 55762fd208STycho Nightingale [IO_ICU2] = vatpic_slave_handler, 56762fd208STycho Nightingale [IO_ICU2 + ICU_IMR_OFFSET] = vatpic_slave_handler, 57762fd208STycho Nightingale [IO_ELCR1] = vatpic_elc_handler, 58762fd208STycho Nightingale [IO_ELCR2] = vatpic_elc_handler, 59160ef77aSNeel Natu [IO_PMTMR] = vpmtmr_handler, 600dafa5cdSNeel Natu [IO_RTC] = vrtc_addr_handler, 610dafa5cdSNeel Natu [IO_RTC + 1] = vrtc_data_handler, 62762fd208STycho Nightingale }; 63762fd208STycho Nightingale 64d17b5104SNeel Natu #ifdef KTR 65d17b5104SNeel Natu static const char * 66d17b5104SNeel Natu inout_instruction(struct vm_exit *vmexit) 67d17b5104SNeel Natu { 68d17b5104SNeel Natu int index; 69d17b5104SNeel Natu 70d17b5104SNeel Natu static const char *iodesc[] = { 71d17b5104SNeel Natu "outb", "outw", "outl", 72d17b5104SNeel Natu "inb", "inw", "inl", 7307820b4bSNeel Natu "outsb", "outsw", "outsd", 74d17b5104SNeel Natu "insb", "insw", "insd", 75d17b5104SNeel Natu }; 76d17b5104SNeel Natu 77d17b5104SNeel Natu switch (vmexit->u.inout.bytes) { 78d17b5104SNeel Natu case 1: 79d17b5104SNeel Natu index = 0; 80d17b5104SNeel Natu break; 81d17b5104SNeel Natu case 2: 82d17b5104SNeel Natu index = 1; 83d17b5104SNeel Natu break; 84d17b5104SNeel Natu default: 85d17b5104SNeel Natu index = 2; 86d17b5104SNeel Natu break; 87d17b5104SNeel Natu } 88d17b5104SNeel Natu 89d17b5104SNeel Natu if (vmexit->u.inout.in) 90d17b5104SNeel Natu index += 3; 91d17b5104SNeel Natu 92d17b5104SNeel Natu if (vmexit->u.inout.string) 93d17b5104SNeel Natu index += 6; 94d17b5104SNeel Natu 95d17b5104SNeel Natu KASSERT(index < nitems(iodesc), ("%s: invalid index %d", 96d17b5104SNeel Natu __func__, index)); 97d17b5104SNeel Natu 98d17b5104SNeel Natu return (iodesc[index]); 99d17b5104SNeel Natu } 100d17b5104SNeel Natu #endif /* KTR */ 101d17b5104SNeel Natu 102d17b5104SNeel Natu static int 103d17b5104SNeel Natu emulate_inout_port(struct vm *vm, int vcpuid, struct vm_exit *vmexit, 104d17b5104SNeel Natu bool *retu) 105762fd208STycho Nightingale { 106762fd208STycho Nightingale ioport_handler_func_t handler; 107d6aa08c3STycho Nightingale uint32_t mask, val; 108d6aa08c3STycho Nightingale int error; 109762fd208STycho Nightingale 11031b117beSNeel Natu /* 11131b117beSNeel Natu * If there is no handler for the I/O port then punt to userspace. 11231b117beSNeel Natu */ 11331b117beSNeel Natu if (vmexit->u.inout.port >= MAX_IOPORTS || 11431b117beSNeel Natu (handler = ioport_handler[vmexit->u.inout.port]) == NULL) { 115d17b5104SNeel Natu *retu = true; 11631b117beSNeel Natu return (0); 11731b117beSNeel Natu } 118762fd208STycho Nightingale 119d17b5104SNeel Natu mask = vie_size2mask(vmexit->u.inout.bytes); 12082c2c890STycho Nightingale 12182c2c890STycho Nightingale if (!vmexit->u.inout.in) { 122d6aa08c3STycho Nightingale val = vmexit->u.inout.eax & mask; 123d6aa08c3STycho Nightingale } 124d6aa08c3STycho Nightingale 125d6aa08c3STycho Nightingale error = (*handler)(vm, vcpuid, vmexit->u.inout.in, 126d6aa08c3STycho Nightingale vmexit->u.inout.port, vmexit->u.inout.bytes, &val); 12731b117beSNeel Natu if (error) { 12831b117beSNeel Natu /* 12931b117beSNeel Natu * The value returned by this function is also the return value 13031b117beSNeel Natu * of vm_run(). This needs to be a positive number otherwise it 13131b117beSNeel Natu * can be interpreted as a "pseudo-error" like ERESTART. 13231b117beSNeel Natu * 13331b117beSNeel Natu * Enforce this by mapping all errors to EIO. 13431b117beSNeel Natu */ 13531b117beSNeel Natu return (EIO); 13631b117beSNeel Natu } 137d6aa08c3STycho Nightingale 138d17b5104SNeel Natu if (vmexit->u.inout.in) { 139d6aa08c3STycho Nightingale vmexit->u.inout.eax &= ~mask; 140d6aa08c3STycho Nightingale vmexit->u.inout.eax |= val & mask; 14131b117beSNeel Natu error = vm_set_register(vm, vcpuid, VM_REG_GUEST_RAX, 14231b117beSNeel Natu vmexit->u.inout.eax); 14331b117beSNeel Natu KASSERT(error == 0, ("emulate_ioport: error %d setting guest " 14431b117beSNeel Natu "rax register", error)); 145d6aa08c3STycho Nightingale } 14631b117beSNeel Natu *retu = false; 14731b117beSNeel Natu return (0); 148d17b5104SNeel Natu } 149d17b5104SNeel Natu 150d17b5104SNeel Natu static int 151d17b5104SNeel Natu emulate_inout_str(struct vm *vm, int vcpuid, struct vm_exit *vmexit, bool *retu) 152d17b5104SNeel Natu { 153d17b5104SNeel Natu *retu = true; 154d17b5104SNeel Natu return (0); /* Return to userspace to finish emulation */ 155d17b5104SNeel Natu } 156d17b5104SNeel Natu 157d17b5104SNeel Natu int 158d17b5104SNeel Natu vm_handle_inout(struct vm *vm, int vcpuid, struct vm_exit *vmexit, bool *retu) 159d17b5104SNeel Natu { 160*5a17f489SRobert Wing int bytes __diagused, error; 161d17b5104SNeel Natu 162d17b5104SNeel Natu bytes = vmexit->u.inout.bytes; 163d17b5104SNeel Natu KASSERT(bytes == 1 || bytes == 2 || bytes == 4, 164d17b5104SNeel Natu ("vm_handle_inout: invalid operand size %d", bytes)); 165d17b5104SNeel Natu 166d17b5104SNeel Natu if (vmexit->u.inout.string) 167d17b5104SNeel Natu error = emulate_inout_str(vm, vcpuid, vmexit, retu); 168d17b5104SNeel Natu else 169d17b5104SNeel Natu error = emulate_inout_port(vm, vcpuid, vmexit, retu); 170d17b5104SNeel Natu 171d17b5104SNeel Natu VCPU_CTR4(vm, vcpuid, "%s%s 0x%04x: %s", 172d17b5104SNeel Natu vmexit->u.inout.rep ? "rep " : "", 173d17b5104SNeel Natu inout_instruction(vmexit), 174d17b5104SNeel Natu vmexit->u.inout.port, 175d17b5104SNeel Natu error ? "error" : (*retu ? "userspace" : "handled")); 176d6aa08c3STycho Nightingale 177d6aa08c3STycho Nightingale return (error); 178762fd208STycho Nightingale } 179