Home | History | Annotate | Line # | Download | only in vax
      1 /*	$NetBSD: vm_machdep.c,v 1.119 2025/02/28 20:11:21 hans 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.119 2025/02/28 20:11:21 hans 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
     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_ap = 0;
    128 	cf->ca_fp = 0;
    129 	cf->ca_pc = (uintptr_t)&sret;	/* return PC; userspace trampoline */
    130 	cf->ca_argno = 1;
    131 	cf->ca_arg1 = 0;		/* unused */
    132 
    133 	/*
    134 	 * Set up internal defs in PCB. This matches the "fake" CALLS frame
    135 	 * that were constructed earlier.
    136 	 */
    137 	pcb2->pcb_onfault = NULL;
    138 	pcb2->AP = (uintptr_t)&cf->ca_argno;
    139 	pcb2->KSP = (uintptr_t)cf;
    140 	pcb2->FP = (uintptr_t)cf;
    141 	pcb2->PC = (uintptr_t)cpu_lwp_bootstrap + 2;
    142 	pcb2->PSL = PSL_HIGHIPL;
    143 	pcb2->ESP = (uintptr_t)&pcb2->pcb_onfault;
    144 	pcb2->SSP = (uintptr_t)l2;
    145 
    146 	/* pcb->R[0] (oldlwp) set by Swtchto */
    147 	pcb2->R[1] = (uintptr_t)l2;
    148 	pcb2->R[2] = (uintptr_t)func;
    149 	pcb2->R[3] = (uintptr_t)arg;
    150 	pcb2->pcb_paddr = kvtophys(pcb2);
    151 
    152 	/*
    153 	 * If specified, give the child a different stack.
    154 	 */
    155 	if (stack != NULL)
    156 		tf->tf_sp = (uintptr_t)stack + stacksize;
    157 
    158 	/*
    159 	 * Set the last return information after fork().
    160 	 * This is only interesting if the child will return to userspace,
    161 	 * but doesn't hurt otherwise.
    162 	 */
    163 	tf->tf_r0 = l1->l_proc->p_pid; /* parent pid. (shouldn't be needed) */
    164 	tf->tf_r1 = 1;
    165 	tf->tf_psl = PSL_U|PSL_PREVU;
    166 }
    167 
    168 vaddr_t
    169 cpu_lwp_pc(struct lwp *l)
    170 {
    171 	return l->l_md.md_utf->tf_pc;
    172 }
    173 
    174 void
    175 cpu_lwp_free(struct lwp *l, int proc)
    176 {
    177 
    178 	(void)l;
    179 	(void)proc;
    180 }
    181 
    182 void
    183 cpu_lwp_free2(struct lwp *l)
    184 {
    185 
    186 	(void)l;
    187 }
    188 
    189 #ifdef EXEC_AOUT
    190 int
    191 cpu_exec_aout_makecmds(struct lwp *l, struct exec_package *epp)
    192 {
    193 	return ENOEXEC;
    194 }
    195 #endif
    196 
    197 int
    198 sys_sysarch(struct lwp *l, const struct sys_sysarch_args *uap, register_t *retval)
    199 {
    200 	return (ENOSYS);
    201 }
    202 
    203 /*
    204  * Map in a bunch of pages read/writable for the kernel.
    205  */
    206 void
    207 ioaccess(vaddr_t vaddr, paddr_t paddr, size_t npgs)
    208 {
    209 	uint32_t *pte = (uint32_t *)kvtopte(vaddr);
    210 	int i;
    211 
    212 	for (i = 0; i < npgs; i++)
    213 		pte[i] = PG_V | PG_KW | (PG_PFNUM(paddr) + i);
    214 }
    215 
    216 /*
    217  * Opposite to the above: just forget their mapping.
    218  */
    219 void
    220 iounaccess(vaddr_t vaddr, size_t npgs)
    221 {
    222 	uint32_t *pte = (uint32_t *)kvtopte(vaddr);
    223 	int i;
    224 
    225 	for (i = 0; i < npgs; i++)
    226 		pte[i] = 0;
    227 	mtpr(0, PR_TBIA);
    228 }
    229 
    230 /*
    231  * Map a user I/O request into kernel virtual address space.
    232  * Note: the pages are already locked by uvm_vslock(), so we
    233  * do not need to pass an access_type to pmap_enter().
    234  */
    235 int
    236 vmapbuf(struct buf *bp, vsize_t len)
    237 {
    238 #if VAX46 || VAX48 || VAX49 || VAX53 || VAXANY
    239 	vaddr_t faddr, taddr, off;
    240 	paddr_t pa;
    241 	struct proc *p;
    242 
    243 	if (vax_boardtype != VAX_BTYP_46
    244 	    && vax_boardtype != VAX_BTYP_48
    245 	    && vax_boardtype != VAX_BTYP_49
    246 	    && vax_boardtype != VAX_BTYP_53)
    247 		return 0;
    248 	if ((bp->b_flags & B_PHYS) == 0)
    249 		panic("vmapbuf");
    250 	p = bp->b_proc;
    251 	bp->b_saveaddr = bp->b_data;
    252 	faddr = trunc_page((vaddr_t)bp->b_saveaddr);
    253 	off = (vaddr_t)bp->b_data - faddr;
    254 	len = round_page(off + len);
    255 	taddr = uvm_km_alloc(phys_map, len, 0, UVM_KMF_VAONLY | UVM_KMF_WAITVA);
    256 	bp->b_data = (void *)(taddr + off);
    257 	len = atop(len);
    258 	while (len--) {
    259 		if (pmap_extract(vm_map_pmap(&p->p_vmspace->vm_map), faddr,
    260 		    &pa) == false)
    261 			panic("vmapbuf: null page frame");
    262 		pmap_enter(vm_map_pmap(phys_map), taddr, trunc_page(pa),
    263 		    VM_PROT_READ|VM_PROT_WRITE, PMAP_WIRED);
    264 		faddr += PAGE_SIZE;
    265 		taddr += PAGE_SIZE;
    266 	}
    267 	pmap_update(vm_map_pmap(phys_map));
    268 #endif
    269 
    270 	return 0;
    271 }
    272 
    273 /*
    274  * Unmap a previously-mapped user I/O request.
    275  */
    276 void
    277 vunmapbuf(struct buf *bp, vsize_t len)
    278 {
    279 #if VAX46 || VAX48 || VAX49 || VAX53 || VAXANY
    280 	vaddr_t addr, off;
    281 
    282 	if (vax_boardtype != VAX_BTYP_46
    283 	    && vax_boardtype != VAX_BTYP_48
    284 	    && vax_boardtype != VAX_BTYP_49
    285 	    && vax_boardtype != VAX_BTYP_53)
    286 		return;
    287 	if ((bp->b_flags & B_PHYS) == 0)
    288 		panic("vunmapbuf");
    289 	addr = trunc_page((vaddr_t)bp->b_data);
    290 	off = (vaddr_t)bp->b_data - addr;
    291 	len = round_page(off + len);
    292 	pmap_remove(vm_map_pmap(phys_map), addr, addr + len);
    293 	pmap_update(vm_map_pmap(phys_map));
    294 	uvm_km_free(phys_map, addr, len, UVM_KMF_VAONLY);
    295 	bp->b_data = bp->b_saveaddr;
    296 	bp->b_saveaddr = NULL;
    297 #endif
    298 }
    299