@@ -62,6 +62,7 @@ u64 xfeatures_mask_all __read_mostly;
62
62
static unsigned int xstate_offsets [XFEATURE_MAX ] = { [ 0 ... XFEATURE_MAX - 1 ] = -1 };
63
63
static unsigned int xstate_sizes [XFEATURE_MAX ] = { [ 0 ... XFEATURE_MAX - 1 ] = -1 };
64
64
static unsigned int xstate_comp_offsets [XFEATURE_MAX ] = { [ 0 ... XFEATURE_MAX - 1 ] = -1 };
65
+ static unsigned int xstate_supervisor_only_offsets [XFEATURE_MAX ] = { [ 0 ... XFEATURE_MAX - 1 ] = -1 };
65
66
66
67
/*
67
68
* The XSAVE area of kernel can be in standard or compacted format;
@@ -392,6 +393,33 @@ static void __init setup_xstate_comp_offsets(void)
392
393
}
393
394
}
394
395
396
+ /*
397
+ * Setup offsets of a supervisor-state-only XSAVES buffer:
398
+ *
399
+ * The offsets stored in xstate_comp_offsets[] only work for one specific
400
+ * value of the Requested Feature BitMap (RFBM). In cases where a different
401
+ * RFBM value is used, a different set of offsets is required. This set of
402
+ * offsets is for when RFBM=xfeatures_mask_supervisor().
403
+ */
404
+ static void __init setup_supervisor_only_offsets (void )
405
+ {
406
+ unsigned int next_offset ;
407
+ int i ;
408
+
409
+ next_offset = FXSAVE_SIZE + XSAVE_HDR_SIZE ;
410
+
411
+ for (i = FIRST_EXTENDED_XFEATURE ; i < XFEATURE_MAX ; i ++ ) {
412
+ if (!xfeature_enabled (i ) || !xfeature_is_supervisor (i ))
413
+ continue ;
414
+
415
+ if (xfeature_is_aligned (i ))
416
+ next_offset = ALIGN (next_offset , 64 );
417
+
418
+ xstate_supervisor_only_offsets [i ] = next_offset ;
419
+ next_offset += xstate_sizes [i ];
420
+ }
421
+ }
422
+
395
423
/*
396
424
* Print out xstate component offsets and sizes
397
425
*/
@@ -790,6 +818,7 @@ void __init fpu__init_system_xstate(void)
790
818
fpu__init_prepare_fx_sw_frame ();
791
819
setup_init_fpu_buf ();
792
820
setup_xstate_comp_offsets ();
821
+ setup_supervisor_only_offsets ();
793
822
print_xstate_offset_size ();
794
823
795
824
pr_info ("x86/fpu: Enabled xstate features 0x%llx, context size is %d bytes, using '%s' format.\n" ,
@@ -1262,6 +1291,61 @@ int copy_user_to_xstate(struct xregs_state *xsave, const void __user *ubuf)
1262
1291
return 0 ;
1263
1292
}
1264
1293
1294
+ /*
1295
+ * Save only supervisor states to the kernel buffer. This blows away all
1296
+ * old states, and is intended to be used only in __fpu__restore_sig(), where
1297
+ * user states are restored from the user buffer.
1298
+ */
1299
+ void copy_supervisor_to_kernel (struct xregs_state * xstate )
1300
+ {
1301
+ struct xstate_header * header ;
1302
+ u64 max_bit , min_bit ;
1303
+ u32 lmask , hmask ;
1304
+ int err , i ;
1305
+
1306
+ if (WARN_ON (!boot_cpu_has (X86_FEATURE_XSAVES )))
1307
+ return ;
1308
+
1309
+ if (!xfeatures_mask_supervisor ())
1310
+ return ;
1311
+
1312
+ max_bit = __fls (xfeatures_mask_supervisor ());
1313
+ min_bit = __ffs (xfeatures_mask_supervisor ());
1314
+
1315
+ lmask = xfeatures_mask_supervisor ();
1316
+ hmask = xfeatures_mask_supervisor () >> 32 ;
1317
+ XSTATE_OP (XSAVES , xstate , lmask , hmask , err );
1318
+
1319
+ /* We should never fault when copying to a kernel buffer: */
1320
+ if (WARN_ON_FPU (err ))
1321
+ return ;
1322
+
1323
+ /*
1324
+ * At this point, the buffer has only supervisor states and must be
1325
+ * converted back to normal kernel format.
1326
+ */
1327
+ header = & xstate -> header ;
1328
+ header -> xcomp_bv |= xfeatures_mask_all ;
1329
+
1330
+ /*
1331
+ * This only moves states up in the buffer. Start with
1332
+ * the last state and move backwards so that states are
1333
+ * not overwritten until after they are moved. Note:
1334
+ * memmove() allows overlapping src/dst buffers.
1335
+ */
1336
+ for (i = max_bit ; i >= min_bit ; i -- ) {
1337
+ u8 * xbuf = (u8 * )xstate ;
1338
+
1339
+ if (!((header -> xfeatures >> i ) & 1 ))
1340
+ continue ;
1341
+
1342
+ /* Move xfeature 'i' into its normal location */
1343
+ memmove (xbuf + xstate_comp_offsets [i ],
1344
+ xbuf + xstate_supervisor_only_offsets [i ],
1345
+ xstate_sizes [i ]);
1346
+ }
1347
+ }
1348
+
1265
1349
#ifdef CONFIG_PROC_PID_ARCH_STATUS
1266
1350
/*
1267
1351
* Report the amount of time elapsed in millisecond since last AVX512
0 commit comments