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*32509Skre * @(#)kern_malloc.c 7.3 (Berkeley) 10/22/87 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; 2331422Smckusick 2431422Smckusick /* 2531422Smckusick * Allocate a block of memory 2631422Smckusick */ 2731422Smckusick qaddr_t malloc(size, type, flags) 2831422Smckusick unsigned long size; 2931422Smckusick long type, flags; 3031422Smckusick { 3131422Smckusick register struct kmembuckets *kbp; 3231422Smckusick register struct kmemusage *kup; 3331422Smckusick long indx, npg, alloc, allocsize, s; 3431422Smckusick caddr_t va, cp; 3531422Smckusick #ifdef KMEMSTATS 3631422Smckusick register struct kmemstats *ksp; 3731422Smckusick 3831422Smckusick ksp = &kmemstats[type]; 3931422Smckusick if (ksp->ks_inuse >= ksp->ks_limit) 4031422Smckusick return (0); 4131422Smckusick #endif 4231422Smckusick indx = BUCKETINDX(size); 4331422Smckusick kbp = &bucket[indx]; 4431422Smckusick s = splimp(); 4531422Smckusick if (kbp->kb_next == NULL) { 4631422Smckusick if (size > MAXALLOCSAVE) 4731422Smckusick allocsize = roundup(size, CLBYTES); 4831422Smckusick else 4931422Smckusick allocsize = 1 << indx; 5031422Smckusick npg = clrnd(btoc(allocsize)); 5131422Smckusick if ((flags & M_NOWAIT) && freemem < npg) { 5231422Smckusick splx(s); 5331422Smckusick return (0); 5431422Smckusick } 5531422Smckusick alloc = rmalloc(kmemmap, npg); 5631422Smckusick if (alloc == 0) { 5731422Smckusick splx(s); 5831422Smckusick return (0); 5931422Smckusick } 6031422Smckusick if (vmemall(&kmempt[alloc], npg, &proc[0], CSYS) == 0) { 6131422Smckusick rmfree(kmemmap, npg, alloc); 6231422Smckusick splx(s); 6331422Smckusick return (0); 6431422Smckusick } 6531422Smckusick va = (caddr_t) kmemxtob(alloc); 6631422Smckusick vmaccess(&kmempt[alloc], va, npg); 6731422Smckusick #ifdef KMEMSTATS 6831422Smckusick kbp->kb_total += kbp->kb_elmpercl; 6931422Smckusick #endif 7031422Smckusick kup = btokup(va); 7131422Smckusick kup->ku_indx = indx; 7231422Smckusick if (allocsize > MAXALLOCSAVE) { 7331422Smckusick if (npg > 65535) 7431422Smckusick panic("malloc: allocation too large"); 7531422Smckusick kup->ku_pagecnt = npg; 7631422Smckusick goto out; 7731422Smckusick } 7831422Smckusick #ifdef KMEMSTATS 7931422Smckusick kup->ku_freecnt = kbp->kb_elmpercl; 8031422Smckusick kbp->kb_totalfree += kbp->kb_elmpercl; 8131422Smckusick #endif 8231422Smckusick kbp->kb_next = va + (npg * NBPG) - allocsize; 8331422Smckusick for(cp = kbp->kb_next; cp > va; cp -= allocsize) 8431422Smckusick *(caddr_t *)cp = cp - allocsize; 8531422Smckusick *(caddr_t *)cp = NULL; 8631422Smckusick } 8731422Smckusick va = kbp->kb_next; 8831422Smckusick kbp->kb_next = *(caddr_t *)va; 8931422Smckusick #ifdef KMEMSTATS 9031422Smckusick kup = btokup(va); 9131422Smckusick if (kup->ku_indx != indx) 9231422Smckusick panic("malloc: wrong bucket"); 9331422Smckusick if (kup->ku_freecnt == 0) 9431422Smckusick panic("malloc: lost data"); 9531422Smckusick kup->ku_freecnt--; 9631422Smckusick kbp->kb_totalfree--; 9731422Smckusick out: 9831422Smckusick kbp->kb_calls++; 9931422Smckusick ksp->ks_inuse++; 10031422Smckusick ksp->ks_calls++; 10131422Smckusick if (ksp->ks_inuse > ksp->ks_maxused) 10231422Smckusick ksp->ks_maxused = ksp->ks_inuse; 10331422Smckusick #else 10431422Smckusick out: 10531422Smckusick #endif 10631422Smckusick splx(s); 10731422Smckusick return ((qaddr_t)va); 10831422Smckusick } 10931422Smckusick 11031422Smckusick /* 11131422Smckusick * Free a block of memory allocated by malloc. 11231422Smckusick */ 11331422Smckusick void free(addr, type) 11431422Smckusick caddr_t addr; 11531422Smckusick long type; 11631422Smckusick { 11731422Smckusick register struct kmembuckets *kbp; 11831422Smckusick register struct kmemusage *kup; 11931422Smckusick long alloc, s; 12031422Smckusick 12131422Smckusick kup = btokup(addr); 12231422Smckusick s = splimp(); 12331422Smckusick if (1 << kup->ku_indx > MAXALLOCSAVE) { 12431422Smckusick alloc = btokmemx(addr); 12531422Smckusick (void) memfree(&kmempt[alloc], kup->ku_pagecnt, 0); 12631422Smckusick rmfree(kmemmap, (long)kup->ku_pagecnt, alloc); 12731422Smckusick #ifdef KMEMSTATS 12831422Smckusick kup->ku_indx = 0; 12931422Smckusick kup->ku_pagecnt = 0; 13031422Smckusick kmemstats[type].ks_inuse--; 13131422Smckusick #endif 13231422Smckusick splx(s); 13331422Smckusick return; 13431422Smckusick } 13531422Smckusick kbp = &bucket[kup->ku_indx]; 13631422Smckusick #ifdef KMEMSTATS 13731422Smckusick kup->ku_freecnt++; 13831422Smckusick if (kup->ku_freecnt >= kbp->kb_elmpercl) 13931422Smckusick if (kup->ku_freecnt > kbp->kb_elmpercl) 14031422Smckusick panic("free: multiple frees"); 14131422Smckusick else if (kbp->kb_totalfree > kbp->kb_highwat) 14231422Smckusick kbp->kb_couldfree++; 14331422Smckusick kbp->kb_totalfree++; 14431422Smckusick kmemstats[type].ks_inuse--; 14531422Smckusick #endif 14631422Smckusick *(caddr_t *)addr = kbp->kb_next; 14731422Smckusick kbp->kb_next = addr; 14831422Smckusick splx(s); 14931422Smckusick } 15031422Smckusick 15131422Smckusick /* 15231422Smckusick * Initialize the kernel memory allocator 15331422Smckusick */ 15431422Smckusick kmeminit() 15531422Smckusick { 15631422Smckusick register long indx; 15731422Smckusick 15831422Smckusick if (!powerof2(MAXALLOCSAVE)) 15931422Smckusick panic("kmeminit: MAXALLOCSAVE not power of 2"); 16031422Smckusick if (MAXALLOCSAVE > MINALLOCSIZE * 32768) 16131422Smckusick panic("kmeminit: MAXALLOCSAVE too big"); 16231422Smckusick if (MAXALLOCSAVE < CLBYTES) 16331422Smckusick panic("kmeminit: MAXALLOCSAVE too small"); 164*32509Skre rminit(kmemmap, ekmempt - kmempt, (long)CLSIZE, 16531422Smckusick "malloc map", ekmempt - kmempt); 16631422Smckusick #ifdef KMEMSTATS 16731422Smckusick for (indx = 0; indx < MINBUCKET + 16; indx++) { 16831422Smckusick if (1 << indx >= CLBYTES) 16931422Smckusick bucket[indx].kb_elmpercl = 1; 17031422Smckusick else 17131422Smckusick bucket[indx].kb_elmpercl = CLBYTES / (1 << indx); 17231422Smckusick bucket[indx].kb_highwat = 5 * bucket[indx].kb_elmpercl; 17331422Smckusick } 17431422Smckusick for (indx = 0; indx < M_LAST; indx++) 17531422Smckusick kmemstats[indx].ks_limit = 0x7fffffff; 17631422Smckusick #endif 17731422Smckusick } 178