131422Smckusick /* 231422Smckusick * Copyright (c) 1987 Regents of the University of California. 331422Smckusick * All rights reserved. The Berkeley software License Agreement 431422Smckusick * specifies the terms and conditions for redistribution. 531422Smckusick * 6*33438Smckusick * @(#)kern_malloc.c 7.5 (Berkeley) 02/06/88 731422Smckusick */ 831422Smckusick 931422Smckusick #include "param.h" 1031422Smckusick #include "vm.h" 1131422Smckusick #include "cmap.h" 1231422Smckusick #include "time.h" 1331422Smckusick #include "proc.h" 1431422Smckusick #include "map.h" 1531422Smckusick #include "kernel.h" 1631422Smckusick #include "malloc.h" 1731422Smckusick 1831422Smckusick #include "../machine/pte.h" 1931422Smckusick 2031422Smckusick struct kmembuckets bucket[MINBUCKET + 16]; 2131422Smckusick struct kmemstats kmemstats[M_LAST]; 2231422Smckusick struct kmemusage *kmemusage; 23*33438Smckusick long wantkmemmap; 2431422Smckusick 2531422Smckusick /* 2631422Smckusick * Allocate a block of memory 2731422Smckusick */ 2831422Smckusick qaddr_t malloc(size, type, flags) 2931422Smckusick unsigned long size; 3031422Smckusick long type, flags; 3131422Smckusick { 3231422Smckusick register struct kmembuckets *kbp; 3331422Smckusick register struct kmemusage *kup; 3431422Smckusick long indx, npg, alloc, allocsize, s; 3531422Smckusick caddr_t va, cp; 3631422Smckusick #ifdef KMEMSTATS 37*33438Smckusick register struct kmemstats *ksp = &kmemstats[type]; 38*33438Smckusick #endif 3931422Smckusick 4031422Smckusick indx = BUCKETINDX(size); 4131422Smckusick kbp = &bucket[indx]; 4231422Smckusick s = splimp(); 43*33438Smckusick again: 44*33438Smckusick #ifdef KMEMSTATS 45*33438Smckusick while (ksp->ks_inuse >= ksp->ks_limit) { 46*33438Smckusick if (flags & M_NOWAIT) { 47*33438Smckusick splx(s); 48*33438Smckusick return (0); 49*33438Smckusick } 50*33438Smckusick if (ksp->ks_limblocks < 65535) 51*33438Smckusick ksp->ks_limblocks++; 52*33438Smckusick sleep((caddr_t)ksp, PSWP+2); 53*33438Smckusick } 54*33438Smckusick #endif 5531422Smckusick if (kbp->kb_next == NULL) { 5631422Smckusick if (size > MAXALLOCSAVE) 5731422Smckusick allocsize = roundup(size, CLBYTES); 5831422Smckusick else 5931422Smckusick allocsize = 1 << indx; 6031422Smckusick npg = clrnd(btoc(allocsize)); 6131422Smckusick if ((flags & M_NOWAIT) && freemem < npg) { 6231422Smckusick splx(s); 6331422Smckusick return (0); 6431422Smckusick } 6531422Smckusick alloc = rmalloc(kmemmap, npg); 6631422Smckusick if (alloc == 0) { 67*33438Smckusick if (flags & M_NOWAIT) { 68*33438Smckusick splx(s); 69*33438Smckusick return (0); 70*33438Smckusick } 71*33438Smckusick #ifdef KMEMSTATS 72*33438Smckusick if (ksp->ks_mapblocks < 65535) 73*33438Smckusick ksp->ks_mapblocks++; 74*33438Smckusick #endif 75*33438Smckusick wantkmemmap++; 76*33438Smckusick sleep((caddr_t)&wantkmemmap, PSWP+2); 77*33438Smckusick goto again; 7831422Smckusick } 7932530Skre alloc -= CLSIZE; /* convert to base 0 */ 80*33438Smckusick (void) vmemall(&kmempt[alloc], npg, &proc[0], CSYS); 8131422Smckusick va = (caddr_t) kmemxtob(alloc); 8231422Smckusick vmaccess(&kmempt[alloc], va, npg); 8331422Smckusick #ifdef KMEMSTATS 8431422Smckusick kbp->kb_total += kbp->kb_elmpercl; 8531422Smckusick #endif 8631422Smckusick kup = btokup(va); 8731422Smckusick kup->ku_indx = indx; 8831422Smckusick if (allocsize > MAXALLOCSAVE) { 8931422Smckusick if (npg > 65535) 9031422Smckusick panic("malloc: allocation too large"); 9131422Smckusick kup->ku_pagecnt = npg; 92*33438Smckusick #ifdef KMEMSTATS 93*33438Smckusick ksp->ks_memuse += allocsize; 94*33438Smckusick #endif 9531422Smckusick goto out; 9631422Smckusick } 9731422Smckusick #ifdef KMEMSTATS 9831422Smckusick kup->ku_freecnt = kbp->kb_elmpercl; 9931422Smckusick kbp->kb_totalfree += kbp->kb_elmpercl; 10031422Smckusick #endif 10131422Smckusick kbp->kb_next = va + (npg * NBPG) - allocsize; 102*33438Smckusick for (cp = kbp->kb_next; cp > va; cp -= allocsize) 10331422Smckusick *(caddr_t *)cp = cp - allocsize; 10431422Smckusick *(caddr_t *)cp = NULL; 10531422Smckusick } 10631422Smckusick va = kbp->kb_next; 10731422Smckusick kbp->kb_next = *(caddr_t *)va; 10831422Smckusick #ifdef KMEMSTATS 10931422Smckusick kup = btokup(va); 11031422Smckusick if (kup->ku_indx != indx) 11131422Smckusick panic("malloc: wrong bucket"); 11231422Smckusick if (kup->ku_freecnt == 0) 11331422Smckusick panic("malloc: lost data"); 11431422Smckusick kup->ku_freecnt--; 11531422Smckusick kbp->kb_totalfree--; 116*33438Smckusick ksp->ks_memuse += 1 << indx; 11731422Smckusick out: 11831422Smckusick kbp->kb_calls++; 11931422Smckusick ksp->ks_inuse++; 12031422Smckusick ksp->ks_calls++; 12131422Smckusick if (ksp->ks_inuse > ksp->ks_maxused) 12231422Smckusick ksp->ks_maxused = ksp->ks_inuse; 12331422Smckusick #else 12431422Smckusick out: 12531422Smckusick #endif 12631422Smckusick splx(s); 12731422Smckusick return ((qaddr_t)va); 12831422Smckusick } 12931422Smckusick 13031422Smckusick /* 13131422Smckusick * Free a block of memory allocated by malloc. 13231422Smckusick */ 13331422Smckusick void free(addr, type) 13431422Smckusick caddr_t addr; 13531422Smckusick long type; 13631422Smckusick { 13731422Smckusick register struct kmembuckets *kbp; 13831422Smckusick register struct kmemusage *kup; 13931422Smckusick long alloc, s; 140*33438Smckusick #ifdef KMEMSTATS 141*33438Smckusick register struct kmemstats *ksp = &kmemstats[type]; 142*33438Smckusick #endif 14331422Smckusick 14431422Smckusick kup = btokup(addr); 14531422Smckusick s = splimp(); 14631422Smckusick if (1 << kup->ku_indx > MAXALLOCSAVE) { 14731422Smckusick alloc = btokmemx(addr); 14831422Smckusick (void) memfree(&kmempt[alloc], kup->ku_pagecnt, 0); 149*33438Smckusick rmfree(kmemmap, (long)kup->ku_pagecnt, alloc + CLSIZE); 150*33438Smckusick if (wantkmemmap) { 151*33438Smckusick wakeup((caddr_t)&wantkmemmap); 152*33438Smckusick wantkmemmap = 0; 153*33438Smckusick } 15431422Smckusick #ifdef KMEMSTATS 155*33438Smckusick ksp->ks_memuse -= kup->ku_pagecnt << PGSHIFT; 15631422Smckusick kup->ku_indx = 0; 15731422Smckusick kup->ku_pagecnt = 0; 158*33438Smckusick if (ksp->ks_inuse == ksp->ks_limit) 159*33438Smckusick wakeup((caddr_t)ksp); 160*33438Smckusick ksp->ks_inuse--; 16131422Smckusick #endif 16231422Smckusick splx(s); 16331422Smckusick return; 16431422Smckusick } 16531422Smckusick kbp = &bucket[kup->ku_indx]; 16631422Smckusick #ifdef KMEMSTATS 16731422Smckusick kup->ku_freecnt++; 16831422Smckusick if (kup->ku_freecnt >= kbp->kb_elmpercl) 16931422Smckusick if (kup->ku_freecnt > kbp->kb_elmpercl) 17031422Smckusick panic("free: multiple frees"); 17131422Smckusick else if (kbp->kb_totalfree > kbp->kb_highwat) 17231422Smckusick kbp->kb_couldfree++; 17331422Smckusick kbp->kb_totalfree++; 174*33438Smckusick if (ksp->ks_inuse == ksp->ks_limit) 175*33438Smckusick wakeup((caddr_t)ksp); 176*33438Smckusick ksp->ks_inuse--; 177*33438Smckusick ksp->ks_memuse -= 1 << kup->ku_indx; 17831422Smckusick #endif 17931422Smckusick *(caddr_t *)addr = kbp->kb_next; 18031422Smckusick kbp->kb_next = addr; 18131422Smckusick splx(s); 18231422Smckusick } 18331422Smckusick 18431422Smckusick /* 18531422Smckusick * Initialize the kernel memory allocator 18631422Smckusick */ 18731422Smckusick kmeminit() 18831422Smckusick { 18931422Smckusick register long indx; 19031422Smckusick 19131422Smckusick if (!powerof2(MAXALLOCSAVE)) 19231422Smckusick panic("kmeminit: MAXALLOCSAVE not power of 2"); 19331422Smckusick if (MAXALLOCSAVE > MINALLOCSIZE * 32768) 19431422Smckusick panic("kmeminit: MAXALLOCSAVE too big"); 19531422Smckusick if (MAXALLOCSAVE < CLBYTES) 19631422Smckusick panic("kmeminit: MAXALLOCSAVE too small"); 19732509Skre rminit(kmemmap, ekmempt - kmempt, (long)CLSIZE, 19831422Smckusick "malloc map", ekmempt - kmempt); 19931422Smckusick #ifdef KMEMSTATS 20031422Smckusick for (indx = 0; indx < MINBUCKET + 16; indx++) { 20131422Smckusick if (1 << indx >= CLBYTES) 20231422Smckusick bucket[indx].kb_elmpercl = 1; 20331422Smckusick else 20431422Smckusick bucket[indx].kb_elmpercl = CLBYTES / (1 << indx); 20531422Smckusick bucket[indx].kb_highwat = 5 * bucket[indx].kb_elmpercl; 20631422Smckusick } 20731422Smckusick for (indx = 0; indx < M_LAST; indx++) 208*33438Smckusick kmemstats[indx].ks_limit = 209*33438Smckusick (ekmempt - kmempt) * CLBYTES * 9 / 10; 21031422Smckusick #endif 21131422Smckusick } 212