1 /* 2 * processor control and status function 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU Library General Public License version 2. 6 */ 7 8 #include <libcflat.h> 9 #include <asm/processor.h> 10 #include <asm/ptrace.h> 11 #include <asm/setup.h> 12 #include <asm/barrier.h> 13 #include <asm/hcall.h> 14 #include <asm/handlers.h> 15 16 static struct { 17 void (*func)(struct pt_regs *, void *data); 18 void *data; 19 } handlers[128]; 20 21 /* 22 * Exception handlers span from 0x100 to 0x1000 and can have a granularity 23 * of 0x20 bytes in some cases. Indexing spans 0-0x1000 with 0x20 increments 24 * resulting in 128 slots. 25 */ 26 void handle_exception(int trap, void (*func)(struct pt_regs *, void *), 27 void * data) 28 { 29 assert(!(trap & ~0xfe0)); 30 31 trap >>= 5; 32 33 if (func && handlers[trap].func) { 34 printf("exception handler installed twice %#x\n", trap << 5); 35 abort(); 36 } 37 38 handlers[trap].func = func; 39 handlers[trap].data = data; 40 } 41 42 void do_handle_exception(struct pt_regs *regs) 43 { 44 unsigned char v; 45 46 v = regs->trap >> 5; 47 48 if (v < 128 && handlers[v].func) { 49 handlers[v].func(regs, handlers[v].data); 50 return; 51 } 52 53 printf("unhandled cpu exception %#lx at NIA:0x%016lx MSR:0x%016lx\n", regs->trap, regs->nip, regs->msr); 54 abort(); 55 } 56 57 void delay(uint64_t cycles) 58 { 59 uint64_t start = get_tb(); 60 61 while ((get_tb() - start) < cycles) 62 cpu_relax(); 63 } 64 65 void udelay(uint64_t us) 66 { 67 delay((us * tb_hz) / 1000000); 68 } 69 70 void sleep_tb(uint64_t cycles) 71 { 72 uint64_t start, end, now; 73 74 start = now = get_tb(); 75 end = start + cycles; 76 77 while (end > now) { 78 uint64_t left = end - now; 79 80 /* TODO: Could support large decrementer */ 81 if (left > 0x7fffffff) 82 left = 0x7fffffff; 83 84 /* DEC won't fire until H_CEDE is called because EE=0 */ 85 asm volatile ("mtdec %0" : : "r" (left)); 86 handle_exception(0x900, &dec_handler_oneshot, NULL); 87 /* 88 * H_CEDE is called with MSR[EE] clear and enables it as part 89 * of the hcall, returning with EE enabled. The dec interrupt 90 * is then taken immediately and the handler disables EE. 91 * 92 * If H_CEDE returned for any other interrupt than dec 93 * expiring, that is considered an unhandled interrupt and 94 * the test case would be stopped. 95 */ 96 if (hcall(H_CEDE) != H_SUCCESS) { 97 printf("H_CEDE failed\n"); 98 abort(); 99 } 100 handle_exception(0x900, NULL, NULL); 101 102 now = get_tb(); 103 } 104 } 105 106 void usleep(uint64_t us) 107 { 108 sleep_tb((us * tb_hz) / 1000000); 109 } 110