1845a180fSFrançois Revol /* 24e44040dSFrançois Revol * Copyright 2007, François Revol, revol@free.fr. 34e44040dSFrançois Revol * Distributed under the terms of the MIT License. 44e44040dSFranç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 204e44040dSFrançois Revol extern struct m68k_cpu_ops cpu_ops_030; 214e44040dSFrançois Revol extern struct m68k_cpu_ops cpu_ops_040; 224e44040dSFrançois Revol extern struct m68k_cpu_ops cpu_ops_060; 234e44040dSFrançois Revol 244e44040dSFrançois Revol struct m68k_cpu_ops cpu_ops; 254e44040dSFrançois Revol 26*f0c5a3daSFrançois Revol int arch_cpu_type; 27*f0c5a3daSFrançois Revol int arch_fpu_type; 28*f0c5a3daSFrançois Revol int arch_mmu_type; 29*f0c5a3daSFrançois Revol int arch_platform; 30*f0c5a3daSFranç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 { 48a3dc7ef0SFrançois Revol arch_cpu_type = args->arch_args.cpu_type; 49a3dc7ef0SFrançois Revol arch_fpu_type = args->arch_args.fpu_type; 50a3dc7ef0SFrançois Revol arch_mmu_type = args->arch_args.mmu_type; 51a3dc7ef0SFrançois Revol arch_platform = args->arch_args.platform; 52*f0c5a3daSFrançois Revol arch_platform = args->arch_args.machine; 53a3dc7ef0SFrançois Revol void (*flush_insn_pipeline)(void); 54a3dc7ef0SFrançois Revol void (*flush_atc_all)(void); 55a3dc7ef0SFrançois Revol void (*flush_atc_user)(void); 56a3dc7ef0SFrançois Revol void (*flush_atc_addr)(void *addr); 57a3dc7ef0SFrançois Revol void (*flush_dcache)(void *address, size_t len); 58a3dc7ef0SFrançois Revol void (*flush_icache)(void *address, size_t len); 59a3dc7ef0SFrançois Revol void (*idle)(void); 604e44040dSFrançois Revol 61a3dc7ef0SFrançois Revol switch (arch_cpu_type) { 62a3dc7ef0SFrançois Revol case 68020: 63a3dc7ef0SFrançois Revol case 68030: 644e44040dSFrançois Revol cpu_ops.flush_insn_pipeline = cpu_ops_030.flush_insn_pipeline; 654e44040dSFrançois Revol cpu_ops.flush_atc_all = cpu_ops_030.flush_atc_all; 664e44040dSFrançois Revol cpu_ops.flush_atc_user = cpu_ops_030.flush_atc_user; 674e44040dSFrançois Revol cpu_ops.flush_atc_addr = cpu_ops_030.flush_atc_addr; 68a3dc7ef0SFrançois Revol cpu_ops.flush_dcache = cpu_ops_030.flush_dcache; 69a3dc7ef0SFrançois Revol cpu_ops.flush_icache = cpu_ops_030.flush_icache; 704e44040dSFrançois Revol cpu_ops.idle = cpu_ops_030.idle; // NULL 714e44040dSFrançois Revol break; 724e44040dSFrançois Revol #ifdef SUPPORTS_040 73a3dc7ef0SFrançois Revol case 68040: 744e44040dSFrançois Revol cpu_ops.flush_insn_pipeline = cpu_ops_040.flush_insn_pipeline; 754e44040dSFrançois Revol cpu_ops.flush_atc_all = cpu_ops_040.flush_atc_all; 764e44040dSFrançois Revol cpu_ops.flush_atc_user = cpu_ops_040.flush_atc_user; 774e44040dSFrançois Revol cpu_ops.flush_atc_addr = cpu_ops_040.flush_atc_addr; 78a3dc7ef0SFrançois Revol cpu_ops.flush_dcache = cpu_ops_040.flush_dcache; 79a3dc7ef0SFrançois Revol cpu_ops.flush_icache = cpu_ops_040.flush_icache; 804e44040dSFrançois Revol cpu_ops.idle = cpu_ops_040.idle; // NULL 814e44040dSFrançois Revol break; 824e44040dSFrançois Revol #endif 834e44040dSFrançois Revol #ifdef SUPPORTS_060 84a3dc7ef0SFrançois Revol case 68060: 854e44040dSFrançois Revol cpu_ops.flush_insn_pipeline = cpu_ops_060.flush_insn_pipeline; 864e44040dSFrançois Revol cpu_ops.flush_atc_all = cpu_ops_060.flush_atc_all; 874e44040dSFrançois Revol cpu_ops.flush_atc_user = cpu_ops_060.flush_atc_user; 884e44040dSFrançois Revol cpu_ops.flush_atc_addr = cpu_ops_060.flush_atc_addr; 89a3dc7ef0SFrançois Revol cpu_ops.flush_dcache = cpu_ops_060.flush_dcache; 90a3dc7ef0SFrançois Revol cpu_ops.flush_icache = cpu_ops_060.flush_icache; 914e44040dSFrançois Revol cpu_ops.idle = cpu_ops_060.idle; 924e44040dSFrançois Revol break; 934e44040dSFrançois Revol #endif 944e44040dSFrançois Revol default: 95a3dc7ef0SFrançois Revol panic("unknown cpu_type %d\n", arch_cpu_type); 964e44040dSFrançois Revol } 97a3dc7ef0SFrançois Revol 98845a180fSFrançois Revol return B_OK; 99845a180fSFrançois Revol } 100845a180fSFrançois Revol 101845a180fSFrançois Revol 102845a180fSFrançois Revol status_t 103845a180fSFrançois Revol arch_cpu_init_post_vm(kernel_args *args) 104845a180fSFrançois Revol { 105845a180fSFrançois Revol return B_OK; 106845a180fSFrançois Revol } 107845a180fSFrançois Revol 108845a180fSFrançois Revol status_t 109845a180fSFrançois Revol arch_cpu_init_post_modules(kernel_args *args) 110845a180fSFrançois Revol { 111845a180fSFrançois Revol return B_OK; 112845a180fSFrançois Revol } 113845a180fSFrançois Revol 114845a180fSFrançois Revol 115845a180fSFrançois Revol void 116845a180fSFrançois Revol arch_cpu_sync_icache(void *address, size_t len) 117845a180fSFrançois Revol { 118a3dc7ef0SFrançois Revol cpu_ops.flush_icache((addr_t)address, len); 119845a180fSFrançois Revol } 120845a180fSFrançois Revol 121845a180fSFrançois Revol 122845a180fSFrançois Revol void 123807cf76dSFrançois Revol arch_cpu_memory_read_barrier(void) 124807cf76dSFrançois Revol { 125807cf76dSFrançois Revol asm volatile ("nop;" : : : "memory"); 126807cf76dSFrançois Revol #warning M68k: check arch_cpu_memory_read_barrier 127807cf76dSFrançois Revol } 128807cf76dSFrançois Revol 129807cf76dSFrançois Revol 130807cf76dSFrançois Revol void 131807cf76dSFrançois Revol arch_cpu_memory_write_barrier(void) 132807cf76dSFrançois Revol { 133807cf76dSFrançois Revol asm volatile ("nop;" : : : "memory"); 134807cf76dSFrançois Revol #warning M68k: check arch_cpu_memory_write_barrier 135807cf76dSFrançois Revol } 136807cf76dSFrançois Revol 137807cf76dSFrançois Revol 138807cf76dSFrançois Revol void 139845a180fSFrançois Revol arch_cpu_invalidate_TLB_range(addr_t start, addr_t end) 140845a180fSFrançois Revol { 1414237dbd0SFrançois Revol int32 num_pages = end / B_PAGE_SIZE - start / B_PAGE_SIZE; 1424e44040dSFrançois Revol cpu_ops.flush_insn_pipeline(); 1434237dbd0SFrançois Revol while (num_pages-- >= 0) { 1444e44040dSFrançois Revol cpu_ops.flush_atc_addr(start); 1454e44040dSFrançois Revol cpu_ops.flush_insn_pipeline(); 146845a180fSFrançois Revol start += B_PAGE_SIZE; 147845a180fSFrançois Revol } 1484e44040dSFrançois Revol cpu_ops.flush_insn_pipeline(); 149845a180fSFrançois Revol } 150845a180fSFrançois Revol 151845a180fSFrançois Revol 152845a180fSFrançois Revol void 153845a180fSFrançois Revol arch_cpu_invalidate_TLB_list(addr_t pages[], int num_pages) 154845a180fSFrançois Revol { 155845a180fSFrançois Revol int i; 156845a180fSFrançois Revol 1574e44040dSFrançois Revol cpu_ops.flush_insn_pipeline(); 158845a180fSFrançois Revol for (i = 0; i < num_pages; i++) { 1594e44040dSFrançois Revol cpu_ops.flush_atc_addr(pages[i]); 1604e44040dSFrançois Revol cpu_ops.flush_insn_pipeline(); 161845a180fSFrançois Revol } 1624e44040dSFrançois Revol cpu_ops.flush_insn_pipeline(); 163845a180fSFrançois Revol } 164845a180fSFrançois Revol 165845a180fSFrançois Revol 166845a180fSFrançois Revol void 167845a180fSFrançois Revol arch_cpu_global_TLB_invalidate(void) 168845a180fSFrançois Revol { 1694e44040dSFrançois Revol cpu_ops.flush_insn_pipeline(); 1704e44040dSFrançois Revol cpu_ops.flush_atc_all(); 1714e44040dSFrançois Revol cpu_ops.flush_insn_pipeline(); 172845a180fSFrançois Revol } 173845a180fSFrançois Revol 174845a180fSFrançois Revol 175845a180fSFrançois Revol void 176845a180fSFrançois Revol arch_cpu_user_TLB_invalidate(void) 177845a180fSFrançois Revol { 1784e44040dSFrançois Revol cpu_ops.flush_insn_pipeline(); 1794e44040dSFrançois Revol cpu_ops.flush_atc_user(); 1804e44040dSFrançois Revol cpu_ops.flush_insn_pipeline(); 181845a180fSFrançois Revol } 182845a180fSFrançois Revol 183845a180fSFrançois Revol 184845a180fSFrançois Revol status_t 185845a180fSFrançois Revol arch_cpu_user_memcpy(void *to, const void *from, size_t size, 186845a180fSFrançois Revol addr_t *faultHandler) 187845a180fSFrançois Revol { 188845a180fSFrançois Revol char *tmp = (char *)to; 189845a180fSFrançois Revol char *s = (char *)from; 190845a180fSFrançois Revol addr_t oldFaultHandler = *faultHandler; 191845a180fSFrançois Revol 192845a180fSFrançois Revol if (m68k_set_fault_handler(faultHandler, (addr_t)&&error)) 193845a180fSFrançois Revol goto error; 194845a180fSFrançois Revol 195845a180fSFrançois Revol while (size--) 196845a180fSFrançois Revol *tmp++ = *s++; 197845a180fSFrançois Revol 198845a180fSFrançois Revol *faultHandler = oldFaultHandler; 199845a180fSFrançois Revol return 0; 200845a180fSFrançois Revol 201845a180fSFrançois Revol error: 202845a180fSFrançois Revol *faultHandler = oldFaultHandler; 203845a180fSFrançois Revol return B_BAD_ADDRESS; 204845a180fSFrançois Revol } 205845a180fSFrançois Revol 206845a180fSFrançois Revol 207845a180fSFrançois Revol /** \brief Copies at most (\a size - 1) characters from the string in \a from to 208845a180fSFrançois Revol * the string in \a to, NULL-terminating the result. 209845a180fSFrançois Revol * 210845a180fSFrançois Revol * \param to Pointer to the destination C-string. 211845a180fSFrançois Revol * \param from Pointer to the source C-string. 212845a180fSFrançois Revol * \param size Size in bytes of the string buffer pointed to by \a to. 213845a180fSFrançois Revol * 214845a180fSFrançois Revol * \return strlen(\a from). 215845a180fSFrançois Revol */ 216845a180fSFrançois Revol 217845a180fSFrançois Revol ssize_t 218845a180fSFrançois Revol arch_cpu_user_strlcpy(char *to, const char *from, size_t size, addr_t *faultHandler) 219845a180fSFrançois Revol { 220845a180fSFrançois Revol int from_length = 0; 221845a180fSFrançois Revol addr_t oldFaultHandler = *faultHandler; 222845a180fSFrançois Revol 223845a180fSFrançois Revol if (m68k_set_fault_handler(faultHandler, (addr_t)&&error)) 224845a180fSFrançois Revol goto error; 225845a180fSFrançois Revol 226845a180fSFrançois Revol if (size > 0) { 227845a180fSFrançois Revol to[--size] = '\0'; 228845a180fSFrançois Revol // copy 229845a180fSFrançois Revol for ( ; size; size--, from_length++, to++, from++) { 230845a180fSFrançois Revol if ((*to = *from) == '\0') 231845a180fSFrançois Revol break; 232845a180fSFrançois Revol } 233845a180fSFrançois Revol } 234845a180fSFrançois Revol // count any leftover from chars 235845a180fSFrançois Revol while (*from++ != '\0') 236845a180fSFrançois Revol from_length++; 237845a180fSFrançois Revol 238845a180fSFrançois Revol *faultHandler = oldFaultHandler; 239845a180fSFrançois Revol return from_length; 240845a180fSFrançois Revol 241845a180fSFrançois Revol error: 242845a180fSFrançois Revol *faultHandler = oldFaultHandler; 243845a180fSFrançois Revol return B_BAD_ADDRESS; 244845a180fSFrançois Revol } 245845a180fSFrançois Revol 246845a180fSFrançois Revol 247845a180fSFrançois Revol status_t 248845a180fSFrançois Revol arch_cpu_user_memset(void *s, char c, size_t count, addr_t *faultHandler) 249845a180fSFrançois Revol { 250845a180fSFrançois Revol char *xs = (char *)s; 251845a180fSFrançois Revol addr_t oldFaultHandler = *faultHandler; 252845a180fSFrançois Revol 253845a180fSFrançois Revol if (m68k_set_fault_handler(faultHandler, (addr_t)&&error)) 254845a180fSFrançois Revol goto error; 255845a180fSFrançois Revol 256845a180fSFrançois Revol while (count--) 257845a180fSFrançois Revol *xs++ = c; 258845a180fSFrançois Revol 259845a180fSFrançois Revol *faultHandler = oldFaultHandler; 260845a180fSFrançois Revol return 0; 261845a180fSFrançois Revol 262845a180fSFrançois Revol error: 263845a180fSFrançois Revol *faultHandler = oldFaultHandler; 264845a180fSFrançois Revol return B_BAD_ADDRESS; 265845a180fSFrançois Revol } 266845a180fSFrançois Revol 267845a180fSFrançois Revol 268845a180fSFrançois Revol status_t 269845a180fSFrançois Revol arch_cpu_shutdown(bool reboot) 270845a180fSFrançois Revol { 271845a180fSFrançois Revol M68KPlatform::Default()->ShutDown(reboot); 272845a180fSFrançois Revol return B_ERROR; 273845a180fSFrançois Revol } 274845a180fSFrançois Revol 275845a180fSFrançois Revol 276845a180fSFrançois Revol void 277845a180fSFrançois Revol arch_cpu_idle(void) 278845a180fSFrançois Revol { 2794e44040dSFrançois Revol if (cpu_ops.idle) 2804e44040dSFrançois Revol cpu_ops.idle(); 281ac1a8a0cSFrançois Revol #warning M68K: use LPSTOP ? 282ac1a8a0cSFrançois Revol //asm volatile ("lpstop"); 283845a180fSFrançois Revol } 284845a180fSFrançois Revol 285845a180fSFrançois Revol 286845a180fSFrançois Revol // The purpose of this function is to trick the compiler. When setting the 287845a180fSFrançois Revol // page_handler to a label that is obviously (to the compiler) never used, 288845a180fSFrançois Revol // it may reorganize the control flow, so that the labeled part is optimized 289845a180fSFrançois Revol // away. 290845a180fSFrançois Revol // By invoking the function like this 291845a180fSFrançois Revol // 292845a180fSFrançois Revol // if (m68k_set_fault_handler(faultHandler, (addr_t)&&error)) 293845a180fSFrançois Revol // goto error; 294845a180fSFrançois Revol // 295845a180fSFrançois Revol // the compiler has to keep the labeled code, since it can't guess the return 296845a180fSFrançois Revol // value of this (non-inlinable) function. At least in my tests it worked that 297845a180fSFrançois Revol // way, and I hope it will continue to work like this in the future. 298845a180fSFrançois Revol // 299845a180fSFrançois Revol bool 300845a180fSFrançois Revol m68k_set_fault_handler(addr_t *handlerLocation, addr_t handler) 301845a180fSFrançois Revol { 302845a180fSFrançois Revol *handlerLocation = handler; 303845a180fSFrançois Revol return false; 304845a180fSFrançois Revol } 305