headers/bsd: Add sys/queue.h.
[haiku.git] / src / system / kernel / arch / ppc / arch_cpu.cpp
blob5582c955208f6f05c6ad06c67f71dfd9a5ee3d01
1 /*
2 * Copyright 2003-2005, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
5 * Copyright 2001, Travis Geiselbrecht. All rights reserved.
6 * Distributed under the terms of the NewOS License.
7 */
10 #include <KernelExport.h>
12 #include <arch_platform.h>
13 #include <arch/cpu.h>
14 #include <arch/thread.h>
15 #include <boot/kernel_args.h>
17 static bool sHasTlbia;
19 status_t
20 arch_cpu_preboot_init_percpu(kernel_args *args, int curr_cpu)
22 // enable FPU
23 set_msr(get_msr() | MSR_FP_AVAILABLE);
25 // The current thread must be NULL for all CPUs till we have threads.
26 // Some boot code relies on this.
27 arch_thread_set_current_thread(NULL);
29 return B_OK;
33 status_t
34 arch_cpu_init(kernel_args *args)
36 // TODO: Let the boot loader put that info into the kernel args
37 // (property "tlbia" in the CPU node).
38 sHasTlbia = false;
40 return B_OK;
44 status_t
45 arch_cpu_init_post_vm(kernel_args *args)
47 return B_OK;
50 status_t
51 arch_cpu_init_percpu(kernel_args *args, int curr_cpu)
53 //detect_cpu(curr_cpu);
55 // we only support one on ppc anyway at the moment...
56 //XXX: WRITEME
57 return 0;
60 status_t
61 arch_cpu_init_post_modules(kernel_args *args)
63 return B_OK;
66 #define CACHELINE 32
68 void
69 arch_cpu_sync_icache(void *address, size_t len)
71 int l, off;
72 char *p;
74 off = (unsigned int)address & (CACHELINE - 1);
75 len += off;
77 l = len;
78 p = (char *)address - off;
79 do {
80 asm volatile ("dcbst 0,%0" :: "r"(p));
81 p += CACHELINE;
82 } while ((l -= CACHELINE) > 0);
83 asm volatile ("sync");
85 p = (char *)address - off;
86 do {
87 asm volatile ("icbi 0,%0" :: "r"(p));
88 p += CACHELINE;
89 } while ((len -= CACHELINE) > 0);
90 asm volatile ("sync");
91 isync();
95 void
96 arch_cpu_memory_read_barrier(void)
98 // WARNING PPC: is it model-dependant ?
99 asm volatile ("lwsync");
103 void
104 arch_cpu_memory_write_barrier(void)
106 // WARNING PPC: is it model-dependant ?
107 asm volatile ("isync");
108 asm volatile ("eieio");
112 void
113 arch_cpu_invalidate_TLB_range(addr_t start, addr_t end)
115 asm volatile("sync");
116 while (start < end) {
117 asm volatile("tlbie %0" :: "r" (start));
118 asm volatile("eieio");
119 asm volatile("sync");
120 start += B_PAGE_SIZE;
122 asm volatile("tlbsync");
123 asm volatile("sync");
127 void
128 arch_cpu_invalidate_TLB_list(addr_t pages[], int num_pages)
130 int i;
132 asm volatile("sync");
133 for (i = 0; i < num_pages; i++) {
134 asm volatile("tlbie %0" :: "r" (pages[i]));
135 asm volatile("eieio");
136 asm volatile("sync");
138 asm volatile("tlbsync");
139 asm volatile("sync");
143 void
144 arch_cpu_global_TLB_invalidate(void)
146 if (sHasTlbia) {
147 ppc_sync();
148 tlbia();
149 ppc_sync();
150 } else {
151 addr_t address = 0;
152 unsigned long i;
154 ppc_sync();
155 for (i = 0; i < 0x100000; i++) {
156 tlbie(address);
157 eieio();
158 ppc_sync();
160 address += B_PAGE_SIZE;
162 tlbsync();
163 ppc_sync();
168 void
169 arch_cpu_user_TLB_invalidate(void)
171 arch_cpu_global_TLB_invalidate();
175 // TODO: all functions that use fault handlers need to be implemented
176 // in assembly due to problems passing in label addresses in gcc4.
178 status_t
179 arch_cpu_user_memcpy(void *to, const void *from, size_t size,
180 addr_t *faultHandler)
182 char *tmp = (char *)to;
183 char *s = (char *)from;
184 addr_t oldFaultHandler = *faultHandler;
186 // TODO: This doesn't work correctly with gcc 4 anymore!
187 if (ppc_set_fault_handler(faultHandler, (addr_t)&&error))
188 goto error;
190 while (size--)
191 *tmp++ = *s++;
193 *faultHandler = oldFaultHandler;
194 return 0;
196 error:
197 *faultHandler = oldFaultHandler;
198 return B_BAD_ADDRESS;
202 /** \brief Copies at most (\a size - 1) characters from the string in \a from to
203 * the string in \a to, NULL-terminating the result.
205 * \param to Pointer to the destination C-string.
206 * \param from Pointer to the source C-string.
207 * \param size Size in bytes of the string buffer pointed to by \a to.
209 * \return strlen(\a from).
212 ssize_t
213 arch_cpu_user_strlcpy(char *to, const char *from, size_t size, addr_t *faultHandler)
215 int from_length = 0;
216 addr_t oldFaultHandler = *faultHandler;
218 // TODO: This doesn't work correctly with gcc 4 anymore!
219 if (ppc_set_fault_handler(faultHandler, (addr_t)&&error))
220 goto error;
222 if (size > 0) {
223 to[--size] = '\0';
224 // copy
225 for ( ; size; size--, from_length++, to++, from++) {
226 if ((*to = *from) == '\0')
227 break;
230 // count any leftover from chars
231 while (*from++ != '\0')
232 from_length++;
234 *faultHandler = oldFaultHandler;
235 return from_length;
237 error:
238 *faultHandler = oldFaultHandler;
239 return B_BAD_ADDRESS;
243 status_t
244 arch_cpu_user_memset(void *s, char c, size_t count, addr_t *faultHandler)
246 char *xs = (char *)s;
247 addr_t oldFaultHandler = *faultHandler;
249 // TODO: This doesn't work correctly with gcc 4 anymore!
250 if (ppc_set_fault_handler(faultHandler, (addr_t)&&error))
251 goto error;
253 while (count--)
254 *xs++ = c;
256 *faultHandler = oldFaultHandler;
257 return 0;
259 error:
260 *faultHandler = oldFaultHandler;
261 return B_BAD_ADDRESS;
265 status_t
266 arch_cpu_shutdown(bool reboot)
268 PPCPlatform::Default()->ShutDown(reboot);
269 return B_ERROR;
273 // The purpose of this function is to trick the compiler. When setting the
274 // page_handler to a label that is obviously (to the compiler) never used,
275 // it may reorganize the control flow, so that the labeled part is optimized
276 // away.
277 // By invoking the function like this
279 // if (ppc_set_fault_handler(faultHandler, (addr_t)&&error))
280 // goto error;
282 // the compiler has to keep the labeled code, since it can't guess the return
283 // value of this (non-inlinable) function. At least in my tests it worked that
284 // way, and I hope it will continue to work like this in the future.
286 bool
287 ppc_set_fault_handler(addr_t *handlerLocation, addr_t handler)
289 // TODO: This doesn't work correctly with gcc 4 anymore!
290 *handlerLocation = handler;
291 return false;