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 208baf8813SIngo Weinhold arch_cpu_preboot_init(kernel_args *args) 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 518baf8813SIngo Weinhold arch_cpu_init_post_modules(kernel_args *args) 528baf8813SIngo Weinhold { 538baf8813SIngo Weinhold return B_OK; 548baf8813SIngo Weinhold } 558baf8813SIngo Weinhold 568baf8813SIngo Weinhold #define CACHELINE 32 578baf8813SIngo Weinhold 588baf8813SIngo Weinhold void 598baf8813SIngo Weinhold arch_cpu_sync_icache(void *address, size_t len) 608baf8813SIngo Weinhold { 618baf8813SIngo Weinhold int l, off; 628baf8813SIngo Weinhold char *p; 638baf8813SIngo Weinhold 648baf8813SIngo Weinhold off = (unsigned int)address & (CACHELINE - 1); 658baf8813SIngo Weinhold len += off; 668baf8813SIngo Weinhold 678baf8813SIngo Weinhold l = len; 688baf8813SIngo Weinhold p = (char *)address - off; 698baf8813SIngo Weinhold do { 708baf8813SIngo Weinhold asm volatile ("dcbst 0,%0" :: "r"(p)); 718baf8813SIngo Weinhold p += CACHELINE; 728baf8813SIngo Weinhold } while ((l -= CACHELINE) > 0); 738baf8813SIngo Weinhold asm volatile ("sync"); 748baf8813SIngo Weinhold 758baf8813SIngo Weinhold p = (char *)address - off; 768baf8813SIngo Weinhold do { 778baf8813SIngo Weinhold asm volatile ("icbi 0,%0" :: "r"(p)); 788baf8813SIngo Weinhold p += CACHELINE; 798baf8813SIngo Weinhold } while ((len -= CACHELINE) > 0); 808baf8813SIngo Weinhold asm volatile ("sync"); 818baf8813SIngo Weinhold isync(); 828baf8813SIngo Weinhold } 838baf8813SIngo Weinhold 848baf8813SIngo Weinhold 858baf8813SIngo Weinhold void 868baf8813SIngo Weinhold arch_cpu_invalidate_TLB_range(addr_t start, addr_t end) 878baf8813SIngo Weinhold { 888baf8813SIngo Weinhold asm volatile("sync"); 898baf8813SIngo Weinhold while (start < end) { 908baf8813SIngo Weinhold asm volatile("tlbie %0" :: "r" (start)); 918baf8813SIngo Weinhold asm volatile("eieio"); 928baf8813SIngo Weinhold asm volatile("sync"); 938baf8813SIngo Weinhold start += B_PAGE_SIZE; 948baf8813SIngo Weinhold } 958baf8813SIngo Weinhold asm volatile("tlbsync"); 968baf8813SIngo Weinhold asm volatile("sync"); 978baf8813SIngo Weinhold } 988baf8813SIngo Weinhold 998baf8813SIngo Weinhold 1008baf8813SIngo Weinhold void 1018baf8813SIngo Weinhold arch_cpu_invalidate_TLB_list(addr_t pages[], int num_pages) 1028baf8813SIngo Weinhold { 1038baf8813SIngo Weinhold int i; 1048baf8813SIngo Weinhold 1058baf8813SIngo Weinhold asm volatile("sync"); 1068baf8813SIngo Weinhold for (i = 0; i < num_pages; i++) { 1078baf8813SIngo Weinhold asm volatile("tlbie %0" :: "r" (pages[i])); 1088baf8813SIngo Weinhold asm volatile("eieio"); 1098baf8813SIngo Weinhold asm volatile("sync"); 1108baf8813SIngo Weinhold } 1118baf8813SIngo Weinhold asm volatile("tlbsync"); 1128baf8813SIngo Weinhold asm volatile("sync"); 1138baf8813SIngo Weinhold } 1148baf8813SIngo Weinhold 1158baf8813SIngo Weinhold 1168baf8813SIngo Weinhold void 1178baf8813SIngo Weinhold arch_cpu_global_TLB_invalidate(void) 1188baf8813SIngo Weinhold { 119d0648592SIngo Weinhold if (sHasTlbia) { 1208baf8813SIngo Weinhold ppc_sync(); 1218baf8813SIngo Weinhold tlbia(); 1228baf8813SIngo Weinhold ppc_sync(); 123d0648592SIngo Weinhold } else { 124d0648592SIngo Weinhold addr_t address = 0; 125d0648592SIngo Weinhold unsigned long i; 126d0648592SIngo Weinhold 127d0648592SIngo Weinhold ppc_sync(); 128d0648592SIngo Weinhold for (i = 0; i < 0x100000; i++) { 129d0648592SIngo Weinhold tlbie(address); 130d0648592SIngo Weinhold eieio(); 131d0648592SIngo Weinhold ppc_sync(); 132d0648592SIngo Weinhold 133d0648592SIngo Weinhold address += B_PAGE_SIZE; 134d0648592SIngo Weinhold } 135d0648592SIngo Weinhold tlbsync(); 136d0648592SIngo Weinhold ppc_sync(); 137d0648592SIngo Weinhold } 1388baf8813SIngo Weinhold } 1398baf8813SIngo Weinhold 1408baf8813SIngo Weinhold 1418baf8813SIngo Weinhold void 1428baf8813SIngo Weinhold arch_cpu_user_TLB_invalidate(void) 1438baf8813SIngo Weinhold { 144d0648592SIngo Weinhold arch_cpu_global_TLB_invalidate(); 1458baf8813SIngo Weinhold } 1468baf8813SIngo Weinhold 1478baf8813SIngo Weinhold 1488baf8813SIngo Weinhold status_t 149*7afc16f0SIngo Weinhold arch_cpu_user_memcpy(void *to, const void *from, size_t size, 150*7afc16f0SIngo Weinhold addr_t *faultHandler) 1518baf8813SIngo Weinhold { 1528baf8813SIngo Weinhold char *tmp = (char *)to; 1538baf8813SIngo Weinhold char *s = (char *)from; 1548baf8813SIngo Weinhold 155*7afc16f0SIngo Weinhold if (ppc_set_fault_handler(faultHandler, (addr_t)&&error)) 156*7afc16f0SIngo Weinhold goto error; 1578baf8813SIngo Weinhold 1588baf8813SIngo Weinhold while (size--) 1598baf8813SIngo Weinhold *tmp++ = *s++; 1608baf8813SIngo Weinhold 161*7afc16f0SIngo Weinhold *faultHandler = 0; 1628baf8813SIngo Weinhold return 0; 1638baf8813SIngo Weinhold 1648baf8813SIngo Weinhold error: 165*7afc16f0SIngo Weinhold *faultHandler = 0; 1668baf8813SIngo Weinhold return B_BAD_ADDRESS; 1678baf8813SIngo Weinhold } 1688baf8813SIngo Weinhold 1698baf8813SIngo Weinhold 1708baf8813SIngo Weinhold /** \brief Copies at most (\a size - 1) characters from the string in \a from to 1718baf8813SIngo Weinhold * the string in \a to, NULL-terminating the result. 1728baf8813SIngo Weinhold * 1738baf8813SIngo Weinhold * \param to Pointer to the destination C-string. 1748baf8813SIngo Weinhold * \param from Pointer to the source C-string. 1758baf8813SIngo Weinhold * \param size Size in bytes of the string buffer pointed to by \a to. 1768baf8813SIngo Weinhold * 1778baf8813SIngo Weinhold * \return strlen(\a from). 1788baf8813SIngo Weinhold */ 1798baf8813SIngo Weinhold 1808baf8813SIngo Weinhold ssize_t 1818baf8813SIngo Weinhold arch_cpu_user_strlcpy(char *to, const char *from, size_t size, addr_t *faultHandler) 1828baf8813SIngo Weinhold { 1838baf8813SIngo Weinhold int from_length = 0; 1848baf8813SIngo Weinhold 185*7afc16f0SIngo Weinhold if (ppc_set_fault_handler(faultHandler, (addr_t)&&error)) 186*7afc16f0SIngo Weinhold goto error; 1878baf8813SIngo Weinhold 1888baf8813SIngo Weinhold if (size > 0) { 1898baf8813SIngo Weinhold to[--size] = '\0'; 1908baf8813SIngo Weinhold // copy 1918baf8813SIngo Weinhold for ( ; size; size--, from_length++, to++, from++) { 1928baf8813SIngo Weinhold if ((*to = *from) == '\0') 1938baf8813SIngo Weinhold break; 1948baf8813SIngo Weinhold } 1958baf8813SIngo Weinhold } 1968baf8813SIngo Weinhold // count any leftover from chars 1978baf8813SIngo Weinhold while (*from++ != '\0') 1988baf8813SIngo Weinhold from_length++; 1998baf8813SIngo Weinhold 2008baf8813SIngo Weinhold *faultHandler = 0; 2018baf8813SIngo Weinhold return from_length; 2028baf8813SIngo Weinhold 2038baf8813SIngo Weinhold error: 2048baf8813SIngo Weinhold *faultHandler = 0; 2058baf8813SIngo Weinhold return B_BAD_ADDRESS; 2068baf8813SIngo Weinhold } 2078baf8813SIngo Weinhold 2088baf8813SIngo Weinhold 2098baf8813SIngo Weinhold status_t 210*7afc16f0SIngo Weinhold arch_cpu_user_memset(void *s, char c, size_t count, addr_t *faultHandler) 2118baf8813SIngo Weinhold { 2128baf8813SIngo Weinhold char *xs = (char *)s; 2138baf8813SIngo Weinhold 214*7afc16f0SIngo Weinhold if (ppc_set_fault_handler(faultHandler, (addr_t)&&error)) 215*7afc16f0SIngo Weinhold goto error; 2168baf8813SIngo Weinhold 2178baf8813SIngo Weinhold while (count--) 2188baf8813SIngo Weinhold *xs++ = c; 2198baf8813SIngo Weinhold 220*7afc16f0SIngo Weinhold *faultHandler = 0; 2218baf8813SIngo Weinhold return 0; 2228baf8813SIngo Weinhold 2238baf8813SIngo Weinhold error: 224*7afc16f0SIngo Weinhold *faultHandler = 0; 2258baf8813SIngo Weinhold return B_BAD_ADDRESS; 2268baf8813SIngo Weinhold } 2278baf8813SIngo Weinhold 2288baf8813SIngo Weinhold 2298baf8813SIngo Weinhold status_t 2308baf8813SIngo Weinhold arch_cpu_shutdown(bool reboot) 2318baf8813SIngo Weinhold { 2328baf8813SIngo Weinhold PPCPlatform::Default()->ShutDown(reboot); 2338baf8813SIngo Weinhold return B_ERROR; 2348baf8813SIngo Weinhold } 2358baf8813SIngo Weinhold 2368baf8813SIngo Weinhold 2378baf8813SIngo Weinhold void 2388baf8813SIngo Weinhold arch_cpu_idle(void) 2398baf8813SIngo Weinhold { 2408baf8813SIngo Weinhold } 2418baf8813SIngo Weinhold 242*7afc16f0SIngo Weinhold 243*7afc16f0SIngo Weinhold // The purpose of this function is to trick the compiler. When setting the 244*7afc16f0SIngo Weinhold // page_handler to a label that is obviously (to the compiler) never used, 245*7afc16f0SIngo Weinhold // it may reorganize the control flow, so that the labeled part is optimized 246*7afc16f0SIngo Weinhold // away. 247*7afc16f0SIngo Weinhold // By invoking the function like this 248*7afc16f0SIngo Weinhold // 249*7afc16f0SIngo Weinhold // if (ppc_set_fault_handler(faultHandler, (addr_t)&&error)) 250*7afc16f0SIngo Weinhold // goto error; 251*7afc16f0SIngo Weinhold // 252*7afc16f0SIngo Weinhold // the compiler has to keep the labeled code, since it can't guess the return 253*7afc16f0SIngo Weinhold // value of this (non-inlinable) function. At least in my tests it worked that 254*7afc16f0SIngo Weinhold // way, and I hope it will continue to work like this in the future. 255*7afc16f0SIngo Weinhold // 256*7afc16f0SIngo Weinhold bool 257*7afc16f0SIngo Weinhold ppc_set_fault_handler(addr_t *handlerLocation, addr_t handler) 258*7afc16f0SIngo Weinhold { 259*7afc16f0SIngo Weinhold *handlerLocation = handler; 260*7afc16f0SIngo Weinhold return false; 261*7afc16f0SIngo Weinhold } 262