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/time.h> 11 #include <asm/ptrace.h> 12 #include <asm/setup.h> 13 #include <asm/barrier.h> 14 #include <asm/hcall.h> 15 #include <asm/handlers.h> 16 #include <asm/mmu.h> 17 #include <asm/smp.h> 18 19 static struct { 20 void (*func)(struct pt_regs *, void *data); 21 void *data; 22 } handlers[128]; 23 24 /* 25 * Exception handlers span from 0x100 to 0x1000 and can have a granularity 26 * of 0x20 bytes in some cases. Indexing spans 0-0x1000 with 0x20 increments 27 * resulting in 128 slots. 28 */ 29 void handle_exception(int trap, void (*func)(struct pt_regs *, void *), 30 void * data) 31 { 32 assert(!(trap & ~0xfe0)); 33 34 trap >>= 5; 35 36 if (func && handlers[trap].func) { 37 printf("exception handler installed twice %#x\n", trap << 5); 38 abort(); 39 } 40 41 handlers[trap].func = func; 42 handlers[trap].data = data; 43 } 44 45 void do_handle_exception(struct pt_regs *regs) 46 { 47 unsigned char v; 48 49 __current_cpu = (struct cpu *)mfspr(SPR_SPRG0); 50 if (in_usermode()) 51 current_cpu()->in_user = false; 52 53 /* 54 * We run with AIL=0, so interrupts taken with MMU disabled. 55 * Enable here. 56 */ 57 assert(!(mfmsr() & (MSR_IR|MSR_DR))); 58 if (mmu_enabled()) 59 mtmsr(mfmsr() | (MSR_IR|MSR_DR)); 60 61 v = regs->trap >> 5; 62 63 if (v < 128 && handlers[v].func) { 64 handlers[v].func(regs, handlers[v].data); 65 if (regs->msr & MSR_PR) 66 current_cpu()->in_user = true; 67 return; 68 } 69 70 printf("Unhandled CPU%d exception %#lx at NIA:0x%016lx MSR:0x%016lx\n", 71 smp_processor_id(), regs->trap, regs->nip, regs->msr); 72 dump_frame_stack((void *)regs->nip, (void *)regs->gpr[1]); 73 abort(); 74 } 75 76 uint64_t get_clock_us(void) 77 { 78 return get_tb() * 1000000 / tb_hz; 79 } 80 81 uint64_t get_clock_ms(void) 82 { 83 return get_tb() * 1000 / tb_hz; 84 } 85 86 void delay(uint64_t cycles) 87 { 88 uint64_t start = get_tb(); 89 90 while ((get_tb() - start) < cycles) 91 cpu_relax(); 92 } 93 94 void udelay(uint64_t us) 95 { 96 delay((us * tb_hz) / 1000000); 97 } 98 99 void sleep_tb(uint64_t cycles) 100 { 101 uint64_t start, end, now; 102 103 if (!machine_is_pseries()) { 104 /* 105 * P9/10 Could use 'stop' to sleep here which would be 106 * interesting. stop with ESL=0 should be simple enough, ESL=1 107 * would require SRESET based wakeup which is more involved. 108 */ 109 delay(cycles); 110 return; 111 } 112 113 start = now = get_tb(); 114 end = start + cycles; 115 116 while (end > now) { 117 uint64_t left = end - now; 118 119 /* TODO: Could support large decrementer */ 120 if (left > 0x7fffffff) 121 left = 0x7fffffff; 122 123 /* DEC won't fire until H_CEDE is called because EE=0 */ 124 asm volatile ("mtdec %0" : : "r" (left)); 125 handle_exception(0x900, &dec_handler_oneshot, NULL); 126 /* 127 * H_CEDE is called with MSR[EE] clear and enables it as part 128 * of the hcall, returning with EE enabled. The dec interrupt 129 * is then taken immediately and the handler disables EE. 130 * 131 * If H_CEDE returned for any other interrupt than dec 132 * expiring, that is considered an unhandled interrupt and 133 * the test case would be stopped. 134 */ 135 if (hcall(H_CEDE) != H_SUCCESS) { 136 printf("H_CEDE failed\n"); 137 abort(); 138 } 139 handle_exception(0x900, NULL, NULL); 140 141 now = get_tb(); 142 } 143 } 144 145 void usleep(uint64_t us) 146 { 147 sleep_tb((us * tb_hz) / 1000000); 148 } 149 150 static void rfid_msr(uint64_t msr) 151 { 152 uint64_t tmp; 153 154 asm volatile( 155 "mtsrr1 %1 \n\ 156 bl 0f \n\ 157 0: \n\ 158 mflr %0 \n\ 159 addi %0,%0,1f-0b \n\ 160 mtsrr0 %0 \n\ 161 rfid \n\ 162 1: \n" 163 : "=r"(tmp) : "r"(msr) : "lr"); 164 } 165 166 void enable_mcheck(void) 167 { 168 /* This is a no-op on pseries */ 169 rfid_msr(mfmsr() | MSR_ME); 170 } 171 172 void disable_mcheck(void) 173 { 174 rfid_msr(mfmsr() & ~MSR_ME); 175 } 176 177 bool in_usermode(void) 178 { 179 return current_cpu()->in_user; 180 } 181 182 static void usermode_sc_handler(struct pt_regs *regs, void *data) 183 { 184 regs->msr &= ~(MSR_PR|MSR_EE); 185 /* Interrupt return handler will keep in_user clear */ 186 } 187 188 void enter_usermode(void) 189 { 190 assert_msg(!in_usermode(), "enter_usermode called with in_usermode"); 191 /* mfmsr would fault in usermode anyway */ 192 assert_msg(!(mfmsr() & MSR_PR), "enter_usermode called from user mode"); 193 assert_msg(!(mfmsr() & MSR_EE), "enter_usermode called with interrupts enabled"); 194 assert_msg((mfmsr() & (MSR_IR|MSR_DR)) == (MSR_IR|MSR_DR), 195 "enter_usermode called with virtual memory disabled"); 196 197 handle_exception(0xc00, usermode_sc_handler, NULL); 198 rfid_msr(mfmsr() | (MSR_PR|MSR_IR|MSR_DR|MSR_EE)); 199 current_cpu()->in_user = true; 200 } 201 202 void exit_usermode(void) 203 { 204 assert_msg(in_usermode(), "enter_usermode called with !in_usermode"); 205 asm volatile("sc 0" ::: "memory"); 206 handle_exception(0xc00, NULL, NULL); 207 assert(!in_usermode()); 208 assert(!(mfmsr() & MSR_PR)); 209 } 210