1 /* $NetBSD: vm_machdep.c,v 1.78 2021/03/28 10:29:05 skrll Exp $ */ 2 3 /* 4 * Copyright (c) 1994-1998 Mark Brinicombe. 5 * Copyright (c) 1994 Brini. 6 * All rights reserved. 7 * 8 * This code is derived from software written for Brini by Mark Brinicombe 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by Brini. 21 * 4. The name of the company nor the name of the author may be used to 22 * endorse or promote products derived from this software without specific 23 * prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED 26 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 27 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 28 * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 29 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * RiscBSD kernel project 38 * 39 * vm_machdep.h 40 * 41 * vm machine specific bits 42 * 43 * Created : 08/10/94 44 */ 45 46 #include <sys/cdefs.h> 47 __KERNEL_RCSID(0, "$NetBSD: vm_machdep.c,v 1.78 2021/03/28 10:29:05 skrll Exp $"); 48 49 #include "opt_armfpe.h" 50 #include "opt_cputypes.h" 51 52 #include <sys/param.h> 53 54 #include <sys/buf.h> 55 #include <sys/cpu.h> 56 #include <sys/exec.h> 57 #include <sys/proc.h> 58 #include <sys/systm.h> 59 #include <sys/vnode.h> 60 61 #include <uvm/uvm_extern.h> 62 63 #include <arm/vfpreg.h> 64 65 #include <machine/pcb.h> 66 #include <machine/pmap.h> 67 #include <machine/reg.h> 68 #include <machine/vmparam.h> 69 70 void lwp_trampoline(void); 71 72 /* 73 * Special compilation symbols: 74 * 75 * STACKCHECKS - Fill undefined and supervisor stacks with a known pattern 76 * on forking and check the pattern on exit, reporting 77 * the amount of stack used. 78 */ 79 80 void 81 cpu_proc_fork(struct proc *p1, struct proc *p2) 82 { 83 /* 84 * Copy machine arch string (it's small so just memcpy it). 85 */ 86 memcpy(p2->p_md.md_march, p1->p_md.md_march, sizeof(p2->p_md.md_march)); 87 } 88 89 /* 90 * Finish a fork operation, with LWP l2 nearly set up. 91 * 92 * Copy and update the pcb and trapframe, making the child ready to run. 93 * 94 * Rig the child's kernel stack so that it will start out in 95 * lwp_trampoline() which will call the specified func with the argument arg. 96 * 97 * If an alternate user-level stack is requested (with non-zero values 98 * in both the stack and stacksize args), set up the user stack pointer 99 * accordingly. 100 */ 101 void 102 cpu_lwp_fork(struct lwp *l1, struct lwp *l2, void *stack, size_t stacksize, 103 void (*func)(void *), void *arg) 104 { 105 struct switchframe *sf; 106 vaddr_t uv; 107 108 const struct pcb * const pcb1 = lwp_getpcb(l1); 109 struct pcb * const pcb2 = lwp_getpcb(l2); 110 111 #ifdef XXXDEBUG 112 printf("cpu_lwp_fork: %p %p %p %p\n", l1, l2, curlwp, &lwp0); 113 #endif /* DEBUG */ 114 115 /* Copy the pcb */ 116 *pcb2 = *pcb1; 117 118 #ifdef FPU_VFP 119 /* 120 * Disable the VFP for a newly created LWP but remember if the 121 * VFP state is valid. 122 */ 123 pcb2->pcb_vfp.vfp_fpexc &= ~VFP_FPEXC_EN; 124 #endif 125 126 /* 127 * Set up the kernel stack for the process. 128 * Note: this stack is not in use if we are forking from p1 129 */ 130 uv = uvm_lwp_getuarea(l2); 131 pcb2->pcb_ksp = uv + USPACE_SVC_STACK_TOP; 132 133 #ifdef STACKCHECKS 134 /* Fill the kernel stack with a known pattern */ 135 memset((void *)(uv + USPACE_SVC_STACK_BOTTOM), 0xdd, 136 (USPACE_SVC_STACK_TOP - USPACE_SVC_STACK_BOTTOM)); 137 #endif /* STACKCHECKS */ 138 139 #ifdef XXXDEBUG 140 printf("l1: pcb=%p pid=%d pmap=%p\n", 141 pcb1, l1->l_lid, l1->l_proc->p_vmspace->vm_map.pmap); 142 printf("l2: pcb=%p pid=%d pmap=%p\n", 143 pcb2, l2->l_lid, l2->l_proc->p_vmspace->vm_map.pmap); 144 #endif /* DEBUG */ 145 146 struct trapframe *tf = (struct trapframe *)pcb2->pcb_ksp - 1; 147 lwp_settrapframe(l2, tf); 148 *tf = *lwp_trapframe(l1); 149 150 /* 151 * If specified, give the child a different stack (make sure 152 * it's 8-byte aligned). 153 */ 154 if (stack != NULL) 155 tf->tf_usr_sp = ((vaddr_t)(stack) + stacksize) & -8; 156 157 sf = (struct switchframe *)tf - 1; 158 sf->sf_r4 = (u_int)func; 159 sf->sf_r5 = (u_int)arg; 160 sf->sf_r7 = PSR_USR32_MODE; /* for returning to userspace */ 161 sf->sf_sp = (u_int)tf; 162 sf->sf_pc = (u_int)lwp_trampoline; 163 pcb2->pcb_ksp = (u_int)sf; 164 } 165 166 /* 167 * cpu_exit is called as the last action during exit. 168 * 169 * We clean up a little and then call switch_exit() with the old proc as an 170 * argument. switch_exit() first switches to lwp0's context, and finally 171 * jumps into switch() to wait for another process to wake up. 172 */ 173 174 void 175 cpu_lwp_free(struct lwp *l, int proc) 176 { 177 #ifdef STACKCHECKS 178 /* Report how much stack has been used - debugging */ 179 struct pcb * const pcb = lwp_getpcb(l); 180 u_char *ptr; 181 u_int loop; 182 183 ptr = (u_char *)pcb + USPACE_SVC_STACK_BOTTOM; 184 for (loop = 0; loop < (USPACE_SVC_STACK_TOP - USPACE_SVC_STACK_BOTTOM) 185 && *ptr == 0xdd; ++loop, ++ptr) ; 186 log(LOG_INFO, "%u bytes of svc stack fill pattern\n", loop); 187 #endif /* STACKCHECKS */ 188 } 189 190 void 191 cpu_lwp_free2(struct lwp *l) 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 struct pmap * const pm = vm_map_pmap(&bp->b_proc->p_vmspace->vm_map); 204 vaddr_t faddr, taddr, off; 205 paddr_t fpa; 206 207 KASSERT(pm != pmap_kernel()); 208 209 #ifdef XXXDEBUG 210 printf("vmapbuf: bp=%08x buf=%08x len=%08x\n", (u_int)bp, 211 (u_int)bp->b_data, (u_int)len); 212 #endif /* XXXDEBUG */ 213 214 if ((bp->b_flags & B_PHYS) == 0) 215 panic("vmapbuf"); 216 217 bp->b_saveaddr = bp->b_data; 218 faddr = trunc_page((vaddr_t)bp->b_data); 219 off = (vaddr_t)bp->b_data - faddr; 220 len = round_page(off + len); 221 taddr = uvm_km_alloc(phys_map, len, atop(faddr) & uvmexp.colormask, 222 UVM_KMF_VAONLY | UVM_KMF_WAITVA | UVM_KMF_COLORMATCH); 223 bp->b_data = (void *)(taddr + off); 224 225 /* 226 * The region is locked, so we expect that pmap_extract() will return 227 * true. 228 */ 229 while (len) { 230 (void) pmap_extract(pm, faddr, &fpa); 231 pmap_enter(pmap_kernel(), taddr, fpa, VM_PROT_READ|VM_PROT_WRITE, 232 VM_PROT_READ|VM_PROT_WRITE|PMAP_WIRED); 233 faddr += PAGE_SIZE; 234 taddr += PAGE_SIZE; 235 len -= PAGE_SIZE; 236 } 237 pmap_update(pmap_kernel()); 238 239 return 0; 240 } 241 242 /* 243 * Unmap a previously-mapped user I/O request. 244 */ 245 void 246 vunmapbuf(struct buf *bp, vsize_t len) 247 { 248 vaddr_t addr, off; 249 250 #ifdef XXXDEBUG 251 printf("vunmapbuf: bp=%08x buf=%08x len=%08x\n", 252 (u_int)bp, (u_int)bp->b_data, (u_int)len); 253 #endif /* XXXDEBUG */ 254 255 if ((bp->b_flags & B_PHYS) == 0) 256 panic("vunmapbuf"); 257 258 /* 259 * Make sure the cache does not have dirty data for the 260 * pages we had mapped. 261 */ 262 addr = trunc_page((vaddr_t)bp->b_data); 263 off = (vaddr_t)bp->b_data - addr; 264 len = round_page(off + len); 265 266 pmap_remove(pmap_kernel(), addr, addr + len); 267 pmap_update(pmap_kernel()); 268 uvm_km_free(phys_map, addr, len, UVM_KMF_VAONLY); 269 bp->b_data = bp->b_saveaddr; 270 bp->b_saveaddr = 0; 271 } 272 273 void 274 ktext_write(void *to, const void *from, size_t size) 275 { 276 struct pmap *pmap = pmap_kernel(); 277 pd_entry_t *pde, oldpde, tmppde; 278 pt_entry_t *pte, oldpte, tmppte; 279 vaddr_t pgva; 280 size_t limit, savesize; 281 const char *src; 282 char *dst; 283 284 /* XXX: gcc */ 285 oldpte = 0; 286 287 if ((savesize = size) == 0) 288 return; 289 290 dst = (char *) to; 291 src = (const char *) from; 292 293 do { 294 /* Get the PDE of the current VA. */ 295 if (pmap_get_pde_pte(pmap, (vaddr_t) dst, &pde, &pte) == false) 296 goto no_mapping; 297 switch ((oldpde = *pde) & L1_TYPE_MASK) { 298 case L1_TYPE_S: 299 pgva = (vaddr_t)dst & L1_S_FRAME; 300 limit = L1_S_SIZE - ((vaddr_t)dst & L1_S_OFFSET); 301 302 tmppde = l1pte_set_writable(oldpde); 303 *pde = tmppde; 304 PTE_SYNC(pde); 305 break; 306 307 case L1_TYPE_C: 308 pgva = (vaddr_t)dst & L2_S_FRAME; 309 limit = L2_S_SIZE - ((vaddr_t)dst & L2_S_OFFSET); 310 311 if (pte == NULL) 312 goto no_mapping; 313 oldpte = *pte; 314 tmppte = l2pte_set_writable(oldpte); 315 *pte = tmppte; 316 PTE_SYNC(pte); 317 break; 318 319 default: 320 no_mapping: 321 printf(" address 0x%08lx not a valid page\n", 322 (vaddr_t) dst); 323 return; 324 } 325 cpu_tlb_flushD_SE(pgva); 326 cpu_cpwait(); 327 328 if (limit > size) 329 limit = size; 330 size -= limit; 331 332 /* 333 * Page is now writable. Do as much access as we 334 * can in this page. 335 */ 336 for (; limit > 0; limit--) 337 *dst++ = *src++; 338 339 /* 340 * Restore old mapping permissions. 341 */ 342 switch (oldpde & L1_TYPE_MASK) { 343 case L1_TYPE_S: 344 *pde = oldpde; 345 PTE_SYNC(pde); 346 break; 347 348 case L1_TYPE_C: 349 *pte = oldpte; 350 PTE_SYNC(pte); 351 break; 352 } 353 cpu_tlb_flushD_SE(pgva); 354 cpu_cpwait(); 355 } while (size != 0); 356 357 /* Sync the I-cache. */ 358 cpu_icache_sync_range((vaddr_t)to, savesize); 359 } 360 361 /* End of vm_machdep.c */ 362