xref: /netbsd/sys/arch/vax/vax/vm_machdep.c (revision 2d5d8524)
1 /*	$NetBSD: vm_machdep.c,v 1.118 2017/05/22 16:53:05 ragge Exp $	     */
2 
3 /*
4  * Copyright (c) 1994 Ludd, University of Lule}, Sweden.
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 BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <sys/cdefs.h>
29 __KERNEL_RCSID(0, "$NetBSD: vm_machdep.c,v 1.118 2017/05/22 16:53:05 ragge Exp $");
30 
31 #include "opt_execfmt.h"
32 #include "opt_compat_ultrix.h"
33 #include "opt_multiprocessor.h"
34 #include "opt_cputype.h"
35 
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/buf.h>
39 #include <sys/core.h>
40 #include <sys/cpu.h>
41 #include <sys/exec.h>
42 #include <sys/exec_aout.h>
43 #include <sys/proc.h>
44 #include <sys/syscallargs.h>
45 
46 #include <uvm/uvm_extern.h>
47 
48 #include <machine/vmparam.h>
49 #include <machine/macros.h>
50 #include <machine/frame.h>
51 #include <machine/sid.h>
52 
53 /*
54  * Finish a fork operation, with process p2 nearly set up.
55  * Copy and update the pcb and trap frame, making the child ready to run.
56  *
57  * Rig the child's kernel stack so that it will start out in
58  * cpu_lwp_bootstrap() and call child_return() with p2 as an
59  * argument. This causes the newly-created child process to go
60  * directly to user level with an apparent return value of 0 from
61  * fork(), while the parent process returns normally.
62  *
63  * p1 is the process being forked; if p1 == &proc0, we are creating
64  * a kernel thread, and the return path and argument are specified with
65  * `func' and `arg'.
66  *
67  * If an alternate user-level stack is requested (with non-zero values
68  * in both the stack and stacksize args), set up the user stack pointer
69  * accordingly.
70  *
71  * cpu_lwp_fork() copies parent process trapframe and creates a fake CALLS
72  * frame on top of it, so that it can safely call child_return().
73  * We also take away mapping for the fourth page after pcb, so that
74  * we get something like a "red zone" for the kernel stack.
75  */
76 void cpu_lwp_bootstrap(void);
77 void
cpu_lwp_fork(struct lwp * l1,struct lwp * l2,void * stack,size_t stacksize,void (* func)(void *),void * arg)78 cpu_lwp_fork(struct lwp *l1, struct lwp *l2, void *stack, size_t stacksize,
79     void (*func)(void *), void *arg)
80 {
81 	struct callsframe *cf;
82 	extern int sret; /* Return address in trap routine */
83 
84 	struct pcb * const pcb2 = lwp_getpcb(l2);
85 
86 #ifdef DIAGNOSTIC
87 	/*
88 	 * if p1 != curlwp && p1 == &proc0, we're creating a kernel thread.
89 	 */
90 	if (l1 != curlwp && l1 != &lwp0)
91 		panic("cpu_lwp_fork: curlwp");
92 #endif
93 
94 	/*
95 	 * Clear new pcb
96 	 */
97 	memset(pcb2, 0, sizeof(*pcb2));
98 
99 	/*
100 	 * Copy the trap frame.
101 	 */
102 	const vaddr_t uv = uvm_lwp_getuarea(l2);
103 	struct trapframe * const tf = (struct trapframe *)(uv + USPACE) - 1;
104 	l2->l_md.md_utf = tf;
105 	*tf = *l1->l_md.md_utf;
106 
107 	/*
108 	 * Activate address space for the new process.	The PTEs have
109 	 * already been allocated by way of pmap_create().
110 	 * This writes the page table registers to the PCB.
111 	 */
112 	pcb2->pcb_pm = NULL;
113 	pmap_activate(l2);
114 
115 	/* Mark guard page invalid in kernel stack */
116 	kvtopte((uintptr_t)uv + REDZONEADDR)->pg_v = 0;
117 
118 	/*
119 	 * Set up the calls frame above (below) the trapframe and populate
120 	 * it with something good.  This is so that we can simulate that we
121 	 * called cpu_lwp_bootstrap with a CALLS insn and it can return to
122 	 * sret.
123 	 */
124 	cf = (struct callsframe *)tf - 1;
125 	cf->ca_cond = 0;
126 	cf->ca_maskpsw = 0x20000000;	/* CALLS stack frame, no registers */
127 	cf->ca_pc = (uintptr_t)&sret;	/* return PC; userspace trampoline */
128 	cf->ca_argno = 1;
129 	cf->ca_arg1 = 0;		/* unused */
130 
131 	/*
132 	 * Set up internal defs in PCB. This matches the "fake" CALLS frame
133 	 * that were constructed earlier.
134 	 */
135 	pcb2->pcb_onfault = NULL;
136 	pcb2->AP = (uintptr_t)&cf->ca_argno;
137 	pcb2->KSP = (uintptr_t)cf;
138 	pcb2->FP = (uintptr_t)cf;
139 	pcb2->PC = (uintptr_t)cpu_lwp_bootstrap + 2;
140 	pcb2->PSL = PSL_HIGHIPL;
141 	pcb2->ESP = (uintptr_t)&pcb2->pcb_onfault;
142 	pcb2->SSP = (uintptr_t)l2;
143 
144 	/* pcb->R[0] (oldlwp) set by Swtchto */
145 	pcb2->R[1] = (uintptr_t)l2;
146 	pcb2->R[2] = (uintptr_t)func;
147 	pcb2->R[3] = (uintptr_t)arg;
148 	pcb2->pcb_paddr = kvtophys(pcb2);
149 
150 	/*
151 	 * If specified, give the child a different stack.
152 	 */
153 	if (stack != NULL)
154 		tf->tf_sp = (uintptr_t)stack + stacksize;
155 
156 	/*
157 	 * Set the last return information after fork().
158 	 * This is only interesting if the child will return to userspace,
159 	 * but doesn't hurt otherwise.
160 	 */
161 	tf->tf_r0 = l1->l_proc->p_pid; /* parent pid. (shouldn't be needed) */
162 	tf->tf_r1 = 1;
163 	tf->tf_psl = PSL_U|PSL_PREVU;
164 }
165 
166 vaddr_t
cpu_lwp_pc(struct lwp * l)167 cpu_lwp_pc(struct lwp *l)
168 {
169 	return l->l_md.md_utf->tf_pc;
170 }
171 
172 void
cpu_lwp_free(struct lwp * l,int proc)173 cpu_lwp_free(struct lwp *l, int proc)
174 {
175 
176 	(void)l;
177 	(void)proc;
178 }
179 
180 void
cpu_lwp_free2(struct lwp * l)181 cpu_lwp_free2(struct lwp *l)
182 {
183 
184 	(void)l;
185 }
186 
187 #ifdef EXEC_AOUT
188 int
cpu_exec_aout_makecmds(struct lwp * l,struct exec_package * epp)189 cpu_exec_aout_makecmds(struct lwp *l, struct exec_package *epp)
190 {
191 	return ENOEXEC;
192 }
193 #endif
194 
195 int
sys_sysarch(struct lwp * l,const struct sys_sysarch_args * uap,register_t * retval)196 sys_sysarch(struct lwp *l, const struct sys_sysarch_args *uap, register_t *retval)
197 {
198 	return (ENOSYS);
199 }
200 
201 /*
202  * Map in a bunch of pages read/writable for the kernel.
203  */
204 void
ioaccess(vaddr_t vaddr,paddr_t paddr,size_t npgs)205 ioaccess(vaddr_t vaddr, paddr_t paddr, size_t npgs)
206 {
207 	uint32_t *pte = (uint32_t *)kvtopte(vaddr);
208 	int i;
209 
210 	for (i = 0; i < npgs; i++)
211 		pte[i] = PG_V | PG_KW | (PG_PFNUM(paddr) + i);
212 }
213 
214 /*
215  * Opposite to the above: just forget their mapping.
216  */
217 void
iounaccess(vaddr_t vaddr,size_t npgs)218 iounaccess(vaddr_t vaddr, size_t npgs)
219 {
220 	uint32_t *pte = (uint32_t *)kvtopte(vaddr);
221 	int i;
222 
223 	for (i = 0; i < npgs; i++)
224 		pte[i] = 0;
225 	mtpr(0, PR_TBIA);
226 }
227 
228 /*
229  * Map a user I/O request into kernel virtual address space.
230  * Note: the pages are already locked by uvm_vslock(), so we
231  * do not need to pass an access_type to pmap_enter().
232  */
233 int
vmapbuf(struct buf * bp,vsize_t len)234 vmapbuf(struct buf *bp, vsize_t len)
235 {
236 #if VAX46 || VAX48 || VAX49 || VAX53 || VAXANY
237 	vaddr_t faddr, taddr, off;
238 	paddr_t pa;
239 	struct proc *p;
240 
241 	if (vax_boardtype != VAX_BTYP_46
242 	    && vax_boardtype != VAX_BTYP_48
243 	    && vax_boardtype != VAX_BTYP_49
244 	    && vax_boardtype != VAX_BTYP_53)
245 		return 0;
246 	if ((bp->b_flags & B_PHYS) == 0)
247 		panic("vmapbuf");
248 	p = bp->b_proc;
249 	bp->b_saveaddr = bp->b_data;
250 	faddr = trunc_page((vaddr_t)bp->b_saveaddr);
251 	off = (vaddr_t)bp->b_data - faddr;
252 	len = round_page(off + len);
253 	taddr = uvm_km_alloc(phys_map, len, 0, UVM_KMF_VAONLY | UVM_KMF_WAITVA);
254 	bp->b_data = (void *)(taddr + off);
255 	len = atop(len);
256 	while (len--) {
257 		if (pmap_extract(vm_map_pmap(&p->p_vmspace->vm_map), faddr,
258 		    &pa) == false)
259 			panic("vmapbuf: null page frame");
260 		pmap_enter(vm_map_pmap(phys_map), taddr, trunc_page(pa),
261 		    VM_PROT_READ|VM_PROT_WRITE, PMAP_WIRED);
262 		faddr += PAGE_SIZE;
263 		taddr += PAGE_SIZE;
264 	}
265 	pmap_update(vm_map_pmap(phys_map));
266 #endif
267 
268 	return 0;
269 }
270 
271 /*
272  * Unmap a previously-mapped user I/O request.
273  */
274 void
vunmapbuf(struct buf * bp,vsize_t len)275 vunmapbuf(struct buf *bp, vsize_t len)
276 {
277 #if VAX46 || VAX48 || VAX49 || VAX53 || VAXANY
278 	vaddr_t addr, off;
279 
280 	if (vax_boardtype != VAX_BTYP_46
281 	    && vax_boardtype != VAX_BTYP_48
282 	    && vax_boardtype != VAX_BTYP_49
283 	    && vax_boardtype != VAX_BTYP_53)
284 		return;
285 	if ((bp->b_flags & B_PHYS) == 0)
286 		panic("vunmapbuf");
287 	addr = trunc_page((vaddr_t)bp->b_data);
288 	off = (vaddr_t)bp->b_data - addr;
289 	len = round_page(off + len);
290 	pmap_remove(vm_map_pmap(phys_map), addr, addr + len);
291 	pmap_update(vm_map_pmap(phys_map));
292 	uvm_km_free(phys_map, addr, len, UVM_KMF_VAONLY);
293 	bp->b_data = bp->b_saveaddr;
294 	bp->b_saveaddr = NULL;
295 #endif
296 }
297