1 /* $NetBSD: vm_machdep.c,v 1.47 2025/04/24 01:50:39 riastradh Exp $ */ 2 3 /*- 4 * Copyright (c) 1982, 1986 The Regents of the University of California. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * the Systems Programming Group of the University of Utah Computer 9 * Science Department, and William Jolitz. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * @(#)vm_machdep.c 7.3 (Berkeley) 5/13/91 36 */ 37 38 /*- 39 * Copyright (c) 1995 Charles M. Hannum. All rights reserved. 40 * Copyright (c) 1989, 1990 William Jolitz 41 * All rights reserved. 42 * 43 * This code is derived from software contributed to Berkeley by 44 * the Systems Programming Group of the University of Utah Computer 45 * Science Department, and William Jolitz. 46 * 47 * Redistribution and use in source and binary forms, with or without 48 * modification, are permitted provided that the following conditions 49 * are met: 50 * 1. Redistributions of source code must retain the above copyright 51 * notice, this list of conditions and the following disclaimer. 52 * 2. Redistributions in binary form must reproduce the above copyright 53 * notice, this list of conditions and the following disclaimer in the 54 * documentation and/or other materials provided with the distribution. 55 * 3. All advertising materials mentioning features or use of this software 56 * must display the following acknowledgement: 57 * This product includes software developed by the University of 58 * California, Berkeley and its contributors. 59 * 4. Neither the name of the University nor the names of its contributors 60 * may be used to endorse or promote products derived from this software 61 * without specific prior written permission. 62 * 63 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 64 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 65 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 66 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 67 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 68 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 69 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 70 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 71 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 72 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 73 * SUCH DAMAGE. 74 * 75 * @(#)vm_machdep.c 7.3 (Berkeley) 5/13/91 76 */ 77 78 /* 79 * Utah $Hdr: vm_machdep.c 1.16.1.1 89/06/23$ 80 */ 81 82 #include <sys/cdefs.h> 83 __KERNEL_RCSID(0, "$NetBSD: vm_machdep.c,v 1.47 2025/04/24 01:50:39 riastradh Exp $"); 84 85 #include "opt_mtrr.h" 86 87 #include <sys/param.h> 88 #include <sys/systm.h> 89 #include <sys/proc.h> 90 #include <sys/vnode.h> 91 #include <sys/buf.h> 92 #include <sys/core.h> 93 #include <sys/exec.h> 94 #include <sys/ptrace.h> 95 96 #include <uvm/uvm.h> 97 98 #include <machine/cpu.h> 99 #include <machine/gdt.h> 100 #include <machine/reg.h> 101 #include <machine/specialreg.h> 102 103 #ifdef MTRR 104 #include <machine/mtrr.h> 105 #endif 106 107 #include <x86/fpu.h> 108 #include <x86/dbregs.h> 109 110 extern struct pool x86_dbregspl; 111 112 void 113 cpu_proc_fork(struct proc *p1, struct proc *p2) 114 { 115 116 p2->p_md.md_flags = p1->p_md.md_flags; 117 } 118 119 /* 120 * cpu_lwp_fork: finish a new LWP (l2) operation. 121 * 122 * First LWP (l1) is the process being forked. If it is &lwp0, then we 123 * are creating a kthread, where return path and argument are specified 124 * with `func' and `arg'. 125 * 126 * If an alternate user-level stack is requested (with non-zero values 127 * in both the stack and stacksize arguments), then set up the user stack 128 * pointer accordingly. 129 */ 130 void 131 cpu_lwp_fork(struct lwp *l1, struct lwp *l2, void *stack, size_t stacksize, 132 void (*func)(void *), void *arg) 133 { 134 struct pcb *pcb1, *pcb2; 135 struct trapframe *tf; 136 struct switchframe *sf; 137 vaddr_t uv; 138 139 KASSERT(l1 == curlwp || l1 == &lwp0); 140 141 pcb1 = lwp_getpcb(l1); 142 pcb2 = lwp_getpcb(l2); 143 144 /* Copy the PCB from parent, except the FPU state. */ 145 memcpy(pcb2, pcb1, offsetof(struct pcb, pcb_savefpu)); 146 147 /* Fork the FPU state. */ 148 fpu_lwp_fork(l1, l2); 149 150 /* Never inherit CPU Debug Registers */ 151 pcb2->pcb_dbregs = NULL; 152 pcb2->pcb_flags &= ~PCB_DBREGS; 153 154 #if defined(XENPV) 155 pcb2->pcb_iopl = IOPL_KPL; 156 #endif 157 158 /* 159 * Set the kernel stack address (from the address to uarea) and 160 * trapframe address for child. 161 * 162 * Rig kernel stack so that it would start out in lwp_trampoline() 163 * and call child_return() with l2 as an argument. This causes the 164 * newly-created child process to go directly to user level with a 165 * parent return value of 0 from fork(), while the parent process 166 * returns normally. 167 */ 168 uv = uvm_lwp_getuarea(l2); 169 KASSERT(uv % PAGE_SIZE == 0); 170 171 #ifdef __x86_64__ 172 #ifdef SVS 173 pcb2->pcb_rsp0 = (uv + USPACE - PAGE_SIZE + 174 sizeof(struct trapframe)); 175 KASSERT((pcb2->pcb_rsp0 & 0xF) == 0); 176 #else 177 pcb2->pcb_rsp0 = (uv + USPACE - 16); 178 #endif 179 tf = (struct trapframe *)pcb2->pcb_rsp0 - 1; 180 #else 181 pcb2->pcb_esp0 = (uv + USPACE - 16); 182 tf = (struct trapframe *)pcb2->pcb_esp0 - 1; 183 184 pcb2->pcb_iomap = NULL; 185 #endif 186 l2->l_md.md_regs = tf; 187 188 /* 189 * Copy the trapframe from parent, so that return to userspace 190 * will be to right address, with correct registers. 191 */ 192 memcpy(tf, l1->l_md.md_regs, sizeof(struct trapframe)); 193 194 /* Child LWP might get aston() before returning to userspace. */ 195 tf->tf_trapno = T_ASTFLT; 196 197 /* If specified, set a different user stack for a child. */ 198 if (stack != NULL) { 199 #ifdef __x86_64__ 200 tf->tf_rsp = (uint64_t)stack + stacksize; 201 #else 202 tf->tf_esp = (uint32_t)stack + stacksize; 203 #endif 204 } 205 206 l2->l_md.md_flags = l1->l_md.md_flags; 207 KASSERT(l2->l_md.md_astpending == 0); 208 209 sf = (struct switchframe *)tf - 1; 210 211 #ifdef __x86_64__ 212 sf->sf_r12 = (uint64_t)func; 213 sf->sf_r13 = (uint64_t)arg; 214 sf->sf_rip = (uint64_t)lwp_trampoline; 215 pcb2->pcb_rsp = (uint64_t)sf; 216 pcb2->pcb_rbp = (uint64_t)l2; 217 #else 218 /* 219 * XXX Is there a reason sf->sf_edi isn't initialized here? 220 * Could this leak potentially sensitive information to new 221 * userspace processes? 222 */ 223 sf->sf_esi = (int)func; 224 sf->sf_ebx = (int)arg; 225 sf->sf_eip = (int)lwp_trampoline; 226 pcb2->pcb_esp = (int)sf; 227 pcb2->pcb_ebp = (int)l2; 228 #endif 229 } 230 231 /* 232 * cpu_lwp_free is called from exit() to let machine-dependent 233 * code free machine-dependent resources. Note that this routine 234 * must not block. NB: this may be called with l != curlwp in 235 * error paths. 236 */ 237 void 238 cpu_lwp_free(struct lwp *l, int proc) 239 { 240 241 if (l != curlwp) 242 return; 243 244 /* Abandon the FPU state. */ 245 fpu_lwp_abandon(l); 246 247 /* Abandon the dbregs state. */ 248 x86_dbregs_abandon(l); 249 250 #ifdef MTRR 251 if (proc && l->l_proc->p_md.md_flags & MDP_USEDMTRR) 252 mtrr_clean(l->l_proc); 253 #endif 254 } 255 256 /* 257 * cpu_lwp_free2 is called when an LWP is being reaped. 258 * This routine may block. 259 */ 260 void 261 cpu_lwp_free2(struct lwp *l) 262 { 263 struct pcb *pcb; 264 265 pcb = lwp_getpcb(l); 266 KASSERT((pcb->pcb_flags & PCB_DBREGS) == 0); 267 if (pcb->pcb_dbregs) { 268 pool_put(&x86_dbregspl, pcb->pcb_dbregs); 269 pcb->pcb_dbregs = NULL; 270 } 271 } 272 273 /* 274 * Convert kernel VA to physical address 275 */ 276 paddr_t 277 kvtop(void *addr) 278 { 279 paddr_t pa; 280 bool ret __diagused; 281 282 ret = pmap_extract(pmap_kernel(), (vaddr_t)addr, &pa); 283 KASSERT(ret == true); 284 return pa; 285 } 286 287 /* 288 * Map a user I/O request into kernel virtual address space. 289 * Note: the pages are already locked by uvm_vslock(), so we 290 * do not need to pass an access_type to pmap_enter(). 291 */ 292 int 293 vmapbuf(struct buf *bp, vsize_t len) 294 { 295 vaddr_t faddr, taddr, off; 296 paddr_t fpa; 297 298 KASSERT((bp->b_flags & B_PHYS) != 0); 299 300 bp->b_saveaddr = bp->b_data; 301 faddr = trunc_page((vaddr_t)bp->b_data); 302 off = (vaddr_t)bp->b_data - faddr; 303 len = round_page(off + len); 304 taddr = uvm_km_alloc(phys_map, len, 0, UVM_KMF_VAONLY | UVM_KMF_WAITVA); 305 bp->b_data = (void *)(taddr + off); 306 /* 307 * The region is locked, so we expect that pmap_extract() will return 308 * true. 309 * XXX: unwise to expect this in a multithreaded environment. 310 * anything can happen to a pmap between the time we lock a 311 * region, release the pmap lock, and then relock it for 312 * the pmap_extract(). 313 * 314 * no need to flush TLB since we expect nothing to be mapped 315 * where we just allocated (TLB will be flushed when our 316 * mapping is removed). 317 */ 318 while (len) { 319 (void) pmap_extract(vm_map_pmap(&bp->b_proc->p_vmspace->vm_map), 320 faddr, &fpa); 321 pmap_kenter_pa(taddr, fpa, VM_PROT_READ|VM_PROT_WRITE, 0); 322 faddr += PAGE_SIZE; 323 taddr += PAGE_SIZE; 324 len -= PAGE_SIZE; 325 } 326 pmap_update(pmap_kernel()); 327 328 return 0; 329 } 330 331 /* 332 * Unmap a previously-mapped user I/O request. 333 */ 334 void 335 vunmapbuf(struct buf *bp, vsize_t len) 336 { 337 vaddr_t addr, off; 338 339 KASSERT((bp->b_flags & B_PHYS) != 0); 340 341 addr = trunc_page((vaddr_t)bp->b_data); 342 off = (vaddr_t)bp->b_data - addr; 343 len = round_page(off + len); 344 pmap_kremove(addr, len); 345 pmap_update(pmap_kernel()); 346 uvm_km_free(phys_map, addr, len, UVM_KMF_VAONLY); 347 bp->b_data = bp->b_saveaddr; 348 bp->b_saveaddr = 0; 349 } 350 351 #ifdef __HAVE_CPU_UAREA_ROUTINES 352 /* 353 * Layout of the uarea: 354 * Page[0] = PCB 355 * Page[1] = RedZone 356 * Page[2] = Stack 357 * Page[...] = Stack 358 * Page[UPAGES-1] = Stack 359 * Page[UPAGES] = RedZone 360 * There is a redzone at the beginning of the stack, and another one at the 361 * end. The former is to protect against deep recursions that could corrupt 362 * the PCB, the latter to protect against severe stack overflows. 363 */ 364 void * 365 cpu_uarea_alloc(bool system) 366 { 367 vaddr_t base, va; 368 paddr_t pa; 369 struct pcb *pcb; 370 371 base = uvm_km_alloc(kernel_map, USPACE + PAGE_SIZE, 0, 372 UVM_KMF_WIRED|UVM_KMF_WAITVA); 373 374 /* 375 * Prepare the FPU save area: 376 * 377 * 1. If this is a system thread, no save area. 378 * XXX Allocate/free one in kthread_fpu_enter/exit_md. 379 * 380 * 2. If this is a user thread, and the fpu save size is large 381 * enough, allocate an extra block of memory for it. 382 * 383 * 3. Otherwise, this is a user thread and the fpu save size 384 * fits inside the pcb page, so use that. 385 * 386 * XXX Note that this is currently amd64-only -- if you extend 387 * this FPU save space allocation to i386, you'll need to 388 * remove the panic in fpuinit_mxcsr_mask on 389 * x86_fpu_save_separate_p and make pcb_savefpu a pointer 390 * indirection in struct pcb. 391 */ 392 pcb = (void *)base; 393 if (system) { /* (1) */ 394 pcb->pcb_savefpu = NULL; 395 } else if (x86_fpu_save_separate_p()) { /* (2) */ 396 __CTASSERT(PAGE_SIZE >= 64); 397 /* No need to zero -- caller will initialize. */ 398 va = uvm_km_alloc(kernel_map, x86_fpu_save_size, PAGE_SIZE, 399 UVM_KMF_WIRED|UVM_KMF_WAITVA); 400 pcb->pcb_savefpu = (void *)va; 401 } else { /* (3) */ 402 pcb->pcb_savefpu = &pcb->pcb_savefpusmall; 403 } 404 405 /* Page[1] = RedZone */ 406 va = base + PAGE_SIZE; 407 if (!pmap_extract(pmap_kernel(), va, &pa)) { 408 panic("%s: impossible, Page[1] unmapped", __func__); 409 } 410 pmap_kremove(va, PAGE_SIZE); 411 uvm_pagefree(PHYS_TO_VM_PAGE(pa)); 412 413 /* Page[UPAGES] = RedZone */ 414 va = base + USPACE; 415 if (!pmap_extract(pmap_kernel(), va, &pa)) { 416 panic("%s: impossible, Page[UPAGES] unmapped", __func__); 417 } 418 pmap_kremove(va, PAGE_SIZE); 419 uvm_pagefree(PHYS_TO_VM_PAGE(pa)); 420 421 pmap_update(pmap_kernel()); 422 423 return (void *)base; 424 } 425 426 bool 427 cpu_uarea_free(void *addr) 428 { 429 const struct pcb *const pcb = addr; 430 vaddr_t base = (vaddr_t)addr; 431 432 /* 433 * If we allocated a separate FPU save area, free it. 434 */ 435 if (pcb->pcb_savefpu != NULL && 436 pcb->pcb_savefpu != &pcb->pcb_savefpusmall) { 437 KASSERTMSG(x86_fpu_save_separate_p(), "pcb=%p pcb_savefpu=%p", 438 pcb, pcb->pcb_savefpu); 439 uvm_km_free(kernel_map, (vaddr_t)pcb->pcb_savefpu, 440 x86_fpu_save_size, UVM_KMF_WIRED); 441 } 442 443 KASSERT(!pmap_extract(pmap_kernel(), base + PAGE_SIZE, NULL)); 444 KASSERT(!pmap_extract(pmap_kernel(), base + USPACE, NULL)); 445 uvm_km_free(kernel_map, base, USPACE + PAGE_SIZE, UVM_KMF_WIRED); 446 return true; 447 } 448 #endif /* __HAVE_CPU_UAREA_ROUTINES */ 449