| #include <parlib/stdio.h> | 
 | #include <sys/types.h> | 
 | #include <sys/stat.h> | 
 | #include <fcntl.h> | 
 | #include <parlib/arch/arch.h> | 
 | #include <parlib/ros_debug.h> | 
 | #include <unistd.h> | 
 | #include <errno.h> | 
 | #include <dirent.h> | 
 | #include <stdlib.h> | 
 | #include <string.h> | 
 | #include <ros/syscall.h> | 
 | #include <sys/mman.h> | 
 | #include <vmm/coreboot_tables.h> | 
 | #include <ros/common.h> | 
 | #include <vmm/vmm.h> | 
 | #include <vmm/virtio.h> | 
 | #include <vmm/virtio_mmio.h> | 
 | #include <vmm/virtio_ids.h> | 
 | #include <ros/arch/vmx.h> | 
 | #include <vmm/sched.h> | 
 | #include <vmm/util.h> | 
 | #include <ros/arch/mmu.h> | 
 | #include <ros/arch/trapframe.h> | 
 |  | 
 | char *vmxexit[] = { | 
 | 	VMX_EXIT_REASONS | 
 | }; | 
 |  | 
 | void showstatus(FILE *f, struct guest_thread *vm_thread) | 
 | { | 
 | 	struct vm_trapframe *vm_tf = gth_to_vmtf(vm_thread); | 
 | 	int shutdown = vm_tf->tf_exit_reason; | 
 | 	char *when = shutdown & VMX_EXIT_REASONS_FAILED_VMENTRY ? "entry" | 
 | 		                                                : "exit"; | 
 | 	char *reason = "UNKNOWN"; | 
 |  | 
 | 	shutdown &= ~VMX_EXIT_REASONS_FAILED_VMENTRY; | 
 | 	if (shutdown < COUNT_OF(vmxexit) && vmxexit[shutdown]) | 
 | 		reason = vmxexit[shutdown]; | 
 | 	fprintf(f, "Shutdown: core %d, %s due to %s(0x%x); ret code 0x%x\n", | 
 | 	        vm_tf->tf_guest_pcoreid, when, reason, shutdown, | 
 | 			vm_tf->tf_exit_reason); | 
 | 	fprintf_vm_tf(f, vm_tf); | 
 | 	backtrace_guest_thread(f, vm_thread); | 
 | } | 
 |  | 
 | /* Convert a guest virtual address to physical address. */ | 
 | int gva2gpa(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*)PTE_ADDR(vm_tf->tf_cr3); | 
 | 	uint64_t entry; | 
 |  | 
 | 	for (int shift = PML4_SHIFT; | 
 | 	     shift >= PML1_SHIFT; | 
 | 	     shift -= BITS_PER_PML) { | 
 | 		entry = ptptr[PMLx(va, shift)]; | 
 | 		/* bit 63 can be NX.  Bits 62:52 are ignored (for PML4) */ | 
 | 		entry &= 0x000fffffffffffff; | 
 |  | 
 | 		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; | 
 | } | 
 |  | 
 | /* Get the RIP as a physical address. */ | 
 | int rippa(struct guest_thread *vm_thread, uint64_t *pa) | 
 | { | 
 | 	assert(vm_thread != NULL); | 
 | 	return gva2gpa(vm_thread, gth_to_vmtf(vm_thread)->tf_rip, pa); | 
 | } | 
 |  | 
 | int fetch_insn(struct guest_thread *gth, uint8_t *insn) | 
 | { | 
 | 	uint64_t rip_gpa; | 
 |  | 
 | 	/* TODO: this will break if an instruction crosses a page boundary where | 
 | 	 * the adjacent pages do not map to guest-physically contiguous pages. | 
 | 	 * All callers of rippa() have this problem. */ | 
 | 	if (rippa(gth, &rip_gpa)) | 
 | 		return -1; | 
 | 	memcpy(insn, (void*)rip_gpa, VMM_MAX_INSN_SZ); | 
 | 	return 0; | 
 | } |