1 /* $NetBSD: vm_machdep.c,v 1.106 2023/12/15 09:43:59 rin Exp $ */ 2 3 /* 4 * Copyright (C) 1995, 1996 Wolfgang Solfrank. 5 * Copyright (C) 1995, 1996 TooLs GmbH. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by TooLs GmbH. 19 * 4. The name of TooLs GmbH may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 28 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <sys/cdefs.h> 35 __KERNEL_RCSID(0, "$NetBSD: vm_machdep.c,v 1.106 2023/12/15 09:43:59 rin Exp $"); 36 37 #ifdef _KERNEL_OPT 38 #include "opt_altivec.h" 39 #include "opt_ppcarch.h" 40 #include "opt_ppccache.h" 41 #endif 42 43 #include <sys/param.h> 44 #include <sys/core.h> 45 #include <sys/exec.h> 46 #include <sys/proc.h> 47 #include <sys/systm.h> 48 #include <sys/vnode.h> 49 #include <sys/buf.h> 50 51 #include <uvm/uvm.h> 52 53 #if defined(ALTIVEC) || defined(PPC_HAVE_SPE) 54 #include <powerpc/altivec.h> 55 #endif 56 #include <machine/fpu.h> 57 #include <machine/pcb.h> 58 #include <machine/psl.h> 59 60 #ifdef PPC_IBM4XX 61 vaddr_t vmaprange(struct proc *, vaddr_t, vsize_t, int); 62 void vunmaprange(vaddr_t, vsize_t); 63 #endif 64 65 void cpu_lwp_bootstrap(void); 66 67 /* 68 * Finish a fork operation, with execution context l2 nearly set up. 69 * Copy and update the pcb and trap frame, making the child ready to run. 70 * 71 * Rig the child's kernel stack so that it will have a switch frame which 72 * returns to cpu_lwp_bootstrap() which will call child_return() with l2 73 * as its argument. This causes the newly-created child process to go 74 * directly to user level with an apparent return value of 0 from 75 * fork(), while the parent process returns normally. 76 * 77 * l1 is the execution context being forked; if l1 == &lwp0, we are creating 78 * a kernel thread, and the return path and argument are specified with 79 * `func' and `arg'. 80 * 81 * If an alternate user-level stack is requested (with non-zero values 82 * in both the stack and stacksize args), set up the user stack pointer 83 * accordingly. 84 */ 85 void 86 cpu_lwp_fork(struct lwp *l1, struct lwp *l2, void *stack, size_t stacksize, 87 void (*func)(void *), void *arg) 88 { 89 90 /* 91 * If l1 != curlwp && l1 == &lwp0, we're creating a kernel thread. 92 */ 93 KASSERT(l1 == curlwp || l1 == &lwp0); 94 95 struct pcb * const pcb1 = lwp_getpcb(l1); 96 struct pcb * const pcb2 = lwp_getpcb(l2); 97 98 /* Set up user trapframe pointer. */ 99 l2->l_md.md_utf = trapframe(l2); 100 101 /* Copy PCB. */ 102 *pcb2 = *pcb1; 103 104 pcb2->pcb_pm = l2->l_proc->p_vmspace->vm_map.pmap; 105 106 /* 107 * Setup the trap frame for the new process 108 */ 109 *l2->l_md.md_utf = *l1->l_md.md_utf; 110 111 /* 112 * If specified, give the child a different stack. Make sure to 113 * reserve enough at the top to store the previous LR. 114 */ 115 if (stack != NULL) { 116 l2->l_md.md_utf->tf_fixreg[1] = 117 ((register_t)stack + stacksize - STACK_ALIGNBYTES) 118 & ~STACK_ALIGNBYTES; 119 } 120 121 /* 122 * Now deal setting up the initial function and its argument. 123 */ 124 struct ktrapframe * const ktf = ktrapframe(l2); 125 struct callframe * const cf = ((struct callframe *)ktf) - 1; 126 struct switchframe * const sf = ((struct switchframe *)cf) - 1; 127 128 /* 129 * Align stack pointer 130 * struct ktrapframe has a partial callframe (sp & lr) 131 * followed by a real trapframe. The partial callframe 132 * is for the callee to store LR. The SP isn't really used 133 * since trap/syscall will use the SP in the trapframe. 134 * There happens to be a partial callframe in front of the 135 * trapframe, too. 136 */ 137 ktf->ktf_lr = (register_t) cpu_lwp_bootstrap; 138 ktf->ktf_sp = (register_t) (ktf + 1); /* just in case */ 139 140 cf->cf_sp = (register_t) ktf; 141 cf->cf_r31 = (register_t) func; 142 cf->cf_r30 = (register_t) arg; 143 144 memset((void *)sf, 0, sizeof *sf); /* just in case */ 145 sf->sf_sp = (register_t) cf; 146 #if defined (PPC_OEA) || defined (PPC_OEA64_BRIDGE) 147 sf->sf_user_sr = pmap_kernel()->pm_sr[USER_SR]; /* again, just in case */ 148 #endif 149 pcb2->pcb_sp = (register_t)sf; 150 pcb2->pcb_kmapsr = 0; 151 pcb2->pcb_umapsr = 0; 152 #ifdef PPC_HAVE_FPU 153 pcb2->pcb_flags = PSL_FE_DFLT; 154 #endif 155 #ifdef CACHE_PROTO_MEI 156 { 157 paddr_t pa; 158 int dcache_line_size, i; 159 160 /* Flush on cache values for other cpu. */ 161 162 dcache_line_size = curcpu()->ci_ci.dcache_line_size; 163 pa = vtophys((vaddr_t)sf); 164 for (i = 0; i < SFRAMELEN + CALLFRAMELEN + FRAMELEN; 165 i += dcache_line_size) { 166 __asm volatile ("dcbf 0,%0"::"r"(pa):"memory"); 167 pa += dcache_line_size; 168 } 169 __asm volatile ("dcbf 0,%0"::"r"(pa):"memory"); 170 pa = vtophys((vaddr_t)pcb2->pcb_pm); 171 for (i = 0; i < sizeof(*pcb2->pcb_pm); i += dcache_line_size) { 172 __asm volatile ("dcbf 0,%0"::"r"(pa):"memory"); 173 pa += dcache_line_size; 174 } 175 __asm volatile ("dcbf 0,%0"::"r"(pa):"memory"); 176 pa = vtophys((vaddr_t)pcb2); 177 for (i = 0; i < sizeof(*pcb2); i += dcache_line_size) { 178 __asm volatile ("dcbf 0,%0"::"r"(pa):"memory"); 179 pa += dcache_line_size; 180 } 181 __asm volatile ("dcbf 0,%0"::"r"(pa):"memory"); 182 183 /* Need more flush? */ 184 } 185 #endif 186 } 187 188 void 189 cpu_lwp_free(struct lwp *l, int proc) 190 { 191 192 (void)l; 193 } 194 195 void 196 cpu_lwp_free2(struct lwp *l) 197 { 198 199 (void)l; 200 } 201 202 #ifdef PPC_IBM4XX 203 /* 204 * Map a range of user addresses into the kernel. 205 */ 206 vaddr_t 207 vmaprange(struct proc *p, vaddr_t uaddr, vsize_t len, int prot) 208 { 209 vaddr_t faddr, taddr, kaddr; 210 vsize_t off; 211 paddr_t pa; 212 213 faddr = trunc_page(uaddr); 214 off = uaddr - faddr; 215 len = round_page(off + len); 216 taddr = uvm_km_alloc(phys_map, len, 0, UVM_KMF_VAONLY | UVM_KMF_WAITVA); 217 kaddr = taddr + off; 218 for (; len > 0; len -= PAGE_SIZE) { 219 (void) pmap_extract(vm_map_pmap(&p->p_vmspace->vm_map), 220 faddr, &pa); 221 pmap_kenter_pa(taddr, pa, prot, 0); 222 faddr += PAGE_SIZE; 223 taddr += PAGE_SIZE; 224 } 225 return (kaddr); 226 } 227 228 /* 229 * Undo vmaprange. 230 */ 231 void 232 vunmaprange(vaddr_t kaddr, vsize_t len) 233 { 234 vaddr_t addr; 235 vsize_t off; 236 237 addr = trunc_page(kaddr); 238 off = kaddr - addr; 239 len = round_page(off + len); 240 pmap_kremove(addr, len); 241 uvm_km_free(phys_map, addr, len, UVM_KMF_VAONLY); 242 } 243 #endif /* PPC_IBM4XX */ 244 245 /* 246 * Map a user I/O request into kernel virtual address space. 247 * Note: these pages have already been locked by uvm_vslock. 248 */ 249 int 250 vmapbuf(struct buf *bp, vsize_t len) 251 { 252 vaddr_t faddr, taddr; 253 vsize_t off; 254 paddr_t pa; 255 int prot = VM_PROT_READ | ((bp->b_flags & B_READ) ? VM_PROT_WRITE : 0); 256 257 #ifdef DIAGNOSTIC 258 if (!(bp->b_flags & B_PHYS)) 259 panic("vmapbuf"); 260 #endif 261 /* 262 * XXX Reimplement this with vmaprange (on at least PPC_IBM4XX CPUs). 263 */ 264 bp->b_saveaddr = bp->b_data; 265 faddr = trunc_page((vaddr_t)bp->b_saveaddr); 266 off = (vaddr_t)bp->b_data - faddr; 267 len = round_page(off + len); 268 taddr = uvm_km_alloc(phys_map, len, 0, UVM_KMF_VAONLY | UVM_KMF_WAITVA); 269 bp->b_data = (void *)(taddr + off); 270 for (; len > 0; len -= PAGE_SIZE) { 271 (void) pmap_extract(vm_map_pmap(&bp->b_proc->p_vmspace->vm_map), 272 faddr, &pa); 273 /* 274 * Use pmap_enter so the referenced and modified bits are 275 * appropriately set. 276 */ 277 pmap_kenter_pa(taddr, pa, prot, 0); 278 faddr += PAGE_SIZE; 279 taddr += PAGE_SIZE; 280 } 281 pmap_update(pmap_kernel()); 282 283 return 0; 284 } 285 286 /* 287 * Unmap a previously-mapped user I/O request. 288 */ 289 void 290 vunmapbuf(struct buf *bp, vsize_t len) 291 { 292 vaddr_t addr; 293 vsize_t off; 294 295 #ifdef DIAGNOSTIC 296 if (!(bp->b_flags & B_PHYS)) 297 panic("vunmapbuf"); 298 #endif 299 addr = trunc_page((vaddr_t)bp->b_data); 300 off = (vaddr_t)bp->b_data - addr; 301 len = round_page(off + len); 302 /* 303 * Since the pages were entered by pmap_enter, use pmap_remove 304 * to remove them. 305 */ 306 pmap_kremove(addr, len); 307 pmap_update(pmap_kernel()); 308 uvm_km_free(phys_map, addr, len, UVM_KMF_VAONLY); 309 bp->b_data = bp->b_saveaddr; 310 bp->b_saveaddr = 0; 311 } 312 313 #ifdef __HAVE_CPU_UAREA_ROUTINES 314 void * 315 cpu_uarea_alloc(bool system) 316 { 317 #ifdef PMAP_MAP_POOLPAGE 318 struct pglist pglist; 319 int error; 320 321 /* 322 * Allocate a new physically contiguous uarea which can be 323 * direct-mapped. 324 */ 325 error = uvm_pglistalloc(USPACE, 0, PMAP_DIRECT_MAPPED_LEN, 0, 0, 326 &pglist, 1, 1); 327 if (error) { 328 return NULL; 329 } 330 331 /* 332 * Get the physical address from the first page. 333 */ 334 const struct vm_page * const pg = TAILQ_FIRST(&pglist); 335 KASSERT(pg != NULL); 336 const paddr_t pa = VM_PAGE_TO_PHYS(pg); 337 338 /* 339 * We need to return a direct-mapped VA for the pa. 340 */ 341 342 return (void *)(uintptr_t)PMAP_MAP_POOLPAGE(pa); 343 #else 344 return NULL; 345 #endif 346 } 347 348 /* 349 * Return true if we freed it, false if we didn't. 350 */ 351 bool 352 cpu_uarea_free(void *vva) 353 { 354 #ifdef PMAP_UNMAP_POOLPAGE 355 vaddr_t va = (vaddr_t) vva; 356 if (va >= VM_MIN_KERNEL_ADDRESS && va < VM_MAX_KERNEL_ADDRESS) 357 return false; 358 359 /* 360 * Since the pages are physically contiguous, the vm_page structure 361 * will be as well. 362 */ 363 struct vm_page *pg = PHYS_TO_VM_PAGE(PMAP_UNMAP_POOLPAGE(va)); 364 KASSERT(pg != NULL); 365 for (size_t i = 0; i < UPAGES; i++, pg++) { 366 uvm_pagefree(pg); 367 } 368 return true; 369 #else 370 return false; 371 #endif 372 } 373 #endif /* __HAVE_CPU_UAREA_ROUTINES */ 374