From owner-svn-src-stable@FreeBSD.ORG Sun Aug 17 01:16:41 2014 Return-Path: Delivered-To: svn-src-stable@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id EA89C8DE; Sun, 17 Aug 2014 01:16:41 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id D52DD2224; Sun, 17 Aug 2014 01:16:41 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id s7H1GfAI076712; Sun, 17 Aug 2014 01:16:41 GMT (envelope-from grehan@FreeBSD.org) Received: (from grehan@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id s7H1Gfgh076709; Sun, 17 Aug 2014 01:16:41 GMT (envelope-from grehan@FreeBSD.org) Message-Id: <201408170116.s7H1Gfgh076709@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: grehan set sender to grehan@FreeBSD.org using -f From: Peter Grehan Date: Sun, 17 Aug 2014 01:16:41 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org Subject: svn commit: r270073 - in stable/10/sys/amd64/vmm: intel io X-SVN-Group: stable-10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-stable@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: SVN commit messages for all the -stable branches of the src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 17 Aug 2014 01:16:42 -0000 Author: grehan Date: Sun Aug 17 01:16:40 2014 New Revision: 270073 URL: http://svnweb.freebsd.org/changeset/base/270073 Log: MFC r267178, r267300 Support guest accesses to %cr8 Add reserved bit checking when doing %CR8 emulation and inject #GP if required. Modified: stable/10/sys/amd64/vmm/intel/vmx.c stable/10/sys/amd64/vmm/io/vlapic.c stable/10/sys/amd64/vmm/io/vlapic.h Directory Properties: stable/10/ (props changed) Modified: stable/10/sys/amd64/vmm/intel/vmx.c ============================================================================== --- stable/10/sys/amd64/vmm/intel/vmx.c Sun Aug 17 01:15:34 2014 (r270072) +++ stable/10/sys/amd64/vmm/intel/vmx.c Sun Aug 17 01:16:40 2014 (r270073) @@ -83,7 +83,9 @@ __FBSDID("$FreeBSD$"); (PROCBASED_SECONDARY_CONTROLS | \ PROCBASED_IO_EXITING | \ PROCBASED_MSR_BITMAPS | \ - PROCBASED_CTLS_WINDOW_SETTING) + PROCBASED_CTLS_WINDOW_SETTING | \ + PROCBASED_CR8_LOAD_EXITING | \ + PROCBASED_CR8_STORE_EXITING) #define PROCBASED_CTLS_ZERO_SETTING \ (PROCBASED_CR3_LOAD_EXITING | \ PROCBASED_CR3_STORE_EXITING | \ @@ -714,6 +716,13 @@ vmx_init(int ipinum) procbased_ctls2 &= ~PROCBASED2_VIRTUALIZE_X2APIC_MODE; /* + * No need to emulate accesses to %CR8 if virtual + * interrupt delivery is enabled. + */ + procbased_ctls &= ~PROCBASED_CR8_LOAD_EXITING; + procbased_ctls &= ~PROCBASED_CR8_STORE_EXITING; + + /* * Check for Posted Interrupts only if Virtual Interrupt * Delivery is enabled. */ @@ -1442,97 +1451,130 @@ vmx_emulate_xsetbv(struct vmx *vmx, int return (HANDLED); } -static int -vmx_emulate_cr_access(struct vmx *vmx, int vcpu, uint64_t exitqual) +static uint64_t +vmx_get_guest_reg(struct vmx *vmx, int vcpu, int ident) { - int cr, vmcs_guest_cr, vmcs_shadow_cr; - uint64_t crval, regval, ones_mask, zeros_mask; const struct vmxctx *vmxctx; - /* We only handle mov to %cr0 or %cr4 at this time */ - if ((exitqual & 0xf0) != 0x00) - return (UNHANDLED); + vmxctx = &vmx->ctx[vcpu]; - cr = exitqual & 0xf; - if (cr != 0 && cr != 4) - return (UNHANDLED); + switch (ident) { + case 0: + return (vmxctx->guest_rax); + case 1: + return (vmxctx->guest_rcx); + case 2: + return (vmxctx->guest_rdx); + case 3: + return (vmxctx->guest_rbx); + case 4: + return (vmcs_read(VMCS_GUEST_RSP)); + case 5: + return (vmxctx->guest_rbp); + case 6: + return (vmxctx->guest_rsi); + case 7: + return (vmxctx->guest_rdi); + case 8: + return (vmxctx->guest_r8); + case 9: + return (vmxctx->guest_r9); + case 10: + return (vmxctx->guest_r10); + case 11: + return (vmxctx->guest_r11); + case 12: + return (vmxctx->guest_r12); + case 13: + return (vmxctx->guest_r13); + case 14: + return (vmxctx->guest_r14); + case 15: + return (vmxctx->guest_r15); + default: + panic("invalid vmx register %d", ident); + } +} + +static void +vmx_set_guest_reg(struct vmx *vmx, int vcpu, int ident, uint64_t regval) +{ + struct vmxctx *vmxctx; - regval = 0; /* silence gcc */ vmxctx = &vmx->ctx[vcpu]; - /* - * We must use vmcs_write() directly here because vmcs_setreg() will - * call vmclear(vmcs) as a side-effect which we certainly don't want. - */ - switch ((exitqual >> 8) & 0xf) { + switch (ident) { case 0: - regval = vmxctx->guest_rax; + vmxctx->guest_rax = regval; break; case 1: - regval = vmxctx->guest_rcx; + vmxctx->guest_rcx = regval; break; case 2: - regval = vmxctx->guest_rdx; + vmxctx->guest_rdx = regval; break; case 3: - regval = vmxctx->guest_rbx; + vmxctx->guest_rbx = regval; break; case 4: - regval = vmcs_read(VMCS_GUEST_RSP); + vmcs_write(VMCS_GUEST_RSP, regval); break; case 5: - regval = vmxctx->guest_rbp; + vmxctx->guest_rbp = regval; break; case 6: - regval = vmxctx->guest_rsi; + vmxctx->guest_rsi = regval; break; case 7: - regval = vmxctx->guest_rdi; + vmxctx->guest_rdi = regval; break; case 8: - regval = vmxctx->guest_r8; + vmxctx->guest_r8 = regval; break; case 9: - regval = vmxctx->guest_r9; + vmxctx->guest_r9 = regval; break; case 10: - regval = vmxctx->guest_r10; + vmxctx->guest_r10 = regval; break; case 11: - regval = vmxctx->guest_r11; + vmxctx->guest_r11 = regval; break; case 12: - regval = vmxctx->guest_r12; + vmxctx->guest_r12 = regval; break; case 13: - regval = vmxctx->guest_r13; + vmxctx->guest_r13 = regval; break; case 14: - regval = vmxctx->guest_r14; + vmxctx->guest_r14 = regval; break; case 15: - regval = vmxctx->guest_r15; + vmxctx->guest_r15 = regval; break; + default: + panic("invalid vmx register %d", ident); } +} - if (cr == 0) { - ones_mask = cr0_ones_mask; - zeros_mask = cr0_zeros_mask; - vmcs_guest_cr = VMCS_GUEST_CR0; - vmcs_shadow_cr = VMCS_CR0_SHADOW; - } else { - ones_mask = cr4_ones_mask; - zeros_mask = cr4_zeros_mask; - vmcs_guest_cr = VMCS_GUEST_CR4; - vmcs_shadow_cr = VMCS_CR4_SHADOW; - } - vmcs_write(vmcs_shadow_cr, regval); - - crval = regval | ones_mask; - crval &= ~zeros_mask; - vmcs_write(vmcs_guest_cr, crval); +static int +vmx_emulate_cr0_access(struct vmx *vmx, int vcpu, uint64_t exitqual) +{ + uint64_t crval, regval; + + /* We only handle mov to %cr0 at this time */ + if ((exitqual & 0xf0) != 0x00) + return (UNHANDLED); - if (cr == 0 && regval & CR0_PG) { + regval = vmx_get_guest_reg(vmx, vcpu, (exitqual >> 8) & 0xf); + + vmcs_write(VMCS_CR0_SHADOW, regval); + + crval = regval | cr0_ones_mask; + crval &= ~cr0_zeros_mask; + vmcs_write(VMCS_GUEST_CR0, crval); + + if (regval & CR0_PG) { uint64_t efer, entry_ctls; /* @@ -1553,6 +1595,51 @@ vmx_emulate_cr_access(struct vmx *vmx, i return (HANDLED); } +static int +vmx_emulate_cr4_access(struct vmx *vmx, int vcpu, uint64_t exitqual) +{ + uint64_t crval, regval; + + /* We only handle mov to %cr4 at this time */ + if ((exitqual & 0xf0) != 0x00) + return (UNHANDLED); + + regval = vmx_get_guest_reg(vmx, vcpu, (exitqual >> 8) & 0xf); + + vmcs_write(VMCS_CR4_SHADOW, regval); + + crval = regval | cr4_ones_mask; + crval &= ~cr4_zeros_mask; + vmcs_write(VMCS_GUEST_CR4, crval); + + return (HANDLED); +} + +static int +vmx_emulate_cr8_access(struct vmx *vmx, int vcpu, uint64_t exitqual) +{ + struct vlapic *vlapic; + uint64_t cr8; + int regnum; + + /* We only handle mov %cr8 to/from a register at this time. */ + if ((exitqual & 0xe0) != 0x00) { + return (UNHANDLED); + } + + vlapic = vm_lapic(vmx->vm, vcpu); + regnum = (exitqual >> 8) & 0xf; + if (exitqual & 0x10) { + cr8 = vlapic_get_cr8(vlapic); + vmx_set_guest_reg(vmx, vcpu, regnum, cr8); + } else { + cr8 = vmx_get_guest_reg(vmx, vcpu, regnum); + vlapic_set_cr8(vlapic, cr8); + } + + return (HANDLED); +} + /* * From section "Guest Register State" in the Intel SDM: CPL = SS.DPL */ @@ -1945,7 +2032,17 @@ vmx_exit_process(struct vmx *vmx, int vc switch (reason) { case EXIT_REASON_CR_ACCESS: vmm_stat_incr(vmx->vm, vcpu, VMEXIT_CR_ACCESS, 1); - handled = vmx_emulate_cr_access(vmx, vcpu, qual); + switch (qual & 0xf) { + case 0: + handled = vmx_emulate_cr0_access(vmx, vcpu, qual); + break; + case 4: + handled = vmx_emulate_cr4_access(vmx, vcpu, qual); + break; + case 8: + handled = vmx_emulate_cr8_access(vmx, vcpu, qual); + break; + } break; case EXIT_REASON_RDMSR: vmm_stat_incr(vmx->vm, vcpu, VMEXIT_RDMSR, 1); Modified: stable/10/sys/amd64/vmm/io/vlapic.c ============================================================================== --- stable/10/sys/amd64/vmm/io/vlapic.c Sun Aug 17 01:15:34 2014 (r270072) +++ stable/10/sys/amd64/vmm/io/vlapic.c Sun Aug 17 01:16:40 2014 (r270073) @@ -906,6 +906,46 @@ vlapic_calcdest(struct vm *vm, cpuset_t static VMM_STAT_ARRAY(IPIS_SENT, VM_MAXCPU, "ipis sent to vcpu"); +static void +vlapic_set_tpr(struct vlapic *vlapic, uint8_t val) +{ + struct LAPIC *lapic = vlapic->apic_page; + + lapic->tpr = val; + vlapic_update_ppr(vlapic); +} + +static uint8_t +vlapic_get_tpr(struct vlapic *vlapic) +{ + struct LAPIC *lapic = vlapic->apic_page; + + return (lapic->tpr); +} + +void +vlapic_set_cr8(struct vlapic *vlapic, uint64_t val) +{ + uint8_t tpr; + + if (val & ~0xf) { + vm_inject_gp(vlapic->vm, vlapic->vcpuid); + return; + } + + tpr = val << 4; + vlapic_set_tpr(vlapic, tpr); +} + +uint64_t +vlapic_get_cr8(struct vlapic *vlapic) +{ + uint8_t tpr; + + tpr = vlapic_get_tpr(vlapic); + return (tpr >> 4); +} + int vlapic_icrlo_write_handler(struct vlapic *vlapic, bool *retu) { @@ -1184,7 +1224,7 @@ vlapic_read(struct vlapic *vlapic, int m *data = lapic->version; break; case APIC_OFFSET_TPR: - *data = lapic->tpr; + *data = vlapic_get_tpr(vlapic); break; case APIC_OFFSET_APR: *data = lapic->apr; @@ -1305,8 +1345,7 @@ vlapic_write(struct vlapic *vlapic, int vlapic_id_write_handler(vlapic); break; case APIC_OFFSET_TPR: - lapic->tpr = data & 0xff; - vlapic_update_ppr(vlapic); + vlapic_set_tpr(vlapic, data & 0xff); break; case APIC_OFFSET_EOI: vlapic_process_eoi(vlapic); Modified: stable/10/sys/amd64/vmm/io/vlapic.h ============================================================================== --- stable/10/sys/amd64/vmm/io/vlapic.h Sun Aug 17 01:15:34 2014 (r270072) +++ stable/10/sys/amd64/vmm/io/vlapic.h Sun Aug 17 01:16:40 2014 (r270073) @@ -92,6 +92,9 @@ void vlapic_reset_tmr(struct vlapic *vla void vlapic_set_tmr_level(struct vlapic *vlapic, uint32_t dest, bool phys, int delmode, int vector); +void vlapic_set_cr8(struct vlapic *vlapic, uint64_t val); +uint64_t vlapic_get_cr8(struct vlapic *vlapic); + /* APIC write handlers */ void vlapic_id_write_handler(struct vlapic *vlapic); void vlapic_ldr_write_handler(struct vlapic *vlapic);