cregit-Linux how code gets into the kernel

Release 4.10 tools/testing/selftests/powerpc/mm/subpage_prot.c

/*
 * 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; }

Contributors

PersonTokensPropCommitsCommitProp
paul mackerraspaul mackerras77100.00%1100.00%
Total77100.00%1100.00%


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"); }

Contributors

PersonTokensPropCommitsCommitProp
paul mackerraspaul mackerras19100.00%1100.00%
Total19100.00%1100.00%


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"); }

Contributors

PersonTokensPropCommitsCommitProp
paul mackerraspaul mackerras21100.00%1100.00%
Total21100.00%1100.00%


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"); } }

Contributors

PersonTokensPropCommitsCommitProp
paul mackerraspaul mackerras12198.37%150.00%
michael ellermanmichael ellerman21.63%150.00%
Total123100.00%2100.00%


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; }

Contributors

PersonTokensPropCommitsCommitProp
paul mackerraspaul mackerras234100.00%1100.00%
Total234100.00%1100.00%


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); }

Contributors

PersonTokensPropCommitsCommitProp
paul mackerraspaul mackerras14299.30%150.00%
michael ellermanmichael ellerman10.70%150.00%
Total143100.00%2100.00%


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); }

Contributors

PersonTokensPropCommitsCommitProp
paul mackerraspaul mackerras14999.33%150.00%
michael ellermanmichael ellerman10.67%150.00%
Total150100.00%2100.00%


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"); }

Contributors

PersonTokensPropCommitsCommitProp
paul mackerraspaul mackerras4577.59%150.00%
michael ellermanmichael ellerman1322.41%150.00%
Total58100.00%2100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
paul mackerraspaul mackerras87098.08%150.00%
michael ellermanmichael ellerman171.92%150.00%
Total887100.00%2100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.