1*31422Smckusick /* 2*31422Smckusick * Copyright (c) 1987 Regents of the University of California. 3*31422Smckusick * All rights reserved. The Berkeley software License Agreement 4*31422Smckusick * specifies the terms and conditions for redistribution. 5*31422Smckusick * 6*31422Smckusick * @(#)kern_malloc.c 7.1 (Berkeley) 06/06/87 7*31422Smckusick */ 8*31422Smckusick 9*31422Smckusick #include "param.h" 10*31422Smckusick #include "vm.h" 11*31422Smckusick #include "cmap.h" 12*31422Smckusick #include "time.h" 13*31422Smckusick #include "proc.h" 14*31422Smckusick #include "map.h" 15*31422Smckusick #include "kernel.h" 16*31422Smckusick #include "malloc.h" 17*31422Smckusick 18*31422Smckusick #include "../machine/pte.h" 19*31422Smckusick 20*31422Smckusick struct kmembuckets bucket[MINBUCKET + 16]; 21*31422Smckusick struct kmemstats kmemstats[M_LAST]; 22*31422Smckusick struct kmemusage *kmemusage; 23*31422Smckusick 24*31422Smckusick /* 25*31422Smckusick * Allocate a block of memory 26*31422Smckusick */ 27*31422Smckusick qaddr_t malloc(size, type, flags) 28*31422Smckusick unsigned long size; 29*31422Smckusick long type, flags; 30*31422Smckusick { 31*31422Smckusick register struct kmembuckets *kbp; 32*31422Smckusick register struct kmemusage *kup; 33*31422Smckusick long indx, npg, alloc, allocsize, s; 34*31422Smckusick caddr_t va, cp; 35*31422Smckusick #ifdef KMEMSTATS 36*31422Smckusick register struct kmemstats *ksp; 37*31422Smckusick 38*31422Smckusick ksp = &kmemstats[type]; 39*31422Smckusick if (ksp->ks_inuse >= ksp->ks_limit) 40*31422Smckusick return (0); 41*31422Smckusick #endif 42*31422Smckusick indx = BUCKETINDX(size); 43*31422Smckusick kbp = &bucket[indx]; 44*31422Smckusick s = splimp(); 45*31422Smckusick if (kbp->kb_next == NULL) { 46*31422Smckusick if (size > MAXALLOCSAVE) 47*31422Smckusick allocsize = roundup(size, CLBYTES); 48*31422Smckusick else 49*31422Smckusick allocsize = 1 << indx; 50*31422Smckusick npg = clrnd(btoc(allocsize)); 51*31422Smckusick if ((flags & M_NOWAIT) && freemem < npg) { 52*31422Smckusick splx(s); 53*31422Smckusick return (0); 54*31422Smckusick } 55*31422Smckusick alloc = rmalloc(kmemmap, npg); 56*31422Smckusick if (alloc == 0) { 57*31422Smckusick splx(s); 58*31422Smckusick return (0); 59*31422Smckusick } 60*31422Smckusick if (vmemall(&kmempt[alloc], npg, &proc[0], CSYS) == 0) { 61*31422Smckusick rmfree(kmemmap, npg, alloc); 62*31422Smckusick splx(s); 63*31422Smckusick return (0); 64*31422Smckusick } 65*31422Smckusick va = (caddr_t) kmemxtob(alloc); 66*31422Smckusick vmaccess(&kmempt[alloc], va, npg); 67*31422Smckusick #ifdef KMEMSTATS 68*31422Smckusick kbp->kb_total += kbp->kb_elmpercl; 69*31422Smckusick #endif 70*31422Smckusick kup = btokup(va); 71*31422Smckusick kup->ku_indx = indx; 72*31422Smckusick if (allocsize > MAXALLOCSAVE) { 73*31422Smckusick if (npg > 65535) 74*31422Smckusick panic("malloc: allocation too large"); 75*31422Smckusick kup->ku_pagecnt = npg; 76*31422Smckusick goto out; 77*31422Smckusick } 78*31422Smckusick #ifdef KMEMSTATS 79*31422Smckusick kup->ku_freecnt = kbp->kb_elmpercl; 80*31422Smckusick kbp->kb_totalfree += kbp->kb_elmpercl; 81*31422Smckusick #endif 82*31422Smckusick kbp->kb_next = va + (npg * NBPG) - allocsize; 83*31422Smckusick for(cp = kbp->kb_next; cp > va; cp -= allocsize) 84*31422Smckusick *(caddr_t *)cp = cp - allocsize; 85*31422Smckusick *(caddr_t *)cp = NULL; 86*31422Smckusick } 87*31422Smckusick va = kbp->kb_next; 88*31422Smckusick kbp->kb_next = *(caddr_t *)va; 89*31422Smckusick #ifdef KMEMSTATS 90*31422Smckusick kup = btokup(va); 91*31422Smckusick if (kup->ku_indx != indx) 92*31422Smckusick panic("malloc: wrong bucket"); 93*31422Smckusick if (kup->ku_freecnt == 0) 94*31422Smckusick panic("malloc: lost data"); 95*31422Smckusick kup->ku_freecnt--; 96*31422Smckusick kbp->kb_totalfree--; 97*31422Smckusick out: 98*31422Smckusick kbp->kb_calls++; 99*31422Smckusick ksp->ks_inuse++; 100*31422Smckusick ksp->ks_calls++; 101*31422Smckusick if (ksp->ks_inuse > ksp->ks_maxused) 102*31422Smckusick ksp->ks_maxused = ksp->ks_inuse; 103*31422Smckusick #else 104*31422Smckusick out: 105*31422Smckusick #endif 106*31422Smckusick splx(s); 107*31422Smckusick return ((qaddr_t)va); 108*31422Smckusick } 109*31422Smckusick 110*31422Smckusick /* 111*31422Smckusick * Free a block of memory allocated by malloc. 112*31422Smckusick */ 113*31422Smckusick void free(addr, type) 114*31422Smckusick caddr_t addr; 115*31422Smckusick long type; 116*31422Smckusick { 117*31422Smckusick register struct kmembuckets *kbp; 118*31422Smckusick register struct kmemusage *kup; 119*31422Smckusick long alloc, s; 120*31422Smckusick 121*31422Smckusick kup = btokup(addr); 122*31422Smckusick s = splimp(); 123*31422Smckusick if (1 << kup->ku_indx > MAXALLOCSAVE) { 124*31422Smckusick alloc = btokmemx(addr); 125*31422Smckusick (void) memfree(&kmempt[alloc], kup->ku_pagecnt, 0); 126*31422Smckusick rmfree(kmemmap, (long)kup->ku_pagecnt, alloc); 127*31422Smckusick #ifdef KMEMSTATS 128*31422Smckusick kup->ku_indx = 0; 129*31422Smckusick kup->ku_pagecnt = 0; 130*31422Smckusick kbp->kb_total -= kbp->kb_elmpercl; 131*31422Smckusick kmemstats[type].ks_inuse--; 132*31422Smckusick #endif 133*31422Smckusick splx(s); 134*31422Smckusick return; 135*31422Smckusick } 136*31422Smckusick kbp = &bucket[kup->ku_indx]; 137*31422Smckusick #ifdef KMEMSTATS 138*31422Smckusick kup->ku_freecnt++; 139*31422Smckusick if (kup->ku_freecnt >= kbp->kb_elmpercl) 140*31422Smckusick if (kup->ku_freecnt > kbp->kb_elmpercl) 141*31422Smckusick panic("free: multiple frees"); 142*31422Smckusick else if (kbp->kb_totalfree > kbp->kb_highwat) 143*31422Smckusick kbp->kb_couldfree++; 144*31422Smckusick kbp->kb_totalfree++; 145*31422Smckusick kmemstats[type].ks_inuse--; 146*31422Smckusick #endif 147*31422Smckusick *(caddr_t *)addr = kbp->kb_next; 148*31422Smckusick kbp->kb_next = addr; 149*31422Smckusick splx(s); 150*31422Smckusick } 151*31422Smckusick 152*31422Smckusick /* 153*31422Smckusick * Initialize the kernel memory allocator 154*31422Smckusick */ 155*31422Smckusick kmeminit() 156*31422Smckusick { 157*31422Smckusick register long indx; 158*31422Smckusick 159*31422Smckusick if (!powerof2(MAXALLOCSAVE)) 160*31422Smckusick panic("kmeminit: MAXALLOCSAVE not power of 2"); 161*31422Smckusick if (MAXALLOCSAVE > MINALLOCSIZE * 32768) 162*31422Smckusick panic("kmeminit: MAXALLOCSAVE too big"); 163*31422Smckusick if (MAXALLOCSAVE < CLBYTES) 164*31422Smckusick panic("kmeminit: MAXALLOCSAVE too small"); 165*31422Smckusick rminit(kmemmap, ekmempt - kmempt, (long)1, 166*31422Smckusick "malloc map", ekmempt - kmempt); 167*31422Smckusick #ifdef KMEMSTATS 168*31422Smckusick for (indx = 0; indx < MINBUCKET + 16; indx++) { 169*31422Smckusick if (1 << indx >= CLBYTES) 170*31422Smckusick bucket[indx].kb_elmpercl = 1; 171*31422Smckusick else 172*31422Smckusick bucket[indx].kb_elmpercl = CLBYTES / (1 << indx); 173*31422Smckusick bucket[indx].kb_highwat = 5 * bucket[indx].kb_elmpercl; 174*31422Smckusick } 175*31422Smckusick for (indx = 0; indx < M_LAST; indx++) 176*31422Smckusick kmemstats[indx].ks_limit = 0x7fffffff; 177*31422Smckusick #endif 178*31422Smckusick } 179