forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
kselftest/arm64: check GCR_EL1 after context switch
This test is specific to MTE and verifies that the GCR_EL1 register is context switched correctly. It spawns 1024 processes and each process spawns 5 threads. Each thread writes a random setting of GCR_EL1 through the prctl() system call and reads it back verifying that it is the same. If the values are not the same it reports a failure. Note: The test has been extended to verify that even SYNC and ASYNC mode setting is preserved correctly over context switching. Link: https://lkml.kernel.org/r/b51a165426e906e7ec8a68d806ef3f8cd92581a6.1606161801.git.andreyknvl@google.com Signed-off-by: Vincenzo Frascino <[email protected]> Signed-off-by: Andrey Konovalov <[email protected]> Acked-by: Catalin Marinas <[email protected]> Tested-by: Vincenzo Frascino <[email protected]> Cc: Alexander Potapenko <[email protected]> Cc: Andrey Ryabinin <[email protected]> Cc: Branislav Rankov <[email protected]> Cc: Dmitry Vyukov <[email protected]> Cc: Evgenii Stepanov <[email protected]> Cc: Kevin Brodsky <[email protected]> Cc: Marco Elver <[email protected]> Cc: Vasily Gorbik <[email protected]> Cc: Will Deacon <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
- Loading branch information
Showing
2 changed files
with
155 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
154 changes: 154 additions & 0 deletions
154
tools/testing/selftests/arm64/mte/check_gcr_el1_cswitch.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
// Copyright (C) 2020 ARM Limited | ||
|
||
#define _GNU_SOURCE | ||
|
||
#include <errno.h> | ||
#include <pthread.h> | ||
#include <stdint.h> | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <time.h> | ||
#include <unistd.h> | ||
#include <sys/auxv.h> | ||
#include <sys/mman.h> | ||
#include <sys/prctl.h> | ||
#include <sys/types.h> | ||
#include <sys/wait.h> | ||
|
||
#include "kselftest.h" | ||
#include "mte_common_util.h" | ||
|
||
#define PR_SET_TAGGED_ADDR_CTRL 55 | ||
#define PR_GET_TAGGED_ADDR_CTRL 56 | ||
# define PR_TAGGED_ADDR_ENABLE (1UL << 0) | ||
# define PR_MTE_TCF_SHIFT 1 | ||
# define PR_MTE_TCF_NONE (0UL << PR_MTE_TCF_SHIFT) | ||
# define PR_MTE_TCF_SYNC (1UL << PR_MTE_TCF_SHIFT) | ||
# define PR_MTE_TCF_ASYNC (2UL << PR_MTE_TCF_SHIFT) | ||
# define PR_MTE_TCF_MASK (3UL << PR_MTE_TCF_SHIFT) | ||
# define PR_MTE_TAG_SHIFT 3 | ||
# define PR_MTE_TAG_MASK (0xffffUL << PR_MTE_TAG_SHIFT) | ||
|
||
#include "mte_def.h" | ||
|
||
#define NUM_ITERATIONS 1024 | ||
#define MAX_THREADS 5 | ||
#define THREAD_ITERATIONS 1000 | ||
|
||
void *execute_thread(void *x) | ||
{ | ||
pid_t pid = *((pid_t *)x); | ||
pid_t tid = gettid(); | ||
uint64_t prctl_tag_mask; | ||
uint64_t prctl_set; | ||
uint64_t prctl_get; | ||
uint64_t prctl_tcf; | ||
|
||
srand(time(NULL) ^ (pid << 16) ^ (tid << 16)); | ||
|
||
prctl_tag_mask = rand() & 0xffff; | ||
|
||
if (prctl_tag_mask % 2) | ||
prctl_tcf = PR_MTE_TCF_SYNC; | ||
else | ||
prctl_tcf = PR_MTE_TCF_ASYNC; | ||
|
||
prctl_set = PR_TAGGED_ADDR_ENABLE | prctl_tcf | (prctl_tag_mask << PR_MTE_TAG_SHIFT); | ||
|
||
for (int j = 0; j < THREAD_ITERATIONS; j++) { | ||
if (prctl(PR_SET_TAGGED_ADDR_CTRL, prctl_set, 0, 0, 0)) { | ||
perror("prctl() failed"); | ||
goto fail; | ||
} | ||
|
||
prctl_get = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0); | ||
|
||
if (prctl_set != prctl_get) { | ||
ksft_print_msg("Error: prctl_set: 0x%lx != prctl_get: 0x%lx\n", | ||
prctl_set, prctl_get); | ||
goto fail; | ||
} | ||
} | ||
|
||
return (void *)KSFT_PASS; | ||
|
||
fail: | ||
return (void *)KSFT_FAIL; | ||
} | ||
|
||
int execute_test(pid_t pid) | ||
{ | ||
pthread_t thread_id[MAX_THREADS]; | ||
int thread_data[MAX_THREADS]; | ||
|
||
for (int i = 0; i < MAX_THREADS; i++) | ||
pthread_create(&thread_id[i], NULL, | ||
execute_thread, (void *)&pid); | ||
|
||
for (int i = 0; i < MAX_THREADS; i++) | ||
pthread_join(thread_id[i], (void *)&thread_data[i]); | ||
|
||
for (int i = 0; i < MAX_THREADS; i++) | ||
if (thread_data[i] == KSFT_FAIL) | ||
return KSFT_FAIL; | ||
|
||
return KSFT_PASS; | ||
} | ||
|
||
int mte_gcr_fork_test(void) | ||
{ | ||
pid_t pid; | ||
int results[NUM_ITERATIONS]; | ||
pid_t cpid; | ||
int res; | ||
|
||
for (int i = 0; i < NUM_ITERATIONS; i++) { | ||
pid = fork(); | ||
|
||
if (pid < 0) | ||
return KSFT_FAIL; | ||
|
||
if (pid == 0) { | ||
cpid = getpid(); | ||
|
||
res = execute_test(cpid); | ||
|
||
exit(res); | ||
} | ||
} | ||
|
||
for (int i = 0; i < NUM_ITERATIONS; i++) { | ||
wait(&res); | ||
|
||
if (WIFEXITED(res)) | ||
results[i] = WEXITSTATUS(res); | ||
else | ||
--i; | ||
} | ||
|
||
for (int i = 0; i < NUM_ITERATIONS; i++) | ||
if (results[i] == KSFT_FAIL) | ||
return KSFT_FAIL; | ||
|
||
return KSFT_PASS; | ||
} | ||
|
||
int main(int argc, char *argv[]) | ||
{ | ||
int err; | ||
|
||
err = mte_default_setup(); | ||
if (err) | ||
return err; | ||
|
||
ksft_set_plan(1); | ||
|
||
evaluate_test(mte_gcr_fork_test(), | ||
"Verify that GCR_EL1 is set correctly on context switch\n"); | ||
|
||
mte_restore_setup(); | ||
ksft_print_cnts(); | ||
|
||
return ksft_get_fail_cnt() == 0 ? KSFT_PASS : KSFT_FAIL; | ||
} |