Skip to content

Commit df331f2

Browse files
VMM/NEM/linux: Don't require KVM_CAP_XCRS to allow running on older CPUs (untested), bugref:11046, github:gh-301
svn:sync-xref-src-repo-rev: r173376
1 parent 350eac1 commit df331f2

3 files changed

Lines changed: 60 additions & 56 deletions

File tree

src/VBox/VMM/VMMR3/NEMR3NativeTemplate-linux.cpp.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $Id: NEMR3NativeTemplate-linux.cpp.h 113132 2026-02-23 18:18:04Z alexander.eichner@oracle.com $ */
1+
/* $Id: NEMR3NativeTemplate-linux.cpp.h 113606 2026-03-27 07:25:58Z alexander.eichner@oracle.com $ */
22
/** @file
33
* NEM - Native execution manager, native ring-3 Linux backend, common bits for x86 and arm64.
44
*/
@@ -593,7 +593,7 @@ static int nemR3LnxInitCheckCapabilities(PVM pVM, PRTERRINFO pErrInfo)
593593
CAP_ENTRY__U(55),
594594
#endif
595595
#ifdef __KVM_HAVE_XCRS
596-
CAP_ENTRY_ML(KVM_CAP_XCRS),
596+
CAP_ENTRY__S(KVM_CAP_XCRS, fXcrs),
597597
#else
598598
CAP_ENTRY__U(56),
599599
#endif

src/VBox/VMM/VMMR3/target-x86/NEMR3Native-linux-x86.cpp

