1 /* $OpenBSD: vm_machdep.c,v 1.85 2022/10/25 15:15:38 guenther 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
cpu_fork(struct proc * p1,struct proc * p2,void * stack,void * tcb,void (* func)(void *),void * arg)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)&proc_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
cpu_exit(struct proc * p)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
vmapbuf(struct buf * bp,vsize_t len)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
vunmapbuf(struct buf * bp,vsize_t len)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