Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Userspace test harness for load_unaligned_zeropad. Creates two
0004  * pages and uses mprotect to prevent access to the second page and
0005  * a SEGV handler that walks the exception tables and runs the fixup
0006  * routine.
0007  *
0008  * The results are compared against a normal load that is that is
0009  * performed while access to the second page is enabled via mprotect.
0010  *
0011  * Copyright (C) 2014 Anton Blanchard <anton@au.ibm.com>, IBM
0012  */
0013 
0014 #include <stdlib.h>
0015 #include <string.h>
0016 #include <stdio.h>
0017 #include <stdbool.h>
0018 #include <signal.h>
0019 #include <unistd.h>
0020 #include <sys/mman.h>
0021 
0022 #define FIXUP_SECTION ".ex_fixup"
0023 
0024 static inline unsigned long __fls(unsigned long x);
0025 
0026 #include "word-at-a-time.h"
0027 
0028 #include "utils.h"
0029 
0030 static inline unsigned long __fls(unsigned long x)
0031 {
0032     int lz;
0033 
0034     asm (PPC_CNTLZL "%0,%1" : "=r" (lz) : "r" (x));
0035     return sizeof(unsigned long) - 1 - lz;
0036 }
0037 
0038 static int page_size;
0039 static char *mem_region;
0040 
0041 static int protect_region(void)
0042 {
0043     if (mprotect(mem_region + page_size, page_size, PROT_NONE)) {
0044         perror("mprotect");
0045         return 1;
0046     }
0047 
0048     return 0;
0049 }
0050 
0051 static int unprotect_region(void)
0052 {
0053     if (mprotect(mem_region + page_size, page_size, PROT_READ|PROT_WRITE)) {
0054         perror("mprotect");
0055         return 1;
0056     }
0057 
0058     return 0;
0059 }
0060 
0061 extern char __start___ex_table[];
0062 extern char __stop___ex_table[];
0063 
0064 struct extbl_entry {
0065     int insn;
0066     int fixup;
0067 };
0068 
0069 static void segv_handler(int signr, siginfo_t *info, void *ptr)
0070 {
0071     ucontext_t *uc = (ucontext_t *)ptr;
0072     unsigned long addr = (unsigned long)info->si_addr;
0073     unsigned long *ip = &UCONTEXT_NIA(uc);
0074     struct extbl_entry *entry = (struct extbl_entry *)__start___ex_table;
0075 
0076     while (entry < (struct extbl_entry *)__stop___ex_table) {
0077         unsigned long insn, fixup;
0078 
0079         insn  = (unsigned long)&entry->insn + entry->insn;
0080         fixup = (unsigned long)&entry->fixup + entry->fixup;
0081 
0082         if (insn == *ip) {
0083             *ip = fixup;
0084             return;
0085         }
0086     }
0087 
0088     printf("No exception table match for NIA %lx ADDR %lx\n", *ip, addr);
0089     abort();
0090 }
0091 
0092 static void setup_segv_handler(void)
0093 {
0094     struct sigaction action;
0095 
0096     memset(&action, 0, sizeof(action));
0097     action.sa_sigaction = segv_handler;
0098     action.sa_flags = SA_SIGINFO;
0099     sigaction(SIGSEGV, &action, NULL);
0100 }
0101 
0102 static int do_one_test(char *p, int page_offset)
0103 {
0104     unsigned long should;
0105     unsigned long got;
0106 
0107     FAIL_IF(unprotect_region());
0108     should = *(unsigned long *)p;
0109     FAIL_IF(protect_region());
0110 
0111     got = load_unaligned_zeropad(p);
0112 
0113     if (should != got) {
0114         printf("offset %u load_unaligned_zeropad returned 0x%lx, should be 0x%lx\n", page_offset, got, should);
0115         return 1;
0116     }
0117 
0118     return 0;
0119 }
0120 
0121 static int test_body(void)
0122 {
0123     unsigned long i;
0124 
0125     page_size = getpagesize();
0126     mem_region = mmap(NULL, page_size * 2, PROT_READ|PROT_WRITE,
0127         MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
0128 
0129     FAIL_IF(mem_region == MAP_FAILED);
0130 
0131     for (i = 0; i < page_size; i++)
0132         mem_region[i] = i;
0133 
0134     memset(mem_region+page_size, 0, page_size);
0135 
0136     setup_segv_handler();
0137 
0138     for (i = 0; i < page_size; i++)
0139         FAIL_IF(do_one_test(mem_region+i, i));
0140 
0141     return 0;
0142 }
0143 
0144 int main(void)
0145 {
0146     return test_harness(test_body, "load_unaligned_zeropad");
0147 }