1 /* $NetBSD: vm_machdep.c,v 1.58 2023/02/25 08:30:31 skrll Exp $ */ 2 3 /* $OpenBSD: vm_machdep.c,v 1.64 2008/09/30 18:54:26 miod Exp $ */ 4 5 /* 6 * Copyright (c) 1999-2004 Michael Shalayeff 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 22 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 27 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 28 * THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 __KERNEL_RCSID(0, "$NetBSD: vm_machdep.c,v 1.58 2023/02/25 08:30:31 skrll Exp $"); 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/proc.h> 37 #include <sys/signalvar.h> 38 #include <sys/buf.h> 39 #include <sys/vnode.h> 40 #include <sys/ptrace.h> 41 #include <sys/exec.h> 42 #include <sys/core.h> 43 #include <sys/pool.h> 44 #include <sys/cpu.h> 45 46 #include <machine/cpufunc.h> 47 #include <machine/pmap.h> 48 #include <machine/pcb.h> 49 50 #include <uvm/uvm.h> 51 52 extern struct pool hppa_fppl; 53 54 #include <hppa/hppa/machdep.h> 55 56 static inline void 57 cpu_activate_pcb(struct lwp *l) 58 { 59 struct trapframe *tf = l->l_md.md_regs; 60 struct pcb *pcb = lwp_getpcb(l); 61 #ifdef DIAGNOSTIC 62 vaddr_t uarea = (vaddr_t)pcb; 63 vaddr_t maxsp = uarea + USPACE; 64 KASSERT(tf == (void *)(uarea + PAGE_SIZE)); 65 #endif 66 /* 67 * Stash the physical address of FP regs for later perusal 68 */ 69 tf->tf_cr30 = (u_int)pcb->pcb_fpregs; 70 71 #ifdef DIAGNOSTIC 72 /* Create the kernel stack red zone. */ 73 pmap_remove(pmap_kernel(), maxsp - PAGE_SIZE, maxsp); 74 pmap_update(pmap_kernel()); 75 #endif 76 } 77 78 void 79 cpu_proc_fork(struct proc *p1, struct proc *p2) 80 { 81 82 p2->p_md.md_flags = p1->p_md.md_flags; 83 } 84 85 void 86 cpu_lwp_fork(struct lwp *l1, struct lwp *l2, void *stack, size_t stacksize, 87 void (*func)(void *), void *arg) 88 { 89 struct pcb *pcb1, *pcb2; 90 struct trapframe *tf; 91 register_t sp, osp; 92 vaddr_t uv; 93 94 KASSERT(round_page(sizeof(struct pcb)) <= PAGE_SIZE); 95 96 pcb1 = lwp_getpcb(l1); 97 pcb2 = lwp_getpcb(l2); 98 99 KASSERT(l2->l_md.md_astpending == 0); 100 KASSERT(l2->l_md.md_flags == 0); 101 102 /* Flush the parent LWP out of the FPU. */ 103 hppa_fpu_flush(l1); 104 105 /* Now copy the parent PCB into the child. */ 106 memcpy(pcb2, pcb1, sizeof(struct pcb)); 107 108 pcb2->pcb_fpregs = pool_get(&hppa_fppl, PR_WAITOK); 109 *pcb2->pcb_fpregs = *pcb1->pcb_fpregs; 110 111 /* reset any of the pending FPU exceptions from parent */ 112 pcb2->pcb_fpregs->fpr_regs[0] = 113 HPPA_FPU_FORK(pcb2->pcb_fpregs->fpr_regs[0]); 114 pcb2->pcb_fpregs->fpr_regs[1] = 0; 115 pcb2->pcb_fpregs->fpr_regs[2] = 0; 116 pcb2->pcb_fpregs->fpr_regs[3] = 0; 117 118 l2->l_md.md_bpva = l1->l_md.md_bpva; 119 l2->l_md.md_bpsave[0] = l1->l_md.md_bpsave[0]; 120 l2->l_md.md_bpsave[1] = l1->l_md.md_bpsave[1]; 121 122 uv = uvm_lwp_getuarea(l2); 123 sp = (register_t)uv + PAGE_SIZE; 124 tf = l2->l_md.md_regs = (struct trapframe *)sp; 125 sp += sizeof(struct trapframe); 126 127 /* copy the l1's trapframe to l2 */ 128 memcpy(tf, l1->l_md.md_regs, sizeof(*tf)); 129 130 /* Fill out all the PAs we are going to need in locore. */ 131 cpu_activate_pcb(l2); 132 133 if (__predict_true(l2->l_proc->p_vmspace != NULL)) { 134 hppa_setvmspace(l2); 135 /* 136 * theoretically these could be inherited from the father, 137 * but just in case. 138 */ 139 mfctl(CR_EIEM, tf->tf_eiem); 140 tf->tf_ipsw = PSW_C | PSW_Q | PSW_P | PSW_D | PSW_I /* | PSW_L */ | 141 (curcpu()->ci_psw & PSW_O); 142 } 143 144 /* 145 * Set up return value registers as libc:fork() expects 146 */ 147 tf->tf_ret0 = l1->l_proc->p_pid; 148 tf->tf_ret1 = 1; /* ischild */ 149 tf->tf_t1 = 0; /* errno */ 150 151 /* 152 * If specified, give the child a different stack. 153 */ 154 if (stack != NULL) 155 tf->tf_sp = (register_t)stack; 156 157 /* 158 * Build stack frames for the cpu_switchto & co. 159 */ 160 osp = sp; 161 162 /* lwp_trampoline's frame */ 163 sp += HPPA_FRAME_SIZE; 164 165 *(register_t *)(sp) = 0; /* previous frame pointer */ 166 *(register_t *)(sp + HPPA_FRAME_PSP) = osp; 167 *(register_t *)(sp + HPPA_FRAME_CRP) = (register_t)lwp_trampoline; 168 169 *HPPA_FRAME_CARG(2, sp) = KERNMODE(func); 170 *HPPA_FRAME_CARG(3, sp) = (register_t)arg; 171 172 /* 173 * cpu_switchto's frame 174 * stack usage is std frame + callee-save registers 175 */ 176 sp += HPPA_FRAME_SIZE + 16*4; 177 pcb2->pcb_ksp = sp; 178 fdcache(HPPA_SID_KERNEL, uv, sp - uv); 179 } 180 181 void 182 cpu_lwp_free(struct lwp *l, int proc) 183 { 184 struct pcb *pcb = lwp_getpcb(l); 185 186 /* 187 * If this thread was using the FPU, disable the FPU and record 188 * that it's unused. 189 */ 190 191 hppa_fpu_flush(l); 192 pool_put(&hppa_fppl, pcb->pcb_fpregs); 193 } 194 195 void 196 cpu_lwp_free2(struct lwp *l) 197 { 198 199 (void)l; 200 } 201 202 /* 203 * Map an IO request into kernel virtual address space. 204 */ 205 int 206 vmapbuf(struct buf *bp, vsize_t len) 207 { 208 vaddr_t uva, kva; 209 paddr_t pa; 210 vsize_t size, off; 211 int npf; 212 struct pmap *upmap, *kpmap; 213 214 #ifdef DIAGNOSTIC 215 if ((bp->b_flags & B_PHYS) == 0) 216 panic("vmapbuf"); 217 #endif 218 upmap = vm_map_pmap(&bp->b_proc->p_vmspace->vm_map); 219 kpmap = vm_map_pmap(phys_map); 220 bp->b_saveaddr = bp->b_data; 221 uva = trunc_page((vaddr_t)bp->b_data); 222 off = (vaddr_t)bp->b_data - uva; 223 size = round_page(off + len); 224 kva = uvm_km_alloc(phys_map, len, 0, UVM_KMF_VAONLY | UVM_KMF_WAITVA); 225 bp->b_data = (void *)(kva + off); 226 npf = btoc(size); 227 while (npf--) { 228 if (pmap_extract(upmap, uva, &pa) == false) 229 panic("vmapbuf: null page frame"); 230 pmap_enter(kpmap, kva, pa, 231 VM_PROT_READ | VM_PROT_WRITE, PMAP_WIRED); 232 uva += PAGE_SIZE; 233 kva += PAGE_SIZE; 234 } 235 pmap_update(kpmap); 236 237 return 0; 238 } 239 240 /* 241 * Unmap IO request from the kernel virtual address space. 242 */ 243 void 244 vunmapbuf(struct buf *bp, vsize_t len) 245 { 246 struct pmap *pmap; 247 vaddr_t kva; 248 vsize_t off; 249 250 #ifdef DIAGNOSTIC 251 if ((bp->b_flags & B_PHYS) == 0) 252 panic("vunmapbuf"); 253 #endif 254 kva = trunc_page((vaddr_t)bp->b_data); 255 off = (vaddr_t)bp->b_data - kva; 256 len = round_page(off + len); 257 pmap = vm_map_pmap(phys_map); 258 pmap_remove(pmap, kva, kva + len); 259 pmap_update(pmap); 260 uvm_km_free(phys_map, kva, len, UVM_KMF_VAONLY); 261 bp->b_data = bp->b_saveaddr; 262 bp->b_saveaddr = NULL; 263 } 264 265 int 266 cpu_lwp_setprivate(lwp_t *l, void *addr) 267 { 268 269 l->l_md.md_regs->tf_cr27 = (u_int)addr; 270 if (l == curlwp) 271 mtctl(addr, CR_TLS); 272 return 0; 273 } 274 275