1 /* $NetBSD: vm_machdep.c,v 1.124 2026/10/22 10:47:30 rin Exp $ */ 2 3 /* 4 * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University. 5 * All rights reserved. 6 * 7 * Author: Chris G. Demetriou 8 * 9 * Permission to use, copy, modify and distribute this software and 10 * its documentation is hereby granted, provided that both the copyright 11 * notice and this permission notice appear in all copies of the 12 * software, derivative works or modified versions, and any portions 13 * thereof, and that both notices appear in supporting documentation. 14 * 15 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 16 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 17 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 18 * 19 * Carnegie Mellon requests users of this software to return to 20 * 21 * Software Distribution Coordinator or Software.Distribution (at) CS.CMU.EDU 22 * School of Computer Science 23 * Carnegie Mellon University 24 * Pittsburgh PA 15213-3890 25 * 26 * any improvements or extensions that they make and grant Carnegie the 27 * rights to redistribute these changes. 28 */ 29 30 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 31 32 __KERNEL_RCSID(0, "$NetBSD: vm_machdep.c,v 1.124 2026/10/22 10:47:30 rin Exp $"); 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/proc.h> 37 #include <sys/buf.h> 38 #include <sys/vnode.h> 39 #include <sys/core.h> 40 #include <sys/exec.h> 41 42 #include <uvm/uvm.h> 43 44 #include <machine/cpu.h> 45 #include <machine/alpha.h> 46 #include <machine/pmap.h> 47 #include <machine/reg.h> 48 49 void 50 cpu_lwp_free(struct lwp *l, int proc) 51 { 52 (void) l; 53 } 54 55 void 56 cpu_lwp_free2(struct lwp *l) 57 { 58 (void) l; 59 } 60 61 /* 62 * This is a backstop used to ensure that kernel threads never do 63 * something silly like attempt to return to userspace. We achieve 64 * this by putting this at the root of their call graph instead of 65 * exception_return(). 66 */ 67 void 68 alpha_kthread_backstop(void) 69 { 70 struct lwp * const l = curlwp; 71 72 panic("kthread lwp %p (%s) hit the backstop", l, l->l_name); 73 } 74 75 /* 76 * Finish a fork operation, with thread l2 nearly set up. 77 * Copy and update the pcb and trap frame, making the child ready to run. 78 * 79 * Rig the child's kernel stack so that it will start out in 80 * lwp_trampoline() and call child_return() with l2 as an 81 * argument. This causes the newly-created child thread to go 82 * directly to user level with an apparent return value of 0 from 83 * fork(), while the parent process returns normally. 84 * 85 * l1 is the thread being forked; if l1 == &lwp0, we are creating 86 * a kernel thread, and the return path and argument are specified with 87 * `func' and `arg'. 88 * 89 * If an alternate user-level stack is requested (with non-zero values 90 * in both the stack and stacksize args), set up the user stack pointer 91 * accordingly. 92 */ 93 void 94 cpu_lwp_fork(struct lwp *l1, struct lwp *l2, void *stack, size_t stacksize, 95 void (*func)(void *), void *arg) 96 { 97 struct pcb *pcb1, *pcb2; 98 extern void lwp_trampoline(void); 99 100 pcb1 = lwp_getpcb(l1); 101 pcb2 = lwp_getpcb(l2); 102 103 l2->l_md.md_tf = l1->l_md.md_tf; 104 l2->l_md.md_flags = l1->l_md.md_flags & MDLWP_FP_C; 105 KASSERT(l2->l_md.md_astpending == 0); 106 107 /* 108 * Cache the physical address of the pcb, so we can 109 * swap to it easily. 110 */ 111 l2->l_md.md_pcbpaddr = (void *)vtophys((vaddr_t)pcb2); 112 113 /* 114 * Copy pcb and user stack pointer from proc p1 to p2. 115 * If specified, give the child a different stack. 116 * Floating point state from the FP chip has already been saved. 117 */ 118 *pcb2 = *pcb1; 119 if (stack != NULL) { 120 pcb2->pcb_hw.apcb_usp = 121 ((u_long)stack + stacksize) & ~((u_long)STACK_ALIGNBYTES); 122 } else { 123 pcb2->pcb_hw.apcb_usp = alpha_pal_rdusp(); 124 } 125 126 /* 127 * Put l2 on the kernel's page tables until its first trip 128 * through pmap_activate(). 129 */ 130 pcb2->pcb_hw.apcb_ptbr = 131 ALPHA_K0SEG_TO_PHYS((vaddr_t)kernel_lev1map) >> PGSHIFT; 132 pcb2->pcb_hw.apcb_asn = PMAP_ASN_KERNEL; 133 134 #ifdef DIAGNOSTIC 135 /* 136 * If l1 != curlwp && l1 == &lwp0, we are creating a kernel 137 * thread. 138 */ 139 if (l1 != curlwp && l1 != &lwp0) 140 panic("cpu_lwp_fork: curlwp"); 141 #endif 142 143 /* 144 * create the child's kernel stack, from scratch. 145 */ 146 { 147 struct trapframe *l2tf; 148 uint64_t call_root; 149 150 /* 151 * Pick a stack pointer, leaving room for a trapframe; 152 * copy trapframe from parent so return to user mode 153 * will be to right address, with correct registers. 154 */ 155 l2tf = l2->l_md.md_tf = (struct trapframe *)((uintptr_t) 156 (uvm_lwp_getuarea(l2) + USPACE - sizeof(struct trapframe)) & 157 ~STACK_ALIGNBYTES); 158 memcpy(l2->l_md.md_tf, l1->l_md.md_tf, 159 sizeof(struct trapframe)); 160 161 /* 162 * Set up return-value registers as fork() libc stub expects. 163 */ 164 l2tf->tf_regs[FRAME_V0] = l1->l_proc->p_pid; /* parent's pid */ 165 l2tf->tf_regs[FRAME_A3] = 0; /* no error */ 166 l2tf->tf_regs[FRAME_A4] = 1; /* is child */ 167 168 /* 169 * Normal LWPs have their return address set to 170 * exception_return() so that they'll pop into 171 * user space. But kernel threads don't have 172 * a user space, so we put a backtop in place 173 * just in case they try. 174 */ 175 if (__predict_true(l2->l_proc != &proc0)) 176 call_root = (uint64_t)exception_return; 177 else 178 call_root = (uint64_t)alpha_kthread_backstop; 179 180 pcb2->pcb_hw.apcb_ksp = 181 (uint64_t)l2->l_md.md_tf; 182 pcb2->pcb_context[0] = 183 (uint64_t)func; /* s0: pc */ 184 pcb2->pcb_context[1] = 185 call_root; /* s1: ra */ 186 pcb2->pcb_context[2] = 187 (uint64_t)arg; /* s2: arg */ 188 pcb2->pcb_context[3] = 189 (uint64_t)l2; /* s3: lwp */ 190 pcb2->pcb_context[7] = 191 (uint64_t)lwp_trampoline; /* ra: assembly magic */ 192 } 193 } 194 195 /* 196 * Map a user I/O request into kernel virtual address space. 197 * Note: the pages are already locked by uvm_vslock(), so we 198 * do not need to pass an access_type to pmap_enter(). 199 */ 200 int 201 vmapbuf(struct buf *bp, vsize_t len) 202 { 203 vaddr_t faddr, taddr, off; 204 paddr_t pa; 205 struct proc *p; 206 207 if ((bp->b_flags & B_PHYS) == 0) 208 panic("vmapbuf"); 209 p = bp->b_proc; 210 bp->b_saveaddr = bp->b_data; 211 faddr = trunc_page((vaddr_t)bp->b_data); 212 off = (vaddr_t)bp->b_data - faddr; 213 len = round_page(off + len); 214 taddr = uvm_km_alloc(phys_map, len, 0, UVM_KMF_VAONLY|UVM_KMF_WAITVA); 215 bp->b_data = (void *)(taddr + off); 216 len = atop(len); 217 while (len--) { 218 if (pmap_extract(vm_map_pmap(&p->p_vmspace->vm_map), faddr, 219 &pa) == false) 220 panic("vmapbuf: null page frame"); 221 pmap_enter(vm_map_pmap(phys_map), taddr, trunc_page(pa), 222 VM_PROT_READ|VM_PROT_WRITE, PMAP_WIRED); 223 faddr += PAGE_SIZE; 224 taddr += PAGE_SIZE; 225 } 226 pmap_update(vm_map_pmap(phys_map)); 227 228 return 0; 229 } 230 231 /* 232 * Unmap a previously-mapped user I/O request. 233 */ 234 void 235 vunmapbuf(struct buf *bp, vsize_t len) 236 { 237 vaddr_t addr, off; 238 239 if ((bp->b_flags & B_PHYS) == 0) 240 panic("vunmapbuf"); 241 addr = trunc_page((vaddr_t)bp->b_data); 242 off = (vaddr_t)bp->b_data - addr; 243 len = round_page(off + len); 244 pmap_remove(vm_map_pmap(phys_map), addr, addr + len); 245 pmap_update(vm_map_pmap(phys_map)); 246 uvm_km_free(phys_map, addr, len, UVM_KMF_VAONLY); 247 bp->b_data = bp->b_saveaddr; 248 bp->b_saveaddr = NULL; 249 } 250 251 #ifdef __HAVE_CPU_UAREA_ROUTINES 252 static struct evcnt uarea_direct_success = 253 EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "uarea direct", "success"); 254 static struct evcnt uarea_direct_failure = 255 EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "uarea direct", "failure"); 256 257 EVCNT_ATTACH_STATIC(uarea_direct_success); 258 EVCNT_ATTACH_STATIC(uarea_direct_failure); 259 260 void * 261 cpu_uarea_alloc(bool system) 262 { 263 struct pglist pglist; 264 int error; 265 266 /* 267 * Allocate a new physically contiguous uarea which can be 268 * direct-mapped. 269 */ 270 error = uvm_pglistalloc(USPACE, 0, ptoa(physmem), 0, 0, &pglist, 1, 1); 271 if (error) { 272 atomic_inc_ulong(&uarea_direct_failure.ev_count); 273 return NULL; 274 } 275 atomic_inc_ulong(&uarea_direct_success.ev_count); 276 277 /* 278 * Get the physical address from the first page. 279 */ 280 const struct vm_page * const pg = TAILQ_FIRST(&pglist); 281 KASSERT(pg != NULL); 282 const paddr_t pa = VM_PAGE_TO_PHYS(pg); 283 284 /* 285 * We need to return a direct-mapped VA for the pa. 286 */ 287 288 return (void *)PMAP_MAP_POOLPAGE(pa); 289 } 290 291 /* 292 * Return true if we freed it, false if we didn't. 293 */ 294 bool 295 cpu_uarea_free(void *vva) 296 { 297 vaddr_t va = (vaddr_t) vva; 298 if (va >= VM_MIN_KERNEL_ADDRESS && va < VM_MAX_KERNEL_ADDRESS) 299 return false; 300 301 /* 302 * Since the pages are physically contiguous, the vm_page structure 303 * will be as well. 304 */ 305 struct vm_page *pg = PHYS_TO_VM_PAGE(PMAP_UNMAP_POOLPAGE(va)); 306 KASSERT(pg != NULL); 307 for (size_t i = 0; i < UPAGES; i++, pg++) { 308 uvm_pagefree(pg); 309 } 310 return true; 311 } 312 #endif /* __HAVE_CPU_UAREA_ROUTINES */ 313