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