diff options
Diffstat (limited to 'tools/testing')
33 files changed, 1119 insertions, 130 deletions
diff --git a/tools/testing/selftests/powerpc/Makefile b/tools/testing/selftests/powerpc/Makefile index 2958fe9a74e9..5ad042345ab9 100644 --- a/tools/testing/selftests/powerpc/Makefile +++ b/tools/testing/selftests/powerpc/Makefile @@ -12,37 +12,37 @@ CFLAGS := -Wall -O2 -flto -Wall -Werror -DGIT_VERSION='"$(GIT_VERSION)"' -I$(CUR export CFLAGS -TARGETS = pmu copyloops mm tm primitives stringloops +SUB_DIRS = pmu copyloops mm tm primitives stringloops vphn switch_endian endif -all: $(TARGETS) +all: $(SUB_DIRS) -$(TARGETS): +$(SUB_DIRS): $(MAKE) -k -C $@ all include ../lib.mk override define RUN_TESTS - @for TARGET in $(TARGETS); do \ + @for TARGET in $(SUB_DIRS); do \ $(MAKE) -C $$TARGET run_tests; \ done; endef override define INSTALL_RULE - @for TARGET in $(TARGETS); do \ + @for TARGET in $(SUB_DIRS); do \ $(MAKE) -C $$TARGET install; \ done; endef override define EMIT_TESTS - @for TARGET in $(TARGETS); do \ + @for TARGET in $(SUB_DIRS); do \ $(MAKE) -s -C $$TARGET emit_tests; \ done; endef clean: - @for TARGET in $(TARGETS); do \ + @for TARGET in $(SUB_DIRS); do \ $(MAKE) -C $$TARGET clean; \ done; rm -f tags @@ -50,4 +50,4 @@ clean: tags: find . -name '*.c' -o -name '*.h' | xargs ctags -.PHONY: tags $(TARGETS) +.PHONY: tags $(SUB_DIRS) diff --git a/tools/testing/selftests/powerpc/copyloops/Makefile b/tools/testing/selftests/powerpc/copyloops/Makefile index c05023514ce8..384843ea0d40 100644 --- a/tools/testing/selftests/powerpc/copyloops/Makefile +++ b/tools/testing/selftests/powerpc/copyloops/Makefile @@ -2,6 +2,7 @@ CFLAGS += -m64 CFLAGS += -I$(CURDIR) CFLAGS += -D SELFTEST +CFLAGS += -maltivec # Use our CFLAGS for the implicit .S rule ASFLAGS = $(CFLAGS) diff --git a/tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h b/tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h index d1dc37425510..50ae7d2091ce 100644 --- a/tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h +++ b/tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h @@ -4,39 +4,6 @@ #define r1 1 -#define vr0 0 -#define vr1 1 -#define vr2 2 -#define vr3 3 -#define vr4 4 -#define vr5 5 -#define vr6 6 -#define vr7 7 -#define vr8 8 -#define vr9 9 -#define vr10 10 -#define vr11 11 -#define vr12 12 -#define vr13 13 -#define vr14 14 -#define vr15 15 -#define vr16 16 -#define vr17 17 -#define vr18 18 -#define vr19 19 -#define vr20 20 -#define vr21 21 -#define vr22 22 -#define vr23 23 -#define vr24 24 -#define vr25 25 -#define vr26 26 -#define vr27 27 -#define vr28 28 -#define vr29 29 -#define vr30 30 -#define vr31 31 - #define R14 r14 #define R15 r15 #define R16 r16 diff --git a/tools/testing/selftests/powerpc/harness.c b/tools/testing/selftests/powerpc/harness.c index 8ebc58a09311..f7997affd143 100644 --- a/tools/testing/selftests/powerpc/harness.c +++ b/tools/testing/selftests/powerpc/harness.c @@ -11,6 +11,10 @@ #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> +#include <elf.h> +#include <fcntl.h> +#include <link.h> +#include <sys/stat.h> #include "subunit.h" #include "utils.h" @@ -112,3 +116,46 @@ int test_harness(int (test_function)(void), char *name) return rc; } + +static char auxv[4096]; + +void *get_auxv_entry(int type) +{ + ElfW(auxv_t) *p; + void *result; + ssize_t num; + int fd; + + fd = open("/proc/self/auxv", O_RDONLY); + if (fd == -1) { + perror("open"); + return NULL; + } + + result = NULL; + + num = read(fd, auxv, sizeof(auxv)); + if (num < 0) { + perror("read"); + goto out; + } + + if (num > sizeof(auxv)) { + printf("Overflowed auxv buffer\n"); + goto out; + } + + p = (ElfW(auxv_t) *)auxv; + + while (p->a_type != AT_NULL) { + if (p->a_type == type) { + result = (void *)p->a_un.a_val; + break; + } + + p++; + } +out: + close(fd); + return result; +} diff --git a/tools/testing/selftests/powerpc/mm/hugetlb_vs_thp_test.c b/tools/testing/selftests/powerpc/mm/hugetlb_vs_thp_test.c index 3d8e5b033e1d..49003674de4f 100644 --- a/tools/testing/selftests/powerpc/mm/hugetlb_vs_thp_test.c +++ b/tools/testing/selftests/powerpc/mm/hugetlb_vs_thp_test.c @@ -21,9 +21,13 @@ static int test_body(void) * Typically the mmap will fail because no huge pages are * allocated on the system. But if there are huge pages * allocated the mmap will succeed. That's fine too, we just - * munmap here before continuing. + * munmap here before continuing. munmap() length of + * MAP_HUGETLB memory must be hugepage aligned. */ - munmap(addr, SIZE); + if (munmap(addr, SIZE)) { + perror("munmap"); + return 1; + } } p = mmap(addr, SIZE, PROT_READ | PROT_WRITE, diff --git a/tools/testing/selftests/powerpc/pmu/Makefile b/tools/testing/selftests/powerpc/pmu/Makefile index 5a161175bbd4..a9099d9f8f39 100644 --- a/tools/testing/selftests/powerpc/pmu/Makefile +++ b/tools/testing/selftests/powerpc/pmu/Makefile @@ -26,7 +26,7 @@ override define EMIT_TESTS $(MAKE) -s -C ebb emit_tests endef -DEFAULT_INSTALL := $(INSTALL_RULE) +DEFAULT_INSTALL_RULE := $(INSTALL_RULE) override define INSTALL_RULE $(DEFAULT_INSTALL_RULE) $(MAKE) -C ebb install diff --git a/tools/testing/selftests/powerpc/pmu/lib.c b/tools/testing/selftests/powerpc/pmu/lib.c index 9768dea37bf3..a07104c2afe6 100644 --- a/tools/testing/selftests/powerpc/pmu/lib.c +++ b/tools/testing/selftests/powerpc/pmu/lib.c @@ -5,15 +5,10 @@ #define _GNU_SOURCE /* For CPU_ZERO etc. */ -#include <elf.h> #include <errno.h> -#include <fcntl.h> -#include <link.h> #include <sched.h> #include <setjmp.h> #include <stdlib.h> -#include <sys/stat.h> -#include <sys/types.h> #include <sys/wait.h> #include "utils.h" @@ -256,45 +251,3 @@ out: return rc; } -static char auxv[4096]; - -void *get_auxv_entry(int type) -{ - ElfW(auxv_t) *p; - void *result; - ssize_t num; - int fd; - - fd = open("/proc/self/auxv", O_RDONLY); - if (fd == -1) { - perror("open"); - return NULL; - } - - result = NULL; - - num = read(fd, auxv, sizeof(auxv)); - if (num < 0) { - perror("read"); - goto out; - } - - if (num > sizeof(auxv)) { - printf("Overflowed auxv buffer\n"); - goto out; - } - - p = (ElfW(auxv_t) *)auxv; - - while (p->a_type != AT_NULL) { - if (p->a_type == type) { - result = (void *)p->a_un.a_val; - break; - } - - p++; - } -out: - close(fd); - return result; -} diff --git a/tools/testing/selftests/powerpc/pmu/lib.h b/tools/testing/selftests/powerpc/pmu/lib.h index 0f0339c8a6f6..ca5d72ae3be6 100644 --- a/tools/testing/selftests/powerpc/pmu/lib.h +++ b/tools/testing/selftests/powerpc/pmu/lib.h @@ -29,7 +29,6 @@ extern int notify_parent(union pipe write_pipe); extern int notify_parent_of_error(union pipe write_pipe); extern pid_t eat_cpu(int (test_function)(void)); extern bool require_paranoia_below(int level); -extern void *get_auxv_entry(int type); struct addr_range { uint64_t first, last; diff --git a/tools/testing/selftests/powerpc/switch_endian/.gitignore b/tools/testing/selftests/powerpc/switch_endian/.gitignore new file mode 100644 index 000000000000..89e762eab676 --- /dev/null +++ b/tools/testing/selftests/powerpc/switch_endian/.gitignore @@ -0,0 +1,2 @@ +switch_endian_test +check-reversed.S diff --git a/tools/testing/selftests/powerpc/switch_endian/Makefile b/tools/testing/selftests/powerpc/switch_endian/Makefile new file mode 100644 index 000000000000..081473db22b7 --- /dev/null +++ b/tools/testing/selftests/powerpc/switch_endian/Makefile @@ -0,0 +1,24 @@ +CC := $(CROSS_COMPILE)gcc +PROGS := switch_endian_test + +ASFLAGS += -O2 -Wall -g -nostdlib -m64 + +all: $(PROGS) + +switch_endian_test: check-reversed.S + +check-reversed.o: check.o + $(CROSS_COMPILE)objcopy -j .text --reverse-bytes=4 -O binary $< $@ + +check-reversed.S: check-reversed.o + hexdump -v -e '/1 ".byte 0x%02X\n"' $< > $@ + +run_tests: all + @-for PROG in $(PROGS); do \ + ./$$PROG; \ + done; + +clean: + rm -f $(PROGS) *.o check-reversed.S + +.PHONY: all run_tests clean diff --git a/tools/testing/selftests/powerpc/switch_endian/check.S b/tools/testing/selftests/powerpc/switch_endian/check.S new file mode 100644 index 000000000000..e2484d2c24f4 --- /dev/null +++ b/tools/testing/selftests/powerpc/switch_endian/check.S @@ -0,0 +1,100 @@ +#include "common.h" + +/* + * Checks that registers contain what we expect, ie. they were not clobbered by + * the syscall. + * + * r15: pattern to check registers against. + * + * At the end r3 == 0 if everything's OK. + */ + nop # guaranteed to be illegal in reverse-endian + mr r9,r15 + cmpd r9,r3 # check r3 + bne 1f + addi r9,r15,4 # check r4 + cmpd r9,r4 + bne 1f + lis r9,0x00FF # check CR + ori r9,r9,0xF000 + mfcr r10 + and r10,r10,r9 + cmpw r9,r10 + addi r9,r15,34 + bne 1f + addi r9,r15,32 # check LR + mflr r10 + cmpd r9,r10 + bne 1f + addi r9,r15,5 # check r5 + cmpd r9,r5 + bne 1f + addi r9,r15,6 # check r6 + cmpd r9,r6 + bne 1f + addi r9,r15,7 # check r7 + cmpd r9,r7 + bne 1f + addi r9,r15,8 # check r8 + cmpd r9,r8 + bne 1f + addi r9,r15,13 # check r13 + cmpd r9,r13 + bne 1f + addi r9,r15,14 # check r14 + cmpd r9,r14 + bne 1f + addi r9,r15,16 # check r16 + cmpd r9,r16 + bne 1f + addi r9,r15,17 # check r17 + cmpd r9,r17 + bne 1f + addi r9,r15,18 # check r18 + cmpd r9,r18 + bne 1f + addi r9,r15,19 # check r19 + cmpd r9,r19 + bne 1f + addi r9,r15,20 # check r20 + cmpd r9,r20 + bne 1f + addi r9,r15,21 # check r21 + cmpd r9,r21 + bne 1f + addi r9,r15,22 # check r22 + cmpd r9,r22 + bne 1f + addi r9,r15,23 # check r23 + cmpd r9,r23 + bne 1f + addi r9,r15,24 # check r24 + cmpd r9,r24 + bne 1f + addi r9,r15,25 # check r25 + cmpd r9,r25 + bne 1f + addi r9,r15,26 # check r26 + cmpd r9,r26 + bne 1f + addi r9,r15,27 # check r27 + cmpd r9,r27 + bne 1f + addi r9,r15,28 # check r28 + cmpd r9,r28 + bne 1f + addi r9,r15,29 # check r29 + cmpd r9,r29 + bne 1f + addi r9,r15,30 # check r30 + cmpd r9,r30 + bne 1f + addi r9,r15,31 # check r31 + cmpd r9,r31 + bne 1f + b 2f +1: mr r3, r9 + li r0, __NR_exit + sc +2: li r0, __NR_switch_endian + nop diff --git a/tools/testing/selftests/powerpc/switch_endian/common.h b/tools/testing/selftests/powerpc/switch_endian/common.h new file mode 100644 index 000000000000..69e399698c64 --- /dev/null +++ b/tools/testing/selftests/powerpc/switch_endian/common.h @@ -0,0 +1,6 @@ +#include <ppc-asm.h> +#include <asm/unistd.h> + +#ifndef __NR_switch_endian +#define __NR_switch_endian 363 +#endif diff --git a/tools/testing/selftests/powerpc/switch_endian/switch_endian_test.S b/tools/testing/selftests/powerpc/switch_endian/switch_endian_test.S new file mode 100644 index 000000000000..ef7c971abb67 --- /dev/null +++ b/tools/testing/selftests/powerpc/switch_endian/switch_endian_test.S @@ -0,0 +1,81 @@ +#include "common.h" + + .data + .balign 8 +message: + .ascii "success: switch_endian_test\n\0" + + .section ".toc" + .balign 8 +pattern: + .llong 0x5555AAAA5555AAAA + + .text +FUNC_START(_start) + /* Load the pattern */ + ld r15, pattern@TOC(%r2) + + /* Setup CR, only CR2-CR4 are maintained */ + lis r3, 0x00FF + ori r3, r3, 0xF000 + mtcr r3 + + /* Load the pattern slightly modified into the registers */ + mr r3, r15 + addi r4, r15, 4 + + addi r5, r15, 32 + mtlr r5 + + addi r5, r15, 5 + addi r6, r15, 6 + addi r7, r15, 7 + addi r8, r15, 8 + + /* r9 - r12 are clobbered */ + + addi r13, r15, 13 + addi r14, r15, 14 + + /* Skip r15 we're using it */ + + addi r16, r15, 16 + addi r17, r15, 17 + addi r18, r15, 18 + addi r19, r15, 19 + addi r20, r15, 20 + addi r21, r15, 21 + addi r22, r15, 22 + addi r23, r15, 23 + addi r24, r15, 24 + addi r25, r15, 25 + addi r26, r15, 26 + addi r27, r15, 27 + addi r28, r15, 28 + addi r29, r15, 29 + addi r30, r15, 30 + addi r31, r15, 31 + + /* + * Call the syscall to switch endian. + * It clobbers r9-r12, XER, CTR and CR0-1,5-7. + */ + li r0, __NR_switch_endian + sc + +#include "check-reversed.S" + + /* Flip back, r0 already has the switch syscall number */ + .long 0x02000044 /* sc */ + +#include "check.S" + + li r0, __NR_write + li r3, 1 /* stdout */ + ld r4, message@got(%r2) + li r5, 28 /* strlen(message3) */ + sc + li r0, __NR_exit + li r3, 0 + sc + b . diff --git a/tools/testing/selftests/powerpc/tm/.gitignore b/tools/testing/selftests/powerpc/tm/.gitignore index 33d02cc54a3e..2699635d2cd9 100644 --- a/tools/testing/selftests/powerpc/tm/.gitignore +++ b/tools/testing/selftests/powerpc/tm/.gitignore @@ -1 +1,2 @@ tm-resched-dscr +tm-syscall diff --git a/tools/testing/selftests/powerpc/tm/Makefile b/tools/testing/selftests/powerpc/tm/Makefile index 34f2ec634b40..6bff955e1d55 100644 --- a/tools/testing/selftests/powerpc/tm/Makefile +++ b/tools/testing/selftests/powerpc/tm/Makefile @@ -4,6 +4,9 @@ all: $(TEST_PROGS) $(TEST_PROGS): ../harness.c +tm-syscall: tm-syscall-asm.S +tm-syscall: CFLAGS += -mhtm + include ../../lib.mk clean: diff --git a/tools/testing/selftests/powerpc/tm/tm-syscall-asm.S b/tools/testing/selftests/powerpc/tm/tm-syscall-asm.S new file mode 100644 index 000000000000..431f61ae2368 --- /dev/null +++ b/tools/testing/selftests/powerpc/tm/tm-syscall-asm.S @@ -0,0 +1,27 @@ +#include <ppc-asm.h> +#include <asm/unistd.h> + + .text +FUNC_START(getppid_tm_active) + tbegin. + beq 1f + li r0, __NR_getppid + sc + tend. + blr +1: + li r3, -1 + blr + +FUNC_START(getppid_tm_suspended) + tbegin. + beq 1f + li r0, __NR_getppid + tsuspend. + sc + tresume. + tend. + blr +1: + li r3, -1 + blr diff --git a/tools/testing/selftests/powerpc/tm/tm-syscall.c b/tools/testing/selftests/powerpc/tm/tm-syscall.c new file mode 100644 index 000000000000..3ed8d4b252fa --- /dev/null +++ b/tools/testing/selftests/powerpc/tm/tm-syscall.c @@ -0,0 +1,121 @@ +/* + * Copyright 2015, Sam Bobroff, IBM Corp. + * Licensed under GPLv2. + * + * Test the kernel's system call code to ensure that a system call + * made from within an active HTM transaction is aborted with the + * correct failure code. + * Conversely, ensure that a system call made from within a + * suspended transaction can succeed. + */ + +#include <stdio.h> +#include <unistd.h> +#include <sys/syscall.h> +#include <asm/tm.h> +#include <asm/cputable.h> +#include <linux/auxvec.h> +#include <sys/time.h> +#include <stdlib.h> + +#include "utils.h" + +extern int getppid_tm_active(void); +extern int getppid_tm_suspended(void); + +unsigned retries = 0; + +#define TEST_DURATION 10 /* seconds */ +#define TM_RETRIES 100 + +long failure_code(void) +{ + return __builtin_get_texasru() >> 24; +} + +bool failure_is_persistent(void) +{ + return (failure_code() & TM_CAUSE_PERSISTENT) == TM_CAUSE_PERSISTENT; +} + +bool failure_is_syscall(void) +{ + return (failure_code() & TM_CAUSE_SYSCALL) == TM_CAUSE_SYSCALL; +} + +pid_t getppid_tm(bool suspend) +{ + int i; + pid_t pid; + + for (i = 0; i < TM_RETRIES; i++) { + if (suspend) + pid = getppid_tm_suspended(); + else + pid = getppid_tm_active(); + + if (pid >= 0) + return pid; + + if (failure_is_persistent()) { + if (failure_is_syscall()) + return -1; + + printf("Unexpected persistent transaction failure.\n"); + printf("TEXASR 0x%016lx, TFIAR 0x%016lx.\n", + __builtin_get_texasr(), __builtin_get_tfiar()); + exit(-1); + } + + retries++; + } + + printf("Exceeded limit of %d temporary transaction failures.\n", TM_RETRIES); + printf("TEXASR 0x%016lx, TFIAR 0x%016lx.\n", + __builtin_get_texasr(), __builtin_get_tfiar()); + + exit(-1); +} + +int tm_syscall(void) +{ + unsigned count = 0; + struct timeval end, now; + + SKIP_IF(!((long)get_auxv_entry(AT_HWCAP2) & PPC_FEATURE2_HTM)); + setbuf(stdout, NULL); + + printf("Testing transactional syscalls for %d seconds...\n", TEST_DURATION); + + gettimeofday(&end, NULL); + now.tv_sec = TEST_DURATION; + now.tv_usec = 0; + timeradd(&end, &now, &end); + + for (count = 0; timercmp(&now, &end, <); count++) { + /* + * Test a syscall within a suspended transaction and verify + * that it succeeds. + */ + FAIL_IF(getppid_tm(true) == -1); /* Should succeed. */ + + /* + * Test a syscall within an active transaction and verify that + * it fails with the correct failure code. + */ + FAIL_IF(getppid_tm(false) != -1); /* Should fail... */ + FAIL_IF(!failure_is_persistent()); /* ...persistently... */ + FAIL_IF(!failure_is_syscall()); /* ...with code syscall. */ + gettimeofday(&now, 0); + } + + printf("%d active and suspended transactions behaved correctly.\n", count); + printf("(There were %d transaction retries.)\n", retries); + + return 0; +} + +int main(void) +{ + return test_harness(tm_syscall, "tm_syscall"); +} diff --git a/tools/testing/selftests/powerpc/utils.h b/tools/testing/selftests/powerpc/utils.h index a93777ae0684..b7d41086bb0a 100644 --- a/tools/testing/selftests/powerpc/utils.h +++ b/tools/testing/selftests/powerpc/utils.h @@ -15,11 +15,12 @@ typedef signed long long s64; /* Just for familiarity */ typedef uint32_t u32; +typedef uint16_t u16; typedef uint8_t u8; int test_harness(int (test_function)(void), char *name); - +extern void *get_auxv_entry(int type); /* Yes, this is evil */ #define FAIL_IF(x) \ diff --git a/tools/testing/selftests/powerpc/vphn/.gitignore b/tools/testing/selftests/powerpc/vphn/.gitignore new file mode 100644 index 000000000000..7c04395010cb --- /dev/null +++ b/tools/testing/selftests/powerpc/vphn/.gitignore @@ -0,0 +1 @@ +test-vphn diff --git a/tools/testing/selftests/powerpc/vphn/Makefile b/tools/testing/selftests/powerpc/vphn/Makefile new file mode 100644 index 000000000000..e539f775fd8f --- /dev/null +++ b/tools/testing/selftests/powerpc/vphn/Makefile @@ -0,0 +1,15 @@ +PROG := test-vphn + +CFLAGS += -m64 + +all: $(PROG) + +$(PROG): ../harness.c + +run_tests: all + ./$(PROG) + +clean: + rm -f $(PROG) + +.PHONY: all run_tests clean diff --git a/tools/testing/selftests/powerpc/vphn/test-vphn.c b/tools/testing/selftests/powerpc/vphn/test-vphn.c new file mode 100644 index 000000000000..5742f6876b25 --- /dev/null +++ b/tools/testing/selftests/powerpc/vphn/test-vphn.c @@ -0,0 +1,410 @@ +#include <stdio.h> +#include <byteswap.h> +#include "utils.h" +#include "subunit.h" + +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define cpu_to_be32(x) bswap_32(x) +#define be32_to_cpu(x) bswap_32(x) +#define be16_to_cpup(x) bswap_16(*x) +#define cpu_to_be64(x) bswap_64(x) +#else +#define cpu_to_be32(x) (x) +#define be32_to_cpu(x) (x) +#define be16_to_cpup(x) (*x) +#define cpu_to_be64(x) (x) +#endif + +#include "vphn.c" + +static struct test { + char *descr; + long input[VPHN_REGISTER_COUNT]; + u32 expected[VPHN_ASSOC_BUFSIZE]; +} all_tests[] = { + { + "vphn: no data", + { + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + }, + { + 0x00000000 + } + }, + { + "vphn: 1 x 16-bit value", + { + 0x8001ffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + }, + { + 0x00000001, + 0x00000001 + } + }, + { + "vphn: 2 x 16-bit values", + { + 0x80018002ffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + }, + { + 0x00000002, + 0x00000001, + 0x00000002 + } + }, + { + "vphn: 3 x 16-bit values", + { + 0x800180028003ffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + }, + { + 0x00000003, + 0x00000001, + 0x00000002, + 0x00000003 + } + }, + { + "vphn: 4 x 16-bit values", + { + 0x8001800280038004, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + }, + { + 0x00000004, + 0x00000001, + 0x00000002, + 0x00000003, + 0x00000004 + } + }, + { + /* Parsing the next 16-bit value out of the next 64-bit input + * value. + */ + "vphn: 5 x 16-bit values", + { + 0x8001800280038004, + 0x8005ffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + }, + { + 0x00000005, + 0x00000001, + 0x00000002, + 0x00000003, + 0x00000004, + 0x00000005 + } + }, + { + /* Parse at most 6 x 64-bit input values */ + "vphn: 24 x 16-bit values", + { + 0x8001800280038004, + 0x8005800680078008, + 0x8009800a800b800c, + 0x800d800e800f8010, + 0x8011801280138014, + 0x8015801680178018 + }, + { + 0x00000018, + 0x00000001, + 0x00000002, + 0x00000003, + 0x00000004, + 0x00000005, + 0x00000006, + 0x00000007, + 0x00000008, + 0x00000009, + 0x0000000a, + 0x0000000b, + 0x0000000c, + 0x0000000d, + 0x0000000e, + 0x0000000f, + 0x00000010, + 0x00000011, + 0x00000012, + 0x00000013, + 0x00000014, + 0x00000015, + 0x00000016, + 0x00000017, + 0x00000018 + } + }, + { + "vphn: 1 x 32-bit value", + { + 0x00000001ffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff + }, + { + 0x00000001, + 0x00000001 + } + }, + { + "vphn: 2 x 32-bit values", + { + 0x0000000100000002, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff + }, + { + 0x00000002, + 0x00000001, + 0x00000002 + } + }, + { + /* Parsing the next 32-bit value out of the next 64-bit input + * value. + */ + "vphn: 3 x 32-bit values", + { + 0x0000000100000002, + 0x00000003ffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff + }, + { + 0x00000003, + 0x00000001, + 0x00000002, + 0x00000003 + } + }, + { + /* Parse at most 6 x 64-bit input values */ + "vphn: 12 x 32-bit values", + { + 0x0000000100000002, + 0x0000000300000004, + 0x0000000500000006, + 0x0000000700000008, + 0x000000090000000a, + 0x0000000b0000000c + }, + { + 0x0000000c, + 0x00000001, + 0x00000002, + 0x00000003, + 0x00000004, + 0x00000005, + 0x00000006, + 0x00000007, + 0x00000008, + 0x00000009, + 0x0000000a, + 0x0000000b, + 0x0000000c + } + }, + { + "vphn: 16-bit value followed by 32-bit value", + { + 0x800100000002ffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff + }, + { + 0x00000002, + 0x00000001, + 0x00000002 + } + }, + { + "vphn: 32-bit value followed by 16-bit value", + { + 0x000000018002ffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff + }, + { + 0x00000002, + 0x00000001, + 0x00000002 + } + }, + { + /* Parse a 32-bit value split accross two consecutives 64-bit + * input values. + */ + "vphn: 16-bit value followed by 2 x 32-bit values", + { + 0x8001000000020000, + 0x0003ffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff + }, + { + 0x00000003, + 0x00000001, + 0x00000002, + 0x00000003, + 0x00000004, + 0x00000005 + } + }, + { + /* The lower bits in 0x0001ffff don't get mixed up with the + * 0xffff terminator. + */ + "vphn: 32-bit value has all ones in 16 lower bits", + { + 0x0001ffff80028003, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff + }, + { + 0x00000003, + 0x0001ffff, + 0x00000002, + 0x00000003 + } + }, + { + /* The following input doesn't follow the specification. + */ + "vphn: last 32-bit value is truncated", + { + 0x0000000100000002, + 0x0000000300000004, + 0x0000000500000006, + 0x0000000700000008, + 0x000000090000000a, + 0x0000000b800c2bad + }, + { + 0x0000000c, + 0x00000001, + 0x00000002, + 0x00000003, + 0x00000004, + 0x00000005, + 0x00000006, + 0x00000007, + 0x00000008, + 0x00000009, + 0x0000000a, + 0x0000000b, + 0x0000000c + } + }, + { + "vphn: garbage after terminator", + { + 0xffff2bad2bad2bad, + 0x2bad2bad2bad2bad, + 0x2bad2bad2bad2bad, + 0x2bad2bad2bad2bad, + 0x2bad2bad2bad2bad, + 0x2bad2bad2bad2bad + }, + { + 0x00000000 + } + }, + { + NULL + } +}; + +static int test_one(struct test *test) +{ + __be32 output[VPHN_ASSOC_BUFSIZE] = { 0 }; + int i, len; + + vphn_unpack_associativity(test->input, output); + + len = be32_to_cpu(output[0]); + if (len != test->expected[0]) { + printf("expected %d elements, got %d\n", test->expected[0], + len); + return 1; + } + + for (i = 1; i < len; i++) { + u32 val = be32_to_cpu(output[i]); + if (val != test->expected[i]) { + printf("element #%d is 0x%x, should be 0x%x\n", i, val, + test->expected[i]); + return 1; + } + } + + return 0; +} + +static int test_vphn(void) +{ + static struct test *test; + + for (test = all_tests; test->descr; test++) { + int ret; + + ret = test_one(test); + test_finish(test->descr, ret); + if (ret) + return ret; + } + + return 0; +} + +int main(int argc, char **argv) +{ + return test_harness(test_vphn, "test-vphn"); +} diff --git a/tools/testing/selftests/powerpc/vphn/vphn.c b/tools/testing/selftests/powerpc/vphn/vphn.c new file mode 120000 index 000000000000..186b906e66d5 --- /dev/null +++ b/tools/testing/selftests/powerpc/vphn/vphn.c @@ -0,0 +1 @@ +../../../../../arch/powerpc/mm/vphn.c
\ No newline at end of file diff --git a/tools/testing/selftests/powerpc/vphn/vphn.h b/tools/testing/selftests/powerpc/vphn/vphn.h new file mode 120000 index 000000000000..7131efe38c65 --- /dev/null +++ b/tools/testing/selftests/powerpc/vphn/vphn.h @@ -0,0 +1 @@ +../../../../../arch/powerpc/mm/vphn.h
\ No newline at end of file diff --git a/tools/testing/selftests/rcutorture/bin/kvm.sh b/tools/testing/selftests/rcutorture/bin/kvm.sh index 368d64ac779e..dd2812ceb0ba 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm.sh @@ -310,7 +310,7 @@ function dump(first, pastlast) cfr[jn] = cf[j] "." cfrep[cf[j]]; } if (cpusr[jn] > ncpus && ncpus != 0) - ovf = "(!)"; + ovf = "-ovf"; else ovf = ""; print "echo ", cfr[jn], cpusr[jn] ovf ": Starting build. `date`"; diff --git a/tools/testing/selftests/rcutorture/configs/rcu/CFcommon b/tools/testing/selftests/rcutorture/configs/rcu/CFcommon index d2d2a86139db..49701218dc62 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/CFcommon +++ b/tools/testing/selftests/rcutorture/configs/rcu/CFcommon @@ -1,2 +1,3 @@ CONFIG_RCU_TORTURE_TEST=y CONFIG_PRINTK_TIME=y +CONFIG_RCU_TORTURE_TEST_SLOW_INIT=y diff --git a/tools/testing/selftests/vm/hugetlbfstest.c b/tools/testing/selftests/vm/hugetlbfstest.c index ea40ff8c2391..02e1072ec187 100644 --- a/tools/testing/selftests/vm/hugetlbfstest.c +++ b/tools/testing/selftests/vm/hugetlbfstest.c @@ -34,6 +34,7 @@ static void do_mmap(int fd, int extra_flags, int unmap) int *p; int flags = MAP_PRIVATE | MAP_POPULATE | extra_flags; u64 before, after; + int ret; before = read_rss(); p = mmap(NULL, length, PROT_READ | PROT_WRITE, flags, fd, 0); @@ -44,7 +45,8 @@ static void do_mmap(int fd, int extra_flags, int unmap) !"rss didn't grow as expected"); if (!unmap) return; - munmap(p, length); + ret = munmap(p, length); + assert(!ret || !"munmap returned an unexpected error"); after = read_rss(); assert(llabs(after - before) < 0x40000 || !"rss didn't shrink as expected"); diff --git a/tools/testing/selftests/vm/map_hugetlb.c b/tools/testing/selftests/vm/map_hugetlb.c index ac56639dd4a9..addcd6fc1ecc 100644 --- a/tools/testing/selftests/vm/map_hugetlb.c +++ b/tools/testing/selftests/vm/map_hugetlb.c @@ -73,7 +73,11 @@ int main(void) write_bytes(addr); ret = read_bytes(addr); - munmap(addr, LENGTH); + /* munmap() length of MAP_HUGETLB memory must be hugepage aligned */ + if (munmap(addr, LENGTH)) { + perror("munmap"); + exit(1); + } return ret; } diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile index f0a7918178dd..5bdb781163d1 100644 --- a/tools/testing/selftests/x86/Makefile +++ b/tools/testing/selftests/x86/Makefile @@ -1,48 +1,57 @@ -.PHONY: all all_32 all_64 check_build32 clean run_tests +all: -TARGETS_C_BOTHBITS := sigreturn +include ../lib.mk + +.PHONY: all all_32 all_64 warn_32bit_failure clean + +TARGETS_C_BOTHBITS := sigreturn single_step_syscall BINARIES_32 := $(TARGETS_C_BOTHBITS:%=%_32) BINARIES_64 := $(TARGETS_C_BOTHBITS:%=%_64) CFLAGS := -O2 -g -std=gnu99 -pthread -Wall -UNAME_P := $(shell uname -p) +UNAME_M := $(shell uname -m) +CAN_BUILD_I386 := $(shell ./check_cc.sh $(CC) trivial_32bit_program.c -m32) +CAN_BUILD_X86_64 := $(shell ./check_cc.sh $(CC) trivial_64bit_program.c) -# Always build 32-bit tests +ifeq ($(CAN_BUILD_I386),1) all: all_32 +TEST_PROGS += $(BINARIES_32) +endif -# If we're on a 64-bit host, build 64-bit tests as well -ifeq ($(shell uname -p),x86_64) +ifeq ($(CAN_BUILD_X86_64),1) all: all_64 +TEST_PROGS += $(BINARIES_64) endif -all_32: check_build32 $(BINARIES_32) +all_32: $(BINARIES_32) all_64: $(BINARIES_64) clean: $(RM) $(BINARIES_32) $(BINARIES_64) -run_tests: - ./run_x86_tests.sh - $(TARGETS_C_BOTHBITS:%=%_32): %_32: %.c $(CC) -m32 -o $@ $(CFLAGS) $(EXTRA_CFLAGS) $^ -lrt -ldl $(TARGETS_C_BOTHBITS:%=%_64): %_64: %.c $(CC) -m64 -o $@ $(CFLAGS) $(EXTRA_CFLAGS) $^ -lrt -ldl -check_build32: - @if ! $(CC) -m32 -o /dev/null trivial_32bit_program.c; then \ - echo "Warning: you seem to have a broken 32-bit build" 2>&1; \ - echo "environment. If you are using a Debian-like"; \ - echo " distribution, try:"; \ - echo ""; \ - echo " apt-get install gcc-multilib libc6-i386 libc6-dev-i386"; \ - echo ""; \ - echo "If you are using a Fedora-like distribution, try:"; \ - echo ""; \ - echo " yum install glibc-devel.*i686"; \ - exit 1; \ - fi +# x86_64 users should be encouraged to install 32-bit libraries +ifeq ($(CAN_BUILD_I386)$(CAN_BUILD_X86_64),01) +all: warn_32bit_failure + +warn_32bit_failure: + @echo "Warning: you seem to have a broken 32-bit build" 2>&1; \ + echo "environment. This will reduce test coverage of 64-bit" 2>&1; \ + echo "kernels. If you are using a Debian-like distribution," 2>&1; \ + echo "try:"; 2>&1; \ + echo ""; \ + echo " apt-get install gcc-multilib libc6-i386 libc6-dev-i386"; \ + echo ""; \ + echo "If you are using a Fedora-like distribution, try:"; \ + echo ""; \ + echo " yum install glibc-devel.*i686"; \ + exit 0; +endif diff --git a/tools/testing/selftests/x86/check_cc.sh b/tools/testing/selftests/x86/check_cc.sh new file mode 100755 index 000000000000..172d3293fb7b --- /dev/null +++ b/tools/testing/selftests/x86/check_cc.sh @@ -0,0 +1,16 @@ +#!/bin/sh +# check_cc.sh - Helper to test userspace compilation support +# Copyright (c) 2015 Andrew Lutomirski +# GPL v2 + +CC="$1" +TESTPROG="$2" +shift 2 + +if "$CC" -o /dev/null "$TESTPROG" -O0 "$@" 2>/dev/null; then + echo 1 +else + echo 0 +fi + +exit 0 diff --git a/tools/testing/selftests/x86/run_x86_tests.sh b/tools/testing/selftests/x86/run_x86_tests.sh deleted file mode 100644 index 3d3ec65f3e7c..000000000000 --- a/tools/testing/selftests/x86/run_x86_tests.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -# This is deliberately minimal. IMO kselftests should provide a standard -# script here. -./sigreturn_32 || exit 1 - -if [[ "$uname -p" -eq "x86_64" ]]; then - ./sigreturn_64 || exit 1 -fi - -exit 0 diff --git a/tools/testing/selftests/x86/single_step_syscall.c b/tools/testing/selftests/x86/single_step_syscall.c new file mode 100644 index 000000000000..50c26358e8b7 --- /dev/null +++ b/tools/testing/selftests/x86/single_step_syscall.c @@ -0,0 +1,181 @@ +/* + * single_step_syscall.c - single-steps various x86 syscalls + * Copyright (c) 2014-2015 Andrew Lutomirski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * This is a very simple series of tests that makes system calls with + * the TF flag set. This exercises some nasty kernel code in the + * SYSENTER case: SYSENTER does not clear TF, so SYSENTER with TF set + * immediately issues #DB from CPL 0. This requires special handling in + * the kernel. + */ + +#define _GNU_SOURCE + +#include <sys/time.h> +#include <time.h> +#include <stdlib.h> +#include <sys/syscall.h> +#include <unistd.h> +#include <stdio.h> +#include <string.h> +#include <inttypes.h> +#include <sys/mman.h> +#include <sys/signal.h> +#include <sys/ucontext.h> +#include <asm/ldt.h> +#include <err.h> +#include <setjmp.h> +#include <stddef.h> +#include <stdbool.h> +#include <sys/ptrace.h> +#include <sys/user.h> + +static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), + int flags) +{ + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_sigaction = handler; + sa.sa_flags = SA_SIGINFO | flags; + sigemptyset(&sa.sa_mask); + if (sigaction(sig, &sa, 0)) + err(1, "sigaction"); +} + +static volatile sig_atomic_t sig_traps; + +#ifdef __x86_64__ +# define REG_IP REG_RIP +# define WIDTH "q" +#else +# define REG_IP REG_EIP +# define WIDTH "l" +#endif + +static unsigned long get_eflags(void) +{ + unsigned long eflags; + asm volatile ("pushf" WIDTH "\n\tpop" WIDTH " %0" : "=rm" (eflags)); + return eflags; +} + +static void set_eflags(unsigned long eflags) +{ + asm volatile ("push" WIDTH " %0\n\tpopf" WIDTH + : : "rm" (eflags) : "flags"); +} + +#define X86_EFLAGS_TF (1UL << 8) + +static void sigtrap(int sig, siginfo_t *info, void *ctx_void) +{ + ucontext_t *ctx = (ucontext_t*)ctx_void; + + if (get_eflags() & X86_EFLAGS_TF) { + set_eflags(get_eflags() & ~X86_EFLAGS_TF); + printf("[WARN]\tSIGTRAP handler had TF set\n"); + _exit(1); + } + + sig_traps++; + + if (sig_traps == 10000 || sig_traps == 10001) { + printf("[WARN]\tHit %d SIGTRAPs with si_addr 0x%lx, ip 0x%lx\n", + (int)sig_traps, + (unsigned long)info->si_addr, + (unsigned long)ctx->uc_mcontext.gregs[REG_IP]); + } +} + +static void check_result(void) +{ + unsigned long new_eflags = get_eflags(); + set_eflags(new_eflags & ~X86_EFLAGS_TF); + + if (!sig_traps) { + printf("[FAIL]\tNo SIGTRAP\n"); + exit(1); + } + + if (!(new_eflags & X86_EFLAGS_TF)) { + printf("[FAIL]\tTF was cleared\n"); + exit(1); + } + + printf("[OK]\tSurvived with TF set and %d traps\n", (int)sig_traps); + sig_traps = 0; +} + +int main() +{ + int tmp; + + sethandler(SIGTRAP, sigtrap, 0); + + printf("[RUN]\tSet TF and check nop\n"); + set_eflags(get_eflags() | X86_EFLAGS_TF); + asm volatile ("nop"); + check_result(); + +#ifdef __x86_64__ + printf("[RUN]\tSet TF and check syscall-less opportunistic sysret\n"); + set_eflags(get_eflags() | X86_EFLAGS_TF); + extern unsigned char post_nop[]; + asm volatile ("pushf" WIDTH "\n\t" + "pop" WIDTH " %%r11\n\t" + "nop\n\t" + "post_nop:" + : : "c" (post_nop) : "r11"); + check_result(); +#endif + + printf("[RUN]\tSet TF and check int80\n"); + set_eflags(get_eflags() | X86_EFLAGS_TF); + asm volatile ("int $0x80" : "=a" (tmp) : "a" (SYS_getpid)); + check_result(); + + /* + * This test is particularly interesting if fast syscalls use + * SYSENTER: it triggers a nasty design flaw in SYSENTER. + * Specifically, SYSENTER does not clear TF, so either SYSENTER + * or the next instruction traps at CPL0. (Of course, Intel + * mostly forgot to document exactly what happens here.) So we + * get a CPL0 fault with usergs (on 64-bit kernels) and possibly + * no stack. The only sane way the kernel can possibly handle + * it is to clear TF on return from the #DB handler, but this + * happens way too early to set TF in the saved pt_regs, so the + * kernel has to do something clever to avoid losing track of + * the TF bit. + * + * Needless to say, we've had bugs in this area. + */ + syscall(SYS_getpid); /* Force symbol binding without TF set. */ + printf("[RUN]\tSet TF and check a fast syscall\n"); + set_eflags(get_eflags() | X86_EFLAGS_TF); + syscall(SYS_getpid); + check_result(); + + /* Now make sure that another fast syscall doesn't set TF again. */ + printf("[RUN]\tFast syscall with TF cleared\n"); + fflush(stdout); /* Force a syscall */ + if (get_eflags() & X86_EFLAGS_TF) { + printf("[FAIL]\tTF is now set\n"); + exit(1); + } + if (sig_traps) { + printf("[FAIL]\tGot SIGTRAP\n"); + exit(1); + } + printf("[OK]\tNothing unexpected happened\n"); + + return 0; +} diff --git a/tools/testing/selftests/x86/trivial_32bit_program.c b/tools/testing/selftests/x86/trivial_32bit_program.c index 2e231beb0a39..fabdf0f51621 100644 --- a/tools/testing/selftests/x86/trivial_32bit_program.c +++ b/tools/testing/selftests/x86/trivial_32bit_program.c @@ -4,6 +4,10 @@ * GPL v2 */ +#ifndef __i386__ +# error wrong architecture +#endif + #include <stdio.h> int main() diff --git a/tools/testing/selftests/x86/trivial_64bit_program.c b/tools/testing/selftests/x86/trivial_64bit_program.c new file mode 100644 index 000000000000..b994946c40fb --- /dev/null +++ b/tools/testing/selftests/x86/trivial_64bit_program.c @@ -0,0 +1,18 @@ +/* + * Trivial program to check that we have a valid 32-bit build environment. + * Copyright (c) 2015 Andy Lutomirski + * GPL v2 + */ + +#ifndef __x86_64__ +# error wrong architecture +#endif + +#include <stdio.h> + +int main() +{ + printf("\n"); + + return 0; +} |