get rid of some old flags; TPF_GENERAL_ADDR means somebody is listening
[unix-history] / usr / src / sys / vm / vm_glue.c
index 898ebe4..82989d8 100644 (file)
@@ -7,7 +7,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)vm_glue.c   7.3 (Berkeley) %G%
+ *     @(#)vm_glue.c   7.9 (Berkeley) %G%
  *
  *
  * Copyright (c) 1987, 1990 Carnegie-Mellon University.
  *
  *
  * Copyright (c) 1987, 1990 Carnegie-Mellon University.
 
 int    avefree = 0;            /* XXX */
 unsigned maxdmap = MAXDSIZ;    /* XXX */
 
 int    avefree = 0;            /* XXX */
 unsigned maxdmap = MAXDSIZ;    /* XXX */
+int    readbuffers = 0;        /* XXX allow kgdb to read kernel buffer pool */
 
 kernacc(addr, len, rw)
        caddr_t addr;
        int len, rw;
 {
        boolean_t rv;
 
 kernacc(addr, len, rw)
        caddr_t addr;
        int len, rw;
 {
        boolean_t rv;
+       vm_offset_t saddr, eaddr;
        vm_prot_t prot = rw == B_READ ? VM_PROT_READ : VM_PROT_WRITE;
 
        vm_prot_t prot = rw == B_READ ? VM_PROT_READ : VM_PROT_WRITE;
 
-       rv = vm_map_check_protection(kernel_map, trunc_page(addr),
-                                    round_page(addr+len-1), prot);
+       saddr = trunc_page(addr);
+       eaddr = round_page(addr+len-1);
+       rv = vm_map_check_protection(kernel_map, saddr, eaddr, prot);
+       /*
+        * XXX there are still some things (e.g. the buffer cache) that
+        * are managed behind the VM system's back so even though an
+        * address is accessible in the mind of the VM system, there may
+        * not be physical pages where the VM thinks there is.  This can
+        * lead to bogus allocation of pages in the kernel address space
+        * or worse, inconsistencies at the pmap level.  We only worry
+        * about the buffer cache for now.
+        */
+       if (!readbuffers && rv && (eaddr > (vm_offset_t)buffers &&
+                  saddr < (vm_offset_t)buffers + MAXBSIZE * nbuf))
+               rv = FALSE;
        return(rv == TRUE);
 }
 
        return(rv == TRUE);
 }
 
@@ -74,7 +89,7 @@ useracc(addr, len, rw)
 
 #ifdef KGDB
 /*
 
 #ifdef KGDB
 /*
- * Change protections on kernel pages from addr to addr+size
+ * Change protections on kernel pages from addr to addr+len
  * (presumably so debugger can plant a breakpoint).
  * All addresses are assumed to reside in the Sysmap,
  */
  * (presumably so debugger can plant a breakpoint).
  * All addresses are assumed to reside in the Sysmap,
  */
@@ -109,14 +124,32 @@ vsunlock(addr, len, dirtied)
                        round_page(addr+len-1), TRUE);
 }
 
                        round_page(addr+len-1), TRUE);
 }
 
