xref: /openbsd/sys/arch/hppa/hppa/vm_machdep.c (revision 0be467f4)
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