1 /* $OpenBSD: m88k_machdep.c,v 1.73 2024/05/28 09:27:54 claudio Exp $ */
2 /*
3 * Copyright (c) 1998, 1999, 2000, 2001 Steve Murphree, Jr.
4 * Copyright (c) 1996 Nivas Madhur
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Nivas Madhur.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33 /*
34 * Mach Operating System
35 * Copyright (c) 1993-1991 Carnegie Mellon University
36 * Copyright (c) 1991 OMRON Corporation
37 * All Rights Reserved.
38 *
39 * Permission to use, copy, modify and distribute this software and its
40 * documentation is hereby granted, provided that both the copyright
41 * notice and this permission notice appear in all copies of the
42 * software, derivative works or modified versions, and any portions
43 * thereof, and that both notices appear in supporting documentation.
44 *
45 */
46
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/kernel.h>
50 #include <sys/proc.h>
51 #include <sys/user.h>
52 #include <sys/msgbuf.h>
53 #include <sys/exec.h>
54 #include <sys/errno.h>
55 #include <sys/malloc.h>
56 #ifdef MULTIPROCESSOR
57 #include <sys/mplock.h>
58 #endif
59
60 #include <machine/asm.h>
61 #include <machine/asm_macro.h>
62 #include <machine/atomic.h>
63 #include <machine/cmmu.h>
64 #include <machine/cpu.h>
65 #include <machine/reg.h>
66 #ifdef M88100
67 #include <machine/m88100.h>
68 #endif
69
70 #include <uvm/uvm_extern.h>
71
72 #ifdef DDB
73 #include <machine/db_machdep.h>
74 #include <ddb/db_extern.h>
75 #include <ddb/db_interface.h>
76 #endif /* DDB */
77
78 typedef struct {
79 u_int32_t word_one, word_two;
80 } m88k_exception_vector_area;
81
82 void dumpconf(void);
83 void dumpsys(void);
84 void regdump(struct trapframe *f);
85 void *vector_init(m88k_exception_vector_area *, u_int32_t *, int);
86 void atomic_init(void);
87
88 /*
89 * CMMU and CPU variables
90 */
91
92 #ifdef MULTIPROCESSOR
93 cpuid_t master_cpu;
94 __cpu_simple_lock_t cmmu_cpu_lock = __SIMPLELOCK_UNLOCKED;
95 #endif
96
97 struct cpu_info m88k_cpus[MAX_CPUS] = {
98 #ifndef MULTIPROCESSOR
99 { .ci_flags = CIF_ALIVE | CIF_PRIMARY }
100 #endif
101 };
102 const struct cmmu_p *cmmu;
103
104 /*
105 * safepri is a safe priority for sleep to set for a spin-wait
106 * during autoconfiguration or after a panic.
107 */
108 int safepri = IPL_NONE;
109
110 /*
111 * Set registers on exec.
112 * Clear all except sp and pc.
113 */
114 void
setregs(struct proc * p,struct exec_package * pack,u_long stack,struct ps_strings * arginfo)115 setregs(struct proc *p, struct exec_package *pack, u_long stack,
116 struct ps_strings *arginfo)
117 {
118 struct trapframe *tf = (struct trapframe *)USER_REGS(p);
119
120 /*
121 * Setup proper floating-point settings. This is necessary because
122 * we will return through the exception path, which only saves the
123 * integer registers, and not through cpu_switchto() (which saves
124 * fcr62 and fcr63 in the pcb). This is safe to do here since the
125 * FPU is enabled and the kernel doesn't use it.
126 */
127 __asm__ volatile ("fstcr %r0, %fcr0");
128 __asm__ volatile ("fstcr %r0, %fcr62");
129 __asm__ volatile ("fstcr %r0, %fcr63");
130
131 memset(tf, 0, sizeof *tf);
132
133 #ifdef M88110
134 if (CPU_IS88110) {
135 /*
136 * user mode, interrupts enabled,
137 * graphics unit, fp enabled
138 */
139 tf->tf_epsr = PSR_SFD;
140 }
141 #endif
142 #ifdef M88100
143 if (CPU_IS88100) {
144 /*
145 * user mode, interrupts enabled,
146 * no graphics unit, fp enabled
147 */
148 tf->tf_epsr = PSR_SFD | PSR_SFD2;
149 }
150 #endif
151
152 /*
153 * We want to start executing at pack->ep_entry. The way to
154 * do this is force the processor to fetch from ep_entry.
155 *
156 * However, since we will return through m{88100,88110}_syscall(),
157 * we need to setup registers so that the success return, when
158 * ``incrementing'' the instruction pointers, will cause the
159 * binary to start at the expected address.
160 *
161 * This relies on the fact that binaries start with
162 *
163 * br.n 1f
164 * or r2, r0, r30
165 * 1:
166 *
167 * So the first two instructions can be skipped.
168 */
169 #ifdef M88110
170 if (CPU_IS88110) {
171 /*
172 * The first instruction we want to run is at
173 * ep_entry + 8. m88110_syscall() returning EJUSTRETURN
174 * will resume at exip + 4, so make it point to
175 * ep_entry + 4.
176 */
177 tf->tf_exip = (pack->ep_entry & XIP_ADDR) + 4;
178 }
179 #endif
180 #ifdef M88100
181 if (CPU_IS88100) {
182 /*
183 * The first instruction we want to run is at
184 * ep_entry + 8. m88100_syscall() returning EJUSTRETURN
185 * will resume at snip, so make it point to
186 * ep_entry + 8.
187 */
188 tf->tf_snip = ((pack->ep_entry + 8) & FIP_ADDR) | FIP_V;
189 tf->tf_sfip = tf->tf_snip + 4;
190 }
191 #endif
192 tf->tf_r[2] = stack;
193 tf->tf_r[31] = stack;
194 }
195
196 #ifdef DDB
197 int longformat = 1;
198 void
regdump(struct trapframe * f)199 regdump(struct trapframe *f)
200 {
201 #define R(i) f->tf_r[i]
202 printf("R00-05: 0x%08lx 0x%08lx 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n",
203 R(0),R(1),R(2),R(3),R(4),R(5));
204 printf("R06-11: 0x%08lx 0x%08lx 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n",
205 R(6),R(7),R(8),R(9),R(10),R(11));
206 printf("R12-17: 0x%08lx 0x%08lx 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n",
207 R(12),R(13),R(14),R(15),R(16),R(17));
208 printf("R18-23: 0x%08lx 0x%08lx 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n",
209 R(18),R(19),R(20),R(21),R(22),R(23));
210 printf("R24-29: 0x%08lx 0x%08lx 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n",
211 R(24),R(25),R(26),R(27),R(28),R(29));
212 printf("R30-31: 0x%08lx 0x%08lx\n",R(30),R(31));
213 #ifdef M88110
214 if (CPU_IS88110) {
215 printf("exip %lx enip %lx\n", f->tf_exip, f->tf_enip);
216 }
217 #endif
218 #ifdef M88100
219 if (CPU_IS88100) {
220 printf("sxip %lx snip %lx sfip %lx\n",
221 f->tf_sxip, f->tf_snip, f->tf_sfip);
222 }
223 if (CPU_IS88100 && ISSET(f->tf_dmt0, DMT_VALID)) {
224 /* print dmt stuff for data access fault */
225 printf("fault type %ld\n", (f->tf_dpfsr >> 16) & 0x7);
226 dae_print((u_int *)f);
227 }
228 if (CPU_IS88100 && longformat != 0) {
229 printf("fpsr %lx fpcr %lx epsr %lx ssbr %lx\n",
230 f->tf_fpsr, f->tf_fpcr, f->tf_epsr, f->tf_ssbr);
231 printf("fpecr %lx fphs1 %lx fpls1 %lx fphs2 %lx fpls2 %lx\n",
232 f->tf_fpecr, f->tf_fphs1, f->tf_fpls1,
233 f->tf_fphs2, f->tf_fpls2);
234 printf("fppt %lx fprh %lx fprl %lx fpit %lx\n",
235 f->tf_fppt, f->tf_fprh, f->tf_fprl, f->tf_fpit);
236 printf("vector %ld mask %lx flags %lx scratch1 %lx cpu %p\n",
237 f->tf_vector, f->tf_mask, f->tf_flags,
238 f->tf_scratch1, f->tf_cpu);
239 }
240 #endif
241 #ifdef M88110
242 if (CPU_IS88110 && longformat != 0) {
243 printf("fpsr %lx fpcr %lx fpecr %lx epsr %lx\n",
244 f->tf_fpsr, f->tf_fpcr, f->tf_fpecr, f->tf_epsr);
245 printf("dsap %lx duap %lx dsr %lx dlar %lx dpar %lx\n",
246 f->tf_dsap, f->tf_duap, f->tf_dsr, f->tf_dlar, f->tf_dpar);
247 printf("isap %lx iuap %lx isr %lx ilar %lx ipar %lx\n",
248 f->tf_isap, f->tf_iuap, f->tf_isr, f->tf_ilar, f->tf_ipar);
249 printf("vector %ld mask %lx flags %lx scratch1 %lx cpu %p\n",
250 f->tf_vector, f->tf_mask, f->tf_flags,
251 f->tf_scratch1, f->tf_cpu);
252 }
253 #endif
254 }
255 #endif /* DDB */
256
257 /*
258 * Set up the cpu_info pointer and the cpu number for the current processor.
259 */
260 struct cpu_info *
set_cpu_number(cpuid_t number)261 set_cpu_number(cpuid_t number)
262 {
263 struct cpu_info *ci;
264
265 #ifdef MULTIPROCESSOR
266 ci = &m88k_cpus[number];
267 #else
268 ci = &m88k_cpus[0];
269 #endif
270 ci->ci_cpuid = number;
271
272 __asm__ volatile ("stcr %0, %%cr17" :: "r" (ci));
273 flush_pipeline();
274 return ci;
275 }
276
277 /*
278 * Notify the current process (p) that it has a signal pending,
279 * process as soon as possible.
280 */
281 void
signotify(struct proc * p)282 signotify(struct proc *p)
283 {
284 aston(p);
285 cpu_unidle(p->p_cpu);
286 }
287
288 #ifdef MULTIPROCESSOR
289 void
cpu_unidle(struct cpu_info * ci)290 cpu_unidle(struct cpu_info *ci)
291 {
292 if (ci != curcpu())
293 m88k_send_ipi(CI_IPI_NOTIFY, ci->ci_cpuid);
294 }
295 #endif
296
297 /*
298 * Preempt the current process if in interrupt from user mode,
299 * or after the current trap/syscall if in system mode.
300 */
301 void
need_resched(struct cpu_info * ci)302 need_resched(struct cpu_info *ci)
303 {
304 ci->ci_want_resched = 1;
305
306 /* There's a risk we'll be called before the idle threads start */
307 if (ci->ci_curproc != NULL) {
308 aston(ci->ci_curproc);
309 if (ci != curcpu())
310 cpu_unidle(ci);
311 }
312 }
313
314 /*
315 * Generic soft interrupt interface
316 */
317
318 void dosoftint(int);
319 int softpending;
320
321 void
dosoftint(int sir)322 dosoftint(int sir)
323 {
324 int q, mask;
325
326 #ifdef MULTIPROCESSOR
327 __mp_lock(&kernel_lock);
328 #endif
329
330 for (q = SI_NQUEUES - 1, mask = 1 << (SI_NQUEUES - 1); mask != 0;
331 q--, mask >>= 1)
332 if (mask & sir)
333 softintr_dispatch(q);
334
335 #ifdef MULTIPROCESSOR
336 __mp_unlock(&kernel_lock);
337 #endif
338 }
339
340 int
spl0()341 spl0()
342 {
343 int sir;
344 int s;
345
346 /*
347 * Try to avoid potentially expensive setipl calls if nothing
348 * seems to be pending.
349 */
350 if ((sir = atomic_clear_int(&softpending)) != 0) {
351 s = setipl(IPL_SOFTINT);
352 dosoftint(sir);
353 setipl(IPL_NONE);
354 } else
355 s = setipl(IPL_NONE);
356
357 return (s);
358 }
359
360 #define EMPTY_BR 0xc0000000 /* empty "br" instruction */
361 #define NO_OP 0xf4005800 /* "or r0, r0, r0" */
362
363 #define BRANCH(FROM, TO) \
364 (EMPTY_BR | ((((vaddr_t)(TO) - (vaddr_t)(FROM)) >> 2) & 0x03ffffff))
365
366 #define SET_VECTOR_88100(NUM, VALUE) \
367 do { \
368 vbr[NUM].word_one = NO_OP; \
369 vbr[NUM].word_two = BRANCH(&vbr[NUM].word_two, VALUE); \
370 } while (0)
371
372 #define SET_VECTOR_88110(NUM, VALUE) \
373 do { \
374 vbr[NUM].word_one = BRANCH(&vbr[NUM].word_one, VALUE); \
375 vbr[NUM].word_two = NO_OP; \
376 } while (0)
377
378 /*
379 * vector_init(vector, vector_init_list, bootstrap)
380 *
381 * This routine sets up the m88k vector table for the running processor,
382 * as well as the atomic operation routines for multiprocessor kernels.
383 * This is the first C code to run, before anything is initialized.
384 *
385 * I would add an extra four bytes to the exception vectors page pointed
386 * to by the vbr, since the 88100 may execute the first instruction of the
387 * next trap handler, as documented in its Errata. Processing trap #511
388 * would then fall into the next page, unless the address computation wraps,
389 * or software traps can not trigger the issue - the Errata does not provide
390 * more detail. And since the MVME BUG does not add an extra NOP after its
391 * VBR page, I'll assume this is safe for now -- miod
392 */
393 void *
vector_init(m88k_exception_vector_area * vbr,u_int32_t * vector_init_list,int bootstrap)394 vector_init(m88k_exception_vector_area *vbr, u_int32_t *vector_init_list,
395 int bootstrap)
396 {
397 u_int num;
398 u_int32_t vec;
399
400 switch (cputyp) {
401 default:
402 #ifdef M88110
403 case CPU_88110:
404 {
405 extern void m88110_sigsys(void);
406 extern void m88110_syscall_handler(void);
407 extern void m88110_cache_flush_handler(void);
408 extern void m88110_stepbpt(void);
409 extern void m88110_userbpt(void);
410
411 for (num = 0; (vec = vector_init_list[num]) != 0; num++)
412 SET_VECTOR_88110(num, vec);
413
414 if (bootstrap)
415 SET_VECTOR_88110(0x03, vector_init_list[num + 1]);
416
417 for (; num < 512; num++)
418 SET_VECTOR_88110(num, m88110_sigsys);
419
420 SET_VECTOR_88110(450, m88110_syscall_handler);
421 SET_VECTOR_88110(451, m88110_cache_flush_handler);
422 /*
423 * GCC will by default produce explicit trap 503
424 * for division by zero
425 */
426 SET_VECTOR_88110(503, vector_init_list[8]);
427 SET_VECTOR_88110(504, m88110_stepbpt);
428 SET_VECTOR_88110(511, m88110_userbpt);
429 }
430 break;
431 #endif
432 #ifdef M88100
433 case CPU_88100:
434 {
435 extern void sigsys(void);
436 extern void syscall_handler(void);
437 extern void cache_flush_handler(void);
438 extern void stepbpt(void);
439 extern void userbpt(void);
440
441 for (num = 0; (vec = vector_init_list[num]) != 0; num++)
442 SET_VECTOR_88100(num, vec);
443
444 if (bootstrap)
445 SET_VECTOR_88100(0x03, vector_init_list[num + 1]);
446
447 for (; num < 512; num++)
448 SET_VECTOR_88100(num, sigsys);
449
450 SET_VECTOR_88100(450, syscall_handler);
451 SET_VECTOR_88100(451, cache_flush_handler);
452 /*
453 * GCC will by default produce explicit trap 503
454 * for division by zero
455 */
456 SET_VECTOR_88100(503, vector_init_list[8]);
457 SET_VECTOR_88100(504, stepbpt);
458 SET_VECTOR_88100(511, userbpt);
459 }
460 break;
461 #endif
462 }
463
464 return vbr;
465 }
466
467 #ifdef MULTIPROCESSOR
468 /*
469 * void atomic_init(void);
470 *
471 * This routine sets up proper atomic operation code for SMP kernels
472 * with both 88100 and 88110 support compiled-in. This is crucial enough
473 * to have to be done as early as possible.
474 * This is among the first C code to run, before anything is initialized.
475 */
476 void
atomic_init()477 atomic_init()
478 {
479 #if defined(M88100) && defined(M88110)
480 if (cputyp == CPU_88100) {
481 extern uint32_t __atomic_lock[];
482 extern uint32_t __atomic_lock_88100[], __atomic_lock_88100_end[];
483 extern uint32_t __atomic_unlock[];
484 extern uint32_t __atomic_unlock_88100[], __atomic_unlock_88100_end[];
485
486 uint32_t *s, *e, *d;
487
488 d = __atomic_lock;
489 s = __atomic_lock_88100;
490 e = __atomic_lock_88100_end;
491 while (s != e)
492 *d++ = *s++;
493
494 d = __atomic_unlock;
495 s = __atomic_unlock_88100;
496 e = __atomic_unlock_88100_end;
497 while (s != e)
498 *d++ = *s++;
499 }
500 #endif /* M88100 && M88110 */
501 }
502 #endif /* MULTIPROCESSOR */
503