Ah, OK. This should follow style(9):

—

Ah, OK. This should follow style(9):

---

diff --git a/sys/arch/amd64/amd64/vmm.c b/sys/arch/amd64/amd64/vmm.c
index 4ffb2ff899f..7de38facc78 100644
--- a/sys/arch/amd64/amd64/vmm.c
+++ b/sys/arch/amd64/amd64/vmm.c
@@ -5359,6 +5359,8 @@ svm_handle_inout(struct vcpu *vcpu)
        case IO_ICU1 ... IO_ICU1 + 1:
        case 0x40 ... 0x43:
        case PCKBC_AUX:
+       case 0x60:
+       case 0x64:
        case IO_RTC ... IO_RTC + 1:
        case IO_ICU2 ... IO_ICU2 + 1:
        case 0x3f8 ... 0x3ff:
diff --git a/usr.sbin/vmd/Makefile b/usr.sbin/vmd/Makefile
index 8645df7aecf..f39d85b1b14 100644
--- a/usr.sbin/vmd/Makefile
+++ b/usr.sbin/vmd/Makefile
@@ -4,7 +4,7 @@
 
 PROG=          vmd
 SRCS=          vmd.c control.c log.c priv.c proc.c config.c vmm.c
-SRCS+=         vm.c loadfile_elf.c pci.c virtio.c i8259.c mc146818.c
+SRCS+=         vm.c loadfile_elf.c pci.c virtio.c i8259.c mc146818.c i8042.c
 SRCS+=         ns8250.c i8253.c vmboot.c ufs.c disklabel.c dhcp.c packet.c
 SRCS+=         parse.y atomicio.c vioscsi.c vioraw.c vioqcow2.c fw_cfg.c
 
