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>
138baf8813SIngo Weinhold #include <arch/cpu.h>
146ec9dff3SJérôme Duval #include <arch/thread.h>
158baf8813SIngo Weinhold #include <boot/kernel_args.h>
168baf8813SIngo Weinhold
17d0648592SIngo Weinhold static bool sHasTlbia;
188baf8813SIngo Weinhold
198baf8813SIngo Weinhold status_t
arch_cpu_preboot_init_percpu(kernel_args * args,int curr_cpu)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
arch_cpu_init(kernel_args * args)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
arch_cpu_init_post_vm(kernel_args * args)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
arch_cpu_init_percpu(kernel_args * args,int curr_cpu)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
arch_cpu_init_post_modules(kernel_args * args)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
arch_cpu_sync_icache(void * address,size_t len)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
arch_cpu_memory_read_barrier(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
arch_cpu_memory_write_barrier(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
arch_cpu_invalidate_TLB_range(addr_t start,addr_t end)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
arch_cpu_invalidate_TLB_list(addr_t pages[],int num_pages)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
arch_cpu_global_TLB_invalidate(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
arch_cpu_user_TLB_invalidate(void)1698baf8813SIngo Weinhold arch_cpu_user_TLB_invalidate(void)
1708baf8813SIngo Weinhold {
171d0648592SIngo Weinhold arch_cpu_global_TLB_invalidate();
1728baf8813SIngo Weinhold }
1738baf8813SIngo Weinhold
1748baf8813SIngo Weinhold
175*dc5a16bbSRene Gollent // TODO: all functions that use fault handlers need to be implemented
176*dc5a16bbSRene Gollent // in assembly due to problems passing in label addresses in gcc4.
177*dc5a16bbSRene Gollent
1788baf8813SIngo Weinhold status_t
arch_cpu_user_memcpy(void * to,const void * from,size_t size,addr_t * faultHandler)1797afc16f0SIngo Weinhold arch_cpu_user_memcpy(void *to, const void *from, size_t size,
1807afc16f0SIngo Weinhold addr_t *faultHandler)
1818baf8813SIngo Weinhold {
1828baf8813SIngo Weinhold char *tmp = (char *)to;
1838baf8813SIngo Weinhold char *s = (char *)from;
184962b0b88SIngo Weinhold addr_t oldFaultHandler = *faultHandler;
1858baf8813SIngo Weinhold
186ea2abd11SIngo Weinhold // TODO: This doesn't work correctly with gcc 4 anymore!
1877afc16f0SIngo Weinhold if (ppc_set_fault_handler(faultHandler, (addr_t)&&error))
1887afc16f0SIngo Weinhold goto error;
1898baf8813SIngo Weinhold
1908baf8813SIngo Weinhold while (size--)
1918baf8813SIngo Weinhold *tmp++ = *s++;
1928baf8813SIngo Weinhold
193962b0b88SIngo Weinhold *faultHandler = oldFaultHandler;
1948baf8813SIngo Weinhold return 0;
1958baf8813SIngo Weinhold
1968baf8813SIngo Weinhold error:
197962b0b88SIngo Weinhold *faultHandler = oldFaultHandler;
1988baf8813SIngo Weinhold return B_BAD_ADDRESS;
1998baf8813SIngo Weinhold }
2008baf8813SIngo Weinhold
2018baf8813SIngo Weinhold
2028baf8813SIngo Weinhold /** \brief Copies at most (\a size - 1) characters from the string in \a from to
2038baf8813SIngo Weinhold * the string in \a to, NULL-terminating the result.
2048baf8813SIngo Weinhold *
2058baf8813SIngo Weinhold * \param to Pointer to the destination C-string.
2068baf8813SIngo Weinhold * \param from Pointer to the source C-string.
2078baf8813SIngo Weinhold * \param size Size in bytes of the string buffer pointed to by \a to.
2088baf8813SIngo Weinhold *
2098baf8813SIngo Weinhold * \return strlen(\a from).
2108baf8813SIngo Weinhold */
2118baf8813SIngo Weinhold
2128baf8813SIngo Weinhold ssize_t
arch_cpu_user_strlcpy(char * to,const char * from,size_t size,addr_t * faultHandler)2138baf8813SIngo Weinhold arch_cpu_user_strlcpy(char *to, const char *from, size_t size, addr_t *faultHandler)
2148baf8813SIngo Weinhold {
2158baf8813SIngo Weinhold int from_length = 0;
216962b0b88SIngo Weinhold addr_t oldFaultHandler = *faultHandler;
2178baf8813SIngo Weinhold
218ea2abd11SIngo Weinhold // TODO: This doesn't work correctly with gcc 4 anymore!
2197afc16f0SIngo Weinhold if (ppc_set_fault_handler(faultHandler, (addr_t)&&error))
2207afc16f0SIngo Weinhold goto error;
2218baf8813SIngo Weinhold
2228baf8813SIngo Weinhold if (size > 0) {
2238baf8813SIngo Weinhold to[--size] = '\0';
2248baf8813SIngo Weinhold // copy
2258baf8813SIngo Weinhold for ( ; size; size--, from_length++, to++, from++) {
2268baf8813SIngo Weinhold if ((*to = *from) == '\0')
2278baf8813SIngo Weinhold break;
2288baf8813SIngo Weinhold }
2298baf8813SIngo Weinhold }
2308baf8813SIngo Weinhold // count any leftover from chars
2318baf8813SIngo Weinhold while (*from++ != '\0')
2328baf8813SIngo Weinhold from_length++;
2338baf8813SIngo Weinhold
234962b0b88SIngo Weinhold *faultHandler = oldFaultHandler;
2358baf8813SIngo Weinhold return from_length;
2368baf8813SIngo Weinhold
2378baf8813SIngo Weinhold error:
238962b0b88SIngo Weinhold *faultHandler = oldFaultHandler;
2398baf8813SIngo Weinhold return B_BAD_ADDRESS;
2408baf8813SIngo Weinhold }
2418baf8813SIngo Weinhold
2428baf8813SIngo Weinhold
2438baf8813SIngo Weinhold status_t
arch_cpu_user_memset(void * s,char c,size_t count,addr_t * faultHandler)2447afc16f0SIngo Weinhold arch_cpu_user_memset(void *s, char c, size_t count, addr_t *faultHandler)
2458baf8813SIngo Weinhold {
2468baf8813SIngo Weinhold char *xs = (char *)s;
247962b0b88SIngo Weinhold addr_t oldFaultHandler = *faultHandler;
2488baf8813SIngo Weinhold
249ea2abd11SIngo Weinhold // TODO: This doesn't work correctly with gcc 4 anymore!
2507afc16f0SIngo Weinhold if (ppc_set_fault_handler(faultHandler, (addr_t)&&error))
2517afc16f0SIngo Weinhold goto error;
2528baf8813SIngo Weinhold
2538baf8813SIngo Weinhold while (count--)
2548baf8813SIngo Weinhold *xs++ = c;
2558baf8813SIngo Weinhold
256962b0b88SIngo Weinhold *faultHandler = oldFaultHandler;
2578baf8813SIngo Weinhold return 0;
2588baf8813SIngo Weinhold
2598baf8813SIngo Weinhold error:
260962b0b88SIngo Weinhold *faultHandler = oldFaultHandler;
2618baf8813SIngo Weinhold return B_BAD_ADDRESS;
2628baf8813SIngo Weinhold }
2638baf8813SIngo Weinhold
2648baf8813SIngo Weinhold
2658baf8813SIngo Weinhold status_t
arch_cpu_shutdown(bool reboot)2668baf8813SIngo Weinhold arch_cpu_shutdown(bool reboot)
2678baf8813SIngo Weinhold {
2688baf8813SIngo Weinhold PPCPlatform::Default()->ShutDown(reboot);
2698baf8813SIngo Weinhold return B_ERROR;
2708baf8813SIngo Weinhold }
2718baf8813SIngo Weinhold
2728baf8813SIngo Weinhold
2737afc16f0SIngo Weinhold // The purpose of this function is to trick the compiler. When setting the
2747afc16f0SIngo Weinhold // page_handler to a label that is obviously (to the compiler) never used,
2757afc16f0SIngo Weinhold // it may reorganize the control flow, so that the labeled part is optimized
2767afc16f0SIngo Weinhold // away.
2777afc16f0SIngo Weinhold // By invoking the function like this
2787afc16f0SIngo Weinhold //
2797afc16f0SIngo Weinhold // if (ppc_set_fault_handler(faultHandler, (addr_t)&&error))
2807afc16f0SIngo Weinhold // goto error;
2817afc16f0SIngo Weinhold //
2827afc16f0SIngo Weinhold // the compiler has to keep the labeled code, since it can't guess the return
2837afc16f0SIngo Weinhold // value of this (non-inlinable) function. At least in my tests it worked that
2847afc16f0SIngo Weinhold // way, and I hope it will continue to work like this in the future.
2857afc16f0SIngo Weinhold //
2867afc16f0SIngo Weinhold bool
ppc_set_fault_handler(addr_t * handlerLocation,addr_t handler)2877afc16f0SIngo Weinhold ppc_set_fault_handler(addr_t *handlerLocation, addr_t handler)
2887afc16f0SIngo Weinhold {
289ea2abd11SIngo Weinhold // TODO: This doesn't work correctly with gcc 4 anymore!
2907afc16f0SIngo Weinhold *handlerLocation = handler;
2917afc16f0SIngo Weinhold return false;
2927afc16f0SIngo Weinhold }
293