18c2ecf20Sopenharmony_ci#include <stdlib.h> 28c2ecf20Sopenharmony_ci#include <string.h> 38c2ecf20Sopenharmony_ci#include <stdio.h> 48c2ecf20Sopenharmony_ci#include <signal.h> 58c2ecf20Sopenharmony_ci#include <unistd.h> 68c2ecf20Sopenharmony_ci#include <sys/mman.h> 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include "utils.h" 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ciextern char __start___ex_table[]; 118c2ecf20Sopenharmony_ciextern char __stop___ex_table[]; 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#if defined(__powerpc64__) 148c2ecf20Sopenharmony_ci#define UCONTEXT_NIA(UC) (UC)->uc_mcontext.gp_regs[PT_NIP] 158c2ecf20Sopenharmony_ci#elif defined(__powerpc__) 168c2ecf20Sopenharmony_ci#define UCONTEXT_NIA(UC) (UC)->uc_mcontext.uc_regs->gregs[PT_NIP] 178c2ecf20Sopenharmony_ci#else 188c2ecf20Sopenharmony_ci#error implement UCONTEXT_NIA 198c2ecf20Sopenharmony_ci#endif 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic void segv_handler(int signr, siginfo_t *info, void *ptr) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci ucontext_t *uc = (ucontext_t *)ptr; 248c2ecf20Sopenharmony_ci unsigned long addr = (unsigned long)info->si_addr; 258c2ecf20Sopenharmony_ci unsigned long *ip = &UCONTEXT_NIA(uc); 268c2ecf20Sopenharmony_ci unsigned long *ex_p = (unsigned long *)__start___ex_table; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci while (ex_p < (unsigned long *)__stop___ex_table) { 298c2ecf20Sopenharmony_ci unsigned long insn, fixup; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci insn = *ex_p++; 328c2ecf20Sopenharmony_ci fixup = *ex_p++; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci if (insn == *ip) { 358c2ecf20Sopenharmony_ci *ip = fixup; 368c2ecf20Sopenharmony_ci return; 378c2ecf20Sopenharmony_ci } 388c2ecf20Sopenharmony_ci } 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci printf("No exception table match for NIA %lx ADDR %lx\n", *ip, addr); 418c2ecf20Sopenharmony_ci abort(); 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic void setup_segv_handler(void) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci struct sigaction action; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci memset(&action, 0, sizeof(action)); 498c2ecf20Sopenharmony_ci action.sa_sigaction = segv_handler; 508c2ecf20Sopenharmony_ci action.sa_flags = SA_SIGINFO; 518c2ecf20Sopenharmony_ci sigaction(SIGSEGV, &action, NULL); 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ciunsigned long COPY_LOOP(void *to, const void *from, unsigned long size); 558c2ecf20Sopenharmony_ciunsigned long test_copy_tofrom_user_reference(void *to, const void *from, unsigned long size); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic int total_passed; 588c2ecf20Sopenharmony_cistatic int total_failed; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic void do_one_test(char *dstp, char *srcp, unsigned long len) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci unsigned long got, expected; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci got = COPY_LOOP(dstp, srcp, len); 658c2ecf20Sopenharmony_ci expected = test_copy_tofrom_user_reference(dstp, srcp, len); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci if (got != expected) { 688c2ecf20Sopenharmony_ci total_failed++; 698c2ecf20Sopenharmony_ci printf("FAIL from=%p to=%p len=%ld returned %ld, expected %ld\n", 708c2ecf20Sopenharmony_ci srcp, dstp, len, got, expected); 718c2ecf20Sopenharmony_ci //abort(); 728c2ecf20Sopenharmony_ci } else 738c2ecf20Sopenharmony_ci total_passed++; 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci//#define MAX_LEN 512 778c2ecf20Sopenharmony_ci#define MAX_LEN 16 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ciint test_copy_exception(void) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci int page_size; 828c2ecf20Sopenharmony_ci static char *p, *q; 838c2ecf20Sopenharmony_ci unsigned long src, dst, len; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci page_size = getpagesize(); 868c2ecf20Sopenharmony_ci p = mmap(NULL, page_size * 2, PROT_READ|PROT_WRITE, 878c2ecf20Sopenharmony_ci MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci if (p == MAP_FAILED) { 908c2ecf20Sopenharmony_ci perror("mmap"); 918c2ecf20Sopenharmony_ci exit(1); 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci memset(p, 0, page_size); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci setup_segv_handler(); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci if (mprotect(p + page_size, page_size, PROT_NONE)) { 998c2ecf20Sopenharmony_ci perror("mprotect"); 1008c2ecf20Sopenharmony_ci exit(1); 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci q = p + page_size - MAX_LEN; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci for (src = 0; src < MAX_LEN; src++) { 1068c2ecf20Sopenharmony_ci for (dst = 0; dst < MAX_LEN; dst++) { 1078c2ecf20Sopenharmony_ci for (len = 0; len < MAX_LEN+1; len++) { 1088c2ecf20Sopenharmony_ci // printf("from=%p to=%p len=%ld\n", q+dst, q+src, len); 1098c2ecf20Sopenharmony_ci do_one_test(q+dst, q+src, len); 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci printf("Totals:\n"); 1158c2ecf20Sopenharmony_ci printf(" Pass: %d\n", total_passed); 1168c2ecf20Sopenharmony_ci printf(" Fail: %d\n", total_failed); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci return 0; 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ciint main(void) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci return test_harness(test_copy_exception, str(COPY_LOOP)); 1248c2ecf20Sopenharmony_ci} 125