1 /* 2 * Copyright (c) 1987, 1991 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)kern_malloc.c 7.32 (Berkeley) 03/14/92 8 */ 9 10 #include "param.h" 11 #include "proc.h" 12 #include "map.h" 13 #include "kernel.h" 14 #include "malloc.h" 15 #include "vm/vm.h" 16 #include "vm/vm_kern.h" 17 18 struct kmembuckets bucket[MINBUCKET + 16]; 19 struct kmemstats kmemstats[M_LAST]; 20 struct kmemusage *kmemusage; 21 char *kmembase, *kmemlimit; 22 char *memname[] = INITKMEMNAMES; 23 24 #ifdef DIAGNOSTIC 25 /* 26 * This structure provides a set of masks to catch unaligned frees. 27 */ 28 long addrmask[] = { 0, 29 0x00000001, 0x00000003, 0x00000007, 0x0000000f, 30 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 31 0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff, 32 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff, 33 }; 34 35 /* 36 * The WEIRD_ADDR is used as known text to copy into free objects so 37 * that modifications after frees can be detected. 38 */ 39 #define WEIRD_ADDR 0xdeadbeef 40 #define MAX_COPY 32 41 42 /* 43 * Normally the first word of the structure is used to hold the list 44 * pointer for free objects. However, when running with diagnostics, 45 * we use the third and fourth fields, so as to catch modifications 46 * in the most commonly trashed first two words. 47 */ 48 struct freelist { 49 long spare0; 50 long spare1; 51 short type; 52 short spare2; 53 caddr_t next; 54 }; 55 #else /* !DIAGNOSTIC */ 56 struct freelist { 57 caddr_t next; 58 }; 59 #endif /* DIAGNOSTIC */ 60 61 /* 62 * Allocate a block of memory 63 */ 64 void * 65 malloc(size, type, flags) 66 unsigned long size; 67 int type, flags; 68 { 69 register struct kmembuckets *kbp; 70 register struct kmemusage *kup; 71 register struct freelist *freep; 72 long indx, npg, alloc, allocsize; 73 int s; 74 caddr_t va, cp, savedlist; 75 #ifdef DIAGNOSTIC 76 long *end, *lp; 77 int copysize; 78 char *savedtype; 79 #endif 80 #ifdef KMEMSTATS 81 register struct kmemstats *ksp = &kmemstats[type]; 82 83 if (((unsigned long)type) > M_LAST) 84 panic("malloc - bogus type"); 85 #endif 86 87 indx = BUCKETINDX(size); 88 kbp = &bucket[indx]; 89 s = splimp(); 90 #ifdef KMEMSTATS 91 while (ksp->ks_memuse >= ksp->ks_limit) { 92 if (flags & M_NOWAIT) { 93 splx(s); 94 return ((void *) NULL); 95 } 96 if (ksp->ks_limblocks < 65535) 97 ksp->ks_limblocks++; 98 tsleep((caddr_t)ksp, PSWP+2, memname[type], 0); 99 } 100 #endif 101 #ifdef DIAGNOSTIC 102 copysize = 1 << indx < MAX_COPY ? 1 << indx : MAX_COPY; 103 #endif 104 if (kbp->kb_next == NULL) { 105 if (size > MAXALLOCSAVE) 106 allocsize = roundup(size, CLBYTES); 107 else 108 allocsize = 1 << indx; 109 npg = clrnd(btoc(allocsize)); 110 va = (caddr_t) kmem_malloc(kmem_map, (vm_size_t)ctob(npg), 111 !(flags & M_NOWAIT)); 112 if (va == NULL) { 113 splx(s); 114 return ((void *) NULL); 115 } 116 #ifdef KMEMSTATS 117 kbp->kb_total += kbp->kb_elmpercl; 118 #endif 119 kup = btokup(va); 120 kup->ku_indx = indx; 121 if (allocsize > MAXALLOCSAVE) { 122 if (npg > 65535) 123 panic("malloc: allocation too large"); 124 kup->ku_pagecnt = npg; 125 #ifdef KMEMSTATS 126 ksp->ks_memuse += allocsize; 127 #endif 128 goto out; 129 } 130 #ifdef KMEMSTATS 131 kup->ku_freecnt = kbp->kb_elmpercl; 132 kbp->kb_totalfree += kbp->kb_elmpercl; 133 #endif 134 /* 135 * Just in case we blocked while allocating memory, 136 * and someone else also allocated memory for this 137 * bucket, don't assume the list is still empty. 138 */ 139 savedlist = kbp->kb_next; 140 kbp->kb_next = cp = va + (npg * NBPG) - allocsize; 141 for (;;) { 142 freep = (struct freelist *)cp; 143 #ifdef DIAGNOSTIC 144 /* 145 * Copy in known text to detect modification 146 * after freeing. 147 */ 148 end = (long *)&cp[copysize]; 149 for (lp = (long *)cp; lp < end; lp++) 150 *lp = WEIRD_ADDR; 151 freep->type = M_FREE; 152 #endif /* DIAGNOSTIC */ 153 if (cp <= va) 154 break; 155 cp -= allocsize; 156 freep->next = cp; 157 } 158 freep->next = savedlist; 159 } 160 va = kbp->kb_next; 161 kbp->kb_next = ((struct freelist *)va)->next; 162 #ifdef DIAGNOSTIC 163 freep = (struct freelist *)va; 164 savedtype = (unsigned)freep->type < M_LAST ? 165 memname[freep->type] : "???"; 166 #if BYTE_ORDER == BIG_ENDIAN 167 freep->type = WEIRD_ADDR >> 16; 168 #endif 169 #if BYTE_ORDER == LITTLE_ENDIAN 170 freep->type = WEIRD_ADDR; 171 #endif 172 freep->next = (caddr_t)WEIRD_ADDR; 173 end = (long *)&va[copysize]; 174 for (lp = (long *)va; lp < end; lp++) { 175 if (*lp == WEIRD_ADDR) 176 continue; 177 printf("%s %d of object 0x%x size %d %s %s (0x%x != 0x%x)\n", 178 "Data modified on freelist: word", lp - (long *)va, 179 va, size, "previous type", savedtype, *lp, WEIRD_ADDR); 180 break; 181 } 182 freep->spare0 = 0; 183 #endif /* DIAGNOSTIC */ 184 #ifdef KMEMSTATS 185 kup = btokup(va); 186 if (kup->ku_indx != indx) 187 panic("malloc: wrong bucket"); 188 if (kup->ku_freecnt == 0) 189 panic("malloc: lost data"); 190 kup->ku_freecnt--; 191 kbp->kb_totalfree--; 192 ksp->ks_memuse += 1 << indx; 193 out: 194 kbp->kb_calls++; 195 ksp->ks_inuse++; 196 ksp->ks_calls++; 197 if (ksp->ks_memuse > ksp->ks_maxused) 198 ksp->ks_maxused = ksp->ks_memuse; 199 #else 200 out: 201 #endif 202 splx(s); 203 return ((void *) va); 204 } 205 206 /* 207 * Free a block of memory allocated by malloc. 208 */ 209 void 210 free(addr, type) 211 void *addr; 212 int type; 213 { 214 register struct kmembuckets *kbp; 215 register struct kmemusage *kup; 216 register struct freelist *freep; 217 long size; 218 int s; 219 #ifdef DIAGNOSTIC 220 caddr_t cp; 221 long *end, *lp, alloc, copysize; 222 #endif 223 #ifdef KMEMSTATS 224 register struct kmemstats *ksp = &kmemstats[type]; 225 #endif 226 227 kup = btokup(addr); 228 size = 1 << kup->ku_indx; 229 kbp = &bucket[kup->ku_indx]; 230 s = splimp(); 231 #ifdef DIAGNOSTIC 232 /* 233 * Check for returns of data that do not point to the 234 * beginning of the allocation. 235 */ 236 if (size > NBPG * CLSIZE) 237 alloc = addrmask[BUCKETINDX(NBPG * CLSIZE)]; 238 else 239 alloc = addrmask[kup->ku_indx]; 240 if (((u_long)addr & alloc) != 0) 241 panic("free: unaligned addr 0x%x, size %d, type %s, mask %d\n", 242 addr, size, memname[type], alloc); 243 #endif /* DIAGNOSTIC */ 244 if (size > MAXALLOCSAVE) { 245 kmem_free(kmem_map, (vm_offset_t)addr, ctob(kup->ku_pagecnt)); 246 #ifdef KMEMSTATS 247 size = kup->ku_pagecnt << PGSHIFT; 248 ksp->ks_memuse -= size; 249 kup->ku_indx = 0; 250 kup->ku_pagecnt = 0; 251 if (ksp->ks_memuse + size >= ksp->ks_limit && 252 ksp->ks_memuse < ksp->ks_limit) 253 wakeup((caddr_t)ksp); 254 ksp->ks_inuse--; 255 kbp->kb_total -= 1; 256 #endif 257 splx(s); 258 return; 259 } 260 freep = (struct freelist *)addr; 261 #ifdef DIAGNOSTIC 262 /* 263 * Check for multiple frees. Use a quick check to see if 264 * it looks free before laboriously searching the freelist. 265 */ 266 if (freep->spare0 == WEIRD_ADDR) { 267 for (cp = kbp->kb_next; cp; cp = *(caddr_t *)cp) { 268 if (addr != cp) 269 continue; 270 printf("multiply freed item 0x%x\n", addr); 271 panic("free: duplicated free"); 272 } 273 } 274 /* 275 * Copy in known text to detect modification after freeing 276 * and to make it look free. Also, save the type being freed 277 * so we can list likely culprit if modification is detected 278 * when the object is reallocated. 279 */ 280 copysize = size < MAX_COPY ? size : MAX_COPY; 281 end = (long *)&((caddr_t)addr)[copysize]; 282 for (lp = (long *)addr; lp < end; lp++) 283 *lp = WEIRD_ADDR; 284 freep->type = type; 285 #endif /* DIAGNOSTIC */ 286 #ifdef KMEMSTATS 287 kup->ku_freecnt++; 288 if (kup->ku_freecnt >= kbp->kb_elmpercl) 289 if (kup->ku_freecnt > kbp->kb_elmpercl) 290 panic("free: multiple frees"); 291 else if (kbp->kb_totalfree > kbp->kb_highwat) 292 kbp->kb_couldfree++; 293 kbp->kb_totalfree++; 294 ksp->ks_memuse -= size; 295 if (ksp->ks_memuse + size >= ksp->ks_limit && 296 ksp->ks_memuse < ksp->ks_limit) 297 wakeup((caddr_t)ksp); 298 ksp->ks_inuse--; 299 #endif 300 freep->next = kbp->kb_next; 301 kbp->kb_next = addr; 302 splx(s); 303 } 304 305 /* 306 * Initialize the kernel memory allocator 307 */ 308 kmeminit() 309 { 310 register long indx; 311 int npg; 312 313 #if ((MAXALLOCSAVE & (MAXALLOCSAVE - 1)) != 0) 314 ERROR!_kmeminit:_MAXALLOCSAVE_not_power_of_2 315 #endif 316 #if (MAXALLOCSAVE > MINALLOCSIZE * 32768) 317 ERROR!_kmeminit:_MAXALLOCSAVE_too_big 318 #endif 319 #if (MAXALLOCSAVE < CLBYTES) 320 ERROR!_kmeminit:_MAXALLOCSAVE_too_small 321 #endif 322 npg = VM_KMEM_SIZE/ NBPG; 323 kmemusage = (struct kmemusage *) kmem_alloc(kernel_map, 324 (vm_size_t)(npg * sizeof(struct kmemusage))); 325 kmem_map = kmem_suballoc(kernel_map, (vm_offset_t *)&kmembase, 326 (vm_offset_t *)&kmemlimit, (vm_size_t)(npg * NBPG), FALSE); 327 #ifdef KMEMSTATS 328 for (indx = 0; indx < MINBUCKET + 16; indx++) { 329 if (1 << indx >= CLBYTES) 330 bucket[indx].kb_elmpercl = 1; 331 else 332 bucket[indx].kb_elmpercl = CLBYTES / (1 << indx); 333 bucket[indx].kb_highwat = 5 * bucket[indx].kb_elmpercl; 334 } 335 for (indx = 0; indx < M_LAST; indx++) 336 kmemstats[indx].ks_limit = npg * NBPG * 6 / 10; 337 #endif 338 } 339