xref: /haiku/src/system/kernel/arch/m68k/arch_cpu.cpp (revision 746cac055adc6ac3308c7bc2d29040fb95689cc9)
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 
64 	switch (arch_cpu_type) {
65 		case 68020:
66 		case 68030:
67 			memcpy(&cpu_ops, &cpu_ops_030, sizeof(cpu_ops));
68 			break;
69 
70 		case 68040:
71 			memcpy(&cpu_ops, &cpu_ops_040, sizeof(cpu_ops));
72 			break;
73 
74 #ifdef SUPPORTS_060
75 		case 68060:
76 			memcpy(&cpu_ops, &cpu_ops_060, sizeof(cpu_ops));
77 			break;
78 #endif
79 		default:
80 			panic("unknown cpu_type %d\n", arch_cpu_type);
81 	}
82 
83 	return B_OK;
84 }
85 
86 
87 status_t
88 arch_cpu_init_post_vm(kernel_args *args)
89 {
90 	return B_OK;
91 }
92 
93 status_t
94 arch_cpu_init_post_modules(kernel_args *args)
95 {
96 	return B_OK;
97 }
98 
99 
100 void
101 arch_cpu_sync_icache(void *address, size_t len)
102 {
103 	cpu_ops.flush_icache((addr_t)address, len);
104 }
105 
106 
107 void
108 arch_cpu_memory_read_barrier(void)
109 {
110 	asm volatile ("nop;" : : : "memory");
111 #warning M68k: check arch_cpu_memory_read_barrier (FNOP ?)
112 }
113 
114 
115 void
116 arch_cpu_memory_write_barrier(void)
117 {
118 	asm volatile ("nop;" : : : "memory");
119 #warning M68k: check arch_cpu_memory_write_barrier (FNOP ?)
120 }
121 
122 
123 void
124 arch_cpu_invalidate_TLB_range(addr_t start, addr_t end)
125 {
126 	int32 num_pages = end / B_PAGE_SIZE - start / B_PAGE_SIZE;
127 	cpu_ops.flush_insn_pipeline();
128 	while (num_pages-- >= 0) {
129 		cpu_ops.flush_atc_addr(start);
130 		cpu_ops.flush_insn_pipeline();
131 		start += B_PAGE_SIZE;
132 	}
133 	cpu_ops.flush_insn_pipeline();
134 }
135 
136 
137 void
138 arch_cpu_invalidate_TLB_list(addr_t pages[], int num_pages)
139 {
140 	int i;
141 
142 	cpu_ops.flush_insn_pipeline();
143 	for (i = 0; i < num_pages; i++) {
144 		cpu_ops.flush_atc_addr(pages[i]);
145 		cpu_ops.flush_insn_pipeline();
146 	}
147 	cpu_ops.flush_insn_pipeline();
148 }
149 
150 
151 void
152 arch_cpu_global_TLB_invalidate(void)
153 {
154 	cpu_ops.flush_insn_pipeline();
155 	cpu_ops.flush_atc_all();
156 	cpu_ops.flush_insn_pipeline();
157 }
158 
159 
160 void
161 arch_cpu_user_TLB_invalidate(void)
162 {
163 	cpu_ops.flush_insn_pipeline();
164 	cpu_ops.flush_atc_user();
165 	cpu_ops.flush_insn_pipeline();
166 }
167 
168 
169 status_t
170 arch_cpu_user_memcpy(void *to, const void *from, size_t size,
171 	addr_t *faultHandler)
172 {
173 	char *tmp = (char *)to;
174 	char *s = (char *)from;
175 	addr_t oldFaultHandler = *faultHandler;
176 
177 	if (m68k_set_fault_handler(faultHandler, (addr_t)&&error))
178 		goto error;
179 
180 	while (size--)
181 		*tmp++ = *s++;
182 
183 	*faultHandler = oldFaultHandler;
184 	return 0;
185 
186 error:
187 	*faultHandler = oldFaultHandler;
188 	return B_BAD_ADDRESS;
189 }
190 
191 
192 /**	\brief Copies at most (\a size - 1) characters from the string in \a from to
193  *	the string in \a to, NULL-terminating the result.
194  *
195  *	\param to Pointer to the destination C-string.
196  *	\param from Pointer to the source C-string.
197  *	\param size Size in bytes of the string buffer pointed to by \a to.
198  *
199  *	\return strlen(\a from).
200  */
201 
202 ssize_t
203 arch_cpu_user_strlcpy(char *to, const char *from, size_t size, addr_t *faultHandler)
204 {
205 	int from_length = 0;
206 	addr_t oldFaultHandler = *faultHandler;
207 
208 	if (m68k_set_fault_handler(faultHandler, (addr_t)&&error))
209 		goto error;
210 
211 	if (size > 0) {
212 		to[--size] = '\0';
213 		// copy
214 		for ( ; size; size--, from_length++, to++, from++) {
215 			if ((*to = *from) == '\0')
216 				break;
217 		}
218 	}
219 	// count any leftover from chars
220 	while (*from++ != '\0')
221 		from_length++;
222 
223 	*faultHandler = oldFaultHandler;
224 	return from_length;
225 
226 error:
227 	*faultHandler = oldFaultHandler;
228 	return B_BAD_ADDRESS;
229 }
230 
231 
232 status_t
233 arch_cpu_user_memset(void *s, char c, size_t count, addr_t *faultHandler)
234 {
235 	char *xs = (char *)s;
236 	addr_t oldFaultHandler = *faultHandler;
237 
238 	if (m68k_set_fault_handler(faultHandler, (addr_t)&&error))
239 		goto error;
240 
241 	while (count--)
242 		*xs++ = c;
243 
244 	*faultHandler = oldFaultHandler;
245 	return 0;
246 
247 error:
248 	*faultHandler = oldFaultHandler;
249 	return B_BAD_ADDRESS;
250 }
251 
252 
253 status_t
254 arch_cpu_shutdown(bool reboot)
255 {
256 	M68KPlatform::Default()->ShutDown(reboot);
257 	return B_ERROR;
258 }
259 
260 
261 void
262 arch_cpu_idle(void)
263 {
264 	if (cpu_ops.idle)
265 		cpu_ops.idle();
266 #warning M68K: use LPSTOP ?
267 	//asm volatile ("lpstop");
268 }
269 
270 
271 // The purpose of this function is to trick the compiler. When setting the
272 // page_handler to a label that is obviously (to the compiler) never used,
273 // it may reorganize the control flow, so that the labeled part is optimized
274 // away.
275 // By invoking the function like this
276 //
277 //	if (m68k_set_fault_handler(faultHandler, (addr_t)&&error))
278 //		goto error;
279 //
280 // the compiler has to keep the labeled code, since it can't guess the return
281 // value of this (non-inlinable) function. At least in my tests it worked that
282 // way, and I hope it will continue to work like this in the future.
283 //
284 bool
285 m68k_set_fault_handler(addr_t *handlerLocation, addr_t handler)
286 {
287 	*handlerLocation = handler;
288 	return false;
289 }
290