18baf8813SIngo Weinhold /* 28baf8813SIngo Weinhold * Copyright 2003-2005, Axel Dörfler, axeld@pinc-software.de. 38baf8813SIngo Weinhold * Distributed under the terms of the MIT License. 48baf8813SIngo Weinhold * 58baf8813SIngo Weinhold * Copyright 2001, Travis Geiselbrecht. All rights reserved. 68baf8813SIngo Weinhold * Distributed under the terms of the NewOS License. 78baf8813SIngo Weinhold */ 88baf8813SIngo Weinhold 98baf8813SIngo Weinhold 108baf8813SIngo Weinhold #include <KernelExport.h> 118baf8813SIngo Weinhold 128baf8813SIngo Weinhold #include <arch_platform.h> 136c678c57SIngo Weinhold #include <arch_thread.h> 148baf8813SIngo Weinhold #include <arch/cpu.h> 158baf8813SIngo Weinhold #include <boot/kernel_args.h> 168baf8813SIngo Weinhold 17d0648592SIngo Weinhold static bool sHasTlbia; 188baf8813SIngo Weinhold 198baf8813SIngo Weinhold status_t 20badc7b67STravis Geiselbrecht arch_cpu_preboot_init_percpu(kernel_args *args, int curr_cpu) 218baf8813SIngo Weinhold { 22b7ba8a18SIngo Weinhold // enable FPU 23b7ba8a18SIngo Weinhold set_msr(get_msr() | MSR_FP_AVAILABLE); 24b7ba8a18SIngo Weinhold 256c678c57SIngo Weinhold // The current thread must be NULL for all CPUs till we have threads. 266c678c57SIngo Weinhold // Some boot code relies on this. 276c678c57SIngo Weinhold arch_thread_set_current_thread(NULL); 286c678c57SIngo Weinhold 298baf8813SIngo Weinhold return B_OK; 308baf8813SIngo Weinhold } 318baf8813SIngo Weinhold 328baf8813SIngo Weinhold 338baf8813SIngo Weinhold status_t 348baf8813SIngo Weinhold arch_cpu_init(kernel_args *args) 358baf8813SIngo Weinhold { 36d0648592SIngo Weinhold // TODO: Let the boot loader put that info into the kernel args 37d0648592SIngo Weinhold // (property "tlbia" in the CPU node). 38d0648592SIngo Weinhold sHasTlbia = false; 39d0648592SIngo Weinhold 408baf8813SIngo Weinhold return B_OK; 418baf8813SIngo Weinhold } 428baf8813SIngo Weinhold 438baf8813SIngo Weinhold 448baf8813SIngo Weinhold status_t 458baf8813SIngo Weinhold arch_cpu_init_post_vm(kernel_args *args) 468baf8813SIngo Weinhold { 478baf8813SIngo Weinhold return B_OK; 488baf8813SIngo Weinhold } 498baf8813SIngo Weinhold 508baf8813SIngo Weinhold status_t 514b8d0e68SFrançois Revol arch_cpu_init_percpu(kernel_args *args, int curr_cpu) 524b8d0e68SFrançois Revol { 534b8d0e68SFrançois Revol //detect_cpu(curr_cpu); 544b8d0e68SFrançois Revol 554b8d0e68SFrançois Revol // we only support one on ppc anyway at the moment... 564b8d0e68SFrançois Revol //XXX: WRITEME 574b8d0e68SFrançois Revol return 0; 584b8d0e68SFrançois Revol } 594b8d0e68SFrançois Revol 604b8d0e68SFrançois Revol status_t 618baf8813SIngo Weinhold arch_cpu_init_post_modules(kernel_args *args) 628baf8813SIngo Weinhold { 638baf8813SIngo Weinhold return B_OK; 648baf8813SIngo Weinhold } 658baf8813SIngo Weinhold 668baf8813SIngo Weinhold #define CACHELINE 32 678baf8813SIngo Weinhold 688baf8813SIngo Weinhold void 698baf8813SIngo Weinhold arch_cpu_sync_icache(void *address, size_t len) 708baf8813SIngo Weinhold { 718baf8813SIngo Weinhold int l, off; 728baf8813SIngo Weinhold char *p; 738baf8813SIngo Weinhold 748baf8813SIngo Weinhold off = (unsigned int)address & (CACHELINE - 1); 758baf8813SIngo Weinhold len += off; 768baf8813SIngo Weinhold 778baf8813SIngo Weinhold l = len; 788baf8813SIngo Weinhold p = (char *)address - off; 798baf8813SIngo Weinhold do { 808baf8813SIngo Weinhold asm volatile ("dcbst 0,%0" :: "r"(p)); 818baf8813SIngo Weinhold p += CACHELINE; 828baf8813SIngo Weinhold } while ((l -= CACHELINE) > 0); 838baf8813SIngo Weinhold asm volatile ("sync"); 848baf8813SIngo Weinhold 858baf8813SIngo Weinhold p = (char *)address - off; 868baf8813SIngo Weinhold do { 878baf8813SIngo Weinhold asm volatile ("icbi 0,%0" :: "r"(p)); 888baf8813SIngo Weinhold p += CACHELINE; 898baf8813SIngo Weinhold } while ((len -= CACHELINE) > 0); 908baf8813SIngo Weinhold asm volatile ("sync"); 918baf8813SIngo Weinhold isync(); 928baf8813SIngo Weinhold } 938baf8813SIngo Weinhold 948baf8813SIngo Weinhold 958baf8813SIngo Weinhold void 96807cf76dSFrançois Revol arch_cpu_memory_read_barrier(void) 97807cf76dSFrançois Revol { 98328029e1SIngo Weinhold // WARNING PPC: is it model-dependant ? 99807cf76dSFrançois Revol asm volatile ("lwsync"); 100807cf76dSFrançois Revol } 101807cf76dSFrançois Revol 102807cf76dSFrançois Revol 103807cf76dSFrançois Revol void 104807cf76dSFrançois Revol arch_cpu_memory_write_barrier(void) 105807cf76dSFrançois Revol { 106328029e1SIngo Weinhold // WARNING PPC: is it model-dependant ? 107807cf76dSFrançois Revol asm volatile ("isync"); 108867bc161SFrançois Revol asm volatile ("eieio"); 109807cf76dSFrançois Revol } 110807cf76dSFrançois Revol 111807cf76dSFrançois Revol 112807cf76dSFrançois Revol void 1138baf8813SIngo Weinhold arch_cpu_invalidate_TLB_range(addr_t start, addr_t end) 1148baf8813SIngo Weinhold { 1158baf8813SIngo Weinhold asm volatile("sync"); 1168baf8813SIngo Weinhold while (start < end) { 1178baf8813SIngo Weinhold asm volatile("tlbie %0" :: "r" (start)); 1188baf8813SIngo Weinhold asm volatile("eieio"); 1198baf8813SIngo Weinhold asm volatile("sync"); 1208baf8813SIngo Weinhold start += B_PAGE_SIZE; 1218baf8813SIngo Weinhold } 1228baf8813SIngo Weinhold asm volatile("tlbsync"); 1238baf8813SIngo Weinhold asm volatile("sync"); 1248baf8813SIngo Weinhold } 1258baf8813SIngo Weinhold 1268baf8813SIngo Weinhold 1278baf8813SIngo Weinhold void 1288baf8813SIngo Weinhold arch_cpu_invalidate_TLB_list(addr_t pages[], int num_pages) 1298baf8813SIngo Weinhold { 1308baf8813SIngo Weinhold int i; 1318baf8813SIngo Weinhold 1328baf8813SIngo Weinhold asm volatile("sync"); 1338baf8813SIngo Weinhold for (i = 0; i < num_pages; i++) { 1348baf8813SIngo Weinhold asm volatile("tlbie %0" :: "r" (pages[i])); 1358baf8813SIngo Weinhold asm volatile("eieio"); 1368baf8813SIngo Weinhold asm volatile("sync"); 1378baf8813SIngo Weinhold } 1388baf8813SIngo Weinhold asm volatile("tlbsync"); 1398baf8813SIngo Weinhold asm volatile("sync"); 1408baf8813SIngo Weinhold } 1418baf8813SIngo Weinhold 1428baf8813SIngo Weinhold 1438baf8813SIngo Weinhold void 1448baf8813SIngo Weinhold arch_cpu_global_TLB_invalidate(void) 1458baf8813SIngo Weinhold { 146d0648592SIngo Weinhold if (sHasTlbia) { 1478baf8813SIngo Weinhold ppc_sync(); 1488baf8813SIngo Weinhold tlbia(); 1498baf8813SIngo Weinhold ppc_sync(); 150d0648592SIngo Weinhold } else { 151d0648592SIngo Weinhold addr_t address = 0; 152d0648592SIngo Weinhold unsigned long i; 153d0648592SIngo Weinhold 154d0648592SIngo Weinhold ppc_sync(); 155d0648592SIngo Weinhold for (i = 0; i < 0x100000; i++) { 156d0648592SIngo Weinhold tlbie(address); 157d0648592SIngo Weinhold eieio(); 158d0648592SIngo Weinhold ppc_sync(); 159d0648592SIngo Weinhold 160d0648592SIngo Weinhold address += B_PAGE_SIZE; 161d0648592SIngo Weinhold } 162d0648592SIngo Weinhold tlbsync(); 163d0648592SIngo Weinhold ppc_sync(); 164d0648592SIngo Weinhold } 1658baf8813SIngo Weinhold } 1668baf8813SIngo Weinhold 1678baf8813SIngo Weinhold 1688baf8813SIngo Weinhold void 1698baf8813SIngo Weinhold arch_cpu_user_TLB_invalidate(void) 1708baf8813SIngo Weinhold { 171d0648592SIngo Weinhold arch_cpu_global_TLB_invalidate(); 1728baf8813SIngo Weinhold } 1738baf8813SIngo Weinhold 1748baf8813SIngo Weinhold 1758baf8813SIngo Weinhold status_t 1767afc16f0SIngo Weinhold arch_cpu_user_memcpy(void *to, const void *from, size_t size, 1777afc16f0SIngo Weinhold addr_t *faultHandler) 1788baf8813SIngo Weinhold { 1798baf8813SIngo Weinhold char *tmp = (char *)to; 1808baf8813SIngo Weinhold char *s = (char *)from; 181962b0b88SIngo Weinhold addr_t oldFaultHandler = *faultHandler; 1828baf8813SIngo Weinhold 183*ea2abd11SIngo Weinhold // TODO: This doesn't work correctly with gcc 4 anymore! 1847afc16f0SIngo Weinhold if (ppc_set_fault_handler(faultHandler, (addr_t)&&error)) 1857afc16f0SIngo Weinhold goto error; 1868baf8813SIngo Weinhold 1878baf8813SIngo Weinhold while (size--) 1888baf8813SIngo Weinhold *tmp++ = *s++; 1898baf8813SIngo Weinhold 190962b0b88SIngo Weinhold *faultHandler = oldFaultHandler; 1918baf8813SIngo Weinhold return 0; 1928baf8813SIngo Weinhold 1938baf8813SIngo Weinhold error: 194962b0b88SIngo Weinhold *faultHandler = oldFaultHandler; 1958baf8813SIngo Weinhold return B_BAD_ADDRESS; 1968baf8813SIngo Weinhold } 1978baf8813SIngo Weinhold 1988baf8813SIngo Weinhold 1998baf8813SIngo Weinhold /** \brief Copies at most (\a size - 1) characters from the string in \a from to 2008baf8813SIngo Weinhold * the string in \a to, NULL-terminating the result. 2018baf8813SIngo Weinhold * 2028baf8813SIngo Weinhold * \param to Pointer to the destination C-string. 2038baf8813SIngo Weinhold * \param from Pointer to the source C-string. 2048baf8813SIngo Weinhold * \param size Size in bytes of the string buffer pointed to by \a to. 2058baf8813SIngo Weinhold * 2068baf8813SIngo Weinhold * \return strlen(\a from). 2078baf8813SIngo Weinhold */ 2088baf8813SIngo Weinhold 2098baf8813SIngo Weinhold ssize_t 2108baf8813SIngo Weinhold arch_cpu_user_strlcpy(char *to, const char *from, size_t size, addr_t *faultHandler) 2118baf8813SIngo Weinhold { 2128baf8813SIngo Weinhold int from_length = 0; 213962b0b88SIngo Weinhold addr_t oldFaultHandler = *faultHandler; 2148baf8813SIngo Weinhold 215*ea2abd11SIngo Weinhold // TODO: This doesn't work correctly with gcc 4 anymore! 2167afc16f0SIngo Weinhold if (ppc_set_fault_handler(faultHandler, (addr_t)&&error)) 2177afc16f0SIngo Weinhold goto error; 2188baf8813SIngo Weinhold 2198baf8813SIngo Weinhold if (size > 0) { 2208baf8813SIngo Weinhold to[--size] = '\0'; 2218baf8813SIngo Weinhold // copy 2228baf8813SIngo Weinhold for ( ; size; size--, from_length++, to++, from++) { 2238baf8813SIngo Weinhold if ((*to = *from) == '\0') 2248baf8813SIngo Weinhold break; 2258baf8813SIngo Weinhold } 2268baf8813SIngo Weinhold } 2278baf8813SIngo Weinhold // count any leftover from chars 2288baf8813SIngo Weinhold while (*from++ != '\0') 2298baf8813SIngo Weinhold from_length++; 2308baf8813SIngo Weinhold 231962b0b88SIngo Weinhold *faultHandler = oldFaultHandler; 2328baf8813SIngo Weinhold return from_length; 2338baf8813SIngo Weinhold 2348baf8813SIngo Weinhold error: 235962b0b88SIngo Weinhold *faultHandler = oldFaultHandler; 2368baf8813SIngo Weinhold return B_BAD_ADDRESS; 2378baf8813SIngo Weinhold } 2388baf8813SIngo Weinhold 2398baf8813SIngo Weinhold 2408baf8813SIngo Weinhold status_t 2417afc16f0SIngo Weinhold arch_cpu_user_memset(void *s, char c, size_t count, addr_t *faultHandler) 2428baf8813SIngo Weinhold { 2438baf8813SIngo Weinhold char *xs = (char *)s; 244962b0b88SIngo Weinhold addr_t oldFaultHandler = *faultHandler; 2458baf8813SIngo Weinhold 246*ea2abd11SIngo Weinhold // TODO: This doesn't work correctly with gcc 4 anymore! 2477afc16f0SIngo Weinhold if (ppc_set_fault_handler(faultHandler, (addr_t)&&error)) 2487afc16f0SIngo Weinhold goto error; 2498baf8813SIngo Weinhold 2508baf8813SIngo Weinhold while (count--) 2518baf8813SIngo Weinhold *xs++ = c; 2528baf8813SIngo Weinhold 253962b0b88SIngo Weinhold *faultHandler = oldFaultHandler; 2548baf8813SIngo Weinhold return 0; 2558baf8813SIngo Weinhold 2568baf8813SIngo Weinhold error: 257962b0b88SIngo Weinhold *faultHandler = oldFaultHandler; 2588baf8813SIngo Weinhold return B_BAD_ADDRESS; 2598baf8813SIngo Weinhold } 2608baf8813SIngo Weinhold 2618baf8813SIngo Weinhold 2628baf8813SIngo Weinhold status_t 2638baf8813SIngo Weinhold arch_cpu_shutdown(bool reboot) 2648baf8813SIngo Weinhold { 2658baf8813SIngo Weinhold PPCPlatform::Default()->ShutDown(reboot); 2668baf8813SIngo Weinhold return B_ERROR; 2678baf8813SIngo Weinhold } 2688baf8813SIngo Weinhold 2698baf8813SIngo Weinhold 2708baf8813SIngo Weinhold void 2718baf8813SIngo Weinhold arch_cpu_idle(void) 2728baf8813SIngo Weinhold { 2738baf8813SIngo Weinhold } 2748baf8813SIngo Weinhold 2757afc16f0SIngo Weinhold 2767afc16f0SIngo Weinhold // The purpose of this function is to trick the compiler. When setting the 2777afc16f0SIngo Weinhold // page_handler to a label that is obviously (to the compiler) never used, 2787afc16f0SIngo Weinhold // it may reorganize the control flow, so that the labeled part is optimized 2797afc16f0SIngo Weinhold // away. 2807afc16f0SIngo Weinhold // By invoking the function like this 2817afc16f0SIngo Weinhold // 2827afc16f0SIngo Weinhold // if (ppc_set_fault_handler(faultHandler, (addr_t)&&error)) 2837afc16f0SIngo Weinhold // goto error; 2847afc16f0SIngo Weinhold // 2857afc16f0SIngo Weinhold // the compiler has to keep the labeled code, since it can't guess the return 2867afc16f0SIngo Weinhold // value of this (non-inlinable) function. At least in my tests it worked that 2877afc16f0SIngo Weinhold // way, and I hope it will continue to work like this in the future. 2887afc16f0SIngo Weinhold // 2897afc16f0SIngo Weinhold bool 2907afc16f0SIngo Weinhold ppc_set_fault_handler(addr_t *handlerLocation, addr_t handler) 2917afc16f0SIngo Weinhold { 292*ea2abd11SIngo Weinhold // TODO: This doesn't work correctly with gcc 4 anymore! 2937afc16f0SIngo Weinhold *handlerLocation = handler; 2947afc16f0SIngo Weinhold return false; 2957afc16f0SIngo Weinhold } 296