1df8bae1dSRodney W. Grimes /* 2df8bae1dSRodney W. Grimes * Copyright (c) 1987, 1991, 1993 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * 5df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 6df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 7df8bae1dSRodney W. Grimes * are met: 8df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 9df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 10df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 11df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 12df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 13df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 14df8bae1dSRodney W. Grimes * must display the following acknowledgement: 15df8bae1dSRodney W. Grimes * This product includes software developed by the University of 16df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 17df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 18df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 19df8bae1dSRodney W. Grimes * without specific prior written permission. 20df8bae1dSRodney W. Grimes * 21df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31df8bae1dSRodney W. Grimes * SUCH DAMAGE. 32df8bae1dSRodney W. Grimes * 33df8bae1dSRodney W. Grimes * @(#)kern_malloc.c 8.3 (Berkeley) 1/4/94 34efeaf95aSDavid Greenman * $Id: kern_malloc.c,v 1.15 1995/12/02 17:10:34 bde Exp $ 35df8bae1dSRodney W. Grimes */ 36df8bae1dSRodney W. Grimes 37df8bae1dSRodney W. Grimes #include <sys/param.h> 3826f9a767SRodney W. Grimes #include <sys/systm.h> 39df8bae1dSRodney W. Grimes #include <sys/proc.h> 40df8bae1dSRodney W. Grimes #include <sys/kernel.h> 41df8bae1dSRodney W. Grimes #include <sys/malloc.h> 42efeaf95aSDavid Greenman #include <sys/vmmeter.h> 43df8bae1dSRodney W. Grimes 44df8bae1dSRodney W. Grimes #include <vm/vm.h> 45efeaf95aSDavid Greenman #include <vm/vm_param.h> 46df8bae1dSRodney W. Grimes #include <vm/vm_kern.h> 47efeaf95aSDavid Greenman #include <vm/vm_extern.h> 48df8bae1dSRodney W. Grimes 494590fd3aSDavid Greenman static void kmeminit __P((void *)); 502b14f991SJulian Elischer SYSINIT(kmem, SI_SUB_KMEM, SI_ORDER_FIRST, kmeminit, NULL) 512b14f991SJulian Elischer 52df8bae1dSRodney W. Grimes struct kmembuckets bucket[MINBUCKET + 16]; 53df8bae1dSRodney W. Grimes struct kmemstats kmemstats[M_LAST]; 54df8bae1dSRodney W. Grimes struct kmemusage *kmemusage; 55df8bae1dSRodney W. Grimes char *kmembase, *kmemlimit; 56df8bae1dSRodney W. Grimes char *memname[] = INITKMEMNAMES; 57df8bae1dSRodney W. Grimes 58df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 59df8bae1dSRodney W. Grimes /* 60df8bae1dSRodney W. Grimes * This structure provides a set of masks to catch unaligned frees. 61df8bae1dSRodney W. Grimes */ 62df8bae1dSRodney W. Grimes long addrmask[] = { 0, 63df8bae1dSRodney W. Grimes 0x00000001, 0x00000003, 0x00000007, 0x0000000f, 64df8bae1dSRodney W. Grimes 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 65df8bae1dSRodney W. Grimes 0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff, 66df8bae1dSRodney W. Grimes 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff, 67df8bae1dSRodney W. Grimes }; 68df8bae1dSRodney W. Grimes 69df8bae1dSRodney W. Grimes /* 70df8bae1dSRodney W. Grimes * The WEIRD_ADDR is used as known text to copy into free objects so 71df8bae1dSRodney W. Grimes * that modifications after frees can be detected. 72df8bae1dSRodney W. Grimes */ 735124d598SDavid Greenman #define WEIRD_ADDR 0xdeadc0de 745124d598SDavid Greenman #define MAX_COPY 64 75df8bae1dSRodney W. Grimes 76df8bae1dSRodney W. Grimes /* 77df8bae1dSRodney W. Grimes * Normally the first word of the structure is used to hold the list 78df8bae1dSRodney W. Grimes * pointer for free objects. However, when running with diagnostics, 79df8bae1dSRodney W. Grimes * we use the third and fourth fields, so as to catch modifications 80df8bae1dSRodney W. Grimes * in the most commonly trashed first two words. 81df8bae1dSRodney W. Grimes */ 82df8bae1dSRodney W. Grimes struct freelist { 83df8bae1dSRodney W. Grimes long spare0; 84df8bae1dSRodney W. Grimes short type; 85df8bae1dSRodney W. Grimes long spare1; 86df8bae1dSRodney W. Grimes caddr_t next; 87df8bae1dSRodney W. Grimes }; 88df8bae1dSRodney W. Grimes #else /* !DIAGNOSTIC */ 89df8bae1dSRodney W. Grimes struct freelist { 90df8bae1dSRodney W. Grimes caddr_t next; 91df8bae1dSRodney W. Grimes }; 92df8bae1dSRodney W. Grimes #endif /* DIAGNOSTIC */ 93df8bae1dSRodney W. Grimes 94df8bae1dSRodney W. Grimes /* 95df8bae1dSRodney W. Grimes * Allocate a block of memory 96df8bae1dSRodney W. Grimes */ 97df8bae1dSRodney W. Grimes void * 98df8bae1dSRodney W. Grimes malloc(size, type, flags) 99df8bae1dSRodney W. Grimes unsigned long size; 100df8bae1dSRodney W. Grimes int type, flags; 101df8bae1dSRodney W. Grimes { 102df8bae1dSRodney W. Grimes register struct kmembuckets *kbp; 103df8bae1dSRodney W. Grimes register struct kmemusage *kup; 104df8bae1dSRodney W. Grimes register struct freelist *freep; 105df8bae1dSRodney W. Grimes long indx, npg, allocsize; 106df8bae1dSRodney W. Grimes int s; 107df8bae1dSRodney W. Grimes caddr_t va, cp, savedlist; 108df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 109df8bae1dSRodney W. Grimes long *end, *lp; 110df8bae1dSRodney W. Grimes int copysize; 111df8bae1dSRodney W. Grimes char *savedtype; 112df8bae1dSRodney W. Grimes #endif 113df8bae1dSRodney W. Grimes #ifdef KMEMSTATS 114df8bae1dSRodney W. Grimes register struct kmemstats *ksp = &kmemstats[type]; 115df8bae1dSRodney W. Grimes 116df8bae1dSRodney W. Grimes if (((unsigned long)type) > M_LAST) 117df8bae1dSRodney W. Grimes panic("malloc - bogus type"); 118df8bae1dSRodney W. Grimes #endif 119df8bae1dSRodney W. Grimes indx = BUCKETINDX(size); 120df8bae1dSRodney W. Grimes kbp = &bucket[indx]; 121763424fcSDavid Greenman s = splhigh(); 122df8bae1dSRodney W. Grimes #ifdef KMEMSTATS 123df8bae1dSRodney W. Grimes while (ksp->ks_memuse >= ksp->ks_limit) { 124df8bae1dSRodney W. Grimes if (flags & M_NOWAIT) { 125df8bae1dSRodney W. Grimes splx(s); 126df8bae1dSRodney W. Grimes return ((void *) NULL); 127df8bae1dSRodney W. Grimes } 128df8bae1dSRodney W. Grimes if (ksp->ks_limblocks < 65535) 129df8bae1dSRodney W. Grimes ksp->ks_limblocks++; 130df8bae1dSRodney W. Grimes tsleep((caddr_t)ksp, PSWP+2, memname[type], 0); 131df8bae1dSRodney W. Grimes } 132df8bae1dSRodney W. Grimes ksp->ks_size |= 1 << indx; 133df8bae1dSRodney W. Grimes #endif 134df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 135df8bae1dSRodney W. Grimes copysize = 1 << indx < MAX_COPY ? 1 << indx : MAX_COPY; 136df8bae1dSRodney W. Grimes #endif 137df8bae1dSRodney W. Grimes if (kbp->kb_next == NULL) { 138df8bae1dSRodney W. Grimes kbp->kb_last = NULL; 139df8bae1dSRodney W. Grimes if (size > MAXALLOCSAVE) 140df8bae1dSRodney W. Grimes allocsize = roundup(size, CLBYTES); 141df8bae1dSRodney W. Grimes else 142df8bae1dSRodney W. Grimes allocsize = 1 << indx; 143df8bae1dSRodney W. Grimes npg = clrnd(btoc(allocsize)); 1449f518539SDavid Greenman va = (caddr_t) kmem_malloc(kmem_map, (vm_size_t)ctob(npg), flags); 145df8bae1dSRodney W. Grimes if (va == NULL) { 146df8bae1dSRodney W. Grimes splx(s); 147df8bae1dSRodney W. Grimes return ((void *) NULL); 148df8bae1dSRodney W. Grimes } 149df8bae1dSRodney W. Grimes #ifdef KMEMSTATS 150df8bae1dSRodney W. Grimes kbp->kb_total += kbp->kb_elmpercl; 151df8bae1dSRodney W. Grimes #endif 152df8bae1dSRodney W. Grimes kup = btokup(va); 153df8bae1dSRodney W. Grimes kup->ku_indx = indx; 154df8bae1dSRodney W. Grimes if (allocsize > MAXALLOCSAVE) { 155df8bae1dSRodney W. Grimes if (npg > 65535) 156df8bae1dSRodney W. Grimes panic("malloc: allocation too large"); 157df8bae1dSRodney W. Grimes kup->ku_pagecnt = npg; 158df8bae1dSRodney W. Grimes #ifdef KMEMSTATS 159df8bae1dSRodney W. Grimes ksp->ks_memuse += allocsize; 160df8bae1dSRodney W. Grimes #endif 161df8bae1dSRodney W. Grimes goto out; 162df8bae1dSRodney W. Grimes } 163df8bae1dSRodney W. Grimes #ifdef KMEMSTATS 164df8bae1dSRodney W. Grimes kup->ku_freecnt = kbp->kb_elmpercl; 165df8bae1dSRodney W. Grimes kbp->kb_totalfree += kbp->kb_elmpercl; 166df8bae1dSRodney W. Grimes #endif 167df8bae1dSRodney W. Grimes /* 168df8bae1dSRodney W. Grimes * Just in case we blocked while allocating memory, 169df8bae1dSRodney W. Grimes * and someone else also allocated memory for this 170df8bae1dSRodney W. Grimes * bucket, don't assume the list is still empty. 171df8bae1dSRodney W. Grimes */ 172df8bae1dSRodney W. Grimes savedlist = kbp->kb_next; 173df8bae1dSRodney W. Grimes kbp->kb_next = cp = va + (npg * NBPG) - allocsize; 174df8bae1dSRodney W. Grimes for (;;) { 175df8bae1dSRodney W. Grimes freep = (struct freelist *)cp; 176df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 177df8bae1dSRodney W. Grimes /* 178df8bae1dSRodney W. Grimes * Copy in known text to detect modification 179df8bae1dSRodney W. Grimes * after freeing. 180df8bae1dSRodney W. Grimes */ 181df8bae1dSRodney W. Grimes end = (long *)&cp[copysize]; 182df8bae1dSRodney W. Grimes for (lp = (long *)cp; lp < end; lp++) 183df8bae1dSRodney W. Grimes *lp = WEIRD_ADDR; 184df8bae1dSRodney W. Grimes freep->type = M_FREE; 185df8bae1dSRodney W. Grimes #endif /* DIAGNOSTIC */ 186df8bae1dSRodney W. Grimes if (cp <= va) 187df8bae1dSRodney W. Grimes break; 188df8bae1dSRodney W. Grimes cp -= allocsize; 189df8bae1dSRodney W. Grimes freep->next = cp; 190df8bae1dSRodney W. Grimes } 191df8bae1dSRodney W. Grimes freep->next = savedlist; 192df8bae1dSRodney W. Grimes if (kbp->kb_last == NULL) 193df8bae1dSRodney W. Grimes kbp->kb_last = (caddr_t)freep; 194df8bae1dSRodney W. Grimes } 195df8bae1dSRodney W. Grimes va = kbp->kb_next; 196df8bae1dSRodney W. Grimes kbp->kb_next = ((struct freelist *)va)->next; 197df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 198df8bae1dSRodney W. Grimes freep = (struct freelist *)va; 199df8bae1dSRodney W. Grimes savedtype = (unsigned)freep->type < M_LAST ? 200df8bae1dSRodney W. Grimes memname[freep->type] : "???"; 201df8bae1dSRodney W. Grimes if (kbp->kb_next && 202df8bae1dSRodney W. Grimes !kernacc(kbp->kb_next, sizeof(struct freelist), 0)) { 203797f2d22SPoul-Henning Kamp printf("%s of object %p size %ld %s %s (invalid addr %p)\n", 204df8bae1dSRodney W. Grimes "Data modified on freelist: word 2.5", va, size, 205df8bae1dSRodney W. Grimes "previous type", savedtype, kbp->kb_next); 206df8bae1dSRodney W. Grimes kbp->kb_next = NULL; 207df8bae1dSRodney W. Grimes } 208df8bae1dSRodney W. Grimes #if BYTE_ORDER == BIG_ENDIAN 209df8bae1dSRodney W. Grimes freep->type = WEIRD_ADDR >> 16; 210df8bae1dSRodney W. Grimes #endif 211df8bae1dSRodney W. Grimes #if BYTE_ORDER == LITTLE_ENDIAN 212df8bae1dSRodney W. Grimes freep->type = (short)WEIRD_ADDR; 213df8bae1dSRodney W. Grimes #endif 214df8bae1dSRodney W. Grimes if (((long)(&freep->next)) & 0x2) 215df8bae1dSRodney W. Grimes freep->next = (caddr_t)((WEIRD_ADDR >> 16)|(WEIRD_ADDR << 16)); 216df8bae1dSRodney W. Grimes else 217df8bae1dSRodney W. Grimes freep->next = (caddr_t)WEIRD_ADDR; 218df8bae1dSRodney W. Grimes end = (long *)&va[copysize]; 219df8bae1dSRodney W. Grimes for (lp = (long *)va; lp < end; lp++) { 220df8bae1dSRodney W. Grimes if (*lp == WEIRD_ADDR) 221df8bae1dSRodney W. Grimes continue; 222797f2d22SPoul-Henning Kamp printf("%s %d of object %p size %ld %s %s (0x%lx != 0x%x)\n", 223df8bae1dSRodney W. Grimes "Data modified on freelist: word", lp - (long *)va, 224df8bae1dSRodney W. Grimes va, size, "previous type", savedtype, *lp, WEIRD_ADDR); 225df8bae1dSRodney W. Grimes break; 226df8bae1dSRodney W. Grimes } 227df8bae1dSRodney W. Grimes freep->spare0 = 0; 228df8bae1dSRodney W. Grimes #endif /* DIAGNOSTIC */ 229df8bae1dSRodney W. Grimes #ifdef KMEMSTATS 230df8bae1dSRodney W. Grimes kup = btokup(va); 231df8bae1dSRodney W. Grimes if (kup->ku_indx != indx) 232df8bae1dSRodney W. Grimes panic("malloc: wrong bucket"); 233df8bae1dSRodney W. Grimes if (kup->ku_freecnt == 0) 234df8bae1dSRodney W. Grimes panic("malloc: lost data"); 235df8bae1dSRodney W. Grimes kup->ku_freecnt--; 236df8bae1dSRodney W. Grimes kbp->kb_totalfree--; 237df8bae1dSRodney W. Grimes ksp->ks_memuse += 1 << indx; 238df8bae1dSRodney W. Grimes out: 239df8bae1dSRodney W. Grimes kbp->kb_calls++; 240df8bae1dSRodney W. Grimes ksp->ks_inuse++; 241df8bae1dSRodney W. Grimes ksp->ks_calls++; 242df8bae1dSRodney W. Grimes if (ksp->ks_memuse > ksp->ks_maxused) 243df8bae1dSRodney W. Grimes ksp->ks_maxused = ksp->ks_memuse; 244df8bae1dSRodney W. Grimes #else 245df8bae1dSRodney W. Grimes out: 246df8bae1dSRodney W. Grimes #endif 247df8bae1dSRodney W. Grimes splx(s); 248df8bae1dSRodney W. Grimes return ((void *) va); 249df8bae1dSRodney W. Grimes } 250df8bae1dSRodney W. Grimes 251df8bae1dSRodney W. Grimes /* 252df8bae1dSRodney W. Grimes * Free a block of memory allocated by malloc. 253df8bae1dSRodney W. Grimes */ 254df8bae1dSRodney W. Grimes void 255df8bae1dSRodney W. Grimes free(addr, type) 256df8bae1dSRodney W. Grimes void *addr; 257df8bae1dSRodney W. Grimes int type; 258df8bae1dSRodney W. Grimes { 259df8bae1dSRodney W. Grimes register struct kmembuckets *kbp; 260df8bae1dSRodney W. Grimes register struct kmemusage *kup; 261df8bae1dSRodney W. Grimes register struct freelist *freep; 262df8bae1dSRodney W. Grimes long size; 263df8bae1dSRodney W. Grimes int s; 264df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 265df8bae1dSRodney W. Grimes caddr_t cp; 266df8bae1dSRodney W. Grimes long *end, *lp, alloc, copysize; 267df8bae1dSRodney W. Grimes #endif 268df8bae1dSRodney W. Grimes #ifdef KMEMSTATS 269df8bae1dSRodney W. Grimes register struct kmemstats *ksp = &kmemstats[type]; 270df8bae1dSRodney W. Grimes #endif 271df8bae1dSRodney W. Grimes 27217dda4c9SDavid Greenman #ifdef DIAGNOSTIC 27317dda4c9SDavid Greenman if ((char *)addr < kmembase || (char *)addr >= kmemlimit) { 274edf8a815SDavid Greenman panic("free: address 0x%x out of range", addr); 27517dda4c9SDavid Greenman } 27617dda4c9SDavid Greenman if ((u_long)type > M_LAST) { 277edf8a815SDavid Greenman panic("free: type %d out of range", type); 27817dda4c9SDavid Greenman } 27917dda4c9SDavid Greenman #endif 280df8bae1dSRodney W. Grimes kup = btokup(addr); 281df8bae1dSRodney W. Grimes size = 1 << kup->ku_indx; 282df8bae1dSRodney W. Grimes kbp = &bucket[kup->ku_indx]; 283763424fcSDavid Greenman s = splhigh(); 284df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 285df8bae1dSRodney W. Grimes /* 286df8bae1dSRodney W. Grimes * Check for returns of data that do not point to the 287df8bae1dSRodney W. Grimes * beginning of the allocation. 288df8bae1dSRodney W. Grimes */ 289df8bae1dSRodney W. Grimes if (size > NBPG * CLSIZE) 290df8bae1dSRodney W. Grimes alloc = addrmask[BUCKETINDX(NBPG * CLSIZE)]; 291df8bae1dSRodney W. Grimes else 292df8bae1dSRodney W. Grimes alloc = addrmask[kup->ku_indx]; 293df8bae1dSRodney W. Grimes if (((u_long)addr & alloc) != 0) 294edf8a815SDavid Greenman panic("free: unaligned addr 0x%x, size %d, type %s, mask %d", 295df8bae1dSRodney W. Grimes addr, size, memname[type], alloc); 296df8bae1dSRodney W. Grimes #endif /* DIAGNOSTIC */ 297df8bae1dSRodney W. Grimes if (size > MAXALLOCSAVE) { 298df8bae1dSRodney W. Grimes kmem_free(kmem_map, (vm_offset_t)addr, ctob(kup->ku_pagecnt)); 299df8bae1dSRodney W. Grimes #ifdef KMEMSTATS 300df8bae1dSRodney W. Grimes size = kup->ku_pagecnt << PGSHIFT; 301df8bae1dSRodney W. Grimes ksp->ks_memuse -= size; 302df8bae1dSRodney W. Grimes kup->ku_indx = 0; 303df8bae1dSRodney W. Grimes kup->ku_pagecnt = 0; 304df8bae1dSRodney W. Grimes if (ksp->ks_memuse + size >= ksp->ks_limit && 305df8bae1dSRodney W. Grimes ksp->ks_memuse < ksp->ks_limit) 306df8bae1dSRodney W. Grimes wakeup((caddr_t)ksp); 307df8bae1dSRodney W. Grimes ksp->ks_inuse--; 308df8bae1dSRodney W. Grimes kbp->kb_total -= 1; 309df8bae1dSRodney W. Grimes #endif 310df8bae1dSRodney W. Grimes splx(s); 311df8bae1dSRodney W. Grimes return; 312df8bae1dSRodney W. Grimes } 313df8bae1dSRodney W. Grimes freep = (struct freelist *)addr; 314df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 315df8bae1dSRodney W. Grimes /* 316df8bae1dSRodney W. Grimes * Check for multiple frees. Use a quick check to see if 317df8bae1dSRodney W. Grimes * it looks free before laboriously searching the freelist. 318df8bae1dSRodney W. Grimes */ 319df8bae1dSRodney W. Grimes if (freep->spare0 == WEIRD_ADDR) { 320df8bae1dSRodney W. Grimes for (cp = kbp->kb_next; cp; cp = *(caddr_t *)cp) { 321df8bae1dSRodney W. Grimes if (addr != cp) 322df8bae1dSRodney W. Grimes continue; 323797f2d22SPoul-Henning Kamp printf("multiply freed item %p\n", addr); 324df8bae1dSRodney W. Grimes panic("free: duplicated free"); 325df8bae1dSRodney W. Grimes } 326df8bae1dSRodney W. Grimes } 327df8bae1dSRodney W. Grimes /* 328df8bae1dSRodney W. Grimes * Copy in known text to detect modification after freeing 329df8bae1dSRodney W. Grimes * and to make it look free. Also, save the type being freed 330df8bae1dSRodney W. Grimes * so we can list likely culprit if modification is detected 331df8bae1dSRodney W. Grimes * when the object is reallocated. 332df8bae1dSRodney W. Grimes */ 333df8bae1dSRodney W. Grimes copysize = size < MAX_COPY ? size : MAX_COPY; 334df8bae1dSRodney W. Grimes end = (long *)&((caddr_t)addr)[copysize]; 335df8bae1dSRodney W. Grimes for (lp = (long *)addr; lp < end; lp++) 336df8bae1dSRodney W. Grimes *lp = WEIRD_ADDR; 337df8bae1dSRodney W. Grimes freep->type = type; 338df8bae1dSRodney W. Grimes #endif /* DIAGNOSTIC */ 339df8bae1dSRodney W. Grimes #ifdef KMEMSTATS 340df8bae1dSRodney W. Grimes kup->ku_freecnt++; 341df8bae1dSRodney W. Grimes if (kup->ku_freecnt >= kbp->kb_elmpercl) 342df8bae1dSRodney W. Grimes if (kup->ku_freecnt > kbp->kb_elmpercl) 343df8bae1dSRodney W. Grimes panic("free: multiple frees"); 344df8bae1dSRodney W. Grimes else if (kbp->kb_totalfree > kbp->kb_highwat) 345df8bae1dSRodney W. Grimes kbp->kb_couldfree++; 346df8bae1dSRodney W. Grimes kbp->kb_totalfree++; 347df8bae1dSRodney W. Grimes ksp->ks_memuse -= size; 348df8bae1dSRodney W. Grimes if (ksp->ks_memuse + size >= ksp->ks_limit && 349df8bae1dSRodney W. Grimes ksp->ks_memuse < ksp->ks_limit) 350df8bae1dSRodney W. Grimes wakeup((caddr_t)ksp); 351df8bae1dSRodney W. Grimes ksp->ks_inuse--; 352df8bae1dSRodney W. Grimes #endif 353df8bae1dSRodney W. Grimes if (kbp->kb_next == NULL) 354df8bae1dSRodney W. Grimes kbp->kb_next = addr; 355df8bae1dSRodney W. Grimes else 356df8bae1dSRodney W. Grimes ((struct freelist *)kbp->kb_last)->next = addr; 357df8bae1dSRodney W. Grimes freep->next = NULL; 358df8bae1dSRodney W. Grimes kbp->kb_last = addr; 359df8bae1dSRodney W. Grimes splx(s); 360df8bae1dSRodney W. Grimes } 361df8bae1dSRodney W. Grimes 362df8bae1dSRodney W. Grimes /* 363df8bae1dSRodney W. Grimes * Initialize the kernel memory allocator 364df8bae1dSRodney W. Grimes */ 3652b14f991SJulian Elischer /* ARGSUSED*/ 3662b14f991SJulian Elischer static void 367d841aaa7SBruce Evans kmeminit(dummy) 368d841aaa7SBruce Evans void *dummy; 369df8bae1dSRodney W. Grimes { 370df8bae1dSRodney W. Grimes register long indx; 371df8bae1dSRodney W. Grimes int npg; 372df8bae1dSRodney W. Grimes 373df8bae1dSRodney W. Grimes #if ((MAXALLOCSAVE & (MAXALLOCSAVE - 1)) != 0) 374df8bae1dSRodney W. Grimes ERROR!_kmeminit:_MAXALLOCSAVE_not_power_of_2 375df8bae1dSRodney W. Grimes #endif 376df8bae1dSRodney W. Grimes #if (MAXALLOCSAVE > MINALLOCSIZE * 32768) 377df8bae1dSRodney W. Grimes ERROR!_kmeminit:_MAXALLOCSAVE_too_big 378df8bae1dSRodney W. Grimes #endif 379df8bae1dSRodney W. Grimes #if (MAXALLOCSAVE < CLBYTES) 380df8bae1dSRodney W. Grimes ERROR!_kmeminit:_MAXALLOCSAVE_too_small 381df8bae1dSRodney W. Grimes #endif 382df8bae1dSRodney W. Grimes npg = VM_KMEM_SIZE/ NBPG; 3830d94caffSDavid Greenman if( npg > cnt.v_page_count) 3840d94caffSDavid Greenman npg = cnt.v_page_count; 3850d94caffSDavid Greenman 386df8bae1dSRodney W. Grimes kmemusage = (struct kmemusage *) kmem_alloc(kernel_map, 387df8bae1dSRodney W. Grimes (vm_size_t)(npg * sizeof(struct kmemusage))); 388df8bae1dSRodney W. Grimes kmem_map = kmem_suballoc(kernel_map, (vm_offset_t *)&kmembase, 389df8bae1dSRodney W. Grimes (vm_offset_t *)&kmemlimit, (vm_size_t)(npg * NBPG), FALSE); 390df8bae1dSRodney W. Grimes #ifdef KMEMSTATS 391df8bae1dSRodney W. Grimes for (indx = 0; indx < MINBUCKET + 16; indx++) { 392df8bae1dSRodney W. Grimes if (1 << indx >= CLBYTES) 393df8bae1dSRodney W. Grimes bucket[indx].kb_elmpercl = 1; 394df8bae1dSRodney W. Grimes else 395df8bae1dSRodney W. Grimes bucket[indx].kb_elmpercl = CLBYTES / (1 << indx); 396df8bae1dSRodney W. Grimes bucket[indx].kb_highwat = 5 * bucket[indx].kb_elmpercl; 397df8bae1dSRodney W. Grimes } 398df8bae1dSRodney W. Grimes for (indx = 0; indx < M_LAST; indx++) 399df8bae1dSRodney W. Grimes kmemstats[indx].ks_limit = npg * NBPG * 6 / 10; 400df8bae1dSRodney W. Grimes #endif 401df8bae1dSRodney W. Grimes } 402