1 /* $OpenBSD: vm_machdep.c,v 1.45 2024/03/29 21:27:53 miod Exp $ */
2 /* $NetBSD: vm_machdep.c,v 1.38 2001/06/30 00:02:20 eeh Exp $ */
3
4 /*
5 * Copyright (c) 1996
6 * The President and Fellows of Harvard College. All rights reserved.
7 * Copyright (c) 1992, 1993
8 * The Regents of the University of California. All rights reserved.
9 *
10 * This software was developed by the Computer Systems Engineering group
11 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
12 * contributed to Berkeley.
13 *
14 * All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by the University of
17 * California, Lawrence Berkeley Laboratory.
18 * This product includes software developed by Harvard University.
19 *
20 * Redistribution and use in source and binary forms, with or without
21 * modification, are permitted provided that the following conditions
22 * are met:
23 * 1. Redistributions of source code must retain the above copyright
24 * notice, this list of conditions and the following disclaimer.
25 * 2. Redistributions in binary form must reproduce the above copyright
26 * notice, this list of conditions and the following disclaimer in the
27 * documentation and/or other materials provided with the distribution.
28 * 3. All advertising materials mentioning features or use of this software
29 * must display the following acknowledgement:
30 * This product includes software developed by Harvard University.
31 * This product includes software developed by the University of
32 * California, Berkeley and its contributors.
33 * 4. Neither the name of the University nor the names of its contributors
34 * may be used to endorse or promote products derived from this software
35 * without specific prior written permission.
36 *
37 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
38 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
40 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
41 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
42 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
43 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
45 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
46 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47 * SUCH DAMAGE.
48 *
49 * @(#)vm_machdep.c 8.2 (Berkeley) 9/23/93
50 */
51
52 #include <sys/param.h>
53 #include <sys/systm.h>
54 #include <sys/proc.h>
55 #include <sys/user.h>
56 #include <sys/malloc.h>
57 #include <sys/buf.h>
58 #include <sys/exec.h>
59 #include <sys/vnode.h>
60 #include <sys/signalvar.h>
61
62 #include <uvm/uvm_extern.h>
63
64 #include <machine/cpu.h>
65 #include <machine/frame.h>
66 #include <machine/trap.h>
67 #include <machine/bus.h>
68
69 #include <sparc64/sparc64/cache.h>
70
71 /*
72 * The offset of the topmost frame in the kernel stack.
73 */
74 #define TOPFRAMEOFF (USPACE-sizeof(struct trapframe)-CC64FSZ)
75
76 #ifdef DEBUG
77 char cpu_forkname[] = "cpu_fork()";
78 #endif
79
80 /*
81 * Finish a fork operation, with process p2 nearly set up.
82 * Copy and update the pcb and trap frame, making the child ready to run.
83 *
84 * Rig the child's kernel stack so that it will start out in
85 * proc_trampoline() and call 'func' with 'arg' as an argument.
86 * For normal processes this is child_return(), which causes the
87 * child to go directly to user level with an apparent return value
88 * of 0 from fork(), while the parent process returns normally.
89 * For kernel threads this will be a function that never returns.
90 *
91 * An alternate user-level stack or TCB can be requested by passing
92 * a non-NULL value; these are poked into the PCB so they're in
93 * effect at the initial return to userspace.
94 */
95 void
cpu_fork(struct proc * p1,struct proc * p2,void * stack,void * tcb,void (* func)(void *),void * arg)96 cpu_fork(struct proc *p1, struct proc *p2, void *stack, void *tcb,
97 void (*func)(void *), void *arg)
98 {
99 struct pcb *opcb = &p1->p_addr->u_pcb;
100 struct pcb *npcb = &p2->p_addr->u_pcb;
101 struct trapframe *tf2;
102 struct rwindow *rp;
103 size_t pcbsz;
104 extern struct proc proc0;
105
106 /*
107 * Cache the physical address of the pcb, to speed up window
108 * spills in locore.
109 */
110 (void)pmap_extract(pmap_kernel(), (vaddr_t)npcb,
111 &p2->p_md.md_pcbpaddr);
112
113 /*
114 * Save all user registers to p1's stack or, in the case of
115 * user registers and invalid stack pointers, to opcb.
116 * We then copy the whole pcb to p2; when switch() selects p2
117 * to run, it will run at the `proc_trampoline' stub, rather
118 * than returning at the copying code below.
119 *
120 * If process p1 has an FPU state, we must copy it. If it is
121 * the FPU user, we must save the FPU state first.
122 */
123
124 #ifdef NOTDEF_DEBUG
125 printf("cpu_fork()\n");
126 #endif
127 if (p1 == curproc) {
128 write_user_windows();
129
130 /*
131 * We're in the kernel, so we don't really care about
132 * %ccr or %asi. We do want to duplicate %pstate and %cwp.
133 */
134 opcb->pcb_pstate = getpstate();
135 opcb->pcb_cwp = getcwp();
136 }
137 #ifdef DIAGNOSTIC
138 else if (p1 != &proc0)
139 panic("cpu_fork: curproc");
140 #endif
141 #ifdef DEBUG
142 /* prevent us from having NULL lastcall */
143 opcb->lastcall = cpu_forkname;
144 #else
145 opcb->lastcall = NULL;
146 #endif
147 /*
148 * If a new stack is provided, do not bother copying saved windows
149 * in the new pcb. Also, we'll reset pcb_nsaved accordingly below.
150 */
151 if (stack != NULL)
152 pcbsz = offsetof(struct pcb, pcb_rw);
153 else
154 pcbsz = sizeof(struct pcb);
155 bcopy((caddr_t)opcb, (caddr_t)npcb, pcbsz);
156 if (p1->p_md.md_fpstate) {
157 fpusave_proc(p1, 1);
158 p2->p_md.md_fpstate = malloc(sizeof(struct fpstate),
159 M_SUBPROC, M_WAITOK);
160 bcopy(p1->p_md.md_fpstate, p2->p_md.md_fpstate,
161 sizeof(struct fpstate));
162 } else
163 p2->p_md.md_fpstate = NULL;
164
165 /*
166 * Setup (kernel) stack frame that will by-pass the child
167 * out of the kernel. (The trap frame invariably resides at
168 * the tippity-top of the u. area.)
169 */
170 tf2 = p2->p_md.md_tf = (struct trapframe *)
171 ((long)npcb + USPACE - sizeof(*tf2));
172
173 /* Copy parent's trapframe */
174 *tf2 = *(struct trapframe *)((long)opcb + USPACE - sizeof(*tf2));
175
176 /*
177 * If specified, give the child a different stack, offset and
178 * with space reserved for the frame, and zero the frame pointer.
179 */
180 if (stack != NULL) {
181 npcb->pcb_nsaved = 0;
182 tf2->tf_out[6] = (u_int64_t)(u_long)stack - (BIAS + CC64FSZ);
183 tf2->tf_in[6] = 0;
184 }
185 if (tcb != NULL)
186 tf2->tf_global[7] = (u_int64_t)tcb;
187
188 /* Construct kernel frame to return to in cpu_switch() */
189 rp = (struct rwindow *)((u_long)npcb + TOPFRAMEOFF);
190 *rp = *(struct rwindow *)((u_long)opcb + TOPFRAMEOFF);
191 rp->rw_local[0] = (long)func; /* Function to call */
192 rp->rw_local[1] = (long)arg; /* and its argument */
193
194 npcb->pcb_pc = (long)proc_trampoline - 8;
195 npcb->pcb_sp = (long)rp - BIAS;
196
197 /* Need to create a %tstate if we're forking from proc0. */
198 if (p1 == &proc0)
199 tf2->tf_tstate =
200 ((u_int64_t)ASI_PRIMARY_NO_FAULT << TSTATE_ASI_SHIFT) |
201 ((PSTATE_USER) << TSTATE_PSTATE_SHIFT);
202 else
203 /* Clear condition codes and disable FPU. */
204 tf2->tf_tstate &=
205 ~((PSTATE_PEF << TSTATE_PSTATE_SHIFT) | TSTATE_CCR);
206
207 #ifdef NOTDEF_DEBUG
208 printf("cpu_fork: Copying over trapframe: otf=%p ntf=%p sp=%p opcb=%p npcb=%p\n",
209 (struct trapframe *)((char *)opcb + USPACE - sizeof(*tf2)), tf2, rp, opcb, npcb);
210 printf("cpu_fork: tstate=%lx pc=%lx npc=%lx rsp=%lx\n",
211 (long)tf2->tf_tstate, (long)tf2->tf_pc, (long)tf2->tf_npc,
212 (long)(tf2->tf_out[6]));
213 db_enter();
214 #endif
215 }
216
217 /*
218 * These are the "function" entry points in locore.s to handle IPI's.
219 */
220 void ipi_save_fpstate(void);
221 void ipi_drop_fpstate(void);
222
223 void
fpusave_cpu(struct cpu_info * ci,int save)224 fpusave_cpu(struct cpu_info *ci, int save)
225 {
226 struct proc *p;
227
228 KDASSERT(ci == curcpu());
229
230 p = ci->ci_fpproc;
231 if (p == NULL)
232 return;
233
234 if (save)
235 savefpstate(p->p_md.md_fpstate);
236 else
237 clearfpstate();
238
239 ci->ci_fpproc = NULL;
240 }
241
242 void
fpusave_proc(struct proc * p,int save)243 fpusave_proc(struct proc *p, int save)
244 {
245 struct cpu_info *ci = curcpu();
246
247 #ifdef MULTIPROCESSOR
248 if (p == ci->ci_fpproc) {
249 u_int64_t s = intr_disable();
250 fpusave_cpu(ci, save);
251 intr_restore(s);
252 return;
253 }
254
255 for (ci = cpus; ci != NULL; ci = ci->ci_next) {
256 if (ci == curcpu())
257 continue;
258 if (ci->ci_fpproc != p)
259 continue;
260 sparc64_send_ipi(ci->ci_itid,
261 save ? ipi_save_fpstate : ipi_drop_fpstate, (vaddr_t)p, 0);
262 while (ci->ci_fpproc == p)
263 membar_sync();
264 break;
265 }
266 #else
267 if (p == ci->ci_fpproc)
268 fpusave_cpu(ci, save);
269 #endif
270 }
271
272 /*
273 * cpu_exit is called as the last action during exit.
274 *
275 * We clean up a little and then call sched_exit() with the old proc
276 * as an argument. sched_exit() schedules the old vmspace and stack
277 * to be freed, then selects a new process to run.
278 */
279 void
cpu_exit(struct proc * p)280 cpu_exit(struct proc *p)
281 {
282 if (p->p_md.md_fpstate != NULL) {
283 fpusave_proc(p, 0);
284 free(p->p_md.md_fpstate, M_SUBPROC, sizeof(struct fpstate));
285 p->p_md.md_fpstate = NULL;
286 }
287
288 pmap_deactivate(p);
289 sched_exit(p);
290 }
291
292
293 struct kmem_va_mode kv_physwait = {
294 .kv_map = &phys_map,
295 .kv_wait = 1,
296 };
297
298 /*
299 * Map an IO request into kernel virtual address space.
300 */
301 void
vmapbuf(struct buf * bp,vsize_t len)302 vmapbuf(struct buf *bp, vsize_t len)
303 {
304 struct kmem_dyn_mode kd_prefer = { .kd_waitok = 1 };
305 struct pmap *pm = vm_map_pmap(&bp->b_proc->p_vmspace->vm_map);
306 vaddr_t kva, uva;
307 vsize_t size, off;
308
309 #ifdef DIAGNOSTIC
310 if ((bp->b_flags & B_PHYS) == 0)
311 panic("vmapbuf");
312 #endif
313 bp->b_saveaddr = bp->b_data;
314 uva = trunc_page((vaddr_t)bp->b_data);
315 off = (vaddr_t)bp->b_data - uva;
316 size = round_page(off + len);
317
318 kd_prefer.kd_prefer = uva;
319 kva = (vaddr_t)km_alloc(size, &kv_physwait, &kp_none, &kd_prefer);
320 bp->b_data = (caddr_t)(kva + off);
321 while (size > 0) {
322 paddr_t pa;
323
324 if (pmap_extract(pm, uva, &pa) == FALSE)
325 panic("vmapbuf: null page frame");
326 else
327 pmap_kenter_pa(kva, pa, PROT_READ | PROT_WRITE);
328 uva += PAGE_SIZE;
329 kva += PAGE_SIZE;
330 size -= PAGE_SIZE;
331 }
332 pmap_update(pmap_kernel());
333 }
334
335 /*
336 * Unmap IO request from the kernel virtual address space.
337 */
338 void
vunmapbuf(struct buf * bp,vsize_t len)339 vunmapbuf(struct buf *bp, vsize_t len)
340 {
341 vaddr_t addr, off;
342
343 #ifdef DIAGNOSTIC
344 if ((bp->b_flags & B_PHYS) == 0)
345 panic("vunmapbuf");
346 #endif
347 addr = trunc_page((vaddr_t)bp->b_data);
348 off = (vaddr_t)bp->b_data - addr;
349 len = round_page(off + len);
350 pmap_kremove(addr, len);
351 pmap_update(pmap_kernel());
352 km_free((void *)addr, len, &kv_physwait, &kp_none);
353 bp->b_data = bp->b_saveaddr;
354 bp->b_saveaddr = NULL;
355 }
356