+/*
+ * Implement fork's actions on an address space.
+ * Here we arrange for the address space to be copied or referenced,
+ * allocate a user struct (pcb and kernel stack), then call the
+ * machine-dependent layer to fill those in and make the new process
+ * ready to run.
+ * NOTE: the kernel stack may be at a different location in the child
+ * process, and thus addresses of automatic variables may be invalid
+ * after cpu_fork returns in the child process.  We do nothing here
+ * after cpu_fork returns.
+ */
 vm_fork(p1, p2, isvfork)
        register struct proc *p1, *p2;
        int isvfork;
 {
        register struct user *up;
        vm_offset_t addr;
 vm_fork(p1, p2, isvfork)
        register struct proc *p1, *p2;
        int isvfork;
 {
        register struct user *up;
        vm_offset_t addr;
-       vm_size_t size;
 
 
+#ifdef i386
+       /*
+        * avoid copying any of the parent's pagetables or other per-process
+        * objects that reside in the map by marking all of them non-inheritable
+        */
+       (void)vm_map_inherit(&p1->p_vmspace->vm_map,
+               UPT_MIN_ADDRESS-UPAGES*NBPG, VM_MAX_ADDRESS, VM_INHERIT_NONE);
+#endif
        p2->p_vmspace = vmspace_fork(p1->p_vmspace);
 
 #ifdef SYSVSHM
        p2->p_vmspace = vmspace_fork(p1->p_vmspace);
 
 #ifdef SYSVSHM
@@ -125,49 +158,47 @@ vm_fork(p1, p2, isvfork)
 #endif
 
        /*
 #endif
 
        /*
-        * Allocate a wired-down (for now) u-area for the process
+        * Allocate a wired-down (for now) pcb and kernel stack for the process
         */
         */
-       size = round_page(ctob(UPAGES));
-       addr = kmem_alloc_pageable(kernel_map, size);
-       vm_map_pageable(kernel_map, addr, addr + size, FALSE);
-       p2->p_addr = (caddr_t)addr;
+       addr = kmem_alloc_pageable(kernel_map, ctob(UPAGES));
+       vm_map_pageable(kernel_map, addr, addr + ctob(UPAGES), FALSE);
        up = (struct user *)addr;
        up = (struct user *)addr;
+       p2->p_addr = up;
 
 
-       /*
-        * Update the current u-area and copy it to the new one
-        * THIS SHOULD BE DONE DIFFERENTLY, probably with a single
-        * machine-dependent call that copies and updates the pcb+stack,
-        * replacing the resume and savectx.
-        */
-       resume(pcbb(p1));
-       bcopy(p1->p_addr, p2->p_addr, size);
        /*
         * p_stats and p_sigacts currently point at fields
         * in the user struct but not at &u, instead at p_addr.
        /*
         * p_stats and p_sigacts currently point at fields
         * in the user struct but not at &u, instead at p_addr.
+        * Copy p_sigacts and parts of p_stats; zero the rest
+        * of p_stats (statistics).
         */
         */
-       p2->p_stats = &((struct user *)p2->p_addr)->u_stats;
-       p2->p_sigacts = &((struct user *)p2->p_addr)->u_sigacts;
-
-       /*
-        * Clear vm statistics of new process.
-        */
-       bzero((caddr_t)&up->u_stats.p_ru, sizeof (struct rusage));
-       bzero((caddr_t)&up->u_stats.p_cru, sizeof (struct rusage));
-
-       PMAP_ACTIVATE(&p2->p_vmspace->vm_pmap, (struct pcb *)p2->p_addr, 0);
-
+       p2->p_stats = &up->u_stats;
+       p2->p_sigacts = &up->u_sigacts;
+       up->u_sigacts = *p1->p_sigacts;
+       bzero(&up->u_stats.pstat_startzero,
+           (unsigned) ((caddr_t)&up->u_stats.pstat_endzero -
+           (caddr_t)&up->u_stats.pstat_startzero));
+       bcopy(&p1->p_stats->pstat_startcopy, &up->u_stats.pstat_startcopy,
+           ((caddr_t)&up->u_stats.pstat_endcopy -
+            (caddr_t)&up->u_stats.pstat_startcopy));
+
+#ifdef i386
+       { u_int addr = UPT_MIN_ADDRESS - UPAGES*NBPG; struct vm_map *vp;
+
+       vp = &p2->p_vmspace->vm_map;
+       (void)vm_map_pageable(vp, addr, 0xfe000000 - addr, TRUE);
+       (void)vm_deallocate(vp, addr, 0xfe000000 - addr);
+       (void)vm_allocate(vp, &addr, UPT_MAX_ADDRESS - addr, FALSE);
+       (void)vm_map_inherit(vp, addr, UPT_MAX_ADDRESS, VM_INHERIT_NONE);
+       }
+#endif
        /*
        /*
-        * Arrange for a non-local goto when the new process
-        * is started, to resume here, returning nonzero from setjmp.
+        * cpu_fork will copy and update the kernel stack and pcb,
+        * and make the child ready to run.  It marks the child
+        * so that it can return differently than the parent.
+        * It returns twice, once in the parent process and
+        * once in the child.
         */
         */
-       up->u_pcb.pcb_sswap = (int *)&u.u_ssave;
-       if (savectx(&up->u_ssave)) {
-               /*
-                * Return 1 in child.
-                */
-               return (1);
-       }
-       return (0);
+       return (cpu_fork(p1, p2));
 }
 
 /*
 }
 
 /*
@@ -190,7 +221,7 @@ vm_init_limits(p)
         p->p_rlimit[RLIMIT_DATA].rlim_cur = DFLDSIZ;
         p->p_rlimit[RLIMIT_DATA].rlim_max = MAXDSIZ;
        p->p_rlimit[RLIMIT_RSS].rlim_cur = p->p_rlimit[RLIMIT_RSS].rlim_max =
         p->p_rlimit[RLIMIT_DATA].rlim_cur = DFLDSIZ;
         p->p_rlimit[RLIMIT_DATA].rlim_max = MAXDSIZ;
        p->p_rlimit[RLIMIT_RSS].rlim_cur = p->p_rlimit[RLIMIT_RSS].rlim_max =
-               ptoa(vm_page_free_count);
+               ptoa(vm_stat.free_count);
 }
 
 #include "../vm/vm_pageout.h"
 }
 
 #include "../vm/vm_pageout.h"
@@ -256,12 +287,12 @@ noswap:
         */
        size = round_page(ctob(UPAGES));
        addr = (vm_offset_t) p->p_addr;
         */
        size = round_page(ctob(UPAGES));
        addr = (vm_offset_t) p->p_addr;
-       if (vm_page_free_count > atop(size)) {
+       if (vm_stat.free_count > atop(size)) {
 #ifdef DEBUG
                if (swapdebug & SDB_SWAPIN)
                        printf("swapin: pid %d(%s)@%x, pri %d free %d\n",
                               p->p_pid, p->p_comm, p->p_addr,
 #ifdef DEBUG
                if (swapdebug & SDB_SWAPIN)
                        printf("swapin: pid %d(%s)@%x, pri %d free %d\n",
                               p->p_pid, p->p_comm, p->p_addr,
-                              ppri, vm_page_free_count);
+                              ppri, vm_stat.free_count);
 #endif
                vm_map_pageable(kernel_map, addr, addr+size, FALSE);
                (void) splclock();
 #endif
                vm_map_pageable(kernel_map, addr, addr+size, FALSE);
                (void) splclock();
@@ -279,14 +310,14 @@ noswap:
 #ifdef DEBUG
        if (swapdebug & SDB_FOLLOW)
                printf("sched: no room for pid %d(%s), free %d\n",
 #ifdef DEBUG
        if (swapdebug & SDB_FOLLOW)
                printf("sched: no room for pid %d(%s), free %d\n",
-                      p->p_pid, p->p_comm, vm_page_free_count);
+                      p->p_pid, p->p_comm, vm_stat.free_count);
 #endif
        (void) splhigh();
        VM_WAIT;
        (void) spl0();
 #ifdef DEBUG
        if (swapdebug & SDB_FOLLOW)
 #endif
        (void) splhigh();
        VM_WAIT;
        (void) spl0();
 #ifdef DEBUG
        if (swapdebug & SDB_FOLLOW)
-               printf("sched: room again, free %d\n", vm_page_free_count);
+               printf("sched: room again, free %d\n", vm_stat.free_count);
 #endif
        goto loop;
 }
 #endif
        goto loop;
 }
@@ -346,7 +377,7 @@ swapout_threads()
         * it (UPAGES pages).
         */
        if (didswap == 0 &&
         * it (UPAGES pages).
         */
        if (didswap == 0 &&
-           vm_page_free_count <= atop(round_page(ctob(UPAGES)))) {
+           vm_stat.free_count <= atop(round_page(ctob(UPAGES)))) {
                if ((p = outp) == 0)
                        p = outp2;
 #ifdef DEBUG
                if ((p = outp) == 0)
                        p = outp2;
 #ifdef DEBUG
@@ -368,10 +399,30 @@ swapout(p)
        if (swapdebug & SDB_SWAPOUT)
                printf("swapout: pid %d(%s)@%x, stat %x pri %d free %d\n",
                       p->p_pid, p->p_comm, p->p_addr, p->p_stat,
        if (swapdebug & SDB_SWAPOUT)
                printf("swapout: pid %d(%s)@%x, stat %x pri %d free %d\n",
                       p->p_pid, p->p_comm, p->p_addr, p->p_stat,
-                      p->p_slptime, vm_page_free_count);
+                      p->p_slptime, vm_stat.free_count);
 #endif
        size = round_page(ctob(UPAGES));
        addr = (vm_offset_t) p->p_addr;
 #endif
        size = round_page(ctob(UPAGES));
        addr = (vm_offset_t) p->p_addr;
+#ifdef hp300
+       /*
+        * Ugh!  u-area is double mapped to a fixed address behind the
+        * back of the VM system and accesses are usually through that
+        * address rather than the per-process address.  Hence reference
+        * and modify information are recorded at the fixed address and
+        * lost at context switch time.  We assume the u-struct and
+        * kernel stack are always accessed/modified and force it to be so.
+        */
+       {
+               register int i;
+               volatile long tmp;
+
+               for (i = 0; i < UPAGES; i++) {
+                       tmp = *(long *)addr; *(long *)addr = tmp;
+                       addr += NBPG;
+               }
+               addr = (vm_offset_t) p->p_addr;
+       }
+#endif
        vm_map_pageable(kernel_map, addr, addr+size, TRUE);
        pmap_collect(vm_map_pmap(&p->p_vmspace->vm_map));
        (void) splhigh();
        vm_map_pageable(kernel_map, addr, addr+size, TRUE);
        pmap_collect(vm_map_pmap(&p->p_vmspace->vm_map));
        (void) splhigh();
@@ -445,14 +496,12 @@ iprintf(a, b, c, d, e, f, g, h)
 {
        register int i;
 
 {
        register int i;
 
-       for (i = indent; i > 0; ) {
-               if (i >= 8) {
-                       putchar('\t', 1, (caddr_t)0);
-                       i -= 8;
-               } else {
-                       putchar(' ', 1, (caddr_t)0);
-                       i--;
-               }
+       i = indent;
+       while (i >= 8) {
+               printf("\t");
+               i -= 8;
        }
        }
+       for (; i > 0; --i)
+               printf(" ");
        printf(a, b, c, d, e, f, g, h);
 }
        printf(a, b, c, d, e, f, g, h);
 }