xref: /haiku/src/system/kernel/arch/m68k/arch_cpu.cpp (revision e221c09e508ffc3c62738140c9b6fc4fa211662a)
1 /*
2  * Copyright 2007, François Revol, revol@free.fr.
3  * Distributed under the terms of the MIT License.
4  *
5  * Copyright 2003-2005, Axel Dörfler, axeld@pinc-software.de.
6  * Distributed under the terms of the MIT License.
7  *
8  * Copyright 2001, Travis Geiselbrecht. All rights reserved.
9  * Distributed under the terms of the NewOS License.
10  */
11 
12 
13 #include <KernelExport.h>
14 
15 #include <arch_platform.h>
16 #include <arch_thread.h>
17 #include <arch/cpu.h>
18 #include <boot/kernel_args.h>
19 
20 extern struct m68k_cpu_ops cpu_ops_030;
21 extern struct m68k_cpu_ops cpu_ops_040;
22 extern struct m68k_cpu_ops cpu_ops_060;
23 
24 struct m68k_cpu_ops cpu_ops;
25 
26 int arch_cpu_type;
27 int arch_fpu_type;
28 int arch_mmu_type;
29 int arch_platform;
30 
31 status_t
32 arch_cpu_preboot_init_percpu(kernel_args *args, int curr_cpu)
33 {
34 	// enable FPU
35 	//ppc:set_msr(get_msr() | MSR_FP_AVAILABLE);
36 
37 	// The current thread must be NULL for all CPUs till we have threads.
38 	// Some boot code relies on this.
39 	arch_thread_set_current_thread(NULL);
40 
41 	return B_OK;
42 }
43 
44 
45 status_t
46 arch_cpu_init_percpu(kernel_args *args, int curr_cpu)
47 {
48 	//detect_cpu(curr_cpu);
49 
50 	// we only support one anyway...
51 	return 0;
52 }
53 
54 
55 status_t
56 arch_cpu_init(kernel_args *args)
57 {
58 	arch_cpu_type = args->arch_args.cpu_type;
59 	arch_fpu_type = args->arch_args.fpu_type;
60 	arch_mmu_type = args->arch_args.mmu_type;
61 	arch_platform = args->arch_args.platform;
62 	arch_platform = args->arch_args.machine;
63 	void (*flush_insn_pipeline)(void);
64 	void (*flush_atc_all)(void);
65 	void (*flush_atc_user)(void);
66 	void (*flush_atc_addr)(void *addr);
67 	void (*flush_dcache)(void *address, size_t len);
68 	void (*flush_icache)(void *address, size_t len);
69 	void (*idle)(void);
70 
71 	switch (arch_cpu_type) {
72 		case 68020:
73 		case 68030:
74 			cpu_ops.flush_insn_pipeline = cpu_ops_030.flush_insn_pipeline;
75 			cpu_ops.flush_atc_all = cpu_ops_030.flush_atc_all;
76 			cpu_ops.flush_atc_user = cpu_ops_030.flush_atc_user;
77 			cpu_ops.flush_atc_addr = cpu_ops_030.flush_atc_addr;
78 			cpu_ops.flush_dcache = cpu_ops_030.flush_dcache;
79 			cpu_ops.flush_icache = cpu_ops_030.flush_icache;
80 			cpu_ops.idle = cpu_ops_030.idle; // NULL
81 			break;
82 #ifdef SUPPORTS_040
83 		case 68040:
84 			cpu_ops.flush_insn_pipeline = cpu_ops_040.flush_insn_pipeline;
85 			cpu_ops.flush_atc_all = cpu_ops_040.flush_atc_all;
86 			cpu_ops.flush_atc_user = cpu_ops_040.flush_atc_user;
87 			cpu_ops.flush_atc_addr = cpu_ops_040.flush_atc_addr;
88 			cpu_ops.flush_dcache = cpu_ops_040.flush_dcache;
89 			cpu_ops.flush_icache = cpu_ops_040.flush_icache;
90 			cpu_ops.idle = cpu_ops_040.idle; // NULL
91 			break;
92 #endif
93 #ifdef SUPPORTS_060
94 		case 68060:
95 			cpu_ops.flush_insn_pipeline = cpu_ops_060.flush_insn_pipeline;
96 			cpu_ops.flush_atc_all = cpu_ops_060.flush_atc_all;
97 			cpu_ops.flush_atc_user = cpu_ops_060.flush_atc_user;
98 			cpu_ops.flush_atc_addr = cpu_ops_060.flush_atc_addr;
99 			cpu_ops.flush_dcache = cpu_ops_060.flush_dcache;
100 			cpu_ops.flush_icache = cpu_ops_060.flush_icache;
101 			cpu_ops.idle = cpu_ops_060.idle;
102 		break;
103 #endif
104 		default:
105 			panic("unknown cpu_type %d\n", arch_cpu_type);
106 	}
107 
108 	return B_OK;
109 }
110 
111 
112 status_t
113 arch_cpu_init_post_vm(kernel_args *args)
114 {
115 	return B_OK;
116 }
117 
118 status_t
119 arch_cpu_init_post_modules(kernel_args *args)
120 {
121 	return B_OK;
122 }
123 
124 
125 void
126 arch_cpu_sync_icache(void *address, size_t len)
127 {
128 	cpu_ops.flush_icache((addr_t)address, len);
129 }
130 
131 
132 void
133 arch_cpu_memory_read_barrier(void)
134 {
135 	asm volatile ("nop;" : : : "memory");
136 #warning M68k: check arch_cpu_memory_read_barrier
137 }
138 
139 
140 void
141 arch_cpu_memory_write_barrier(void)
142 {
143 	asm volatile ("nop;" : : : "memory");
144 #warning M68k: check arch_cpu_memory_write_barrier
145 }
146 
147 
148 void
149 arch_cpu_invalidate_TLB_range(addr_t start, addr_t end)
150 {
151 	int32 num_pages = end / B_PAGE_SIZE - start / B_PAGE_SIZE;
152 	cpu_ops.flush_insn_pipeline();
153 	while (num_pages-- >= 0) {
154 		cpu_ops.flush_atc_addr(start);
155 		cpu_ops.flush_insn_pipeline();
156 		start += B_PAGE_SIZE;
157 	}
158 	cpu_ops.flush_insn_pipeline();
159 }
160 
161 
162 void
163 arch_cpu_invalidate_TLB_list(addr_t pages[], int num_pages)
164 {
165 	int i;
166 
167 	cpu_ops.flush_insn_pipeline();
168 	for (i = 0; i < num_pages; i++) {
169 		cpu_ops.flush_atc_addr(pages[i]);
170 		cpu_ops.flush_insn_pipeline();
171 	}
172 	cpu_ops.flush_insn_pipeline();
173 }
174 
175 
176 void
177 arch_cpu_global_TLB_invalidate(void)
178 {
179 	cpu_ops.flush_insn_pipeline();
180 	cpu_ops.flush_atc_all();
181 	cpu_ops.flush_insn_pipeline();
182 }
183 
184 
185 void
186 arch_cpu_user_TLB_invalidate(void)
187 {
188 	cpu_ops.flush_insn_pipeline();
189 	cpu_ops.flush_atc_user();
190 	cpu_ops.flush_insn_pipeline();
191 }
192 
193 
194 status_t
195 arch_cpu_user_memcpy(void *to, const void *from, size_t size,
196 	addr_t *faultHandler)
197 {
198 	char *tmp = (char *)to;
199 	char *s = (char *)from;
200 	addr_t oldFaultHandler = *faultHandler;
201 
202 	if (m68k_set_fault_handler(faultHandler, (addr_t)&&error))
203 		goto error;
204 
205 	while (size--)
206 		*tmp++ = *s++;
207 
208 	*faultHandler = oldFaultHandler;
209 	return 0;
210 
211 error:
212 	*faultHandler = oldFaultHandler;
213 	return B_BAD_ADDRESS;
214 }
215 
216 
217 /**	\brief Copies at most (\a size - 1) characters from the string in \a from to
218  *	the string in \a to, NULL-terminating the result.
219  *
220  *	\param to Pointer to the destination C-string.
221  *	\param from Pointer to the source C-string.
222  *	\param size Size in bytes of the string buffer pointed to by \a to.
223  *
224  *	\return strlen(\a from).
225  */
226 
227 ssize_t
228 arch_cpu_user_strlcpy(char *to, const char *from, size_t size, addr_t *faultHandler)
229 {
230 	int from_length = 0;
231 	addr_t oldFaultHandler = *faultHandler;
232 
233 	if (m68k_set_fault_handler(faultHandler, (addr_t)&&error))
234 		goto error;
235 
236 	if (size > 0) {
237 		to[--size] = '\0';
238 		// copy
239 		for ( ; size; size--, from_length++, to++, from++) {
240 			if ((*to = *from) == '\0')
241 				break;
242 		}
243 	}
244 	// count any leftover from chars
245 	while (*from++ != '\0')
246 		from_length++;
247 
248 	*faultHandler = oldFaultHandler;
249 	return from_length;
250 
251 error:
252 	*faultHandler = oldFaultHandler;
253 	return B_BAD_ADDRESS;
254 }
255 
256 
257 status_t
258 arch_cpu_user_memset(void *s, char c, size_t count, addr_t *faultHandler)
259 {
260 	char *xs = (char *)s;
261 	addr_t oldFaultHandler = *faultHandler;
262 
263 	if (m68k_set_fault_handler(faultHandler, (addr_t)&&error))
264 		goto error;
265 
266 	while (count--)
267 		*xs++ = c;
268 
269 	*faultHandler = oldFaultHandler;
270 	return 0;
271 
272 error:
273 	*faultHandler = oldFaultHandler;
274 	return B_BAD_ADDRESS;
275 }
276 
277 
278 status_t
279 arch_cpu_shutdown(bool reboot)
280 {
281 	M68KPlatform::Default()->ShutDown(reboot);
282 	return B_ERROR;
283 }
284 
285 
286 void
287 arch_cpu_idle(void)
288 {
289 	if (cpu_ops.idle)
290 		cpu_ops.idle();
291 #warning M68K: use LPSTOP ?
292 	//asm volatile ("lpstop");
293 }
294 
295 
296 // The purpose of this function is to trick the compiler. When setting the
297 // page_handler to a label that is obviously (to the compiler) never used,
298 // it may reorganize the control flow, so that the labeled part is optimized
299 // away.
300 // By invoking the function like this
301 //
302 //	if (m68k_set_fault_handler(faultHandler, (addr_t)&&error))
303 //		goto error;
304 //
305 // the compiler has to keep the labeled code, since it can't guess the return
306 // value of this (non-inlinable) function. At least in my tests it worked that
307 // way, and I hope it will continue to work like this in the future.
308 //
309 bool
310 m68k_set_fault_handler(addr_t *handlerLocation, addr_t handler)
311 {
312 	*handlerLocation = handler;
313 	return false;
314 }
315