Re: vmd(8) i8042 device implementation questions

2019-06-07 Thread Katherine Rohl
OK, here’s an updated diff. Sorry for the delay, I’ve been having network 
problems. Boots up and gets detected immediately by OpenBSD, no delays.

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 000..927edf6e60a
--- /dev/null
+++ b/usr.sbin/vmd/i8042.c
@@ -0,0 +1,417 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2019 Katherine Rohl 
+ *
+ * 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 
+
+#include 
+
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#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(, 0, sizeof(kbc));
+
+   if(pthread_mutex_init(_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, 1);
+   vcpu_deassert_pic_irq(kbc.vm_id, 0, 1);
+   }
+   if (((old_output_port & 0x20) == 0) &&
+   ((kbc.output_port & 0x20) == 1))
+   {
+   vcpu_assert_pic_irq(kbc.vm_id, 0, 1);
+   vcpu_deassert_pic_irq(kbc.vm_id, 0, 1);
+   }
+}
+
+/*
+ * 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);
+   

Re: vmd(8) i8042 device implementation questions

2019-06-05 Thread Mike Larkin
On Sat, Jun 01, 2019 at 06:12:16PM -0500, Katherine Rohl wrote:
> Couple questions:
> 
> > This means no interrupt will be injected. I'm not sure if that's what you 
> > want.
> > See vm.c: vcpu_exit_inout(..). It looks like you may have manually asserted 
> > the
> > IRQ in this file, which is a bit different than what we do in other 
> > devices. That
> > may be okay, though.
> 
> The device can assert zero, one, or two IRQs depending on the state of the 
> input ports. Are we capable of asserting two IRQs at once through 
> vcpu_exit_i8042?
> 

Yes, just assert/deassert what you want and it should drive the PIC state
machine accordingly. LMK if that doesn't work. Assert followed by immediate
deassert for edge triggered, and assert followed by deassert after ack for
level triggered. I think all these are edge triggered though.

> > For this IRQ, if it's edge triggered, please assert then deassert the line.
> > The i8259 code should handle that properly. What you have here is a level
> > triggered interrupt (eg, the line will stay asserted until someone
> > does a 1 -> 0 transition below). Same goes for the next few cases.
> 
> Would asserting the IRQs through the exit function handle this for me if 
> that’s possible?

The return-to-vmm path can assert one single interrupt via returning something
other than 0xFF from the exit handler in vmd. But if you need two, you'll need
to either rework that logic (and fix all the other devices) or just
assert/deassert one in the exit handler function and have the return-to-vmm
path handle the other. Your call.

Note - it is probably a good idea to rework the logic at some point because the
current model can only handle "inject this edge triggered interrupt", and not
other interesting scenarios we may need later like "assert this level triggered
interrupt" or being able to flexibly configure a number of different interrupts
(edge or level triggered). There is also no provision to handle deasserting
something in the return-to-vmm path presently (that has to be handled in each
device's I/O routine in vmd - yuck).

> 
> > Also, please bump the revision in the vcpu struct for send/receive
> > as we will be sending a new struct layout now.
> 
> Where exactly? The file revision?



Re: vmd(8) i8042 device implementation questions

2019-06-05 Thread Mike Larkin
On Sun, Jun 02, 2019 at 03:21:34PM +0200, Jasper Lievisse Adriaanse wrote:
> On Sat, Jun 01, 2019 at 06:12:16PM -0500, Katherine Rohl wrote:
> > Couple questions:
> > 
> > > This means no interrupt will be injected. I'm not sure if that's what you 
> > > want.
> > > See vm.c: vcpu_exit_inout(..). It looks like you may have manually 
> > > asserted the
> > > IRQ in this file, which is a bit different than what we do in other 
> > > devices. That
> > > may be okay, though.
> > 
> > The device can assert zero, one, or two IRQs depending on the state of the 
> > input ports. Are we capable of asserting two IRQs at once through 
> > vcpu_exit_i8042?
> > 
> > > For this IRQ, if it's edge triggered, please assert then deassert the 
> > > line.
> > > The i8259 code should handle that properly. What you have here is a level
> > > triggered interrupt (eg, the line will stay asserted until someone
> > > does a 1 -> 0 transition below). Same goes for the next few cases.
> > 
> > Would asserting the IRQs through the exit function handle this for me if 
> > that???s possible?
> > 
> > > Also, please bump the revision in the vcpu struct for send/receive
> > > as we will be sending a new struct layout now.
> > 
> > Where exactly? The file revision?
> That would be VM_DUMP_VERSION in vmd.h I reckon.
> 

Yes, that's what I meant.

> -- 
> jasper
> 



Re: vmd(8) i8042 device implementation questions

2019-06-02 Thread Jasper Lievisse Adriaanse
On Sat, Jun 01, 2019 at 06:12:16PM -0500, Katherine Rohl wrote:
> Couple questions:
> 
> > This means no interrupt will be injected. I'm not sure if that's what you 
> > want.
> > See vm.c: vcpu_exit_inout(..). It looks like you may have manually asserted 
> > the
> > IRQ in this file, which is a bit different than what we do in other 
> > devices. That
> > may be okay, though.
> 
> The device can assert zero, one, or two IRQs depending on the state of the 
> input ports. Are we capable of asserting two IRQs at once through 
> vcpu_exit_i8042?
> 
> > For this IRQ, if it's edge triggered, please assert then deassert the line.
> > The i8259 code should handle that properly. What you have here is a level
> > triggered interrupt (eg, the line will stay asserted until someone
> > does a 1 -> 0 transition below). Same goes for the next few cases.
> 
> Would asserting the IRQs through the exit function handle this for me if 
> that???s possible?
> 
> > Also, please bump the revision in the vcpu struct for send/receive
> > as we will be sending a new struct layout now.
> 
> Where exactly? The file revision?
That would be VM_DUMP_VERSION in vmd.h I reckon.

-- 
jasper



Re: vmd(8) i8042 device implementation questions

2019-06-01 Thread Katherine Rohl
Couple questions:

> This means no interrupt will be injected. I'm not sure if that's what you 
> want.
> See vm.c: vcpu_exit_inout(..). It looks like you may have manually asserted 
> the
> IRQ in this file, which is a bit different than what we do in other devices. 
> That
> may be okay, though.

The device can assert zero, one, or two IRQs depending on the state of the 
input ports. Are we capable of asserting two IRQs at once through 
vcpu_exit_i8042?

> For this IRQ, if it's edge triggered, please assert then deassert the line.
> The i8259 code should handle that properly. What you have here is a level
> triggered interrupt (eg, the line will stay asserted until someone
> does a 1 -> 0 transition below). Same goes for the next few cases.

Would asserting the IRQs through the exit function handle this for me if that’s 
possible?

> Also, please bump the revision in the vcpu struct for send/receive
> as we will be sending a new struct layout now.

Where exactly? The file revision?



Re: vmd(8) i8042 device implementation questions

2019-05-31 Thread Mike Larkin
On Thu, May 30, 2019 at 11:06:57PM -0500, Katherine Rohl wrote:
> Apologies.
> 
> ---
> 

Hi Katherine,

 Thanks for the diff. I think we are getting close! A few comments below. 

-ml

> 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 000..ced3b43da1c
> --- /dev/null
> +++ b/usr.sbin/vmd/i8042.c
> @@ -0,0 +1,423 @@
> +/* $OpenBSD$ */
> +/*
> + * Copyright (c) 2019 Katherine Rohl 
> + *
> + * 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 
> +
> +#include 
> +
> +#include 
> +
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +
> +#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(, 0, sizeof(kbc));
> +
> + if(pthread_mutex_init(_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);

For this IRQ, if it's edge triggered, please assert then deassert the line.
The i8259 code should handle that properly. What you have here is a level
triggered interrupt (eg, the line will stay asserted until someone
does a 1 -> 0 transition below). Same goes for the next few cases.

> + 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))
> + 

Re: vmd(8) i8042 device implementation questions

2019-05-30 Thread Katherine Rohl
Apologies.

---

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 000..ced3b43da1c
--- /dev/null
+++ b/usr.sbin/vmd/i8042.c
@@ -0,0 +1,423 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2019 Katherine Rohl 
+ *
+ * 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 
+
+#include 
+
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#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(, 0, sizeof(kbc));
+
+   if(pthread_mutex_init(_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;
+   

Re: vmd(8) i8042 device implementation questions

2019-05-30 Thread Katherine Rohl
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 000..a62386b79ff
--- /dev/null
+++ b/usr.sbin/vmd/i8042.c
@@ -0,0 +1,421 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2019 Katherine Rohl 
+ *
+ * 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 
+
+#include 
+
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#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(, 0, sizeof(kbc));
+
+   if(pthread_mutex_init(_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] = 

Re: vmd(8) i8042 device implementation questions

2019-05-30 Thread Bryan Steele
On Thu, May 30, 2019 at 12:09:01AM -0500, Katherine Rohl wrote:
> Okay, here's the first pass of my 8042 device - I wasn't able to figure out 
> how to tie the reset line to the guest VM reset, so I was hoping someone 
> could give me a hand with that. Other than that, it attaches to i386 and 
> amd64 OpenBSD guests. There's no input yet as I mentioned, but the 8042 
> commands execute according to specs.

Cool! :-)

Some style(9) nits inline below.

> 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 000..b57139368cf
> --- /dev/null
> +++ b/usr.sbin/vmd/i8042.c
> @@ -0,0 +1,439 @@
> +/* $OpenBSD: i8042.c,v 1.00 2019/05/25 18:18:00 rohl Exp $ */

