162306a36Sopenharmony_ci#include <stdlib.h> 262306a36Sopenharmony_ci#include <string.h> 362306a36Sopenharmony_ci#include <stdio.h> 462306a36Sopenharmony_ci#include <signal.h> 562306a36Sopenharmony_ci#include <unistd.h> 662306a36Sopenharmony_ci#include <sys/mman.h> 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "utils.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ciextern char __start___ex_table[]; 1162306a36Sopenharmony_ciextern char __stop___ex_table[]; 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#if defined(__powerpc64__) 1462306a36Sopenharmony_ci#define UCONTEXT_NIA(UC) (UC)->uc_mcontext.gp_regs[PT_NIP] 1562306a36Sopenharmony_ci#elif defined(__powerpc__) 1662306a36Sopenharmony_ci#define UCONTEXT_NIA(UC) (UC)->uc_mcontext.uc_regs->gregs[PT_NIP] 1762306a36Sopenharmony_ci#else 1862306a36Sopenharmony_ci#error implement UCONTEXT_NIA 1962306a36Sopenharmony_ci#endif 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic void segv_handler(int signr, siginfo_t *info, void *ptr) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci ucontext_t *uc = (ucontext_t *)ptr; 2462306a36Sopenharmony_ci unsigned long addr = (unsigned long)info->si_addr; 2562306a36Sopenharmony_ci unsigned long *ip = &UCONTEXT_NIA(uc); 2662306a36Sopenharmony_ci unsigned long *ex_p = (unsigned long *)__start___ex_table; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci while (ex_p < (unsigned long *)__stop___ex_table) { 2962306a36Sopenharmony_ci unsigned long insn, fixup; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci insn = *ex_p++; 3262306a36Sopenharmony_ci fixup = *ex_p++; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci if (insn == *ip) { 3562306a36Sopenharmony_ci *ip = fixup; 3662306a36Sopenharmony_ci return; 3762306a36Sopenharmony_ci } 3862306a36Sopenharmony_ci } 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci printf("No exception table match for NIA %lx ADDR %lx\n", *ip, addr); 4162306a36Sopenharmony_ci abort(); 4262306a36Sopenharmony_ci} 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic void setup_segv_handler(void) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci struct sigaction action; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci memset(&action, 0, sizeof(action)); 4962306a36Sopenharmony_ci action.sa_sigaction = segv_handler; 5062306a36Sopenharmony_ci action.sa_flags = SA_SIGINFO; 5162306a36Sopenharmony_ci sigaction(SIGSEGV, &action, NULL); 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ciunsigned long COPY_LOOP(void *to, const void *from, unsigned long size); 5562306a36Sopenharmony_ciunsigned long test_copy_tofrom_user_reference(void *to, const void *from, unsigned long size); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistatic int total_passed; 5862306a36Sopenharmony_cistatic int total_failed; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistatic void do_one_test(char *dstp, char *srcp, unsigned long len) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci unsigned long got, expected; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci got = COPY_LOOP(dstp, srcp, len); 6562306a36Sopenharmony_ci expected = test_copy_tofrom_user_reference(dstp, srcp, len); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci if (got != expected) { 6862306a36Sopenharmony_ci total_failed++; 6962306a36Sopenharmony_ci printf("FAIL from=%p to=%p len=%ld returned %ld, expected %ld\n", 7062306a36Sopenharmony_ci srcp, dstp, len, got, expected); 7162306a36Sopenharmony_ci //abort(); 7262306a36Sopenharmony_ci } else 7362306a36Sopenharmony_ci total_passed++; 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci//#define MAX_LEN 512 7762306a36Sopenharmony_ci#define MAX_LEN 16 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ciint test_copy_exception(void) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci int page_size; 8262306a36Sopenharmony_ci static char *p, *q; 8362306a36Sopenharmony_ci unsigned long src, dst, len; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci page_size = getpagesize(); 8662306a36Sopenharmony_ci p = mmap(NULL, page_size * 2, PROT_READ|PROT_WRITE, 8762306a36Sopenharmony_ci MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci if (p == MAP_FAILED) { 9062306a36Sopenharmony_ci perror("mmap"); 9162306a36Sopenharmony_ci exit(1); 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci memset(p, 0, page_size); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci setup_segv_handler(); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci if (mprotect(p + page_size, page_size, PROT_NONE)) { 9962306a36Sopenharmony_ci perror("mprotect"); 10062306a36Sopenharmony_ci exit(1); 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci q = p + page_size - MAX_LEN; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci for (src = 0; src < MAX_LEN; src++) { 10662306a36Sopenharmony_ci for (dst = 0; dst < MAX_LEN; dst++) { 10762306a36Sopenharmony_ci for (len = 0; len < MAX_LEN+1; len++) { 10862306a36Sopenharmony_ci // printf("from=%p to=%p len=%ld\n", q+dst, q+src, len); 10962306a36Sopenharmony_ci do_one_test(q+dst, q+src, len); 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci } 11262306a36Sopenharmony_ci } 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci printf("Totals:\n"); 11562306a36Sopenharmony_ci printf(" Pass: %d\n", total_passed); 11662306a36Sopenharmony_ci printf(" Fail: %d\n", total_failed); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci return 0; 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ciint main(void) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci return test_harness(test_copy_exception, str(COPY_LOOP)); 12462306a36Sopenharmony_ci} 125