xref: /haiku/src/system/kernel/arch/m68k/arch_cpu.cpp (revision f0c5a3da4b596f2d3de4cfa6478ee8f5c1c2f60b)
1845a180fSFrançois Revol /*
24e44040dSFrançois Revol  * Copyright 2007, François Revol, revol@free.fr.
34e44040dSFrançois Revol  * Distributed under the terms of the MIT License.
44e44040dSFrançois Revol  *
5845a180fSFrançois Revol  * Copyright 2003-2005, Axel Dörfler, axeld@pinc-software.de.
6845a180fSFrançois Revol  * Distributed under the terms of the MIT License.
7845a180fSFrançois Revol  *
8845a180fSFrançois Revol  * Copyright 2001, Travis Geiselbrecht. All rights reserved.
9845a180fSFrançois Revol  * Distributed under the terms of the NewOS License.
10845a180fSFrançois Revol  */
11845a180fSFrançois Revol 
12845a180fSFrançois Revol 
13845a180fSFrançois Revol #include <KernelExport.h>
14845a180fSFrançois Revol 
15845a180fSFrançois Revol #include <arch_platform.h>
16845a180fSFrançois Revol #include <arch_thread.h>
17845a180fSFrançois Revol #include <arch/cpu.h>
18845a180fSFrançois Revol #include <boot/kernel_args.h>
19845a180fSFrançois Revol 
204e44040dSFrançois Revol extern struct m68k_cpu_ops cpu_ops_030;
214e44040dSFrançois Revol extern struct m68k_cpu_ops cpu_ops_040;
224e44040dSFrançois Revol extern struct m68k_cpu_ops cpu_ops_060;
234e44040dSFrançois Revol 
244e44040dSFrançois Revol struct m68k_cpu_ops cpu_ops;
254e44040dSFrançois Revol 
26*f0c5a3daSFrançois Revol int arch_cpu_type;
27*f0c5a3daSFrançois Revol int arch_fpu_type;
28*f0c5a3daSFrançois Revol int arch_mmu_type;
29*f0c5a3daSFrançois Revol int arch_platform;
30*f0c5a3daSFrançois Revol 
31845a180fSFrançois Revol status_t
32845a180fSFrançois Revol arch_cpu_preboot_init_percpu(kernel_args *args, int curr_cpu)
33845a180fSFrançois Revol {
34845a180fSFrançois Revol 	// enable FPU
35829748d8SFrançois Revol 	//ppc:set_msr(get_msr() | MSR_FP_AVAILABLE);
36845a180fSFrançois Revol 
37845a180fSFrançois Revol 	// The current thread must be NULL for all CPUs till we have threads.
38845a180fSFrançois Revol 	// Some boot code relies on this.
39845a180fSFrançois Revol 	arch_thread_set_current_thread(NULL);
40845a180fSFrançois Revol 
41845a180fSFrançois Revol 	return B_OK;
42845a180fSFrançois Revol }
43845a180fSFrançois Revol 
44845a180fSFrançois Revol 
45845a180fSFrançois Revol status_t
46845a180fSFrançois Revol arch_cpu_init(kernel_args *args)
47845a180fSFrançois Revol {
48a3dc7ef0SFrançois Revol 	arch_cpu_type = args->arch_args.cpu_type;
49a3dc7ef0SFrançois Revol 	arch_fpu_type = args->arch_args.fpu_type;
50a3dc7ef0SFrançois Revol 	arch_mmu_type = args->arch_args.mmu_type;
51a3dc7ef0SFrançois Revol 	arch_platform = args->arch_args.platform;
52*f0c5a3daSFrançois Revol 	arch_platform = args->arch_args.machine;
53a3dc7ef0SFrançois Revol 	void (*flush_insn_pipeline)(void);
54a3dc7ef0SFrançois Revol 	void (*flush_atc_all)(void);
55a3dc7ef0SFrançois Revol 	void (*flush_atc_user)(void);
56a3dc7ef0SFrançois Revol 	void (*flush_atc_addr)(void *addr);
57a3dc7ef0SFrançois Revol 	void (*flush_dcache)(void *address, size_t len);
58a3dc7ef0SFrançois Revol 	void (*flush_icache)(void *address, size_t len);
59a3dc7ef0SFrançois Revol 	void (*idle)(void);
604e44040dSFrançois Revol 
61a3dc7ef0SFrançois Revol 	switch (arch_cpu_type) {
62a3dc7ef0SFrançois Revol 		case 68020:
63a3dc7ef0SFrançois Revol 		case 68030:
644e44040dSFrançois Revol 			cpu_ops.flush_insn_pipeline = cpu_ops_030.flush_insn_pipeline;
654e44040dSFrançois Revol 			cpu_ops.flush_atc_all = cpu_ops_030.flush_atc_all;
664e44040dSFrançois Revol 			cpu_ops.flush_atc_user = cpu_ops_030.flush_atc_user;
674e44040dSFrançois Revol 			cpu_ops.flush_atc_addr = cpu_ops_030.flush_atc_addr;
68a3dc7ef0SFrançois Revol 			cpu_ops.flush_dcache = cpu_ops_030.flush_dcache;
69a3dc7ef0SFrançois Revol 			cpu_ops.flush_icache = cpu_ops_030.flush_icache;
704e44040dSFrançois Revol 			cpu_ops.idle = cpu_ops_030.idle; // NULL
714e44040dSFrançois Revol 			break;
724e44040dSFrançois Revol #ifdef SUPPORTS_040
73a3dc7ef0SFrançois Revol 		case 68040:
744e44040dSFrançois Revol 			cpu_ops.flush_insn_pipeline = cpu_ops_040.flush_insn_pipeline;
754e44040dSFrançois Revol 			cpu_ops.flush_atc_all = cpu_ops_040.flush_atc_all;
764e44040dSFrançois Revol 			cpu_ops.flush_atc_user = cpu_ops_040.flush_atc_user;
774e44040dSFrançois Revol 			cpu_ops.flush_atc_addr = cpu_ops_040.flush_atc_addr;
78a3dc7ef0SFrançois Revol 			cpu_ops.flush_dcache = cpu_ops_040.flush_dcache;
79a3dc7ef0SFrançois Revol 			cpu_ops.flush_icache = cpu_ops_040.flush_icache;
804e44040dSFrançois Revol 			cpu_ops.idle = cpu_ops_040.idle; // NULL
814e44040dSFrançois Revol 			break;
824e44040dSFrançois Revol #endif
834e44040dSFrançois Revol #ifdef SUPPORTS_060
84a3dc7ef0SFrançois Revol 		case 68060:
854e44040dSFrançois Revol 			cpu_ops.flush_insn_pipeline = cpu_ops_060.flush_insn_pipeline;
864e44040dSFrançois Revol 			cpu_ops.flush_atc_all = cpu_ops_060.flush_atc_all;
874e44040dSFrançois Revol 			cpu_ops.flush_atc_user = cpu_ops_060.flush_atc_user;
884e44040dSFrançois Revol 			cpu_ops.flush_atc_addr = cpu_ops_060.flush_atc_addr;
89a3dc7ef0SFrançois Revol 			cpu_ops.flush_dcache = cpu_ops_060.flush_dcache;
90a3dc7ef0SFrançois Revol 			cpu_ops.flush_icache = cpu_ops_060.flush_icache;
914e44040dSFrançois Revol 			cpu_ops.idle = cpu_ops_060.idle;
924e44040dSFrançois Revol 		break;
934e44040dSFrançois Revol #endif
944e44040dSFrançois Revol 		default:
95a3dc7ef0SFrançois Revol 			panic("unknown cpu_type %d\n", arch_cpu_type);
964e44040dSFrançois Revol 	}
97a3dc7ef0SFrançois Revol 
98845a180fSFrançois Revol 	return B_OK;
99845a180fSFrançois Revol }
100845a180fSFrançois Revol 
101845a180fSFrançois Revol 
102845a180fSFrançois Revol status_t
103845a180fSFrançois Revol arch_cpu_init_post_vm(kernel_args *args)
104845a180fSFrançois Revol {
105845a180fSFrançois Revol 	return B_OK;
106845a180fSFrançois Revol }
107845a180fSFrançois Revol 
108845a180fSFrançois Revol status_t
109845a180fSFrançois Revol arch_cpu_init_post_modules(kernel_args *args)
110845a180fSFrançois Revol {
111845a180fSFrançois Revol 	return B_OK;
112845a180fSFrançois Revol }
113845a180fSFrançois Revol 
114845a180fSFrançois Revol 
115845a180fSFrançois Revol void
116845a180fSFrançois Revol arch_cpu_sync_icache(void *address, size_t len)
117845a180fSFrançois Revol {
118a3dc7ef0SFrançois Revol 	cpu_ops.flush_icache((addr_t)address, len);
119845a180fSFrançois Revol }
120845a180fSFrançois Revol 
121845a180fSFrançois Revol 
122845a180fSFrançois Revol void
123807cf76dSFrançois Revol arch_cpu_memory_read_barrier(void)
124807cf76dSFrançois Revol {
125807cf76dSFrançois Revol 	asm volatile ("nop;" : : : "memory");
126807cf76dSFrançois Revol #warning M68k: check arch_cpu_memory_read_barrier
127807cf76dSFrançois Revol }
128807cf76dSFrançois Revol 
129807cf76dSFrançois Revol 
130807cf76dSFrançois Revol void
131807cf76dSFrançois Revol arch_cpu_memory_write_barrier(void)
132807cf76dSFrançois Revol {
133807cf76dSFrançois Revol 	asm volatile ("nop;" : : : "memory");
134807cf76dSFrançois Revol #warning M68k: check arch_cpu_memory_write_barrier
135807cf76dSFrançois Revol }
136807cf76dSFrançois Revol 
137807cf76dSFrançois Revol 
138807cf76dSFrançois Revol void
139845a180fSFrançois Revol arch_cpu_invalidate_TLB_range(addr_t start, addr_t end)
140845a180fSFrançois Revol {
1414237dbd0SFrançois Revol 	int32 num_pages = end / B_PAGE_SIZE - start / B_PAGE_SIZE;
1424e44040dSFrançois Revol 	cpu_ops.flush_insn_pipeline();
1434237dbd0SFrançois Revol 	while (num_pages-- >= 0) {
1444e44040dSFrançois Revol 		cpu_ops.flush_atc_addr(start);
1454e44040dSFrançois Revol 		cpu_ops.flush_insn_pipeline();
146845a180fSFrançois Revol 		start += B_PAGE_SIZE;
147845a180fSFrançois Revol 	}
1484e44040dSFrançois Revol 	cpu_ops.flush_insn_pipeline();
149845a180fSFrançois Revol }
150845a180fSFrançois Revol 
151845a180fSFrançois Revol 
152845a180fSFrançois Revol void
153845a180fSFrançois Revol arch_cpu_invalidate_TLB_list(addr_t pages[], int num_pages)
154845a180fSFrançois Revol {
155845a180fSFrançois Revol 	int i;
156845a180fSFrançois Revol 
1574e44040dSFrançois Revol 	cpu_ops.flush_insn_pipeline();
158845a180fSFrançois Revol 	for (i = 0; i < num_pages; i++) {
1594e44040dSFrançois Revol 		cpu_ops.flush_atc_addr(pages[i]);
1604e44040dSFrançois Revol 		cpu_ops.flush_insn_pipeline();
161845a180fSFrançois Revol 	}
1624e44040dSFrançois Revol 	cpu_ops.flush_insn_pipeline();
163845a180fSFrançois Revol }
164845a180fSFrançois Revol 
165845a180fSFrançois Revol 
166845a180fSFrançois Revol void
167845a180fSFrançois Revol arch_cpu_global_TLB_invalidate(void)
168845a180fSFrançois Revol {
1694e44040dSFrançois Revol 	cpu_ops.flush_insn_pipeline();
1704e44040dSFrançois Revol 	cpu_ops.flush_atc_all();
1714e44040dSFrançois Revol 	cpu_ops.flush_insn_pipeline();
172845a180fSFrançois Revol }
173845a180fSFrançois Revol 
174845a180fSFrançois Revol 
175845a180fSFrançois Revol void
176845a180fSFrançois Revol arch_cpu_user_TLB_invalidate(void)
177845a180fSFrançois Revol {
1784e44040dSFrançois Revol 	cpu_ops.flush_insn_pipeline();
1794e44040dSFrançois Revol 	cpu_ops.flush_atc_user();
1804e44040dSFrançois Revol 	cpu_ops.flush_insn_pipeline();
181845a180fSFrançois Revol }
182845a180fSFrançois Revol 
183845a180fSFrançois Revol 
184845a180fSFrançois Revol status_t
185845a180fSFrançois Revol arch_cpu_user_memcpy(void *to, const void *from, size_t size,
186845a180fSFrançois Revol 	addr_t *faultHandler)
187845a180fSFrançois Revol {
188845a180fSFrançois Revol 	char *tmp = (char *)to;
189845a180fSFrançois Revol 	char *s = (char *)from;
190845a180fSFrançois Revol 	addr_t oldFaultHandler = *faultHandler;
191845a180fSFrançois Revol 
192845a180fSFrançois Revol 	if (m68k_set_fault_handler(faultHandler, (addr_t)&&error))
193845a180fSFrançois Revol 		goto error;
194845a180fSFrançois Revol 
195845a180fSFrançois Revol 	while (size--)
196845a180fSFrançois Revol 		*tmp++ = *s++;
197845a180fSFrançois Revol 
198845a180fSFrançois Revol 	*faultHandler = oldFaultHandler;
199845a180fSFrançois Revol 	return 0;
200845a180fSFrançois Revol 
201845a180fSFrançois Revol error:
202845a180fSFrançois Revol 	*faultHandler = oldFaultHandler;
203845a180fSFrançois Revol 	return B_BAD_ADDRESS;
204845a180fSFrançois Revol }
205845a180fSFrançois Revol 
206845a180fSFrançois Revol 
207845a180fSFrançois Revol /**	\brief Copies at most (\a size - 1) characters from the string in \a from to
208845a180fSFrançois Revol  *	the string in \a to, NULL-terminating the result.
209845a180fSFrançois Revol  *
210845a180fSFrançois Revol  *	\param to Pointer to the destination C-string.
211845a180fSFrançois Revol  *	\param from Pointer to the source C-string.
212845a180fSFrançois Revol  *	\param size Size in bytes of the string buffer pointed to by \a to.
213845a180fSFrançois Revol  *
214845a180fSFrançois Revol  *	\return strlen(\a from).
215845a180fSFrançois Revol  */
216845a180fSFrançois Revol 
217845a180fSFrançois Revol ssize_t
218845a180fSFrançois Revol arch_cpu_user_strlcpy(char *to, const char *from, size_t size, addr_t *faultHandler)
219845a180fSFrançois Revol {
220845a180fSFrançois Revol 	int from_length = 0;
221845a180fSFrançois Revol 	addr_t oldFaultHandler = *faultHandler;
222845a180fSFrançois Revol 
223845a180fSFrançois Revol 	if (m68k_set_fault_handler(faultHandler, (addr_t)&&error))
224845a180fSFrançois Revol 		goto error;
225845a180fSFrançois Revol 
226845a180fSFrançois Revol 	if (size > 0) {
227845a180fSFrançois Revol 		to[--size] = '\0';
228845a180fSFrançois Revol 		// copy
229845a180fSFrançois Revol 		for ( ; size; size--, from_length++, to++, from++) {
230845a180fSFrançois Revol 			if ((*to = *from) == '\0')
231845a180fSFrançois Revol 				break;
232845a180fSFrançois Revol 		}
233845a180fSFrançois Revol 	}
234845a180fSFrançois Revol 	// count any leftover from chars
235845a180fSFrançois Revol 	while (*from++ != '\0')
236845a180fSFrançois Revol 		from_length++;
237845a180fSFrançois Revol 
238845a180fSFrançois Revol 	*faultHandler = oldFaultHandler;
239845a180fSFrançois Revol 	return from_length;
240845a180fSFrançois Revol 
241845a180fSFrançois Revol error:
242845a180fSFrançois Revol 	*faultHandler = oldFaultHandler;
243845a180fSFrançois Revol 	return B_BAD_ADDRESS;
244845a180fSFrançois Revol }
245845a180fSFrançois Revol 
246845a180fSFrançois Revol 
247845a180fSFrançois Revol status_t
248845a180fSFrançois Revol arch_cpu_user_memset(void *s, char c, size_t count, addr_t *faultHandler)
249845a180fSFrançois Revol {
250845a180fSFrançois Revol 	char *xs = (char *)s;
251845a180fSFrançois Revol 	addr_t oldFaultHandler = *faultHandler;
252845a180fSFrançois Revol 
253845a180fSFrançois Revol 	if (m68k_set_fault_handler(faultHandler, (addr_t)&&error))
254845a180fSFrançois Revol 		goto error;
255845a180fSFrançois Revol 
256845a180fSFrançois Revol 	while (count--)
257845a180fSFrançois Revol 		*xs++ = c;
258845a180fSFrançois Revol 
259845a180fSFrançois Revol 	*faultHandler = oldFaultHandler;
260845a180fSFrançois Revol 	return 0;
261845a180fSFrançois Revol 
262845a180fSFrançois Revol error:
263845a180fSFrançois Revol 	*faultHandler = oldFaultHandler;
264845a180fSFrançois Revol 	return B_BAD_ADDRESS;
265845a180fSFrançois Revol }
266845a180fSFrançois Revol 
267845a180fSFrançois Revol 
268845a180fSFrançois Revol status_t
269845a180fSFrançois Revol arch_cpu_shutdown(bool reboot)
270845a180fSFrançois Revol {
271845a180fSFrançois Revol 	M68KPlatform::Default()->ShutDown(reboot);
272845a180fSFrançois Revol 	return B_ERROR;
273845a180fSFrançois Revol }
274845a180fSFrançois Revol 
275845a180fSFrançois Revol 
276845a180fSFrançois Revol void
277845a180fSFrançois Revol arch_cpu_idle(void)
278845a180fSFrançois Revol {
2794e44040dSFrançois Revol 	if (cpu_ops.idle)
2804e44040dSFrançois Revol 		cpu_ops.idle();
281ac1a8a0cSFrançois Revol #warning M68K: use LPSTOP ?
282ac1a8a0cSFrançois Revol 	//asm volatile ("lpstop");
283845a180fSFrançois Revol }
284845a180fSFrançois Revol 
285845a180fSFrançois Revol 
286845a180fSFrançois Revol // The purpose of this function is to trick the compiler. When setting the
287845a180fSFrançois Revol // page_handler to a label that is obviously (to the compiler) never used,
288845a180fSFrançois Revol // it may reorganize the control flow, so that the labeled part is optimized
289845a180fSFrançois Revol // away.
290845a180fSFrançois Revol // By invoking the function like this
291845a180fSFrançois Revol //
292845a180fSFrançois Revol //	if (m68k_set_fault_handler(faultHandler, (addr_t)&&error))
293845a180fSFrançois Revol //		goto error;
294845a180fSFrançois Revol //
295845a180fSFrançois Revol // the compiler has to keep the labeled code, since it can't guess the return
296845a180fSFrançois Revol // value of this (non-inlinable) function. At least in my tests it worked that
297845a180fSFrançois Revol // way, and I hope it will continue to work like this in the future.
298845a180fSFrançois Revol //
299845a180fSFrançois Revol bool
300845a180fSFrançois Revol m68k_set_fault_handler(addr_t *handlerLocation, addr_t handler)
301845a180fSFrançois Revol {
302845a180fSFrançois Revol 	*handlerLocation = handler;
303845a180fSFrançois Revol 	return false;
304845a180fSFrançois Revol }
305