Beispiel #1
0
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, &regx, &regp, &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;
}
Beispiel #2
0
/* 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;
}