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