diff --git a/usr.sbin/vmd/i8042.c b/usr.sbin/vmd/i8042.c
new file mode 100644
index 00000000000..a62386b79ff
--- /dev/null
+++ b/usr.sbin/vmd/i8042.c
@@ -0,0 +1,421 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2019 Katherine Rohl <luig...@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include <dev/ic/i8042reg.h>
+
+#include <machine/vmmvar.h>
+
+#include <event.h>
+#include <pthread.h>
+#include <string.h>
+#include <stddef.h>
+#include <unistd.h>
+
+#include "i8042.h"
+#include "proc.h"
+#include "vmm.h"
+#include "atomicio.h"
+#include "vmd.h"
+
+struct i8042 {
+       uint8_t data;
+       uint8_t command;
+       uint8_t status;
+       uint8_t internal_ram[16];
+
+       uint8_t input_port;
+       uint8_t output_port;
+       
+       /* Port 0 is keyboard, Port 1 is mouse */
+       uint8_t ps2_enabled[2];
+       
+       uint32_t vm_id;
+
+       /* Is the 8042 awaiting a command argument byte? */
+       uint8_t awaiting_argbyte;
+};
+
+struct i8042 kbc;
+pthread_mutex_t kbc_mtx;
+
+/*
+ * i8042_init
+ *
+ * Initialize the emulated i8042 KBC.
+ *
+ * Parameters:
+ *  vm_id: vmm(4) assigned ID of the VM
+ */
+void
+i8042_init(uint32_t vm_id)
+{
+       memset(&kbc, 0, sizeof(kbc));
+
+       if(pthread_mutex_init(&kbc_mtx, NULL) != 0)
+               fatalx("unable to create kbc mutex");
+
+       kbc.vm_id = vm_id;
+
+       /* Always initialize the reset bit to 1 for proper operation. */
+       kbc.output_port = KBC_DEFOUTPORT;
+       kbc.input_port = KBC_DEFINPORT;
+}
+
+/*
+ * i8042_set_output_port
+ *
+ * Set the output port of the KBC.
+ * Many bits have side effects, so handle their on/off
+ *  transition effects as required.
+ */
+static void
+i8042_set_output_port(uint8_t byte)
+{
+       /* 0x01: reset line
+        * 0x02: A20 gate (not implemented)
+        * 0x04: aux port clock
+        * 0x08: aux port data
+        * 0x10: data in output buffer is from kb port (IRQ1)
+        * 0x20: data in output buffer is from aux port (IRQ12)
+        * 0x40: kb port clock
+        * 0x80: kb port data
+        */
+
+       uint8_t old_output_port = kbc.output_port;
+       kbc.output_port = byte;
+       
+       // 0 -> 1 transition
+       if (((old_output_port & 0x10) == 0) &&
+           ((kbc.output_port & 0x10) == 1))
+               vcpu_assert_pic_irq(kbc.vm_id, 0, KBC_KBDIRQ);
+       if (((old_output_port & 0x20) == 0) &&
+           ((kbc.output_port & 0x20) == 1))
+               vcpu_assert_pic_irq(kbc.vm_id, 0, KBC_AUXIRQ);
+
+       // 1 -> 0 transition
+       if (((old_output_port & 0x10) == 1) &&
+           ((kbc.output_port & 0x10) == 0))
+               vcpu_deassert_pic_irq(kbc.vm_id, 0, KBC_KBDIRQ);
+       if (((old_output_port & 0x20) == 1) &&
+           ((kbc.output_port & 0x20) == 0))
+               vcpu_deassert_pic_irq(kbc.vm_id, 0, KBC_AUXIRQ);
+}
+
+/*
+ * i8042_perform_twobyte_command
+ *
+ * Handles the two-byte command (one byte of command and
+ *  one byte of data) after the data has been received.
+ */
+static void
+i8042_perform_twobyte_command(void)
+{
+       // The command is in kbc.command and the argument
+       //  is in kbc.data.
+
+       switch (kbc.command) {
+       case 0x60 ... 0x7F: // KBC_RAMWRITE
+               kbc.internal_ram[kbc.command - 0x60] = kbc.data;
+               break;
+       case KBC_CMDWOUT:
+               i8042_set_output_port(kbc.data);
+               break;
+       case KBC_KBDECHO:
+               i8042_set_output_port(kbc.output_port|0x10);
+               break;
+       case KBC_AUXECHO:
+               i8042_set_output_port(kbc.output_port|0x20);
+               break;
+       case KBC_AUXWRITE:
+               // No auxiliary device for this to go to.
+               break;
+       }
+
+       kbc.awaiting_argbyte = 0;
+}
+
+/*
+ * i8042_process_command
+ *
+ * Handles the command byte currently in the KBC's command
+ *  register, setting the data register accordingly.
+ */
+static void
+i8042_process_command(void)
+{
+#define SET_DIB_BIT (kbc.status |= KBS_DIB)
+       kbc.awaiting_argbyte = 0;
+       
+       switch (kbc.command) {
+       case 0x20 ... 0x3F: // KBC_RAMREAD
+               kbc.data = kbc.internal_ram[kbc.command - 0x20];
+               SET_DIB_BIT;
+               break;
+       case 0x60 ... 0x7F: // KBC_RAMWRITE
+       case KBC_CMDWOUT:
+       case KBC_KBDECHO:
+       case KBC_AUXECHO:
+       case KBC_AUXWRITE:
+               kbc.awaiting_argbyte = 1;
+               break;
+       case KBC_AUXENABLE:
+               kbc.ps2_enabled[KBC_AUXPORT] = 1;
+               break;
+       case KBC_AUXDISABLE:
+               kbc.ps2_enabled[KBC_AUXPORT] = 0;
+               break;
+       case KBC_AUXTEST:
+               kbc.data = 0;
+               SET_DIB_BIT;
+               break;
+       case KBC_KBDTEST:
+               kbc.data = 0;
+               SET_DIB_BIT;
+               break;
+       case KBC_KBDENABLE:
+               kbc.ps2_enabled[KBC_KBDPORT] = 1;
+               break;
+       case KBC_KBDDISABLE:
+               kbc.ps2_enabled[KBC_KBDPORT] = 0;
+               break;  
+       case KBC_READINPORT:
+               kbc.data = kbc.input_port;
+               SET_DIB_BIT;
+               break;
+       case KBC_POLLINLO:
+               kbc.status &= 0x0F;
+               kbc.status |= (kbc.input_port << 4);
+               break;
+       case KBC_POLLINHI:
+               kbc.status &= 0x0F;
+               kbc.status |= (kbc.input_port & 0xF0);
+               break;
+       case KBC_CMDROUT:
+               kbc.data = kbc.output_port;
+               SET_DIB_BIT;
+               break;
+       case KBC_SELFTEST:
+               kbc.data = 0x55;
+               SET_DIB_BIT;
+               break;
+       case KBC_PULSE0:
+               kbc.output_port &= 0xFE;
+               break;
+       case KBC_PULSE1:
+       case KBC_PULSE2:
+       case KBC_PULSE3:
+               // Ignore these commands.
+               break;
+       }
+}
+
+/*
+ * i8042_read_status_register 
+ *
+ * Handles status register reads.
+ * 
+ * Parameters:
+ *
+ * Return value:
+ *  Value of the KBC status register.
+ */
+static uint8_t
+i8042_read_status_register(void)
+{
+       return kbc.status;
+}
+
+/*
+ * i8042_read_data_register
+ *
+ * Reads the data register of the KBC.
+ *
+ * Parameters:
+ *
+ * Return value:
+ *  Value of the KBC data register.
+ */
+static uint8_t
+i8042_read_data_register(void)
+{
+       // Clear the output buffer full bit.
+       kbc.status &= 0xFE;
+
+       return kbc.data;
+}
+
+/*
+ * i8042_write_command_register
+ *
+ * Writes a byte to the 8042 command register.
+ *
+ * Parameters:
+ *  data: The byte to write.
+ */
+static void
+i8042_write_command_register(uint8_t data)
+{
+       kbc.command = data;
+       i8042_process_command();
+}
+
+/*
+ * i8042_write_data_register
+ *
+ * Write a byte to the KBC data register.
+ *
+ * Parameters:
+ *  data: The byte to write.
+ */
+static void
+i8042_write_data_register(uint8_t data)
+{      
+       kbc.data = data;
+
+       if (kbc.awaiting_argbyte) {
+               i8042_perform_twobyte_command();
+       }
+}
+
+/*
+ * i8042_io_read
+ *
+ * Handles emulated reads of the KBC's I/O ports.
+ *
+ * Parameters:
+ *  vei:
+ *
+ * Return value:
+ *  The byte read from the addressed port.
+ *
+ */
+static uint8_t
+i8042_io_read(struct vm_exit *vei)
+{              
+       uint16_t port = vei->vei.vei_port;
+       uint8_t rv;
+               
+       mutex_lock(&kbc_mtx);
+       
+       switch (port) {
+       case KBC_CMD:
+               rv = i8042_read_status_register();;
+               break;
+       case KBC_DATA:
+               rv = i8042_read_data_register();
+               break;
+       default:
+               fatal("%s: invalid port 0x%x", __func__, port);
+       }
+
+       mutex_unlock(&kbc_mtx);
+       return(rv);
+}
+
+/*
+ * i8042_io_write
+ *
+ * Handles writes to the emulated KBC device, setting the
+ *  value of the selected register.
+ *
+ * Parameters:
+ *  vei:
+ *
+ */
+static void
+i8042_io_write(struct vm_exit *vei)
+{
+       uint16_t port = vei->vei.vei_port;
+       uint32_t data;
+
+       get_input_data(vei, &data);
+
+       mutex_lock(&kbc_mtx);
+       switch (port) {
+       case KBC_DATA:
+               i8042_write_data_register(data);
+               break;
+       case KBC_CMD:
+               i8042_write_command_register(data);
+               break;
+       default:
+               fatal("%s: invalid port 0x%x", __func__, port);
+       }
+
+       if ((kbc.output_port & 0x01) == 0) /* Deasserted the reset line? */
+       {
+               /* TODO: Reset the CPU. */
+       }
+
+       mutex_unlock(&kbc_mtx);
+}
+
+/*
+ * vcpu_exit_i8042
+ *
+ * Handles the 0x60 and 0x64 i8042 KBC in/out exits.
+ *
+ * Parameters:
+ *  vrp: vm run parameters containing exit information for the I/O
+ *   instruction being performed.
+ *
+ * Return value:
+ *  0xFF (?)
+ *
+ */
+uint8_t
+vcpu_exit_i8042(struct vm_run_params *vrp)
+{
+       struct vm_exit *vei = vrp->vrp_exit;
+
+       if (vei->vei.vei_dir == VEI_DIR_OUT)
+               i8042_io_write(vei);
+       else
+               set_return_data(vei, i8042_io_read(vei));
+
+       return (0xFF);
+}
+
+int
+i8042_restore(int fd)
+{
+       log_debug("%s: restoring KBC", __func__);
+       if (atomicio(read, fd, &kbc, sizeof(kbc)) != sizeof(kbc)) {
+               log_warnx("%s: error reading KBC from fd", __func__);
+               return (-1);
+       }
+
+       if (pthread_mutex_init(&kbc_mtx, NULL) != 0)
+               fatalx("unable to create kbc mutex");
+
+       return (0);
+}
+
+int
+i8042_dump(int fd)
+{
+       log_debug("%s: sending KBC", __func__);
+       if (atomicio(vwrite, fd, &kbc, sizeof(kbc)) != sizeof(kbc)) {
+               log_warnx("%s: error writing KBC to fd", __func__);
+               return (-1);
+       }
+
+       return (0);
+       
+}
diff --git a/usr.sbin/vmd/i8042.h b/usr.sbin/vmd/i8042.h
new file mode 100644
index 00000000000..67af8f54f2a
--- /dev/null
+++ b/usr.sbin/vmd/i8042.h
@@ -0,0 +1,45 @@
+/* $OpenBSD: i8042.c,v 1.00 2019/05/25 18:18:00 rohl Exp $ */
+/*
+ * Copyright (c) 2019 Katherine Rohl <luig...@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Emulated i8042 (keyboard controller, based on 8048)
+ */
+
+#define KBC_DEFINPORT  0xB0    /* Default input port value. */
+#define KBC_DEFOUTPORT 0x01    /* Default output port value. */
+
+#define KBC_KBDPORT 0          /* Keyboard is port 0. */
+#define KBC_AUXPORT 1          /* Auxiliary is port 1. */
+
+#define KBC_KBDIRQ   1                 /* Keyboard IRQ.  */
+#define KBC_AUXIRQ  12                 /* Secondary IRQ. */
+
+#define KBC_DATA 0x60          /* Data is I/O port 60h. */
+#define KBC_CMD  0x64          /* Command is I/O port 64h. */
+
+/* Commands that aren't useful for public includes. */
+#define KBC_READINPORT 0xC0    /* Read the input port, place in data. */
+#define KBC_POLLINLO   0xC1    /* Poll low 4 bits of input, place in status. */
+#define KBC_POLLINHI   0xC2    /* Poll high 4 bits of input, place in status. 
*/
+#define KBC_CMDROUT    0xD0    /* Read the output port. */
+
+uint8_t vcpu_exit_i8042(struct vm_run_params *);
+
+void i8042_init(uint32_t);
+
+int i8042_restore(int);
+int i8042_dump(int);
diff --git a/usr.sbin/vmd/vm.c b/usr.sbin/vmd/vm.c
index 72b2e379ac3..35adf25c1cf 100644
--- a/usr.sbin/vmd/vm.c
+++ b/usr.sbin/vmd/vm.c
@@ -61,6 +61,7 @@
 #include "i8259.h"
 #include "ns8250.h"
 #include "mc146818.h"
