summaryrefslogtreecommitdiffstats
path: root/private/ntos/boot/veneer/vrmalloc.c
blob: c0872f2546dd2c60f669a17af50a22b9cd19a229 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
/*
 *
 * Copyright 1994 FirmWorks, Mountain View CA USA. All rights reserved.
 * Copyright (c) 1995 FirePower Systems, Inc.
 *
 * $RCSfile: vrmalloc.c $
 * $Revision: 1.6 $
 * $Date: 1996/02/17 00:41:29 $
 * $Locker:  $
 *
 *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * A  "smarter" malloc				William L. Sebok
 *						Sept. 24, 1984
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *	 If n = the size of an area rounded DOWN to the nearest power of two,
 *	all free areas of memory whose length is the same index n is organized
 *	into a chain with other free areas of index n. A request for memory
 *	takes the first item in the chain whose index is the size of the
 *	request rounded UP to the nearest power of two.  If this chain is
 *	empty the next higher chain is examined.  If no larger chain has memory
 *	then new memory is allocated.  Only the amount of new memory needed is
 *	allocated.  Any old free memory left after an allocation is returned
 *	to the free list.  Extra new memory returned because of rounding
 *	to page boundaries is returned to free list.
 *
 *	  All memory areas (free or busy) handled by malloc are also chained
 *	sequentially by increasing address.  When memory is freed it is
 *	merged with adjacent free areas, if any.  If a free area of memory
 *	ends at the end of memory (i.e. at the break),  the break is
 *	contracted, freeing the memory back to the system.
 *
 *	Notes:
 *		ov_length field includes sizeof(struct overhead)
 *		adjacency chain includes all memory, allocated plus free.
 */

#include "veneer.h"

#define	MAGIC_FREE	0x548a934c
#define	MAGIC_BUSY	0xc139569a

#define NBUCKETS	24
#define NALIGN		4

struct qelem {
	struct qelem *q_forw;
	struct qelem *q_back;
};

struct overhead {
	struct qelem	ov_adj;		/* adjacency chain pointers */
	struct qelem	ov_buk;		/* bucket chain pointers */
	long		ov_magic;
	unsigned long	ov_length;
};

char endfree = 0;
struct qelem adjhead = { &adjhead, &adjhead };
struct qelem buckets[NBUCKETS] = {
	&buckets[0],  &buckets[0],
	&buckets[1],  &buckets[1],
	&buckets[2],  &buckets[2],
	&buckets[3],  &buckets[3],
	&buckets[4],  &buckets[4],
	&buckets[5],  &buckets[5],
	&buckets[6],  &buckets[6],
	&buckets[7],  &buckets[7],
	&buckets[8],  &buckets[8],
	&buckets[9],  &buckets[9],
	&buckets[10], &buckets[10],
	&buckets[11], &buckets[11],
	&buckets[12], &buckets[12],
	&buckets[13], &buckets[13],
	&buckets[14], &buckets[14],
	&buckets[15], &buckets[15],
	&buckets[16], &buckets[16],
	&buckets[17], &buckets[17],
	&buckets[18], &buckets[18],
	&buckets[19], &buckets[19],
	&buckets[20], &buckets[20],
	&buckets[21], &buckets[21],
	&buckets[22], &buckets[22],
	&buckets[23], &buckets[23],
};

/*
 * The following macros depend on the order of the elements in struct overhead
 */
#define TOADJ(p)	((struct qelem *)(p))
#define FROMADJ(p)	((struct overhead *)(p))
#define FROMBUK(p)	((struct overhead *)( (char *)p - sizeof(struct qelem)))
#define TOBUK(p)	((struct qelem *)( (char *)p + sizeof(struct qelem)))

#ifndef CURBRK
#define CURBRK	sbrk(0)
#endif CURBRK

STATIC void insque(), remque();

#ifdef	NULL
#undef  NULL
#endif
#define NULL	0
#ifdef debug
# define ASSERT(p,q)	if (!(p)) fatal(q)
#else
# define ASSERT(p,q)
#endif

#define ALIGN(n, granule)  ((n + ((granule)-1)) & ~((granule)-1))

