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*32530Skre * @(#)kern_malloc.c 7.4 (Berkeley) 10/23/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 } 60*32530Skre alloc -= CLSIZE; /* convert to base 0 */ 6131422Smckusick if (vmemall(&kmempt[alloc], npg, &proc[0], CSYS) == 0) { 62*32530Skre rmfree(kmemmap, npg, alloc+CLSIZE); 6331422Smckusick splx(s); 6431422Smckusick return (0); 6531422Smckusick } 6631422Smckusick va = (caddr_t) kmemxtob(alloc); 6731422Smckusick vmaccess(&kmempt[alloc], va, npg); 6831422Smckusick #ifdef KMEMSTATS 6931422Smckusick kbp->kb_total += kbp->kb_elmpercl; 7031422Smckusick #endif 7131422Smckusick kup = btokup(va); 7231422Smckusick kup->ku_indx = indx; 7331422Smckusick if (allocsize > MAXALLOCSAVE) { 7431422Smckusick if (npg > 65535) 7531422Smckusick panic("malloc: allocation too large"); 7631422Smckusick kup->ku_pagecnt = npg; 7731422Smckusick goto out; 7831422Smckusick } 7931422Smckusick #ifdef KMEMSTATS 8031422Smckusick kup->ku_freecnt = kbp->kb_elmpercl; 8131422Smckusick kbp->kb_totalfree += kbp->kb_elmpercl; 8231422Smckusick #endif 8331422Smckusick kbp->kb_next = va + (npg * NBPG) - allocsize; 8431422Smckusick for(cp = kbp->kb_next; cp > va; cp -= allocsize) 8531422Smckusick *(caddr_t *)cp = cp - allocsize; 8631422Smckusick *(caddr_t *)cp = NULL; 8731422Smckusick } 8831422Smckusick va = kbp->kb_next; 8931422Smckusick kbp->kb_next = *(caddr_t *)va; 9031422Smckusick #ifdef KMEMSTATS 9131422Smckusick kup = btokup(va); 9231422Smckusick if (kup->ku_indx != indx) 9331422Smckusick panic("malloc: wrong bucket"); 9431422Smckusick if (kup->ku_freecnt == 0) 9531422Smckusick panic("malloc: lost data"); 9631422Smckusick kup->ku_freecnt--; 9731422Smckusick kbp->kb_totalfree--; 9831422Smckusick out: 9931422Smckusick kbp->kb_calls++; 10031422Smckusick ksp->ks_inuse++; 10131422Smckusick ksp->ks_calls++; 10231422Smckusick if (ksp->ks_inuse > ksp->ks_maxused) 10331422Smckusick ksp->ks_maxused = ksp->ks_inuse; 10431422Smckusick #else 10531422Smckusick out: 10631422Smckusick #endif 10731422Smckusick splx(s); 10831422Smckusick return ((qaddr_t)va); 10931422Smckusick } 11031422Smckusick 11131422Smckusick /* 11231422Smckusick * Free a block of memory allocated by malloc. 11331422Smckusick */ 11431422Smckusick void free(addr, type) 11531422Smckusick caddr_t addr; 11631422Smckusick long type; 11731422Smckusick { 11831422Smckusick register struct kmembuckets *kbp; 11931422Smckusick register struct kmemusage *kup; 12031422Smckusick long alloc, s; 12131422Smckusick 12231422Smckusick kup = btokup(addr); 12331422Smckusick s = splimp(); 12431422Smckusick if (1 << kup->ku_indx > MAXALLOCSAVE) { 12531422Smckusick alloc = btokmemx(addr); 12631422Smckusick (void) memfree(&kmempt[alloc], kup->ku_pagecnt, 0); 127*32530Skre rmfree(kmemmap, (long)kup->ku_pagecnt, alloc+CLSIZE); 12831422Smckusick #ifdef KMEMSTATS 12931422Smckusick kup->ku_indx = 0; 13031422Smckusick kup->ku_pagecnt = 0; 13131422Smckusick kmemstats[type].ks_inuse--; 13231422Smckusick #endif 13331422Smckusick splx(s); 13431422Smckusick return; 13531422Smckusick } 13631422Smckusick kbp = &bucket[kup->ku_indx]; 13731422Smckusick #ifdef KMEMSTATS 13831422Smckusick kup->ku_freecnt++; 13931422Smckusick if (kup->ku_freecnt >= kbp->kb_elmpercl) 14031422Smckusick if (kup->ku_freecnt > kbp->kb_elmpercl) 14131422Smckusick panic("free: multiple frees"); 14231422Smckusick else if (kbp->kb_totalfree > kbp->kb_highwat) 14331422Smckusick kbp->kb_couldfree++; 14431422Smckusick kbp->kb_totalfree++; 14531422Smckusick kmemstats[type].ks_inuse--; 14631422Smckusick #endif 14731422Smckusick *(caddr_t *)addr = kbp->kb_next; 14831422Smckusick kbp->kb_next = addr; 14931422Smckusick splx(s); 15031422Smckusick } 15131422Smckusick 15231422Smckusick /* 15331422Smckusick * Initialize the kernel memory allocator 15431422Smckusick */ 15531422Smckusick kmeminit() 15631422Smckusick { 15731422Smckusick register long indx; 15831422Smckusick 15931422Smckusick if (!powerof2(MAXALLOCSAVE)) 16031422Smckusick panic("kmeminit: MAXALLOCSAVE not power of 2"); 16131422Smckusick if (MAXALLOCSAVE > MINALLOCSIZE * 32768) 16231422Smckusick panic("kmeminit: MAXALLOCSAVE too big"); 16331422Smckusick if (MAXALLOCSAVE < CLBYTES) 16431422Smckusick panic("kmeminit: MAXALLOCSAVE too small"); 16532509Skre rminit(kmemmap, ekmempt - kmempt, (long)CLSIZE, 16631422Smckusick "malloc map", ekmempt - kmempt); 16731422Smckusick #ifdef KMEMSTATS 16831422Smckusick for (indx = 0; indx < MINBUCKET + 16; indx++) { 16931422Smckusick if (1 << indx >= CLBYTES) 17031422Smckusick bucket[indx].kb_elmpercl = 1; 17131422Smckusick else 17231422Smckusick bucket[indx].kb_elmpercl = CLBYTES / (1 << indx); 17331422Smckusick bucket[indx].kb_highwat = 5 * bucket[indx].kb_elmpercl; 17431422Smckusick } 17531422Smckusick for (indx = 0; indx < M_LAST; indx++) 17631422Smckusick kmemstats[indx].ks_limit = 0x7fffffff; 17731422Smckusick #endif 17831422Smckusick } 179