xref: /haiku/src/system/kernel/arch/m68k/arch_cpu.cpp (revision 239222b2369c39dc52df52b0a7cdd6cc0a91bc92)
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 status_t
175 arch_cpu_user_memcpy(void *to, const void *from, size_t size,
176 	addr_t *faultHandler)
177 {
178 	char *tmp = (char *)to;
179 	char *s = (char *)from;
180 	addr_t oldFaultHandler = *faultHandler;
181 
182 // TODO: This doesn't work correctly with gcc 4 anymore!
183 	if (m68k_set_fault_handler(faultHandler, (addr_t)&&error))
184 		goto error;
185 
186 	while (size--)
187 		*tmp++ = *s++;
188 
189 	*faultHandler = oldFaultHandler;
190 	return 0;
191 
192 error:
193 	*faultHandler = oldFaultHandler;
194 	return B_BAD_ADDRESS;
195 }
196 
197 
198 /**	\brief Copies at most (\a size - 1) characters from the string in \a from to
199  *	the string in \a to, NULL-terminating the result.
200  *
201  *	\param to Pointer to the destination C-string.
202  *	\param from Pointer to the source C-string.
203  *	\param size Size in bytes of the string buffer pointed to by \a to.
204  *
205  *	\return strlen(\a from).
206  */
207 
208 ssize_t
209 arch_cpu_user_strlcpy(char *to, const char *from, size_t size, addr_t *faultHandler)
210 {
211 	int from_length = 0;
212 	addr_t oldFaultHandler = *faultHandler;
213 
214 // TODO: This doesn't work correctly with gcc 4 anymore!
215 	if (m68k_set_fault_handler(faultHandler, (addr_t)&&error))
216 		goto error;
217 
218 	if (size > 0) {
219 		to[--size] = '\0';
220 		// copy
221 		for ( ; size; size--, from_length++, to++, from++) {
222 			if ((*to = *from) == '\0')
223 				break;
224 		}
225 	}
226 	// count any leftover from chars
227 	while (*from++ != '\0')
228 		from_length++;
229 
230 	*faultHandler = oldFaultHandler;
231 	return from_length;
232 
233 error:
234 	*faultHandler = oldFaultHandler;
235 	return B_BAD_ADDRESS;
236 }
237 
238 
239 status_t
240 arch_cpu_user_memset(void *s, char c, size_t count, addr_t *faultHandler)
241 {
242 	char *xs = (char *)s;
243 	addr_t oldFaultHandler = *faultHandler;
244 
245 // TODO: This doesn't work correctly with gcc 4 anymore!
246 	if (m68k_set_fault_handler(faultHandler, (addr_t)&&error))
247 		goto error;
248 
249 	while (count--)
250 		*xs++ = c;
251 
252 	*faultHandler = oldFaultHandler;
253 	return 0;
254 
255 error:
256 	*faultHandler = oldFaultHandler;
257 	return B_BAD_ADDRESS;
258 }
259 
260 
261 status_t
262 arch_cpu_shutdown(bool reboot)
263 {
264 	M68KPlatform::Default()->ShutDown(reboot);
265 	return B_ERROR;
266 }
267 
268 
269 void
270 arch_cpu_idle(void)
271 {
272 	if (cpu_ops.idle)
273 		cpu_ops.idle();
274 #warning M68K: use LPSTOP ?
275 	//asm volatile ("lpstop");
276 }
277 
278 
279 // The purpose of this function is to trick the compiler. When setting the
280 // page_handler to a label that is obviously (to the compiler) never used,
281 // it may reorganize the control flow, so that the labeled part is optimized
282 // away.
283 // By invoking the function like this
284 //
285 //	if (m68k_set_fault_handler(faultHandler, (addr_t)&&error))
286 //		goto error;
287 //
288 // the compiler has to keep the labeled code, since it can't guess the return
289 // value of this (non-inlinable) function. At least in my tests it worked that
290 // way, and I hope it will continue to work like this in the future.
291 //
292 bool
293 m68k_set_fault_handler(addr_t *handlerLocation, addr_t handler)
294 {
295 // TODO: This doesn't work correctly with gcc 4 anymore!
296 	*handlerLocation = handler;
297 	return false;
298 }
299