1845a180fSFrançois Revol /* 2*4e44040dSFrançois Revol * Copyright 2007, François Revol, revol@free.fr. 3*4e44040dSFrançois Revol * Distributed under the terms of the MIT License. 4*4e44040dSFrançois Revol * 5845a180fSFrançois Revol * Copyright 2003-2005, Axel Dörfler, axeld@pinc-software.de. 6845a180fSFrançois Revol * Distributed under the terms of the MIT License. 7845a180fSFrançois Revol * 8845a180fSFrançois Revol * Copyright 2001, Travis Geiselbrecht. All rights reserved. 9845a180fSFrançois Revol * Distributed under the terms of the NewOS License. 10845a180fSFrançois Revol */ 11845a180fSFrançois Revol 12845a180fSFrançois Revol 13845a180fSFrançois Revol #include <KernelExport.h> 14845a180fSFrançois Revol 15845a180fSFrançois Revol #include <arch_platform.h> 16845a180fSFrançois Revol #include <arch_thread.h> 17845a180fSFrançois Revol #include <arch/cpu.h> 18845a180fSFrançois Revol #include <boot/kernel_args.h> 19845a180fSFrançois Revol 20*4e44040dSFrançois Revol extern struct m68k_cpu_ops cpu_ops_030; 21*4e44040dSFrançois Revol extern struct m68k_cpu_ops cpu_ops_040; 22*4e44040dSFrançois Revol extern struct m68k_cpu_ops cpu_ops_060; 23*4e44040dSFrançois Revol 24*4e44040dSFrançois Revol struct m68k_cpu_ops cpu_ops; 25*4e44040dSFrançois Revol 26*4e44040dSFrançois Revol int cpu_type; 27*4e44040dSFrançois Revol int fpu_type; 28*4e44040dSFrançois Revol int mmu_type; 29*4e44040dSFrançois Revol int platform; 30845a180fSFrançois Revol 31845a180fSFrançois Revol status_t 32845a180fSFrançois Revol arch_cpu_preboot_init_percpu(kernel_args *args, int curr_cpu) 33845a180fSFrançois Revol { 34845a180fSFrançois Revol // enable FPU 35829748d8SFrançois Revol //ppc:set_msr(get_msr() | MSR_FP_AVAILABLE); 36845a180fSFrançois Revol 37845a180fSFrançois Revol // The current thread must be NULL for all CPUs till we have threads. 38845a180fSFrançois Revol // Some boot code relies on this. 39845a180fSFrançois Revol arch_thread_set_current_thread(NULL); 40845a180fSFrançois Revol 41845a180fSFrançois Revol return B_OK; 42845a180fSFrançois Revol } 43845a180fSFrançois Revol 44845a180fSFrançois Revol 45845a180fSFrançois Revol status_t 46845a180fSFrançois Revol arch_cpu_init(kernel_args *args) 47845a180fSFrançois Revol { 48*4e44040dSFrançois Revol cpu_type = args->arch_args.cpu_type; 49*4e44040dSFrançois Revol fpu_type = args->arch_args.fpu_type; 50*4e44040dSFrançois Revol mmu_type = args->arch_args.mmu_type; 51*4e44040dSFrançois Revol platform = args->arch_args.platform; 52*4e44040dSFrançois Revol 53*4e44040dSFrançois Revol switch (cpu_type) { 54*4e44040dSFrançois Revol case CPU_68020: 55*4e44040dSFrançois Revol case CPU_68030: 56*4e44040dSFrançois Revol cpu_ops.flush_insn_pipeline = cpu_ops_030.flush_insn_pipeline; 57*4e44040dSFrançois Revol cpu_ops.flush_atc_all = cpu_ops_030.flush_atc_all; 58*4e44040dSFrançois Revol cpu_ops.flush_atc_user = cpu_ops_030.flush_atc_user; 59*4e44040dSFrançois Revol cpu_ops.flush_atc_addr = cpu_ops_030.flush_atc_addr; 60*4e44040dSFrançois Revol cpu_ops.flush_cache_line = cpu_ops_030.flush_cache_line; 61*4e44040dSFrançois Revol cpu_ops.idle = cpu_ops_030.idle; // NULL 62*4e44040dSFrançois Revol //cpu_ops. = cpu_ops_030.; 63*4e44040dSFrançois Revol break; 64*4e44040dSFrançois Revol #ifdef SUPPORTS_040 65*4e44040dSFrançois Revol case CPU_68040: 66*4e44040dSFrançois Revol cpu_ops.flush_insn_pipeline = cpu_ops_040.flush_insn_pipeline; 67*4e44040dSFrançois Revol cpu_ops.flush_atc_all = cpu_ops_040.flush_atc_all; 68*4e44040dSFrançois Revol cpu_ops.flush_atc_user = cpu_ops_040.flush_atc_user; 69*4e44040dSFrançois Revol cpu_ops.flush_atc_addr = cpu_ops_040.flush_atc_addr; 70*4e44040dSFrançois Revol cpu_ops.flush_cache_line = cpu_ops_040.flush_cache_line; 71*4e44040dSFrançois Revol cpu_ops.idle = cpu_ops_040.idle; // NULL 72*4e44040dSFrançois Revol //cpu_ops. = cpu_ops_040.; 73*4e44040dSFrançois Revol break; 74*4e44040dSFrançois Revol #endif 75*4e44040dSFrançois Revol #ifdef SUPPORTS_060 76*4e44040dSFrançois Revol case CPU_68060: 77*4e44040dSFrançois Revol cpu_ops.flush_insn_pipeline = cpu_ops_060.flush_insn_pipeline; 78*4e44040dSFrançois Revol cpu_ops.flush_atc_all = cpu_ops_060.flush_atc_all; 79*4e44040dSFrançois Revol cpu_ops.flush_atc_user = cpu_ops_060.flush_atc_user; 80*4e44040dSFrançois Revol cpu_ops.flush_atc_addr = cpu_ops_060.flush_atc_addr; 81*4e44040dSFrançois Revol cpu_ops.flush_cache_line = cpu_ops_060.flush_cache_line; 82*4e44040dSFrançois Revol cpu_ops.idle = cpu_ops_060.idle; 83*4e44040dSFrançois Revol //cpu_ops. = cpu_ops_060.; 84*4e44040dSFrançois Revol break; 85*4e44040dSFrançois Revol #endif 86*4e44040dSFrançois Revol default: 87*4e44040dSFrançois Revol panic("unknown cpu_type 0x%08lx\n", args->arch_args.cpu_type); 88*4e44040dSFrançois Revol } 89845a180fSFrançois Revol return B_OK; 90845a180fSFrançois Revol } 91845a180fSFrançois Revol 92845a180fSFrançois Revol 93845a180fSFrançois Revol status_t 94845a180fSFrançois Revol arch_cpu_init_post_vm(kernel_args *args) 95845a180fSFrançois Revol { 96845a180fSFrançois Revol return B_OK; 97845a180fSFrançois Revol } 98845a180fSFrançois Revol 99845a180fSFrançois Revol status_t 100845a180fSFrançois Revol arch_cpu_init_post_modules(kernel_args *args) 101845a180fSFrançois Revol { 102845a180fSFrançois Revol return B_OK; 103845a180fSFrançois Revol } 104845a180fSFrançois Revol 105845a180fSFrançois Revol 106845a180fSFrançois Revol void 107845a180fSFrançois Revol arch_cpu_sync_icache(void *address, size_t len) 108845a180fSFrançois Revol { 109*4e44040dSFrançois Revol cpu_ops.flush_icache(address, len); 110845a180fSFrançois Revol } 111845a180fSFrançois Revol 112845a180fSFrançois Revol 113845a180fSFrançois Revol void 114845a180fSFrançois Revol arch_cpu_invalidate_TLB_range(addr_t start, addr_t end) 115845a180fSFrançois Revol { 116*4e44040dSFrançois Revol cpu_ops.flush_insn_pipeline(); 117845a180fSFrançois Revol while (start < end) { 118*4e44040dSFrançois Revol cpu_ops.flush_atc_addr(start); 119*4e44040dSFrançois Revol cpu_ops.flush_insn_pipeline(); 120845a180fSFrançois Revol start += B_PAGE_SIZE; 121845a180fSFrançois Revol } 122*4e44040dSFrançois Revol cpu_ops.flush_insn_pipeline(); 123845a180fSFrançois Revol } 124845a180fSFrançois Revol 125845a180fSFrançois Revol 126845a180fSFrançois Revol void 127845a180fSFrançois Revol arch_cpu_invalidate_TLB_list(addr_t pages[], int num_pages) 128845a180fSFrançois Revol { 129845a180fSFrançois Revol int i; 130845a180fSFrançois Revol 131*4e44040dSFrançois Revol cpu_ops.flush_insn_pipeline(); 132845a180fSFrançois Revol for (i = 0; i < num_pages; i++) { 133*4e44040dSFrançois Revol cpu_ops.flush_atc_addr(pages[i]); 134*4e44040dSFrançois Revol cpu_ops.flush_insn_pipeline(); 135845a180fSFrançois Revol } 136*4e44040dSFrançois Revol cpu_ops.flush_insn_pipeline(); 137845a180fSFrançois Revol } 138845a180fSFrançois Revol 139845a180fSFrançois Revol 140845a180fSFrançois Revol void 141845a180fSFrançois Revol arch_cpu_global_TLB_invalidate(void) 142845a180fSFrançois Revol { 143*4e44040dSFrançois Revol cpu_ops.flush_insn_pipeline(); 144*4e44040dSFrançois Revol cpu_ops.flush_atc_all(); 145*4e44040dSFrançois Revol cpu_ops.flush_insn_pipeline(); 146845a180fSFrançois Revol } 147845a180fSFrançois Revol 148845a180fSFrançois Revol 149845a180fSFrançois Revol void 150845a180fSFrançois Revol arch_cpu_user_TLB_invalidate(void) 151845a180fSFrançois Revol { 152*4e44040dSFrançois Revol cpu_ops.flush_insn_pipeline(); 153*4e44040dSFrançois Revol cpu_ops.flush_atc_user(); 154*4e44040dSFrançois Revol cpu_ops.flush_insn_pipeline(); 155845a180fSFrançois Revol } 156845a180fSFrançois Revol 157845a180fSFrançois Revol 158845a180fSFrançois Revol status_t 159845a180fSFrançois Revol arch_cpu_user_memcpy(void *to, const void *from, size_t size, 160845a180fSFrançois Revol addr_t *faultHandler) 161845a180fSFrançois Revol { 162845a180fSFrançois Revol char *tmp = (char *)to; 163845a180fSFrançois Revol char *s = (char *)from; 164845a180fSFrançois Revol addr_t oldFaultHandler = *faultHandler; 165845a180fSFrançois Revol 166845a180fSFrançois Revol if (m68k_set_fault_handler(faultHandler, (addr_t)&&error)) 167845a180fSFrançois Revol goto error; 168845a180fSFrançois Revol 169845a180fSFrançois Revol while (size--) 170845a180fSFrançois Revol *tmp++ = *s++; 171845a180fSFrançois Revol 172845a180fSFrançois Revol *faultHandler = oldFaultHandler; 173845a180fSFrançois Revol return 0; 174845a180fSFrançois Revol 175845a180fSFrançois Revol error: 176845a180fSFrançois Revol *faultHandler = oldFaultHandler; 177845a180fSFrançois Revol return B_BAD_ADDRESS; 178845a180fSFrançois Revol } 179845a180fSFrançois Revol 180845a180fSFrançois Revol 181845a180fSFrançois Revol /** \brief Copies at most (\a size - 1) characters from the string in \a from to 182845a180fSFrançois Revol * the string in \a to, NULL-terminating the result. 183845a180fSFrançois Revol * 184845a180fSFrançois Revol * \param to Pointer to the destination C-string. 185845a180fSFrançois Revol * \param from Pointer to the source C-string. 186845a180fSFrançois Revol * \param size Size in bytes of the string buffer pointed to by \a to. 187845a180fSFrançois Revol * 188845a180fSFrançois Revol * \return strlen(\a from). 189845a180fSFrançois Revol */ 190845a180fSFrançois Revol 191845a180fSFrançois Revol ssize_t 192845a180fSFrançois Revol arch_cpu_user_strlcpy(char *to, const char *from, size_t size, addr_t *faultHandler) 193845a180fSFrançois Revol { 194845a180fSFrançois Revol int from_length = 0; 195845a180fSFrançois Revol addr_t oldFaultHandler = *faultHandler; 196845a180fSFrançois Revol 197845a180fSFrançois Revol if (m68k_set_fault_handler(faultHandler, (addr_t)&&error)) 198845a180fSFrançois Revol goto error; 199845a180fSFrançois Revol 200845a180fSFrançois Revol if (size > 0) { 201845a180fSFrançois Revol to[--size] = '\0'; 202845a180fSFrançois Revol // copy 203845a180fSFrançois Revol for ( ; size; size--, from_length++, to++, from++) { 204845a180fSFrançois Revol if ((*to = *from) == '\0') 205845a180fSFrançois Revol break; 206845a180fSFrançois Revol } 207845a180fSFrançois Revol } 208845a180fSFrançois Revol // count any leftover from chars 209845a180fSFrançois Revol while (*from++ != '\0') 210845a180fSFrançois Revol from_length++; 211845a180fSFrançois Revol 212845a180fSFrançois Revol *faultHandler = oldFaultHandler; 213845a180fSFrançois Revol return from_length; 214845a180fSFrançois Revol 215845a180fSFrançois Revol error: 216845a180fSFrançois Revol *faultHandler = oldFaultHandler; 217845a180fSFrançois Revol return B_BAD_ADDRESS; 218845a180fSFrançois Revol } 219845a180fSFrançois Revol 220845a180fSFrançois Revol 221845a180fSFrançois Revol status_t 222845a180fSFrançois Revol arch_cpu_user_memset(void *s, char c, size_t count, addr_t *faultHandler) 223845a180fSFrançois Revol { 224845a180fSFrançois Revol char *xs = (char *)s; 225845a180fSFrançois Revol addr_t oldFaultHandler = *faultHandler; 226845a180fSFrançois Revol 227845a180fSFrançois Revol if (m68k_set_fault_handler(faultHandler, (addr_t)&&error)) 228845a180fSFrançois Revol goto error; 229845a180fSFrançois Revol 230845a180fSFrançois Revol while (count--) 231845a180fSFrançois Revol *xs++ = c; 232845a180fSFrançois Revol 233845a180fSFrançois Revol *faultHandler = oldFaultHandler; 234845a180fSFrançois Revol return 0; 235845a180fSFrançois Revol 236845a180fSFrançois Revol error: 237845a180fSFrançois Revol *faultHandler = oldFaultHandler; 238845a180fSFrançois Revol return B_BAD_ADDRESS; 239845a180fSFrançois Revol } 240845a180fSFrançois Revol 241845a180fSFrançois Revol 242845a180fSFrançois Revol status_t 243845a180fSFrançois Revol arch_cpu_shutdown(bool reboot) 244845a180fSFrançois Revol { 245845a180fSFrançois Revol M68KPlatform::Default()->ShutDown(reboot); 246845a180fSFrançois Revol return B_ERROR; 247845a180fSFrançois Revol } 248845a180fSFrançois Revol 249845a180fSFrançois Revol 250845a180fSFrançois Revol void 251845a180fSFrançois Revol arch_cpu_idle(void) 252845a180fSFrançois Revol { 253*4e44040dSFrançois Revol if (cpu_ops.idle) 254*4e44040dSFrançois Revol cpu_ops.idle(); 255ac1a8a0cSFrançois Revol #warning M68K: use LPSTOP ? 256ac1a8a0cSFrançois Revol //asm volatile ("lpstop"); 257845a180fSFrançois Revol } 258845a180fSFrançois Revol 259845a180fSFrançois Revol 260845a180fSFrançois Revol // The purpose of this function is to trick the compiler. When setting the 261845a180fSFrançois Revol // page_handler to a label that is obviously (to the compiler) never used, 262845a180fSFrançois Revol // it may reorganize the control flow, so that the labeled part is optimized 263845a180fSFrançois Revol // away. 264845a180fSFrançois Revol // By invoking the function like this 265845a180fSFrançois Revol // 266845a180fSFrançois Revol // if (m68k_set_fault_handler(faultHandler, (addr_t)&&error)) 267845a180fSFrançois Revol // goto error; 268845a180fSFrançois Revol // 269845a180fSFrançois Revol // the compiler has to keep the labeled code, since it can't guess the return 270845a180fSFrançois Revol // value of this (non-inlinable) function. At least in my tests it worked that 271845a180fSFrançois Revol // way, and I hope it will continue to work like this in the future. 272845a180fSFrançois Revol // 273845a180fSFrançois Revol bool 274845a180fSFrançois Revol m68k_set_fault_handler(addr_t *handlerLocation, addr_t handler) 275845a180fSFrançois Revol { 276845a180fSFrançois Revol *handlerLocation = handler; 277845a180fSFrançois Revol return false; 278845a180fSFrançois Revol } 279