xref: /haiku/src/system/kernel/arch/m68k/arch_cpu.cpp (revision 829748d89de3b641c3d05ea327041b8bbfd753cb)
1845a180fSFrançois Revol /*
2845a180fSFrançois Revol  * Copyright 2003-2005, Axel Dörfler, axeld@pinc-software.de.
3845a180fSFrançois Revol  * Distributed under the terms of the MIT License.
4845a180fSFrançois Revol  *
5845a180fSFrançois Revol  * Copyright 2001, Travis Geiselbrecht. All rights reserved.
6845a180fSFrançois Revol  * Distributed under the terms of the NewOS License.
7845a180fSFrançois Revol  */
8845a180fSFrançois Revol 
9845a180fSFrançois Revol 
10845a180fSFrançois Revol #include <KernelExport.h>
11845a180fSFrançois Revol 
12845a180fSFrançois Revol #include <arch_platform.h>
13845a180fSFrançois Revol #include <arch_thread.h>
14845a180fSFrançois Revol #include <arch/cpu.h>
15845a180fSFrançois Revol #include <boot/kernel_args.h>
16845a180fSFrançois Revol 
17845a180fSFrançois Revol 
18845a180fSFrançois Revol status_t
19845a180fSFrançois Revol arch_cpu_preboot_init_percpu(kernel_args *args, int curr_cpu)
20845a180fSFrançois Revol {
21845a180fSFrançois Revol 	// enable FPU
22*829748d8SFrançois Revol 	//ppc:set_msr(get_msr() | MSR_FP_AVAILABLE);
23845a180fSFrançois Revol 
24845a180fSFrançois Revol 	// The current thread must be NULL for all CPUs till we have threads.
25845a180fSFrançois Revol 	// Some boot code relies on this.
26845a180fSFrançois Revol 	arch_thread_set_current_thread(NULL);
27845a180fSFrançois Revol 
28845a180fSFrançois Revol 	return B_OK;
29845a180fSFrançois Revol }
30845a180fSFrançois Revol 
31845a180fSFrançois Revol 
32845a180fSFrançois Revol status_t
33845a180fSFrançois Revol arch_cpu_init(kernel_args *args)
34845a180fSFrançois Revol {
35845a180fSFrançois Revol 	return B_OK;
36845a180fSFrançois Revol }
37845a180fSFrançois Revol 
38845a180fSFrançois Revol 
39845a180fSFrançois Revol status_t
40845a180fSFrançois Revol arch_cpu_init_post_vm(kernel_args *args)
41845a180fSFrançois Revol {
42845a180fSFrançois Revol 	return B_OK;
43845a180fSFrançois Revol }
44845a180fSFrançois Revol 
45845a180fSFrançois Revol status_t
46845a180fSFrançois Revol arch_cpu_init_post_modules(kernel_args *args)
47845a180fSFrançois Revol {
48845a180fSFrançois Revol 	return B_OK;
49845a180fSFrançois Revol }
50845a180fSFrançois Revol 
51845a180fSFrançois Revol #define CACHELINE 32
52845a180fSFrançois Revol 
53845a180fSFrançois Revol void
54845a180fSFrançois Revol arch_cpu_sync_icache(void *address, size_t len)
55845a180fSFrançois Revol {
56845a180fSFrançois Revol 	int l, off;
57845a180fSFrançois Revol 	char *p;
58*829748d8SFrançois Revol 	uint32 cacr;
59845a180fSFrançois Revol 
60845a180fSFrançois Revol 	off = (unsigned int)address & (CACHELINE - 1);
61845a180fSFrançois Revol 	len += off;
62845a180fSFrançois Revol 
63845a180fSFrançois Revol 	l = len;
64845a180fSFrançois Revol 	p = (char *)address - off;
65*829748d8SFrançois Revol 	asm volatile ("movec %%cacr,%0" : "=r"(cacr):);
66*829748d8SFrançois Revol 	cacr |= 0x00000004; /* ClearInstructionCacheEntry */
67845a180fSFrançois Revol 	do {
68*829748d8SFrançois Revol 		asm volatile ("movec %0,%%caar" :: "r"(p));
69*829748d8SFrançois Revol 		asm volatile ("movec %0,%%cacr" :: "r"(cacr));
70845a180fSFrançois Revol 		p += CACHELINE;
71845a180fSFrançois Revol 	} while ((l -= CACHELINE) > 0);
72*829748d8SFrançois Revol 	m68k_nop();
73845a180fSFrançois Revol }
74845a180fSFrançois Revol 
75845a180fSFrançois Revol 
76845a180fSFrançois Revol void
77845a180fSFrançois Revol arch_cpu_invalidate_TLB_range(addr_t start, addr_t end)
78845a180fSFrançois Revol {
79ee75f852SFrançois Revol 	m68k_nop();
80845a180fSFrançois Revol 	while (start < end) {
81ee75f852SFrançois Revol 		pflush(start);
82ee75f852SFrançois Revol 		m68k_nop();
83845a180fSFrançois Revol 		start += B_PAGE_SIZE;
84845a180fSFrançois Revol 	}
85ee75f852SFrançois Revol 	m68k_nop();
86845a180fSFrançois Revol }
87845a180fSFrançois Revol 
88845a180fSFrançois Revol 
89845a180fSFrançois Revol void
90845a180fSFrançois Revol arch_cpu_invalidate_TLB_list(addr_t pages[], int num_pages)
91845a180fSFrançois Revol {
92845a180fSFrançois Revol 	int i;
93845a180fSFrançois Revol 
94ee75f852SFrançois Revol 	m68k_nop();
95845a180fSFrançois Revol 	for (i = 0; i < num_pages; i++) {
96ee75f852SFrançois Revol 		pflush(pages[i]);
97ee75f852SFrançois Revol 		m68k_nop();
98845a180fSFrançois Revol 	}
99ee75f852SFrançois Revol 	m68k_nop();
100845a180fSFrançois Revol }
101845a180fSFrançois Revol 
102845a180fSFrançois Revol 
103845a180fSFrançois Revol void
104845a180fSFrançois Revol arch_cpu_global_TLB_invalidate(void)
105845a180fSFrançois Revol {
106ee75f852SFrançois Revol 	m68k_nop();
107*829748d8SFrançois Revol 	pflusha();
108ee75f852SFrançois Revol 	m68k_nop();
109845a180fSFrançois Revol }
110845a180fSFrançois Revol 
111845a180fSFrançois Revol 
112845a180fSFrançois Revol void
113845a180fSFrançois Revol arch_cpu_user_TLB_invalidate(void)
114845a180fSFrançois Revol {
115*829748d8SFrançois Revol 	// pflushfd ?
116845a180fSFrançois Revol 	arch_cpu_global_TLB_invalidate();
117845a180fSFrançois Revol }
118845a180fSFrançois Revol 
119845a180fSFrançois Revol 
120845a180fSFrançois Revol status_t
121845a180fSFrançois Revol arch_cpu_user_memcpy(void *to, const void *from, size_t size,
122845a180fSFrançois Revol 	addr_t *faultHandler)
123845a180fSFrançois Revol {
124845a180fSFrançois Revol 	char *tmp = (char *)to;
125845a180fSFrançois Revol 	char *s = (char *)from;
126845a180fSFrançois Revol 	addr_t oldFaultHandler = *faultHandler;
127845a180fSFrançois Revol 
128845a180fSFrançois Revol 	if (m68k_set_fault_handler(faultHandler, (addr_t)&&error))
129845a180fSFrançois Revol 		goto error;
130845a180fSFrançois Revol 
131845a180fSFrançois Revol 	while (size--)
132845a180fSFrançois Revol 		*tmp++ = *s++;
133845a180fSFrançois Revol 
134845a180fSFrançois Revol 	*faultHandler = oldFaultHandler;
135845a180fSFrançois Revol 	return 0;
136845a180fSFrançois Revol 
137845a180fSFrançois Revol error:
138845a180fSFrançois Revol 	*faultHandler = oldFaultHandler;
139845a180fSFrançois Revol 	return B_BAD_ADDRESS;
140845a180fSFrançois Revol }
141845a180fSFrançois Revol 
142845a180fSFrançois Revol 
143845a180fSFrançois Revol /**	\brief Copies at most (\a size - 1) characters from the string in \a from to
144845a180fSFrançois Revol  *	the string in \a to, NULL-terminating the result.
145845a180fSFrançois Revol  *
146845a180fSFrançois Revol  *	\param to Pointer to the destination C-string.
147845a180fSFrançois Revol  *	\param from Pointer to the source C-string.
148845a180fSFrançois Revol  *	\param size Size in bytes of the string buffer pointed to by \a to.
149845a180fSFrançois Revol  *
150845a180fSFrançois Revol  *	\return strlen(\a from).
151845a180fSFrançois Revol  */
152845a180fSFrançois Revol 
153845a180fSFrançois Revol ssize_t
154845a180fSFrançois Revol arch_cpu_user_strlcpy(char *to, const char *from, size_t size, addr_t *faultHandler)
155845a180fSFrançois Revol {
156845a180fSFrançois Revol 	int from_length = 0;
157845a180fSFrançois Revol 	addr_t oldFaultHandler = *faultHandler;
158845a180fSFrançois Revol 
159845a180fSFrançois Revol 	if (m68k_set_fault_handler(faultHandler, (addr_t)&&error))
160845a180fSFrançois Revol 		goto error;
161845a180fSFrançois Revol 
162845a180fSFrançois Revol 	if (size > 0) {
163845a180fSFrançois Revol 		to[--size] = '\0';
164845a180fSFrançois Revol 		// copy
165845a180fSFrançois Revol 		for ( ; size; size--, from_length++, to++, from++) {
166845a180fSFrançois Revol 			if ((*to = *from) == '\0')
167845a180fSFrançois Revol 				break;
168845a180fSFrançois Revol 		}
169845a180fSFrançois Revol 	}
170845a180fSFrançois Revol 	// count any leftover from chars
171845a180fSFrançois Revol 	while (*from++ != '\0')
172845a180fSFrançois Revol 		from_length++;
173845a180fSFrançois Revol 
174845a180fSFrançois Revol 	*faultHandler = oldFaultHandler;
175845a180fSFrançois Revol 	return from_length;
176845a180fSFrançois Revol 
177845a180fSFrançois Revol error:
178845a180fSFrançois Revol 	*faultHandler = oldFaultHandler;
179845a180fSFrançois Revol 	return B_BAD_ADDRESS;
180845a180fSFrançois Revol }
181845a180fSFrançois Revol 
182845a180fSFrançois Revol 
183845a180fSFrançois Revol status_t
184845a180fSFrançois Revol arch_cpu_user_memset(void *s, char c, size_t count, addr_t *faultHandler)
185845a180fSFrançois Revol {
186845a180fSFrançois Revol 	char *xs = (char *)s;
187845a180fSFrançois Revol 	addr_t oldFaultHandler = *faultHandler;
188845a180fSFrançois Revol 
189845a180fSFrançois Revol 	if (m68k_set_fault_handler(faultHandler, (addr_t)&&error))
190845a180fSFrançois Revol 		goto error;
191845a180fSFrançois Revol 
192845a180fSFrançois Revol 	while (count--)
193845a180fSFrançois Revol 		*xs++ = c;
194845a180fSFrançois Revol 
195845a180fSFrançois Revol 	*faultHandler = oldFaultHandler;
196845a180fSFrançois Revol 	return 0;
197845a180fSFrançois Revol 
198845a180fSFrançois Revol error:
199845a180fSFrançois Revol 	*faultHandler = oldFaultHandler;
200845a180fSFrançois Revol 	return B_BAD_ADDRESS;
201845a180fSFrançois Revol }
202845a180fSFrançois Revol 
203845a180fSFrançois Revol 
204845a180fSFrançois Revol status_t
205845a180fSFrançois Revol arch_cpu_shutdown(bool reboot)
206845a180fSFrançois Revol {
207845a180fSFrançois Revol 	M68KPlatform::Default()->ShutDown(reboot);
208845a180fSFrançois Revol 	return B_ERROR;
209845a180fSFrançois Revol }
210845a180fSFrançois Revol 
211845a180fSFrançois Revol 
212845a180fSFrançois Revol void
213845a180fSFrançois Revol arch_cpu_idle(void)
214845a180fSFrançois Revol {
215845a180fSFrançois Revol }
216845a180fSFrançois Revol 
217845a180fSFrançois Revol 
218845a180fSFrançois Revol // The purpose of this function is to trick the compiler. When setting the
219845a180fSFrançois Revol // page_handler to a label that is obviously (to the compiler) never used,
220845a180fSFrançois Revol // it may reorganize the control flow, so that the labeled part is optimized
221845a180fSFrançois Revol // away.
222845a180fSFrançois Revol // By invoking the function like this
223845a180fSFrançois Revol //
224845a180fSFrançois Revol //	if (m68k_set_fault_handler(faultHandler, (addr_t)&&error))
225845a180fSFrançois Revol //		goto error;
226845a180fSFrançois Revol //
227845a180fSFrançois Revol // the compiler has to keep the labeled code, since it can't guess the return
228845a180fSFrançois Revol // value of this (non-inlinable) function. At least in my tests it worked that
229845a180fSFrançois Revol // way, and I hope it will continue to work like this in the future.
230845a180fSFrançois Revol //
231845a180fSFrançois Revol bool
232845a180fSFrançois Revol m68k_set_fault_handler(addr_t *handlerLocation, addr_t handler)
233845a180fSFrançois Revol {
234845a180fSFrançois Revol 	*handlerLocation = handler;
235845a180fSFrançois Revol 	return false;
236845a180fSFrançois Revol }
237