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