static bool handle_ept_fault(struct guest_thread *gth) { struct vm_trapframe *vm_tf = gth_to_vmtf(gth); struct virtual_machine *vm = gth_to_vm(gth); uint64_t gpa, *regp; uint8_t regx; int store, size; int advance; if (decode(gth, &gpa, ®x, ®p, &store, &size, &advance)) return FALSE; assert(size >= 0); /* TODO use helpers for some of these addr checks. the fee/fec ones might * be wrong too. */ for (int i = 0; i < VIRTIO_MMIO_MAX_NUM_DEV; i++) { if (vm->virtio_mmio_devices[i] == NULL) continue; if (PG_ADDR(gpa) != vm->virtio_mmio_devices[i]->addr) continue; /* TODO: can the guest cause us to spawn off infinite threads? */ if (store) virtio_mmio_wr(vm, vm->virtio_mmio_devices[i], gpa, size, (uint32_t *)regp); else *regp = virtio_mmio_rd(vm, vm->virtio_mmio_devices[i], gpa, size); vm_tf->tf_rip += advance; return TRUE; } if (PG_ADDR(gpa) == 0xfec00000) { do_ioapic(gth, gpa, regx, regp, store); } else if (PG_ADDR(gpa) == 0) { memmove(regp, &vm->low4k[gpa], size); } else { fprintf(stderr, "EPT violation: can't handle %p\n", gpa); fprintf(stderr, "RIP %p, exit reason 0x%x\n", vm_tf->tf_rip, vm_tf->tf_exit_reason); fprintf(stderr, "Returning 0xffffffff\n"); showstatus(stderr, gth); /* Just fill the whole register for now. */ *regp = (uint64_t) -1; return FALSE; } vm_tf->tf_rip += advance; return TRUE; }
/* Convert a kernel guest virtual address to physical address. * Assumes that the guest VA is in the high negative address space. * TODO: Takes the vm_thread argument so that we can walk the page tables * instead of just coercing the pointer. Therefore, this is not in vmm.h * since it may get complex. */ int gvatogpa(struct guest_thread *vm_thread, uint64_t va, uint64_t *pa) { assert(vm_thread != NULL); struct vm_trapframe *vm_tf = gth_to_vmtf(vm_thread); uint64_t *ptptr = (uint64_t *)vm_tf->tf_cr3; uint64_t entry; for (int shift = PML4_SHIFT; shift >= PML1_SHIFT; shift -= BITS_PER_PML) { entry = ptptr[PMLx(va, shift)]; if (!PAGE_PRESENT(entry)) return -1; if ((entry & PTE_PS) != 0) { uint64_t bitmask = ((1 << shift) - 1); *pa = (((uint64_t)va & bitmask) | (entry & ~bitmask)); return 0; } ptptr = (uint64_t *)PG_ADDR(entry); } *pa = ((uint64_t)va & 0xfff) | (uint64_t)ptptr; return 0; }