1 /* 2 * Copyright 2007, François Revol, revol@free.fr. 3 * Distributed under the terms of the MIT License. 4 * 5 * Copyright 2003-2005, Axel Dörfler, axeld@pinc-software.de. 6 * Distributed under the terms of the MIT License. 7 * 8 * Copyright 2001, Travis Geiselbrecht. All rights reserved. 9 * Distributed under the terms of the NewOS License. 10 */ 11 12 13 #include <KernelExport.h> 14 15 #include <arch_platform.h> 16 #include <arch_thread.h> 17 #include <arch/cpu.h> 18 #include <boot/kernel_args.h> 19 20 extern struct m68k_cpu_ops cpu_ops_030; 21 extern struct m68k_cpu_ops cpu_ops_040; 22 extern struct m68k_cpu_ops cpu_ops_060; 23 24 struct m68k_cpu_ops cpu_ops; 25 26 int arch_cpu_type; 27 int arch_fpu_type; 28 int arch_mmu_type; 29 int arch_platform; 30 31 status_t 32 arch_cpu_preboot_init_percpu(kernel_args *args, int curr_cpu) 33 { 34 // enable FPU 35 //ppc:set_msr(get_msr() | MSR_FP_AVAILABLE); 36 37 // The current thread must be NULL for all CPUs till we have threads. 38 // Some boot code relies on this. 39 arch_thread_set_current_thread(NULL); 40 41 return B_OK; 42 } 43 44 45 status_t 46 arch_cpu_init_percpu(kernel_args *args, int curr_cpu) 47 { 48 //detect_cpu(curr_cpu); 49 50 // we only support one anyway... 51 return 0; 52 } 53 54 55 status_t 56 arch_cpu_init(kernel_args *args) 57 { 58 arch_cpu_type = args->arch_args.cpu_type; 59 arch_fpu_type = args->arch_args.fpu_type; 60 arch_mmu_type = args->arch_args.mmu_type; 61 arch_platform = args->arch_args.platform; 62 arch_platform = args->arch_args.machine; 63 void (*flush_insn_pipeline)(void); 64 void (*flush_atc_all)(void); 65 void (*flush_atc_user)(void); 66 void (*flush_atc_addr)(void *addr); 67 void (*flush_dcache)(void *address, size_t len); 68 void (*flush_icache)(void *address, size_t len); 69 void (*idle)(void); 70 71 switch (arch_cpu_type) { 72 case 68020: 73 case 68030: 74 cpu_ops.flush_insn_pipeline = cpu_ops_030.flush_insn_pipeline; 75 cpu_ops.flush_atc_all = cpu_ops_030.flush_atc_all; 76 cpu_ops.flush_atc_user = cpu_ops_030.flush_atc_user; 77 cpu_ops.flush_atc_addr = cpu_ops_030.flush_atc_addr; 78 cpu_ops.flush_dcache = cpu_ops_030.flush_dcache; 79 cpu_ops.flush_icache = cpu_ops_030.flush_icache; 80 cpu_ops.idle = cpu_ops_030.idle; // NULL 81 break; 82 #ifdef SUPPORTS_040 83 case 68040: 84 cpu_ops.flush_insn_pipeline = cpu_ops_040.flush_insn_pipeline; 85 cpu_ops.flush_atc_all = cpu_ops_040.flush_atc_all; 86 cpu_ops.flush_atc_user = cpu_ops_040.flush_atc_user; 87 cpu_ops.flush_atc_addr = cpu_ops_040.flush_atc_addr; 88 cpu_ops.flush_dcache = cpu_ops_040.flush_dcache; 89 cpu_ops.flush_icache = cpu_ops_040.flush_icache; 90 cpu_ops.idle = cpu_ops_040.idle; // NULL 91 break; 92 #endif 93 #ifdef SUPPORTS_060 94 case 68060: 95 cpu_ops.flush_insn_pipeline = cpu_ops_060.flush_insn_pipeline; 96 cpu_ops.flush_atc_all = cpu_ops_060.flush_atc_all; 97 cpu_ops.flush_atc_user = cpu_ops_060.flush_atc_user; 98 cpu_ops.flush_atc_addr = cpu_ops_060.flush_atc_addr; 99 cpu_ops.flush_dcache = cpu_ops_060.flush_dcache; 100 cpu_ops.flush_icache = cpu_ops_060.flush_icache; 101 cpu_ops.idle = cpu_ops_060.idle; 102 break; 103 #endif 104 default: 105 panic("unknown cpu_type %d\n", arch_cpu_type); 106 } 107 108 return B_OK; 109 } 110 111 112 status_t 113 arch_cpu_init_post_vm(kernel_args *args) 114 { 115 return B_OK; 116 } 117 118 status_t 119 arch_cpu_init_post_modules(kernel_args *args) 120 { 121 return B_OK; 122 } 123 124 125 void 126 arch_cpu_sync_icache(void *address, size_t len) 127 { 128 cpu_ops.flush_icache((addr_t)address, len); 129 } 130 131 132 void 133 arch_cpu_memory_read_barrier(void) 134 { 135 asm volatile ("nop;" : : : "memory"); 136 #warning M68k: check arch_cpu_memory_read_barrier 137 } 138 139 140 void 141 arch_cpu_memory_write_barrier(void) 142 { 143 asm volatile ("nop;" : : : "memory"); 144 #warning M68k: check arch_cpu_memory_write_barrier 145 } 146 147 148 void 149 arch_cpu_invalidate_TLB_range(addr_t start, addr_t end) 150 { 151 int32 num_pages = end / B_PAGE_SIZE - start / B_PAGE_SIZE; 152 cpu_ops.flush_insn_pipeline(); 153 while (num_pages-- >= 0) { 154 cpu_ops.flush_atc_addr(start); 155 cpu_ops.flush_insn_pipeline(); 156 start += B_PAGE_SIZE; 157 } 158 cpu_ops.flush_insn_pipeline(); 159 } 160 161 162 void 163 arch_cpu_invalidate_TLB_list(addr_t pages[], int num_pages) 164 { 165 int i; 166 167 cpu_ops.flush_insn_pipeline(); 168 for (i = 0; i < num_pages; i++) { 169 cpu_ops.flush_atc_addr(pages[i]); 170 cpu_ops.flush_insn_pipeline(); 171 } 172 cpu_ops.flush_insn_pipeline(); 173 } 174 175 176 void 177 arch_cpu_global_TLB_invalidate(void) 178 { 179 cpu_ops.flush_insn_pipeline(); 180 cpu_ops.flush_atc_all(); 181 cpu_ops.flush_insn_pipeline(); 182 } 183 184 185 void 186 arch_cpu_user_TLB_invalidate(void) 187 { 188 cpu_ops.flush_insn_pipeline(); 189 cpu_ops.flush_atc_user(); 190 cpu_ops.flush_insn_pipeline(); 191 } 192 193 194 status_t 195 arch_cpu_user_memcpy(void *to, const void *from, size_t size, 196 addr_t *faultHandler) 197 { 198 char *tmp = (char *)to; 199 char *s = (char *)from; 200 addr_t oldFaultHandler = *faultHandler; 201 202 if (m68k_set_fault_handler(faultHandler, (addr_t)&&error)) 203 goto error; 204 205 while (size--) 206 *tmp++ = *s++; 207 208 *faultHandler = oldFaultHandler; 209 return 0; 210 211 error: 212 *faultHandler = oldFaultHandler; 213 return B_BAD_ADDRESS; 214 } 215 216 217 /** \brief Copies at most (\a size - 1) characters from the string in \a from to 218 * the string in \a to, NULL-terminating the result. 219 * 220 * \param to Pointer to the destination C-string. 221 * \param from Pointer to the source C-string. 222 * \param size Size in bytes of the string buffer pointed to by \a to. 223 * 224 * \return strlen(\a from). 225 */ 226 227 ssize_t 228 arch_cpu_user_strlcpy(char *to, const char *from, size_t size, addr_t *faultHandler) 229 { 230 int from_length = 0; 231 addr_t oldFaultHandler = *faultHandler; 232 233 if (m68k_set_fault_handler(faultHandler, (addr_t)&&error)) 234 goto error; 235 236 if (size > 0) { 237 to[--size] = '\0'; 238 // copy 239 for ( ; size; size--, from_length++, to++, from++) { 240 if ((*to = *from) == '\0') 241 break; 242 } 243 } 244 // count any leftover from chars 245 while (*from++ != '\0') 246 from_length++; 247 248 *faultHandler = oldFaultHandler; 249 return from_length; 250 251 error: 252 *faultHandler = oldFaultHandler; 253 return B_BAD_ADDRESS; 254 } 255 256 257 status_t 258 arch_cpu_user_memset(void *s, char c, size_t count, addr_t *faultHandler) 259 { 260 char *xs = (char *)s; 261 addr_t oldFaultHandler = *faultHandler; 262 263 if (m68k_set_fault_handler(faultHandler, (addr_t)&&error)) 264 goto error; 265 266 while (count--) 267 *xs++ = c; 268 269 *faultHandler = oldFaultHandler; 270 return 0; 271 272 error: 273 *faultHandler = oldFaultHandler; 274 return B_BAD_ADDRESS; 275 } 276 277 278 status_t 279 arch_cpu_shutdown(bool reboot) 280 { 281 M68KPlatform::Default()->ShutDown(reboot); 282 return B_ERROR; 283 } 284 285 286 void 287 arch_cpu_idle(void) 288 { 289 if (cpu_ops.idle) 290 cpu_ops.idle(); 291 #warning M68K: use LPSTOP ? 292 //asm volatile ("lpstop"); 293 } 294 295 296 // The purpose of this function is to trick the compiler. When setting the 297 // page_handler to a label that is obviously (to the compiler) never used, 298 // it may reorganize the control flow, so that the labeled part is optimized 299 // away. 300 // By invoking the function like this 301 // 302 // if (m68k_set_fault_handler(faultHandler, (addr_t)&&error)) 303 // goto error; 304 // 305 // the compiler has to keep the labeled code, since it can't guess the return 306 // value of this (non-inlinable) function. At least in my tests it worked that 307 // way, and I hope it will continue to work like this in the future. 308 // 309 bool 310 m68k_set_fault_handler(addr_t *handlerLocation, addr_t handler) 311 { 312 *handlerLocation = handler; 313 return false; 314 } 315