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 34db669378SPeter Wemm * $Id: kern_malloc.c,v 1.48 1998/10/25 17:44:51 phk Exp $ 35df8bae1dSRodney W. Grimes */ 36df8bae1dSRodney W. Grimes 378a58a9f6SJohn Dyson #include "opt_vm.h" 388a58a9f6SJohn Dyson 39df8bae1dSRodney W. Grimes #include <sys/param.h> 4026f9a767SRodney W. Grimes #include <sys/systm.h> 41df8bae1dSRodney W. Grimes #include <sys/kernel.h> 42254c6cb3SPoul-Henning Kamp #define MALLOC_INSTANTIATE 43df8bae1dSRodney W. Grimes #include <sys/malloc.h> 4454e7152cSDavid Greenman #include <sys/mbuf.h> 45efeaf95aSDavid Greenman #include <sys/vmmeter.h> 463075778bSJohn Dyson #include <sys/lock.h> 47df8bae1dSRodney W. Grimes 48df8bae1dSRodney W. Grimes #include <vm/vm.h> 49efeaf95aSDavid Greenman #include <vm/vm_param.h> 50df8bae1dSRodney W. Grimes #include <vm/vm_kern.h> 51efeaf95aSDavid Greenman #include <vm/vm_extern.h> 523075778bSJohn Dyson #include <vm/pmap.h> 533075778bSJohn Dyson #include <vm/vm_map.h> 54df8bae1dSRodney W. Grimes 554590fd3aSDavid Greenman static void kmeminit __P((void *)); 562b14f991SJulian Elischer SYSINIT(kmem, SI_SUB_KMEM, SI_ORDER_FIRST, kmeminit, NULL) 572b14f991SJulian Elischer 58a1c995b6SPoul-Henning Kamp static MALLOC_DEFINE(M_FREE, "free", "should be on free list"); 59a1c995b6SPoul-Henning Kamp 60db669378SPeter Wemm static struct malloc_type *kmemstatistics; 61254c6cb3SPoul-Henning Kamp static struct kmembuckets bucket[MINBUCKET + 16]; 62254c6cb3SPoul-Henning Kamp static struct kmemusage *kmemusage; 63254c6cb3SPoul-Henning Kamp static char *kmembase; 64043a2f3bSBruce Evans static char *kmemlimit; 658a58a9f6SJohn Dyson static int vm_kmem_size; 66df8bae1dSRodney W. Grimes 67df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 68df8bae1dSRodney W. Grimes /* 69df8bae1dSRodney W. Grimes * This structure provides a set of masks to catch unaligned frees. 70df8bae1dSRodney W. Grimes */ 7187b6de2bSPoul-Henning Kamp static long addrmask[] = { 0, 72df8bae1dSRodney W. Grimes 0x00000001, 0x00000003, 0x00000007, 0x0000000f, 73df8bae1dSRodney W. Grimes 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 74df8bae1dSRodney W. Grimes 0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff, 75df8bae1dSRodney W. Grimes 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff, 76df8bae1dSRodney W. Grimes }; 77df8bae1dSRodney W. Grimes 78df8bae1dSRodney W. Grimes /* 79df8bae1dSRodney W. Grimes * The WEIRD_ADDR is used as known text to copy into free objects so 80df8bae1dSRodney W. Grimes * that modifications after frees can be detected. 81df8bae1dSRodney W. Grimes */ 825124d598SDavid Greenman #define WEIRD_ADDR 0xdeadc0de 835124d598SDavid Greenman #define MAX_COPY 64 84df8bae1dSRodney W. Grimes 85df8bae1dSRodney W. Grimes /* 86df8bae1dSRodney W. Grimes * Normally the first word of the structure is used to hold the list 87df8bae1dSRodney W. Grimes * pointer for free objects. However, when running with diagnostics, 88df8bae1dSRodney W. Grimes * we use the third and fourth fields, so as to catch modifications 89df8bae1dSRodney W. Grimes * in the most commonly trashed first two words. 90df8bae1dSRodney W. Grimes */ 91df8bae1dSRodney W. Grimes struct freelist { 92df8bae1dSRodney W. Grimes long spare0; 9360a513e9SPoul-Henning Kamp struct malloc_type *type; 94df8bae1dSRodney W. Grimes long spare1; 95df8bae1dSRodney W. Grimes caddr_t next; 96df8bae1dSRodney W. Grimes }; 97df8bae1dSRodney W. Grimes #else /* !DIAGNOSTIC */ 98df8bae1dSRodney W. Grimes struct freelist { 99df8bae1dSRodney W. Grimes caddr_t next; 100df8bae1dSRodney W. Grimes }; 101df8bae1dSRodney W. Grimes #endif /* DIAGNOSTIC */ 102df8bae1dSRodney W. Grimes 103df8bae1dSRodney W. Grimes /* 104df8bae1dSRodney W. Grimes * Allocate a block of memory 105df8bae1dSRodney W. Grimes */ 106df8bae1dSRodney W. Grimes void * 107df8bae1dSRodney W. Grimes malloc(size, type, flags) 108df8bae1dSRodney W. Grimes unsigned long size; 10960a513e9SPoul-Henning Kamp struct malloc_type *type; 110254c6cb3SPoul-Henning Kamp int flags; 111df8bae1dSRodney W. Grimes { 112df8bae1dSRodney W. Grimes register struct kmembuckets *kbp; 113df8bae1dSRodney W. Grimes register struct kmemusage *kup; 114df8bae1dSRodney W. Grimes register struct freelist *freep; 115df8bae1dSRodney W. Grimes long indx, npg, allocsize; 116df8bae1dSRodney W. Grimes int s; 117df8bae1dSRodney W. Grimes caddr_t va, cp, savedlist; 118df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 119df8bae1dSRodney W. Grimes long *end, *lp; 120df8bae1dSRodney W. Grimes int copysize; 121df8bae1dSRodney W. Grimes char *savedtype; 122df8bae1dSRodney W. Grimes #endif 12360a513e9SPoul-Henning Kamp register struct malloc_type *ksp = type; 124df8bae1dSRodney W. Grimes 125254c6cb3SPoul-Henning Kamp if (!type->ks_next) 126254c6cb3SPoul-Henning Kamp malloc_init(type); 127254c6cb3SPoul-Henning Kamp 128df8bae1dSRodney W. Grimes indx = BUCKETINDX(size); 129df8bae1dSRodney W. Grimes kbp = &bucket[indx]; 130b1897c19SJulian Elischer s = splmem(); 131df8bae1dSRodney W. Grimes while (ksp->ks_memuse >= ksp->ks_limit) { 132df8bae1dSRodney W. Grimes if (flags & M_NOWAIT) { 133df8bae1dSRodney W. Grimes splx(s); 134df8bae1dSRodney W. Grimes return ((void *) NULL); 135df8bae1dSRodney W. Grimes } 136df8bae1dSRodney W. Grimes if (ksp->ks_limblocks < 65535) 137df8bae1dSRodney W. Grimes ksp->ks_limblocks++; 138254c6cb3SPoul-Henning Kamp tsleep((caddr_t)ksp, PSWP+2, type->ks_shortdesc, 0); 139df8bae1dSRodney W. Grimes } 140df8bae1dSRodney W. Grimes ksp->ks_size |= 1 << indx; 141df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 142df8bae1dSRodney W. Grimes copysize = 1 << indx < MAX_COPY ? 1 << indx : MAX_COPY; 143df8bae1dSRodney W. Grimes #endif 144df8bae1dSRodney W. Grimes if (kbp->kb_next == NULL) { 145df8bae1dSRodney W. Grimes kbp->kb_last = NULL; 146df8bae1dSRodney W. Grimes if (size > MAXALLOCSAVE) 147f8845af0SPoul-Henning Kamp allocsize = roundup(size, PAGE_SIZE); 148df8bae1dSRodney W. Grimes else 149df8bae1dSRodney W. Grimes allocsize = 1 << indx; 150e911eafcSPoul-Henning Kamp npg = btoc(allocsize); 1519f518539SDavid Greenman va = (caddr_t) kmem_malloc(kmem_map, (vm_size_t)ctob(npg), flags); 152df8bae1dSRodney W. Grimes if (va == NULL) { 153df8bae1dSRodney W. Grimes splx(s); 154df8bae1dSRodney W. Grimes return ((void *) NULL); 155df8bae1dSRodney W. Grimes } 156df8bae1dSRodney W. Grimes kbp->kb_total += kbp->kb_elmpercl; 157df8bae1dSRodney W. Grimes kup = btokup(va); 158df8bae1dSRodney W. Grimes kup->ku_indx = indx; 159df8bae1dSRodney W. Grimes if (allocsize > MAXALLOCSAVE) { 160df8bae1dSRodney W. Grimes if (npg > 65535) 161df8bae1dSRodney W. Grimes panic("malloc: allocation too large"); 162df8bae1dSRodney W. Grimes kup->ku_pagecnt = npg; 163df8bae1dSRodney W. Grimes ksp->ks_memuse += allocsize; 164df8bae1dSRodney W. Grimes goto out; 165df8bae1dSRodney W. Grimes } 166df8bae1dSRodney W. Grimes kup->ku_freecnt = kbp->kb_elmpercl; 167df8bae1dSRodney W. Grimes kbp->kb_totalfree += kbp->kb_elmpercl; 168df8bae1dSRodney W. Grimes /* 169df8bae1dSRodney W. Grimes * Just in case we blocked while allocating memory, 170df8bae1dSRodney W. Grimes * and someone else also allocated memory for this 171df8bae1dSRodney W. Grimes * bucket, don't assume the list is still empty. 172df8bae1dSRodney W. Grimes */ 173df8bae1dSRodney W. Grimes savedlist = kbp->kb_next; 174e911eafcSPoul-Henning Kamp kbp->kb_next = cp = va + (npg * PAGE_SIZE) - allocsize; 175df8bae1dSRodney W. Grimes for (;;) { 176df8bae1dSRodney W. Grimes freep = (struct freelist *)cp; 177df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 178df8bae1dSRodney W. Grimes /* 179df8bae1dSRodney W. Grimes * Copy in known text to detect modification 180df8bae1dSRodney W. Grimes * after freeing. 181df8bae1dSRodney W. Grimes */ 182df8bae1dSRodney W. Grimes end = (long *)&cp[copysize]; 183df8bae1dSRodney W. Grimes for (lp = (long *)cp; lp < end; lp++) 184df8bae1dSRodney W. Grimes *lp = WEIRD_ADDR; 185df8bae1dSRodney W. Grimes freep->type = M_FREE; 186df8bae1dSRodney W. Grimes #endif /* DIAGNOSTIC */ 187df8bae1dSRodney W. Grimes if (cp <= va) 188df8bae1dSRodney W. Grimes break; 189df8bae1dSRodney W. Grimes cp -= allocsize; 190df8bae1dSRodney W. Grimes freep->next = cp; 191df8bae1dSRodney W. Grimes } 192df8bae1dSRodney W. Grimes freep->next = savedlist; 193df8bae1dSRodney W. Grimes if (kbp->kb_last == NULL) 194df8bae1dSRodney W. Grimes kbp->kb_last = (caddr_t)freep; 195df8bae1dSRodney W. Grimes } 196df8bae1dSRodney W. Grimes va = kbp->kb_next; 197df8bae1dSRodney W. Grimes kbp->kb_next = ((struct freelist *)va)->next; 198df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 199df8bae1dSRodney W. Grimes freep = (struct freelist *)va; 20095461b45SJohn Dyson savedtype = (char *) type->ks_shortdesc; 201df8bae1dSRodney W. Grimes #if BYTE_ORDER == BIG_ENDIAN 20260a513e9SPoul-Henning Kamp freep->type = (struct malloc_type *)WEIRD_ADDR >> 16; 203df8bae1dSRodney W. Grimes #endif 204df8bae1dSRodney W. Grimes #if BYTE_ORDER == LITTLE_ENDIAN 20560a513e9SPoul-Henning Kamp freep->type = (struct malloc_type *)WEIRD_ADDR; 206df8bae1dSRodney W. Grimes #endif 20786a14a7aSBruce Evans if ((intptr_t)(void *)&freep->next & 0x2) 208df8bae1dSRodney W. Grimes freep->next = (caddr_t)((WEIRD_ADDR >> 16)|(WEIRD_ADDR << 16)); 209df8bae1dSRodney W. Grimes else 210df8bae1dSRodney W. Grimes freep->next = (caddr_t)WEIRD_ADDR; 211df8bae1dSRodney W. Grimes end = (long *)&va[copysize]; 212df8bae1dSRodney W. Grimes for (lp = (long *)va; lp < end; lp++) { 213df8bae1dSRodney W. Grimes if (*lp == WEIRD_ADDR) 214df8bae1dSRodney W. Grimes continue; 215d974cf4dSBruce Evans printf("%s %ld of object %p size %lu %s %s (0x%lx != 0x%lx)\n", 216d974cf4dSBruce Evans "Data modified on freelist: word", 217d974cf4dSBruce Evans (long)(lp - (long *)va), (void *)va, size, 218d974cf4dSBruce Evans "previous type", savedtype, *lp, (u_long)WEIRD_ADDR); 219df8bae1dSRodney W. Grimes break; 220df8bae1dSRodney W. Grimes } 221df8bae1dSRodney W. Grimes freep->spare0 = 0; 222df8bae1dSRodney W. Grimes #endif /* DIAGNOSTIC */ 223df8bae1dSRodney W. Grimes kup = btokup(va); 224df8bae1dSRodney W. Grimes if (kup->ku_indx != indx) 225df8bae1dSRodney W. Grimes panic("malloc: wrong bucket"); 226df8bae1dSRodney W. Grimes if (kup->ku_freecnt == 0) 227df8bae1dSRodney W. Grimes panic("malloc: lost data"); 228df8bae1dSRodney W. Grimes kup->ku_freecnt--; 229df8bae1dSRodney W. Grimes kbp->kb_totalfree--; 230df8bae1dSRodney W. Grimes ksp->ks_memuse += 1 << indx; 231df8bae1dSRodney W. Grimes out: 232df8bae1dSRodney W. Grimes kbp->kb_calls++; 233df8bae1dSRodney W. Grimes ksp->ks_inuse++; 234df8bae1dSRodney W. Grimes ksp->ks_calls++; 235df8bae1dSRodney W. Grimes if (ksp->ks_memuse > ksp->ks_maxused) 236df8bae1dSRodney W. Grimes ksp->ks_maxused = ksp->ks_memuse; 237df8bae1dSRodney W. Grimes splx(s); 238df8bae1dSRodney W. Grimes return ((void *) va); 239df8bae1dSRodney W. Grimes } 240df8bae1dSRodney W. Grimes 241df8bae1dSRodney W. Grimes /* 242df8bae1dSRodney W. Grimes * Free a block of memory allocated by malloc. 243df8bae1dSRodney W. Grimes */ 244df8bae1dSRodney W. Grimes void 245df8bae1dSRodney W. Grimes free(addr, type) 246df8bae1dSRodney W. Grimes void *addr; 24760a513e9SPoul-Henning Kamp struct malloc_type *type; 248df8bae1dSRodney W. Grimes { 249df8bae1dSRodney W. Grimes register struct kmembuckets *kbp; 250df8bae1dSRodney W. Grimes register struct kmemusage *kup; 251df8bae1dSRodney W. Grimes register struct freelist *freep; 252df8bae1dSRodney W. Grimes long size; 253df8bae1dSRodney W. Grimes int s; 254df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 255ca67a4e4SPoul-Henning Kamp struct freelist *fp; 256df8bae1dSRodney W. Grimes long *end, *lp, alloc, copysize; 257df8bae1dSRodney W. Grimes #endif 25860a513e9SPoul-Henning Kamp register struct malloc_type *ksp = type; 259254c6cb3SPoul-Henning Kamp 260254c6cb3SPoul-Henning Kamp if (!type->ks_next) 26122c64348SPoul-Henning Kamp panic("freeing with unknown type (%s)", type->ks_shortdesc); 262df8bae1dSRodney W. Grimes 26317dda4c9SDavid Greenman #ifdef DIAGNOSTIC 26417dda4c9SDavid Greenman if ((char *)addr < kmembase || (char *)addr >= kmemlimit) { 265d974cf4dSBruce Evans panic("free: address %p out of range", (void *)addr); 26617dda4c9SDavid Greenman } 26717dda4c9SDavid Greenman #endif 268df8bae1dSRodney W. Grimes kup = btokup(addr); 269df8bae1dSRodney W. Grimes size = 1 << kup->ku_indx; 270df8bae1dSRodney W. Grimes kbp = &bucket[kup->ku_indx]; 271b1897c19SJulian Elischer s = splmem(); 272df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 273df8bae1dSRodney W. Grimes /* 274df8bae1dSRodney W. Grimes * Check for returns of data that do not point to the 275df8bae1dSRodney W. Grimes * beginning of the allocation. 276df8bae1dSRodney W. Grimes */ 277f8845af0SPoul-Henning Kamp if (size > PAGE_SIZE) 278f8845af0SPoul-Henning Kamp alloc = addrmask[BUCKETINDX(PAGE_SIZE)]; 279df8bae1dSRodney W. Grimes else 280df8bae1dSRodney W. Grimes alloc = addrmask[kup->ku_indx]; 28186a14a7aSBruce Evans if (((uintptr_t)(void *)addr & alloc) != 0) 282d974cf4dSBruce Evans panic("free: unaligned addr %p, size %ld, type %s, mask %ld", 283d974cf4dSBruce Evans (void *)addr, size, type->ks_shortdesc, alloc); 284df8bae1dSRodney W. Grimes #endif /* DIAGNOSTIC */ 285df8bae1dSRodney W. Grimes if (size > MAXALLOCSAVE) { 286df8bae1dSRodney W. Grimes kmem_free(kmem_map, (vm_offset_t)addr, ctob(kup->ku_pagecnt)); 287e911eafcSPoul-Henning Kamp size = kup->ku_pagecnt << PAGE_SHIFT; 288df8bae1dSRodney W. Grimes ksp->ks_memuse -= size; 289df8bae1dSRodney W. Grimes kup->ku_indx = 0; 290df8bae1dSRodney W. Grimes kup->ku_pagecnt = 0; 291df8bae1dSRodney W. Grimes if (ksp->ks_memuse + size >= ksp->ks_limit && 292df8bae1dSRodney W. Grimes ksp->ks_memuse < ksp->ks_limit) 293df8bae1dSRodney W. Grimes wakeup((caddr_t)ksp); 294df8bae1dSRodney W. Grimes ksp->ks_inuse--; 295df8bae1dSRodney W. Grimes kbp->kb_total -= 1; 296df8bae1dSRodney W. Grimes splx(s); 297df8bae1dSRodney W. Grimes return; 298df8bae1dSRodney W. Grimes } 299df8bae1dSRodney W. Grimes freep = (struct freelist *)addr; 300df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 301df8bae1dSRodney W. Grimes /* 302df8bae1dSRodney W. Grimes * Check for multiple frees. Use a quick check to see if 303df8bae1dSRodney W. Grimes * it looks free before laboriously searching the freelist. 304df8bae1dSRodney W. Grimes */ 305df8bae1dSRodney W. Grimes if (freep->spare0 == WEIRD_ADDR) { 306ca67a4e4SPoul-Henning Kamp fp = (struct freelist *)kbp->kb_next; 307ca67a4e4SPoul-Henning Kamp while (fp) { 308ca67a4e4SPoul-Henning Kamp if (fp->spare0 != WEIRD_ADDR) { 309ca67a4e4SPoul-Henning Kamp printf("trashed free item %p\n", fp); 310ca67a4e4SPoul-Henning Kamp panic("free: free item modified"); 311ca67a4e4SPoul-Henning Kamp } else if (addr == (caddr_t)fp) { 312ca67a4e4SPoul-Henning Kamp printf("multiple freed item %p\n", addr); 313ca67a4e4SPoul-Henning Kamp panic("free: multiple free"); 314ca67a4e4SPoul-Henning Kamp } 315ca67a4e4SPoul-Henning Kamp fp = (struct freelist *)fp->next; 316df8bae1dSRodney W. Grimes } 317df8bae1dSRodney W. Grimes } 318df8bae1dSRodney W. Grimes /* 319df8bae1dSRodney W. Grimes * Copy in known text to detect modification after freeing 320df8bae1dSRodney W. Grimes * and to make it look free. Also, save the type being freed 321df8bae1dSRodney W. Grimes * so we can list likely culprit if modification is detected 322df8bae1dSRodney W. Grimes * when the object is reallocated. 323df8bae1dSRodney W. Grimes */ 324df8bae1dSRodney W. Grimes copysize = size < MAX_COPY ? size : MAX_COPY; 325df8bae1dSRodney W. Grimes end = (long *)&((caddr_t)addr)[copysize]; 326df8bae1dSRodney W. Grimes for (lp = (long *)addr; lp < end; lp++) 327df8bae1dSRodney W. Grimes *lp = WEIRD_ADDR; 328df8bae1dSRodney W. Grimes freep->type = type; 329df8bae1dSRodney W. Grimes #endif /* DIAGNOSTIC */ 330df8bae1dSRodney W. Grimes kup->ku_freecnt++; 331df8bae1dSRodney W. Grimes if (kup->ku_freecnt >= kbp->kb_elmpercl) 332df8bae1dSRodney W. Grimes if (kup->ku_freecnt > kbp->kb_elmpercl) 333df8bae1dSRodney W. Grimes panic("free: multiple frees"); 334df8bae1dSRodney W. Grimes else if (kbp->kb_totalfree > kbp->kb_highwat) 335df8bae1dSRodney W. Grimes kbp->kb_couldfree++; 336df8bae1dSRodney W. Grimes kbp->kb_totalfree++; 337df8bae1dSRodney W. Grimes ksp->ks_memuse -= size; 338df8bae1dSRodney W. Grimes if (ksp->ks_memuse + size >= ksp->ks_limit && 339df8bae1dSRodney W. Grimes ksp->ks_memuse < ksp->ks_limit) 340df8bae1dSRodney W. Grimes wakeup((caddr_t)ksp); 341df8bae1dSRodney W. Grimes ksp->ks_inuse--; 34214bf02f8SJohn Dyson #ifdef OLD_MALLOC_MEMORY_POLICY 343df8bae1dSRodney W. Grimes if (kbp->kb_next == NULL) 344df8bae1dSRodney W. Grimes kbp->kb_next = addr; 345df8bae1dSRodney W. Grimes else 346df8bae1dSRodney W. Grimes ((struct freelist *)kbp->kb_last)->next = addr; 347df8bae1dSRodney W. Grimes freep->next = NULL; 348df8bae1dSRodney W. Grimes kbp->kb_last = addr; 34914bf02f8SJohn Dyson #else 35014bf02f8SJohn Dyson /* 35114bf02f8SJohn Dyson * Return memory to the head of the queue for quick reuse. This 35214bf02f8SJohn Dyson * can improve performance by improving the probability of the 35314bf02f8SJohn Dyson * item being in the cache when it is reused. 35414bf02f8SJohn Dyson */ 35514bf02f8SJohn Dyson if (kbp->kb_next == NULL) { 35614bf02f8SJohn Dyson kbp->kb_next = addr; 35714bf02f8SJohn Dyson kbp->kb_last = addr; 35814bf02f8SJohn Dyson freep->next = NULL; 35914bf02f8SJohn Dyson } else { 36014bf02f8SJohn Dyson freep->next = kbp->kb_next; 36114bf02f8SJohn Dyson kbp->kb_next = addr; 36214bf02f8SJohn Dyson } 36314bf02f8SJohn Dyson #endif 364df8bae1dSRodney W. Grimes splx(s); 365df8bae1dSRodney W. Grimes } 366df8bae1dSRodney W. Grimes 367df8bae1dSRodney W. Grimes /* 368df8bae1dSRodney W. Grimes * Initialize the kernel memory allocator 369df8bae1dSRodney W. Grimes */ 3702b14f991SJulian Elischer /* ARGSUSED*/ 3712b14f991SJulian Elischer static void 372d841aaa7SBruce Evans kmeminit(dummy) 373d841aaa7SBruce Evans void *dummy; 374df8bae1dSRodney W. Grimes { 375df8bae1dSRodney W. Grimes register long indx; 376df8bae1dSRodney W. Grimes int npg; 3778a58a9f6SJohn Dyson int mem_size; 378df8bae1dSRodney W. Grimes 379df8bae1dSRodney W. Grimes #if ((MAXALLOCSAVE & (MAXALLOCSAVE - 1)) != 0) 380cb7545a9SGarrett Wollman #error "kmeminit: MAXALLOCSAVE not power of 2" 381df8bae1dSRodney W. Grimes #endif 382df8bae1dSRodney W. Grimes #if (MAXALLOCSAVE > MINALLOCSIZE * 32768) 383cb7545a9SGarrett Wollman #error "kmeminit: MAXALLOCSAVE too big" 384df8bae1dSRodney W. Grimes #endif 385f8845af0SPoul-Henning Kamp #if (MAXALLOCSAVE < PAGE_SIZE) 386cb7545a9SGarrett Wollman #error "kmeminit: MAXALLOCSAVE too small" 387df8bae1dSRodney W. Grimes #endif 3888a58a9f6SJohn Dyson 3898a58a9f6SJohn Dyson /* 3908a58a9f6SJohn Dyson * Try to auto-tune the kernel memory size, so that it is 3918a58a9f6SJohn Dyson * more applicable for a wider range of machine sizes. 3928a58a9f6SJohn Dyson * On an X86, a VM_KMEM_SIZE_SCALE value of 4 is good, while 3938a58a9f6SJohn Dyson * a VM_KMEM_SIZE of 12MB is a fair compromise. The 3948a58a9f6SJohn Dyson * VM_KMEM_SIZE_MAX is dependent on the maximum KVA space 3958a58a9f6SJohn Dyson * available, and on an X86 with a total KVA space of 256MB, 3968a58a9f6SJohn Dyson * try to keep VM_KMEM_SIZE_MAX at 80MB or below. 3978a58a9f6SJohn Dyson * 3988a58a9f6SJohn Dyson * Note that the kmem_map is also used by the zone allocator, 3998a58a9f6SJohn Dyson * so make sure that there is enough space. 4008a58a9f6SJohn Dyson */ 4018a58a9f6SJohn Dyson vm_kmem_size = VM_KMEM_SIZE; 4028a58a9f6SJohn Dyson mem_size = cnt.v_page_count * PAGE_SIZE; 4038a58a9f6SJohn Dyson 4048a58a9f6SJohn Dyson #if defined(VM_KMEM_SIZE_SCALE) 4058a58a9f6SJohn Dyson if ((mem_size / VM_KMEM_SIZE_SCALE) > vm_kmem_size) 4068a58a9f6SJohn Dyson vm_kmem_size = mem_size / VM_KMEM_SIZE_SCALE; 4078a58a9f6SJohn Dyson #endif 4088a58a9f6SJohn Dyson 4098a58a9f6SJohn Dyson #if defined(VM_KMEM_SIZE_MAX) 4108a58a9f6SJohn Dyson if (vm_kmem_size >= VM_KMEM_SIZE_MAX) 4118a58a9f6SJohn Dyson vm_kmem_size = VM_KMEM_SIZE_MAX; 4128a58a9f6SJohn Dyson #endif 4138a58a9f6SJohn Dyson 4148a58a9f6SJohn Dyson if (vm_kmem_size > 2 * (cnt.v_page_count * PAGE_SIZE)) 4158a58a9f6SJohn Dyson vm_kmem_size = 2 * (cnt.v_page_count * PAGE_SIZE); 4168a58a9f6SJohn Dyson 4178a58a9f6SJohn Dyson npg = (nmbufs * MSIZE + nmbclusters * MCLBYTES + vm_kmem_size) 418cb7545a9SGarrett Wollman / PAGE_SIZE; 4190d94caffSDavid Greenman 420df8bae1dSRodney W. Grimes kmemusage = (struct kmemusage *) kmem_alloc(kernel_map, 421df8bae1dSRodney W. Grimes (vm_size_t)(npg * sizeof(struct kmemusage))); 422df8bae1dSRodney W. Grimes kmem_map = kmem_suballoc(kernel_map, (vm_offset_t *)&kmembase, 4232d8acc0fSJohn Dyson (vm_offset_t *)&kmemlimit, (vm_size_t)(npg * PAGE_SIZE)); 4243075778bSJohn Dyson kmem_map->system_map = 1; 425df8bae1dSRodney W. Grimes for (indx = 0; indx < MINBUCKET + 16; indx++) { 426f8845af0SPoul-Henning Kamp if (1 << indx >= PAGE_SIZE) 427df8bae1dSRodney W. Grimes bucket[indx].kb_elmpercl = 1; 428df8bae1dSRodney W. Grimes else 429f8845af0SPoul-Henning Kamp bucket[indx].kb_elmpercl = PAGE_SIZE / (1 << indx); 430df8bae1dSRodney W. Grimes bucket[indx].kb_highwat = 5 * bucket[indx].kb_elmpercl; 431df8bae1dSRodney W. Grimes } 432254c6cb3SPoul-Henning Kamp } 433254c6cb3SPoul-Henning Kamp 434db669378SPeter Wemm void 435db669378SPeter Wemm malloc_init(data) 436db669378SPeter Wemm void *data; 437254c6cb3SPoul-Henning Kamp { 438db669378SPeter Wemm struct malloc_type *type = (struct malloc_type *)data; 439254c6cb3SPoul-Henning Kamp 440d1bbc7ecSPoul-Henning Kamp if (type->ks_magic != M_MAGIC) 441d1bbc7ecSPoul-Henning Kamp panic("malloc type lacks magic"); 442d1bbc7ecSPoul-Henning Kamp 443db669378SPeter Wemm if (type->ks_next) 444db669378SPeter Wemm return; 445db669378SPeter Wemm 446d4060a87SJohn Dyson if (cnt.v_page_count == 0) 447d4060a87SJohn Dyson panic("malloc_init not allowed before vm init"); 448d4060a87SJohn Dyson 44907bbd7f1SDavid Greenman /* 4508a58a9f6SJohn Dyson * The default limits for each malloc region is 1/2 of the 4518a58a9f6SJohn Dyson * malloc portion of the kmem map size. 45207bbd7f1SDavid Greenman */ 4538a58a9f6SJohn Dyson type->ks_limit = vm_kmem_size / 2; 454254c6cb3SPoul-Henning Kamp type->ks_next = kmemstatistics; 455254c6cb3SPoul-Henning Kamp kmemstatistics = type; 456df8bae1dSRodney W. Grimes } 457db669378SPeter Wemm 458db669378SPeter Wemm void 459db669378SPeter Wemm malloc_uninit(data) 460db669378SPeter Wemm void *data; 461db669378SPeter Wemm { 462db669378SPeter Wemm struct malloc_type *type = (struct malloc_type *)data; 463db669378SPeter Wemm struct malloc_type *t; 464db669378SPeter Wemm 465db669378SPeter Wemm if (type->ks_magic != M_MAGIC) 466db669378SPeter Wemm panic("malloc type lacks magic"); 467db669378SPeter Wemm 468db669378SPeter Wemm if (cnt.v_page_count == 0) 469db669378SPeter Wemm panic("malloc_uninit not allowed before vm init"); 470db669378SPeter Wemm 471db669378SPeter Wemm if (type == kmemstatistics) 472db669378SPeter Wemm kmemstatistics = type->ks_next; 473db669378SPeter Wemm else { 474db669378SPeter Wemm for (t = kmemstatistics; t->ks_next != NULL; t = t->ks_next) { 475db669378SPeter Wemm if (t->ks_next == type) { 476db669378SPeter Wemm t->ks_next = type->ks_next; 477db669378SPeter Wemm break; 478db669378SPeter Wemm } 479db669378SPeter Wemm } 480db669378SPeter Wemm } 481db669378SPeter Wemm } 482