xref: /haiku/src/system/kernel/arch/ppc/arch_cpu.cpp (revision 4b8d0e68569c871608f13fc5f5f5776a6846a2f2)
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
51*4b8d0e68SFrançois Revol arch_cpu_init_percpu(kernel_args *args, int curr_cpu)
52*4b8d0e68SFrançois Revol {
53*4b8d0e68SFrançois Revol         //detect_cpu(curr_cpu);
54*4b8d0e68SFrançois Revol 
55*4b8d0e68SFrançois Revol         // we only support one on ppc anyway at the moment...
56*4b8d0e68SFrançois Revol 	//XXX: WRITEME
57*4b8d0e68SFrançois Revol         return 0;
58*4b8d0e68SFrançois Revol }
59*4b8d0e68SFrançois Revol 
60*4b8d0e68SFranç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 
1837afc16f0SIngo Weinhold 	if (ppc_set_fault_handler(faultHandler, (addr_t)&&error))
1847afc16f0SIngo Weinhold 		goto error;
1858baf8813SIngo Weinhold 
1868baf8813SIngo Weinhold 	while (size--)
1878baf8813SIngo Weinhold 		*tmp++ = *s++;
1888baf8813SIngo Weinhold 
189962b0b88SIngo Weinhold 	*faultHandler = oldFaultHandler;
1908baf8813SIngo Weinhold 	return 0;
1918baf8813SIngo Weinhold 
1928baf8813SIngo Weinhold error:
193962b0b88SIngo Weinhold 	*faultHandler = oldFaultHandler;
1948baf8813SIngo Weinhold 	return B_BAD_ADDRESS;
1958baf8813SIngo Weinhold }
1968baf8813SIngo Weinhold 
1978baf8813SIngo Weinhold 
1988baf8813SIngo Weinhold /**	\brief Copies at most (\a size - 1) characters from the string in \a from to
1998baf8813SIngo Weinhold  *	the string in \a to, NULL-terminating the result.
2008baf8813SIngo Weinhold  *
2018baf8813SIngo Weinhold  *	\param to Pointer to the destination C-string.
2028baf8813SIngo Weinhold  *	\param from Pointer to the source C-string.
2038baf8813SIngo Weinhold  *	\param size Size in bytes of the string buffer pointed to by \a to.
2048baf8813SIngo Weinhold  *
2058baf8813SIngo Weinhold  *	\return strlen(\a from).
2068baf8813SIngo Weinhold  */
2078baf8813SIngo Weinhold 
2088baf8813SIngo Weinhold ssize_t
2098baf8813SIngo Weinhold arch_cpu_user_strlcpy(char *to, const char *from, size_t size, addr_t *faultHandler)
2108baf8813SIngo Weinhold {
2118baf8813SIngo Weinhold 	int from_length = 0;
212962b0b88SIngo Weinhold 	addr_t oldFaultHandler = *faultHandler;
2138baf8813SIngo Weinhold 
2147afc16f0SIngo Weinhold 	if (ppc_set_fault_handler(faultHandler, (addr_t)&&error))
2157afc16f0SIngo Weinhold 		goto error;
2168baf8813SIngo Weinhold 
2178baf8813SIngo Weinhold 	if (size > 0) {
2188baf8813SIngo Weinhold 		to[--size] = '\0';
2198baf8813SIngo Weinhold 		// copy
2208baf8813SIngo Weinhold 		for ( ; size; size--, from_length++, to++, from++) {
2218baf8813SIngo Weinhold 			if ((*to = *from) == '\0')
2228baf8813SIngo Weinhold 				break;
2238baf8813SIngo Weinhold 		}
2248baf8813SIngo Weinhold 	}
2258baf8813SIngo Weinhold 	// count any leftover from chars
2268baf8813SIngo Weinhold 	while (*from++ != '\0')
2278baf8813SIngo Weinhold 		from_length++;
2288baf8813SIngo Weinhold 
229962b0b88SIngo Weinhold 	*faultHandler = oldFaultHandler;
2308baf8813SIngo Weinhold 	return from_length;
2318baf8813SIngo Weinhold 
2328baf8813SIngo Weinhold error:
233962b0b88SIngo Weinhold 	*faultHandler = oldFaultHandler;
2348baf8813SIngo Weinhold 	return B_BAD_ADDRESS;
2358baf8813SIngo Weinhold }
2368baf8813SIngo Weinhold 
2378baf8813SIngo Weinhold 
2388baf8813SIngo Weinhold status_t
2397afc16f0SIngo Weinhold arch_cpu_user_memset(void *s, char c, size_t count, addr_t *faultHandler)
2408baf8813SIngo Weinhold {
2418baf8813SIngo Weinhold 	char *xs = (char *)s;
242962b0b88SIngo Weinhold 	addr_t oldFaultHandler = *faultHandler;
2438baf8813SIngo Weinhold 
2447afc16f0SIngo Weinhold 	if (ppc_set_fault_handler(faultHandler, (addr_t)&&error))
2457afc16f0SIngo Weinhold 		goto error;
2468baf8813SIngo Weinhold 
2478baf8813SIngo Weinhold 	while (count--)
2488baf8813SIngo Weinhold 		*xs++ = c;
2498baf8813SIngo Weinhold 
250962b0b88SIngo Weinhold 	*faultHandler = oldFaultHandler;
2518baf8813SIngo Weinhold 	return 0;
2528baf8813SIngo Weinhold 
2538baf8813SIngo Weinhold error:
254962b0b88SIngo Weinhold 	*faultHandler = oldFaultHandler;
2558baf8813SIngo Weinhold 	return B_BAD_ADDRESS;
2568baf8813SIngo Weinhold }
2578baf8813SIngo Weinhold 
2588baf8813SIngo Weinhold 
2598baf8813SIngo Weinhold status_t
2608baf8813SIngo Weinhold arch_cpu_shutdown(bool reboot)
2618baf8813SIngo Weinhold {
2628baf8813SIngo Weinhold 	PPCPlatform::Default()->ShutDown(reboot);
2638baf8813SIngo Weinhold 	return B_ERROR;
2648baf8813SIngo Weinhold }
2658baf8813SIngo Weinhold 
2668baf8813SIngo Weinhold 
2678baf8813SIngo Weinhold void
2688baf8813SIngo Weinhold arch_cpu_idle(void)
2698baf8813SIngo Weinhold {
2708baf8813SIngo Weinhold }
2718baf8813SIngo Weinhold 
2727afc16f0SIngo 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
2877afc16f0SIngo Weinhold ppc_set_fault_handler(addr_t *handlerLocation, addr_t handler)
2887afc16f0SIngo Weinhold {
2897afc16f0SIngo Weinhold 	*handlerLocation = handler;
2907afc16f0SIngo Weinhold 	return false;
2917afc16f0SIngo Weinhold }
292