char *
malloc(nbytes)
	unsigned nbytes;
{
	register struct overhead *p, *q;
	register int surplus = 0;
	register struct qelem *bucket;
	nbytes = ALIGN(nbytes, NALIGN) + sizeof(struct overhead);
	bucket = &buckets[log2(nbytes-1) + 1];	/* log2 rounded up */
	for (p = NULL; bucket < &buckets[NBUCKETS]; bucket++) {
		if (bucket->q_forw != bucket) {
			/*  remove from bucket chain */
			p = FROMBUK(bucket->q_forw);
			ASSERT(p->ov_magic == MAGIC_FREE, "\nmalloc: Entry \
not marked FREE found on Free List!\n");
			remque(TOBUK(p));
			surplus = p->ov_length - nbytes;
			break;
		}
	}
	if (p == NULL) {
#ifdef USE_SBRK
		register int i;
		p = (struct overhead *)CURBRK;
		if ((int)p == -1) {
			return(NULL);
		}
		if (i = (int)p&(NALIGN-1)) {
			sbrk(NALIGN-i);
		}
		p = (struct overhead *)sbrk(nbytes);
		if ((int)p == -1) {
			return(NULL);
		}
		q = (struct overhead *)CURBRK;
		if ((int)q == -1) {
			return(NULL);
		}
		p->ov_length = (char *)q - (char *)p;
		surplus = p->ov_length - nbytes;
		/* add to end of adjacency chain */
		ASSERT((FROMADJ(adjhead.q_back)) < p, "\nmalloc: Entry in \
adjacency chain found with address lower than Chain head!\n" );
		insque(TOADJ(p),adjhead.q_back);
#else
		struct qelem *pp;
		int alloc_size = ALIGN(nbytes, PAGE_SIZE);

		p = (struct overhead *)alloc(alloc_size, NALIGN);
		if ((int)p == -1) {
			return(NULL);
		}
		p->ov_length = alloc_size;
		surplus = p->ov_length - nbytes;

		/* add to adjacency chain in the correct place */
		for (pp = adjhead.q_forw; pp != &adjhead; pp = pp->q_forw) {
			if (p < FROMADJ(pp)) {
				break;
			}
		}
		ASSERT(pp == &adjhead || (p < FROMADJ(pp)),
		       "\nmalloc: Bogus insertion in adjacency list\n");
		insque(TOADJ(p),pp->q_back);
#endif
	}
	if (surplus > sizeof(struct overhead)) {
		/* if big enough, split it up */
		q = (struct overhead *)( (char *)p + nbytes);
		q->ov_length = surplus;
		p->ov_length = nbytes;
		q->ov_magic = MAGIC_FREE;
		/* add surplus into adjacency chain */
		insque(TOADJ(q),TOADJ(p));
		/* add surplus into bucket chain */
		insque(TOBUK(q),&buckets[log2(surplus)]);
	}
	p->ov_magic = MAGIC_BUSY;
	return((char*)p + sizeof(struct overhead));
}

void
free(mem)
register char *mem;
{
	register struct overhead *p, *q;
	if (mem == NULL) {
		return;
	}
	p = (struct overhead *)(mem - sizeof(struct overhead));
	if (p->ov_magic == MAGIC_FREE) {
		return;
	}
	if (p->ov_magic != MAGIC_BUSY) {
		fatal("attempt to free memory not allocated with malloc!\n");
	}
	q = FROMADJ((TOADJ(p))->q_back);
	if (q != FROMADJ(&adjhead)) {	/* q is not the first list item */
		ASSERT(q < p, "\nfree: While trying to merge a free area with \
a lower adjacent free area,\n addresses were found out of order!\n");
		/* If lower segment can be merged */
		if ((q->ov_magic == MAGIC_FREE) &&
							((char *)q + q->ov_length == (char *)p) ) {

			/* remove lower address area from bucket chain */
			remque(TOBUK(q));
			/* remove upper address area from adjacency chain */
			remque(TOADJ(p));
			q->ov_length += p->ov_length;
			p->ov_magic = NULL;
			p = q;
		}
	}
	q = FROMADJ((TOADJ(p))->q_forw);
	if (q != FROMADJ(&adjhead)) {	/* q is not the last list item */
		/* upper segment can be merged */
		ASSERT(q > p, "\nfree: While trying to merge a free area with \
a higher adjacent free area,\n addresses were found out of order!\n");
		if ( 	(q->ov_magic == MAGIC_FREE) &&
							((char *)p + p->ov_length == (char *)q) ) {

			/* remove upper from bucket chain */
			remque(TOBUK(q));
			/* remove upper from adjacency chain */
			remque(TOADJ(q));
			p->ov_length += q->ov_length;
			q->ov_magic = NULL;
		}
	}
#ifdef USE_SBRK
	/* freed area is at end of memory */
	if ((endfree && adjhead.q_back == TOADJ(p)) &&
						((char*)p + p->ov_length == (char *)CURBRK) ) {

		/* remove from end of adjacency chain */
		remque(adjhead.q_back);
		/* release memory to system */
		sbrk( -((int)(p->ov_length)));
		return;
	}
#endif
	p->ov_magic = MAGIC_FREE;
	/* place in bucket chain */
	insque(TOBUK(p),&buckets[log2(p->ov_length)]);
	return;
}

