Skip to content

Commit 7aa5128

Browse files
KAGA-KOKOsuryasaimadhu
authored andcommitted
x86/fpu/xsave: Handle compacted offsets correctly with supervisor states
So far the cached fixed compacted offsets worked, but with (re-)enabling of ENQCMD this does no longer work with KVM fpstate. KVM does not have supervisor features enabled for the guest FPU, which means that KVM has then a different XSAVE area layout than the host FPU state. This in turn breaks the copy from/to UABI functions when invoked for a guest state. Remove the pre-calculated compacted offsets and calculate the offset of each component at runtime based on the XCOMP_BV field in the XSAVE header. The runtime overhead is not interesting because these copy from/to UABI functions are not used in critical fast paths. KVM uses them to save and restore FPU state during migration. The host uses them for ptrace and for the slow path of 32bit signal handling. Fixes: 7c1ef59 ("x86/cpufeatures: Re-enable ENQCMD") Signed-off-by: Thomas Gleixner <[email protected]> Signed-off-by: Borislav Petkov <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 6afbb58 commit 7aa5128

File tree

1 file changed

+41
-45
lines changed

1 file changed

+41
-45
lines changed

arch/x86/kernel/fpu/xstate.c

Lines changed: 41 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,6 @@ static unsigned int xstate_offsets[XFEATURE_MAX] __ro_after_init =
8181
{ [ 0 ... XFEATURE_MAX - 1] = -1};
8282
static unsigned int xstate_sizes[XFEATURE_MAX] __ro_after_init =
8383
{ [ 0 ... XFEATURE_MAX - 1] = -1};
84-
static unsigned int xstate_comp_offsets[XFEATURE_MAX] __ro_after_init =
85-
{ [ 0 ... XFEATURE_MAX - 1] = -1};
8684
static unsigned int xstate_flags[XFEATURE_MAX] __ro_after_init;
8785

8886
#define XSTATE_FLAG_SUPERVISOR BIT(0)
@@ -136,6 +134,33 @@ static bool xfeature_is_supervisor(int xfeature_nr)
136134
return xstate_flags[xfeature_nr] & XSTATE_FLAG_SUPERVISOR;
137135
}
138136

137+
static unsigned int xfeature_get_offset(u64 xcomp_bv, int xfeature)
138+
{
139+
unsigned int offs, i;
140+
141+
/*
142+
* Non-compacted format and legacy features use the cached fixed
143+
* offsets.
144+
*/
145+
if (!cpu_feature_enabled(X86_FEATURE_XSAVES) || xfeature <= XFEATURE_SSE)
146+
return xstate_offsets[xfeature];
147+
148+
/*
149+
* Compacted format offsets depend on the actual content of the
150+
* compacted xsave area which is determined by the xcomp_bv header
151+
* field.
152+
*/
153+
offs = FXSAVE_SIZE + XSAVE_HDR_SIZE;
154+
for_each_extended_xfeature(i, xcomp_bv) {
155+
if (xfeature_is_aligned64(i))
156+
offs = ALIGN(offs, 64);
157+
if (i == xfeature)
158+
break;
159+
offs += xstate_sizes[i];
160+
}
161+
return offs;
162+
}
163+
139164
/*
140165
* Enable the extended processor state save/restore feature.
141166
* Called once per CPU onlining.
@@ -263,42 +288,6 @@ static void __init print_xstate_features(void)
263288
WARN_ON(nr >= XFEATURE_MAX); \
264289
} while (0)
265290

266-
/*
267-
* This function sets up offsets and sizes of all extended states in
268-
* xsave area. This supports both standard format and compacted format
269-
* of the xsave area.
270-
*/
271-
static void __init setup_xstate_comp_offsets(void)
272-
{
273-
unsigned int next_offset;
274-
int i;
275-
276-
/*
277-
* The FP xstates and SSE xstates are legacy states. They are always
278-
* in the fixed offsets in the xsave area in either compacted form
279-
* or standard form.
280-
*/
281-
xstate_comp_offsets[XFEATURE_FP] = 0;
282-
xstate_comp_offsets[XFEATURE_SSE] = offsetof(struct fxregs_state,
283-
xmm_space);
284-
285-
if (!cpu_feature_enabled(X86_FEATURE_XSAVES)) {
286-
for_each_extended_xfeature(i, fpu_kernel_cfg.max_features)
287-
xstate_comp_offsets[i] = xstate_offsets[i];
288-
return;
289-
}
290-
291-
next_offset = FXSAVE_SIZE + XSAVE_HDR_SIZE;
292-
293-
for_each_extended_xfeature(i, fpu_kernel_cfg.max_features) {
294-
if (xfeature_is_aligned64(i))
295-
next_offset = ALIGN(next_offset, 64);
296-
297-
xstate_comp_offsets[i] = next_offset;
298-
next_offset += xstate_sizes[i];
299-
}
300-
}
301-
302291
/*
303292
* Print out xstate component offsets and sizes
304293
*/
@@ -308,7 +297,8 @@ static void __init print_xstate_offset_size(void)
308297

309298
for_each_extended_xfeature(i, fpu_kernel_cfg.max_features) {
310299
pr_info("x86/fpu: xstate_offset[%d]: %4d, xstate_sizes[%d]: %4d\n",
311-
i, xstate_comp_offsets[i], i, xstate_sizes[i]);
300+
i, xfeature_get_offset(fpu_kernel_cfg.max_features, i),
301+
i, xstate_sizes[i]);
312302
}
313303
}
314304

@@ -901,7 +891,6 @@ void __init fpu__init_system_xstate(unsigned int legacy_size)
901891
fpu_user_cfg.max_features);
902892

903893
setup_init_fpu_buf();
904-
setup_xstate_comp_offsets();
905894

906895
/*
907896
* Paranoia check whether something in the setup modified the
@@ -956,13 +945,19 @@ void fpu__resume_cpu(void)
956945
*/
957946
static void *__raw_xsave_addr(struct xregs_state *xsave, int xfeature_nr)
958947
{
959-
if (!xfeature_enabled(xfeature_nr)) {
960-
WARN_ON_FPU(1);
948+
u64 xcomp_bv = xsave->header.xcomp_bv;
949+
950+
if (WARN_ON_ONCE(!xfeature_enabled(xfeature_nr)))
961951
return NULL;
952+
953+
if (cpu_feature_enabled(X86_FEATURE_XSAVES)) {
954+
if (WARN_ON_ONCE(!(xcomp_bv & BIT_ULL(xfeature_nr))))
955+
return NULL;
962956
}
963957

964-
return (void *)xsave + xstate_comp_offsets[xfeature_nr];
958+
return (void *)xsave + xfeature_get_offset(xcomp_bv, xfeature_nr);
965959
}
960+
966961
/*
967962
* Given the xsave area and a state inside, this function returns the
968963
* address of the state.
@@ -993,8 +988,9 @@ void *get_xsave_addr(struct xregs_state *xsave, int xfeature_nr)
993988
* We should not ever be requesting features that we
994989
* have not enabled.
995990
*/
996-
WARN_ONCE(!(fpu_kernel_cfg.max_features & BIT_ULL(xfeature_nr)),
997-
"get of unsupported state");
991+
if (WARN_ON_ONCE(!xfeature_enabled(xfeature_nr)))
992+
return NULL;
993+
998994
/*
999995
* This assumes the last 'xsave*' instruction to
1000996
* have requested that 'xfeature_nr' be saved.

0 commit comments

Comments
 (0)