diff options
| author | Chris Smart <chris@distroguy.com> | 2016-06-16 19:34:47 -0400 |
|---|---|---|
| committer | Michael Ellerman <mpe@ellerman.id.au> | 2016-07-05 09:49:51 -0400 |
| commit | 4375088072295b09cc5d9bf7a8cd2333b608492a (patch) | |
| tree | ee4d78c9d440e0505c347212d5eb945302558d1b /tools/testing | |
| parent | ae26b36f8098c793a754549662771099215904ed (diff) | |
selftests/powerpc: Test unaligned copy and paste
Test that an ISA 3.0 compliant machine performing an unaligned copy,
copy_first, paste or paste_last is sent a SIGBUS.
Signed-off-by: Chris Smart <chris@distroguy.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Diffstat (limited to 'tools/testing')
10 files changed, 332 insertions, 1 deletions
diff --git a/tools/testing/selftests/powerpc/Makefile b/tools/testing/selftests/powerpc/Makefile index 4ca83fe80654..3c40c9d0e6c7 100644 --- a/tools/testing/selftests/powerpc/Makefile +++ b/tools/testing/selftests/powerpc/Makefile | |||
| @@ -12,7 +12,8 @@ CFLAGS := -Wall -O2 -Wall -Werror -DGIT_VERSION='"$(GIT_VERSION)"' -I$(CURDIR) $ | |||
| 12 | 12 | ||
| 13 | export CFLAGS | 13 | export CFLAGS |
| 14 | 14 | ||
| 15 | SUB_DIRS = benchmarks \ | 15 | SUB_DIRS = alignment \ |
| 16 | benchmarks \ | ||
| 16 | copyloops \ | 17 | copyloops \ |
| 17 | context_switch \ | 18 | context_switch \ |
| 18 | dscr \ | 19 | dscr \ |
diff --git a/tools/testing/selftests/powerpc/alignment/.gitignore b/tools/testing/selftests/powerpc/alignment/.gitignore new file mode 100644 index 000000000000..1d980e3d7039 --- /dev/null +++ b/tools/testing/selftests/powerpc/alignment/.gitignore | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | copy_unaligned | ||
| 2 | copy_first_unaligned | ||
| 3 | paste_unaligned | ||
| 4 | paste_last_unaligned | ||
| 5 | copy_paste_unaligned_common | ||
diff --git a/tools/testing/selftests/powerpc/alignment/Makefile b/tools/testing/selftests/powerpc/alignment/Makefile new file mode 100644 index 000000000000..ad6a4e49da91 --- /dev/null +++ b/tools/testing/selftests/powerpc/alignment/Makefile | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | TEST_PROGS := copy_unaligned copy_first_unaligned paste_unaligned paste_last_unaligned | ||
| 2 | |||
| 3 | all: $(TEST_PROGS) | ||
| 4 | |||
| 5 | $(TEST_PROGS): ../harness.c ../utils.c copy_paste_unaligned_common.c | ||
| 6 | |||
| 7 | include ../../lib.mk | ||
| 8 | |||
| 9 | clean: | ||
| 10 | rm -f $(TEST_PROGS) | ||
diff --git a/tools/testing/selftests/powerpc/alignment/copy_first_unaligned.c b/tools/testing/selftests/powerpc/alignment/copy_first_unaligned.c new file mode 100644 index 000000000000..47b73b3a08bd --- /dev/null +++ b/tools/testing/selftests/powerpc/alignment/copy_first_unaligned.c | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2016, Chris Smart, IBM Corporation. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU General Public License | ||
| 6 | * as published by the Free Software Foundation; either version | ||
| 7 | * 2 of the License, or (at your option) any later version. | ||
| 8 | * | ||
| 9 | * Calls to copy_first which are not 128-byte aligned should be | ||
| 10 | * caught and sent a SIGBUS. | ||
| 11 | * | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <string.h> | ||
| 15 | #include <unistd.h> | ||
| 16 | #include "utils.h" | ||
| 17 | #include "instructions.h" | ||
| 18 | #include "copy_paste_unaligned_common.h" | ||
| 19 | |||
| 20 | unsigned int expected_instruction = PPC_INST_COPY_FIRST; | ||
| 21 | unsigned int instruction_mask = 0xfc2007fe; | ||
| 22 | |||
| 23 | int test_copy_first_unaligned(void) | ||
| 24 | { | ||
| 25 | /* Only run this test on a P9 or later */ | ||
| 26 | SKIP_IF(!have_hwcap2(PPC_FEATURE2_ARCH_3_00)); | ||
| 27 | |||
| 28 | /* Register our signal handler with SIGBUS */ | ||
| 29 | setup_signal_handler(); | ||
| 30 | |||
| 31 | /* +1 makes buf unaligned */ | ||
| 32 | copy_first(cacheline_buf+1); | ||
| 33 | |||
| 34 | /* We should not get here */ | ||
| 35 | return 1; | ||
| 36 | } | ||
| 37 | |||
| 38 | int main(int argc, char *argv[]) | ||
| 39 | { | ||
| 40 | return test_harness(test_copy_first_unaligned, "test_copy_first_unaligned"); | ||
| 41 | } | ||
diff --git a/tools/testing/selftests/powerpc/alignment/copy_paste_unaligned_common.c b/tools/testing/selftests/powerpc/alignment/copy_paste_unaligned_common.c new file mode 100644 index 000000000000..d35fa5f5d2d3 --- /dev/null +++ b/tools/testing/selftests/powerpc/alignment/copy_paste_unaligned_common.c | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2016, Chris Smart, IBM Corporation. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU General Public License | ||
| 6 | * as published by the Free Software Foundation; either version | ||
| 7 | * 2 of the License, or (at your option) any later version. | ||
| 8 | * | ||
| 9 | * Common code for copy, copy_first, paste and paste_last unaligned | ||
| 10 | * tests. | ||
| 11 | * | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <signal.h> | ||
| 15 | #include <string.h> | ||
| 16 | #include <unistd.h> | ||
| 17 | #include "utils.h" | ||
| 18 | #include "instructions.h" | ||
| 19 | #include "copy_paste_unaligned_common.h" | ||
| 20 | |||
| 21 | unsigned int expected_instruction; | ||
| 22 | unsigned int instruction_mask; | ||
| 23 | |||
| 24 | char cacheline_buf[128] __cacheline_aligned; | ||
| 25 | |||
| 26 | void signal_action_handler(int signal_num, siginfo_t *info, void *ptr) | ||
| 27 | { | ||
| 28 | ucontext_t *ctx = ptr; | ||
| 29 | #if defined(__powerpc64__) | ||
| 30 | unsigned int *pc = (unsigned int *)ctx->uc_mcontext.gp_regs[PT_NIP]; | ||
| 31 | #else | ||
| 32 | unsigned int *pc = (unsigned int *)ctx->uc_mcontext.uc_regs->gregs[PT_NIP]; | ||
| 33 | #endif | ||
| 34 | |||
| 35 | /* | ||
| 36 | * Check that the signal was on the correct instruction, using a | ||
| 37 | * mask because the compiler assigns the register at RB. | ||
| 38 | */ | ||
| 39 | if ((*pc & instruction_mask) == expected_instruction) | ||
| 40 | _exit(0); /* We hit the right instruction */ | ||
| 41 | |||
| 42 | _exit(1); | ||
| 43 | } | ||
| 44 | |||
| 45 | void setup_signal_handler(void) | ||
| 46 | { | ||
| 47 | struct sigaction signal_action; | ||
| 48 | |||
| 49 | memset(&signal_action, 0, sizeof(signal_action)); | ||
| 50 | signal_action.sa_sigaction = signal_action_handler; | ||
| 51 | signal_action.sa_flags = SA_SIGINFO; | ||
| 52 | sigaction(SIGBUS, &signal_action, NULL); | ||
| 53 | } | ||
diff --git a/tools/testing/selftests/powerpc/alignment/copy_paste_unaligned_common.h b/tools/testing/selftests/powerpc/alignment/copy_paste_unaligned_common.h new file mode 100644 index 000000000000..053899fe506e --- /dev/null +++ b/tools/testing/selftests/powerpc/alignment/copy_paste_unaligned_common.h | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2016, Chris Smart, IBM Corporation. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU General Public License | ||
| 6 | * as published by the Free Software Foundation; either version | ||
| 7 | * 2 of the License, or (at your option) any later version. | ||
| 8 | * | ||
| 9 | * Declarations for common code for copy, copy_first, paste and | ||
| 10 | * paste_last unaligned tests. | ||
| 11 | * | ||
| 12 | */ | ||
| 13 | |||
| 14 | #ifndef _SELFTESTS_POWERPC_COPY_PASTE_H | ||
| 15 | #define _SELFTESTS_POWERPC_COPY_PASTE_H | ||
| 16 | |||
| 17 | #include <signal.h> | ||
| 18 | |||
| 19 | int main(int argc, char *argv[]); | ||
| 20 | void signal_action_handler(int signal_num, siginfo_t *info, void *ptr); | ||
| 21 | void setup_signal_handler(void); | ||
| 22 | extern char cacheline_buf[128] __cacheline_aligned; | ||
| 23 | extern unsigned int expected_instruction; | ||
| 24 | extern unsigned int instruction_mask; | ||
| 25 | |||
| 26 | #endif /* _SELFTESTS_POWERPC_COPY_PASTE_H */ | ||
diff --git a/tools/testing/selftests/powerpc/alignment/copy_unaligned.c b/tools/testing/selftests/powerpc/alignment/copy_unaligned.c new file mode 100644 index 000000000000..3a4e26461554 --- /dev/null +++ b/tools/testing/selftests/powerpc/alignment/copy_unaligned.c | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2016, Chris Smart, IBM Corporation. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU General Public License | ||
| 6 | * as published by the Free Software Foundation; either version | ||
| 7 | * 2 of the License, or (at your option) any later version. | ||
| 8 | * | ||
| 9 | * Calls to copy which are not 128-byte aligned should be caught | ||
| 10 | * and sent a SIGBUS. | ||
| 11 | * | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <string.h> | ||
| 15 | #include <unistd.h> | ||
| 16 | #include "utils.h" | ||
| 17 | #include "instructions.h" | ||
| 18 | #include "copy_paste_unaligned_common.h" | ||
| 19 | |||
| 20 | unsigned int expected_instruction = PPC_INST_COPY; | ||
| 21 | unsigned int instruction_mask = 0xfc0007fe; | ||
| 22 | |||
| 23 | int test_copy_unaligned(void) | ||
| 24 | { | ||
| 25 | /* Only run this test on a P9 or later */ | ||
| 26 | SKIP_IF(!have_hwcap2(PPC_FEATURE2_ARCH_3_00)); | ||
| 27 | |||
| 28 | /* Register our signal handler with SIGBUS */ | ||
| 29 | setup_signal_handler(); | ||
| 30 | |||
| 31 | /* +1 makes buf unaligned */ | ||
| 32 | copy(cacheline_buf+1); | ||
| 33 | |||
| 34 | /* We should not get here */ | ||
| 35 | return 1; | ||
| 36 | } | ||
| 37 | |||
| 38 | int main(int argc, char *argv[]) | ||
| 39 | { | ||
| 40 | return test_harness(test_copy_unaligned, "test_copy_unaligned"); | ||
| 41 | } | ||
diff --git a/tools/testing/selftests/powerpc/alignment/paste_last_unaligned.c b/tools/testing/selftests/powerpc/alignment/paste_last_unaligned.c new file mode 100644 index 000000000000..6e0ad045fcc3 --- /dev/null +++ b/tools/testing/selftests/powerpc/alignment/paste_last_unaligned.c | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2016, Chris Smart, IBM Corporation. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU General Public License | ||
| 6 | * as published by the Free Software Foundation; either version | ||
| 7 | * 2 of the License, or (at your option) any later version. | ||
| 8 | * | ||
| 9 | * Calls to paste_last which are not 128-byte aligned should be | ||
| 10 | * caught and sent a SIGBUS. | ||
| 11 | * | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <string.h> | ||
| 15 | #include <unistd.h> | ||
| 16 | #include "utils.h" | ||
| 17 | #include "instructions.h" | ||
| 18 | #include "copy_paste_unaligned_common.h" | ||
| 19 | |||
| 20 | unsigned int expected_instruction = PPC_INST_PASTE_LAST; | ||
| 21 | unsigned int instruction_mask = 0xfc2007ff; | ||
| 22 | |||
| 23 | int test_paste_last_unaligned(void) | ||
| 24 | { | ||
| 25 | /* Only run this test on a P9 or later */ | ||
| 26 | SKIP_IF(!have_hwcap2(PPC_FEATURE2_ARCH_3_00)); | ||
| 27 | |||
| 28 | /* Register our signal handler with SIGBUS */ | ||
| 29 | setup_signal_handler(); | ||
| 30 | |||
| 31 | copy(cacheline_buf); | ||
| 32 | |||
| 33 | /* +1 makes buf unaligned */ | ||
| 34 | paste_last(cacheline_buf+1); | ||
| 35 | |||
| 36 | /* We should not get here */ | ||
| 37 | return 1; | ||
| 38 | } | ||
| 39 | |||
| 40 | int main(int argc, char *argv[]) | ||
| 41 | { | ||
| 42 | return test_harness(test_paste_last_unaligned, "test_paste_last_unaligned"); | ||
| 43 | } | ||
diff --git a/tools/testing/selftests/powerpc/alignment/paste_unaligned.c b/tools/testing/selftests/powerpc/alignment/paste_unaligned.c new file mode 100644 index 000000000000..6f982b45e4bd --- /dev/null +++ b/tools/testing/selftests/powerpc/alignment/paste_unaligned.c | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2016, Chris Smart, IBM Corporation. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU General Public License | ||
| 6 | * as published by the Free Software Foundation; either version | ||
| 7 | * 2 of the License, or (at your option) any later version. | ||
| 8 | * | ||
| 9 | * Calls to paste which are not 128-byte aligned should be caught | ||
| 10 | * and sent a SIGBUS. | ||
| 11 | * | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <string.h> | ||
| 15 | #include <unistd.h> | ||
| 16 | #include "utils.h" | ||
| 17 | #include "instructions.h" | ||
| 18 | #include "copy_paste_unaligned_common.h" | ||
| 19 | |||
| 20 | unsigned int expected_instruction = PPC_INST_PASTE; | ||
| 21 | unsigned int instruction_mask = 0xfc0007fe; | ||
| 22 | |||
| 23 | int test_paste_unaligned(void) | ||
| 24 | { | ||
| 25 | /* Only run this test on a P9 or later */ | ||
| 26 | SKIP_IF(!have_hwcap2(PPC_FEATURE2_ARCH_3_00)); | ||
| 27 | |||
| 28 | /* Register our signal handler with SIGBUS */ | ||
| 29 | setup_signal_handler(); | ||
| 30 | |||
| 31 | copy(cacheline_buf); | ||
| 32 | |||
| 33 | /* +1 makes buf unaligned */ | ||
| 34 | paste(cacheline_buf+1); | ||
| 35 | |||
| 36 | /* We should not get here */ | ||
| 37 | return 1; | ||
| 38 | } | ||
| 39 | |||
| 40 | int main(int argc, char *argv[]) | ||
| 41 | { | ||
| 42 | return test_harness(test_paste_unaligned, "test_paste_unaligned"); | ||
| 43 | } | ||
diff --git a/tools/testing/selftests/powerpc/instructions.h b/tools/testing/selftests/powerpc/instructions.h new file mode 100644 index 000000000000..0fb0bd3b28c9 --- /dev/null +++ b/tools/testing/selftests/powerpc/instructions.h | |||
| @@ -0,0 +1,68 @@ | |||
| 1 | #ifndef _SELFTESTS_POWERPC_INSTRUCTIONS_H | ||
| 2 | #define _SELFTESTS_POWERPC_INSTRUCTIONS_H | ||
| 3 | |||
| 4 | #include <stdio.h> | ||
| 5 | #include <stdlib.h> | ||
| 6 | |||
| 7 | /* This defines the "copy" instruction from Power ISA 3.0 Book II, section 4.4. */ | ||
| 8 | #define __COPY(RA, RB, L) \ | ||
| 9 | (0x7c00060c | (RA) << (31-15) | (RB) << (31-20) | (L) << (31-10)) | ||
| 10 | #define COPY(RA, RB, L) \ | ||
| 11 | .long __COPY((RA), (RB), (L)) | ||
| 12 | |||
| 13 | static inline void copy(void *i) | ||
| 14 | { | ||
| 15 | asm volatile(str(COPY(0, %0, 0))";" | ||
| 16 | : | ||
| 17 | : "b" (i) | ||
| 18 | : "memory" | ||
| 19 | ); | ||
| 20 | } | ||
| 21 | |||
| 22 | static inline void copy_first(void *i) | ||
| 23 | { | ||
| 24 | asm volatile(str(COPY(0, %0, 1))";" | ||
| 25 | : | ||
| 26 | : "b" (i) | ||
| 27 | : "memory" | ||
| 28 | ); | ||
| 29 | } | ||
| 30 | |||
| 31 | /* This defines the "paste" instruction from Power ISA 3.0 Book II, section 4.4. */ | ||
| 32 | #define __PASTE(RA, RB, L, RC) \ | ||
| 33 | (0x7c00070c | (RA) << (31-15) | (RB) << (31-20) | (L) << (31-10) | (RC) << (31-31)) | ||
| 34 | #define PASTE(RA, RB, L, RC) \ | ||
| 35 | .long __PASTE((RA), (RB), (L), (RC)) | ||
| 36 | |||
| 37 | static inline int paste(void *i) | ||
| 38 | { | ||
| 39 | int cr; | ||
| 40 | |||
| 41 | asm volatile(str(PASTE(0, %1, 0, 0))";" | ||
| 42 | "mfcr %0;" | ||
| 43 | : "=r" (cr) | ||
| 44 | : "b" (i) | ||
| 45 | : "memory" | ||
| 46 | ); | ||
| 47 | return cr; | ||
| 48 | } | ||
| 49 | |||
| 50 | static inline int paste_last(void *i) | ||
| 51 | { | ||
| 52 | int cr; | ||
| 53 | |||
| 54 | asm volatile(str(PASTE(0, %1, 1, 1))";" | ||
| 55 | "mfcr %0;" | ||
| 56 | : "=r" (cr) | ||
| 57 | : "b" (i) | ||
| 58 | : "memory" | ||
| 59 | ); | ||
| 60 | return cr; | ||
| 61 | } | ||
| 62 | |||
| 63 | #define PPC_INST_COPY __COPY(0, 0, 0) | ||
| 64 | #define PPC_INST_COPY_FIRST __COPY(0, 0, 1) | ||
| 65 | #define PPC_INST_PASTE __PASTE(0, 0, 0, 0) | ||
| 66 | #define PPC_INST_PASTE_LAST __PASTE(0, 0, 1, 1) | ||
| 67 | |||
| 68 | #endif /* _SELFTESTS_POWERPC_INSTRUCTIONS_H */ | ||
