Print this page
13275 bhyve needs richer INIT/SIPI support
Reviewed by: Robert Mustacchi <rm@fingolfin.org>
Approved by: Gordon Ross <gordon.w.ross@gmail.com>


1900         gctx->sctx_dr2 = rdr2();
1901         gctx->sctx_dr3 = rdr3();
1902 
1903         /*
1904          * Restore host debug registers.  Restore DR7 and DEBUGCTL
1905          * last.
1906          */
1907         load_dr0(gctx->host_dr0);
1908         load_dr1(gctx->host_dr1);
1909         load_dr2(gctx->host_dr2);
1910         load_dr3(gctx->host_dr3);
1911         load_dr6(gctx->host_dr6);
1912         wrmsr(MSR_DEBUGCTLMSR, gctx->host_debugctl);
1913         load_dr7(gctx->host_dr7);
1914 }
1915 
1916 /*
1917  * Start vcpu with specified RIP.
1918  */
1919 static int
1920 svm_vmrun(void *arg, int vcpu, uint64_t rip, pmap_t pmap,
1921     struct vm_eventinfo *evinfo)
1922 {
1923         struct svm_regctx *gctx;
1924         struct svm_softc *svm_sc;
1925         struct svm_vcpu *vcpustate;
1926         struct vmcb_state *state;
1927         struct vmcb_ctrl *ctrl;
1928         struct vm_exit *vmexit;
1929         struct vlapic *vlapic;
1930         struct vm *vm;
1931         uint64_t vmcb_pa;
1932         int handled;
1933         uint16_t ldt_sel;
1934 
1935         svm_sc = arg;
1936         vm = svm_sc->vm;
1937 
1938         vcpustate = svm_get_vcpu(svm_sc, vcpu);
1939         state = svm_get_vmcb_state(svm_sc, vcpu);
1940         ctrl = svm_get_vmcb_ctrl(svm_sc, vcpu);
1941         vmexit = vm_exitinfo(vm, vcpu);


1993                  */
1994                 inject_state = svm_inject_events(svm_sc, vcpu);
1995                 handled = 0;
1996 
1997                 /*
1998                  * Disable global interrupts to guarantee atomicity during
1999                  * loading of guest state. This includes not only the state
2000                  * loaded by the "vmrun" instruction but also software state
2001                  * maintained by the hypervisor: suspended and rendezvous
2002                  * state, NPT generation number, vlapic interrupts etc.
2003                  */
2004                 disable_gintr();
2005 
2006                 /*
2007                  * Synchronizing and injecting vlapic state is lock-free and is
2008                  * safe (and prudent) to perform with interrupts disabled.
2009                  */
2010                 inject_state = svm_inject_vlapic(svm_sc, vcpu, vlapic,
2011                     inject_state);
2012 
2013                 if (vcpu_suspended(evinfo)) {




2014                         enable_gintr();
2015                         vm_exit_suspended(vm, vcpu, state->rip);
2016                         break;
2017                 }
2018 
2019                 if (vcpu_runblocked(evinfo)) {
2020                         enable_gintr();
2021                         vm_exit_runblock(vm, vcpu, state->rip);
2022                         break;
2023                 }
2024 
2025                 if (vcpu_reqidle(evinfo)) {
2026                         enable_gintr();
2027                         vm_exit_reqidle(vm, vcpu, state->rip);
2028                         break;
2029                 }
2030 
2031                 /* We are asked to give the cpu by scheduler. */
2032                 if (vcpu_should_yield(vm, vcpu)) {
2033                         enable_gintr();
2034                         vm_exit_astpending(vm, vcpu, state->rip);
2035                         break;
2036                 }
2037 
2038                 if (vcpu_debugged(vm, vcpu)) {
2039                         enable_gintr();
2040                         vm_exit_debug(vm, vcpu, state->rip);
2041                         break;
2042                 }
2043 
2044                 /*
2045                  * If subsequent activity queued events which require injection
2046                  * handling, take another lap to handle them.
2047                  */
2048                 if (svm_inject_recheck(svm_sc, vcpu, inject_state)) {
2049                         enable_gintr();
2050                         handled = 1;
2051                         continue;
2052                 }
2053 
2054                 /*
2055                  * #VMEXIT resumes the host with the guest LDTR, so
2056                  * save the current LDT selector so it can be restored
2057                  * after an exit.  The userspace hypervisor probably
2058                  * doesn't use a LDT, but save and restore it to be
2059                  * safe.
2060                  */
2061                 ldt_sel = sldt();
2062 
2063                 /* Activate the nested pmap on 'curcpu' */


2286                 return (EINVAL);
2287 
2288         default:
2289                 return (EINVAL);
2290         }
2291 
2292         if (dirty != VMCB_CACHE_NONE) {
2293                 svm_set_dirty(sc, vcpu, dirty);
2294         }
2295 
2296         /*
2297          * XXX deal with CR3 and invalidate TLB entries tagged with the
2298          * vcpu's ASID. This needs to be treated differently depending on
2299          * whether 'running' is true/false.
2300          */
2301 
2302         return (0);
2303 }
2304 
2305 static int
2306 svm_setdesc(void *arg, int vcpu, int reg, struct seg_desc *desc)
2307 {
2308         struct vmcb *vmcb;
2309         struct svm_softc *sc;
2310         struct vmcb_segment *seg;
2311 
2312         sc = arg;
2313         vmcb = svm_get_vmcb(sc, vcpu);
2314 
2315         switch (reg) {
2316         case VM_REG_GUEST_CS:
2317         case VM_REG_GUEST_DS:
2318         case VM_REG_GUEST_ES:
2319         case VM_REG_GUEST_SS:
2320         case VM_REG_GUEST_FS:
2321         case VM_REG_GUEST_GS:
2322         case VM_REG_GUEST_LDTR:
2323         case VM_REG_GUEST_TR:
2324                 svm_set_dirty(sc, vcpu, VMCB_CACHE_SEG);
2325                 seg = vmcb_segptr(vmcb, reg);
2326                 /*




1900         gctx->sctx_dr2 = rdr2();
1901         gctx->sctx_dr3 = rdr3();
1902 
1903         /*
1904          * Restore host debug registers.  Restore DR7 and DEBUGCTL
1905          * last.
1906          */
1907         load_dr0(gctx->host_dr0);
1908         load_dr1(gctx->host_dr1);
1909         load_dr2(gctx->host_dr2);
1910         load_dr3(gctx->host_dr3);
1911         load_dr6(gctx->host_dr6);
1912         wrmsr(MSR_DEBUGCTLMSR, gctx->host_debugctl);
1913         load_dr7(gctx->host_dr7);
1914 }
1915 
1916 /*
1917  * Start vcpu with specified RIP.
1918  */
1919 static int
1920 svm_vmrun(void *arg, int vcpu, uint64_t rip, pmap_t pmap)

1921 {
1922         struct svm_regctx *gctx;
1923         struct svm_softc *svm_sc;
1924         struct svm_vcpu *vcpustate;
1925         struct vmcb_state *state;
1926         struct vmcb_ctrl *ctrl;
1927         struct vm_exit *vmexit;
1928         struct vlapic *vlapic;
1929         struct vm *vm;
1930         uint64_t vmcb_pa;
1931         int handled;
1932         uint16_t ldt_sel;
1933 
1934         svm_sc = arg;
1935         vm = svm_sc->vm;
1936 
1937         vcpustate = svm_get_vcpu(svm_sc, vcpu);
1938         state = svm_get_vmcb_state(svm_sc, vcpu);
1939         ctrl = svm_get_vmcb_ctrl(svm_sc, vcpu);
1940         vmexit = vm_exitinfo(vm, vcpu);


1992                  */
1993                 inject_state = svm_inject_events(svm_sc, vcpu);
1994                 handled = 0;
1995 
1996                 /*
1997                  * Disable global interrupts to guarantee atomicity during
1998                  * loading of guest state. This includes not only the state
1999                  * loaded by the "vmrun" instruction but also software state
2000                  * maintained by the hypervisor: suspended and rendezvous
2001                  * state, NPT generation number, vlapic interrupts etc.
2002                  */
2003                 disable_gintr();
2004 
2005                 /*
2006                  * Synchronizing and injecting vlapic state is lock-free and is
2007                  * safe (and prudent) to perform with interrupts disabled.
2008                  */
2009                 inject_state = svm_inject_vlapic(svm_sc, vcpu, vlapic,
2010                     inject_state);
2011 
2012                 /*
2013                  * Check for vCPU bail-out conditions.  This must be done after
2014                  * svm_inject_events() to detect a triple-fault condition.
2015                  */
2016                 if (vcpu_entry_bailout_checks(vm, vcpu, state->rip)) {
2017                         enable_gintr();

2018                         break;
2019                 }
2020 
2021                 if (vcpu_run_state_pending(vm, vcpu)) {
2022                         enable_gintr();
2023                         vm_exit_run_state(vm, vcpu, state->rip);
2024                         break;
2025                 }
2026 



















2027                 /*
2028                  * If subsequent activity queued events which require injection
2029                  * handling, take another lap to handle them.
2030                  */
2031                 if (svm_inject_recheck(svm_sc, vcpu, inject_state)) {
2032                         enable_gintr();
2033                         handled = 1;
2034                         continue;
2035                 }
2036 
2037                 /*
2038                  * #VMEXIT resumes the host with the guest LDTR, so
2039                  * save the current LDT selector so it can be restored
2040                  * after an exit.  The userspace hypervisor probably
2041                  * doesn't use a LDT, but save and restore it to be
2042                  * safe.
2043                  */
2044                 ldt_sel = sldt();
2045 
2046                 /* Activate the nested pmap on 'curcpu' */


2269                 return (EINVAL);
2270 
2271         default:
2272                 return (EINVAL);
2273         }
2274 
2275         if (dirty != VMCB_CACHE_NONE) {
2276                 svm_set_dirty(sc, vcpu, dirty);
2277         }
2278 
2279         /*
2280          * XXX deal with CR3 and invalidate TLB entries tagged with the
2281          * vcpu's ASID. This needs to be treated differently depending on
2282          * whether 'running' is true/false.
2283          */
2284 
2285         return (0);
2286 }
2287 
2288 static int
2289 svm_setdesc(void *arg, int vcpu, int reg, const struct seg_desc *desc)
2290 {
2291         struct vmcb *vmcb;
2292         struct svm_softc *sc;
2293         struct vmcb_segment *seg;
2294 
2295         sc = arg;
2296         vmcb = svm_get_vmcb(sc, vcpu);
2297 
2298         switch (reg) {
2299         case VM_REG_GUEST_CS:
2300         case VM_REG_GUEST_DS:
2301         case VM_REG_GUEST_ES:
2302         case VM_REG_GUEST_SS:
2303         case VM_REG_GUEST_FS:
2304         case VM_REG_GUEST_GS:
2305         case VM_REG_GUEST_LDTR:
2306         case VM_REG_GUEST_TR:
2307                 svm_set_dirty(sc, vcpu, VMCB_CACHE_SEG);
2308                 seg = vmcb_segptr(vmcb, reg);
2309                 /*