diff options
Diffstat (limited to 'tools/testing/selftests')
14 files changed, 393 insertions, 4 deletions
diff --git a/tools/testing/selftests/powerpc/Makefile b/tools/testing/selftests/powerpc/Makefile index f6ff90a76bd..1d5e7ad2c46 100644 --- a/tools/testing/selftests/powerpc/Makefile +++ b/tools/testing/selftests/powerpc/Makefile @@ -13,7 +13,7 @@ CFLAGS := -Wall -O2 -flto -Wall -Werror -DGIT_VERSION='"$(GIT_VERSION)"' -I$(CUR export CC CFLAGS -TARGETS = pmu copyloops mm tm primitives +TARGETS = pmu copyloops mm tm primitives stringloops endif diff --git a/tools/testing/selftests/powerpc/copyloops/.gitignore b/tools/testing/selftests/powerpc/copyloops/.gitignore new file mode 100644 index 00000000000..25a192f62c4 --- /dev/null +++ b/tools/testing/selftests/powerpc/copyloops/.gitignore @@ -0,0 +1,4 @@ +copyuser_64 +copyuser_power7 +memcpy_64 +memcpy_power7 diff --git a/tools/testing/selftests/powerpc/mm/.gitignore b/tools/testing/selftests/powerpc/mm/.gitignore new file mode 100644 index 00000000000..b43ade0ec86 --- /dev/null +++ b/tools/testing/selftests/powerpc/mm/.gitignore @@ -0,0 +1,3 @@ +hugetlb_vs_thp_test +subpage_prot +tempfile diff --git a/tools/testing/selftests/powerpc/mm/Makefile b/tools/testing/selftests/powerpc/mm/Makefile index 357ccbd6bad..a14c538dd7f 100644 --- a/tools/testing/selftests/powerpc/mm/Makefile +++ b/tools/testing/selftests/powerpc/mm/Makefile @@ -1,9 +1,9 @@ noarg: $(MAKE) -C ../ -PROGS := hugetlb_vs_thp_test +PROGS := hugetlb_vs_thp_test subpage_prot -all: $(PROGS) +all: $(PROGS) tempfile $(PROGS): ../harness.c @@ -12,7 +12,10 @@ run_tests: all ./$$PROG; \ done; +tempfile: + dd if=/dev/zero of=tempfile bs=64k count=1 + clean: - rm -f $(PROGS) + rm -f $(PROGS) tempfile .PHONY: all run_tests clean diff --git a/tools/testing/selftests/powerpc/mm/subpage_prot.c b/tools/testing/selftests/powerpc/mm/subpage_prot.c new file mode 100644 index 00000000000..440180ff808 --- /dev/null +++ b/tools/testing/selftests/powerpc/mm/subpage_prot.c @@ -0,0 +1,220 @@ +/* + * Copyright IBM Corp. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#include <assert.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/ptrace.h> +#include <sys/syscall.h> +#include <ucontext.h> +#include <unistd.h> + +#include "utils.h" + +char *file_name; + +int in_test; +volatile int faulted; +volatile void *dar; +int errors; + +static void segv(int signum, siginfo_t *info, void *ctxt_v) +{ + ucontext_t *ctxt = (ucontext_t *)ctxt_v; + struct pt_regs *regs = ctxt->uc_mcontext.regs; + + if (!in_test) { + fprintf(stderr, "Segfault outside of test !\n"); + exit(1); + } + + faulted = 1; + dar = (void *)regs->dar; + regs->nip += 4; +} + +static inline void do_read(const volatile void *addr) +{ + int ret; + + asm volatile("lwz %0,0(%1); twi 0,%0,0; isync;\n" + : "=r" (ret) : "r" (addr) : "memory"); +} + +static inline void do_write(const volatile void *addr) +{ + int val = 0x1234567; + + asm volatile("stw %0,0(%1); sync; \n" + : : "r" (val), "r" (addr) : "memory"); +} + +static inline void check_faulted(void *addr, long page, long subpage, int write) +{ + int want_fault = (subpage == ((page + 3) % 16)); + + if (write) + want_fault |= (subpage == ((page + 1) % 16)); + + if (faulted != want_fault) { + printf("Failed at 0x%p (p=%ld,sp=%ld,w=%d), want=%s, got=%s !\n", + addr, page, subpage, write, + want_fault ? "fault" : "pass", + faulted ? "fault" : "pass"); + ++errors; + } + + if (faulted) { + if (dar != addr) { + printf("Fault expected at 0x%p and happened at 0x%p !\n", + addr, dar); + } + faulted = 0; + asm volatile("sync" : : : "memory"); + } +} + +static int run_test(void *addr, unsigned long size) +{ + unsigned int *map; + long i, j, pages, err; + + pages = size / 0x10000; + map = malloc(pages * 4); + assert(map); + + /* + * for each page, mark subpage i % 16 read only and subpage + * (i + 3) % 16 inaccessible + */ + for (i = 0; i < pages; i++) { + map[i] = (0x40000000 >> (((i + 1) * 2) % 32)) | + (0xc0000000 >> (((i + 3) * 2) % 32)); + } + + err = syscall(__NR_subpage_prot, addr, size, map); + if (err) { + perror("subpage_perm"); + return 1; + } + free(map); + + in_test = 1; + errors = 0; + for (i = 0; i < pages; i++) { + for (j = 0; j < 16; j++, addr += 0x1000) { + do_read(addr); + check_faulted(addr, i, j, 0); + do_write(addr); + check_faulted(addr, i, j, 1); + } + } + + in_test = 0; + if (errors) { + printf("%d errors detected\n", errors); + return 1; + } + + return 0; +} + +int test_anon(void) +{ + unsigned long align; + struct sigaction act = { + .sa_sigaction = segv, + .sa_flags = SA_SIGINFO + }; + void *mallocblock; + unsigned long mallocsize; + + if (getpagesize() != 0x10000) { + fprintf(stderr, "Kernel page size must be 64K!\n"); + return 1; + } + + sigaction(SIGSEGV, &act, NULL); + + mallocsize = 4 * 16 * 1024 * 1024; + + FAIL_IF(posix_memalign(&mallocblock, 64 * 1024, mallocsize)); + + align = (unsigned long)mallocblock; + if (align & 0xffff) + align = (align | 0xffff) + 1; + + mallocblock = (void *)align; + + printf("allocated malloc block of 0x%lx bytes at 0x%p\n", + mallocsize, mallocblock); + + printf("testing malloc block...\n"); + + return run_test(mallocblock, mallocsize); +} + +int test_file(void) +{ + struct sigaction act = { + .sa_sigaction = segv, + .sa_flags = SA_SIGINFO + }; + void *fileblock; + off_t filesize; + int fd; + + fd = open(file_name, O_RDWR); + if (fd == -1) { + perror("failed to open file"); + return 1; + } + sigaction(SIGSEGV, &act, NULL); + + filesize = lseek(fd, 0, SEEK_END); + if (filesize & 0xffff) + filesize &= ~0xfffful; + + fileblock = mmap(NULL, filesize, PROT_READ | PROT_WRITE, + MAP_SHARED, fd, 0); + if (fileblock == MAP_FAILED) { + perror("failed to map file"); + return 1; + } + printf("allocated %s for 0x%lx bytes at 0x%p\n", + file_name, filesize, fileblock); + + printf("testing file map...\n"); + + return run_test(fileblock, filesize); +} + +int main(int argc, char *argv[]) +{ + test_harness(test_anon, "subpage_prot_anon"); + + if (argc > 1) + file_name = argv[1]; + else + file_name = "tempfile"; + + test_harness(test_file, "subpage_prot_file"); + + return 0; +} diff --git a/tools/testing/selftests/powerpc/pmu/.gitignore b/tools/testing/selftests/powerpc/pmu/.gitignore new file mode 100644 index 00000000000..e748f336eed --- /dev/null +++ b/tools/testing/selftests/powerpc/pmu/.gitignore @@ -0,0 +1,3 @@ +count_instructions +l3_bank_test +per_event_excludes diff --git a/tools/testing/selftests/powerpc/pmu/ebb/.gitignore b/tools/testing/selftests/powerpc/pmu/ebb/.gitignore new file mode 100644 index 00000000000..42bddbed8b6 --- /dev/null +++ b/tools/testing/selftests/powerpc/pmu/ebb/.gitignore @@ -0,0 +1,22 @@ +reg_access_test +event_attributes_test +cycles_test +cycles_with_freeze_test +pmc56_overflow_test +ebb_vs_cpu_event_test +cpu_event_vs_ebb_test +cpu_event_pinned_vs_ebb_test +task_event_vs_ebb_test +task_event_pinned_vs_ebb_test +multi_ebb_procs_test +multi_counter_test +pmae_handling_test +close_clears_pmcc_test +instruction_count_test +fork_cleanup_test +ebb_on_child_test +ebb_on_willing_child_test +back_to_back_ebbs_test +lost_exception_test +no_handler_test +cycles_with_mmcr2_test diff --git a/tools/testing/selftests/powerpc/primitives/.gitignore b/tools/testing/selftests/powerpc/primitives/.gitignore new file mode 100644 index 00000000000..4cc4e31bed1 --- /dev/null +++ b/tools/testing/selftests/powerpc/primitives/.gitignore @@ -0,0 +1 @@ +load_unaligned_zeropad diff --git a/tools/testing/selftests/powerpc/stringloops/.gitignore b/tools/testing/selftests/powerpc/stringloops/.gitignore new file mode 100644 index 00000000000..0b43da74ee4 --- /dev/null +++ b/tools/testing/selftests/powerpc/stringloops/.gitignore @@ -0,0 +1 @@ +memcmp diff --git a/tools/testing/selftests/powerpc/stringloops/Makefile b/tools/testing/selftests/powerpc/stringloops/Makefile new file mode 100644 index 00000000000..506d7734647 --- /dev/null +++ b/tools/testing/selftests/powerpc/stringloops/Makefile @@ -0,0 +1,20 @@ +# The loops are all 64-bit code +CFLAGS += -m64 +CFLAGS += -I$(CURDIR) + +PROGS := memcmp +EXTRA_SOURCES := memcmp_64.S ../harness.c + +all: $(PROGS) + +$(PROGS): $(EXTRA_SOURCES) + +run_tests: all + @-for PROG in $(PROGS); do \ + ./$$PROG; \ + done; + +clean: + rm -f $(PROGS) *.o + +.PHONY: all run_tests clean diff --git a/tools/testing/selftests/powerpc/stringloops/asm/ppc_asm.h b/tools/testing/selftests/powerpc/stringloops/asm/ppc_asm.h new file mode 100644 index 00000000000..11bece87e88 --- /dev/null +++ b/tools/testing/selftests/powerpc/stringloops/asm/ppc_asm.h @@ -0,0 +1,7 @@ +#include <ppc-asm.h> + +#ifndef r1 +#define r1 sp +#endif + +#define _GLOBAL(A) FUNC_START(test_ ## A) diff --git a/tools/testing/selftests/powerpc/stringloops/memcmp.c b/tools/testing/selftests/powerpc/stringloops/memcmp.c new file mode 100644 index 00000000000..17417dd7070 --- /dev/null +++ b/tools/testing/selftests/powerpc/stringloops/memcmp.c @@ -0,0 +1,103 @@ +#include <malloc.h> +#include <stdlib.h> +#include <string.h> +#include "../utils.h" + +#define SIZE 256 +#define ITERATIONS 10000 + +int test_memcmp(const void *s1, const void *s2, size_t n); + +/* test all offsets and lengths */ +static void test_one(char *s1, char *s2) +{ + unsigned long offset, size; + + for (offset = 0; offset < SIZE; offset++) { + for (size = 0; size < (SIZE-offset); size++) { + int x, y; + unsigned long i; + + y = memcmp(s1+offset, s2+offset, size); + x = test_memcmp(s1+offset, s2+offset, size); + + if (((x ^ y) < 0) && /* Trick to compare sign */ + ((x | y) != 0)) { /* check for zero */ + printf("memcmp returned %d, should have returned %d (offset %ld size %ld)\n", x, y, offset, size); + + for (i = offset; i < offset+size; i++) + printf("%02x ", s1[i]); + printf("\n"); + + for (i = offset; i < offset+size; i++) + printf("%02x ", s2[i]); + printf("\n"); + abort(); + } + } + } +} + +static int testcase(void) +{ + char *s1; + char *s2; + unsigned long i; + + s1 = memalign(128, SIZE); + if (!s1) { + perror("memalign"); + exit(1); + } + + s2 = memalign(128, SIZE); + if (!s2) { + perror("memalign"); + exit(1); + } + + srandom(1); + + for (i = 0; i < ITERATIONS; i++) { + unsigned long j; + unsigned long change; + + for (j = 0; j < SIZE; j++) + s1[j] = random(); + + memcpy(s2, s1, SIZE); + + /* change one byte */ + change = random() % SIZE; + s2[change] = random() & 0xff; + + test_one(s1, s2); + } + + srandom(1); + + for (i = 0; i < ITERATIONS; i++) { + unsigned long j; + unsigned long change; + + for (j = 0; j < SIZE; j++) + s1[j] = random(); + + memcpy(s2, s1, SIZE); + + /* change multiple bytes, 1/8 of total */ + for (j = 0; j < SIZE / 8; j++) { + change = random() % SIZE; + s2[change] = random() & 0xff; + } + + test_one(s1, s2); + } + + return 0; +} + +int main(void) +{ + return test_harness(testcase, "memcmp"); +} diff --git a/tools/testing/selftests/powerpc/stringloops/memcmp_64.S b/tools/testing/selftests/powerpc/stringloops/memcmp_64.S new file mode 120000 index 00000000000..9bc87e438ae --- /dev/null +++ b/tools/testing/selftests/powerpc/stringloops/memcmp_64.S @@ -0,0 +1 @@ +../../../../../arch/powerpc/lib/memcmp_64.S
\ No newline at end of file diff --git a/tools/testing/selftests/powerpc/tm/.gitignore b/tools/testing/selftests/powerpc/tm/.gitignore new file mode 100644 index 00000000000..33d02cc54a3 --- /dev/null +++ b/tools/testing/selftests/powerpc/tm/.gitignore @@ -0,0 +1 @@ +tm-resched-dscr |