xref: /freebsd/sys/kern/kern_malloc.c (revision 26f9a76710a312a951848542b9ca1f44100450e2)
1df8bae1dSRodney W. Grimes /*
2df8bae1dSRodney W. Grimes  * Copyright (c) 1987, 1991, 1993
3df8bae1dSRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
4df8bae1dSRodney W. Grimes  *
5df8bae1dSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
6df8bae1dSRodney W. Grimes  * modification, are permitted provided that the following conditions
7df8bae1dSRodney W. Grimes  * are met:
8df8bae1dSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
9df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
10df8bae1dSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
11df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
12df8bae1dSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
13df8bae1dSRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
14df8bae1dSRodney W. Grimes  *    must display the following acknowledgement:
15df8bae1dSRodney W. Grimes  *	This product includes software developed by the University of
16df8bae1dSRodney W. Grimes  *	California, Berkeley and its contributors.
17df8bae1dSRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
18df8bae1dSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
19df8bae1dSRodney W. Grimes  *    without specific prior written permission.
20df8bae1dSRodney W. Grimes  *
21df8bae1dSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22df8bae1dSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23df8bae1dSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24df8bae1dSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25df8bae1dSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26df8bae1dSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27df8bae1dSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28df8bae1dSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29df8bae1dSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30df8bae1dSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31df8bae1dSRodney W. Grimes  * SUCH DAMAGE.
32df8bae1dSRodney W. Grimes  *
33df8bae1dSRodney W. Grimes  *	@(#)kern_malloc.c	8.3 (Berkeley) 1/4/94
34df8bae1dSRodney W. Grimes  */
35df8bae1dSRodney W. Grimes 
36df8bae1dSRodney W. Grimes #include <sys/param.h>
3726f9a767SRodney W. Grimes #include <sys/systm.h>
38df8bae1dSRodney W. Grimes #include <sys/proc.h>
39df8bae1dSRodney W. Grimes #include <sys/map.h>
40df8bae1dSRodney W. Grimes #include <sys/kernel.h>
41df8bae1dSRodney W. Grimes #include <sys/malloc.h>
42df8bae1dSRodney W. Grimes 
43df8bae1dSRodney W. Grimes #include <vm/vm.h>
44df8bae1dSRodney W. Grimes #include <vm/vm_kern.h>
45df8bae1dSRodney W. Grimes 
46df8bae1dSRodney W. Grimes struct kmembuckets bucket[MINBUCKET + 16];
47df8bae1dSRodney W. Grimes struct kmemstats kmemstats[M_LAST];
48df8bae1dSRodney W. Grimes struct kmemusage *kmemusage;
49df8bae1dSRodney W. Grimes char *kmembase, *kmemlimit;
50df8bae1dSRodney W. Grimes char *memname[] = INITKMEMNAMES;
51df8bae1dSRodney W. Grimes 
52df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
53df8bae1dSRodney W. Grimes /*
54df8bae1dSRodney W. Grimes  * This structure provides a set of masks to catch unaligned frees.
55df8bae1dSRodney W. Grimes  */
56df8bae1dSRodney W. Grimes long addrmask[] = { 0,
57df8bae1dSRodney W. Grimes 	0x00000001, 0x00000003, 0x00000007, 0x0000000f,
58df8bae1dSRodney W. Grimes 	0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
59df8bae1dSRodney W. Grimes 	0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
60df8bae1dSRodney W. Grimes 	0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
61df8bae1dSRodney W. Grimes };
62df8bae1dSRodney W. Grimes 
63df8bae1dSRodney W. Grimes /*
64df8bae1dSRodney W. Grimes  * The WEIRD_ADDR is used as known text to copy into free objects so
65df8bae1dSRodney W. Grimes  * that modifications after frees can be detected.
66df8bae1dSRodney W. Grimes  */
67df8bae1dSRodney W. Grimes #define WEIRD_ADDR	0xdeadbeef
68df8bae1dSRodney W. Grimes #define MAX_COPY	32
69df8bae1dSRodney W. Grimes 
70df8bae1dSRodney W. Grimes /*
71df8bae1dSRodney W. Grimes  * Normally the first word of the structure is used to hold the list
72df8bae1dSRodney W. Grimes  * pointer for free objects. However, when running with diagnostics,
73df8bae1dSRodney W. Grimes  * we use the third and fourth fields, so as to catch modifications
74df8bae1dSRodney W. Grimes  * in the most commonly trashed first two words.
75df8bae1dSRodney W. Grimes  */
76df8bae1dSRodney W. Grimes struct freelist {
77df8bae1dSRodney W. Grimes 	long	spare0;
78df8bae1dSRodney W. Grimes 	short	type;
79df8bae1dSRodney W. Grimes 	long	spare1;
80df8bae1dSRodney W. Grimes 	caddr_t	next;
81df8bae1dSRodney W. Grimes };
82df8bae1dSRodney W. Grimes #else /* !DIAGNOSTIC */
83df8bae1dSRodney W. Grimes struct freelist {
84df8bae1dSRodney W. Grimes 	caddr_t	next;
85df8bae1dSRodney W. Grimes };
86df8bae1dSRodney W. Grimes #endif /* DIAGNOSTIC */
87df8bae1dSRodney W. Grimes 
88df8bae1dSRodney W. Grimes /*
89df8bae1dSRodney W. Grimes  * Allocate a block of memory
90df8bae1dSRodney W. Grimes  */
91df8bae1dSRodney W. Grimes void *
92df8bae1dSRodney W. Grimes malloc(size, type, flags)
93df8bae1dSRodney W. Grimes 	unsigned long size;
94df8bae1dSRodney W. Grimes 	int type, flags;
95df8bae1dSRodney W. Grimes {
96df8bae1dSRodney W. Grimes 	register struct kmembuckets *kbp;
97df8bae1dSRodney W. Grimes 	register struct kmemusage *kup;
98df8bae1dSRodney W. Grimes 	register struct freelist *freep;
99df8bae1dSRodney W. Grimes 	long indx, npg, allocsize;
100df8bae1dSRodney W. Grimes 	int s;
101df8bae1dSRodney W. Grimes 	caddr_t va, cp, savedlist;
102df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
103df8bae1dSRodney W. Grimes 	long *end, *lp;
104df8bae1dSRodney W. Grimes 	int copysize;
105df8bae1dSRodney W. Grimes 	char *savedtype;
106df8bae1dSRodney W. Grimes #endif
107df8bae1dSRodney W. Grimes #ifdef KMEMSTATS
108df8bae1dSRodney W. Grimes 	register struct kmemstats *ksp = &kmemstats[type];
109df8bae1dSRodney W. Grimes 
110df8bae1dSRodney W. Grimes 	if (((unsigned long)type) > M_LAST)
111df8bae1dSRodney W. Grimes 		panic("malloc - bogus type");
112df8bae1dSRodney W. Grimes #endif
113df8bae1dSRodney W. Grimes 	indx = BUCKETINDX(size);
114df8bae1dSRodney W. Grimes 	kbp = &bucket[indx];
115df8bae1dSRodney W. Grimes 	s = splimp();
116df8bae1dSRodney W. Grimes #ifdef KMEMSTATS
117df8bae1dSRodney W. Grimes 	while (ksp->ks_memuse >= ksp->ks_limit) {
118df8bae1dSRodney W. Grimes 		if (flags & M_NOWAIT) {
119df8bae1dSRodney W. Grimes 			splx(s);
120df8bae1dSRodney W. Grimes 			return ((void *) NULL);
121df8bae1dSRodney W. Grimes 		}
122df8bae1dSRodney W. Grimes 		if (ksp->ks_limblocks < 65535)
123df8bae1dSRodney W. Grimes 			ksp->ks_limblocks++;
124df8bae1dSRodney W. Grimes 		tsleep((caddr_t)ksp, PSWP+2, memname[type], 0);
125df8bae1dSRodney W. Grimes 	}
126df8bae1dSRodney W. Grimes 	ksp->ks_size |= 1 << indx;
127df8bae1dSRodney W. Grimes #endif
128df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
129df8bae1dSRodney W. Grimes 	copysize = 1 << indx < MAX_COPY ? 1 << indx : MAX_COPY;
130df8bae1dSRodney W. Grimes #endif
131df8bae1dSRodney W. Grimes 	if (kbp->kb_next == NULL) {
132df8bae1dSRodney W. Grimes 		kbp->kb_last = NULL;
133df8bae1dSRodney W. Grimes 		if (size > MAXALLOCSAVE)
134df8bae1dSRodney W. Grimes 			allocsize = roundup(size, CLBYTES);
135df8bae1dSRodney W. Grimes 		else
136df8bae1dSRodney W. Grimes 			allocsize = 1 << indx;
137df8bae1dSRodney W. Grimes 		npg = clrnd(btoc(allocsize));
138df8bae1dSRodney W. Grimes 		va = (caddr_t) kmem_malloc(kmem_map, (vm_size_t)ctob(npg),
139df8bae1dSRodney W. Grimes 					   !(flags & M_NOWAIT));
140df8bae1dSRodney W. Grimes 		if (va == NULL) {
141df8bae1dSRodney W. Grimes 			splx(s);
142df8bae1dSRodney W. Grimes 			return ((void *) NULL);
143df8bae1dSRodney W. Grimes 		}
144df8bae1dSRodney W. Grimes #ifdef KMEMSTATS
145df8bae1dSRodney W. Grimes 		kbp->kb_total += kbp->kb_elmpercl;
146df8bae1dSRodney W. Grimes #endif
147df8bae1dSRodney W. Grimes 		kup = btokup(va);
148df8bae1dSRodney W. Grimes 		kup->ku_indx = indx;
149df8bae1dSRodney W. Grimes 		if (allocsize > MAXALLOCSAVE) {
150df8bae1dSRodney W. Grimes 			if (npg > 65535)
151df8bae1dSRodney W. Grimes 				panic("malloc: allocation too large");
152df8bae1dSRodney W. Grimes 			kup->ku_pagecnt = npg;
153df8bae1dSRodney W. Grimes #ifdef KMEMSTATS
154df8bae1dSRodney W. Grimes 			ksp->ks_memuse += allocsize;
155df8bae1dSRodney W. Grimes #endif
156df8bae1dSRodney W. Grimes 			goto out;
157df8bae1dSRodney W. Grimes 		}
158df8bae1dSRodney W. Grimes #ifdef KMEMSTATS
159df8bae1dSRodney W. Grimes 		kup->ku_freecnt = kbp->kb_elmpercl;
160df8bae1dSRodney W. Grimes 		kbp->kb_totalfree += kbp->kb_elmpercl;
161df8bae1dSRodney W. Grimes #endif
162df8bae1dSRodney W. Grimes 		/*
163df8bae1dSRodney W. Grimes 		 * Just in case we blocked while allocating memory,
164df8bae1dSRodney W. Grimes 		 * and someone else also allocated memory for this
165df8bae1dSRodney W. Grimes 		 * bucket, don't assume the list is still empty.
166df8bae1dSRodney W. Grimes 		 */
167df8bae1dSRodney W. Grimes 		savedlist = kbp->kb_next;
168df8bae1dSRodney W. Grimes 		kbp->kb_next = cp = va + (npg * NBPG) - allocsize;
169df8bae1dSRodney W. Grimes 		for (;;) {
170df8bae1dSRodney W. Grimes 			freep = (struct freelist *)cp;
171df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
172df8bae1dSRodney W. Grimes 			/*
173df8bae1dSRodney W. Grimes 			 * Copy in known text to detect modification
174df8bae1dSRodney W. Grimes 			 * after freeing.
175df8bae1dSRodney W. Grimes 			 */
176df8bae1dSRodney W. Grimes 			end = (long *)&cp[copysize];
177df8bae1dSRodney W. Grimes 			for (lp = (long *)cp; lp < end; lp++)
178df8bae1dSRodney W. Grimes 				*lp = WEIRD_ADDR;
179df8bae1dSRodney W. Grimes 			freep->type = M_FREE;
180df8bae1dSRodney W. Grimes #endif /* DIAGNOSTIC */
181df8bae1dSRodney W. Grimes 			if (cp <= va)
182df8bae1dSRodney W. Grimes 				break;
183df8bae1dSRodney W. Grimes 			cp -= allocsize;
184df8bae1dSRodney W. Grimes 			freep->next = cp;
185df8bae1dSRodney W. Grimes 		}
186df8bae1dSRodney W. Grimes 		freep->next = savedlist;
187df8bae1dSRodney W. Grimes 		if (kbp->kb_last == NULL)
188df8bae1dSRodney W. Grimes 			kbp->kb_last = (caddr_t)freep;
189df8bae1dSRodney W. Grimes 	}
190df8bae1dSRodney W. Grimes 	va = kbp->kb_next;
191df8bae1dSRodney W. Grimes 	kbp->kb_next = ((struct freelist *)va)->next;
192df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
193df8bae1dSRodney W. Grimes 	freep = (struct freelist *)va;
194df8bae1dSRodney W. Grimes 	savedtype = (unsigned)freep->type < M_LAST ?
195df8bae1dSRodney W. Grimes 		memname[freep->type] : "???";
196df8bae1dSRodney W. Grimes 	if (kbp->kb_next &&
197df8bae1dSRodney W. Grimes 	    !kernacc(kbp->kb_next, sizeof(struct freelist), 0)) {
198df8bae1dSRodney W. Grimes 		printf("%s of object 0x%x size %d %s %s (invalid addr 0x%x)\n",
199df8bae1dSRodney W. Grimes 			"Data modified on freelist: word 2.5", va, size,
200df8bae1dSRodney W. Grimes 			"previous type", savedtype, kbp->kb_next);
201df8bae1dSRodney W. Grimes 		kbp->kb_next = NULL;
202df8bae1dSRodney W. Grimes 	}
203df8bae1dSRodney W. Grimes #if BYTE_ORDER == BIG_ENDIAN
204df8bae1dSRodney W. Grimes 	freep->type = WEIRD_ADDR >> 16;
205df8bae1dSRodney W. Grimes #endif
206df8bae1dSRodney W. Grimes #if BYTE_ORDER == LITTLE_ENDIAN
207df8bae1dSRodney W. Grimes 	freep->type = (short)WEIRD_ADDR;
208df8bae1dSRodney W. Grimes #endif
209df8bae1dSRodney W. Grimes 	if (((long)(&freep->next)) & 0x2)
210df8bae1dSRodney W. Grimes 		freep->next = (caddr_t)((WEIRD_ADDR >> 16)|(WEIRD_ADDR << 16));
211df8bae1dSRodney W. Grimes 	else
212df8bae1dSRodney W. Grimes 		freep->next = (caddr_t)WEIRD_ADDR;
213df8bae1dSRodney W. Grimes 	end = (long *)&va[copysize];
214df8bae1dSRodney W. Grimes 	for (lp = (long *)va; lp < end; lp++) {
215df8bae1dSRodney W. Grimes 		if (*lp == WEIRD_ADDR)
216df8bae1dSRodney W. Grimes 			continue;
217df8bae1dSRodney W. Grimes 		printf("%s %d of object 0x%x size %d %s %s (0x%x != 0x%x)\n",
218df8bae1dSRodney W. Grimes 			"Data modified on freelist: word", lp - (long *)va,
219df8bae1dSRodney W. Grimes 			va, size, "previous type", savedtype, *lp, WEIRD_ADDR);
220df8bae1dSRodney W. Grimes 		break;
221df8bae1dSRodney W. Grimes 	}
222df8bae1dSRodney W. Grimes 	freep->spare0 = 0;
223df8bae1dSRodney W. Grimes #endif /* DIAGNOSTIC */
224df8bae1dSRodney W. Grimes #ifdef KMEMSTATS
225df8bae1dSRodney W. Grimes 	kup = btokup(va);
226df8bae1dSRodney W. Grimes 	if (kup->ku_indx != indx)
227df8bae1dSRodney W. Grimes 		panic("malloc: wrong bucket");
228df8bae1dSRodney W. Grimes 	if (kup->ku_freecnt == 0)
229df8bae1dSRodney W. Grimes 		panic("malloc: lost data");
230df8bae1dSRodney W. Grimes 	kup->ku_freecnt--;
231df8bae1dSRodney W. Grimes 	kbp->kb_totalfree--;
232df8bae1dSRodney W. Grimes 	ksp->ks_memuse += 1 << indx;
233df8bae1dSRodney W. Grimes out:
234df8bae1dSRodney W. Grimes 	kbp->kb_calls++;
235df8bae1dSRodney W. Grimes 	ksp->ks_inuse++;
236df8bae1dSRodney W. Grimes 	ksp->ks_calls++;
237df8bae1dSRodney W. Grimes 	if (ksp->ks_memuse > ksp->ks_maxused)
238df8bae1dSRodney W. Grimes 		ksp->ks_maxused = ksp->ks_memuse;
239df8bae1dSRodney W. Grimes #else
240df8bae1dSRodney W. Grimes out:
241df8bae1dSRodney W. Grimes #endif
242df8bae1dSRodney W. Grimes 	splx(s);
243df8bae1dSRodney W. Grimes 	return ((void *) va);
244df8bae1dSRodney W. Grimes }
245df8bae1dSRodney W. Grimes 
246df8bae1dSRodney W. Grimes /*
247df8bae1dSRodney W. Grimes  * Free a block of memory allocated by malloc.
248df8bae1dSRodney W. Grimes  */
249df8bae1dSRodney W. Grimes void
250df8bae1dSRodney W. Grimes free(addr, type)
251df8bae1dSRodney W. Grimes 	void *addr;
252df8bae1dSRodney W. Grimes 	int type;
253df8bae1dSRodney W. Grimes {
254df8bae1dSRodney W. Grimes 	register struct kmembuckets *kbp;
255df8bae1dSRodney W. Grimes 	register struct kmemusage *kup;
256df8bae1dSRodney W. Grimes 	register struct freelist *freep;
257df8bae1dSRodney W. Grimes 	long size;
258df8bae1dSRodney W. Grimes 	int s;
259df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
260df8bae1dSRodney W. Grimes 	caddr_t cp;
261df8bae1dSRodney W. Grimes 	long *end, *lp, alloc, copysize;
262df8bae1dSRodney W. Grimes #endif
263df8bae1dSRodney W. Grimes #ifdef KMEMSTATS
264df8bae1dSRodney W. Grimes 	register struct kmemstats *ksp = &kmemstats[type];
265df8bae1dSRodney W. Grimes #endif
266df8bae1dSRodney W. Grimes 
267df8bae1dSRodney W. Grimes 	kup = btokup(addr);
268df8bae1dSRodney W. Grimes 	size = 1 << kup->ku_indx;
269df8bae1dSRodney W. Grimes 	kbp = &bucket[kup->ku_indx];
270df8bae1dSRodney W. Grimes 	s = splimp();
271df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
272df8bae1dSRodney W. Grimes 	/*
273df8bae1dSRodney W. Grimes 	 * Check for returns of data that do not point to the
274df8bae1dSRodney W. Grimes 	 * beginning of the allocation.
275df8bae1dSRodney W. Grimes 	 */
276df8bae1dSRodney W. Grimes 	if (size > NBPG * CLSIZE)
277df8bae1dSRodney W. Grimes 		alloc = addrmask[BUCKETINDX(NBPG * CLSIZE)];
278df8bae1dSRodney W. Grimes 	else
279df8bae1dSRodney W. Grimes 		alloc = addrmask[kup->ku_indx];
280df8bae1dSRodney W. Grimes 	if (((u_long)addr & alloc) != 0)
281df8bae1dSRodney W. Grimes 		panic("free: unaligned addr 0x%x, size %d, type %s, mask %d\n",
282df8bae1dSRodney W. Grimes 			addr, size, memname[type], alloc);
283df8bae1dSRodney W. Grimes #endif /* DIAGNOSTIC */
284df8bae1dSRodney W. Grimes 	if (size > MAXALLOCSAVE) {
285df8bae1dSRodney W. Grimes 		kmem_free(kmem_map, (vm_offset_t)addr, ctob(kup->ku_pagecnt));
286df8bae1dSRodney W. Grimes #ifdef KMEMSTATS
287df8bae1dSRodney W. Grimes 		size = kup->ku_pagecnt << PGSHIFT;
288df8bae1dSRodney W. Grimes 		ksp->ks_memuse -= size;
289df8bae1dSRodney W. Grimes 		kup->ku_indx = 0;
290df8bae1dSRodney W. Grimes 		kup->ku_pagecnt = 0;
291df8bae1dSRodney W. Grimes 		if (ksp->ks_memuse + size >= ksp->ks_limit &&
292df8bae1dSRodney W. Grimes 		    ksp->ks_memuse < ksp->ks_limit)
293df8bae1dSRodney W. Grimes 			wakeup((caddr_t)ksp);
294df8bae1dSRodney W. Grimes 		ksp->ks_inuse--;
295df8bae1dSRodney W. Grimes 		kbp->kb_total -= 1;
296df8bae1dSRodney W. Grimes #endif
297df8bae1dSRodney W. Grimes 		splx(s);
298df8bae1dSRodney W. Grimes 		return;
299df8bae1dSRodney W. Grimes 	}
300df8bae1dSRodney W. Grimes 	freep = (struct freelist *)addr;
301df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
302df8bae1dSRodney W. Grimes 	/*
303df8bae1dSRodney W. Grimes 	 * Check for multiple frees. Use a quick check to see if
304df8bae1dSRodney W. Grimes 	 * it looks free before laboriously searching the freelist.
305df8bae1dSRodney W. Grimes 	 */
306df8bae1dSRodney W. Grimes 	if (freep->spare0 == WEIRD_ADDR) {
307df8bae1dSRodney W. Grimes 		for (cp = kbp->kb_next; cp; cp = *(caddr_t *)cp) {
308df8bae1dSRodney W. Grimes 			if (addr != cp)
309df8bae1dSRodney W. Grimes 				continue;
310df8bae1dSRodney W. Grimes 			printf("multiply freed item 0x%x\n", addr);
311df8bae1dSRodney W. Grimes 			panic("free: duplicated free");
312df8bae1dSRodney W. Grimes 		}
313df8bae1dSRodney W. Grimes 	}
314df8bae1dSRodney W. Grimes 	/*
315df8bae1dSRodney W. Grimes 	 * Copy in known text to detect modification after freeing
316df8bae1dSRodney W. Grimes 	 * and to make it look free. Also, save the type being freed
317df8bae1dSRodney W. Grimes 	 * so we can list likely culprit if modification is detected
318df8bae1dSRodney W. Grimes 	 * when the object is reallocated.
319df8bae1dSRodney W. Grimes 	 */
320df8bae1dSRodney W. Grimes 	copysize = size < MAX_COPY ? size : MAX_COPY;
321df8bae1dSRodney W. Grimes 	end = (long *)&((caddr_t)addr)[copysize];
322df8bae1dSRodney W. Grimes 	for (lp = (long *)addr; lp < end; lp++)
323df8bae1dSRodney W. Grimes 		*lp = WEIRD_ADDR;
324df8bae1dSRodney W. Grimes 	freep->type = type;
325df8bae1dSRodney W. Grimes #endif /* DIAGNOSTIC */
326df8bae1dSRodney W. Grimes #ifdef KMEMSTATS
327df8bae1dSRodney W. Grimes 	kup->ku_freecnt++;
328df8bae1dSRodney W. Grimes 	if (kup->ku_freecnt >= kbp->kb_elmpercl)
329df8bae1dSRodney W. Grimes 		if (kup->ku_freecnt > kbp->kb_elmpercl)
330df8bae1dSRodney W. Grimes 			panic("free: multiple frees");
331df8bae1dSRodney W. Grimes 		else if (kbp->kb_totalfree > kbp->kb_highwat)
332df8bae1dSRodney W. Grimes 			kbp->kb_couldfree++;
333df8bae1dSRodney W. Grimes 	kbp->kb_totalfree++;
334df8bae1dSRodney W. Grimes 	ksp->ks_memuse -= size;
335df8bae1dSRodney W. Grimes 	if (ksp->ks_memuse + size >= ksp->ks_limit &&
336df8bae1dSRodney W. Grimes 	    ksp->ks_memuse < ksp->ks_limit)
337df8bae1dSRodney W. Grimes 		wakeup((caddr_t)ksp);
338df8bae1dSRodney W. Grimes 	ksp->ks_inuse--;
339df8bae1dSRodney W. Grimes #endif
340df8bae1dSRodney W. Grimes 	if (kbp->kb_next == NULL)
341df8bae1dSRodney W. Grimes 		kbp->kb_next = addr;
342df8bae1dSRodney W. Grimes 	else
343df8bae1dSRodney W. Grimes 		((struct freelist *)kbp->kb_last)->next = addr;
344df8bae1dSRodney W. Grimes 	freep->next = NULL;
345df8bae1dSRodney W. Grimes 	kbp->kb_last = addr;
346df8bae1dSRodney W. Grimes 	splx(s);
347df8bae1dSRodney W. Grimes }
348df8bae1dSRodney W. Grimes 
349df8bae1dSRodney W. Grimes /*
350df8bae1dSRodney W. Grimes  * Initialize the kernel memory allocator
351df8bae1dSRodney W. Grimes  */
35226f9a767SRodney W. Grimes void
353df8bae1dSRodney W. Grimes kmeminit()
354df8bae1dSRodney W. Grimes {
355df8bae1dSRodney W. Grimes 	register long indx;
356df8bae1dSRodney W. Grimes 	int npg;
357df8bae1dSRodney W. Grimes 
358df8bae1dSRodney W. Grimes #if	((MAXALLOCSAVE & (MAXALLOCSAVE - 1)) != 0)
359df8bae1dSRodney W. Grimes 		ERROR!_kmeminit:_MAXALLOCSAVE_not_power_of_2
360df8bae1dSRodney W. Grimes #endif
361df8bae1dSRodney W. Grimes #if	(MAXALLOCSAVE > MINALLOCSIZE * 32768)
362df8bae1dSRodney W. Grimes 		ERROR!_kmeminit:_MAXALLOCSAVE_too_big
363df8bae1dSRodney W. Grimes #endif
364df8bae1dSRodney W. Grimes #if	(MAXALLOCSAVE < CLBYTES)
365df8bae1dSRodney W. Grimes 		ERROR!_kmeminit:_MAXALLOCSAVE_too_small
366df8bae1dSRodney W. Grimes #endif
367df8bae1dSRodney W. Grimes 	npg = VM_KMEM_SIZE/ NBPG;
368df8bae1dSRodney W. Grimes 	kmemusage = (struct kmemusage *) kmem_alloc(kernel_map,
369df8bae1dSRodney W. Grimes 		(vm_size_t)(npg * sizeof(struct kmemusage)));
370df8bae1dSRodney W. Grimes 	kmem_map = kmem_suballoc(kernel_map, (vm_offset_t *)&kmembase,
371df8bae1dSRodney W. Grimes 		(vm_offset_t *)&kmemlimit, (vm_size_t)(npg * NBPG), FALSE);
372df8bae1dSRodney W. Grimes #ifdef KMEMSTATS
373df8bae1dSRodney W. Grimes 	for (indx = 0; indx < MINBUCKET + 16; indx++) {
374df8bae1dSRodney W. Grimes 		if (1 << indx >= CLBYTES)
375df8bae1dSRodney W. Grimes 			bucket[indx].kb_elmpercl = 1;
376df8bae1dSRodney W. Grimes 		else
377df8bae1dSRodney W. Grimes 			bucket[indx].kb_elmpercl = CLBYTES / (1 << indx);
378df8bae1dSRodney W. Grimes 		bucket[indx].kb_highwat = 5 * bucket[indx].kb_elmpercl;
379df8bae1dSRodney W. Grimes 	}
380df8bae1dSRodney W. Grimes 	for (indx = 0; indx < M_LAST; indx++)
381df8bae1dSRodney W. Grimes 		kmemstats[indx].ks_limit = npg * NBPG * 6 / 10;
382df8bae1dSRodney W. Grimes #endif
383df8bae1dSRodney W. Grimes }
384