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