1 /* $NetBSD: vm_machdep.c,v 1.28 1996/08/02 13:44:48 pk Exp $ */ 2 3 /* 4 * Copyright (c) 1996 5 * The President and Fellows of Harvard College. All rights reserved. 6 * Copyright (c) 1992, 1993 7 * The Regents of the University of California. All rights reserved. 8 * 9 * This software was developed by the Computer Systems Engineering group 10 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 11 * contributed to Berkeley. 12 * 13 * All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Lawrence Berkeley Laboratory. 17 * This product includes software developed by Harvard University. 18 * 19 * Redistribution and use in source and binary forms, with or without 20 * modification, are permitted provided that the following conditions 21 * are met: 22 * 1. Redistributions of source code must retain the above copyright 23 * notice, this list of conditions and the following disclaimer. 24 * 2. Redistributions in binary form must reproduce the above copyright 25 * notice, this list of conditions and the following disclaimer in the 26 * documentation and/or other materials provided with the distribution. 27 * 3. All advertising materials mentioning features or use of this software 28 * must display the following acknowledgement: 29 * This product includes software developed by Harvard University. 30 * This product includes software developed by the University of 31 * California, Berkeley and its contributors. 32 * 4. Neither the name of the University nor the names of its contributors 33 * may be used to endorse or promote products derived from this software 34 * without specific prior written permission. 35 * 36 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 37 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 38 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 39 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 40 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 41 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 42 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 43 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 44 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 45 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 46 * SUCH DAMAGE. 47 * 48 * @(#)vm_machdep.c 8.2 (Berkeley) 9/23/93 49 */ 50 51 #include <sys/param.h> 52 #include <sys/systm.h> 53 #include <sys/proc.h> 54 #include <sys/user.h> 55 #include <sys/core.h> 56 #include <sys/malloc.h> 57 #include <sys/buf.h> 58 #include <sys/exec.h> 59 #include <sys/vnode.h> 60 #include <sys/map.h> 61 62 #include <vm/vm.h> 63 #include <vm/vm_kern.h> 64 65 #include <machine/cpu.h> 66 #include <machine/frame.h> 67 #include <machine/trap.h> 68 69 #include <sparc/sparc/cache.h> 70 71 /* 72 * Move pages from one kernel virtual address to another. 73 */ 74 void 75 pagemove(from, to, size) 76 register caddr_t from, to; 77 size_t size; 78 { 79 register vm_offset_t pa; 80 81 if (size & CLOFSET || (int)from & CLOFSET || (int)to & CLOFSET) 82 panic("pagemove 1"); 83 while (size > 0) { 84 pa = pmap_extract(pmap_kernel(), (vm_offset_t)from); 85 if (pa == 0) 86 panic("pagemove 2"); 87 pmap_remove(pmap_kernel(), 88 (vm_offset_t)from, (vm_offset_t)from + PAGE_SIZE); 89 pmap_enter(pmap_kernel(), 90 (vm_offset_t)to, pa, VM_PROT_READ|VM_PROT_WRITE, 1); 91 from += PAGE_SIZE; 92 to += PAGE_SIZE; 93 size -= PAGE_SIZE; 94 } 95 } 96 97 /* 98 * Wrapper for dvma_mapin() in kernel space, 99 * so drivers need not include VM goo to get at kernel_map. 100 */ 101 caddr_t 102 kdvma_mapin(va, len, canwait) 103 caddr_t va; 104 int len, canwait; 105 { 106 return ((caddr_t)dvma_mapin(kernel_map, (vm_offset_t)va, len, canwait)); 107 } 108 109 caddr_t 110 dvma_malloc(len, kaddr, flags) 111 size_t len; 112 void *kaddr; 113 int flags; 114 { 115 vm_offset_t kva; 116 vm_offset_t dva; 117 118 len = round_page(len); 119 kva = (vm_offset_t)malloc(len, M_DEVBUF, flags); 120 if (kva == NULL) 121 return (NULL); 122 123 *(vm_offset_t *)kaddr = kva; 124 dva = dvma_mapin(kernel_map, kva, len, (flags & M_NOWAIT) ? 0 : 1); 125 if (dva == NULL) { 126 free((void *)kva, M_DEVBUF); 127 return (NULL); 128 } 129 return (caddr_t)dva; 130 } 131 132 void 133 dvma_free(dva, len, kaddr) 134 caddr_t dva; 135 size_t len; 136 void *kaddr; 137 { 138 vm_offset_t kva = *(vm_offset_t *)kaddr; 139 140 dvma_mapout((vm_offset_t)dva, kva, round_page(len)); 141 free((void *)kva, M_DEVBUF); 142 } 143 144 /* 145 * Map a range [va, va+len] of wired virtual addresses in the given map 146 * to a kernel address in DVMA space. 147 */ 148 vm_offset_t 149 dvma_mapin(map, va, len, canwait) 150 struct vm_map *map; 151 vm_offset_t va; 152 int len, canwait; 153 { 154 vm_offset_t kva, tva; 155 register int npf, s; 156 register vm_offset_t pa; 157 long off, pn; 158 #if defined(SUN4M) 159 extern int has_iocache; 160 #endif 161 162 off = (int)va & PGOFSET; 163 va -= off; 164 len = round_page(len + off); 165 npf = btoc(len); 166 167 #if defined(SUN4M) 168 if (!has_iocache) 169 kvm_uncache((caddr_t)va, len >> PGSHIFT); 170 #endif 171 172 s = splimp(); 173 for (;;) { 174 175 pn = rmalloc(dvmamap, npf); 176 177 if (pn != 0) 178 break; 179 if (canwait) { 180 (void)tsleep(dvmamap, PRIBIO+1, "physio", 0); 181 continue; 182 } 183 splx(s); 184 return NULL; 185 } 186 splx(s); 187 188 kva = tva = rctov(pn); 189 190 while (npf--) { 191 pa = pmap_extract(vm_map_pmap(map), va); 192 if (pa == 0) 193 panic("dvma_mapin: null page frame"); 194 pa = trunc_page(pa); 195 196 #if defined(SUN4M) 197 if (cputyp == CPU_SUN4M) { 198 iommu_enter(tva, pa); 199 } else 200 #endif 201 { 202 /* 203 * pmap_enter distributes this mapping to all 204 * contexts... maybe we should avoid this extra work 205 */ 206 #ifdef notyet 207 #if defined(SUN4) 208 if (have_iocache) 209 pa |= PG_IOC; 210 #endif 211 #endif 212 pmap_enter(pmap_kernel(), tva, 213 pa | PMAP_NC, 214 VM_PROT_READ|VM_PROT_WRITE, 1); 215 } 216 217 tva += PAGE_SIZE; 218 va += PAGE_SIZE; 219 } 220 return kva + off; 221 } 222 223 /* 224 * Remove double map of `va' in DVMA space at `kva'. 225 */ 226 void 227 dvma_mapout(kva, va, len) 228 vm_offset_t kva, va; 229 int len; 230 { 231 register int s, off; 232 233 off = (int)kva & PGOFSET; 234 kva -= off; 235 len = round_page(len + off); 236 237 #if defined(SUN4M) 238 if (cputyp == CPU_SUN4M) 239 iommu_remove(kva, len); 240 else 241 #endif 242 pmap_remove(pmap_kernel(), kva, kva + len); 243 244 s = splimp(); 245 rmfree(dvmamap, btoc(len), vtorc(kva)); 246 wakeup(dvmamap); 247 splx(s); 248 249 if (vactype != VAC_NONE) 250 cache_flush((caddr_t)va, len); 251 } 252 253 /* 254 * Map an IO request into kernel virtual address space. 255 */ 256 /*ARGSUSED*/ 257 void 258 vmapbuf(bp, sz) 259 register struct buf *bp; 260 vm_size_t sz; 261 { 262 register vm_offset_t addr, kva, pa; 263 register vm_size_t size, off; 264 register int npf; 265 struct proc *p; 266 register struct vm_map *map; 267 268 if ((bp->b_flags & B_PHYS) == 0) 269 panic("vmapbuf"); 270 p = bp->b_proc; 271 map = &p->p_vmspace->vm_map; 272 bp->b_saveaddr = bp->b_data; 273 addr = (vm_offset_t)bp->b_saveaddr; 274 off = addr & PGOFSET; 275 size = round_page(bp->b_bcount + off); 276 kva = kmem_alloc_wait(kernel_map, size); 277 bp->b_data = (caddr_t)(kva + off); 278 addr = trunc_page(addr); 279 npf = btoc(size); 280 while (npf--) { 281 pa = pmap_extract(vm_map_pmap(map), (vm_offset_t)addr); 282 if (pa == 0) 283 panic("vmapbuf: null page frame"); 284 285 /* 286 * pmap_enter distributes this mapping to all 287 * contexts... maybe we should avoid this extra work 288 */ 289 pmap_enter(pmap_kernel(), kva, 290 pa | PMAP_NC, 291 VM_PROT_READ|VM_PROT_WRITE, 1); 292 293 addr += PAGE_SIZE; 294 kva += PAGE_SIZE; 295 } 296 } 297 298 /* 299 * Free the io map addresses associated with this IO operation. 300 */ 301 /*ARGSUSED*/ 302 void 303 vunmapbuf(bp, sz) 304 register struct buf *bp; 305 vm_size_t sz; 306 { 307 register vm_offset_t kva = (vm_offset_t)bp->b_data; 308 register vm_size_t size, off; 309 310 if ((bp->b_flags & B_PHYS) == 0) 311 panic("vunmapbuf"); 312 313 kva = (vm_offset_t)bp->b_data; 314 off = kva & PGOFSET; 315 size = round_page(bp->b_bcount + off); 316 kmem_free_wakeup(kernel_map, trunc_page(kva), size); 317 bp->b_data = bp->b_saveaddr; 318 bp->b_saveaddr = NULL; 319 if (vactype != VAC_NONE) 320 cache_flush(bp->b_un.b_addr, bp->b_bcount - bp->b_resid); 321 } 322 323 324 /* 325 * The offset of the topmost frame in the kernel stack. 326 */ 327 #define TOPFRAMEOFF (USPACE-sizeof(struct trapframe)-sizeof(struct frame)) 328 329 /* 330 * Finish a fork operation, with process p2 nearly set up. 331 * Copy and update the pcb, making the child ready to run, and marking 332 * it so that it can return differently than the parent. 333 * 334 * This function relies on the fact that the pcb is 335 * the first element in struct user. 336 */ 337 void 338 cpu_fork(p1, p2) 339 register struct proc *p1, *p2; 340 { 341 register struct pcb *opcb = &p1->p_addr->u_pcb; 342 register struct pcb *npcb = &p2->p_addr->u_pcb; 343 register struct trapframe *tf2; 344 register struct rwindow *rp; 345 346 /* 347 * Save all user registers to p1's stack or, in the case of 348 * user registers and invalid stack pointers, to opcb. 349 * We then copy the whole pcb to p2; when switch() selects p2 350 * to run, it will run at the `proc_trampoline' stub, rather 351 * than returning at the copying code below. 352 * 353 * If process p1 has an FPU state, we must copy it. If it is 354 * the FPU user, we must save the FPU state first. 355 */ 356 357 write_user_windows(); 358 opcb->pcb_psr = getpsr(); 359 bcopy((caddr_t)opcb, (caddr_t)npcb, sizeof(struct pcb)); 360 if (p1->p_md.md_fpstate) { 361 if (p1 == fpproc) 362 savefpstate(p1->p_md.md_fpstate); 363 p2->p_md.md_fpstate = malloc(sizeof(struct fpstate), 364 M_SUBPROC, M_WAITOK); 365 bcopy(p1->p_md.md_fpstate, p2->p_md.md_fpstate, 366 sizeof(struct fpstate)); 367 } else 368 p2->p_md.md_fpstate = NULL; 369 370 /* 371 * Setup (kernel) stack frame that will by-pass the child 372 * out of the kernel. (The trap frame invariably resides at 373 * the tippity-top of the u. area.) 374 */ 375 tf2 = p2->p_md.md_tf = (struct trapframe *) 376 ((int)npcb + USPACE - sizeof(*tf2)); 377 378 /* Copy parent's trapframe */ 379 *tf2 = *(struct trapframe *)((int)opcb + USPACE - sizeof(*tf2)); 380 381 /* Duplicate efforts of syscall(), but slightly differently */ 382 if (tf2->tf_global[1] & SYSCALL_G2RFLAG) { 383 /* jmp %g2 (or %g7, deprecated) on success */ 384 tf2->tf_npc = tf2->tf_global[2]; 385 } else { 386 /* 387 * old system call convention: clear C on success 388 * note: proc_trampoline() sets a fresh psr when 389 * returning to user mode. 390 */ 391 /*tf2->tf_psr &= ~PSR_C; -* success */ 392 } 393 394 /* Set return values in child mode */ 395 tf2->tf_out[0] = 0; 396 tf2->tf_out[1] = 1; 397 398 /* Construct kernel frame to return to in cpu_switch() */ 399 rp = (struct rwindow *)((u_int)npcb + TOPFRAMEOFF); 400 rp->rw_local[0] = (int)child_return; /* Function to call */ 401 rp->rw_local[1] = (int)p2; /* and its argument */ 402 403 npcb->pcb_pc = (int)proc_trampoline - 8; 404 npcb->pcb_sp = (int)rp; 405 npcb->pcb_psr &= ~PSR_CWP; /* Run in window #0 */ 406 npcb->pcb_wim = 1; /* Fence at window #1 */ 407 408 } 409 410 /* 411 * cpu_set_kpc: 412 * 413 * Arrange for in-kernel execution of a process to continue at the 414 * named pc, as if the code at that address were called as a function 415 * with the current process's process pointer as an argument. 416 * 417 * Note that it's assumed that when the named process returns, 418 * we immediately return to user mode. 419 * 420 * (Note that cpu_fork(), above, uses an open-coded version of this.) 421 */ 422 void 423 cpu_set_kpc(p, pc) 424 struct proc *p; 425 void (*pc) __P((struct proc *)); 426 { 427 struct pcb *pcb; 428 struct rwindow *rp; 429 430 pcb = &p->p_addr->u_pcb; 431 432 rp = (struct rwindow *)((u_int)pcb + TOPFRAMEOFF); 433 rp->rw_local[0] = (int)pc; /* Function to call */ 434 rp->rw_local[1] = (int)p; /* and its argument */ 435 436 /* 437 * Frob PCB: 438 * - arrange to return to proc_trampoline() from cpu_switch() 439 * - point it at the stack frame constructed above 440 * - make it run in a clear set of register windows 441 */ 442 pcb->pcb_pc = (int)proc_trampoline - 8; 443 pcb->pcb_sp = (int)rp; 444 pcb->pcb_psr &= ~PSR_CWP; /* Run in window #0 */ 445 pcb->pcb_wim = 1; /* Fence at window #1 */ 446 } 447 448 /* 449 * cpu_exit is called as the last action during exit. 450 * We release the address space and machine-dependent resources, 451 * including the memory for the user structure and kernel stack. 452 * Since the latter is also the interrupt stack, we release it 453 * from assembly code after switching to a temporary pcb+stack. 454 */ 455 void 456 cpu_exit(p) 457 struct proc *p; 458 { 459 register struct fpstate *fs; 460 461 if ((fs = p->p_md.md_fpstate) != NULL) { 462 if (p == fpproc) { 463 savefpstate(fs); 464 fpproc = NULL; 465 } 466 free((void *)fs, M_SUBPROC); 467 } 468 vmspace_free(p->p_vmspace); 469 switchexit(kernel_map, p->p_addr, USPACE); 470 /* NOTREACHED */ 471 } 472 473 /* 474 * cpu_coredump is called to write a core dump header. 475 * (should this be defined elsewhere? machdep.c?) 476 */ 477 int 478 cpu_coredump(p, vp, cred, chdr) 479 struct proc *p; 480 struct vnode *vp; 481 struct ucred *cred; 482 struct core *chdr; 483 { 484 int error; 485 struct md_coredump md_core; 486 struct coreseg cseg; 487 488 CORE_SETMAGIC(*chdr, COREMAGIC, MID_SPARC, 0); 489 chdr->c_hdrsize = ALIGN(sizeof(*chdr)); 490 chdr->c_seghdrsize = ALIGN(sizeof(cseg)); 491 chdr->c_cpusize = sizeof(md_core); 492 493 md_core.md_tf = *p->p_md.md_tf; 494 if (p->p_md.md_fpstate) { 495 if (p == fpproc) 496 savefpstate(p->p_md.md_fpstate); 497 md_core.md_fpstate = *p->p_md.md_fpstate; 498 } else 499 bzero((caddr_t)&md_core.md_fpstate, sizeof(struct fpstate)); 500 501 CORE_SETMAGIC(cseg, CORESEGMAGIC, MID_SPARC, CORE_CPU); 502 cseg.c_addr = 0; 503 cseg.c_size = chdr->c_cpusize; 504 error = vn_rdwr(UIO_WRITE, vp, (caddr_t)&cseg, chdr->c_seghdrsize, 505 (off_t)chdr->c_hdrsize, UIO_SYSSPACE, 506 IO_NODELOCKED|IO_UNIT, cred, (int *)NULL, p); 507 if (error) 508 return error; 509 510 error = vn_rdwr(UIO_WRITE, vp, (caddr_t)&md_core, sizeof(md_core), 511 (off_t)(chdr->c_hdrsize + chdr->c_seghdrsize), UIO_SYSSPACE, 512 IO_NODELOCKED|IO_UNIT, cred, (int *)NULL, p); 513 if (!error) 514 chdr->c_nseg++; 515 516 return error; 517 } 518