131422Smckusick /* 249411Skarels * Copyright (c) 1987, 1991 The Regents of the University of California. 333439Smckusick * All rights reserved. 431422Smckusick * 544437Sbostic * %sccs.include.redist.c% 633439Smckusick * 7*50959Smckusick * @(#)kern_malloc.c 7.28 (Berkeley) 09/03/91 831422Smckusick */ 931422Smckusick 1031422Smckusick #include "param.h" 1131422Smckusick #include "proc.h" 1231422Smckusick #include "map.h" 1331422Smckusick #include "kernel.h" 1431422Smckusick #include "malloc.h" 1548411Skarels #include "vm/vm.h" 1648411Skarels #include "vm/vm_kern.h" 1731422Smckusick 1831422Smckusick struct kmembuckets bucket[MINBUCKET + 16]; 1931422Smckusick struct kmemstats kmemstats[M_LAST]; 2031422Smckusick struct kmemusage *kmemusage; 2146259Skarels char *kmembase, *kmemlimit; 2245154Smckusick char *memname[] = INITKMEMNAMES; 2331422Smckusick 2450744Smckusick #ifdef DIAGNOSTIC 2531422Smckusick /* 2650744Smckusick * This structure serves two purposes. 2750744Smckusick * The first is to provide a set of masks to catch unaligned frees. 2850744Smckusick * The second is to provide known text to copy into free objects so 2950744Smckusick * that modifications after frees can be detected. 3050744Smckusick */ 3150744Smckusick #define WEIRD_ADDR 0xdeadbeef 3250744Smckusick long addrmask[] = { WEIRD_ADDR, 3350744Smckusick 0x00000001, 0x00000003, 0x00000007, 0x0000000f, 3450744Smckusick 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 3550744Smckusick 0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff, 3650744Smckusick 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff, 3750744Smckusick }; 3850937Smckusick 3950937Smckusick /* 4050937Smckusick * Normally the first word of the structure is used to hold the list 4150937Smckusick * pointer for free objects. However, when running with diagnostics, 4250937Smckusick * we use the third and fourth fields, so as to catch modifications 4350937Smckusick * in the most commonly trashed first two words. 4450937Smckusick */ 4550937Smckusick struct freelist { 4650937Smckusick long spare0; 4750937Smckusick long spare1; 4850937Smckusick short type; 4950937Smckusick short spare2; 5050937Smckusick caddr_t next; 5150937Smckusick }; 5250937Smckusick #else /* !DIAGNOSTIC */ 5350937Smckusick struct freelist { 5450937Smckusick caddr_t next; 5550937Smckusick }; 5650744Smckusick #endif /* DIAGNOSTIC */ 5750744Smckusick 5850744Smckusick /* 5931422Smckusick * Allocate a block of memory 6031422Smckusick */ 6149066Skarels void * 6233497Smckusick malloc(size, type, flags) 6331422Smckusick unsigned long size; 6434534Skarels int type, flags; 6531422Smckusick { 6631422Smckusick register struct kmembuckets *kbp; 6731422Smckusick register struct kmemusage *kup; 6850937Smckusick register struct freelist *freep; 6934534Skarels long indx, npg, alloc, allocsize; 7034534Skarels int s; 7146259Skarels caddr_t va, cp, savedlist; 7250744Smckusick #ifdef DIAGNOSTIC 7350744Smckusick int i, copysize; 7450937Smckusick short savedtype; 7550744Smckusick #endif 7631422Smckusick #ifdef KMEMSTATS 7733438Smckusick register struct kmemstats *ksp = &kmemstats[type]; 7839732Smckusick 7939732Smckusick if (((unsigned long)type) > M_LAST) 8037478Ssklower panic("malloc - bogus type"); 8133438Smckusick #endif 8231422Smckusick 8331422Smckusick indx = BUCKETINDX(size); 8431422Smckusick kbp = &bucket[indx]; 8531422Smckusick s = splimp(); 8633438Smckusick #ifdef KMEMSTATS 8733613Smckusick while (ksp->ks_memuse >= ksp->ks_limit) { 8833438Smckusick if (flags & M_NOWAIT) { 8933438Smckusick splx(s); 9049066Skarels return ((void *) NULL); 9133438Smckusick } 9233438Smckusick if (ksp->ks_limblocks < 65535) 9333438Smckusick ksp->ks_limblocks++; 9445154Smckusick tsleep((caddr_t)ksp, PSWP+2, memname[type], 0); 9533438Smckusick } 9633438Smckusick #endif 9750744Smckusick #ifdef DIAGNOSTIC 9850744Smckusick copysize = 1 << indx < sizeof addrmask ? 1 << indx : sizeof addrmask; 9950744Smckusick #endif 10031422Smckusick if (kbp->kb_next == NULL) { 10131422Smckusick if (size > MAXALLOCSAVE) 10231422Smckusick allocsize = roundup(size, CLBYTES); 10331422Smckusick else 10431422Smckusick allocsize = 1 << indx; 10531422Smckusick npg = clrnd(btoc(allocsize)); 10646259Skarels va = (caddr_t) kmem_malloc(kmem_map, (vm_size_t)ctob(npg), 10746259Skarels !(flags & M_NOWAIT)); 10846259Skarels if (va == NULL) { 10931422Smckusick splx(s); 11049066Skarels return ((void *) NULL); 11131422Smckusick } 11233438Smckusick #ifdef KMEMSTATS 11331422Smckusick kbp->kb_total += kbp->kb_elmpercl; 11431422Smckusick #endif 11531422Smckusick kup = btokup(va); 11631422Smckusick kup->ku_indx = indx; 11731422Smckusick if (allocsize > MAXALLOCSAVE) { 11831422Smckusick if (npg > 65535) 11931422Smckusick panic("malloc: allocation too large"); 12031422Smckusick kup->ku_pagecnt = npg; 12133438Smckusick #ifdef KMEMSTATS 12233438Smckusick ksp->ks_memuse += allocsize; 12333438Smckusick #endif 12431422Smckusick goto out; 12531422Smckusick } 12631422Smckusick #ifdef KMEMSTATS 12731422Smckusick kup->ku_freecnt = kbp->kb_elmpercl; 12831422Smckusick kbp->kb_totalfree += kbp->kb_elmpercl; 12931422Smckusick #endif 13046259Skarels /* 13146259Skarels * Just in case we blocked while allocating memory, 13246259Skarels * and someone else also allocated memory for this 13346259Skarels * bucket, don't assume the list is still empty. 13446259Skarels */ 13546259Skarels savedlist = kbp->kb_next; 13631422Smckusick kbp->kb_next = va + (npg * NBPG) - allocsize; 13750744Smckusick for (cp = kbp->kb_next; ; cp -= allocsize) { 13850937Smckusick freep = (struct freelist *)cp; 13950744Smckusick #ifdef DIAGNOSTIC 14050744Smckusick /* 14150744Smckusick * Copy in known text to detect modification 14250744Smckusick * after freeing. 14350744Smckusick */ 14450744Smckusick bcopy(addrmask, cp, copysize); 14550937Smckusick freep->type = M_FREE; 14650744Smckusick #endif /* DIAGNOSTIC */ 14750744Smckusick if (cp <= va) 14850744Smckusick break; 14950937Smckusick freep->next = cp - allocsize; 15050744Smckusick } 15150937Smckusick freep->next = savedlist; 15231422Smckusick } 15331422Smckusick va = kbp->kb_next; 15450937Smckusick kbp->kb_next = ((struct freelist *)va)->next; 15550744Smckusick #ifdef DIAGNOSTIC 15650937Smckusick freep = (struct freelist *)va; 15750937Smckusick savedtype = freep->type; 15850937Smckusick freep->type = ((struct freelist *)addrmask)->type; 15950937Smckusick freep->next = ((struct freelist *)addrmask)->next; 16050744Smckusick if (bcmp(addrmask, va, copysize)) { 16150744Smckusick copysize >>= 2; 16250744Smckusick for (i = 0; i < copysize && addrmask[i] == ((int *)va)[i]; i++) 16350744Smckusick /* void */; 16450937Smckusick printf("%s %d of object 0x%x size %d %s %s (0x%x != 0x%x)\n", 16550937Smckusick "Data modified on freelist: word", i, va, size, 16650937Smckusick "previous type", memname[savedtype], ((int *)va)[i], 16750937Smckusick addrmask[i]); 168*50959Smckusick /* panic("malloc: data modified on freelist"); */ 16950744Smckusick } 17050937Smckusick freep->spare0 = 0; 17150744Smckusick #endif /* DIAGNOSTIC */ 17231422Smckusick #ifdef KMEMSTATS 17331422Smckusick kup = btokup(va); 17431422Smckusick if (kup->ku_indx != indx) 17531422Smckusick panic("malloc: wrong bucket"); 17631422Smckusick if (kup->ku_freecnt == 0) 17731422Smckusick panic("malloc: lost data"); 17831422Smckusick kup->ku_freecnt--; 17931422Smckusick kbp->kb_totalfree--; 18033438Smckusick ksp->ks_memuse += 1 << indx; 18131422Smckusick out: 18231422Smckusick kbp->kb_calls++; 18331422Smckusick ksp->ks_inuse++; 18431422Smckusick ksp->ks_calls++; 18533613Smckusick if (ksp->ks_memuse > ksp->ks_maxused) 18633613Smckusick ksp->ks_maxused = ksp->ks_memuse; 18731422Smckusick #else 18831422Smckusick out: 18931422Smckusick #endif 19031422Smckusick splx(s); 19149066Skarels return ((void *) va); 19231422Smckusick } 19331422Smckusick 19431422Smckusick /* 19531422Smckusick * Free a block of memory allocated by malloc. 19631422Smckusick */ 19733497Smckusick void 19833497Smckusick free(addr, type) 19949066Skarels void *addr; 20034534Skarels int type; 20131422Smckusick { 20231422Smckusick register struct kmembuckets *kbp; 20331422Smckusick register struct kmemusage *kup; 20450937Smckusick register struct freelist *freep; 20550744Smckusick long size; 20634534Skarels int s; 20750744Smckusick #ifdef DIAGNOSTIC 20850744Smckusick caddr_t cp; 20950744Smckusick long alloc, copysize; 21050744Smckusick #endif 21133438Smckusick #ifdef KMEMSTATS 21233438Smckusick register struct kmemstats *ksp = &kmemstats[type]; 21333438Smckusick #endif 21431422Smckusick 21531422Smckusick kup = btokup(addr); 21645000Smckusick size = 1 << kup->ku_indx; 21750744Smckusick kbp = &bucket[kup->ku_indx]; 21850744Smckusick s = splimp(); 21945000Smckusick #ifdef DIAGNOSTIC 22050744Smckusick /* 22150744Smckusick * Check for returns of data that do not point to the 22250744Smckusick * beginning of the allocation. 22350744Smckusick */ 22445000Smckusick if (size > NBPG * CLSIZE) 22545000Smckusick alloc = addrmask[BUCKETINDX(NBPG * CLSIZE)]; 22645000Smckusick else 22745000Smckusick alloc = addrmask[kup->ku_indx]; 22845000Smckusick if (((u_long)addr & alloc) != 0) { 22945000Smckusick printf("free: unaligned addr 0x%x, size %d, type %d, mask %d\n", 23045000Smckusick addr, size, type, alloc); 23145000Smckusick panic("free: unaligned addr"); 23245000Smckusick } 23345000Smckusick #endif /* DIAGNOSTIC */ 23433613Smckusick if (size > MAXALLOCSAVE) { 23546259Skarels kmem_free(kmem_map, (vm_offset_t)addr, ctob(kup->ku_pagecnt)); 23631422Smckusick #ifdef KMEMSTATS 23733613Smckusick size = kup->ku_pagecnt << PGSHIFT; 23833613Smckusick ksp->ks_memuse -= size; 23931422Smckusick kup->ku_indx = 0; 24031422Smckusick kup->ku_pagecnt = 0; 24133613Smckusick if (ksp->ks_memuse + size >= ksp->ks_limit && 24233613Smckusick ksp->ks_memuse < ksp->ks_limit) 24333438Smckusick wakeup((caddr_t)ksp); 24433438Smckusick ksp->ks_inuse--; 24533497Smckusick kbp->kb_total -= 1; 24631422Smckusick #endif 24731422Smckusick splx(s); 24831422Smckusick return; 24931422Smckusick } 25050937Smckusick freep = (struct freelist *)addr; 25150744Smckusick #ifdef DIAGNOSTIC 25250744Smckusick /* 25350744Smckusick * Check for multiple frees. Use a quick check to see if 25450744Smckusick * it looks free before laboriously searching the freelist. 25550744Smckusick */ 25650744Smckusick copysize = size < sizeof addrmask ? size : sizeof addrmask; 25750937Smckusick if (freep->spare0 == WEIRD_ADDR) { 25850937Smckusick freep->type = ((struct freelist *)addrmask)->type; 25950937Smckusick freep->next = ((struct freelist *)addrmask)->next; 26050937Smckusick if (!bcmp(addrmask, addr, copysize)) { 26150937Smckusick for (cp = kbp->kb_next; cp; cp = *(caddr_t *)cp) { 26250937Smckusick if (addr == cp) { 26350937Smckusick printf("multiply freed item 0x%x\n", 26450937Smckusick addr); 26550937Smckusick panic("free: duplicated free"); 26650937Smckusick } 26750744Smckusick } 26850744Smckusick } 26950744Smckusick } 27050744Smckusick /* 27150744Smckusick * Copy in known text to detect modification after freeing 27250937Smckusick * and to make it look free. Also, save the type being freed 27350937Smckusick * so we can list likely culprit if modification is detected 27450937Smckusick * when the object is reallocated. 27550744Smckusick */ 27650744Smckusick bcopy(addrmask, addr, copysize); 27750937Smckusick freep->type = type; 27850744Smckusick #endif /* DIAGNOSTIC */ 27931422Smckusick #ifdef KMEMSTATS 28031422Smckusick kup->ku_freecnt++; 28131422Smckusick if (kup->ku_freecnt >= kbp->kb_elmpercl) 28231422Smckusick if (kup->ku_freecnt > kbp->kb_elmpercl) 28331422Smckusick panic("free: multiple frees"); 28431422Smckusick else if (kbp->kb_totalfree > kbp->kb_highwat) 28531422Smckusick kbp->kb_couldfree++; 28631422Smckusick kbp->kb_totalfree++; 28733613Smckusick ksp->ks_memuse -= size; 28833613Smckusick if (ksp->ks_memuse + size >= ksp->ks_limit && 28933613Smckusick ksp->ks_memuse < ksp->ks_limit) 29033438Smckusick wakeup((caddr_t)ksp); 29133438Smckusick ksp->ks_inuse--; 29231422Smckusick #endif 29350937Smckusick freep->next = kbp->kb_next; 29431422Smckusick kbp->kb_next = addr; 29531422Smckusick splx(s); 29631422Smckusick } 29731422Smckusick 29831422Smckusick /* 29931422Smckusick * Initialize the kernel memory allocator 30031422Smckusick */ 30131422Smckusick kmeminit() 30231422Smckusick { 30331422Smckusick register long indx; 30433497Smckusick int npg; 30531422Smckusick 30634534Skarels #if ((MAXALLOCSAVE & (MAXALLOCSAVE - 1)) != 0) 30734534Skarels ERROR!_kmeminit:_MAXALLOCSAVE_not_power_of_2 30834534Skarels #endif 30934534Skarels #if (MAXALLOCSAVE > MINALLOCSIZE * 32768) 31034534Skarels ERROR!_kmeminit:_MAXALLOCSAVE_too_big 31134534Skarels #endif 31234534Skarels #if (MAXALLOCSAVE < CLBYTES) 31334534Skarels ERROR!_kmeminit:_MAXALLOCSAVE_too_small 31434534Skarels #endif 31546259Skarels npg = VM_KMEM_SIZE/ NBPG; 31646259Skarels kmemusage = (struct kmemusage *) kmem_alloc(kernel_map, 31746259Skarels (vm_size_t)(npg * sizeof(struct kmemusage))); 31846259Skarels kmem_map = kmem_suballoc(kernel_map, (vm_offset_t)&kmembase, 31946259Skarels (vm_offset_t)&kmemlimit, (vm_size_t)(npg * NBPG), FALSE); 32031422Smckusick #ifdef KMEMSTATS 32131422Smckusick for (indx = 0; indx < MINBUCKET + 16; indx++) { 32231422Smckusick if (1 << indx >= CLBYTES) 32331422Smckusick bucket[indx].kb_elmpercl = 1; 32431422Smckusick else 32531422Smckusick bucket[indx].kb_elmpercl = CLBYTES / (1 << indx); 32631422Smckusick bucket[indx].kb_highwat = 5 * bucket[indx].kb_elmpercl; 32731422Smckusick } 32831422Smckusick for (indx = 0; indx < M_LAST; indx++) 32941950Smckusick kmemstats[indx].ks_limit = npg * NBPG * 6 / 10; 33031422Smckusick #endif 33131422Smckusick } 332