/* * 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 %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 %p and happened at %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 %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 %p\n", file_name, filesize, fileblock); printf("testing file map...\n"); return run_test(fileblock, filesize); } int main(int argc, char *argv[]) { int rc; rc = test_harness(test_anon, "subpage_prot_anon"); if (rc) return rc; if (argc > 1) file_name = argv[1]; else file_name = "tempfile"; return test_harness(test_file, "subpage_prot_file"); } /option><option value='35'>35</option><option value='40'>40</option></select></td></tr><tr><td class='label'>space:</td><td class='ctrl'><select name='ignorews' onchange='this.form.submit();'><option value='0' selected='selected'>include</option><option value='1'>ignore</option></select></td></tr><tr><td class='label'>mode:</td><td class='ctrl'><select name='dt' onchange='this.form.submit();'><option value='0' selected='selected'>unified</option><option value='1'>ssdiff</option><option value='2'>stat only</option></select></td></tr><tr><td/><td class='ctrl'><noscript><input type='submit' value='reload'/></noscript></td></tr></table></form></div><table summary='commit info' class='commit-info'> <tr><th>author</th><td>Thomas Gleixner <tglx@linutronix.de></td><td class='right'>2017-01-31 19:03:21 +0100</td></tr> <tr><th>committer</th><td>Thomas Gleixner <tglx@linutronix.de></td><td class='right'>2017-01-31 20:22:18 +0100</td></tr> <tr><th>commit</th><td colspan='2' class='oid'><a href='/cgit.cgi/linux/net-next.git/commit/include/dt-bindings/clock/bcm-cygnus.h?h=nds-private-remove&id=aaaec6fc755447a1d056765b11b24d8ff2b81366'>aaaec6fc755447a1d056765b11b24d8ff2b81366</a> (<a href='/cgit.cgi/linux/net-next.git/patch/include/dt-bindings/clock/bcm-cygnus.h?id=aaaec6fc755447a1d056765b11b24d8ff2b81366'>patch</a>)</td></tr> <tr><th>tree</th><td colspan='2' class='oid'><a href='/cgit.cgi/linux/net-next.git/tree/?h=nds-private-remove&id=aaaec6fc755447a1d056765b11b24d8ff2b81366'>a7f4167960ee1df86739905b6ccdeb95465bfe5f</a> /<a href='/cgit.cgi/linux/net-next.git/tree/include/dt-bindings/clock/bcm-cygnus.h?h=nds-private-remove&id=aaaec6fc755447a1d056765b11b24d8ff2b81366'>include/dt-bindings/clock/bcm-cygnus.h</a></td></tr> <tr><th>parent</th><td colspan='2' class='oid'><a href='/cgit.cgi/linux/net-next.git/commit/include/dt-bindings/clock/bcm-cygnus.h?h=nds-private-remove&id=08d85f3ea99f1eeafc4e8507936190e86a16ee8c'>08d85f3ea99f1eeafc4e8507936190e86a16ee8c</a> (<a href='/cgit.cgi/linux/net-next.git/diff/include/dt-bindings/clock/bcm-cygnus.h?h=nds-private-remove&id=aaaec6fc755447a1d056765b11b24d8ff2b81366&id2=08d85f3ea99f1eeafc4e8507936190e86a16ee8c'>diff</a>)</td></tr></table> <div class='commit-subject'>x86/irq: Make irq activate operations symmetric</div><div class='commit-msg'>The recent commit which prevents double activation of interrupts unearthed interesting code in x86. The code (ab)uses irq_domain_activate_irq() to reconfigure an already activated interrupt. That trips over the prevention code now. Fix it by deactivating the interrupt before activating the new configuration. Fixes: 08d85f3ea99f1 "irqdomain: Avoid activating interrupts more than once" Reported-and-tested-by: Mike Galbraith <efault@gmx.de> Reported-and-tested-by: Borislav Petkov <bp@alien8.de> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: Andrey Ryabinin <aryabinin@virtuozzo.com> Cc: Marc Zyngier <marc.zyngier@arm.com> Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/alpine.DEB.2.20.1701311901580.3457@nanos </div><div class='diffstat-header'><a href='/cgit.cgi/linux/net-next.git/diff/?h=nds-private-remove&id=aaaec6fc755447a1d056765b11b24d8ff2b81366'>Diffstat</a> (limited to 'include/dt-bindings/clock/bcm-cygnus.h')</div><table summary='diffstat' class='diffstat'>