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