From nobody Wed May 01 13:01:56 2024 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4VTxzT05YCz5JLgZ; Wed, 1 May 2024 13:01:57 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4VTxzS71Blz401M; Wed, 1 May 2024 13:01:56 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1714568516; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=KyUpwQ9SILRHITfWR0BsVWg2+YvuUwFubXZM8eu3el4=; b=s+zTqYkunE4CnKA8AGU+RMxnkEW8Q8rM/R0Mwbia2Ubzq22mHPSc1M/nl+5zaeHtMtxaBe S8fasDE8s2wmYlc+yrF0z+iAXQjw+YXIV4A1TF2jSaog1UMuOC0NsDcuCSAErYxpfvAvRJ bA7vry1TO0mtn9iK6BJdASt5nRWQVqLgsQCQ3UFWfbwfBB3BimEXzbAX63DyiZcCbt+pvk sZSK1W26nZC+j/qxED/liO6d7EZ5vNBBnquL09bZ5k2jHmdPZkNYEsT3OxDBlD/2LtstoK VmtyHK9h+CUcuKENEyc7JmPNP6gLK2SQs3Jcf8G9SKlsb/BbSwwpC4+I5tuMUg== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1714568516; a=rsa-sha256; cv=none; b=aGPG7VPk/OTfVgI/RIPbiqEBjtM5WJlTs6NNmMKMLzDc5jq2kSpWRGRAPdHClT/qxvSrup pVzHtsBvJ0S16SprJuADPDePf9F1BhgQx9d6RwTqhm0MMnr61vOSyDX8aN/Dl0RdG35J0+ dJcrCRd1j0ZSTRO2Sf5OaPIabEJHRztvQ4n7k74d9OXsfnz5yy/GluSSsRLuZH1R1gfveO dJseGzCdiPyy6xq9sk4sMK2UaE8qP91sc0c28Lpydmq8h3TVAr5q3H49AYnn0Pz6os3FRC adCuvN7T5RtWGOTZOONHqLL+xeD2XJy88gxfE6EHYGrpFK35fL03BUUf2MmwHQ== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1714568516; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=KyUpwQ9SILRHITfWR0BsVWg2+YvuUwFubXZM8eu3el4=; b=kJ0m74nE1Gc2IRZJjwleNdjCkIjj30oRun2DQUjwkeH4NaoAQXrQqL4PUNZ++R/CHYZa1T 5ksHDleXnM84kygIwQmsdR5N2YvJzr3FYg/cuUWqTFtKSyxx4IC+y5SDB5qoHzpm6Lc2HY pnlbapYRYYRctH+TLVDHyg7S9r/zM60xS6isvt+qtIuMGujirNKr9/mgSjheKqfxK0LLxH d4DpVvljeGEoiHsJbwOQN27zD/7HyuKQ42RnKvvWWS8DJrYTT+ZyBJ9wSwoFYlSn3mYkuL kDHolq0ZfGEd6eUO2Rwsf7YVBLCkgrYogoZcN3YGZ3HrX5w4axvjcXnq/Id4YQ== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4VTxzS6ZDczKhl; Wed, 1 May 2024 13:01:56 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.17.1/8.17.1) with ESMTP id 441D1u1V000527; Wed, 1 May 2024 13:01:56 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.17.1/8.17.1/Submit) id 441D1u28000524; Wed, 1 May 2024 13:01:56 GMT (envelope-from git) Date: Wed, 1 May 2024 13:01:56 GMT Message-Id: <202405011301.441D1u28000524@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Mark Johnston Subject: git: 1c4ee7dfb8af - main - bhyvectl: Prepare to add arm64 support List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: markj X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 1c4ee7dfb8affed302171232b0f612e6bcba3c10 Auto-Submitted: auto-generated The branch main has been updated by markj: URL: https://cgit.FreeBSD.org/src/commit/?id=1c4ee7dfb8affed302171232b0f612e6bcba3c10 commit 1c4ee7dfb8affed302171232b0f612e6bcba3c10 Author: Mark Johnston AuthorDate: 2024-05-01 12:31:00 +0000 Commit: Mark Johnston CommitDate: 2024-05-01 12:31:00 +0000 bhyvectl: Prepare to add arm64 support Move MD code into a separate directory and add a simple interface which lets the MD bits register options and handle them. No functional change intended. Reviewed by: jhb Sponsored by: Innovate UK Differential Revision: https://reviews.freebsd.org/D44932 --- usr.sbin/bhyvectl/Makefile | 9 +- usr.sbin/bhyvectl/amd64/Makefile.inc | 1 + usr.sbin/bhyvectl/amd64/bhyvectl_machdep.c | 1888 +++++++++++++++++++++++++++ usr.sbin/bhyvectl/bhyvectl.c | 1920 ++-------------------------- usr.sbin/bhyvectl/bhyvectl.h | 53 + 5 files changed, 2019 insertions(+), 1852 deletions(-) diff --git a/usr.sbin/bhyvectl/Makefile b/usr.sbin/bhyvectl/Makefile index 4f15bc35adf8..e5c6ad18d286 100644 --- a/usr.sbin/bhyvectl/Makefile +++ b/usr.sbin/bhyvectl/Makefile @@ -1,17 +1,18 @@ -# -# - .include +.PATH: ${.CURDIR}/${MACHINE_CPUARCH} + PROG= bhyvectl SRCS= bhyvectl.c PACKAGE= bhyve +.include "${MACHINE_CPUARCH}/Makefile.inc" + MAN= bhyvectl.8 LIBADD= vmmapi util -CFLAGS+= -I${SRCTOP}/sys/amd64/vmm +CFLAGS+= -I${.CURDIR} -I${SRCTOP}/sys/amd64/vmm .if ${MK_BHYVE_SNAPSHOT} != "no" LIBADD+= nv diff --git a/usr.sbin/bhyvectl/amd64/Makefile.inc b/usr.sbin/bhyvectl/amd64/Makefile.inc new file mode 100644 index 000000000000..047e8d6c70bc --- /dev/null +++ b/usr.sbin/bhyvectl/amd64/Makefile.inc @@ -0,0 +1 @@ +SRCS+= bhyvectl_machdep.c diff --git a/usr.sbin/bhyvectl/amd64/bhyvectl_machdep.c b/usr.sbin/bhyvectl/amd64/bhyvectl_machdep.c new file mode 100644 index 000000000000..d7dc002d413e --- /dev/null +++ b/usr.sbin/bhyvectl/amd64/bhyvectl_machdep.c @@ -0,0 +1,1888 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2011 NetApp, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "amd/vmcb.h" +#include "intel/vmcs.h" + +#include "bhyvectl.h" + +enum { + SET_EFER = OPT_START_MD, + SET_CR0, + SET_CR2, + SET_CR3, + SET_CR4, + SET_DR0, + SET_DR1, + SET_DR2, + SET_DR3, + SET_DR6, + SET_DR7, + SET_RSP, + SET_RIP, + SET_RAX, + SET_RFLAGS, + DESC_BASE, + DESC_LIMIT, + DESC_ACCESS, + SET_CS, + SET_DS, + SET_ES, + SET_FS, + SET_GS, + SET_SS, + SET_TR, + SET_LDTR, + SET_X2APIC_STATE, + UNASSIGN_PPTDEV, + GET_GPA_PMAP, + ASSERT_LAPIC_LVT, + SET_RTC_TIME, + SET_RTC_NVRAM, + RTC_NVRAM_OFFSET, +}; + +static int get_rtc_time, set_rtc_time; +static int get_rtc_nvram, set_rtc_nvram; +static int rtc_nvram_offset; +static uint8_t rtc_nvram_value; +static time_t rtc_secs; +static int get_gpa_pmap; +static vm_paddr_t gpa_pmap; +static int inject_nmi, assert_lapic_lvt = -1; +static int get_intinfo; +static int set_cr0, get_cr0, set_cr2, get_cr2, set_cr3, get_cr3; +static int set_cr4, get_cr4; +static uint64_t set_cr0_val, set_cr2_val, set_cr3_val, set_cr4_val; +static int set_efer, get_efer; +static uint64_t set_efer_val; +static int set_dr0, get_dr0; +static int set_dr1, get_dr1; +static int set_dr2, get_dr2; +static int set_dr3, get_dr3; +static int set_dr6, get_dr6; +static int set_dr7, get_dr7; +static uint64_t set_dr0_val, set_dr1_val, set_dr2_val, set_dr3_val, set_dr6_val; +static uint64_t set_dr7_val; +static int set_rsp, get_rsp, set_rip, get_rip, set_rflags, get_rflags; +static int set_rax, get_rax; +static uint64_t set_rsp_val, set_rip_val, set_rflags_val, set_rax_val; +static int get_rbx, get_rcx, get_rdx, get_rsi, get_rdi, get_rbp; +static int get_r8, get_r9, get_r10, get_r11, get_r12, get_r13, get_r14, get_r15; +static int set_desc_ds, get_desc_ds; +static int set_desc_es, get_desc_es; +static int set_desc_fs, get_desc_fs; +static int set_desc_gs, get_desc_gs; +static int set_desc_cs, get_desc_cs; +static int set_desc_ss, get_desc_ss; +static int set_desc_gdtr, get_desc_gdtr; +static int set_desc_idtr, get_desc_idtr; +static int set_desc_tr, get_desc_tr; +static int set_desc_ldtr, get_desc_ldtr; +static int set_cs, set_ds, set_es, set_fs, set_gs, set_ss, set_tr, set_ldtr; +static int get_cs, get_ds, get_es, get_fs, get_gs, get_ss, get_tr, get_ldtr; +static uint64_t set_cs_val, set_ds_val, set_es_val, set_fs_val, set_gs_val; +static uint64_t set_ss_val, set_tr_val, set_ldtr_val; +static int set_x2apic_state, get_x2apic_state; +static enum x2apic_state x2apic_state; +static int unassign_pptdev, bus, slot, func; + +static uint64_t desc_base; +static uint32_t desc_limit, desc_access; + +/* + * VMCB specific. + */ +static int get_vmcb_intercept, get_vmcb_exit_details, get_vmcb_tlb_ctrl; +static int get_vmcb_virq, get_avic_table; + +/* + * VMCS-specific fields + */ +static int get_pinbased_ctls, get_procbased_ctls, get_procbased_ctls2; +static int get_eptp, get_io_bitmap, get_tsc_offset; +static int get_vmcs_entry_interruption_info; +static int get_vmcs_interruptibility; +static int get_vmcs_gpa, get_vmcs_gla; +static int get_exception_bitmap; +static int get_cr0_mask, get_cr0_shadow; +static int get_cr4_mask, get_cr4_shadow; +static int get_cr3_targets; +static int get_apic_access_addr, get_virtual_apic_addr, get_tpr_threshold; +static int get_msr_bitmap, get_msr_bitmap_address; +static int get_vpid_asid; +static int get_inst_err, get_exit_ctls, get_entry_ctls; +static int get_host_cr0, get_host_cr3, get_host_cr4; +static int get_host_rip, get_host_rsp; +static int get_guest_pat, get_host_pat; +static int get_guest_sysenter, get_vmcs_link; +static int get_exit_reason, get_vmcs_exit_qualification; +static int get_vmcs_exit_interruption_info, get_vmcs_exit_interruption_error; +static int get_vmcs_exit_inst_length; + +static bool +cpu_vendor_intel(void) +{ + u_int regs[4], v[3]; + + do_cpuid(0, regs); + v[0] = regs[1]; + v[1] = regs[3]; + v[2] = regs[2]; + + if (memcmp(v, "GenuineIntel", sizeof(v)) == 0) + return (true); + if (memcmp(v, "AuthenticAMD", sizeof(v)) == 0 || + memcmp(v, "HygonGenuine", sizeof(v)) == 0) + return (false); + fprintf(stderr, "Unknown cpu vendor \"%s\"\n", (const char *)v); + exit(1); +} + +void +bhyvectl_dump_vm_run_exitcode(struct vm_exit *vmexit, int vcpu) +{ + printf("vm exit[%d]\n", vcpu); + printf("\trip\t\t0x%016lx\n", vmexit->rip); + printf("\tinst_length\t%d\n", vmexit->inst_length); + switch (vmexit->exitcode) { + case VM_EXITCODE_INOUT: + printf("\treason\t\tINOUT\n"); + printf("\tdirection\t%s\n", vmexit->u.inout.in ? "IN" : "OUT"); + printf("\tbytes\t\t%d\n", vmexit->u.inout.bytes); + printf("\tflags\t\t%s%s\n", + vmexit->u.inout.string ? "STRING " : "", + vmexit->u.inout.rep ? "REP " : ""); + printf("\tport\t\t0x%04x\n", vmexit->u.inout.port); + printf("\teax\t\t0x%08x\n", vmexit->u.inout.eax); + break; + case VM_EXITCODE_VMX: + printf("\treason\t\tVMX\n"); + printf("\tstatus\t\t%d\n", vmexit->u.vmx.status); + printf("\texit_reason\t0x%08x (%u)\n", + vmexit->u.vmx.exit_reason, vmexit->u.vmx.exit_reason); + printf("\tqualification\t0x%016lx\n", + vmexit->u.vmx.exit_qualification); + printf("\tinst_type\t\t%d\n", vmexit->u.vmx.inst_type); + printf("\tinst_error\t\t%d\n", vmexit->u.vmx.inst_error); + break; + case VM_EXITCODE_SVM: + printf("\treason\t\tSVM\n"); + printf("\texit_reason\t\t%#lx\n", vmexit->u.svm.exitcode); + printf("\texitinfo1\t\t%#lx\n", vmexit->u.svm.exitinfo1); + printf("\texitinfo2\t\t%#lx\n", vmexit->u.svm.exitinfo2); + break; + default: + printf("*** unknown vm run exitcode %d\n", vmexit->exitcode); + break; + } +} + +static const char * +wday_str(int idx) +{ + static const char *weekdays[] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" + }; + + if (idx >= 0 && idx < 7) + return (weekdays[idx]); + else + return ("UNK"); +} + +static const char * +mon_str(int idx) +{ + static const char *months[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }; + + if (idx >= 0 && idx < 12) + return (months[idx]); + else + return ("UNK"); +} + +static void +print_intinfo(const char *banner, uint64_t info) +{ + int type; + + printf("%s:\t", banner); + if (info & VM_INTINFO_VALID) { + type = info & VM_INTINFO_TYPE; + switch (type) { + case VM_INTINFO_HWINTR: + printf("extint"); + break; + case VM_INTINFO_NMI: + printf("nmi"); + break; + case VM_INTINFO_SWINTR: + printf("swint"); + break; + default: + printf("exception"); + break; + } + printf(" vector %d", (int)VM_INTINFO_VECTOR(info)); + if (info & VM_INTINFO_DEL_ERRCODE) + printf(" errcode %#x", (u_int)(info >> 32)); + } else { + printf("n/a"); + } + printf("\n"); +} + +/* AMD 6th generation and Intel compatible MSRs */ +#define MSR_AMD6TH_START 0xC0000000 +#define MSR_AMD6TH_END 0xC0001FFF +/* AMD 7th and 8th generation compatible MSRs */ +#define MSR_AMD7TH_START 0xC0010000 +#define MSR_AMD7TH_END 0xC0011FFF + +static const char * +msr_name(uint32_t msr) +{ + static char buf[32]; + + switch (msr) { + case MSR_TSC: + return ("MSR_TSC"); + case MSR_EFER: + return ("MSR_EFER"); + case MSR_STAR: + return ("MSR_STAR"); + case MSR_LSTAR: + return ("MSR_LSTAR"); + case MSR_CSTAR: + return ("MSR_CSTAR"); + case MSR_SF_MASK: + return ("MSR_SF_MASK"); + case MSR_FSBASE: + return ("MSR_FSBASE"); + case MSR_GSBASE: + return ("MSR_GSBASE"); + case MSR_KGSBASE: + return ("MSR_KGSBASE"); + case MSR_SYSENTER_CS_MSR: + return ("MSR_SYSENTER_CS_MSR"); + case MSR_SYSENTER_ESP_MSR: + return ("MSR_SYSENTER_ESP_MSR"); + case MSR_SYSENTER_EIP_MSR: + return ("MSR_SYSENTER_EIP_MSR"); + case MSR_PAT: + return ("MSR_PAT"); + } + snprintf(buf, sizeof(buf), "MSR %#08x", msr); + + return (buf); +} + +static inline void +print_msr_pm(uint64_t msr, int vcpu, int readable, int writeable) +{ + + if (readable || writeable) { + printf("%-20s[%d]\t\t%c%c\n", msr_name(msr), vcpu, + readable ? 'R' : '-', writeable ? 'W' : '-'); + } +} + +/* + * Reference APM vol2, section 15.11 MSR Intercepts. + */ +static void +dump_amd_msr_pm(const char *bitmap, int vcpu) +{ + int byte, bit, readable, writeable; + uint32_t msr; + + for (msr = 0; msr < 0x2000; msr++) { + byte = msr / 4; + bit = (msr % 4) * 2; + + /* Look at MSRs in the range 0x00000000 to 0x00001FFF */ + readable = (bitmap[byte] & (1 << bit)) ? 0 : 1; + writeable = (bitmap[byte] & (2 << bit)) ? 0 : 1; + print_msr_pm(msr, vcpu, readable, writeable); + + /* Look at MSRs in the range 0xC0000000 to 0xC0001FFF */ + byte += 2048; + readable = (bitmap[byte] & (1 << bit)) ? 0 : 1; + writeable = (bitmap[byte] & (2 << bit)) ? 0 : 1; + print_msr_pm(msr + MSR_AMD6TH_START, vcpu, readable, + writeable); + + /* MSR 0xC0010000 to 0xC0011FF is only for AMD */ + byte += 4096; + readable = (bitmap[byte] & (1 << bit)) ? 0 : 1; + writeable = (bitmap[byte] & (2 << bit)) ? 0 : 1; + print_msr_pm(msr + MSR_AMD7TH_START, vcpu, readable, + writeable); + } +} + +/* + * Reference Intel SDM Vol3 Section 24.6.9 MSR-Bitmap Address + */ +static void +dump_intel_msr_pm(const char *bitmap, int vcpu) +{ + int byte, bit, readable, writeable; + uint32_t msr; + + for (msr = 0; msr < 0x2000; msr++) { + byte = msr / 8; + bit = msr & 0x7; + + /* Look at MSRs in the range 0x00000000 to 0x00001FFF */ + readable = (bitmap[byte] & (1 << bit)) ? 0 : 1; + writeable = (bitmap[2048 + byte] & (1 << bit)) ? 0 : 1; + print_msr_pm(msr, vcpu, readable, writeable); + + /* Look at MSRs in the range 0xC0000000 to 0xC0001FFF */ + byte += 1024; + readable = (bitmap[byte] & (1 << bit)) ? 0 : 1; + writeable = (bitmap[2048 + byte] & (1 << bit)) ? 0 : 1; + print_msr_pm(msr + MSR_AMD6TH_START, vcpu, readable, + writeable); + } +} + +static int +dump_msr_bitmap(int vcpu, uint64_t addr, bool cpu_intel) +{ + char *bitmap; + int error, fd, map_size; + + error = -1; + bitmap = MAP_FAILED; + + fd = open("/dev/mem", O_RDONLY, 0); + if (fd < 0) { + perror("Couldn't open /dev/mem"); + goto done; + } + + if (cpu_intel) + map_size = PAGE_SIZE; + else + map_size = 2 * PAGE_SIZE; + + bitmap = mmap(NULL, map_size, PROT_READ, MAP_SHARED, fd, addr); + if (bitmap == MAP_FAILED) { + perror("mmap failed"); + goto done; + } + + if (cpu_intel) + dump_intel_msr_pm(bitmap, vcpu); + else + dump_amd_msr_pm(bitmap, vcpu); + + error = 0; +done: + if (bitmap != MAP_FAILED) + munmap((void *)bitmap, map_size); + if (fd >= 0) + close(fd); + + return (error); +} + +static int +vm_get_vmcs_field(struct vcpu *vcpu, int field, uint64_t *ret_val) +{ + + return (vm_get_register(vcpu, VMCS_IDENT(field), ret_val)); +} + +static int +vm_get_vmcb_field(struct vcpu *vcpu, int off, int bytes, + uint64_t *ret_val) +{ + + return (vm_get_register(vcpu, VMCB_ACCESS(off, bytes), ret_val)); +} + +static int +get_all_registers(struct vcpu *vcpu, int vcpuid, bool get_all) +{ + uint64_t cr0, cr2, cr3, cr4, dr0, dr1, dr2, dr3, dr6, dr7; + uint64_t rsp, rip, rflags, efer; + uint64_t rax, rbx, rcx, rdx, rsi, rdi, rbp; + uint64_t r8, r9, r10, r11, r12, r13, r14, r15; + int error = 0; + + if (!error && (get_efer || get_all)) { + error = vm_get_register(vcpu, VM_REG_GUEST_EFER, &efer); + if (error == 0) + printf("efer[%d]\t\t0x%016lx\n", vcpuid, efer); + } + + if (!error && (get_cr0 || get_all)) { + error = vm_get_register(vcpu, VM_REG_GUEST_CR0, &cr0); + if (error == 0) + printf("cr0[%d]\t\t0x%016lx\n", vcpuid, cr0); + } + + if (!error && (get_cr2 || get_all)) { + error = vm_get_register(vcpu, VM_REG_GUEST_CR2, &cr2); + if (error == 0) + printf("cr2[%d]\t\t0x%016lx\n", vcpuid, cr2); + } + + if (!error && (get_cr3 || get_all)) { + error = vm_get_register(vcpu, VM_REG_GUEST_CR3, &cr3); + if (error == 0) + printf("cr3[%d]\t\t0x%016lx\n", vcpuid, cr3); + } + + if (!error && (get_cr4 || get_all)) { + error = vm_get_register(vcpu, VM_REG_GUEST_CR4, &cr4); + if (error == 0) + printf("cr4[%d]\t\t0x%016lx\n", vcpuid, cr4); + } + + if (!error && (get_dr0 || get_all)) { + error = vm_get_register(vcpu, VM_REG_GUEST_DR0, &dr0); + if (error == 0) + printf("dr0[%d]\t\t0x%016lx\n", vcpuid, dr0); + } + + if (!error && (get_dr1 || get_all)) { + error = vm_get_register(vcpu, VM_REG_GUEST_DR1, &dr1); + if (error == 0) + printf("dr1[%d]\t\t0x%016lx\n", vcpuid, dr1); + } + + if (!error && (get_dr2 || get_all)) { + error = vm_get_register(vcpu, VM_REG_GUEST_DR2, &dr2); + if (error == 0) + printf("dr2[%d]\t\t0x%016lx\n", vcpuid, dr2); + } + + if (!error && (get_dr3 || get_all)) { + error = vm_get_register(vcpu, VM_REG_GUEST_DR3, &dr3); + if (error == 0) + printf("dr3[%d]\t\t0x%016lx\n", vcpuid, dr3); + } + + if (!error && (get_dr6 || get_all)) { + error = vm_get_register(vcpu, VM_REG_GUEST_DR6, &dr6); + if (error == 0) + printf("dr6[%d]\t\t0x%016lx\n", vcpuid, dr6); + } + + if (!error && (get_dr7 || get_all)) { + error = vm_get_register(vcpu, VM_REG_GUEST_DR7, &dr7); + if (error == 0) + printf("dr7[%d]\t\t0x%016lx\n", vcpuid, dr7); + } + + if (!error && (get_rsp || get_all)) { + error = vm_get_register(vcpu, VM_REG_GUEST_RSP, &rsp); + if (error == 0) + printf("rsp[%d]\t\t0x%016lx\n", vcpuid, rsp); + } + + if (!error && (get_rip || get_all)) { + error = vm_get_register(vcpu, VM_REG_GUEST_RIP, &rip); + if (error == 0) + printf("rip[%d]\t\t0x%016lx\n", vcpuid, rip); + } + + if (!error && (get_rax || get_all)) { + error = vm_get_register(vcpu, VM_REG_GUEST_RAX, &rax); + if (error == 0) + printf("rax[%d]\t\t0x%016lx\n", vcpuid, rax); + } + + if (!error && (get_rbx || get_all)) { + error = vm_get_register(vcpu, VM_REG_GUEST_RBX, &rbx); + if (error == 0) + printf("rbx[%d]\t\t0x%016lx\n", vcpuid, rbx); + } + + if (!error && (get_rcx || get_all)) { + error = vm_get_register(vcpu, VM_REG_GUEST_RCX, &rcx); + if (error == 0) + printf("rcx[%d]\t\t0x%016lx\n", vcpuid, rcx); + } + + if (!error && (get_rdx || get_all)) { + error = vm_get_register(vcpu, VM_REG_GUEST_RDX, &rdx); + if (error == 0) + printf("rdx[%d]\t\t0x%016lx\n", vcpuid, rdx); + } + + if (!error && (get_rsi || get_all)) { + error = vm_get_register(vcpu, VM_REG_GUEST_RSI, &rsi); + if (error == 0) + printf("rsi[%d]\t\t0x%016lx\n", vcpuid, rsi); + } + + if (!error && (get_rdi || get_all)) { + error = vm_get_register(vcpu, VM_REG_GUEST_RDI, &rdi); + if (error == 0) + printf("rdi[%d]\t\t0x%016lx\n", vcpuid, rdi); + } + + if (!error && (get_rbp || get_all)) { + error = vm_get_register(vcpu, VM_REG_GUEST_RBP, &rbp); + if (error == 0) + printf("rbp[%d]\t\t0x%016lx\n", vcpuid, rbp); + } + + if (!error && (get_r8 || get_all)) { + error = vm_get_register(vcpu, VM_REG_GUEST_R8, &r8); + if (error == 0) + printf("r8[%d]\t\t0x%016lx\n", vcpuid, r8); + } + + if (!error && (get_r9 || get_all)) { + error = vm_get_register(vcpu, VM_REG_GUEST_R9, &r9); + if (error == 0) + printf("r9[%d]\t\t0x%016lx\n", vcpuid, r9); + } + + if (!error && (get_r10 || get_all)) { + error = vm_get_register(vcpu, VM_REG_GUEST_R10, &r10); + if (error == 0) + printf("r10[%d]\t\t0x%016lx\n", vcpuid, r10); + } + + if (!error && (get_r11 || get_all)) { + error = vm_get_register(vcpu, VM_REG_GUEST_R11, &r11); + if (error == 0) + printf("r11[%d]\t\t0x%016lx\n", vcpuid, r11); + } + + if (!error && (get_r12 || get_all)) { + error = vm_get_register(vcpu, VM_REG_GUEST_R12, &r12); + if (error == 0) + printf("r12[%d]\t\t0x%016lx\n", vcpuid, r12); + } + + if (!error && (get_r13 || get_all)) { + error = vm_get_register(vcpu, VM_REG_GUEST_R13, &r13); + if (error == 0) + printf("r13[%d]\t\t0x%016lx\n", vcpuid, r13); + } + + if (!error && (get_r14 || get_all)) { + error = vm_get_register(vcpu, VM_REG_GUEST_R14, &r14); + if (error == 0) + printf("r14[%d]\t\t0x%016lx\n", vcpuid, r14); + } + + if (!error && (get_r15 || get_all)) { + error = vm_get_register(vcpu, VM_REG_GUEST_R15, &r15); + if (error == 0) + printf("r15[%d]\t\t0x%016lx\n", vcpuid, r15); + } + + if (!error && (get_rflags || get_all)) { + error = vm_get_register(vcpu, VM_REG_GUEST_RFLAGS, + &rflags); + if (error == 0) + printf("rflags[%d]\t0x%016lx\n", vcpuid, rflags); + } + + return (error); +} + +static int +get_all_segments(struct vcpu *vcpu, int vcpuid, bool get_all) +{ + uint64_t cs, ds, es, fs, gs, ss, tr, ldtr; + int error = 0; + + if (!error && (get_desc_ds || get_all)) { + error = vm_get_desc(vcpu, VM_REG_GUEST_DS, + &desc_base, &desc_limit, &desc_access); + if (error == 0) { + printf("ds desc[%d]\t0x%016lx/0x%08x/0x%08x\n", + vcpuid, desc_base, desc_limit, desc_access); + } + } + + if (!error && (get_desc_es || get_all)) { + error = vm_get_desc(vcpu, VM_REG_GUEST_ES, + &desc_base, &desc_limit, &desc_access); + if (error == 0) { + printf("es desc[%d]\t0x%016lx/0x%08x/0x%08x\n", + vcpuid, desc_base, desc_limit, desc_access); + } + } + + if (!error && (get_desc_fs || get_all)) { + error = vm_get_desc(vcpu, VM_REG_GUEST_FS, + &desc_base, &desc_limit, &desc_access); + if (error == 0) { + printf("fs desc[%d]\t0x%016lx/0x%08x/0x%08x\n", + vcpuid, desc_base, desc_limit, desc_access); + } + } + + if (!error && (get_desc_gs || get_all)) { + error = vm_get_desc(vcpu, VM_REG_GUEST_GS, + &desc_base, &desc_limit, &desc_access); + if (error == 0) { + printf("gs desc[%d]\t0x%016lx/0x%08x/0x%08x\n", + vcpuid, desc_base, desc_limit, desc_access); + } + } + + if (!error && (get_desc_ss || get_all)) { + error = vm_get_desc(vcpu, VM_REG_GUEST_SS, + &desc_base, &desc_limit, &desc_access); + if (error == 0) { + printf("ss desc[%d]\t0x%016lx/0x%08x/0x%08x\n", + vcpuid, desc_base, desc_limit, desc_access); + } + } + + if (!error && (get_desc_cs || get_all)) { + error = vm_get_desc(vcpu, VM_REG_GUEST_CS, + &desc_base, &desc_limit, &desc_access); + if (error == 0) { + printf("cs desc[%d]\t0x%016lx/0x%08x/0x%08x\n", + vcpuid, desc_base, desc_limit, desc_access); + } + } + + if (!error && (get_desc_tr || get_all)) { + error = vm_get_desc(vcpu, VM_REG_GUEST_TR, + &desc_base, &desc_limit, &desc_access); + if (error == 0) { + printf("tr desc[%d]\t0x%016lx/0x%08x/0x%08x\n", + vcpuid, desc_base, desc_limit, desc_access); + } + } + + if (!error && (get_desc_ldtr || get_all)) { + error = vm_get_desc(vcpu, VM_REG_GUEST_LDTR, + &desc_base, &desc_limit, &desc_access); + if (error == 0) { + printf("ldtr desc[%d]\t0x%016lx/0x%08x/0x%08x\n", + vcpuid, desc_base, desc_limit, desc_access); + } + } + + if (!error && (get_desc_gdtr || get_all)) { + error = vm_get_desc(vcpu, VM_REG_GUEST_GDTR, + &desc_base, &desc_limit, &desc_access); + if (error == 0) { + printf("gdtr[%d]\t\t0x%016lx/0x%08x\n", + vcpuid, desc_base, desc_limit); + } + } + + if (!error && (get_desc_idtr || get_all)) { + error = vm_get_desc(vcpu, VM_REG_GUEST_IDTR, + &desc_base, &desc_limit, &desc_access); + if (error == 0) { + printf("idtr[%d]\t\t0x%016lx/0x%08x\n", + vcpuid, desc_base, desc_limit); + } + } + + if (!error && (get_cs || get_all)) { + error = vm_get_register(vcpu, VM_REG_GUEST_CS, &cs); + if (error == 0) + printf("cs[%d]\t\t0x%04lx\n", vcpuid, cs); + } + + if (!error && (get_ds || get_all)) { + error = vm_get_register(vcpu, VM_REG_GUEST_DS, &ds); + if (error == 0) + printf("ds[%d]\t\t0x%04lx\n", vcpuid, ds); + } + + if (!error && (get_es || get_all)) { + error = vm_get_register(vcpu, VM_REG_GUEST_ES, &es); + if (error == 0) + printf("es[%d]\t\t0x%04lx\n", vcpuid, es); + } + + if (!error && (get_fs || get_all)) { + error = vm_get_register(vcpu, VM_REG_GUEST_FS, &fs); + if (error == 0) + printf("fs[%d]\t\t0x%04lx\n", vcpuid, fs); + } + + if (!error && (get_gs || get_all)) { + error = vm_get_register(vcpu, VM_REG_GUEST_GS, &gs); + if (error == 0) + printf("gs[%d]\t\t0x%04lx\n", vcpuid, gs); + } + + if (!error && (get_ss || get_all)) { + error = vm_get_register(vcpu, VM_REG_GUEST_SS, &ss); + if (error == 0) + printf("ss[%d]\t\t0x%04lx\n", vcpuid, ss); + } + + if (!error && (get_tr || get_all)) { + error = vm_get_register(vcpu, VM_REG_GUEST_TR, &tr); + if (error == 0) + printf("tr[%d]\t\t0x%04lx\n", vcpuid, tr); + } + + if (!error && (get_ldtr || get_all)) { + error = vm_get_register(vcpu, VM_REG_GUEST_LDTR, &ldtr); + if (error == 0) + printf("ldtr[%d]\t\t0x%04lx\n", vcpuid, ldtr); + } + + return (error); +} + +static int +get_misc_vmcs(struct vcpu *vcpu, int vcpuid, bool get_all) +{ + uint64_t ctl, cr0, cr3, cr4, rsp, rip, pat, addr, u64; + int error = 0; + + if (!error && (get_cr0_mask || get_all)) { + uint64_t cr0mask; + error = vm_get_vmcs_field(vcpu, VMCS_CR0_MASK, &cr0mask); + if (error == 0) + printf("cr0_mask[%d]\t\t0x%016lx\n", vcpuid, cr0mask); + } + + if (!error && (get_cr0_shadow || get_all)) { + uint64_t cr0shadow; + error = vm_get_vmcs_field(vcpu, VMCS_CR0_SHADOW, + &cr0shadow); + if (error == 0) + printf("cr0_shadow[%d]\t\t0x%016lx\n", vcpuid, cr0shadow); + } + + if (!error && (get_cr4_mask || get_all)) { + uint64_t cr4mask; + error = vm_get_vmcs_field(vcpu, VMCS_CR4_MASK, &cr4mask); + if (error == 0) + printf("cr4_mask[%d]\t\t0x%016lx\n", vcpuid, cr4mask); + } + + if (!error && (get_cr4_shadow || get_all)) { + uint64_t cr4shadow; + error = vm_get_vmcs_field(vcpu, VMCS_CR4_SHADOW, + &cr4shadow); + if (error == 0) + printf("cr4_shadow[%d]\t\t0x%016lx\n", vcpuid, cr4shadow); + } + + if (!error && (get_cr3_targets || get_all)) { + uint64_t target_count, target_addr; + error = vm_get_vmcs_field(vcpu, VMCS_CR3_TARGET_COUNT, + &target_count); + if (error == 0) { + printf("cr3_target_count[%d]\t0x%016lx\n", + vcpuid, target_count); + } + + error = vm_get_vmcs_field(vcpu, VMCS_CR3_TARGET0, + &target_addr); + if (error == 0) { + printf("cr3_target0[%d]\t\t0x%016lx\n", + vcpuid, target_addr); + } + + error = vm_get_vmcs_field(vcpu, VMCS_CR3_TARGET1, + &target_addr); + if (error == 0) { + printf("cr3_target1[%d]\t\t0x%016lx\n", + vcpuid, target_addr); + } + + error = vm_get_vmcs_field(vcpu, VMCS_CR3_TARGET2, + &target_addr); + if (error == 0) { + printf("cr3_target2[%d]\t\t0x%016lx\n", + vcpuid, target_addr); + } + + error = vm_get_vmcs_field(vcpu, VMCS_CR3_TARGET3, + &target_addr); + if (error == 0) { + printf("cr3_target3[%d]\t\t0x%016lx\n", + vcpuid, target_addr); + } + } + + if (!error && (get_pinbased_ctls || get_all)) { + error = vm_get_vmcs_field(vcpu, VMCS_PIN_BASED_CTLS, &ctl); + if (error == 0) + printf("pinbased_ctls[%d]\t0x%016lx\n", vcpuid, ctl); + } + + if (!error && (get_procbased_ctls || get_all)) { + error = vm_get_vmcs_field(vcpu, + VMCS_PRI_PROC_BASED_CTLS, &ctl); + if (error == 0) + printf("procbased_ctls[%d]\t0x%016lx\n", vcpuid, ctl); + } + + if (!error && (get_procbased_ctls2 || get_all)) { + error = vm_get_vmcs_field(vcpu, + VMCS_SEC_PROC_BASED_CTLS, &ctl); + if (error == 0) + printf("procbased_ctls2[%d]\t0x%016lx\n", vcpuid, ctl); + } + + if (!error && (get_vmcs_gla || get_all)) { + error = vm_get_vmcs_field(vcpu, + VMCS_GUEST_LINEAR_ADDRESS, &u64); + if (error == 0) + printf("gla[%d]\t\t0x%016lx\n", vcpuid, u64); + } + + if (!error && (get_vmcs_gpa || get_all)) { + error = vm_get_vmcs_field(vcpu, + VMCS_GUEST_PHYSICAL_ADDRESS, &u64); + if (error == 0) + printf("gpa[%d]\t\t0x%016lx\n", vcpuid, u64); + } + + if (!error && (get_vmcs_entry_interruption_info || + get_all)) { + error = vm_get_vmcs_field(vcpu, VMCS_ENTRY_INTR_INFO,&u64); + if (error == 0) { + printf("entry_interruption_info[%d]\t0x%016lx\n", + vcpuid, u64); + } + } + + if (!error && (get_tpr_threshold || get_all)) { + uint64_t threshold; + error = vm_get_vmcs_field(vcpu, VMCS_TPR_THRESHOLD, + &threshold); + if (error == 0) + printf("tpr_threshold[%d]\t0x%016lx\n", vcpuid, threshold); + } + + if (!error && (get_inst_err || get_all)) { + uint64_t insterr; + error = vm_get_vmcs_field(vcpu, VMCS_INSTRUCTION_ERROR, + &insterr); + if (error == 0) { + printf("instruction_error[%d]\t0x%016lx\n", + vcpuid, insterr); *** 3131 LINES SKIPPED ***