+#include "i8042.h"
 #include "fw_cfg.h"
 #include "atomicio.h"
 
@@ -949,6 +950,11 @@ init_emulated_hw(struct vmop_create_params *vmc, int 
child_cdrom,
        ioports_map[ELCR0] = vcpu_exit_elcr;
        ioports_map[ELCR1] = vcpu_exit_elcr;
 
+       /* Init i8042 keyboard controller */
+       i8042_init(vcp->vcp_id);
+       ioports_map[0x64] = vcpu_exit_i8042;
+       ioports_map[0x60] = vcpu_exit_i8042;
+       
        /* Init ns8250 UART */
        ns8250_init(con_fd, vcp->vcp_id);
        for (i = COM1_DATA; i <= COM1_SCR; i++)
@@ -1002,6 +1008,11 @@ restore_emulated_hw(struct vm_create_params *vcp, int fd,
        ioports_map[IO_ICU2] = vcpu_exit_i8259;
        ioports_map[IO_ICU2 + 1] = vcpu_exit_i8259;
 
+       /* Init i8042 keyboard controller */
+       i8042_restore(fd);
+       ioports_map[0x64] = vcpu_exit_i8042;
+       ioports_map[0x60]= vcpu_exit_i8042;
+       
        /* Init ns8250 UART */
        ns8250_restore(fd, con_fd, vcp->vcp_id);
        for (i = COM1_DATA; i <= COM1_SCR; i++)
@@ -1291,7 +1302,7 @@ vcpu_run_loop(void *arg)
 
        for (;;) {
                ret = pthread_mutex_lock(&vcpu_run_mtx[n]);
-
+               
                if (ret) {
                        log_warnx("%s: can't lock vcpu run mtx (%d)",
                            __func__, (int)ret);

Reply via email to