xref: /netbsd/sys/arch/hppa/hppa/hppa_machdep.c (revision 6550d01e)
1 /*	$NetBSD: hppa_machdep.c,v 1.23 2011/01/14 02:06:26 rmind Exp $	*/
2 
3 /*-
4  * Copyright (c) 1997 The NetBSD Foundation, Inc.
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  *
16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: hppa_machdep.c,v 1.23 2011/01/14 02:06:26 rmind Exp $");
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/sa.h>
35 #include <sys/lwp.h>
36 #include <sys/savar.h>
37 #include <sys/proc.h>
38 #include <sys/ras.h>
39 #include <sys/cpu.h>
40 
41 #include <sys/kernel.h>
42 
43 #include <uvm/uvm_extern.h>
44 
45 #include <machine/cpufunc.h>
46 #include <machine/pcb.h>
47 #include <machine/mcontext.h>
48 #include <hppa/hppa/machdep.h>
49 
50 /* the following is used externally (sysctl_hw) */
51 char	machine_arch[] = MACHINE_ARCH;	/* from <machine/param.h> */
52 
53 /*
54  * XXX fredette - much of the TLB trap handler setup should
55  * probably be moved here from hp700/hp700/machdep.c, seeing
56  * that there's related code already in hppa/hppa/trap.S.
57  */
58 
59 
60 /*
61  * Scheduler activations upcall frame.  Pushed onto user stack before
62  * calling an SA upcall.
63  */
64 
65 struct saframe {
66 	/* first 4 arguments passed in registers on entry to upcallcode */
67 	void *		sa_arg;
68 	int		sa_interrupted;	/* arg3 */
69 	int		sa_events;	/* arg2 */
70 	struct sa_t **	sa_sas;		/* arg1 */
71 	int		sa_type;	/* arg0 */
72 };
73 
74 /*
75  * cpu_upcall:
76  *
77  *      Send an an upcall to userland.
78  */
79 
80 void
81 cpu_upcall(struct lwp *l, int type, int nevents, int ninterrupted,
82 	   void *sas, void *ap, void *sp, sa_upcall_t upcall)
83 {
84 	struct saframe *sf, frame;
85 	struct proc *p = l->l_proc;
86 	struct trapframe *tf;
87 	uintptr_t upva;
88 	vaddr_t va;
89 
90 	tf = (struct trapframe *)l->l_md.md_regs;
91 
92 	frame.sa_type = type;
93 	frame.sa_sas = sas;
94 	frame.sa_events = nevents;
95 	frame.sa_interrupted = ninterrupted;
96 	frame.sa_arg = ap;
97 
98 	pmap_activate(l);
99 	va = HPPA_FRAME_ROUND((uintptr_t)sp + sizeof(frame) + HPPA_FRAME_SIZE);
100 	sf = (void *)(va - 32 - sizeof(frame));
101 	if (copyout(&frame, sf, sizeof(frame)) != 0) {
102 		/* Copying onto the stack didn't work. Die. */
103 		mutex_enter(p->p_lock);
104 		sigexit(l, SIGILL);
105 		/* NOTREACHED */
106 	}
107 
108 	/*
109 	 * Deal with the upcall function pointer being a PLABEL.
110 	 */
111 
112 	upva = (uintptr_t)upcall;
113 	if (upva & 2) {
114 		upva &= ~3;
115 		if (copyin((void *)(upva + 4), &tf->tf_t4, 4)) {
116 			printf("copyin t4 failed\n");
117 			mutex_enter(p->p_lock);
118 			sigexit(l, SIGILL);
119 			/* NOTREACHED */
120 		}
121 		if (copyin((void *)upva, &upcall, 4)) {
122 			printf("copyin upcall failed\n");
123 			mutex_enter(p->p_lock);
124 			sigexit(l, SIGILL);
125 			/* NOTREACHED */
126 		}
127 	}
128 
129 	tf->tf_iioq_head = (uintptr_t)upcall | HPPA_PC_PRIV_USER;
130 	tf->tf_iioq_tail = tf->tf_iioq_head + 4;
131 
132 	tf->tf_sp = va;
133 	tf->tf_arg0 = type;
134 	tf->tf_arg1 = (uintptr_t)sas;
135 	tf->tf_arg2 = nevents;
136 	tf->tf_arg3 = ninterrupted;
137 	tf->tf_rp = 0;
138 }
139 
140 void
141 cpu_getmcontext(struct lwp *l, mcontext_t *mcp, unsigned int *flags)
142 {
143 	struct trapframe *tf = l->l_md.md_regs;
144 	struct pcb *pcb = lwp_getpcb(l);
145 	__greg_t *gr = mcp->__gregs;
146 	__greg_t ras_pc;
147 
148 	gr[0]  = tf->tf_ipsw;
149 	gr[1]  = tf->tf_r1;
150 	gr[2]  = tf->tf_rp;
151 	gr[3]  = tf->tf_r3;
152 	gr[4]  = tf->tf_r4;
153 	gr[5]  = tf->tf_r5;
154 	gr[6]  = tf->tf_r6;
155 	gr[7]  = tf->tf_r7;
156 	gr[8]  = tf->tf_r8;
157 	gr[9]  = tf->tf_r9;
158 	gr[10] = tf->tf_r10;
159 	gr[11] = tf->tf_r11;
160 	gr[12] = tf->tf_r12;
161 	gr[13] = tf->tf_r13;
162 	gr[14] = tf->tf_r14;
163 	gr[15] = tf->tf_r15;
164 	gr[16] = tf->tf_r16;
165 	gr[17] = tf->tf_r17;
166 	gr[18] = tf->tf_r18;
167 	gr[19] = tf->tf_t4;
168 	gr[20] = tf->tf_t3;
169 	gr[21] = tf->tf_t2;
170 	gr[22] = tf->tf_t1;
171 	gr[23] = tf->tf_arg3;
172 	gr[24] = tf->tf_arg2;
173 	gr[25] = tf->tf_arg1;
174 	gr[26] = tf->tf_arg0;
175 	gr[27] = tf->tf_dp;
176 	gr[28] = tf->tf_ret0;
177 	gr[29] = tf->tf_ret1;
178 	gr[30] = tf->tf_sp;
179 	gr[31] = tf->tf_r31;
180 
181 	gr[_REG_SAR] = tf->tf_sar;
182 	gr[_REG_PCSQH] = tf->tf_iisq_head;
183 	gr[_REG_PCSQT] = tf->tf_iisq_tail;
184 	gr[_REG_PCOQH] = tf->tf_iioq_head;
185 	gr[_REG_PCOQT] = tf->tf_iioq_tail;
186 	gr[_REG_SR0] = tf->tf_sr0;
187 	gr[_REG_SR1] = tf->tf_sr1;
188 	gr[_REG_SR2] = tf->tf_sr2;
189 	gr[_REG_SR3] = tf->tf_sr3;
190 	gr[_REG_SR4] = tf->tf_sr4;
191 #if 0
192 	gr[_REG_CR26] = tf->tf_cr26;
193 	gr[_REG_CR27] = tf->tf_cr27;
194 #endif
195 
196 	ras_pc = (__greg_t)ras_lookup(l->l_proc,
197 	    (void *)(gr[_REG_PCOQH] & ~HPPA_PC_PRIV_MASK));
198 	if (ras_pc != -1) {
199 		ras_pc |= HPPA_PC_PRIV_USER;
200 		gr[_REG_PCOQH] = ras_pc;
201 		gr[_REG_PCOQT] = ras_pc + 4;
202 	}
203 
204 	*flags |= _UC_CPU;
205 
206 	if (l->l_md.md_flags & 0) {
207 		return;
208 	}
209 
210 	hppa_fpu_flush(l);
211 	memcpy(&mcp->__fpregs, pcb->pcb_fpregs, sizeof(mcp->__fpregs));
212 	*flags |= _UC_FPU;
213 }
214 
215 int
216 cpu_setmcontext(struct lwp *l, const mcontext_t *mcp, unsigned int flags)
217 {
218 	struct trapframe *tf = l->l_md.md_regs;
219 	struct proc *p = l->l_proc;
220 	struct pmap *pmap = p->p_vmspace->vm_map.pmap;
221 	const __greg_t *gr = mcp->__gregs;
222 
223 	if ((flags & _UC_CPU) != 0) {
224 
225 		if ((gr[_REG_PSW] & (PSW_MBS|PSW_MBZ)) != PSW_MBS) {
226 			return EINVAL;
227 		}
228 
229 #if 0
230 		/*
231 		 * XXX
232 		 * Force the space regs and priviledge bits to
233 		 * the right values in the trapframe for now.
234 		 */
235 
236 		if (gr[_REG_PCSQH] != pmap_sid(pmap, gr[_REG_PCOQH])) {
237 			return EINVAL;
238 		}
239 
240 		if (gr[_REG_PCSQT] != pmap_sid(pmap, gr[_REG_PCOQT])) {
241 			return EINVAL;
242 		}
243 
244 		if (gr[_REG_PCOQH] < 0xc0000020 &&
245 		    (gr[_REG_PCOQH] & HPPA_PC_PRIV_MASK) != HPPA_PC_PRIV_USER) {
246 			return EINVAL;
247 		}
248 
249 		if (gr[_REG_PCOQT] < 0xc0000020 &&
250 		    (gr[_REG_PCOQT] & HPPA_PC_PRIV_MASK) != HPPA_PC_PRIV_USER) {
251 			return EINVAL;
252 		}
253 #endif
254 
255 		tf->tf_ipsw	= gr[0] |
256 		    (hppa_cpu_ispa20_p() ? PSW_O : 0);
257 		tf->tf_r1	= gr[1];
258 		tf->tf_rp	= gr[2];
259 		tf->tf_r3	= gr[3];
260 		tf->tf_r4	= gr[4];
261 		tf->tf_r5	= gr[5];
262 		tf->tf_r6	= gr[6];
263 		tf->tf_r7	= gr[7];
264 		tf->tf_r8	= gr[8];
265 		tf->tf_r9	= gr[9];
266 		tf->tf_r10	= gr[10];
267 		tf->tf_r11	= gr[11];
268 		tf->tf_r12	= gr[12];
269 		tf->tf_r13	= gr[13];
270 		tf->tf_r14	= gr[14];
271 		tf->tf_r15	= gr[15];
272 		tf->tf_r16	= gr[16];
273 		tf->tf_r17	= gr[17];
274 		tf->tf_r18	= gr[18];
275 		tf->tf_t4	= gr[19];
276 		tf->tf_t3	= gr[20];
277 		tf->tf_t2	= gr[21];
278 		tf->tf_t1	= gr[22];
279 		tf->tf_arg3	= gr[23];
280 		tf->tf_arg2	= gr[24];
281 		tf->tf_arg1	= gr[25];
282 		tf->tf_arg0	= gr[26];
283 		tf->tf_dp	= gr[27];
284 		tf->tf_ret0	= gr[28];
285 		tf->tf_ret1	= gr[29];
286 		tf->tf_sp	= gr[30];
287 		tf->tf_r31	= gr[31];
288 		tf->tf_sar	= gr[_REG_SAR];
289 		tf->tf_iisq_head = pmap_sid(pmap, gr[_REG_PCOQH]);
290 		tf->tf_iisq_tail = pmap_sid(pmap, gr[_REG_PCOQT]);
291 
292 		tf->tf_iioq_head = gr[_REG_PCOQH];
293 		tf->tf_iioq_tail = gr[_REG_PCOQT];
294 
295 		if (tf->tf_iioq_head >= 0xc0000020) {
296 			tf->tf_iioq_head &= ~HPPA_PC_PRIV_MASK;
297 		} else {
298 			tf->tf_iioq_head |= HPPA_PC_PRIV_USER;
299 		}
300 		if (tf->tf_iioq_tail >= 0xc0000020) {
301 			tf->tf_iioq_tail &= ~HPPA_PC_PRIV_MASK;
302 		} else {
303 			tf->tf_iioq_tail |= HPPA_PC_PRIV_USER;
304 		}
305 
306 #if 0
307 		tf->tf_sr0	= gr[_REG_SR0];
308 		tf->tf_sr1	= gr[_REG_SR1];
309 		tf->tf_sr2	= gr[_REG_SR2];
310 		tf->tf_sr3	= gr[_REG_SR3];
311 		tf->tf_sr4	= gr[_REG_SR4];
312 		tf->tf_cr26	= gr[_REG_CR26];
313 		tf->tf_cr27	= gr[_REG_CR27];
314 #endif
315 	}
316 
317 	if ((flags & _UC_FPU) != 0) {
318 		struct pcb *pcb = lwp_getpcb(l);
319 
320 		hppa_fpu_flush(l);
321 		memcpy(pcb->pcb_fpregs, &mcp->__fpregs, sizeof(mcp->__fpregs));
322 	}
323 
324 	mutex_enter(p->p_lock);
325 	if (flags & _UC_SETSTACK)
326 		l->l_sigstk.ss_flags |= SS_ONSTACK;
327 	if (flags & _UC_CLRSTACK)
328 		l->l_sigstk.ss_flags &= ~SS_ONSTACK;
329 	mutex_exit(p->p_lock);
330 
331 	return 0;
332 }
333 
334 /*
335  * Do RAS processing.
336  */
337 
338 void
339 hppa_ras(struct lwp *l)
340 {
341 	struct proc *p;
342 	struct trapframe *tf;
343 	intptr_t rasaddr;
344 
345 	p = l->l_proc;
346 	tf = l->l_md.md_regs;
347 	rasaddr = (intptr_t)ras_lookup(p, (void *)tf->tf_iioq_head);
348 	if (rasaddr != -1) {
349 		rasaddr |= HPPA_PC_PRIV_USER;
350 		tf->tf_iioq_head = rasaddr;
351 		tf->tf_iioq_tail = rasaddr + 4;
352 	}
353 }
354 
355 /*
356  * Preempt the current LWP if in interrupt from user mode,
357  * or after the current trap/syscall if in system mode.
358  */
359 void
360 cpu_need_resched(struct cpu_info *ci, int flags)
361 {
362 	bool immed = (flags & RESCHED_IMMED) != 0;
363 
364 	if (ci->ci_want_resched && !immed)
365 		return;
366 	ci->ci_want_resched = 1;
367 	setsoftast(ci->ci_data.cpu_onproc);
368 
369 #ifdef MULTIPROCESSOR
370 	if (ci->ci_curlwp != ci->ci_data.cpu_idlelwp) {
371 		if (immed && ci != curcpu()) {
372 			/* XXX send IPI */
373 		}
374 	}
375 #endif
376 }
377