131422Smckusick /* 231422Smckusick * Copyright (c) 1987 Regents of the University of California. 3*33439Smckusick * All rights reserved. 431422Smckusick * 5*33439Smckusick * Redistribution and use in source and binary forms are permitted 6*33439Smckusick * provided that this notice is preserved and that due credit is given 7*33439Smckusick * to the University of California at Berkeley. The name of the University 8*33439Smckusick * may not be used to endorse or promote products derived from this 9*33439Smckusick * software without specific prior written permission. This software 10*33439Smckusick * is provided ``as is'' without express or implied warranty. 11*33439Smckusick * 12*33439Smckusick * @(#)kern_malloc.c 7.6 (Berkeley) 02/06/88 1331422Smckusick */ 1431422Smckusick 1531422Smckusick #include "param.h" 1631422Smckusick #include "vm.h" 1731422Smckusick #include "cmap.h" 1831422Smckusick #include "time.h" 1931422Smckusick #include "proc.h" 2031422Smckusick #include "map.h" 2131422Smckusick #include "kernel.h" 2231422Smckusick #include "malloc.h" 2331422Smckusick 2431422Smckusick #include "../machine/pte.h" 2531422Smckusick 2631422Smckusick struct kmembuckets bucket[MINBUCKET + 16]; 2731422Smckusick struct kmemstats kmemstats[M_LAST]; 2831422Smckusick struct kmemusage *kmemusage; 2933438Smckusick long wantkmemmap; 3031422Smckusick 3131422Smckusick /* 3231422Smckusick * Allocate a block of memory 3331422Smckusick */ 3431422Smckusick qaddr_t malloc(size, type, flags) 3531422Smckusick unsigned long size; 3631422Smckusick long type, flags; 3731422Smckusick { 3831422Smckusick register struct kmembuckets *kbp; 3931422Smckusick register struct kmemusage *kup; 4031422Smckusick long indx, npg, alloc, allocsize, s; 4131422Smckusick caddr_t va, cp; 4231422Smckusick #ifdef KMEMSTATS 4333438Smckusick register struct kmemstats *ksp = &kmemstats[type]; 4433438Smckusick #endif 4531422Smckusick 4631422Smckusick indx = BUCKETINDX(size); 4731422Smckusick kbp = &bucket[indx]; 4831422Smckusick s = splimp(); 4933438Smckusick again: 5033438Smckusick #ifdef KMEMSTATS 5133438Smckusick while (ksp->ks_inuse >= ksp->ks_limit) { 5233438Smckusick if (flags & M_NOWAIT) { 5333438Smckusick splx(s); 5433438Smckusick return (0); 5533438Smckusick } 5633438Smckusick if (ksp->ks_limblocks < 65535) 5733438Smckusick ksp->ks_limblocks++; 5833438Smckusick sleep((caddr_t)ksp, PSWP+2); 5933438Smckusick } 6033438Smckusick #endif 6131422Smckusick if (kbp->kb_next == NULL) { 6231422Smckusick if (size > MAXALLOCSAVE) 6331422Smckusick allocsize = roundup(size, CLBYTES); 6431422Smckusick else 6531422Smckusick allocsize = 1 << indx; 6631422Smckusick npg = clrnd(btoc(allocsize)); 6731422Smckusick if ((flags & M_NOWAIT) && freemem < npg) { 6831422Smckusick splx(s); 6931422Smckusick return (0); 7031422Smckusick } 7131422Smckusick alloc = rmalloc(kmemmap, npg); 7231422Smckusick if (alloc == 0) { 7333438Smckusick if (flags & M_NOWAIT) { 7433438Smckusick splx(s); 7533438Smckusick return (0); 7633438Smckusick } 7733438Smckusick #ifdef KMEMSTATS 7833438Smckusick if (ksp->ks_mapblocks < 65535) 7933438Smckusick ksp->ks_mapblocks++; 8033438Smckusick #endif 8133438Smckusick wantkmemmap++; 8233438Smckusick sleep((caddr_t)&wantkmemmap, PSWP+2); 8333438Smckusick goto again; 8431422Smckusick } 8532530Skre alloc -= CLSIZE; /* convert to base 0 */ 8633438Smckusick (void) vmemall(&kmempt[alloc], npg, &proc[0], CSYS); 8731422Smckusick va = (caddr_t) kmemxtob(alloc); 8831422Smckusick vmaccess(&kmempt[alloc], va, npg); 8931422Smckusick #ifdef KMEMSTATS 9031422Smckusick kbp->kb_total += kbp->kb_elmpercl; 9131422Smckusick #endif 9231422Smckusick kup = btokup(va); 9331422Smckusick kup->ku_indx = indx; 9431422Smckusick if (allocsize > MAXALLOCSAVE) { 9531422Smckusick if (npg > 65535) 9631422Smckusick panic("malloc: allocation too large"); 9731422Smckusick kup->ku_pagecnt = npg; 9833438Smckusick #ifdef KMEMSTATS 9933438Smckusick ksp->ks_memuse += allocsize; 10033438Smckusick #endif 10131422Smckusick goto out; 10231422Smckusick } 10331422Smckusick #ifdef KMEMSTATS 10431422Smckusick kup->ku_freecnt = kbp->kb_elmpercl; 10531422Smckusick kbp->kb_totalfree += kbp->kb_elmpercl; 10631422Smckusick #endif 10731422Smckusick kbp->kb_next = va + (npg * NBPG) - allocsize; 10833438Smckusick for (cp = kbp->kb_next; cp > va; cp -= allocsize) 10931422Smckusick *(caddr_t *)cp = cp - allocsize; 11031422Smckusick *(caddr_t *)cp = NULL; 11131422Smckusick } 11231422Smckusick va = kbp->kb_next; 11331422Smckusick kbp->kb_next = *(caddr_t *)va; 11431422Smckusick #ifdef KMEMSTATS 11531422Smckusick kup = btokup(va); 11631422Smckusick if (kup->ku_indx != indx) 11731422Smckusick panic("malloc: wrong bucket"); 11831422Smckusick if (kup->ku_freecnt == 0) 11931422Smckusick panic("malloc: lost data"); 12031422Smckusick kup->ku_freecnt--; 12131422Smckusick kbp->kb_totalfree--; 12233438Smckusick ksp->ks_memuse += 1 << indx; 12331422Smckusick out: 12431422Smckusick kbp->kb_calls++; 12531422Smckusick ksp->ks_inuse++; 12631422Smckusick ksp->ks_calls++; 12731422Smckusick if (ksp->ks_inuse > ksp->ks_maxused) 12831422Smckusick ksp->ks_maxused = ksp->ks_inuse; 12931422Smckusick #else 13031422Smckusick out: 13131422Smckusick #endif 13231422Smckusick splx(s); 13331422Smckusick return ((qaddr_t)va); 13431422Smckusick } 13531422Smckusick 13631422Smckusick /* 13731422Smckusick * Free a block of memory allocated by malloc. 13831422Smckusick */ 13931422Smckusick void free(addr, type) 14031422Smckusick caddr_t addr; 14131422Smckusick long type; 14231422Smckusick { 14331422Smckusick register struct kmembuckets *kbp; 14431422Smckusick register struct kmemusage *kup; 14531422Smckusick long alloc, s; 14633438Smckusick #ifdef KMEMSTATS 14733438Smckusick register struct kmemstats *ksp = &kmemstats[type]; 14833438Smckusick #endif 14931422Smckusick 15031422Smckusick kup = btokup(addr); 15131422Smckusick s = splimp(); 15231422Smckusick if (1 << kup->ku_indx > MAXALLOCSAVE) { 15331422Smckusick alloc = btokmemx(addr); 15431422Smckusick (void) memfree(&kmempt[alloc], kup->ku_pagecnt, 0); 15533438Smckusick rmfree(kmemmap, (long)kup->ku_pagecnt, alloc + CLSIZE); 15633438Smckusick if (wantkmemmap) { 15733438Smckusick wakeup((caddr_t)&wantkmemmap); 15833438Smckusick wantkmemmap = 0; 15933438Smckusick } 16031422Smckusick #ifdef KMEMSTATS 16133438Smckusick ksp->ks_memuse -= kup->ku_pagecnt << PGSHIFT; 16231422Smckusick kup->ku_indx = 0; 16331422Smckusick kup->ku_pagecnt = 0; 16433438Smckusick if (ksp->ks_inuse == ksp->ks_limit) 16533438Smckusick wakeup((caddr_t)ksp); 16633438Smckusick ksp->ks_inuse--; 16731422Smckusick #endif 16831422Smckusick splx(s); 16931422Smckusick return; 17031422Smckusick } 17131422Smckusick kbp = &bucket[kup->ku_indx]; 17231422Smckusick #ifdef KMEMSTATS 17331422Smckusick kup->ku_freecnt++; 17431422Smckusick if (kup->ku_freecnt >= kbp->kb_elmpercl) 17531422Smckusick if (kup->ku_freecnt > kbp->kb_elmpercl) 17631422Smckusick panic("free: multiple frees"); 17731422Smckusick else if (kbp->kb_totalfree > kbp->kb_highwat) 17831422Smckusick kbp->kb_couldfree++; 17931422Smckusick kbp->kb_totalfree++; 18033438Smckusick if (ksp->ks_inuse == ksp->ks_limit) 18133438Smckusick wakeup((caddr_t)ksp); 18233438Smckusick ksp->ks_inuse--; 18333438Smckusick ksp->ks_memuse -= 1 << kup->ku_indx; 18431422Smckusick #endif 18531422Smckusick *(caddr_t *)addr = kbp->kb_next; 18631422Smckusick kbp->kb_next = addr; 18731422Smckusick splx(s); 18831422Smckusick } 18931422Smckusick 19031422Smckusick /* 19131422Smckusick * Initialize the kernel memory allocator 19231422Smckusick */ 19331422Smckusick kmeminit() 19431422Smckusick { 19531422Smckusick register long indx; 19631422Smckusick 19731422Smckusick if (!powerof2(MAXALLOCSAVE)) 19831422Smckusick panic("kmeminit: MAXALLOCSAVE not power of 2"); 19931422Smckusick if (MAXALLOCSAVE > MINALLOCSIZE * 32768) 20031422Smckusick panic("kmeminit: MAXALLOCSAVE too big"); 20131422Smckusick if (MAXALLOCSAVE < CLBYTES) 20231422Smckusick panic("kmeminit: MAXALLOCSAVE too small"); 20332509Skre rminit(kmemmap, ekmempt - kmempt, (long)CLSIZE, 20431422Smckusick "malloc map", ekmempt - kmempt); 20531422Smckusick #ifdef KMEMSTATS 20631422Smckusick for (indx = 0; indx < MINBUCKET + 16; indx++) { 20731422Smckusick if (1 << indx >= CLBYTES) 20831422Smckusick bucket[indx].kb_elmpercl = 1; 20931422Smckusick else 21031422Smckusick bucket[indx].kb_elmpercl = CLBYTES / (1 << indx); 21131422Smckusick bucket[indx].kb_highwat = 5 * bucket[indx].kb_elmpercl; 21231422Smckusick } 21331422Smckusick for (indx = 0; indx < M_LAST; indx++) 21433438Smckusick kmemstats[indx].ks_limit = 21533438Smckusick (ekmempt - kmempt) * CLBYTES * 9 / 10; 21631422Smckusick #endif 21731422Smckusick } 218