1 /* $OpenBSD: vm_machdep.c,v 1.84 2022/05/21 23:43:31 kettenis Exp $ */ 2 3 /* 4 * Copyright (c) 1999-2004 Michael Shalayeff 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 25 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 26 * THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 30 #include <sys/param.h> 31 #include <sys/systm.h> 32 #include <sys/proc.h> 33 #include <sys/signalvar.h> 34 #include <sys/malloc.h> 35 #include <sys/buf.h> 36 #include <sys/vnode.h> 37 #include <sys/user.h> 38 #include <sys/ptrace.h> 39 #include <sys/exec.h> 40 #include <sys/pool.h> 41 42 #include <uvm/uvm_extern.h> 43 44 #include <machine/cpufunc.h> 45 #include <machine/fpu.h> 46 #include <machine/pmap.h> 47 #include <machine/pcb.h> 48 49 extern struct pool hppa_fppl; 50 51 void 52 cpu_fork(struct proc *p1, struct proc *p2, void *stack, void *tcb, 53 void (*func)(void *), void *arg) 54 { 55 struct pcb *pcbp; 56 struct trapframe *tf; 57 register_t sp; 58 59 #ifdef DIAGNOSTIC 60 if (round_page(sizeof(struct user)) > NBPG) 61 panic("USPACE too small for user"); 62 #endif 63 fpu_proc_save(p1); 64 65 pcbp = &p2->p_addr->u_pcb; 66 bcopy(&p1->p_addr->u_pcb, pcbp, sizeof(*pcbp)); 67 /* space is cached for the copy{in,out}'s pleasure */ 68 pcbp->pcb_space = p2->p_vmspace->vm_map.pmap->pm_space; 69 pcbp->pcb_fpstate = pool_get(&hppa_fppl, PR_WAITOK); 70 *pcbp->pcb_fpstate = *p1->p_addr->u_pcb.pcb_fpstate; 71 /* reset any of the pending FPU exceptions from parent */ 72 pcbp->pcb_fpstate->hfp_regs.fpr_regs[0] = 73 HPPA_FPU_FORK(pcbp->pcb_fpstate->hfp_regs.fpr_regs[0]); 74 pcbp->pcb_fpstate->hfp_regs.fpr_regs[1] = 0; 75 pcbp->pcb_fpstate->hfp_regs.fpr_regs[2] = 0; 76 pcbp->pcb_fpstate->hfp_regs.fpr_regs[3] = 0; 77 78 p2->p_md.md_bpva = p1->p_md.md_bpva; 79 p2->p_md.md_bpsave[0] = p1->p_md.md_bpsave[0]; 80 p2->p_md.md_bpsave[1] = p1->p_md.md_bpsave[1]; 81 82 sp = (register_t)p2->p_addr + NBPG; 83 p2->p_md.md_regs = tf = (struct trapframe *)sp; 84 sp += sizeof(struct trapframe); 85 bcopy(p1->p_md.md_regs, tf, sizeof(*tf)); 86 87 tf->tf_cr30 = (paddr_t)pcbp->pcb_fpstate; 88 89 tf->tf_sr0 = tf->tf_sr1 = tf->tf_sr2 = tf->tf_sr3 = 90 tf->tf_sr4 = tf->tf_sr5 = tf->tf_sr6 = 91 tf->tf_iisq_head = tf->tf_iisq_tail = 92 p2->p_vmspace->vm_map.pmap->pm_space; 93 tf->tf_pidr1 = tf->tf_pidr2 = pmap_sid2pid(tf->tf_sr0); 94 95 /* 96 * theoretically these could be inherited from the father, 97 * but just in case. 98 */ 99 tf->tf_sr7 = HPPA_SID_KERNEL; 100 mfctl(CR_EIEM, tf->tf_eiem); 101 tf->tf_ipsw = PSL_C | PSL_Q | PSL_P | PSL_D | PSL_I /* | PSL_L */ | 102 (curcpu()->ci_psw & PSL_O); 103 104 /* 105 * If specified, give the child a different stack and/or TCB 106 */ 107 if (stack != NULL) 108 setstack(tf, (u_long)stack, 0); /* XXX ignore error? */ 109 if (tcb != NULL) 110 tf->tf_cr27 = (u_long)tcb; 111 112 /* 113 * Build stack frames for the cpu_switchto & co. 114 */ 115 sp += HPPA_FRAME_SIZE; 116 *(register_t*)(sp - HPPA_FRAME_SIZE) = 0; 117 *(register_t*)(sp + HPPA_FRAME_CRP) = (register_t)&switch_trampoline; 118 *(register_t*)(sp) = (sp - HPPA_FRAME_SIZE); 119 120 sp += HPPA_FRAME_SIZE + 16*4; /* frame + callee-saved registers */ 121 *HPPA_FRAME_CARG(0, sp) = (register_t)arg; 122 *HPPA_FRAME_CARG(1, sp) = KERNMODE(func); 123 pcbp->pcb_ksp = sp; 124 } 125 126 void 127 cpu_exit(struct proc *p) 128 { 129 struct pcb *pcb = &p->p_addr->u_pcb; 130 131 fpu_proc_flush(p); 132 133 pool_put(&hppa_fppl, pcb->pcb_fpstate); 134 135 pmap_deactivate(p); 136 sched_exit(p); 137 } 138 139 struct kmem_va_mode kv_physwait = { 140 .kv_map = &phys_map, 141 .kv_wait = 1, 142 }; 143 144 /* 145 * Map an IO request into kernel virtual address space. 146 */ 147 void 148 vmapbuf(struct buf *bp, vsize_t len) 149 { 150 struct kmem_dyn_mode kd_prefer = { .kd_waitok = 1 }; 151 struct pmap *pm = vm_map_pmap(&bp->b_proc->p_vmspace->vm_map); 152 vaddr_t kva, uva; 153 vsize_t size, off; 154 155 #ifdef DIAGNOSTIC 156 if ((bp->b_flags & B_PHYS) == 0) 157 panic("vmapbuf"); 158 #endif 159 bp->b_saveaddr = bp->b_data; 160 uva = trunc_page((vaddr_t)bp->b_data); 161 off = (vaddr_t)bp->b_data - uva; 162 size = round_page(off + len); 163 164 kd_prefer.kd_prefer = uva; 165 kva = (vaddr_t)km_alloc(size, &kv_physwait, &kp_none, &kd_prefer); 166 bp->b_data = (caddr_t)(kva + off); 167 while (size > 0) { 168 paddr_t pa; 169 170 if (pmap_extract(pm, uva, &pa) == FALSE) 171 panic("vmapbuf: null page frame"); 172 else 173 pmap_kenter_pa(kva, pa, PROT_READ | PROT_WRITE); 174 uva += PAGE_SIZE; 175 kva += PAGE_SIZE; 176 size -= PAGE_SIZE; 177 } 178 pmap_update(pmap_kernel()); 179 } 180 181 /* 182 * Unmap IO request from the kernel virtual address space. 183 */ 184 void 185 vunmapbuf(struct buf *bp, vsize_t len) 186 { 187 vaddr_t addr, off; 188 189 #ifdef DIAGNOSTIC 190 if ((bp->b_flags & B_PHYS) == 0) 191 panic("vunmapbuf"); 192 #endif 193 addr = trunc_page((vaddr_t)bp->b_data); 194 off = (vaddr_t)bp->b_data - addr; 195 len = round_page(off + len); 196 pmap_kremove(addr, len); 197 pmap_update(pmap_kernel()); 198 km_free((void *)addr, len, &kv_physwait, &kp_none); 199 bp->b_data = bp->b_saveaddr; 200 bp->b_saveaddr = NULL; 201 } 202