/* * The userspace xstate test suite is designed to be generic and operates * with randomized xstate data. However, some states require special handling: * * - PKRU and XTILECFG need specific adjustments, such as modifying * randomization behavior or using fixed values. * - But, PKRU already has a dedicated test suite in /tools/selftests/mm. * - Legacy states (FP and SSE) are excluded, as they are not considered * part of extended states (xstates) and their usage is already deeply * integrated into user-space libraries.
*/ #define XFEATURE_MASK_TEST_SUPPORTED \
((1 << XFEATURE_YMM) | \
(1 << XFEATURE_OPMASK) | \
(1 << XFEATURE_ZMM_Hi256) | \
(1 << XFEATURE_Hi16_ZMM) | \
(1 << XFEATURE_XTILEDATA) | \
(1 << XFEATURE_APX))
xbuf = alloc_xbuf(); if (!xbuf)
ksft_exit_fail_msg("unable to allocate XSAVE buffer\n");
/* * Load random data into 'xbuf' and then restore it to the xstate * registers.
*/
load_rand_xstate(&xstate, xbuf);
finfo->valid = true;
for (i = 0; i < finfo->iterations; i++) {
pthread_mutex_lock(&finfo->mutex);
/* * Ensure the register values have not diverged from the * record. Then reload a new random value. If it failed * ever before, skip it.
*/ if (finfo->valid) {
finfo->valid = validate_xregs_same(xbuf);
load_rand_xstate(&xstate, xbuf);
}
/* * The last thread's last unlock will be for thread 0's * mutex. However, thread 0 will have already exited the * loop and the mutex will already be unlocked. * * Because this is not an ERRORCHECK mutex, that * inconsistency will be silently ignored.
*/
pthread_mutex_unlock(&finfo->next->mutex);
}
/* * Thread 'i' will wait on this mutex to be unlocked. * Lock it immediately after initialization:
*/
pthread_mutex_init(&finfo[i].mutex, NULL);
pthread_mutex_lock(&finfo[i].mutex);
next_nr = (i + 1) % num_threads;
finfo[i].next = &finfo[next_nr];
if (pthread_create(&finfo[i].thread, NULL, check_xstate, &finfo[i]))
ksft_exit_fail_msg("pthread_create() failed\n");
}
}
for (i = 0; i < num_threads; i++) {
err = pthread_join(finfo[i].thread, &thread_retval); if (err)
ksft_exit_fail_msg("pthread_join() failed for thread %d err: %d\n", i, err);
if (thread_retval != &finfo[i]) {
ksft_exit_fail_msg("unexpected thread retval for thread %d: %p\n",
i, thread_retval);
}
finfo = malloc(sizeof(*finfo) * num_threads); if (!finfo)
ksft_exit_fail_msg("unable allocate memory\n");
create_threads(num_threads, iterations, finfo);
/* * This thread wakes up thread 0 * Thread 0 will wake up 1 * Thread 1 will wake up 2 * ... * The last thread will wake up 0 * * This will repeat for the configured * number of iterations.
*/
pthread_mutex_unlock(&finfo[0].mutex);
/* Wait for all the threads to finish: */ if (checkout_threads(num_threads, finfo))
printf("[OK]\tNo incorrect case was found.\n"); else
printf("[FAIL]\tFailed with context switching test.\n");
free(finfo);
}
/* * Ptrace test for the ABI format as described in arch/x86/include/asm/user.h
*/
/* * Make sure the ptracee has the expanded kernel buffer on the first use. * Then, initialize the state before performing the state injection from * the ptracer. For non-dynamic states, this is benign.
*/ staticinlinevoid ptracee_touch_xstate(void)
{ struct xsave_buffer *xbuf;
/* * Ptracer injects the randomized xstate data. It also reads before and * after that, which will execute the kernel's state copy functions.
*/ staticvoid ptracer_inject_xstate(pid_t target)
{
uint32_t xbuf_size = get_xbuf_size(); struct xsave_buffer *xbuf1, *xbuf2; struct iovec iov;
/* * Allocate buffers to keep data while ptracer can write the * other buffer
*/
xbuf1 = alloc_xbuf();
xbuf2 = alloc_xbuf(); if (!xbuf1 || !xbuf2)
ksft_exit_fail_msg("unable to allocate XSAVE buffer\n");
iov.iov_base = xbuf1;
iov.iov_len = xbuf_size;
if (ptrace(PTRACE_GETREGSET, target, (uint32_t)NT_X86_XSTATE, &iov))
ksft_exit_fail_msg("PTRACE_GETREGSET failed\n");
printf("[RUN]\t%s: inject xstate via ptrace().\n", xstate.name);
if (ptrace(PTRACE_SETREGSET, target, (uint32_t)NT_X86_XSTATE, &iov))
ksft_exit_fail_msg("PTRACE_SETREGSET failed\n");
if (ptrace(PTRACE_GETREGSET, target, (uint32_t)NT_X86_XSTATE, &iov))
ksft_exit_fail_msg("PTRACE_GETREGSET failed\n");
if (*(uint64_t *)get_fpx_sw_bytes(xbuf1) == xgetbv(0))
printf("[OK]\t'xfeatures' in SW reserved area was correctly written\n"); else
printf("[FAIL]\t'xfeatures' in SW reserved area was not correctly written\n");
if (validate_xstate_same(xbuf2, xbuf1))
printf("[OK]\txstate was correctly updated.\n"); else
printf("[FAIL]\txstate was not correctly updated.\n");
free(xbuf1);
free(xbuf2);
}
staticvoid test_ptrace(void)
{
pid_t child; int status;
/* * Test signal delivery for the ABI compatibility. * See the ABI format: arch/x86/include/uapi/asm/sigcontext.h
*/
/* * Avoid using printf() in signal handlers as it is not * async-signal-safe.
*/ #define SIGNAL_BUF_LEN 1000 staticchar signal_message_buffer[SIGNAL_BUF_LEN]; staticvoid sig_print(char *msg)
{ int left = SIGNAL_BUF_LEN - strlen(signal_message_buffer) - 1;
/* Reset the signal message buffer: */
signal_message_buffer[0] = '\0';
sw_bytes = get_fpx_sw_bytes(xbuf); if (sw_bytes->magic1 == FP_XSTATE_MAGIC1)
sig_print("[OK]\t'magic1' is valid\n"); else
sig_print("[FAIL]\t'magic1' is not valid\n");
if (get_fpx_sw_bytes_features(xbuf) & xstate.mask)
sig_print("[OK]\t'xfeatures' in SW reserved area is valid\n"); else
sig_print("[FAIL]\t'xfeatures' in SW reserved area is not valid\n");
if (get_xstatebv(xbuf) & xstate.mask)
sig_print("[OK]\t'xfeatures' in XSAVE header is valid\n"); else
sig_print("[FAIL]\t'xfeatures' in XSAVE header is not valid\n");
if (validate_xstate_same(stashed_xbuf, xbuf))
sig_print("[OK]\txstate delivery was successful\n"); else
sig_print("[FAIL]\txstate delivery was not successful\n");
magic2 = *(uint32_t *)(xbuf + sw_bytes->xstate_size); if (magic2 == FP_XSTATE_MAGIC2)
sig_print("[OK]\t'magic2' is valid\n"); else
sig_print("[FAIL]\t'magic2' is not valid\n");
/* * The signal handler will access this to verify xstate context * preservation.
*/
stashed_xbuf = alloc_xbuf(); if (!stashed_xbuf)
ksft_exit_fail_msg("unable to allocate XSAVE buffer\n");
printf("[RUN]\t%s: load xstate and raise SIGUSR1\n", xstate.name);
sethandler(SIGUSR1, validate_sigfpstate, 0);
load_rand_xstate(&xstate, stashed_xbuf);
raise(SIGUSR1);
/* * Immediately record the test result, deferring printf() to * prevent unintended state contamination by that.
*/
valid_xstate = validate_xregs_same(stashed_xbuf);
printf("%s", signal_message_buffer);
printf("[RUN]\t%s: load new xstate from sighandler and check it after sigreturn\n",
xstate.name);
if (valid_xstate)
printf("[OK]\txstate was restored correctly\n"); else
printf("[FAIL]\txstate restoration failed\n");
if (!(XFEATURE_MASK_TEST_SUPPORTED & (1 << feature_num))) {
ksft_print_msg("The xstate test does not fully support the component %u, yet.\n",
feature_num); return;
}
rc = syscall(SYS_arch_prctl, ARCH_GET_XCOMP_SUPP, &features); if (rc || !(features & (1 << feature_num))) {
ksft_print_msg("The kernel does not support feature number: %u\n", feature_num); return;
}
xstate = get_xstate_info(feature_num); if (!xstate.size || !xstate.xbuf_offset) {
ksft_exit_fail_msg("invalid state size/offset (%d/%d)\n",
xstate.size, xstate.xbuf_offset);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.