[hypervisor] Support synchronous accesses to PIO space.

Fixes a bug reading PCI PIO BARs and also implements the write path for
handling PCI PIO packets synchronously.

Change-Id: I8777a2c0dd6181c536b12f99d5e895725a97a539
diff --git a/kernel/lib/hypervisor/packet_mux.cpp b/kernel/lib/hypervisor/packet_mux.cpp
index ac30478..fa93fc0 100644
--- a/kernel/lib/hypervisor/packet_mux.cpp
+++ b/kernel/lib/hypervisor/packet_mux.cpp
@@ -53,6 +53,8 @@
 }
 
 zx_status_t PortRange::Queue(const zx_port_packet_t& packet, StateReloader* reloader) {
+    if (port_ == nullptr)
+        return ZX_ERR_NOT_FOUND;
     PortPacket* port_packet = port_allocator_.Alloc(reloader);
     if (port_packet == nullptr)
         return ZX_ERR_NO_MEMORY;
@@ -106,6 +108,8 @@
     zx_status_t status = FindPortRange(kind, addr, &port_range);
     if (status != ZX_OK)
         return status;
+
+    DEBUG_ASSERT(port_range->HasPort());
     return port_range->Queue(packet, reloader);
 }
 
diff --git a/system/ulib/hypervisor/vcpu.cpp b/system/ulib/hypervisor/vcpu.cpp
index c28edc3..eb58ef5 100644
--- a/system/ulib/hypervisor/vcpu.cpp
+++ b/system/ulib/hypervisor/vcpu.cpp
@@ -200,7 +200,7 @@
         uint16_t port_off;
         PciBus* bus = vcpu_ctx->guest_ctx->pci_bus;
         PciDevice* pci_device;
-        zx_status_t status = bus->MappedDevice(PCI_BAR_ASPACE_MMIO, io->port, &pci_device, &bar,
+        zx_status_t status = bus->MappedDevice(PCI_BAR_ASPACE_PIO, io->port, &pci_device, &bar,
                                                &port_off);
         if (status != ZX_ERR_NOT_FOUND) {
             status = pci_device->ReadBar(bar, port_off, io->access_size, &vcpu_io);
@@ -242,6 +242,23 @@
         return vcpu_ctx->guest_ctx->pci_bus->WriteIoPort(io);
     case UART_INTERRUPT_ENABLE_PORT ... UART_SCR_SCRATCH_PORT:
         return uart_write(vcpu_ctx->guest_ctx->uart, io);
+    default: {
+        uint8_t bar;
+        uint16_t port_off;
+        PciBus* bus = vcpu_ctx->guest_ctx->pci_bus;
+        PciDevice* pci_device;
+        zx_status_t status = bus->MappedDevice(PCI_BAR_ASPACE_PIO, io->port, &pci_device, &bar,
+                                               &port_off);
+        if (status != ZX_ERR_NOT_FOUND) {
+            // Convert the IO packet into a vcpu_io structure.
+            zx_vcpu_io_t vcpu_io;
+            static_assert(sizeof(vcpu_io.data) == sizeof(io->data),
+                "data size mismatch between zx_vcpu_io and zx_packet_get_io.");
+            memcpy(vcpu_io.data, io->data, sizeof(vcpu_io.data));
+            vcpu_io.access_size = io->access_size;
+            return pci_device->WriteBar(bar, port_off, &vcpu_io);
+        }
+    }
     }
     fprintf(stderr, "Unhandled port out %#x\n", io->port);
     return ZX_ERR_NOT_SUPPORTED;