]> rtime.felk.cvut.cz Git - jailhouse.git/commitdiff
x86: Make vcpu_handle_io_access() generic
authorValentine Sinitsyn <valentine.sinitsyn@gmail.com>
Sat, 16 Aug 2014 19:00:14 +0000 (01:00 +0600)
committerJan Kiszka <jan.kiszka@siemens.com>
Fri, 10 Oct 2014 11:47:37 +0000 (13:47 +0200)
I/O VM exit handling code can now be used for any vendor.
This implies introducing struct vcpu_io_intercept to communicate
intercepted instruction properties like the port number and access
size between vendor-specific and generic code.

Signed-off-by: Valentine Sinitsyn <valentine.sinitsyn@gmail.com>
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
hypervisor/arch/x86/include/asm/vcpu.h
hypervisor/arch/x86/vcpu.c
hypervisor/arch/x86/vmx.c

index ea574946ca720c9e82876ee7c31426ad48be9805..defeeda899c2f3bab22d490e96aee30fe688b40e 100644 (file)
@@ -33,6 +33,14 @@ struct vcpu_execution_state {
        u64 rip;
 };
 
+struct vcpu_io_intercept {
+       u16 port;
+       unsigned int size;
+       bool in;
+       unsigned int inst_len;
+       bool rep_or_str;
+};
+
 int vcpu_vendor_init(void);
 
 int vcpu_cell_init(struct cell *cell);
@@ -87,6 +95,9 @@ void vcpu_vendor_get_execution_state(struct vcpu_execution_state *x_state);
 void vcpu_handle_hypercall(struct registers *guest_regs,
                           struct vcpu_execution_state *x_state);
 
+bool vcpu_handle_io_access(struct registers *guest_regs,
+                          struct vcpu_io_intercept *io);
+
 bool vcpu_get_guest_paging_structs(struct guest_paging_structures *pg_structs);
 
 #endif
index d202f0f28ec9283fd2c2f52e287065c8812d9d26..1a276a0c02a04be3244dbdbc976c6a208e3f5ad2 100644 (file)
@@ -18,6 +18,7 @@
 #include <jailhouse/string.h>
 #include <jailhouse/types.h>
 #include <asm/i8042.h>
+#include <asm/pci.h>
 #include <asm/percpu.h>
 #include <asm/vcpu.h>
 
@@ -154,3 +155,32 @@ void vcpu_handle_hypercall(struct registers *guest_regs,
        if (code == JAILHOUSE_HC_DISABLE && guest_regs->rax == 0)
                vcpu_deactivate_vmm(guest_regs);
 }
+
+bool vcpu_handle_io_access(struct registers *guest_regs,
+                          struct vcpu_io_intercept *io)
+{
+       struct per_cpu *cpu_data = this_cpu_data();
+       int result = 0;
+
+       /* string and REP-prefixed instructions are not supported */
+       if (io->rep_or_str)
+               goto invalid_access;
+
+       result = x86_pci_config_handler(guest_regs, cpu_data->cell, io->port,
+                                       io->in, io->size);
+       if (result == 0)
+               result = i8042_access_handler(guest_regs, io->port,
+                                             io->in, io->size);
+
+       if (result == 1) {
+               vcpu_skip_emulated_instruction(io->inst_len);
+               return true;
+       }
+
+invalid_access:
+       panic_printk("FATAL: Invalid PIO %s, port: %x size: %d\n",
+                    io->in ? "read" : "write", io->port, io->size);
+       panic_printk("PCI address port: %x\n",
+                    cpu_data->cell->pci_addr_port_val);
+       return false;
+}
index d7d164d0c9bcece5d129afba01f8615c98ba3a27..9a8419c8240ea99ec1d663395f87746eab34565a 100644 (file)
@@ -23,7 +23,6 @@
 #include <jailhouse/pci.h>
 #include <asm/apic.h>
 #include <asm/control.h>
-#include <asm/i8042.h>
 #include <asm/io.h>
 #include <asm/ioapic.h>
 #include <asm/iommu.h>
@@ -934,39 +933,6 @@ static void dump_guest_regs(struct registers *guest_regs)
        panic_printk("EFER: %p\n", vmcs_read64(GUEST_IA32_EFER));
 }
 
-static bool vcpu_handle_io_access(struct registers *guest_regs,
-                                struct per_cpu *cpu_data)
-{
-       /* parse exit qualification for I/O instructions (see SDM, 27.2.1 ) */
-       u64 exitq = vmcs_read64(EXIT_QUALIFICATION);
-       u16 port = (exitq >> 16) & 0xFFFF;
-       bool dir_in = (exitq & 0x8) >> 3;
-       unsigned int size = (exitq & 0x3) + 1;
-       int result = 0;
-
-       /* string and REP-prefixed instructions are not supported */
-       if (exitq & 0x30)
-               goto invalid_access;
-
-       result = x86_pci_config_handler(guest_regs, cpu_data->cell, port,
-                                       dir_in, size);
-       if (result == 0)
-               result = i8042_access_handler(guest_regs, port, dir_in, size);
-
-       if (result == 1) {
-               vcpu_skip_emulated_instruction(
-                               vmcs_read64(VM_EXIT_INSTRUCTION_LEN));
-               return true;
-       }
-
-invalid_access:
-       /* report only unhandled access failures */
-       if (result == 0)
-               panic_printk("FATAL: Invalid PIO %s, port: %x size: %d\n",
-                            dir_in ? "read" : "write", port, size);
-       return false;
-}
-
 static bool vcpu_handle_pt_violation(struct registers *guest_regs,
                                     struct per_cpu *cpu_data)
 {
@@ -1016,10 +982,23 @@ invalid_access:
        return false;
 }
 
+static void vcpu_vendor_get_io_intercept(struct vcpu_io_intercept *out)
+{
+       u64 exitq = vmcs_read64(EXIT_QUALIFICATION);
+
+       /* parse exit qualification for I/O instructions (see SDM, 27.2.1 ) */
+       out->port = (exitq >> 16) & 0xFFFF;
+       out->size = (exitq & 0x3) + 1;
+       out->in = !!((exitq & 0x8) >> 3);
+       out->inst_len = vmcs_read64(VM_EXIT_INSTRUCTION_LEN);
+       out->rep_or_str = !!(exitq & 0x30);
+}
+
 void vcpu_handle_exit(struct registers *guest_regs, struct per_cpu *cpu_data)
 {
        u32 reason = vmcs_read32(VM_EXIT_REASON);
        struct vcpu_execution_state x_state;
+       struct vcpu_io_intercept io;
        int sipi_vector;
 
        cpu_data->stats[JAILHOUSE_CPU_STAT_VMEXITS_TOTAL]++;
@@ -1104,7 +1083,8 @@ void vcpu_handle_exit(struct registers *guest_regs, struct per_cpu *cpu_data)
                break;
        case EXIT_REASON_IO_INSTRUCTION:
                cpu_data->stats[JAILHOUSE_CPU_STAT_VMEXITS_PIO]++;
-               if (vcpu_handle_io_access(guest_regs, cpu_data))
+               vcpu_vendor_get_io_intercept(&io);
+               if (vcpu_handle_io_access(guest_regs, &io))
                        return;
                break;
        case EXIT_REASON_EPT_VIOLATION: