xref: /netbsd/sys/arch/hppa/hppa/hppa_machdep.c (revision 5084766f)
1 /*	$NetBSD: hppa_machdep.c,v 1.33 2022/05/13 18:40:02 skrll Exp $	*/
2 
3 /*-
4  * Copyright (c) 1997, 2019 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.33 2022/05/13 18:40:02 skrll Exp $");
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/lwp.h>
35 #include <sys/proc.h>
36 #include <sys/ras.h>
37 #include <sys/cpu.h>
38 
39 #include <sys/kernel.h>
40 
41 #include <uvm/uvm_extern.h>
42 
43 #include <machine/cpufunc.h>
44 #include <machine/pcb.h>
45 #include <machine/mcontext.h>
46 #include <hppa/hppa/machdep.h>
47 
48 /* the following is used externally (sysctl_hw) */
49 char	machine_arch[] = MACHINE_ARCH;	/* from <machine/param.h> */
50 
51 /*
52  * XXX fredette - much of the TLB trap handler setup should
53  * probably be moved here from hppa/hppa/machdep.c, seeing
54  * that there's related code already in hppa/hppa/trap.S.
55  */
56 
57 void
cpu_getmcontext(struct lwp * l,mcontext_t * mcp,unsigned int * flags)58 cpu_getmcontext(struct lwp *l, mcontext_t *mcp, unsigned int *flags)
59 {
60 	struct trapframe *tf = l->l_md.md_regs;
61 	struct pcb *pcb = lwp_getpcb(l);
62 	__greg_t *gr = mcp->__gregs;
63 	__greg_t ras_pc;
64 
65 	gr[0]  = tf->tf_ipsw;
66 	gr[1]  = tf->tf_r1;
67 	gr[2]  = tf->tf_rp;
68 	gr[3]  = tf->tf_r3;
69 	gr[4]  = tf->tf_r4;
70 	gr[5]  = tf->tf_r5;
71 	gr[6]  = tf->tf_r6;
72 	gr[7]  = tf->tf_r7;
73 	gr[8]  = tf->tf_r8;
74 	gr[9]  = tf->tf_r9;
75 	gr[10] = tf->tf_r10;
76 	gr[11] = tf->tf_r11;
77 	gr[12] = tf->tf_r12;
78 	gr[13] = tf->tf_r13;
79 	gr[14] = tf->tf_r14;
80 	gr[15] = tf->tf_r15;
81 	gr[16] = tf->tf_r16;
82 	gr[17] = tf->tf_r17;
83 	gr[18] = tf->tf_r18;
84 	gr[19] = tf->tf_t4;
85 	gr[20] = tf->tf_t3;
86 	gr[21] = tf->tf_t2;
87 	gr[22] = tf->tf_t1;
88 	gr[23] = tf->tf_arg3;
89 	gr[24] = tf->tf_arg2;
90 	gr[25] = tf->tf_arg1;
91 	gr[26] = tf->tf_arg0;
92 	gr[27] = tf->tf_dp;
93 	gr[28] = tf->tf_ret0;
94 	gr[29] = tf->tf_ret1;
95 	gr[30] = tf->tf_sp;
96 	gr[31] = tf->tf_r31;
97 
98 	gr[_REG_SAR] = tf->tf_sar;
99 	gr[_REG_PCSQH] = tf->tf_iisq_head;
100 	gr[_REG_PCSQT] = tf->tf_iisq_tail;
101 	gr[_REG_PCOQH] = tf->tf_iioq_head;
102 	gr[_REG_PCOQT] = tf->tf_iioq_tail;
103 	gr[_REG_SR0] = tf->tf_sr0;
104 	gr[_REG_SR1] = tf->tf_sr1;
105 	gr[_REG_SR2] = tf->tf_sr2;
106 	gr[_REG_SR3] = tf->tf_sr3;
107 	gr[_REG_SR4] = tf->tf_sr4;
108 	gr[_REG_CR27] = tf->tf_cr27;
109 #if 0
110 	gr[_REG_CR26] = tf->tf_cr26;
111 #endif
112 
113 	ras_pc = (__greg_t)ras_lookup(l->l_proc,
114 	    (void *)(gr[_REG_PCOQH] & ~HPPA_PC_PRIV_MASK));
115 	if (ras_pc != -1) {
116 		ras_pc |= HPPA_PC_PRIV_USER;
117 		gr[_REG_PCOQH] = ras_pc;
118 		gr[_REG_PCOQT] = ras_pc + 4;
119 	}
120 
121 	*flags |= _UC_CPU | _UC_TLSBASE;
122 
123 	if (l->l_md.md_flags & 0) {
124 		return;
125 	}
126 
127 	hppa_fpu_flush(l);
128 	memcpy(&mcp->__fpregs, pcb->pcb_fpregs, sizeof(mcp->__fpregs));
129 	*flags |= _UC_FPU;
130 }
131 
132 int
cpu_mcontext_validate(struct lwp * l,const mcontext_t * mcp)133 cpu_mcontext_validate(struct lwp *l, const mcontext_t *mcp)
134 {
135 	const __greg_t *gr = mcp->__gregs;
136 
137 	if ((gr[_REG_PSW] & (PSW_MBS|PSW_MBZ)) != PSW_MBS) {
138 		return EINVAL;
139 	}
140 
141 #if 0
142 	/*
143 	 * XXX
144 	 * Force the space regs and privilege bits to
145 	 * the right values in the trapframe for now.
146 	 */
147 
148 	if (gr[_REG_PCSQH] != pmap_sid(pmap, gr[_REG_PCOQH])) {
149 		return EINVAL;
150 	}
151 
152 	if (gr[_REG_PCSQT] != pmap_sid(pmap, gr[_REG_PCOQT])) {
153 		return EINVAL;
154 	}
155 
156 	if (gr[_REG_PCOQH] < 0xc0000020 &&
157 	    (gr[_REG_PCOQH] & HPPA_PC_PRIV_MASK) != HPPA_PC_PRIV_USER) {
158 		return EINVAL;
159 	}
160 
161 	if (gr[_REG_PCOQT] < 0xc0000020 &&
162 	    (gr[_REG_PCOQT] & HPPA_PC_PRIV_MASK) != HPPA_PC_PRIV_USER) {
163 		return EINVAL;
164 	}
165 #endif
166 
167 	return 0;
168 }
169 
170 int
cpu_setmcontext(struct lwp * l,const mcontext_t * mcp,unsigned int flags)171 cpu_setmcontext(struct lwp *l, const mcontext_t *mcp, unsigned int flags)
172 {
173 	struct trapframe *tf = l->l_md.md_regs;
174 	struct proc *p = l->l_proc;
175 	struct pmap *pmap = p->p_vmspace->vm_map.pmap;
176 	const __greg_t *gr = mcp->__gregs;
177 	int error;
178 
179 	if ((flags & _UC_CPU) != 0) {
180 		error = cpu_mcontext_validate(l, mcp);
181 		if (error)
182 			return error;
183 
184 		tf->tf_ipsw	= gr[0] |
185 		    (hppa_cpu_ispa20_p() ? PSW_O : 0);
186 		tf->tf_r1	= gr[1];
187 		tf->tf_rp	= gr[2];
188 		tf->tf_r3	= gr[3];
189 		tf->tf_r4	= gr[4];
190 		tf->tf_r5	= gr[5];
191 		tf->tf_r6	= gr[6];
192 		tf->tf_r7	= gr[7];
193 		tf->tf_r8	= gr[8];
194 		tf->tf_r9	= gr[9];
195 		tf->tf_r10	= gr[10];
196 		tf->tf_r11	= gr[11];
197 		tf->tf_r12	= gr[12];
198 		tf->tf_r13	= gr[13];
199 		tf->tf_r14	= gr[14];
200 		tf->tf_r15	= gr[15];
201 		tf->tf_r16	= gr[16];
202 		tf->tf_r17	= gr[17];
203 		tf->tf_r18	= gr[18];
204 		tf->tf_t4	= gr[19];
205 		tf->tf_t3	= gr[20];
206 		tf->tf_t2	= gr[21];
207 		tf->tf_t1	= gr[22];
208 		tf->tf_arg3	= gr[23];
209 		tf->tf_arg2	= gr[24];
210 		tf->tf_arg1	= gr[25];
211 		tf->tf_arg0	= gr[26];
212 		tf->tf_dp	= gr[27];
213 		tf->tf_ret0	= gr[28];
214 		tf->tf_ret1	= gr[29];
215 		tf->tf_sp	= gr[30];
216 		tf->tf_r31	= gr[31];
217 		tf->tf_sar	= gr[_REG_SAR];
218 		tf->tf_iisq_head = pmap_sid(pmap, gr[_REG_PCOQH]);
219 		tf->tf_iisq_tail = pmap_sid(pmap, gr[_REG_PCOQT]);
220 
221 		tf->tf_iioq_head = gr[_REG_PCOQH];
222 		tf->tf_iioq_tail = gr[_REG_PCOQT];
223 
224 		if (tf->tf_iioq_head >= 0xc0000020) {
225 			tf->tf_iioq_head &= ~HPPA_PC_PRIV_MASK;
226 		} else {
227 			tf->tf_iioq_head |= HPPA_PC_PRIV_USER;
228 		}
229 		if (tf->tf_iioq_tail >= 0xc0000020) {
230 			tf->tf_iioq_tail &= ~HPPA_PC_PRIV_MASK;
231 		} else {
232 			tf->tf_iioq_tail |= HPPA_PC_PRIV_USER;
233 		}
234 
235 #if 0
236 		tf->tf_sr0	= gr[_REG_SR0];
237 		tf->tf_sr1	= gr[_REG_SR1];
238 		tf->tf_sr2	= gr[_REG_SR2];
239 		tf->tf_sr3	= gr[_REG_SR3];
240 		tf->tf_sr4	= gr[_REG_SR4];
241 		tf->tf_cr26	= gr[_REG_CR26];
242 #endif
243 	}
244 
245 	/* Restore the private thread context */
246 	if (flags & _UC_TLSBASE) {
247 		lwp_setprivate(l, (void *)(uintptr_t)gr[_REG_CR27]);
248 		tf->tf_cr27	= gr[_REG_CR27];
249 	}
250 
251 	/* Restore the floating point registers */
252 	if ((flags & _UC_FPU) != 0) {
253 		struct pcb *pcb = lwp_getpcb(l);
254 
255 		hppa_fpu_flush(l);
256 		memcpy(pcb->pcb_fpregs, &mcp->__fpregs, sizeof(mcp->__fpregs));
257 	}
258 
259 	mutex_enter(p->p_lock);
260 	if (flags & _UC_SETSTACK)
261 		l->l_sigstk.ss_flags |= SS_ONSTACK;
262 	if (flags & _UC_CLRSTACK)
263 		l->l_sigstk.ss_flags &= ~SS_ONSTACK;
264 	mutex_exit(p->p_lock);
265 
266 	return 0;
267 }
268 
269 /*
270  * Do RAS processing.
271  */
272 
273 void
hppa_ras(struct lwp * l)274 hppa_ras(struct lwp *l)
275 {
276 	struct proc *p;
277 	struct trapframe *tf;
278 	intptr_t rasaddr;
279 
280 	p = l->l_proc;
281 	tf = l->l_md.md_regs;
282 
283 	rasaddr = (intptr_t)ras_lookup(p,
284 	    (void *)(tf->tf_iioq_head & ~HPPA_PC_PRIV_MASK));
285 	if (rasaddr != -1) {
286 		rasaddr |= HPPA_PC_PRIV_USER;
287 		tf->tf_iioq_head = rasaddr;
288 		tf->tf_iioq_tail = rasaddr + 4;
289 	}
290 }
291 
292 /*
293  * Preempt the current LWP if in interrupt from user mode,
294  * or after the current trap/syscall if in system mode.
295  */
296 void
cpu_need_resched(struct cpu_info * ci,struct lwp * l,int flags)297 cpu_need_resched(struct cpu_info *ci, struct lwp *l, int flags)
298 {
299 
300 	if ((flags & RESCHED_REMOTE) != 0) {
301 #ifdef MULTIPROCESSOR
302 		/* XXX send IPI */
303 #endif
304 	} else {
305 		setsoftast(l);
306 	}
307 }
308 
309 #ifdef MODULAR
310 struct lwp *
hppa_curlwp(void)311 hppa_curlwp(void)
312 {
313 	return curlwp;
314 }
315 
316 struct cpu_info *
hppa_curcpu(void)317 hppa_curcpu(void)
318 {
319 	return curcpu();
320 }
321 #endif
322 
323