]> rtime.felk.cvut.cz Git - jailhouse.git/commitdiff
x86: Trap xAPIC register writes under AMD-V
authorValentine Sinitsyn <valentine.sinitsyn@gmail.com>
Sun, 28 Sep 2014 12:13:12 +0000 (18:13 +0600)
committerJan Kiszka <jan.kiszka@siemens.com>
Sat, 1 Nov 2014 19:10:09 +0000 (20:10 +0100)
Jailhouse maps APIC MMIO page to cells read-only, so it only needs to handle
register writes, which are translated to Nested Page Faults. The real work is
delegated to generic apic_mmio_access(), which requires guest page tables to
work. These are obtained with vcpu_get_guest_paging_structs(), which supports
real mode cells as well.

As there is no AVIC support for any known AMD hardware, AVIC-related VM exits
are nor intercepted neither handled in Jailhouse.

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

index 142c442a7504d647bcb2a3adf68fdd2bc35ee590..248f8799cd37b5564b9b5ca9b62df05a2ee3d2b4 100644 (file)
@@ -489,6 +489,42 @@ out:
        return result;
 }
 
+/*
+ * TODO: This handles unaccelerated (non-AVIC) access. AVIC should
+ * be treated separately in svm_handle_avic_access().
+ */
+static bool svm_handle_apic_access(struct registers *guest_regs,
+                                  struct per_cpu *cpu_data)
+{
+       struct vmcb *vmcb = &cpu_data->vmcb;
+       struct guest_paging_structures pg_structs;
+       unsigned int inst_len, offset;
+       bool is_write;
+
+       /* The caller is responsible for sanity checks */
+       is_write = !!(vmcb->exitinfo1 & 0x2);
+       offset = vmcb->exitinfo2 - XAPIC_BASE;
+
+       if (offset & 0x00f)
+               goto out_err;
+
+       if (!vcpu_get_guest_paging_structs(&pg_structs))
+               goto out_err;
+
+       inst_len = apic_mmio_access(guest_regs, cpu_data, vmcb->rip,
+                                   &pg_structs, offset >> 4, is_write);
+       if (!inst_len)
+               goto out_err;
+
+       vcpu_skip_emulated_instruction(inst_len);
+       return true;
+
+out_err:
+       panic_printk("FATAL: Unhandled APIC access, offset %d, is_write: %d\n",
+                    offset, is_write);
+       return false;
+}
+
 static void dump_guest_regs(struct registers *guest_regs, struct vmcb *vmcb)
 {
        panic_printk("RIP: %p RSP: %p FLAGS: %x\n", vmcb->rip,
@@ -539,6 +575,23 @@ void vcpu_handle_exit(struct registers *guest_regs, struct per_cpu *cpu_data)
                if (res)
                        return;
                break;
+       case VMEXIT_NPF:
+               if ((vmcb->exitinfo1 & 0x7) == 0x7 &&
+                    vmcb->exitinfo2 >= XAPIC_BASE &&
+                    vmcb->exitinfo2 < XAPIC_BASE + PAGE_SIZE) {
+                       /* APIC access in non-AVIC mode */
+                       cpu_data->stats[JAILHOUSE_CPU_STAT_VMEXITS_XAPIC]++;
+                       if (svm_handle_apic_access(guest_regs, cpu_data))
+                               return;
+               } else {
+                       /* General MMIO (IOAPIC, PCI etc) */
+               }
+
+               panic_printk("FATAL: Unhandled Nested Page Fault for (%p), "
+                            "error code is %x\n", vmcb->exitinfo2,
+                            vmcb->exitinfo1 & 0xf);
+               break;
+       /* TODO: Handle VMEXIT_AVIC_NOACCEL and VMEXIT_AVIC_INCOMPLETE_IPI */
        default:
                panic_printk("FATAL: Unexpected #VMEXIT, exitcode %x, "
                             "exitinfo1 %p exitinfo2 %p\n",