0001
0002
0003
0004
0005
0006
0007 #include <setjmp.h>
0008 #include <stdbool.h>
0009 #include <stdio.h>
0010 #include <stdlib.h>
0011 #include <string.h>
0012 #include <sys/types.h>
0013 #include <sys/wait.h>
0014 #include <unistd.h>
0015
0016 #include "utils.h"
0017
0018
0019 #ifndef SEGV_BNDERR
0020 #define SEGV_BNDERR 3
0021 #endif
0022
0023
0024 #define PAGE_OFFSET (0xcul << 60)
0025
0026 static unsigned long kernel_virt_end;
0027
0028 static volatile int fault_code;
0029 static volatile unsigned long fault_addr;
0030 static jmp_buf setjmp_env;
0031
0032 static void segv_handler(int n, siginfo_t *info, void *ctxt_v)
0033 {
0034 fault_code = info->si_code;
0035 fault_addr = (unsigned long)info->si_addr;
0036 siglongjmp(setjmp_env, 1);
0037 }
0038
0039 int bad_access(char *p, bool write)
0040 {
0041 char x = 0;
0042
0043 fault_code = 0;
0044 fault_addr = 0;
0045
0046 if (sigsetjmp(setjmp_env, 1) == 0) {
0047 if (write)
0048 *p = 1;
0049 else
0050 x = *p;
0051
0052 printf("Bad - no SEGV! (%c)\n", x);
0053 return 1;
0054 }
0055
0056
0057
0058
0059 FAIL_IF(fault_code == SEGV_MAPERR && \
0060 (fault_addr < PAGE_OFFSET || fault_addr >= kernel_virt_end));
0061
0062 FAIL_IF(fault_code != SEGV_MAPERR && fault_code != SEGV_BNDERR);
0063
0064 return 0;
0065 }
0066
0067 static int test(void)
0068 {
0069 unsigned long i, j, addr, region_shift, page_shift, page_size;
0070 struct sigaction sig;
0071 bool hash_mmu;
0072
0073 sig = (struct sigaction) {
0074 .sa_sigaction = segv_handler,
0075 .sa_flags = SA_SIGINFO,
0076 };
0077
0078 FAIL_IF(sigaction(SIGSEGV, &sig, NULL) != 0);
0079
0080 FAIL_IF(using_hash_mmu(&hash_mmu));
0081
0082 page_size = sysconf(_SC_PAGESIZE);
0083 if (page_size == (64 * 1024))
0084 page_shift = 16;
0085 else
0086 page_shift = 12;
0087
0088 if (page_size == (64 * 1024) || !hash_mmu) {
0089 region_shift = 52;
0090
0091
0092 kernel_virt_end = PAGE_OFFSET + (7 * (512ul << 40));
0093 } else if (page_size == (4 * 1024) && hash_mmu) {
0094 region_shift = 46;
0095
0096
0097 kernel_virt_end = PAGE_OFFSET + (7 * (64ul << 40));
0098 } else
0099 FAIL_IF(true);
0100
0101 printf("Using %s MMU, PAGE_SIZE = %dKB start address 0x%016lx\n",
0102 hash_mmu ? "hash" : "radix",
0103 (1 << page_shift) >> 10,
0104 1ul << region_shift);
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120 for (i = 1; i <= ((0xful << 60) >> region_shift); i++) {
0121 for (j = page_shift - 1; j < 60; j++) {
0122 unsigned long base, delta;
0123
0124 base = i << region_shift;
0125 delta = 1ul << j;
0126
0127 if (delta >= base)
0128 break;
0129
0130 addr = (base | delta) & ~((1 << page_shift) - 1);
0131
0132 FAIL_IF(bad_access((char *)addr, false));
0133 FAIL_IF(bad_access((char *)addr, true));
0134 }
0135 }
0136
0137 return 0;
0138 }
0139
0140 int main(void)
0141 {
0142 test_harness_set_timeout(300);
0143 return test_harness(test, "bad_accesses");
0144 }