Home | History | Annotate | Line # | Download | only in hppa
      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