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
22extern struct m68k_cpu_ops cpu_ops_030;
23extern struct m68k_cpu_ops cpu_ops_040;
24extern struct m68k_cpu_ops cpu_ops_060;
25
26struct m68k_cpu_ops cpu_ops;
27
28int arch_cpu_type;
29int arch_fpu_type;
30int arch_mmu_type;
31int arch_platform;
32
33status_t
34arch_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
47status_t
48arch_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
57status_t
58arch_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
89status_t
90arch_cpu_init_post_vm(kernel_args *args)
91{
92	return B_OK;
93}
94
95status_t
96arch_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
105void
106arch_cpu_sync_icache(void *address, size_t len)
107{
108	cpu_ops.flush_icache((addr_t)address, len);
109}
110
111
112void
113arch_cpu_memory_read_barrier(void)
114{
115	asm volatile ("nop;" : : : "memory");
116#warning M68k: check arch_cpu_memory_read_barrier (FNOP ?)
117}
118
119
120void
121arch_cpu_memory_write_barrier(void)
122{
123	asm volatile ("nop;" : : : "memory");
124#warning M68k: check arch_cpu_memory_write_barrier (FNOP ?)
125}
126
127
128void
129arch_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
142void
143arch_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
156void
157arch_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
165void
166arch_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.
176status_t
177arch_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
194error:
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
210ssize_t
211arch_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
235error:
236	*faultHandler = oldFaultHandler;
237	return B_BAD_ADDRESS;
238}
239
240
241status_t
242arch_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
257error:
258	*faultHandler = oldFaultHandler;
259	return B_BAD_ADDRESS;
260}
261
262
263status_t
264arch_cpu_shutdown(bool reboot)
265{
266	M68KPlatform::Default()->ShutDown(reboot);
267	return B_ERROR;
268}
269
270
271void
272arch_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//
294bool
295m68k_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