This can be just:

/* $OpenBSD$ */

It will be expanded automatically by cvs

> +/*
> + * Copyright (c) 2019 Katherine Rohl 
> + *
> + * 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 
> +
> +#include 
> +
> +#include 
> +
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +
> +#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

C++style single-line comments should be avoided, use /* .. */ instead.

> + 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(, 0, sizeof(kbc));
> +
> + if(pthread_mutex_init(_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

..

The braces should be on the same line, or in cases like this can
be omitted. There should also be a space after keywords, if (..).

> + if(((old_output_port & 0x10) == 0) &&
> +((kbc.output_port & 0x10) == 1))
> +{
> +vcpu_assert_pic_irq(kbc.vm_id, 0, 

Re: vmd(8) i8042 device implementation questions

2019-05-29 Thread Katherine Rohl
Okay, here’s the first pass of my 8042 device - I wasn’t able to figure out how 
to tie the reset line to the guest VM reset, so I was hoping someone could give 
me a hand with that. Other than that, it attaches to i386 and amd64 OpenBSD 
guests. There’s no input yet as I mentioned, but the 8042 commands execute 
according to specs.

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 000..b57139368cf
--- /dev/null
+++ b/usr.sbin/vmd/i8042.c
@@ -0,0 +1,439 @@
+/* $OpenBSD: i8042.c,v 1.00 2019/05/25 18:18:00 rohl Exp $ */
+/*
+ * Copyright (c) 2019 Katherine Rohl 
+ *
+ * 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 
+
+#include 
+
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#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(, 0, sizeof(kbc));
+
+   if(pthread_mutex_init(_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
+ 

Re: vmd(8) i8042 device implementation questions

2019-05-29 Thread Katherine Rohl
I did a little more looking and the only practical use is $F0 to pulse the 
reset line rather than setting it directly (and thus locking up the system 
forever). I’ll treat it as a reset.  $F1 would pulse Gate A20 (which is a 
useless operation in a PC) and $F2 and $F3 pulse reserved bits.

> On May 29, 2019, at 3:16 AM, Mike Larkin  wrote:

> We don't have very precise timing, so I'm not sure how you're going to get a
> 6uS pulse. What does an attached device do with such a pulse in a normal
> scenario?



Re: vmd(8) i8042 device implementation questions

2019-05-29 Thread Mike Larkin
On Tue, May 28, 2019 at 09:57:02PM -0500, Katherine Rohl wrote:
> I have my i8042 device for vmd(8) mostly implemented. It’s only missing a few 
> commands, but since there are no PS/2 input devices yet, there isn’t very 
> much in the way of testing I can do beyond ensuring that commands act as they 
> should. 
> 
> I have a couple questions about expected behavior, mostly related to the 8042 
> output port.
> 
> * The 8042 controls the CPU reset line, but I’m not sure what the behavior 
> should be in terms of vmm/vmd. Send a reset command if the reset line gets 
> pulled low?

The reset line being asserted (deasserted?) can be shunted to the same code in
vmd that processes triple faults, thus resetting the CPU.

> * The 8042 controls Gate A20, which doesn’t seem to exist in the VM. I just 
> have the output line not hooked up to anything. That OK?

Ignore for now.

> * There is nothing hooked up to the PS/2 ports since adding input devices is 
> out of scope for my current diff.
> * Commands F0-F3 pulse 8042 output port bits low for 6uS. How should such 
> timing be implemented in a vmd device?
> 

We don't have very precise timing, so I'm not sure how you're going to get a
6uS pulse. What does an attached device do with such a pulse in a normal
scenario?

> Once I get these cleared up, I should have a diff ready by the weekend. The 
> 8042 already gets detected in the OpenBSD boot process!
> 
> Katherine
>