1 /* 2 * Copyright 2003-2005, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 * 5 * Copyright 2001, Travis Geiselbrecht. All rights reserved. 6 * Distributed under the terms of the NewOS License. 7 */ 8 9 10 #include <KernelExport.h> 11 12 #include <arch_platform.h> 13 #include <arch/cpu.h> 14 #include <arch/thread.h> 15 #include <boot/kernel_args.h> 16 17 static bool sHasTlbia; 18 19 status_t 20 arch_cpu_preboot_init_percpu(kernel_args *args, int curr_cpu) 21 { 22 // enable FPU 23 set_msr(get_msr() | MSR_FP_AVAILABLE); 24 25 // The current thread must be NULL for all CPUs till we have threads. 26 // Some boot code relies on this. 27 arch_thread_set_current_thread(NULL); 28 29 return B_OK; 30 } 31 32 33 status_t 34 arch_cpu_init(kernel_args *args) 35 { 36 // TODO: Let the boot loader put that info into the kernel args 37 // (property "tlbia" in the CPU node). 38 sHasTlbia = false; 39 40 return B_OK; 41 } 42 43 44 status_t 45 arch_cpu_init_post_vm(kernel_args *args) 46 { 47 return B_OK; 48 } 49 50 status_t 51 arch_cpu_init_percpu(kernel_args *args, int curr_cpu) 52 { 53 //detect_cpu(curr_cpu); 54 55 // we only support one on ppc anyway at the moment... 56 //XXX: WRITEME 57 return 0; 58 } 59 60 status_t 61 arch_cpu_init_post_modules(kernel_args *args) 62 { 63 return B_OK; 64 } 65 66 #define CACHELINE 32 67 68 void 69 arch_cpu_sync_icache(void *address, size_t len) 70 { 71 int l, off; 72 char *p; 73 74 off = (unsigned int)address & (CACHELINE - 1); 75 len += off; 76 77 l = len; 78 p = (char *)address - off; 79 do { 80 asm volatile ("dcbst 0,%0" :: "r"(p)); 81 p += CACHELINE; 82 } while ((l -= CACHELINE) > 0); 83 asm volatile ("sync"); 84 85 p = (char *)address - off; 86 do { 87 asm volatile ("icbi 0,%0" :: "r"(p)); 88 p += CACHELINE; 89 } while ((len -= CACHELINE) > 0); 90 asm volatile ("sync"); 91 isync(); 92 } 93 94 95 void 96 arch_cpu_memory_read_barrier(void) 97 { 98 // WARNING PPC: is it model-dependant ? 99 asm volatile ("lwsync"); 100 } 101 102 103 void 104 arch_cpu_memory_write_barrier(void) 105 { 106 // WARNING PPC: is it model-dependant ? 107 asm volatile ("isync"); 108 asm volatile ("eieio"); 109 } 110 111 112 void 113 arch_cpu_invalidate_TLB_range(addr_t start, addr_t end) 114 { 115 asm volatile("sync"); 116 while (start < end) { 117 asm volatile("tlbie %0" :: "r" (start)); 118 asm volatile("eieio"); 119 asm volatile("sync"); 120 start += B_PAGE_SIZE; 121 } 122 asm volatile("tlbsync"); 123 asm volatile("sync"); 124 } 125 126 127 void 128 arch_cpu_invalidate_TLB_list(addr_t pages[], int num_pages) 129 { 130 int i; 131 132 asm volatile("sync"); 133 for (i = 0; i < num_pages; i++) { 134 asm volatile("tlbie %0" :: "r" (pages[i])); 135 asm volatile("eieio"); 136 asm volatile("sync"); 137 } 138 asm volatile("tlbsync"); 139 asm volatile("sync"); 140 } 141 142 143 void 144 arch_cpu_global_TLB_invalidate(void) 145 { 146 if (sHasTlbia) { 147 ppc_sync(); 148 tlbia(); 149 ppc_sync(); 150 } else { 151 addr_t address = 0; 152 unsigned long i; 153 154 ppc_sync(); 155 for (i = 0; i < 0x100000; i++) { 156 tlbie(address); 157 eieio(); 158 ppc_sync(); 159 160 address += B_PAGE_SIZE; 161 } 162 tlbsync(); 163 ppc_sync(); 164 } 165 } 166 167 168 void 169 arch_cpu_user_TLB_invalidate(void) 170 { 171 arch_cpu_global_TLB_invalidate(); 172 } 173 174 175 // TODO: all functions that use fault handlers need to be implemented 176 // in assembly due to problems passing in label addresses in gcc4. 177 178 status_t 179 arch_cpu_user_memcpy(void *to, const void *from, size_t size, 180 addr_t *faultHandler) 181 { 182 char *tmp = (char *)to; 183 char *s = (char *)from; 184 addr_t oldFaultHandler = *faultHandler; 185 186 // TODO: This doesn't work correctly with gcc 4 anymore! 187 if (ppc_set_fault_handler(faultHandler, (addr_t)&&error)) 188 goto error; 189 190 while (size--) 191 *tmp++ = *s++; 192 193 *faultHandler = oldFaultHandler; 194 return 0; 195 196 error: 197 *faultHandler = oldFaultHandler; 198 return B_BAD_ADDRESS; 199 } 200 201 202 /** \brief Copies at most (\a size - 1) characters from the string in \a from to 203 * the string in \a to, NULL-terminating the result. 204 * 205 * \param to Pointer to the destination C-string. 206 * \param from Pointer to the source C-string. 207 * \param size Size in bytes of the string buffer pointed to by \a to. 208 * 209 * \return strlen(\a from). 210 */ 211 212 ssize_t 213 arch_cpu_user_strlcpy(char *to, const char *from, size_t size, addr_t *faultHandler) 214 { 215 int from_length = 0; 216 addr_t oldFaultHandler = *faultHandler; 217 218 // TODO: This doesn't work correctly with gcc 4 anymore! 219 if (ppc_set_fault_handler(faultHandler, (addr_t)&&error)) 220 goto error; 221 222 if (size > 0) { 223 to[--size] = '\0'; 224 // copy 225 for ( ; size; size--, from_length++, to++, from++) { 226 if ((*to = *from) == '\0') 227 break; 228 } 229 } 230 // count any leftover from chars 231 while (*from++ != '\0') 232 from_length++; 233 234 *faultHandler = oldFaultHandler; 235 return from_length; 236 237 error: 238 *faultHandler = oldFaultHandler; 239 return B_BAD_ADDRESS; 240 } 241 242 243 status_t 244 arch_cpu_user_memset(void *s, char c, size_t count, addr_t *faultHandler) 245 { 246 char *xs = (char *)s; 247 addr_t oldFaultHandler = *faultHandler; 248 249 // TODO: This doesn't work correctly with gcc 4 anymore! 250 if (ppc_set_fault_handler(faultHandler, (addr_t)&&error)) 251 goto error; 252 253 while (count--) 254 *xs++ = c; 255 256 *faultHandler = oldFaultHandler; 257 return 0; 258 259 error: 260 *faultHandler = oldFaultHandler; 261 return B_BAD_ADDRESS; 262 } 263 264 265 status_t 266 arch_cpu_shutdown(bool reboot) 267 { 268 PPCPlatform::Default()->ShutDown(reboot); 269 return B_ERROR; 270 } 271 272 273 // The purpose of this function is to trick the compiler. When setting the 274 // page_handler to a label that is obviously (to the compiler) never used, 275 // it may reorganize the control flow, so that the labeled part is optimized 276 // away. 277 // By invoking the function like this 278 // 279 // if (ppc_set_fault_handler(faultHandler, (addr_t)&&error)) 280 // goto error; 281 // 282 // the compiler has to keep the labeled code, since it can't guess the return 283 // value of this (non-inlinable) function. At least in my tests it worked that 284 // way, and I hope it will continue to work like this in the future. 285 // 286 bool 287 ppc_set_fault_handler(addr_t *handlerLocation, addr_t handler) 288 { 289 // TODO: This doesn't work correctly with gcc 4 anymore! 290 *handlerLocation = handler; 291 return false; 292 } 293