tools/testing/selftests/powerpc/dexcr/hashchk_test.c

Source file repositories/reference/linux-study-clean/tools/testing/selftests/powerpc/dexcr/hashchk_test.c

File Facts

System
Linux kernel
Corpus path
tools/testing/selftests/powerpc/dexcr/hashchk_test.c
Extension
.c
Size
5068 bytes
Lines
234
Domain
Support Tooling And Documentation
Bucket
tools
Inferred role
Support Tooling And Documentation: implementation source
Status
source implementation candidate

Why This File Exists

Repository support layer: documentation, build tooling, samples, user-space helper tools, generated initramfs support, licenses, and validation utilities.

Dependency Surface

Detected Declarations

Annotated Snippet

// SPDX-License-Identifier: GPL-2.0+

#define _GNU_SOURCE

#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <sched.h>
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/prctl.h>
#include <unistd.h>

#include "dexcr.h"
#include "utils.h"

static int require_nphie(void)
{
	SKIP_IF_MSG(!dexcr_exists(), "DEXCR not supported");

	pr_set_dexcr(PR_PPC_DEXCR_NPHIE, PR_PPC_DEXCR_CTRL_SET | PR_PPC_DEXCR_CTRL_SET_ONEXEC);

	if (get_dexcr(EFFECTIVE) & DEXCR_PR_NPHIE)
		return 0;

	SKIP_IF_MSG(!(get_dexcr(EFFECTIVE) & DEXCR_PR_NPHIE),
		    "Failed to enable DEXCR[NPHIE]");

	return 0;
}

static jmp_buf hashchk_detected_buf;
static const char *hashchk_failure_msg;

static void hashchk_handler(int signum, siginfo_t *info, void *context)
{
	if (signum != SIGILL)
		hashchk_failure_msg = "wrong signal received";
	else if (info->si_code != ILL_ILLOPN)
		hashchk_failure_msg = "wrong signal code received";

	longjmp(hashchk_detected_buf, 0);
}

/*
 * Check that hashchk triggers when DEXCR[NPHIE] is enabled
 * and is detected as such by the kernel exception handler
 */
static int hashchk_detected_test(void)
{
	struct sigaction old;
	int err;

	err = require_nphie();
	if (err)
		return err;

	old = push_signal_handler(SIGILL, hashchk_handler);
	if (setjmp(hashchk_detected_buf))
		goto out;

	hashchk_failure_msg = NULL;
	do_bad_hashchk();
	hashchk_failure_msg = "hashchk failed to trigger";

out:
	pop_signal_handler(SIGILL, old);
	FAIL_IF_MSG(hashchk_failure_msg, hashchk_failure_msg);
	return 0;
}

#define HASH_COUNT 8

static unsigned long hash_values[HASH_COUNT + 1];

static void fill_hash_values(void)
{
	for (unsigned long i = 0; i < HASH_COUNT; i++)
		hashst(i, &hash_values[i]);

	/* Used to ensure the checks uses the same addresses as the hashes */
	hash_values[HASH_COUNT] = (unsigned long)&hash_values;
}

static unsigned int count_hash_values_matches(void)
{

Annotation

Implementation Notes