xref: /haiku/src/system/kernel/arch/ppc/arch_cpu.cpp (revision 88c54b548550f298727c450f2330cdfd59533ad9)
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