char *
realloc(mem,nbytes)
register char *mem; unsigned nbytes;
{
	register char *newmem;
	register struct overhead *p, *q;
	register int surplus;
	if (mem == NULL) {
		return(malloc(nbytes));
	}
	if(mem > (char*)FROMADJ(adjhead.q_back) + sizeof(struct overhead)) {
		return(NULL);
	}
	
	p = (struct overhead *)(mem - sizeof(struct overhead));
	nbytes = (nbytes + (NALIGN-1)) & (~(NALIGN-1));
	if (  (p->ov_magic == MAGIC_BUSY) && (q = FROMADJ(adjhead.q_back)) != p
	   && (q->ov_magic != MAGIC_FREE || (FROMADJ(q->ov_adj.q_back) != p)) ) {

		free(mem);
	}
	if( (p->ov_magic == MAGIC_BUSY || p->ov_magic == MAGIC_FREE)
	 && (surplus = p->ov_length - nbytes - sizeof(struct overhead)) >= 0 ) {
		if (surplus > sizeof(struct overhead)) {
			/*  return surplus to free list */
			nbytes += sizeof(struct overhead);
#ifdef USE_SBRK
			/* freed area is at end of memory */
			if ( endfree && adjhead.q_back == TOADJ(p)
			  &&	(char*)p + p->ov_length == (char *)CURBRK ) {
				/* release memory to system */
				sbrk(-surplus);
			} else
#endif
			{
				q = (struct overhead *)( (char *)p + nbytes);
				q->ov_length = surplus;
				q->ov_magic = MAGIC_FREE;
				insque(TOADJ(q),TOADJ(p));
				insque(TOBUK(q),&buckets[log2(surplus)]);
			}
			p->ov_length = nbytes;
		}
		if (p->ov_magic == MAGIC_FREE) {
			remque(TOBUK(p));
			p->ov_magic = MAGIC_BUSY;
		}
		return(mem);
	}
	newmem = malloc(nbytes);
	if (newmem != mem && newmem != NULL) {
		register unsigned n;
		if (p->ov_magic == MAGIC_BUSY || p->ov_magic == MAGIC_FREE) {
			n = p->ov_length - sizeof(struct overhead);
			nbytes = (nbytes < n) ? nbytes : n ;
		}
		bcopy(mem,newmem,nbytes);
	}
	if (p->ov_magic == MAGIC_BUSY) {
		free(mem);
	}
	return(newmem);
}

log2(n)
register int n;
{
	register int i = 0;
	while ((n >>= 1) > 0) {
		i++;
	}
	return(i);
}

void
insque(item,queu)
register struct qelem *item, *queu;
{
	register struct qelem *pueu;
	pueu = queu->q_forw;
	item->q_forw = pueu;
	item->q_back = queu;
	queu->q_forw = item;
	pueu->q_back = item;
}

void
remque(item)
register struct qelem *item;
{
	register struct qelem *queu, *pueu;
	pueu = item->q_forw;
	queu = item->q_back;
	queu->q_forw = pueu;
	pueu->q_back = queu;
}