vm_machdep.c revision 8074
137535Sdes/*- 263012Sdes * Copyright (c) 1982, 1986 The Regents of the University of California. 337535Sdes * Copyright (c) 1989, 1990 William Jolitz 437535Sdes * Copyright (c) 1994 John Dyson 537535Sdes * All rights reserved. 637535Sdes * 737535Sdes * This code is derived from software contributed to Berkeley by 837535Sdes * the Systems Programming Group of the University of Utah Computer 937535Sdes * Science Department, and William Jolitz. 1037535Sdes * 1137535Sdes * Redistribution and use in source and binary forms, with or without 1237535Sdes * modification, are permitted provided that the following conditions 1337535Sdes * are met: 1437535Sdes * 1. Redistributions of source code must retain the above copyright 1563012Sdes * notice, this list of conditions and the following disclaimer. 1637535Sdes * 2. Redistributions in binary form must reproduce the above copyright 1737535Sdes * notice, this list of conditions and the following disclaimer in the 1837535Sdes * documentation and/or other materials provided with the distribution. 1937535Sdes * 3. All advertising materials mentioning features or use of this software 2037535Sdes * must display the following acknowledgement: 2137535Sdes * This product includes software developed by the University of 2237535Sdes * California, Berkeley and its contributors. 2337535Sdes * 4. Neither the name of the University nor the names of its contributors 2437535Sdes * may be used to endorse or promote products derived from this software 2537535Sdes * without specific prior written permission. 2637535Sdes * 2737535Sdes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2863012Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2937535Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 3037535Sdes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 3137535Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3260737Sume * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3337535Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3463012Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3537535Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3663012Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3760376Sdes * SUCH DAMAGE. 3860189Sdes * 3937608Sdes * from: @(#)vm_machdep.c 7.3 (Berkeley) 5/13/91 4037535Sdes * Utah $Hdr: vm_machdep.c 1.16.1.1 89/06/23$ 4137535Sdes * $Id: vm_machdep.c,v 1.35 1995/03/19 14:28:41 davidg Exp $ 4237535Sdes */ 4360376Sdes 4437535Sdes#include "npx.h" 4537535Sdes#include <sys/param.h> 4637535Sdes#include <sys/systm.h> 4740939Sdes#include <sys/proc.h> 4841862Sdes#include <sys/malloc.h> 4937535Sdes#include <sys/buf.h> 5063012Sdes#include <sys/vnode.h> 5137535Sdes#include <sys/user.h> 5263012Sdes 5363012Sdes#include <machine/clock.h> 5437535Sdes#include <machine/cpu.h> 5563012Sdes#include <machine/md_var.h> 5663012Sdes 5763012Sdes#include <vm/vm.h> 5863012Sdes#include <vm/vm_kern.h> 5963012Sdes 6063012Sdes#include <i386/isa/isa.h> 6163012Sdes 6263012Sdes#ifdef BOUNCE_BUFFERS 6363012Sdesvm_map_t io_map; 6460196Sdesvolatile int kvasfreecnt; 6563012Sdes 6663012Sdes 6763012Sdescaddr_t bouncememory; 6863012Sdesint bouncepages, bpwait; 6963012Sdesvm_offset_t *bouncepa; 7063012Sdesint bmwait, bmfreeing; 7163012Sdes 7263012Sdes#define BITS_IN_UNSIGNED (8*sizeof(unsigned)) 7363012Sdesint bounceallocarraysize; 7463012Sdesunsigned *bounceallocarray; 7537535Sdesint bouncefree; 7637535Sdes 7763012Sdes#define SIXTEENMEG (4096*4096) 7863012Sdes#define MAXBKVA 1024 7963012Sdesint maxbkva = MAXBKVA*NBPG; 8063012Sdes 8163012Sdes/* special list that can be used at interrupt time for eventual kva free */ 8263012Sdesstruct kvasfree { 8363012Sdes vm_offset_t addr; 8463012Sdes vm_offset_t size; 8563012Sdes} kvaf[MAXBKVA]; 8663012Sdes 8763012Sdes 8837535Sdesvm_offset_t vm_bounce_kva(); 8937535Sdes/* 9037608Sdes * get bounce buffer pages (count physically contiguous) 9163012Sdes * (only 1 inplemented now) 9237608Sdes */ 9337608Sdesvm_offset_t 9463012Sdesvm_bounce_page_find(count) 9537608Sdes int count; 9663012Sdes{ 9737608Sdes int bit; 9863012Sdes int s,i; 9963012Sdes 10063012Sdes if (count != 1) 10163012Sdes panic("vm_bounce_page_find -- no support for > 1 page yet!!!"); 10263012Sdes 10363012Sdes s = splbio(); 10463012Sdesretry: 10563012Sdes for (i = 0; i < bounceallocarraysize; i++) { 10663012Sdes if (bounceallocarray[i] != 0xffffffff) { 10763012Sdes bit = ffs(~bounceallocarray[i]); 10863012Sdes if (bit) { 10963012Sdes bounceallocarray[i] |= 1 << (bit - 1) ; 11063012Sdes bouncefree -= count; 11163012Sdes splx(s); 11263012Sdes return bouncepa[(i * BITS_IN_UNSIGNED + (bit - 1))]; 11363012Sdes } 11463012Sdes } 11563012Sdes } 11663012Sdes bpwait = 1; 11763012Sdes tsleep((caddr_t) &bounceallocarray, PRIBIO, "bncwai", 0); 11863012Sdes goto retry; 11963012Sdes} 12063012Sdes 12163012Sdesvoid 12263012Sdesvm_bounce_kva_free(addr, size, now) 12337608Sdes vm_offset_t addr; 12437608Sdes vm_offset_t size; 12537608Sdes int now; 12637608Sdes{ 12737608Sdes int s = splbio(); 12863012Sdes kvaf[kvasfreecnt].addr = addr; 12937535Sdes kvaf[kvasfreecnt].size = size; 13037535Sdes ++kvasfreecnt; 13163012Sdes if( now) { 13263012Sdes /* 13337535Sdes * this will do wakeups 13463012Sdes */ 13563012Sdes vm_bounce_kva(0,0); 13663012Sdes } else { 13763012Sdes if (bmwait) { 13863012Sdes /* 13963012Sdes * if anyone is waiting on the bounce-map, then wakeup 14063012Sdes */ 14163012Sdes wakeup((caddr_t) io_map); 14263012Sdes bmwait = 0; 14363012Sdes } 14437535Sdes } 14537535Sdes splx(s); 14663012Sdes} 14763012Sdes 14863012Sdes/* 14963012Sdes * free count bounce buffer pages 15063012Sdes */ 15163012Sdesvoid 15263012Sdesvm_bounce_page_free(pa, count) 15363012Sdes vm_offset_t pa; 15463012Sdes int count; 15563012Sdes{ 15663012Sdes int allocindex; 15763012Sdes int index; 15863012Sdes int bit; 15963012Sdes 16063012Sdes if (count != 1) 16163012Sdes panic("vm_bounce_page_free -- no support for > 1 page yet!!!"); 16263012Sdes 16363012Sdes for(index=0;index<bouncepages;index++) { 16463012Sdes if( pa == bouncepa[index]) 16563012Sdes break; 16663012Sdes } 16763012Sdes 16837535Sdes if( index == bouncepages) 16937535Sdes panic("vm_bounce_page_free: invalid bounce buffer"); 17037608Sdes 17137608Sdes allocindex = index / BITS_IN_UNSIGNED; 17237608Sdes bit = index % BITS_IN_UNSIGNED; 17337535Sdes 17463012Sdes bounceallocarray[allocindex] &= ~(1 << bit); 17537535Sdes 17663012Sdes bouncefree += count; 17763012Sdes if (bpwait) { 17863012Sdes bpwait = 0; 17963012Sdes wakeup((caddr_t) &bounceallocarray); 18063012Sdes } 18163012Sdes} 18263012Sdes 18363012Sdes/* 18463012Sdes * allocate count bounce buffer kva pages 18537535Sdes */ 18663012Sdesvm_offset_t 18763012Sdesvm_bounce_kva(size, waitok) 18837535Sdes int size; 18963012Sdes int waitok; 19063012Sdes{ 19163012Sdes int i; 19263012Sdes vm_offset_t kva = 0; 19363012Sdes vm_offset_t off; 19463012Sdes int s = splbio(); 19537535Sdesmore: 19663012Sdes if (!bmfreeing && kvasfreecnt) { 19737535Sdes bmfreeing = 1; 19863012Sdes for (i = 0; i < kvasfreecnt; i++) { 19937535Sdes for(off=0;off<kvaf[i].size;off+=NBPG) { 20037535Sdes pmap_kremove( kvaf[i].addr + off); 20137608Sdes } 20237608Sdes kmem_free_wakeup(io_map, kvaf[i].addr, 20337608Sdes kvaf[i].size); 20437535Sdes } 20563012Sdes kvasfreecnt = 0; 20637535Sdes bmfreeing = 0; 20763012Sdes if( bmwait) { 20863012Sdes bmwait = 0; 20963012Sdes wakeup( (caddr_t) io_map); 21037535Sdes } 21137535Sdes } 21237608Sdes 21337608Sdes if( size == 0) { 21437608Sdes splx(s); 21537535Sdes return NULL; 21663012Sdes } 21737535Sdes 21863012Sdes if ((kva = kmem_alloc_pageable(io_map, size)) == 0) { 21963012Sdes if( !waitok) { 22063012Sdes splx(s); 22163012Sdes return NULL; 22263012Sdes } 22363012Sdes bmwait = 1; 22437535Sdes tsleep((caddr_t) io_map, PRIBIO, "bmwait", 0); 22563012Sdes goto more; 22637535Sdes } 22737535Sdes splx(s); 22837608Sdes return kva; 22963012Sdes} 23037608Sdes 23163012Sdes/* 23263012Sdes * same as vm_bounce_kva -- but really allocate (but takes pages as arg) 23337535Sdes */ 23463012Sdesvm_offset_t 23563012Sdesvm_bounce_kva_alloc(count) 23663012Sdesint count; 23763012Sdes{ 23863012Sdes int i; 23963012Sdes vm_offset_t kva; 24063012Sdes vm_offset_t pa; 24163012Sdes if( bouncepages == 0) { 24263012Sdes kva = (vm_offset_t) malloc(count*NBPG, M_TEMP, M_WAITOK); 24363012Sdes return kva; 24463012Sdes } 24563012Sdes kva = vm_bounce_kva(count*NBPG, 1); 24663012Sdes for(i=0;i<count;i++) { 24763012Sdes pa = vm_bounce_page_find(1); 24863012Sdes pmap_kenter(kva + i * NBPG, pa); 24963012Sdes } 25063012Sdes return kva; 25163012Sdes} 25263012Sdes 25363012Sdes/* 25463012Sdes * same as vm_bounce_kva_free -- but really free 25563012Sdes */ 25663012Sdesvoid 25763012Sdesvm_bounce_kva_alloc_free(kva, count) 25863012Sdes vm_offset_t kva; 25963012Sdes int count; 26063012Sdes{ 26163012Sdes int i; 26263012Sdes vm_offset_t pa; 26363012Sdes if( bouncepages == 0) { 26463012Sdes free((caddr_t) kva, M_TEMP); 26563012Sdes return; 26663012Sdes } 26763012Sdes for(i = 0; i < count; i++) { 26863012Sdes pa = pmap_kextract(kva + i * NBPG); 26963012Sdes vm_bounce_page_free(pa, 1); 27063012Sdes } 27163012Sdes vm_bounce_kva_free(kva, count*NBPG, 0); 27263012Sdes} 27363012Sdes 27463012Sdes/* 27563012Sdes * do the things necessary to the struct buf to implement 27663012Sdes * bounce buffers... inserted before the disk sort 27763012Sdes */ 27863012Sdesvoid 27963012Sdesvm_bounce_alloc(bp) 28063012Sdes struct buf *bp; 28163012Sdes{ 28263012Sdes int countvmpg; 28363012Sdes vm_offset_t vastart, vaend; 28463012Sdes vm_offset_t vapstart, vapend; 28563012Sdes vm_offset_t va, kva; 28663012Sdes vm_offset_t pa; 28763012Sdes int dobounceflag = 0; 28863012Sdes int i; 28963012Sdes 29063012Sdes if (bouncepages == 0) 29163012Sdes return; 29263012Sdes 29363012Sdes if (bp->b_flags & B_BOUNCE) { 29463012Sdes printf("vm_bounce_alloc: called recursively???\n"); 29563012Sdes return; 29663012Sdes } 29763012Sdes 29863012Sdes if (bp->b_bufsize < bp->b_bcount) { 29963012Sdes printf( 30063012Sdes "vm_bounce_alloc: b_bufsize(0x%lx) < b_bcount(0x%lx) !!\n", 30163012Sdes bp->b_bufsize, bp->b_bcount); 30263012Sdes panic("vm_bounce_alloc"); 30363012Sdes } 30463012Sdes 30563012Sdes/* 30663012Sdes * This is not really necessary 30763012Sdes * if( bp->b_bufsize != bp->b_bcount) { 30863012Sdes * printf("size: %d, count: %d\n", bp->b_bufsize, bp->b_bcount); 30963012Sdes * } 31063012Sdes */ 31163012Sdes 31263012Sdes 31363012Sdes vastart = (vm_offset_t) bp->b_data; 31463012Sdes vaend = (vm_offset_t) bp->b_data + bp->b_bufsize; 31563012Sdes 31663012Sdes vapstart = i386_trunc_page(vastart); 31763012Sdes vapend = i386_round_page(vaend); 31863012Sdes countvmpg = (vapend - vapstart) / NBPG; 31963012Sdes 32063012Sdes/* 32163012Sdes * if any page is above 16MB, then go into bounce-buffer mode 32263012Sdes */ 32363012Sdes va = vapstart; 32463012Sdes for (i = 0; i < countvmpg; i++) { 32537535Sdes pa = pmap_kextract(va); 32663012Sdes if (pa >= SIXTEENMEG) 32763012Sdes ++dobounceflag; 32863012Sdes if( pa == 0) 32963012Sdes panic("vm_bounce_alloc: Unmapped page"); 33063012Sdes va += NBPG; 33137535Sdes } 33263012Sdes if (dobounceflag == 0) 33363012Sdes return; 33463012Sdes 33563012Sdes if (bouncepages < dobounceflag) 33663012Sdes panic("Not enough bounce buffers!!!"); 33763012Sdes 33863012Sdes/* 33963012Sdes * allocate a replacement kva for b_addr 34063012Sdes */ 34163012Sdes kva = vm_bounce_kva(countvmpg*NBPG, 1); 34237535Sdes#if 0 34337535Sdes printf("%s: vapstart: %x, vapend: %x, countvmpg: %d, kva: %x ", 34437608Sdes (bp->b_flags & B_READ) ? "read":"write", 34563012Sdes vapstart, vapend, countvmpg, kva); 34663012Sdes#endif 34763012Sdes va = vapstart; 34863012Sdes for (i = 0; i < countvmpg; i++) { 34963012Sdes pa = pmap_kextract(va); 35063012Sdes if (pa >= SIXTEENMEG) { 35163012Sdes /* 35263012Sdes * allocate a replacement page 35363012Sdes */ 35463012Sdes vm_offset_t bpa = vm_bounce_page_find(1); 35563012Sdes pmap_kenter(kva + (NBPG * i), bpa); 35663012Sdes#if 0 35763012Sdes printf("r(%d): (%x,%x,%x) ", i, va, pa, bpa); 35863012Sdes#endif 35963012Sdes /* 36063012Sdes * if we are writing, the copy the data into the page 36163012Sdes */ 36263012Sdes if ((bp->b_flags & B_READ) == 0) { 36363012Sdes bcopy((caddr_t) va, (caddr_t) kva + (NBPG * i), NBPG); 36463012Sdes } 36563012Sdes } else { 36663012Sdes /* 36763012Sdes * use original page 36863012Sdes */ 36963012Sdes pmap_kenter(kva + (NBPG * i), pa); 37063012Sdes } 37163012Sdes va += NBPG; 37263012Sdes } 37363012Sdes 37463012Sdes/* 37563012Sdes * flag the buffer as being bounced 37663012Sdes */ 37763012Sdes bp->b_flags |= B_BOUNCE; 37863012Sdes/* 37963012Sdes * save the original buffer kva 38063012Sdes */ 38163012Sdes bp->b_savekva = bp->b_data; 38263012Sdes/* 38363012Sdes * put our new kva into the buffer (offset by original offset) 38463012Sdes */ 38563012Sdes bp->b_data = (caddr_t) (((vm_offset_t) kva) | 38663012Sdes ((vm_offset_t) bp->b_savekva & (NBPG - 1))); 38763012Sdes#if 0 38863012Sdes printf("b_savekva: %x, newva: %x\n", bp->b_savekva, bp->b_data); 38963012Sdes#endif 39063012Sdes return; 39163012Sdes} 39263012Sdes 39363012Sdes/* 39463012Sdes * hook into biodone to free bounce buffer 39563012Sdes */ 39663012Sdesvoid 39763012Sdesvm_bounce_free(bp) 39863012Sdes struct buf *bp; 39963012Sdes{ 40063012Sdes int i; 40163012Sdes vm_offset_t origkva, bouncekva, bouncekvaend; 40263012Sdes 40363012Sdes/* 40463012Sdes * if this isn't a bounced buffer, then just return 40563012Sdes */ 40663012Sdes if ((bp->b_flags & B_BOUNCE) == 0) 40763012Sdes return; 40863012Sdes 40963012Sdes/* 41063012Sdes * This check is not necessary 41163012Sdes * if (bp->b_bufsize != bp->b_bcount) { 41263012Sdes * printf("vm_bounce_free: b_bufsize=%d, b_bcount=%d\n", 41363012Sdes * bp->b_bufsize, bp->b_bcount); 41463012Sdes * } 41563012Sdes */ 41663012Sdes 41763012Sdes origkva = (vm_offset_t) bp->b_savekva; 41863012Sdes bouncekva = (vm_offset_t) bp->b_data; 41963012Sdes/* 42063012Sdes printf("free: %d ", bp->b_bufsize); 42163012Sdes*/ 42263012Sdes 42363012Sdes/* 42463012Sdes * check every page in the kva space for b_addr 42563012Sdes */ 42663012Sdes for (i = 0; i < bp->b_bufsize; ) { 42763012Sdes vm_offset_t mybouncepa; 42863012Sdes vm_offset_t copycount; 42963012Sdes 43063012Sdes copycount = i386_round_page(bouncekva + 1) - bouncekva; 43163012Sdes mybouncepa = pmap_kextract(i386_trunc_page(bouncekva)); 43263012Sdes 43363012Sdes/* 43463012Sdes * if this is a bounced pa, then process as one 43563012Sdes */ 43663012Sdes if ( mybouncepa != pmap_kextract( i386_trunc_page( origkva))) { 43763012Sdes vm_offset_t tocopy = copycount; 43863012Sdes if (i + tocopy > bp->b_bufsize) 43963012Sdes tocopy = bp->b_bufsize - i; 44063012Sdes/* 44163012Sdes * if this is a read, then copy from bounce buffer into original buffer 44263012Sdes */ 44363012Sdes if (bp->b_flags & B_READ) 44463012Sdes bcopy((caddr_t) bouncekva, (caddr_t) origkva, tocopy); 44563012Sdes/* 44637608Sdes * free the bounce allocation 44737608Sdes */ 44862965Sdes 44962965Sdes/* 45037608Sdes printf("(kva: %x, pa: %x)", bouncekva, mybouncepa); 45137608Sdes*/ 45237608Sdes vm_bounce_page_free(mybouncepa, 1); 45337608Sdes } 45437608Sdes 45562965Sdes origkva += copycount; 45662965Sdes bouncekva += copycount; 45762965Sdes i += copycount; 45862965Sdes } 45962965Sdes 46062965Sdes/* 46162965Sdes printf("\n"); 46262965Sdes*/ 46362965Sdes/* 46437608Sdes * add the old kva into the "to free" list 46537608Sdes */ 46637608Sdes 46737608Sdes bouncekva= i386_trunc_page((vm_offset_t) bp->b_data); 46837608Sdes bouncekvaend= i386_round_page((vm_offset_t)bp->b_data + bp->b_bufsize); 46937608Sdes 47037608Sdes/* 47137608Sdes printf("freeva: %d\n", (bouncekvaend - bouncekva) / NBPG); 47237608Sdes*/ 47337608Sdes vm_bounce_kva_free( bouncekva, (bouncekvaend - bouncekva), 0); 47437608Sdes bp->b_data = bp->b_savekva; 47537608Sdes bp->b_savekva = 0; 47637608Sdes bp->b_flags &= ~B_BOUNCE; 47737608Sdes 47837608Sdes return; 47937608Sdes} 48037608Sdes 48137608Sdes 48237608Sdes/* 48337608Sdes * init the bounce buffer system 48437608Sdes */ 48537608Sdesvoid 48637608Sdesvm_bounce_init() 48737608Sdes{ 48837608Sdes int i; 48937608Sdes 49037608Sdes kvasfreecnt = 0; 49137608Sdes 49237608Sdes if (bouncepages == 0) 49337608Sdes return; 49437608Sdes 49537608Sdes bounceallocarraysize = (bouncepages + BITS_IN_UNSIGNED - 1) / BITS_IN_UNSIGNED; 49637608Sdes bounceallocarray = malloc(bounceallocarraysize * sizeof(unsigned), M_TEMP, M_NOWAIT); 49737608Sdes 49862965Sdes if (!bounceallocarray) 49937608Sdes panic("Cannot allocate bounce resource array"); 50037608Sdes 50137608Sdes bouncepa = malloc(bouncepages * sizeof(vm_offset_t), M_TEMP, M_NOWAIT); 50237608Sdes if (!bouncepa) 50337608Sdes panic("Cannot allocate physical memory array"); 50462965Sdes 50563012Sdes for(i=0;i<bounceallocarraysize;i++) { 50637608Sdes bounceallocarray[i] = 0xffffffff; 50762965Sdes } 50862965Sdes 50937608Sdes for(i=0;i<bouncepages;i++) { 51062965Sdes vm_offset_t pa; 51162965Sdes if( (pa = pmap_kextract((vm_offset_t) bouncememory + i * NBPG)) >= SIXTEENMEG) 51262965Sdes panic("bounce memory out of range"); 51362965Sdes if( pa == 0) 51462965Sdes panic("bounce memory not resident"); 51562965Sdes bouncepa[i] = pa; 51663012Sdes bounceallocarray[i/(8*sizeof(int))] &= ~(1<<(i%(8*sizeof(int)))); 51762965Sdes } 51862965Sdes bouncefree = bouncepages; 51962965Sdes 52062965Sdes} 52162965Sdes#endif /* BOUNCE_BUFFERS */ 52262965Sdes/* 52362965Sdes * quick version of vm_fault 52462965Sdes */ 52563012Sdes 52662965Sdesvoid 52762965Sdesvm_fault_quick( v, prot) 52862965Sdes vm_offset_t v; 52962965Sdes int prot; 53062965Sdes{ 53162965Sdes if (prot & VM_PROT_WRITE) 53262965Sdes subyte((char *)v, fubyte((char *)v)); 53362965Sdes else 53462965Sdes (void) fubyte((char *)v); 53562965Sdes} 53662965Sdes 53762965Sdes 53862965Sdes/* 53962965Sdes * Finish a fork operation, with process p2 nearly set up. 54062965Sdes * Copy and update the kernel stack and pcb, making the child 54162965Sdes * ready to run, and marking it so that it can return differently 54263012Sdes * than the parent. Returns 1 in the child process, 0 in the parent. 54362965Sdes * We currently double-map the user area so that the stack is at the same 54462965Sdes * address in each process; in the future we will probably relocate 54562811Sdes * the frame pointers on the stack after copying. 54662965Sdes */ 54737608Sdesint 54837608Sdescpu_fork(p1, p2) 54963012Sdes register struct proc *p1, *p2; 55063012Sdes{ 55163012Sdes register struct user *up = p2->p_addr; 55263012Sdes int offset; 55363012Sdes 55437608Sdes /* 55563012Sdes * Copy pcb and stack from proc p1 to p2. 55637608Sdes * We do this as cheaply as possible, copying only the active 55763012Sdes * part of the stack. The stack and pcb need to agree; 55863012Sdes * this is tricky, as the final pcb is constructed by savectx, 55937535Sdes * but its frame isn't yet on the stack when the stack is copied. 56063012Sdes * swtch compensates for this when the child eventually runs. 56163012Sdes * This should be done differently, with a single call 56263012Sdes * that copies and updates the pcb+stack, 56363012Sdes * replacing the bcopy and savectx. 56463012Sdes */ 56560737Sume p2->p_addr->u_pcb = p1->p_addr->u_pcb; 56663012Sdes offset = mvesp() - (int)kstack; 56763012Sdes bcopy((caddr_t)kstack + offset, (caddr_t)p2->p_addr + offset, 56863012Sdes (unsigned) ctob(UPAGES) - offset); 56963012Sdes p2->p_md.md_regs = p1->p_md.md_regs; 57063012Sdes 57163012Sdes pmap_activate(&p2->p_vmspace->vm_pmap, &up->u_pcb); 57263012Sdes 57363012Sdes /* 57463012Sdes * 57563012Sdes * Arrange for a non-local goto when the new process 57663012Sdes * is started, to resume here, returning nonzero from setjmp. 57763012Sdes */ 57863012Sdes if (savectx(&up->u_pcb, 1)) { 57963012Sdes /* 58063012Sdes * Return 1 in child. 58163012Sdes */ 58263012Sdes return (1); 58363012Sdes } 58463012Sdes return (0); 58563012Sdes} 58663012Sdes 58763012Sdesvoid 58863012Sdescpu_exit(p) 58963012Sdes register struct proc *p; 59063012Sdes{ 59163012Sdes 59263012Sdes#if NNPX > 0 59363012Sdes npxexit(p); 59463012Sdes#endif /* NNPX */ 59563012Sdes cnt.v_swtch++; 59663012Sdes cpu_switch(p); 59763012Sdes panic("cpu_exit"); 59863012Sdes} 59963012Sdes 60063012Sdesvoid 60163012Sdescpu_wait(p) struct proc *p; { 60263012Sdes/* extern vm_map_t upages_map; */ 60363012Sdes 60463012Sdes /* drop per-process resources */ 60563012Sdes pmap_remove(vm_map_pmap(u_map), (vm_offset_t) p->p_addr, 60663012Sdes ((vm_offset_t) p->p_addr) + ctob(UPAGES)); 60763012Sdes kmem_free(u_map, (vm_offset_t)p->p_addr, ctob(UPAGES)); 60863012Sdes vmspace_free(p->p_vmspace); 60963012Sdes} 61063012Sdes 61163012Sdes/* 61263012Sdes * Dump the machine specific header information at the start of a core dump. 61363012Sdes */ 61463012Sdesint 61563012Sdescpu_coredump(p, vp, cred) 61663012Sdes struct proc *p; 61763012Sdes struct vnode *vp; 61863012Sdes struct ucred *cred; 61963012Sdes{ 62063012Sdes 62163012Sdes return (vn_rdwr(UIO_WRITE, vp, (caddr_t) p->p_addr, ctob(UPAGES), 62263012Sdes (off_t)0, UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, (int *)NULL, 62363012Sdes p)); 62463012Sdes} 62563012Sdes 62663012Sdes/* 62763012Sdes * Set a red zone in the kernel stack after the u. area. 62863012Sdes */ 62963012Sdesvoid 63063012Sdessetredzone(pte, vaddr) 63163012Sdes u_short *pte; 63263012Sdes caddr_t vaddr; 63363012Sdes{ 63463012Sdes/* eventually do this by setting up an expand-down stack segment 63563012Sdes for ss0: selector, allowing stack access down to top of u. 63663012Sdes this means though that protection violations need to be handled 63763012Sdes thru a double fault exception that must do an integral task 63863012Sdes switch to a known good context, within which a dump can be 63963012Sdes taken. a sensible scheme might be to save the initial context 64063012Sdes used by sched (that has physical memory mapped 1:1 at bottom) 64163012Sdes and take the dump while still in mapped mode */ 64263012Sdes} 64363012Sdes 64463012Sdes/* 64563012Sdes * Move pages from one kernel virtual address to another. 64663012Sdes * Both addresses are assumed to reside in the Sysmap, 64763012Sdes * and size must be a multiple of CLSIZE. 64863012Sdes */ 64963012Sdes 65063012Sdesvoid 65163012Sdespagemove(from, to, size) 65263012Sdes register caddr_t from, to; 65363012Sdes int size; 65463012Sdes{ 65563012Sdes register vm_offset_t pa; 65663012Sdes 65763012Sdes if (size & CLOFSET) 65860737Sume panic("pagemove"); 65963012Sdes while (size > 0) { 66060737Sume pa = pmap_kextract((vm_offset_t)from); 66163012Sdes if (pa == 0) 66255544Sdes panic("pagemove 2"); 66355544Sdes if (pmap_kextract((vm_offset_t)to) != 0) 66463012Sdes panic("pagemove 3"); 66560737Sume pmap_kremove((vm_offset_t)from); 66663012Sdes pmap_kenter((vm_offset_t)to, pa); 66760737Sume from += PAGE_SIZE; 66841862Sdes to += PAGE_SIZE; 66937535Sdes size -= PAGE_SIZE; 67060189Sdes } 67160189Sdes} 67260189Sdes 67363012Sdes/* 67460587Sume * Convert kernel VA to physical address 67560587Sume */ 67660587Sumeu_long 67760587Sumekvtop(void *addr) 67860587Sume{ 67960189Sdes vm_offset_t va; 68060587Sume 68160587Sume va = pmap_kextract((vm_offset_t)addr); 68260587Sume if (va == 0) 68360587Sume panic("kvtop: zero page frame"); 68460189Sdes return((int)va); 68537535Sdes} 68663012Sdes 68763012Sdes/* 68863012Sdes * Map an IO request into kernel virtual address space. 68963012Sdes * 69063012Sdes * All requests are (re)mapped into kernel VA space. 69163012Sdes * Notice that we use b_bufsize for the size of the buffer 69263012Sdes * to be mapped. b_bcount might be modified by the driver. 69363012Sdes */ 69463012Sdesvoid 69563012Sdesvmapbuf(bp) 69663012Sdes register struct buf *bp; 69760189Sdes{ 69863012Sdes register int npf; 69963012Sdes register caddr_t addr; 70063012Sdes int off; 70163012Sdes vm_offset_t kva; 70237535Sdes vm_offset_t pa, lastv, v; 70337535Sdes 70463012Sdes if ((bp->b_flags & B_PHYS) == 0) 70560376Sdes panic("vmapbuf"); 70660376Sdes 70763012Sdes /* 70863012Sdes * this is the kva that is to be used for 70963012Sdes * the temporary kernel mapping 71060954Sdes */ 71160954Sdes kva = (vm_offset_t) bp->b_saveaddr; 71260954Sdes 71363012Sdes lastv = 0; 71460376Sdes for (addr = (caddr_t)trunc_page(bp->b_data); 71563012Sdes addr < bp->b_data + bp->b_bufsize; 71663012Sdes addr += PAGE_SIZE) { 71760376Sdes 71863012Sdes/* 71963012Sdes * make sure that the pde is valid and held 72063012Sdes */ 72163012Sdes v = trunc_page(((vm_offset_t)vtopte(addr))); 72263012Sdes if (v != lastv) { 72363012Sdes vm_fault_quick(v, VM_PROT_READ); 72463012Sdes pa = pmap_kextract( v); 72560737Sume vm_page_hold(PHYS_TO_VM_PAGE(pa)); 72660737Sume lastv = v; 72760737Sume } 72860737Sume 72963012Sdes/* 73063012Sdes * do the vm_fault if needed, do the copy-on-write thing when 73160376Sdes * reading stuff off device into memory. 73260737Sume */ 73363012Sdes vm_fault_quick(addr, 73463012Sdes (bp->b_flags&B_READ)?(VM_PROT_READ|VM_PROT_WRITE):VM_PROT_READ); 73563069Sdes pa = pmap_kextract((vm_offset_t) addr); 73663069Sdes/* 73763012Sdes * hold the data page 73863012Sdes */ 73963012Sdes vm_page_hold(PHYS_TO_VM_PAGE(pa)); 74063012Sdes } 74163012Sdes 74263069Sdes addr = bp->b_saveaddr = bp->b_data; 74363069Sdes off = (int)addr & PGOFSET; 74463069Sdes npf = btoc(round_page(bp->b_bufsize + off)); 74563069Sdes bp->b_data = (caddr_t) (kva + off); 74663012Sdes while (npf--) { 74763069Sdes pa = pmap_kextract((vm_offset_t)addr); 74863069Sdes if (pa == 0) 74963012Sdes panic("vmapbuf: null page frame"); 75063012Sdes pmap_kenter(kva, trunc_page(pa)); 75163012Sdes addr += PAGE_SIZE; 75263012Sdes kva += PAGE_SIZE; 75363012Sdes } 75463012Sdes} 75560737Sume 75663012Sdes/* 75763012Sdes * Free the io map PTEs associated with this IO operation. 75863012Sdes * We also invalidate the TLB entries and restore the original b_addr. 75963012Sdes */ 76060737Sumevoid 76137535Sdesvunmapbuf(bp) 76263012Sdes register struct buf *bp; 76363012Sdes{ 76463012Sdes register caddr_t addr; 76563012Sdes vm_offset_t v,lastv,pa; 76663012Sdes 76763012Sdes if ((bp->b_flags & B_PHYS) == 0) 76863012Sdes panic("vunmapbuf"); 76963012Sdes 77063012Sdes for (addr = (caddr_t)trunc_page((vm_offset_t) bp->b_data); 77163012Sdes addr < bp->b_data + bp->b_bufsize; 77263012Sdes addr += NBPG) 77337535Sdes pmap_kremove((vm_offset_t) addr); 77463012Sdes 77563012Sdes bp->b_data = bp->b_saveaddr; 77663012Sdes bp->b_saveaddr = NULL; 77763012Sdes 77863012Sdes/* 77963012Sdes * unhold the pde, and data pages 78063012Sdes */ 78163012Sdes lastv = 0; 78263012Sdes for (addr = (caddr_t)trunc_page((vm_offset_t) bp->b_data); 78363012Sdes addr < bp->b_data + bp->b_bufsize; 78463012Sdes addr += NBPG) { 78563012Sdes 78663012Sdes /* 78763012Sdes * release the data page 78863012Sdes */ 78963012Sdes pa = pmap_kextract((vm_offset_t) addr); 79063012Sdes vm_page_unhold(PHYS_TO_VM_PAGE(pa)); 79160376Sdes 79263012Sdes /* 79363012Sdes * and unhold the page table 79463012Sdes */ 79563012Sdes v = trunc_page(((vm_offset_t)vtopte(addr))); 79663012Sdes if (v != lastv) { 79763012Sdes pa = pmap_kextract(v); 79863012Sdes vm_page_unhold(PHYS_TO_VM_PAGE(pa)); 79960376Sdes lastv = v; 80063012Sdes } 80163012Sdes } 80263012Sdes} 80363012Sdes 80463012Sdes/* 80563012Sdes * Force reset the processor by invalidating the entire address space! 80663012Sdes */ 80763012Sdesvoid 80863012Sdescpu_reset() { 80963012Sdes 81063012Sdes /* 81163012Sdes * Attempt to do a CPU reset via the keyboard controller, 81263012Sdes * do not turn of the GateA20, as any machine that fails 81363012Sdes * to do the reset here would then end up in no man's land. 81463012Sdes */ 81563012Sdes outb(IO_KBD + 4, 0xFE); 81663012Sdes DELAY(500000); /* wait 0.5 sec to see if that did it */ 81763012Sdes printf("Keyboard reset did not work, attempting CPU shutdown\n"); 81863012Sdes DELAY(1000000); /* wait 1 sec for printf to complete */ 81963012Sdes 82063012Sdes /* force a shutdown by unmapping entire address space ! */ 82163012Sdes bzero((caddr_t) PTD, NBPG); 82263012Sdes 82363012Sdes /* "good night, sweet prince .... <THUNK!>" */ 82463012Sdes pmap_update(); 82563012Sdes /* NOTREACHED */ 82663012Sdes while(1); 82763012Sdes} 82863012Sdes 82963012Sdes/* 83063012Sdes * Grow the user stack to allow for 'sp'. This version grows the stack in 83163012Sdes * chunks of SGROWSIZ. 83263012Sdes */ 83363012Sdesint 83463012Sdesgrow(p, sp) 83563012Sdes struct proc *p; 83663012Sdes u_int sp; 83763012Sdes{ 83863012Sdes unsigned int nss; 83963012Sdes caddr_t v; 84063012Sdes struct vmspace *vm = p->p_vmspace; 84163012Sdes 84263012Sdes if ((caddr_t)sp <= vm->vm_maxsaddr || (unsigned)sp >= (unsigned)USRSTACK) 84363012Sdes return (1); 84463012Sdes 84563012Sdes nss = roundup(USRSTACK - (unsigned)sp, PAGE_SIZE); 84663012Sdes 84763012Sdes if (nss > p->p_rlimit[RLIMIT_STACK].rlim_cur) 84863012Sdes return (0); 84963012Sdes 85063012Sdes if (vm->vm_ssize && roundup(vm->vm_ssize << PAGE_SHIFT, 85163012Sdes SGROWSIZ) < nss) { 85263012Sdes int grow_amount; 85363012Sdes /* 85463012Sdes * If necessary, grow the VM that the stack occupies 85563012Sdes * to allow for the rlimit. This allows us to not have 85663012Sdes * to allocate all of the VM up-front in execve (which 85763012Sdes * is expensive). 85863012Sdes * Grow the VM by the amount requested rounded up to 85963012Sdes * the nearest SGROWSIZ to provide for some hysteresis. 86063012Sdes */ 86163012Sdes grow_amount = roundup((nss - (vm->vm_ssize << PAGE_SHIFT)), SGROWSIZ); 86263012Sdes v = (char *)USRSTACK - roundup(vm->vm_ssize << PAGE_SHIFT, 86363012Sdes SGROWSIZ) - grow_amount; 86463012Sdes /* 86563012Sdes * If there isn't enough room to extend by SGROWSIZ, then 86663069Sdes * just extend to the maximum size 86763069Sdes */ 86863012Sdes if (v < vm->vm_maxsaddr) { 86963012Sdes v = vm->vm_maxsaddr; 87063069Sdes grow_amount = MAXSSIZ - (vm->vm_ssize << PAGE_SHIFT); 87163069Sdes } 87263069Sdes if ((grow_amount == 0) || (vm_map_find(&vm->vm_map, NULL, 0, (vm_offset_t *)&v, 87363069Sdes grow_amount, FALSE) != KERN_SUCCESS)) { 87463069Sdes return (0); 87563069Sdes } 87663069Sdes vm->vm_ssize += grow_amount >> PAGE_SHIFT; 87763069Sdes } 87863069Sdes 87963012Sdes return (1); 88063069Sdes} 88163012Sdes