Lines changed: 55 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $Id: NEMR3Native-linux-x86.cpp 113168 2026-02-26 08:53:43Z alexander.eichner@oracle.com $ */
1+
/* $Id: NEMR3Native-linux-x86.cpp 113606 2026-03-27 07:25:58Z alexander.eichner@oracle.com $ */
22
/** @file
33
* NEM - Native execution manager, native ring-3 Linux backend.
44
*/
@@ -692,42 +692,43 @@ static int nemHCLnxImportState(PVMCPUCC pVCpu, uint64_t fWhat, PCPUMCTX pCtx, st
692692
/*
693693
* FPU, SSE, AVX, ++.
694694
*/
695+
if (fWhat & (CPUMCTX_EXTRN_X87 | CPUMCTX_EXTRN_SSE_AVX | CPUMCTX_EXTRN_OTHER_XSAVE))
696+
{
697+
fWhat |= CPUMCTX_EXTRN_X87 | CPUMCTX_EXTRN_SSE_AVX | CPUMCTX_EXTRN_OTHER_XSAVE; /* we do all or nothing at all */
698+
699+
AssertCompile(sizeof(pCtx->XState) >= sizeof(struct kvm_xsave));
700+
int rc = ioctl(pVCpu->nem.s.fdVCpu, KVM_GET_XSAVE, &pCtx->XState);
701+
AssertMsgReturn(rc == 0, ("rc=%d errno=%d\n", rc, errno), VERR_NEM_IPE_3);
702+
}
703+
704+
/*
705+
* XCRs.
706+
*/
695707
bool fUpdateXcr0 = false;
696708
uint64_t u64Xcr0 = 0;
697-
if (fWhat & (CPUMCTX_EXTRN_X87 | CPUMCTX_EXTRN_SSE_AVX | CPUMCTX_EXTRN_OTHER_XSAVE | CPUMCTX_EXTRN_XCRx))
709+
if ( pVM->nem.s.fXcrs
710+
&& (fWhat & CPUMCTX_EXTRN_XCRx))
698711
{
699-
if (fWhat & (CPUMCTX_EXTRN_X87 | CPUMCTX_EXTRN_SSE_AVX | CPUMCTX_EXTRN_OTHER_XSAVE))
700-
{
701-
fWhat |= CPUMCTX_EXTRN_X87 | CPUMCTX_EXTRN_SSE_AVX | CPUMCTX_EXTRN_OTHER_XSAVE; /* we do all or nothing at all */
712+
struct kvm_xcrs Xcrs =
713+
{ /*.nr_xcrs = */ 2,
714+
/*.flags = */ 0,
715+
/*.xcrs= */ {
716+
{ /*.xcr =*/ 0, /*.reserved=*/ 0, /*.value=*/ pCtx->aXcr[0] },
717+
{ /*.xcr =*/ 1, /*.reserved=*/ 0, /*.value=*/ pCtx->aXcr[1] },
718+
}
719+
};
702720

703-
AssertCompile(sizeof(pCtx->XState) >= sizeof(struct kvm_xsave));
704-
int rc = ioctl(pVCpu->nem.s.fdVCpu, KVM_GET_XSAVE, &pCtx->XState);
705-
AssertMsgReturn(rc == 0, ("rc=%d errno=%d\n", rc, errno), VERR_NEM_IPE_3);
706-
}
721+
int rc = ioctl(pVCpu->nem.s.fdVCpu, KVM_GET_XCRS, &Xcrs);
722+
AssertMsgReturn(rc == 0, ("rc=%d errno=%d\n", rc, errno), VERR_NEM_IPE_3);
707723

708-
if (fWhat & CPUMCTX_EXTRN_XCRx)
724+
if (pCtx->aXcr[0] != Xcrs.xcrs[0].value)
709725
{
710-
struct kvm_xcrs Xcrs =
711-
{ /*.nr_xcrs = */ 2,
712-
/*.flags = */ 0,
713-
/*.xcrs= */ {
714-
{ /*.xcr =*/ 0, /*.reserved=*/ 0, /*.value=*/ pCtx->aXcr[0] },
715-
{ /*.xcr =*/ 1, /*.reserved=*/ 0, /*.value=*/ pCtx->aXcr[1] },
716-
}
717-
};
718-
719-
int rc = ioctl(pVCpu->nem.s.fdVCpu, KVM_GET_XCRS, &Xcrs);
720-
AssertMsgReturn(rc == 0, ("rc=%d errno=%d\n", rc, errno), VERR_NEM_IPE_3);
721-
722-
if (pCtx->aXcr[0] != Xcrs.xcrs[0].value)
723-
{
724-
u64Xcr0 = Xcrs.xcrs[0].value;
725-
fUpdateXcr0 = true;
726-
}
727-
728-
/** @todo Same logic for XCR1 when it becomes necessary. */
729-
pCtx->aXcr[1] = Xcrs.xcrs[1].value;
726+
u64Xcr0 = Xcrs.xcrs[0].value;
727+
fUpdateXcr0 = true;
730728
}
729+
730+
/** @todo Same logic for XCR1 when it becomes necessary. */
731+
pCtx->aXcr[1] = Xcrs.xcrs[1].value;
731732
}
732733

733734
/*
@@ -1150,33 +1151,34 @@ static int nemHCLnxExportState(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, struct kvm_
11501151
/*
11511152
* FPU, SSE, AVX, ++.
11521153
*/
1153-
if (fExtrn & (CPUMCTX_EXTRN_X87 | CPUMCTX_EXTRN_SSE_AVX | CPUMCTX_EXTRN_OTHER_XSAVE | CPUMCTX_EXTRN_XCRx))
1154+
if (fExtrn & (CPUMCTX_EXTRN_X87 | CPUMCTX_EXTRN_SSE_AVX | CPUMCTX_EXTRN_OTHER_XSAVE))
11541155
{
1155-
if (fExtrn & (CPUMCTX_EXTRN_X87 | CPUMCTX_EXTRN_SSE_AVX | CPUMCTX_EXTRN_OTHER_XSAVE))
1156-
{
1157-
/** @todo could IEM just grab state partial control in some situations? */
1158-
Assert( (fExtrn & (CPUMCTX_EXTRN_X87 | CPUMCTX_EXTRN_SSE_AVX | CPUMCTX_EXTRN_OTHER_XSAVE))
1159-
== (CPUMCTX_EXTRN_X87 | CPUMCTX_EXTRN_SSE_AVX | CPUMCTX_EXTRN_OTHER_XSAVE)); /* no partial states */
1156+
/** @todo could IEM just grab state partial control in some situations? */
1157+
Assert( (fExtrn & (CPUMCTX_EXTRN_X87 | CPUMCTX_EXTRN_SSE_AVX | CPUMCTX_EXTRN_OTHER_XSAVE))
1158+
== (CPUMCTX_EXTRN_X87 | CPUMCTX_EXTRN_SSE_AVX | CPUMCTX_EXTRN_OTHER_XSAVE)); /* no partial states */
11601159

1161-
AssertCompile(sizeof(pCtx->XState) >= sizeof(struct kvm_xsave));
1162-
int rc = ioctl(pVCpu->nem.s.fdVCpu, KVM_SET_XSAVE, &pCtx->XState);
1163-
AssertMsgReturn(rc == 0, ("rc=%d errno=%d\n", rc, errno), VERR_NEM_IPE_3);
1164-
}
1160+
AssertCompile(sizeof(pCtx->XState) >= sizeof(struct kvm_xsave));
1161+
int rc = ioctl(pVCpu->nem.s.fdVCpu, KVM_SET_XSAVE, &pCtx->XState);
1162+
AssertMsgReturn(rc == 0, ("rc=%d errno=%d\n", rc, errno), VERR_NEM_IPE_3);
1163+
}
11651164

1166-
if (fExtrn & CPUMCTX_EXTRN_XCRx)
1167-
{
1168-
struct kvm_xcrs Xcrs =
1169-
{ /*.nr_xcrs = */ 2,
1170-
/*.flags = */ 0,
1171-
/*.xcrs= */ {
1172-
{ /*.xcr =*/ 0, /*.reserved=*/ 0, /*.value=*/ pCtx->aXcr[0] },
1173-
{ /*.xcr =*/ 1, /*.reserved=*/ 0, /*.value=*/ pCtx->aXcr[1] },
1174-
}
1175-
};
1165+
/*
1166+
* XCR.
1167+
*/
1168+
if ( pVM->nem.s.fXcrs
1169+
&& (fExtrn & CPUMCTX_EXTRN_XCRx))
1170+
{
1171+
struct kvm_xcrs Xcrs =
1172+
{ /*.nr_xcrs = */ 2,
1173+
/*.flags = */ 0,
1174+
/*.xcrs= */ {
1175+
{ /*.xcr =*/ 0, /*.reserved=*/ 0, /*.value=*/ pCtx->aXcr[0] },
1176+
{ /*.xcr =*/ 1, /*.reserved=*/ 0, /*.value=*/ pCtx->aXcr[1] },
1177+
}
1178+
};
11761179

1177-
int rc = ioctl(pVCpu->nem.s.fdVCpu, KVM_SET_XCRS, &Xcrs);
1178-
AssertMsgReturn(rc == 0, ("rc=%d errno=%d\n", rc, errno), VERR_NEM_IPE_3);
1179-
}
1180+
int rc = ioctl(pVCpu->nem.s.fdVCpu, KVM_SET_XCRS, &Xcrs);
1181+
AssertMsgReturn(rc == 0, ("rc=%d errno=%d\n", rc, errno), VERR_NEM_IPE_3);
11801182
}
11811183

11821184
/*

src/VBox/VMM/include/NEMInternal.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $Id: NEMInternal.h 113132 2026-02-23 18:18:04Z alexander.eichner@oracle.com $ */
1+
/* $Id: NEMInternal.h 113606 2026-03-27 07:25:58Z alexander.eichner@oracle.com $ */
22
/** @file
33
* NEM - Internal header file.
44
*/
@@ -234,6 +234,8 @@ typedef struct NEM
234234
bool fRobustSingleStep;
235235
/** KVM_CAP_SPLIT_IRQCHIP */
236236
bool fKvmApic;
237+
/** KVM_CAP_XCRS */
238+
bool fXcrs;
237239
# endif
238240
/** Size of the nested virt state, 0 if not supported. */
239241
uint32_t cbNestedState;

0 commit comments

Comments
 (0)