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 64 switch (arch_cpu_type) { 65 case 68020: 66 case 68030: 67 memcpy(&cpu_ops, &cpu_ops_030, sizeof(cpu_ops)); 68 break; 69 70 case 68040: 71 memcpy(&cpu_ops, &cpu_ops_040, sizeof(cpu_ops)); 72 break; 73 74 #ifdef SUPPORTS_060 75 case 68060: 76 memcpy(&cpu_ops, &cpu_ops_060, sizeof(cpu_ops)); 77 break; 78 #endif 79 default: 80 panic("unknown cpu_type %d\n", arch_cpu_type); 81 } 82 83 return B_OK; 84 } 85 86 87 status_t 88 arch_cpu_init_post_vm(kernel_args *args) 89 { 90 return B_OK; 91 } 92 93 status_t 94 arch_cpu_init_post_modules(kernel_args *args) 95 { 96 return B_OK; 97 } 98 99 100 void 101 arch_cpu_sync_icache(void *address, size_t len) 102 { 103 cpu_ops.flush_icache((addr_t)address, len); 104 } 105 106 107 void 108 arch_cpu_memory_read_barrier(void) 109 { 110 asm volatile ("nop;" : : : "memory"); 111 #warning M68k: check arch_cpu_memory_read_barrier (FNOP ?) 112 } 113 114 115 void 116 arch_cpu_memory_write_barrier(void) 117 { 118 asm volatile ("nop;" : : : "memory"); 119 #warning M68k: check arch_cpu_memory_write_barrier (FNOP ?) 120 } 121 122 123 void 124 arch_cpu_invalidate_TLB_range(addr_t start, addr_t end) 125 { 126 int32 num_pages = end / B_PAGE_SIZE - start / B_PAGE_SIZE; 127 cpu_ops.flush_insn_pipeline(); 128 while (num_pages-- >= 0) { 129 cpu_ops.flush_atc_addr(start); 130 cpu_ops.flush_insn_pipeline(); 131 start += B_PAGE_SIZE; 132 } 133 cpu_ops.flush_insn_pipeline(); 134 } 135 136 137 void 138 arch_cpu_invalidate_TLB_list(addr_t pages[], int num_pages) 139 { 140 int i; 141 142 cpu_ops.flush_insn_pipeline(); 143 for (i = 0; i < num_pages; i++) { 144 cpu_ops.flush_atc_addr(pages[i]); 145 cpu_ops.flush_insn_pipeline(); 146 } 147 cpu_ops.flush_insn_pipeline(); 148 } 149 150 151 void 152 arch_cpu_global_TLB_invalidate(void) 153 { 154 cpu_ops.flush_insn_pipeline(); 155 cpu_ops.flush_atc_all(); 156 cpu_ops.flush_insn_pipeline(); 157 } 158 159 160 void 161 arch_cpu_user_TLB_invalidate(void) 162 { 163 cpu_ops.flush_insn_pipeline(); 164 cpu_ops.flush_atc_user(); 165 cpu_ops.flush_insn_pipeline(); 166 } 167 168 169 status_t 170 arch_cpu_user_memcpy(void *to, const void *from, size_t size, 171 addr_t *faultHandler) 172 { 173 char *tmp = (char *)to; 174 char *s = (char *)from; 175 addr_t oldFaultHandler = *faultHandler; 176 177 if (m68k_set_fault_handler(faultHandler, (addr_t)&&error)) 178 goto error; 179 180 while (size--) 181 *tmp++ = *s++; 182 183 *faultHandler = oldFaultHandler; 184 return 0; 185 186 error: 187 *faultHandler = oldFaultHandler; 188 return B_BAD_ADDRESS; 189 } 190 191 192 /** \brief Copies at most (\a size - 1) characters from the string in \a from to 193 * the string in \a to, NULL-terminating the result. 194 * 195 * \param to Pointer to the destination C-string. 196 * \param from Pointer to the source C-string. 197 * \param size Size in bytes of the string buffer pointed to by \a to. 198 * 199 * \return strlen(\a from). 200 */ 201 202 ssize_t 203 arch_cpu_user_strlcpy(char *to, const char *from, size_t size, addr_t *faultHandler) 204 { 205 int from_length = 0; 206 addr_t oldFaultHandler = *faultHandler; 207 208 if (m68k_set_fault_handler(faultHandler, (addr_t)&&error)) 209 goto error; 210 211 if (size > 0) { 212 to[--size] = '\0'; 213 // copy 214 for ( ; size; size--, from_length++, to++, from++) { 215 if ((*to = *from) == '\0') 216 break; 217 } 218 } 219 // count any leftover from chars 220 while (*from++ != '\0') 221 from_length++; 222 223 *faultHandler = oldFaultHandler; 224 return from_length; 225 226 error: 227 *faultHandler = oldFaultHandler; 228 return B_BAD_ADDRESS; 229 } 230 231 232 status_t 233 arch_cpu_user_memset(void *s, char c, size_t count, addr_t *faultHandler) 234 { 235 char *xs = (char *)s; 236 addr_t oldFaultHandler = *faultHandler; 237 238 if (m68k_set_fault_handler(faultHandler, (addr_t)&&error)) 239 goto error; 240 241 while (count--) 242 *xs++ = c; 243 244 *faultHandler = oldFaultHandler; 245 return 0; 246 247 error: 248 *faultHandler = oldFaultHandler; 249 return B_BAD_ADDRESS; 250 } 251 252 253 status_t 254 arch_cpu_shutdown(bool reboot) 255 { 256 M68KPlatform::Default()->ShutDown(reboot); 257 return B_ERROR; 258 } 259 260 261 void 262 arch_cpu_idle(void) 263 { 264 if (cpu_ops.idle) 265 cpu_ops.idle(); 266 #warning M68K: use LPSTOP ? 267 //asm volatile ("lpstop"); 268 } 269 270 271 // The purpose of this function is to trick the compiler. When setting the 272 // page_handler to a label that is obviously (to the compiler) never used, 273 // it may reorganize the control flow, so that the labeled part is optimized 274 // away. 275 // By invoking the function like this 276 // 277 // if (m68k_set_fault_handler(faultHandler, (addr_t)&&error)) 278 // goto error; 279 // 280 // the compiler has to keep the labeled code, since it can't guess the return 281 // value of this (non-inlinable) function. At least in my tests it worked that 282 // way, and I hope it will continue to work like this in the future. 283 // 284 bool 285 m68k_set_fault_handler(addr_t *handlerLocation, addr_t handler) 286 { 287 *handlerLocation = handler; 288 return false; 289 } 290