xref: /haiku/src/system/kernel/arch/m68k/arch_cpu.cpp (revision 4e44040df4d2763e5df092771c9464d4692fdaa3)
1845a180fSFrançois Revol /*
2*4e44040dSFrançois Revol  * Copyright 2007, François Revol, revol@free.fr.
3*4e44040dSFrançois Revol  * Distributed under the terms of the MIT License.
4*4e44040dSFranç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 
20*4e44040dSFrançois Revol extern struct m68k_cpu_ops cpu_ops_030;
21*4e44040dSFrançois Revol extern struct m68k_cpu_ops cpu_ops_040;
22*4e44040dSFrançois Revol extern struct m68k_cpu_ops cpu_ops_060;
23*4e44040dSFrançois Revol 
24*4e44040dSFrançois Revol struct m68k_cpu_ops cpu_ops;
25*4e44040dSFrançois Revol 
26*4e44040dSFrançois Revol int cpu_type;
27*4e44040dSFrançois Revol int fpu_type;
28*4e44040dSFrançois Revol int mmu_type;
29*4e44040dSFrançois Revol int platform;
30845a180fSFranç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 {
48*4e44040dSFrançois Revol 	cpu_type = args->arch_args.cpu_type;
49*4e44040dSFrançois Revol 	fpu_type = args->arch_args.fpu_type;
50*4e44040dSFrançois Revol 	mmu_type = args->arch_args.mmu_type;
51*4e44040dSFrançois Revol 	platform = args->arch_args.platform;
52*4e44040dSFrançois Revol 
53*4e44040dSFrançois Revol 	switch (cpu_type) {
54*4e44040dSFrançois Revol 	case CPU_68020:
55*4e44040dSFrançois Revol 	case CPU_68030:
56*4e44040dSFrançois Revol 		cpu_ops.flush_insn_pipeline = cpu_ops_030.flush_insn_pipeline;
57*4e44040dSFrançois Revol 		cpu_ops.flush_atc_all = cpu_ops_030.flush_atc_all;
58*4e44040dSFrançois Revol 		cpu_ops.flush_atc_user = cpu_ops_030.flush_atc_user;
59*4e44040dSFrançois Revol 		cpu_ops.flush_atc_addr = cpu_ops_030.flush_atc_addr;
60*4e44040dSFrançois Revol 		cpu_ops.flush_cache_line = cpu_ops_030.flush_cache_line;
61*4e44040dSFrançois Revol 		cpu_ops.idle = cpu_ops_030.idle; // NULL
62*4e44040dSFrançois Revol 		//cpu_ops. = cpu_ops_030.;
63*4e44040dSFrançois Revol 		break;
64*4e44040dSFrançois Revol #ifdef SUPPORTS_040
65*4e44040dSFrançois Revol 	case CPU_68040:
66*4e44040dSFrançois Revol 		cpu_ops.flush_insn_pipeline = cpu_ops_040.flush_insn_pipeline;
67*4e44040dSFrançois Revol 		cpu_ops.flush_atc_all = cpu_ops_040.flush_atc_all;
68*4e44040dSFrançois Revol 		cpu_ops.flush_atc_user = cpu_ops_040.flush_atc_user;
69*4e44040dSFrançois Revol 		cpu_ops.flush_atc_addr = cpu_ops_040.flush_atc_addr;
70*4e44040dSFrançois Revol 		cpu_ops.flush_cache_line = cpu_ops_040.flush_cache_line;
71*4e44040dSFrançois Revol 		cpu_ops.idle = cpu_ops_040.idle; // NULL
72*4e44040dSFrançois Revol 		//cpu_ops. = cpu_ops_040.;
73*4e44040dSFrançois Revol 		break;
74*4e44040dSFrançois Revol #endif
75*4e44040dSFrançois Revol #ifdef SUPPORTS_060
76*4e44040dSFrançois Revol 	case CPU_68060:
77*4e44040dSFrançois Revol 		cpu_ops.flush_insn_pipeline = cpu_ops_060.flush_insn_pipeline;
78*4e44040dSFrançois Revol 		cpu_ops.flush_atc_all = cpu_ops_060.flush_atc_all;
79*4e44040dSFrançois Revol 		cpu_ops.flush_atc_user = cpu_ops_060.flush_atc_user;
80*4e44040dSFrançois Revol 		cpu_ops.flush_atc_addr = cpu_ops_060.flush_atc_addr;
81*4e44040dSFrançois Revol 		cpu_ops.flush_cache_line = cpu_ops_060.flush_cache_line;
82*4e44040dSFrançois Revol 		cpu_ops.idle = cpu_ops_060.idle;
83*4e44040dSFrançois Revol 		//cpu_ops. = cpu_ops_060.;
84*4e44040dSFrançois Revol 		break;
85*4e44040dSFrançois Revol #endif
86*4e44040dSFrançois Revol 	default:
87*4e44040dSFrançois Revol 		panic("unknown cpu_type 0x%08lx\n", args->arch_args.cpu_type);
88*4e44040dSFrançois Revol 	}
89845a180fSFrançois Revol 	return B_OK;
90845a180fSFrançois Revol }
91845a180fSFrançois Revol 
92845a180fSFrançois Revol 
93845a180fSFrançois Revol status_t
94845a180fSFrançois Revol arch_cpu_init_post_vm(kernel_args *args)
95845a180fSFrançois Revol {
96845a180fSFrançois Revol 	return B_OK;
97845a180fSFrançois Revol }
98845a180fSFrançois Revol 
99845a180fSFrançois Revol status_t
100845a180fSFrançois Revol arch_cpu_init_post_modules(kernel_args *args)
101845a180fSFrançois Revol {
102845a180fSFrançois Revol 	return B_OK;
103845a180fSFrançois Revol }
104845a180fSFrançois Revol 
105845a180fSFrançois Revol 
106845a180fSFrançois Revol void
107845a180fSFrançois Revol arch_cpu_sync_icache(void *address, size_t len)
108845a180fSFrançois Revol {
109*4e44040dSFrançois Revol 	cpu_ops.flush_icache(address, len);
110845a180fSFrançois Revol }
111845a180fSFrançois Revol 
112845a180fSFrançois Revol 
113845a180fSFrançois Revol void
114845a180fSFrançois Revol arch_cpu_invalidate_TLB_range(addr_t start, addr_t end)
115845a180fSFrançois Revol {
116*4e44040dSFrançois Revol 	cpu_ops.flush_insn_pipeline();
117845a180fSFrançois Revol 	while (start < end) {
118*4e44040dSFrançois Revol 		cpu_ops.flush_atc_addr(start);
119*4e44040dSFrançois Revol 		cpu_ops.flush_insn_pipeline();
120845a180fSFrançois Revol 		start += B_PAGE_SIZE;
121845a180fSFrançois Revol 	}
122*4e44040dSFrançois Revol 	cpu_ops.flush_insn_pipeline();
123845a180fSFrançois Revol }
124845a180fSFrançois Revol 
125845a180fSFrançois Revol 
126845a180fSFrançois Revol void
127845a180fSFrançois Revol arch_cpu_invalidate_TLB_list(addr_t pages[], int num_pages)
128845a180fSFrançois Revol {
129845a180fSFrançois Revol 	int i;
130845a180fSFrançois Revol 
131*4e44040dSFrançois Revol 	cpu_ops.flush_insn_pipeline();
132845a180fSFrançois Revol 	for (i = 0; i < num_pages; i++) {
133*4e44040dSFrançois Revol 		cpu_ops.flush_atc_addr(pages[i]);
134*4e44040dSFrançois Revol 		cpu_ops.flush_insn_pipeline();
135845a180fSFrançois Revol 	}
136*4e44040dSFrançois Revol 	cpu_ops.flush_insn_pipeline();
137845a180fSFrançois Revol }
138845a180fSFrançois Revol 
139845a180fSFrançois Revol 
140845a180fSFrançois Revol void
141845a180fSFrançois Revol arch_cpu_global_TLB_invalidate(void)
142845a180fSFrançois Revol {
143*4e44040dSFrançois Revol 	cpu_ops.flush_insn_pipeline();
144*4e44040dSFrançois Revol 	cpu_ops.flush_atc_all();
145*4e44040dSFrançois Revol 	cpu_ops.flush_insn_pipeline();
146845a180fSFrançois Revol }
147845a180fSFrançois Revol 
148845a180fSFrançois Revol 
149845a180fSFrançois Revol void
150845a180fSFrançois Revol arch_cpu_user_TLB_invalidate(void)
151845a180fSFrançois Revol {
152*4e44040dSFrançois Revol 	cpu_ops.flush_insn_pipeline();
153*4e44040dSFrançois Revol 	cpu_ops.flush_atc_user();
154*4e44040dSFrançois Revol 	cpu_ops.flush_insn_pipeline();
155845a180fSFrançois Revol }
156845a180fSFrançois Revol 
157845a180fSFrançois Revol 
158845a180fSFrançois Revol status_t
159845a180fSFrançois Revol arch_cpu_user_memcpy(void *to, const void *from, size_t size,
160845a180fSFrançois Revol 	addr_t *faultHandler)
161845a180fSFrançois Revol {
162845a180fSFrançois Revol 	char *tmp = (char *)to;
163845a180fSFrançois Revol 	char *s = (char *)from;
164845a180fSFrançois Revol 	addr_t oldFaultHandler = *faultHandler;
165845a180fSFrançois Revol 
166845a180fSFrançois Revol 	if (m68k_set_fault_handler(faultHandler, (addr_t)&&error))
167845a180fSFrançois Revol 		goto error;
168845a180fSFrançois Revol 
169845a180fSFrançois Revol 	while (size--)
170845a180fSFrançois Revol 		*tmp++ = *s++;
171845a180fSFrançois Revol 
172845a180fSFrançois Revol 	*faultHandler = oldFaultHandler;
173845a180fSFrançois Revol 	return 0;
174845a180fSFrançois Revol 
175845a180fSFrançois Revol error:
176845a180fSFrançois Revol 	*faultHandler = oldFaultHandler;
177845a180fSFrançois Revol 	return B_BAD_ADDRESS;
178845a180fSFrançois Revol }
179845a180fSFrançois Revol 
180845a180fSFrançois Revol 
181845a180fSFrançois Revol /**	\brief Copies at most (\a size - 1) characters from the string in \a from to
182845a180fSFrançois Revol  *	the string in \a to, NULL-terminating the result.
183845a180fSFrançois Revol  *
184845a180fSFrançois Revol  *	\param to Pointer to the destination C-string.
185845a180fSFrançois Revol  *	\param from Pointer to the source C-string.
186845a180fSFrançois Revol  *	\param size Size in bytes of the string buffer pointed to by \a to.
187845a180fSFrançois Revol  *
188845a180fSFrançois Revol  *	\return strlen(\a from).
189845a180fSFrançois Revol  */
190845a180fSFrançois Revol 
191845a180fSFrançois Revol ssize_t
192845a180fSFrançois Revol arch_cpu_user_strlcpy(char *to, const char *from, size_t size, addr_t *faultHandler)
193845a180fSFrançois Revol {
194845a180fSFrançois Revol 	int from_length = 0;
195845a180fSFrançois Revol 	addr_t oldFaultHandler = *faultHandler;
196845a180fSFrançois Revol 
197845a180fSFrançois Revol 	if (m68k_set_fault_handler(faultHandler, (addr_t)&&error))
198845a180fSFrançois Revol 		goto error;
199845a180fSFrançois Revol 
200845a180fSFrançois Revol 	if (size > 0) {
201845a180fSFrançois Revol 		to[--size] = '\0';
202845a180fSFrançois Revol 		// copy
203845a180fSFrançois Revol 		for ( ; size; size--, from_length++, to++, from++) {
204845a180fSFrançois Revol 			if ((*to = *from) == '\0')
205845a180fSFrançois Revol 				break;
206845a180fSFrançois Revol 		}
207845a180fSFrançois Revol 	}
208845a180fSFrançois Revol 	// count any leftover from chars
209845a180fSFrançois Revol 	while (*from++ != '\0')
210845a180fSFrançois Revol 		from_length++;
211845a180fSFrançois Revol 
212845a180fSFrançois Revol 	*faultHandler = oldFaultHandler;
213845a180fSFrançois Revol 	return from_length;
214845a180fSFrançois Revol 
215845a180fSFrançois Revol error:
216845a180fSFrançois Revol 	*faultHandler = oldFaultHandler;
217845a180fSFrançois Revol 	return B_BAD_ADDRESS;
218845a180fSFrançois Revol }
219845a180fSFrançois Revol 
220845a180fSFrançois Revol 
221845a180fSFrançois Revol status_t
222845a180fSFrançois Revol arch_cpu_user_memset(void *s, char c, size_t count, addr_t *faultHandler)
223845a180fSFrançois Revol {
224845a180fSFrançois Revol 	char *xs = (char *)s;
225845a180fSFrançois Revol 	addr_t oldFaultHandler = *faultHandler;
226845a180fSFrançois Revol 
227845a180fSFrançois Revol 	if (m68k_set_fault_handler(faultHandler, (addr_t)&&error))
228845a180fSFrançois Revol 		goto error;
229845a180fSFrançois Revol 
230845a180fSFrançois Revol 	while (count--)
231845a180fSFrançois Revol 		*xs++ = c;
232845a180fSFrançois Revol 
233845a180fSFrançois Revol 	*faultHandler = oldFaultHandler;
234845a180fSFrançois Revol 	return 0;
235845a180fSFrançois Revol 
236845a180fSFrançois Revol error:
237845a180fSFrançois Revol 	*faultHandler = oldFaultHandler;
238845a180fSFrançois Revol 	return B_BAD_ADDRESS;
239845a180fSFrançois Revol }
240845a180fSFrançois Revol 
241845a180fSFrançois Revol 
242845a180fSFrançois Revol status_t
243845a180fSFrançois Revol arch_cpu_shutdown(bool reboot)
244845a180fSFrançois Revol {
245845a180fSFrançois Revol 	M68KPlatform::Default()->ShutDown(reboot);
246845a180fSFrançois Revol 	return B_ERROR;
247845a180fSFrançois Revol }
248845a180fSFrançois Revol 
249845a180fSFrançois Revol 
250845a180fSFrançois Revol void
251845a180fSFrançois Revol arch_cpu_idle(void)
252845a180fSFrançois Revol {
253*4e44040dSFrançois Revol 	if (cpu_ops.idle)
254*4e44040dSFrançois Revol 		cpu_ops.idle();
255ac1a8a0cSFrançois Revol #warning M68K: use LPSTOP ?
256ac1a8a0cSFrançois Revol 	//asm volatile ("lpstop");
257845a180fSFrançois Revol }
258845a180fSFrançois Revol 
259845a180fSFrançois Revol 
260845a180fSFrançois Revol // The purpose of this function is to trick the compiler. When setting the
261845a180fSFrançois Revol // page_handler to a label that is obviously (to the compiler) never used,
262845a180fSFrançois Revol // it may reorganize the control flow, so that the labeled part is optimized
263845a180fSFrançois Revol // away.
264845a180fSFrançois Revol // By invoking the function like this
265845a180fSFrançois Revol //
266845a180fSFrançois Revol //	if (m68k_set_fault_handler(faultHandler, (addr_t)&&error))
267845a180fSFrançois Revol //		goto error;
268845a180fSFrançois Revol //
269845a180fSFrançois Revol // the compiler has to keep the labeled code, since it can't guess the return
270845a180fSFrançois Revol // value of this (non-inlinable) function. At least in my tests it worked that
271845a180fSFrançois Revol // way, and I hope it will continue to work like this in the future.
272845a180fSFrançois Revol //
273845a180fSFrançois Revol bool
274845a180fSFrançois Revol m68k_set_fault_handler(addr_t *handlerLocation, addr_t handler)
275845a180fSFrançois Revol {
276845a180fSFrançois Revol 	*handlerLocation = handler;
277845a180fSFrançois Revol 	return false;
278845a180fSFrançois Revol }
279