xref: /haiku/src/system/kernel/arch/ppc/arch_cpu.cpp (revision d0648592cae51dcbbbe37c413eab7279793bc99e)
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 
17*d0648592SIngo Weinhold static bool sHasTlbia;
188baf8813SIngo Weinhold 
198baf8813SIngo Weinhold status_t
208baf8813SIngo Weinhold arch_cpu_preboot_init(kernel_args *args)
218baf8813SIngo Weinhold {
226c678c57SIngo Weinhold 	// The current thread must be NULL for all CPUs till we have threads.
236c678c57SIngo Weinhold 	// Some boot code relies on this.
246c678c57SIngo Weinhold 	arch_thread_set_current_thread(NULL);
256c678c57SIngo Weinhold 
268baf8813SIngo Weinhold 	return B_OK;
278baf8813SIngo Weinhold }
288baf8813SIngo Weinhold 
298baf8813SIngo Weinhold 
308baf8813SIngo Weinhold status_t
318baf8813SIngo Weinhold arch_cpu_init(kernel_args *args)
328baf8813SIngo Weinhold {
33*d0648592SIngo Weinhold 	// TODO: Let the boot loader put that info into the kernel args
34*d0648592SIngo Weinhold 	// (property "tlbia" in the CPU node).
35*d0648592SIngo Weinhold 	sHasTlbia = false;
36*d0648592SIngo Weinhold 
378baf8813SIngo Weinhold 	return B_OK;
388baf8813SIngo Weinhold }
398baf8813SIngo Weinhold 
408baf8813SIngo Weinhold 
418baf8813SIngo Weinhold status_t
428baf8813SIngo Weinhold arch_cpu_init_post_vm(kernel_args *args)
438baf8813SIngo Weinhold {
448baf8813SIngo Weinhold 	return B_OK;
458baf8813SIngo Weinhold }
468baf8813SIngo Weinhold 
478baf8813SIngo Weinhold status_t
488baf8813SIngo Weinhold arch_cpu_init_post_modules(kernel_args *args)
498baf8813SIngo Weinhold {
508baf8813SIngo Weinhold 	return B_OK;
518baf8813SIngo Weinhold }
528baf8813SIngo Weinhold 
538baf8813SIngo Weinhold #define CACHELINE 32
548baf8813SIngo Weinhold 
558baf8813SIngo Weinhold void
568baf8813SIngo Weinhold arch_cpu_sync_icache(void *address, size_t len)
578baf8813SIngo Weinhold {
588baf8813SIngo Weinhold 	int l, off;
598baf8813SIngo Weinhold 	char *p;
608baf8813SIngo Weinhold 
618baf8813SIngo Weinhold 	off = (unsigned int)address & (CACHELINE - 1);
628baf8813SIngo Weinhold 	len += off;
638baf8813SIngo Weinhold 
648baf8813SIngo Weinhold 	l = len;
658baf8813SIngo Weinhold 	p = (char *)address - off;
668baf8813SIngo Weinhold 	do {
678baf8813SIngo Weinhold 		asm volatile ("dcbst 0,%0" :: "r"(p));
688baf8813SIngo Weinhold 		p += CACHELINE;
698baf8813SIngo Weinhold 	} while ((l -= CACHELINE) > 0);
708baf8813SIngo Weinhold 	asm volatile ("sync");
718baf8813SIngo Weinhold 
728baf8813SIngo Weinhold 	p = (char *)address - off;
738baf8813SIngo Weinhold 	do {
748baf8813SIngo Weinhold 		asm volatile ("icbi 0,%0" :: "r"(p));
758baf8813SIngo Weinhold 		p += CACHELINE;
768baf8813SIngo Weinhold 	} while ((len -= CACHELINE) > 0);
778baf8813SIngo Weinhold 	asm volatile ("sync");
788baf8813SIngo Weinhold 	isync();
798baf8813SIngo Weinhold }
808baf8813SIngo Weinhold 
818baf8813SIngo Weinhold 
828baf8813SIngo Weinhold void
838baf8813SIngo Weinhold arch_cpu_invalidate_TLB_range(addr_t start, addr_t end)
848baf8813SIngo Weinhold {
858baf8813SIngo Weinhold 	asm volatile("sync");
868baf8813SIngo Weinhold 	while (start < end) {
878baf8813SIngo Weinhold 		asm volatile("tlbie %0" :: "r" (start));
888baf8813SIngo Weinhold 		asm volatile("eieio");
898baf8813SIngo Weinhold 		asm volatile("sync");
908baf8813SIngo Weinhold 		start += B_PAGE_SIZE;
918baf8813SIngo Weinhold 	}
928baf8813SIngo Weinhold 	asm volatile("tlbsync");
938baf8813SIngo Weinhold 	asm volatile("sync");
948baf8813SIngo Weinhold }
958baf8813SIngo Weinhold 
968baf8813SIngo Weinhold 
978baf8813SIngo Weinhold void
988baf8813SIngo Weinhold arch_cpu_invalidate_TLB_list(addr_t pages[], int num_pages)
998baf8813SIngo Weinhold {
1008baf8813SIngo Weinhold 	int i;
1018baf8813SIngo Weinhold 
1028baf8813SIngo Weinhold 	asm volatile("sync");
1038baf8813SIngo Weinhold 	for (i = 0; i < num_pages; i++) {
1048baf8813SIngo Weinhold 		asm volatile("tlbie %0" :: "r" (pages[i]));
1058baf8813SIngo Weinhold 		asm volatile("eieio");
1068baf8813SIngo Weinhold 		asm volatile("sync");
1078baf8813SIngo Weinhold 	}
1088baf8813SIngo Weinhold 	asm volatile("tlbsync");
1098baf8813SIngo Weinhold 	asm volatile("sync");
1108baf8813SIngo Weinhold }
1118baf8813SIngo Weinhold 
1128baf8813SIngo Weinhold 
1138baf8813SIngo Weinhold void
1148baf8813SIngo Weinhold arch_cpu_global_TLB_invalidate(void)
1158baf8813SIngo Weinhold {
116*d0648592SIngo Weinhold 	if (sHasTlbia) {
1178baf8813SIngo Weinhold 		ppc_sync();
1188baf8813SIngo Weinhold 		tlbia();
1198baf8813SIngo Weinhold 		ppc_sync();
120*d0648592SIngo Weinhold 	} else {
121*d0648592SIngo Weinhold 		addr_t address = 0;
122*d0648592SIngo Weinhold 		unsigned long i;
123*d0648592SIngo Weinhold 
124*d0648592SIngo Weinhold 		ppc_sync();
125*d0648592SIngo Weinhold 		for (i = 0; i < 0x100000; i++) {
126*d0648592SIngo Weinhold 			tlbie(address);
127*d0648592SIngo Weinhold 			eieio();
128*d0648592SIngo Weinhold 			ppc_sync();
129*d0648592SIngo Weinhold 
130*d0648592SIngo Weinhold 			address += B_PAGE_SIZE;
131*d0648592SIngo Weinhold 		}
132*d0648592SIngo Weinhold 		tlbsync();
133*d0648592SIngo Weinhold 		ppc_sync();
134*d0648592SIngo Weinhold 	}
1358baf8813SIngo Weinhold }
1368baf8813SIngo Weinhold 
1378baf8813SIngo Weinhold 
1388baf8813SIngo Weinhold void
1398baf8813SIngo Weinhold arch_cpu_user_TLB_invalidate(void)
1408baf8813SIngo Weinhold {
141*d0648592SIngo Weinhold 	arch_cpu_global_TLB_invalidate();
1428baf8813SIngo Weinhold }
1438baf8813SIngo Weinhold 
1448baf8813SIngo Weinhold 
1458baf8813SIngo Weinhold status_t
1468baf8813SIngo Weinhold arch_cpu_user_memcpy(void *to, const void *from, size_t size, addr_t *fault_handler)
1478baf8813SIngo Weinhold {
1488baf8813SIngo Weinhold 	char *tmp = (char *)to;
1498baf8813SIngo Weinhold 	char *s = (char *)from;
1508baf8813SIngo Weinhold 
1518baf8813SIngo Weinhold 	*fault_handler = (addr_t)&&error;
1528baf8813SIngo Weinhold 
1538baf8813SIngo Weinhold 	while (size--)
1548baf8813SIngo Weinhold 		*tmp++ = *s++;
1558baf8813SIngo Weinhold 
1568baf8813SIngo Weinhold 	*fault_handler = 0;
1578baf8813SIngo Weinhold 	return 0;
1588baf8813SIngo Weinhold 
1598baf8813SIngo Weinhold error:
1608baf8813SIngo Weinhold 	*fault_handler = 0;
1618baf8813SIngo Weinhold 	return B_BAD_ADDRESS;
1628baf8813SIngo Weinhold }
1638baf8813SIngo Weinhold 
1648baf8813SIngo Weinhold 
1658baf8813SIngo Weinhold /**	\brief Copies at most (\a size - 1) characters from the string in \a from to
1668baf8813SIngo Weinhold  *	the string in \a to, NULL-terminating the result.
1678baf8813SIngo Weinhold  *
1688baf8813SIngo Weinhold  *	\param to Pointer to the destination C-string.
1698baf8813SIngo Weinhold  *	\param from Pointer to the source C-string.
1708baf8813SIngo Weinhold  *	\param size Size in bytes of the string buffer pointed to by \a to.
1718baf8813SIngo Weinhold  *
1728baf8813SIngo Weinhold  *	\return strlen(\a from).
1738baf8813SIngo Weinhold  */
1748baf8813SIngo Weinhold 
1758baf8813SIngo Weinhold ssize_t
1768baf8813SIngo Weinhold arch_cpu_user_strlcpy(char *to, const char *from, size_t size, addr_t *faultHandler)
1778baf8813SIngo Weinhold {
1788baf8813SIngo Weinhold 	int from_length = 0;
1798baf8813SIngo Weinhold 
1808baf8813SIngo Weinhold 	*faultHandler = (addr_t)&&error;
1818baf8813SIngo Weinhold 
1828baf8813SIngo Weinhold 	if (size > 0) {
1838baf8813SIngo Weinhold 		to[--size] = '\0';
1848baf8813SIngo Weinhold 		// copy
1858baf8813SIngo Weinhold 		for ( ; size; size--, from_length++, to++, from++) {
1868baf8813SIngo Weinhold 			if ((*to = *from) == '\0')
1878baf8813SIngo Weinhold 				break;
1888baf8813SIngo Weinhold 		}
1898baf8813SIngo Weinhold 	}
1908baf8813SIngo Weinhold 	// count any leftover from chars
1918baf8813SIngo Weinhold 	while (*from++ != '\0')
1928baf8813SIngo Weinhold 		from_length++;
1938baf8813SIngo Weinhold 
1948baf8813SIngo Weinhold 	*faultHandler = 0;
1958baf8813SIngo Weinhold 	return from_length;
1968baf8813SIngo Weinhold 
1978baf8813SIngo Weinhold error:
1988baf8813SIngo Weinhold 	*faultHandler = 0;
1998baf8813SIngo Weinhold 	return B_BAD_ADDRESS;
2008baf8813SIngo Weinhold }
2018baf8813SIngo Weinhold 
2028baf8813SIngo Weinhold 
2038baf8813SIngo Weinhold status_t
2048baf8813SIngo Weinhold arch_cpu_user_memset(void *s, char c, size_t count, addr_t *fault_handler)
2058baf8813SIngo Weinhold {
2068baf8813SIngo Weinhold 	char *xs = (char *)s;
2078baf8813SIngo Weinhold 
2088baf8813SIngo Weinhold 	*fault_handler = (addr_t)&&error;
2098baf8813SIngo Weinhold 
2108baf8813SIngo Weinhold 	while (count--)
2118baf8813SIngo Weinhold 		*xs++ = c;
2128baf8813SIngo Weinhold 
2138baf8813SIngo Weinhold 	*fault_handler = 0;
2148baf8813SIngo Weinhold 	return 0;
2158baf8813SIngo Weinhold 
2168baf8813SIngo Weinhold error:
2178baf8813SIngo Weinhold 	*fault_handler = 0;
2188baf8813SIngo Weinhold 	return B_BAD_ADDRESS;
2198baf8813SIngo Weinhold }
2208baf8813SIngo Weinhold 
2218baf8813SIngo Weinhold 
2228baf8813SIngo Weinhold status_t
2238baf8813SIngo Weinhold arch_cpu_shutdown(bool reboot)
2248baf8813SIngo Weinhold {
2258baf8813SIngo Weinhold 	PPCPlatform::Default()->ShutDown(reboot);
2268baf8813SIngo Weinhold 	return B_ERROR;
2278baf8813SIngo Weinhold }
2288baf8813SIngo Weinhold 
2298baf8813SIngo Weinhold 
2308baf8813SIngo Weinhold void
2318baf8813SIngo Weinhold arch_cpu_idle(void)
2328baf8813SIngo Weinhold {
2338baf8813SIngo Weinhold }
2348baf8813SIngo Weinhold 
235