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