xref: /minix3/minix/servers/vm/alloc.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1*433d6423SLionel Sambuc /* This file is concerned with allocating and freeing arbitrary-size blocks of
2*433d6423SLionel Sambuc  * physical memory.
3*433d6423SLionel Sambuc  */
4*433d6423SLionel Sambuc 
5*433d6423SLionel Sambuc #define _SYSTEM 1
6*433d6423SLionel Sambuc 
7*433d6423SLionel Sambuc #include <minix/com.h>
8*433d6423SLionel Sambuc #include <minix/callnr.h>
9*433d6423SLionel Sambuc #include <minix/type.h>
10*433d6423SLionel Sambuc #include <minix/config.h>
11*433d6423SLionel Sambuc #include <minix/const.h>
12*433d6423SLionel Sambuc #include <minix/sysutil.h>
13*433d6423SLionel Sambuc #include <minix/syslib.h>
14*433d6423SLionel Sambuc #include <minix/debug.h>
15*433d6423SLionel Sambuc #include <minix/bitmap.h>
16*433d6423SLionel Sambuc 
17*433d6423SLionel Sambuc #include <sys/mman.h>
18*433d6423SLionel Sambuc 
19*433d6423SLionel Sambuc #include <limits.h>
20*433d6423SLionel Sambuc #include <string.h>
21*433d6423SLionel Sambuc #include <errno.h>
22*433d6423SLionel Sambuc #include <assert.h>
23*433d6423SLionel Sambuc #include <memory.h>
24*433d6423SLionel Sambuc 
25*433d6423SLionel Sambuc #include "vm.h"
26*433d6423SLionel Sambuc #include "proto.h"
27*433d6423SLionel Sambuc #include "util.h"
28*433d6423SLionel Sambuc #include "glo.h"
29*433d6423SLionel Sambuc #include "sanitycheck.h"
30*433d6423SLionel Sambuc #include "memlist.h"
31*433d6423SLionel Sambuc 
32*433d6423SLionel Sambuc /* Number of physical pages in a 32-bit address space */
33*433d6423SLionel Sambuc #define NUMBER_PHYSICAL_PAGES (int)(0x100000000ULL/VM_PAGE_SIZE)
34*433d6423SLionel Sambuc #define PAGE_BITMAP_CHUNKS BITMAP_CHUNKS(NUMBER_PHYSICAL_PAGES)
35*433d6423SLionel Sambuc static bitchunk_t free_pages_bitmap[PAGE_BITMAP_CHUNKS];
36*433d6423SLionel Sambuc #define PAGE_CACHE_MAX 10000
37*433d6423SLionel Sambuc static int free_page_cache[PAGE_CACHE_MAX];
38*433d6423SLionel Sambuc static int free_page_cache_size = 0;
39*433d6423SLionel Sambuc 
40*433d6423SLionel Sambuc /* Used for sanity check. */
41*433d6423SLionel Sambuc static phys_bytes mem_low, mem_high;
42*433d6423SLionel Sambuc 
43*433d6423SLionel Sambuc static void free_pages(phys_bytes addr, int pages);
44*433d6423SLionel Sambuc static phys_bytes alloc_pages(int pages, int flags);
45*433d6423SLionel Sambuc 
46*433d6423SLionel Sambuc #if SANITYCHECKS
47*433d6423SLionel Sambuc struct {
48*433d6423SLionel Sambuc 	int used;
49*433d6423SLionel Sambuc 	const char *file;
50*433d6423SLionel Sambuc 	int line;
51*433d6423SLionel Sambuc } pagemap[NUMBER_PHYSICAL_PAGES];
52*433d6423SLionel Sambuc #endif
53*433d6423SLionel Sambuc 
54*433d6423SLionel Sambuc #define page_isfree(i) GET_BIT(free_pages_bitmap, i)
55*433d6423SLionel Sambuc 
56*433d6423SLionel Sambuc #define RESERVEDMAGIC		0x6e4c74d5
57*433d6423SLionel Sambuc #define MAXRESERVEDPAGES	300
58*433d6423SLionel Sambuc #define MAXRESERVEDQUEUES	 15
59*433d6423SLionel Sambuc 
60*433d6423SLionel Sambuc static struct reserved_pages {
61*433d6423SLionel Sambuc 	struct reserved_pages *next;	/* next in use */
62*433d6423SLionel Sambuc 	int max_available;	/* queue depth use, 0 if not in use at all */
63*433d6423SLionel Sambuc 	int npages;		/* number of consecutive pages */
64*433d6423SLionel Sambuc 	int mappedin;		/* must reserved pages also be mapped? */
65*433d6423SLionel Sambuc 	int n_available;	/* number of queue entries */
66*433d6423SLionel Sambuc 	int allocflags;		/* allocflags for alloc_mem */
67*433d6423SLionel Sambuc 	struct reserved_pageslot {
68*433d6423SLionel Sambuc 		phys_bytes	phys;
69*433d6423SLionel Sambuc 		void		*vir;
70*433d6423SLionel Sambuc 	} slots[MAXRESERVEDPAGES];
71*433d6423SLionel Sambuc 	u32_t magic;
72*433d6423SLionel Sambuc } reservedqueues[MAXRESERVEDQUEUES], *first_reserved_inuse = NULL;
73*433d6423SLionel Sambuc 
74*433d6423SLionel Sambuc int missing_spares = 0;
75*433d6423SLionel Sambuc 
sanitycheck_queues(void)76*433d6423SLionel Sambuc static void sanitycheck_queues(void)
77*433d6423SLionel Sambuc {
78*433d6423SLionel Sambuc 	struct reserved_pages *mrq;
79*433d6423SLionel Sambuc 	int m = 0;
80*433d6423SLionel Sambuc 
81*433d6423SLionel Sambuc 	for(mrq = first_reserved_inuse; mrq; mrq = mrq->next) {
82*433d6423SLionel Sambuc 		assert(mrq->max_available > 0);
83*433d6423SLionel Sambuc 		assert(mrq->max_available >= mrq->n_available);
84*433d6423SLionel Sambuc 		m += mrq->max_available - mrq->n_available;
85*433d6423SLionel Sambuc 	}
86*433d6423SLionel Sambuc 
87*433d6423SLionel Sambuc 	assert(m == missing_spares);
88*433d6423SLionel Sambuc }
89*433d6423SLionel Sambuc 
sanitycheck_rq(struct reserved_pages * rq)90*433d6423SLionel Sambuc static void sanitycheck_rq(struct reserved_pages *rq)
91*433d6423SLionel Sambuc {
92*433d6423SLionel Sambuc 	assert(rq->magic == RESERVEDMAGIC);
93*433d6423SLionel Sambuc 	assert(rq->n_available >= 0);
94*433d6423SLionel Sambuc 	assert(rq->n_available <= MAXRESERVEDPAGES);
95*433d6423SLionel Sambuc 	assert(rq->n_available <= rq->max_available);
96*433d6423SLionel Sambuc 
97*433d6423SLionel Sambuc 	sanitycheck_queues();
98*433d6423SLionel Sambuc }
99*433d6423SLionel Sambuc 
reservedqueue_new(int max_available,int npages,int mapped,int allocflags)100*433d6423SLionel Sambuc void *reservedqueue_new(int max_available, int npages, int mapped, int allocflags)
101*433d6423SLionel Sambuc {
102*433d6423SLionel Sambuc 	int r;
103*433d6423SLionel Sambuc 	struct reserved_pages *rq;
104*433d6423SLionel Sambuc 
105*433d6423SLionel Sambuc 	assert(max_available > 0);
106*433d6423SLionel Sambuc 	assert(max_available < MAXRESERVEDPAGES);
107*433d6423SLionel Sambuc 	assert(npages > 0);
108*433d6423SLionel Sambuc 	assert(npages < 10);
109*433d6423SLionel Sambuc 
110*433d6423SLionel Sambuc 	for(r = 0; r < MAXRESERVEDQUEUES; r++)
111*433d6423SLionel Sambuc 		if(!reservedqueues[r].max_available)
112*433d6423SLionel Sambuc 			break;
113*433d6423SLionel Sambuc 
114*433d6423SLionel Sambuc 	if(r >= MAXRESERVEDQUEUES) {
115*433d6423SLionel Sambuc 		printf("VM: %d reserved queues in use\n", MAXRESERVEDQUEUES);
116*433d6423SLionel Sambuc 		return NULL;
117*433d6423SLionel Sambuc 	}
118*433d6423SLionel Sambuc 
119*433d6423SLionel Sambuc 	rq = &reservedqueues[r];
120*433d6423SLionel Sambuc 
121*433d6423SLionel Sambuc 	memset(rq, 0, sizeof(*rq));
122*433d6423SLionel Sambuc 	rq->next = first_reserved_inuse;
123*433d6423SLionel Sambuc 	first_reserved_inuse = rq;
124*433d6423SLionel Sambuc 
125*433d6423SLionel Sambuc 	rq->max_available = max_available;
126*433d6423SLionel Sambuc 	rq->npages = npages;
127*433d6423SLionel Sambuc 	rq->mappedin = mapped;
128*433d6423SLionel Sambuc 	rq->allocflags = allocflags;
129*433d6423SLionel Sambuc 	rq->magic = RESERVEDMAGIC;
130*433d6423SLionel Sambuc 
131*433d6423SLionel Sambuc 	missing_spares += max_available;
132*433d6423SLionel Sambuc 
133*433d6423SLionel Sambuc 	return rq;
134*433d6423SLionel Sambuc }
135*433d6423SLionel Sambuc 
136*433d6423SLionel Sambuc static void
reservedqueue_fillslot(struct reserved_pages * rq,struct reserved_pageslot * rps,phys_bytes ph,void * vir)137*433d6423SLionel Sambuc reservedqueue_fillslot(struct reserved_pages *rq,
138*433d6423SLionel Sambuc 	struct reserved_pageslot *rps, phys_bytes ph, void *vir)
139*433d6423SLionel Sambuc {
140*433d6423SLionel Sambuc 	rps->phys = ph;
141*433d6423SLionel Sambuc 	rps->vir = vir;
142*433d6423SLionel Sambuc 	assert(missing_spares > 0);
143*433d6423SLionel Sambuc 	if(rq->mappedin) assert(vir);
144*433d6423SLionel Sambuc 	missing_spares--;
145*433d6423SLionel Sambuc 	rq->n_available++;
146*433d6423SLionel Sambuc }
147*433d6423SLionel Sambuc 
148*433d6423SLionel Sambuc static int
reservedqueue_addslot(struct reserved_pages * rq)149*433d6423SLionel Sambuc reservedqueue_addslot(struct reserved_pages *rq)
150*433d6423SLionel Sambuc {
151*433d6423SLionel Sambuc 	phys_bytes cl, cl_addr;
152*433d6423SLionel Sambuc 	void *vir;
153*433d6423SLionel Sambuc 	struct reserved_pageslot *rps;
154*433d6423SLionel Sambuc 
155*433d6423SLionel Sambuc 	sanitycheck_rq(rq);
156*433d6423SLionel Sambuc 
157*433d6423SLionel Sambuc 	if((cl = alloc_mem(rq->npages, rq->allocflags)) == NO_MEM)
158*433d6423SLionel Sambuc 		return ENOMEM;
159*433d6423SLionel Sambuc 
160*433d6423SLionel Sambuc 	cl_addr = CLICK2ABS(cl);
161*433d6423SLionel Sambuc 
162*433d6423SLionel Sambuc 	vir = NULL;
163*433d6423SLionel Sambuc 
164*433d6423SLionel Sambuc 	if(rq->mappedin) {
165*433d6423SLionel Sambuc 		if(!(vir = vm_mappages(cl_addr, rq->npages))) {
166*433d6423SLionel Sambuc 			free_mem(cl, rq->npages);
167*433d6423SLionel Sambuc 			printf("reservedqueue_addslot: vm_mappages failed\n");
168*433d6423SLionel Sambuc 			return ENOMEM;
169*433d6423SLionel Sambuc 		}
170*433d6423SLionel Sambuc 	}
171*433d6423SLionel Sambuc 
172*433d6423SLionel Sambuc 	rps = &rq->slots[rq->n_available];
173*433d6423SLionel Sambuc 
174*433d6423SLionel Sambuc 	reservedqueue_fillslot(rq, rps, cl_addr, vir);
175*433d6423SLionel Sambuc 
176*433d6423SLionel Sambuc 	return OK;
177*433d6423SLionel Sambuc }
178*433d6423SLionel Sambuc 
reservedqueue_add(void * rq_v,void * vir,phys_bytes ph)179*433d6423SLionel Sambuc void reservedqueue_add(void *rq_v, void *vir, phys_bytes ph)
180*433d6423SLionel Sambuc {
181*433d6423SLionel Sambuc 	struct reserved_pages *rq = rq_v;
182*433d6423SLionel Sambuc 	struct reserved_pageslot *rps;
183*433d6423SLionel Sambuc 
184*433d6423SLionel Sambuc 	sanitycheck_rq(rq);
185*433d6423SLionel Sambuc 
186*433d6423SLionel Sambuc 	rps = &rq->slots[rq->n_available];
187*433d6423SLionel Sambuc 
188*433d6423SLionel Sambuc 	reservedqueue_fillslot(rq, rps, ph, vir);
189*433d6423SLionel Sambuc }
190*433d6423SLionel Sambuc 
reservedqueue_fill(void * rq_v)191*433d6423SLionel Sambuc static int reservedqueue_fill(void *rq_v)
192*433d6423SLionel Sambuc {
193*433d6423SLionel Sambuc 	struct reserved_pages *rq = rq_v;
194*433d6423SLionel Sambuc 	int r;
195*433d6423SLionel Sambuc 
196*433d6423SLionel Sambuc 	sanitycheck_rq(rq);
197*433d6423SLionel Sambuc 
198*433d6423SLionel Sambuc 	while(rq->n_available < rq->max_available)
199*433d6423SLionel Sambuc 		if((r=reservedqueue_addslot(rq)) != OK)
200*433d6423SLionel Sambuc 			return r;
201*433d6423SLionel Sambuc 
202*433d6423SLionel Sambuc 	return OK;
203*433d6423SLionel Sambuc }
204*433d6423SLionel Sambuc 
205*433d6423SLionel Sambuc int
reservedqueue_alloc(void * rq_v,phys_bytes * ph,void ** vir)206*433d6423SLionel Sambuc reservedqueue_alloc(void *rq_v, phys_bytes *ph, void **vir)
207*433d6423SLionel Sambuc {
208*433d6423SLionel Sambuc 	struct reserved_pages *rq = rq_v;
209*433d6423SLionel Sambuc 	struct reserved_pageslot *rps;
210*433d6423SLionel Sambuc 
211*433d6423SLionel Sambuc 	sanitycheck_rq(rq);
212*433d6423SLionel Sambuc 
213*433d6423SLionel Sambuc 	if(rq->n_available < 1) return ENOMEM;
214*433d6423SLionel Sambuc 
215*433d6423SLionel Sambuc 	rq->n_available--;
216*433d6423SLionel Sambuc 	missing_spares++;
217*433d6423SLionel Sambuc 	rps = &rq->slots[rq->n_available];
218*433d6423SLionel Sambuc 
219*433d6423SLionel Sambuc 	*ph = rps->phys;
220*433d6423SLionel Sambuc 	*vir = rps->vir;
221*433d6423SLionel Sambuc 
222*433d6423SLionel Sambuc 	sanitycheck_rq(rq);
223*433d6423SLionel Sambuc 
224*433d6423SLionel Sambuc 	return OK;
225*433d6423SLionel Sambuc }
226*433d6423SLionel Sambuc 
alloc_cycle(void)227*433d6423SLionel Sambuc void alloc_cycle(void)
228*433d6423SLionel Sambuc {
229*433d6423SLionel Sambuc 	struct reserved_pages *rq;
230*433d6423SLionel Sambuc 	sanitycheck_queues();
231*433d6423SLionel Sambuc 	for(rq = first_reserved_inuse; rq && missing_spares > 0; rq = rq->next) {
232*433d6423SLionel Sambuc 		sanitycheck_rq(rq);
233*433d6423SLionel Sambuc 		reservedqueue_fill(rq);
234*433d6423SLionel Sambuc 		sanitycheck_rq(rq);
235*433d6423SLionel Sambuc 	}
236*433d6423SLionel Sambuc 	sanitycheck_queues();
237*433d6423SLionel Sambuc }
238*433d6423SLionel Sambuc 
239*433d6423SLionel Sambuc /*===========================================================================*
240*433d6423SLionel Sambuc  *				alloc_mem				     *
241*433d6423SLionel Sambuc  *===========================================================================*/
alloc_mem(phys_clicks clicks,u32_t memflags)242*433d6423SLionel Sambuc phys_clicks alloc_mem(phys_clicks clicks, u32_t memflags)
243*433d6423SLionel Sambuc {
244*433d6423SLionel Sambuc /* Allocate a block of memory from the free list using first fit. The block
245*433d6423SLionel Sambuc  * consists of a sequence of contiguous bytes, whose length in clicks is
246*433d6423SLionel Sambuc  * given by 'clicks'.  A pointer to the block is returned.  The block is
247*433d6423SLionel Sambuc  * always on a click boundary.  This procedure is called when memory is
248*433d6423SLionel Sambuc  * needed for FORK or EXEC.
249*433d6423SLionel Sambuc  */
250*433d6423SLionel Sambuc   phys_clicks mem = NO_MEM, align_clicks = 0;
251*433d6423SLionel Sambuc 
252*433d6423SLionel Sambuc   if(memflags & PAF_ALIGN64K) {
253*433d6423SLionel Sambuc   	align_clicks = (64 * 1024) / CLICK_SIZE;
254*433d6423SLionel Sambuc 	clicks += align_clicks;
255*433d6423SLionel Sambuc   } else if(memflags & PAF_ALIGN16K) {
256*433d6423SLionel Sambuc 	align_clicks = (16 * 1024) / CLICK_SIZE;
257*433d6423SLionel Sambuc 	clicks += align_clicks;
258*433d6423SLionel Sambuc   }
259*433d6423SLionel Sambuc 
260*433d6423SLionel Sambuc   do {
261*433d6423SLionel Sambuc 	mem = alloc_pages(clicks, memflags);
262*433d6423SLionel Sambuc   } while(mem == NO_MEM && cache_freepages(clicks) > 0);
263*433d6423SLionel Sambuc 
264*433d6423SLionel Sambuc   if(mem == NO_MEM)
265*433d6423SLionel Sambuc   	return mem;
266*433d6423SLionel Sambuc 
267*433d6423SLionel Sambuc   if(align_clicks) {
268*433d6423SLionel Sambuc   	phys_clicks o;
269*433d6423SLionel Sambuc   	o = mem % align_clicks;
270*433d6423SLionel Sambuc   	if(o > 0) {
271*433d6423SLionel Sambuc   		phys_clicks e;
272*433d6423SLionel Sambuc   		e = align_clicks - o;
273*433d6423SLionel Sambuc 	  	free_mem(mem, e);
274*433d6423SLionel Sambuc 	  	mem += e;
275*433d6423SLionel Sambuc 	}
276*433d6423SLionel Sambuc   }
277*433d6423SLionel Sambuc 
278*433d6423SLionel Sambuc   return mem;
279*433d6423SLionel Sambuc }
280*433d6423SLionel Sambuc 
mem_add_total_pages(int pages)281*433d6423SLionel Sambuc void mem_add_total_pages(int pages)
282*433d6423SLionel Sambuc {
283*433d6423SLionel Sambuc 	total_pages += pages;
284*433d6423SLionel Sambuc }
285*433d6423SLionel Sambuc 
286*433d6423SLionel Sambuc /*===========================================================================*
287*433d6423SLionel Sambuc  *				free_mem				     *
288*433d6423SLionel Sambuc  *===========================================================================*/
free_mem(phys_clicks base,phys_clicks clicks)289*433d6423SLionel Sambuc void free_mem(phys_clicks base, phys_clicks clicks)
290*433d6423SLionel Sambuc {
291*433d6423SLionel Sambuc /* Return a block of free memory to the hole list.  The parameters tell where
292*433d6423SLionel Sambuc  * the block starts in physical memory and how big it is.  The block is added
293*433d6423SLionel Sambuc  * to the hole list.  If it is contiguous with an existing hole on either end,
294*433d6423SLionel Sambuc  * it is merged with the hole or holes.
295*433d6423SLionel Sambuc  */
296*433d6423SLionel Sambuc   if (clicks == 0) return;
297*433d6423SLionel Sambuc 
298*433d6423SLionel Sambuc   assert(CLICK_SIZE == VM_PAGE_SIZE);
299*433d6423SLionel Sambuc   free_pages(base, clicks);
300*433d6423SLionel Sambuc   return;
301*433d6423SLionel Sambuc }
302*433d6423SLionel Sambuc 
303*433d6423SLionel Sambuc /*===========================================================================*
304*433d6423SLionel Sambuc  *				mem_init				     *
305*433d6423SLionel Sambuc  *===========================================================================*/
mem_init(struct memory * chunks)306*433d6423SLionel Sambuc void mem_init(struct memory *chunks)
307*433d6423SLionel Sambuc {
308*433d6423SLionel Sambuc /* Initialize hole lists.  There are two lists: 'hole_head' points to a linked
309*433d6423SLionel Sambuc  * list of all the holes (unused memory) in the system; 'free_slots' points to
310*433d6423SLionel Sambuc  * a linked list of table entries that are not in use.  Initially, the former
311*433d6423SLionel Sambuc  * list has one entry for each chunk of physical memory, and the second
312*433d6423SLionel Sambuc  * list links together the remaining table slots.  As memory becomes more
313*433d6423SLionel Sambuc  * fragmented in the course of time (i.e., the initial big holes break up into
314*433d6423SLionel Sambuc  * smaller holes), new table slots are needed to represent them.  These slots
315*433d6423SLionel Sambuc  * are taken from the list headed by 'free_slots'.
316*433d6423SLionel Sambuc  */
317*433d6423SLionel Sambuc   int i, first = 0;
318*433d6423SLionel Sambuc 
319*433d6423SLionel Sambuc   total_pages = 0;
320*433d6423SLionel Sambuc 
321*433d6423SLionel Sambuc   memset(free_pages_bitmap, 0, sizeof(free_pages_bitmap));
322*433d6423SLionel Sambuc 
323*433d6423SLionel Sambuc   /* Use the chunks of physical memory to allocate holes. */
324*433d6423SLionel Sambuc   for (i=NR_MEMS-1; i>=0; i--) {
325*433d6423SLionel Sambuc   	if (chunks[i].size > 0) {
326*433d6423SLionel Sambuc 		phys_bytes from = CLICK2ABS(chunks[i].base),
327*433d6423SLionel Sambuc 			to = CLICK2ABS(chunks[i].base+chunks[i].size)-1;
328*433d6423SLionel Sambuc 		if(first || from < mem_low) mem_low = from;
329*433d6423SLionel Sambuc 		if(first || to > mem_high) mem_high = to;
330*433d6423SLionel Sambuc 		free_mem(chunks[i].base, chunks[i].size);
331*433d6423SLionel Sambuc 		total_pages += chunks[i].size;
332*433d6423SLionel Sambuc 		first = 0;
333*433d6423SLionel Sambuc 	}
334*433d6423SLionel Sambuc   }
335*433d6423SLionel Sambuc }
336*433d6423SLionel Sambuc 
337*433d6423SLionel Sambuc #if SANITYCHECKS
mem_sanitycheck(const char * file,int line)338*433d6423SLionel Sambuc void mem_sanitycheck(const char *file, int line)
339*433d6423SLionel Sambuc {
340*433d6423SLionel Sambuc 	int i;
341*433d6423SLionel Sambuc 	for(i = 0; i < NUMBER_PHYSICAL_PAGES; i++) {
342*433d6423SLionel Sambuc 		if(!page_isfree(i)) continue;
343*433d6423SLionel Sambuc 		MYASSERT(usedpages_add(i * VM_PAGE_SIZE, VM_PAGE_SIZE) == OK);
344*433d6423SLionel Sambuc 	}
345*433d6423SLionel Sambuc }
346*433d6423SLionel Sambuc #endif
347*433d6423SLionel Sambuc 
memstats(int * nodes,int * pages,int * largest)348*433d6423SLionel Sambuc void memstats(int *nodes, int *pages, int *largest)
349*433d6423SLionel Sambuc {
350*433d6423SLionel Sambuc 	int i;
351*433d6423SLionel Sambuc 	*nodes = 0;
352*433d6423SLionel Sambuc 	*pages = 0;
353*433d6423SLionel Sambuc 	*largest = 0;
354*433d6423SLionel Sambuc 
355*433d6423SLionel Sambuc 	for(i = 0; i < NUMBER_PHYSICAL_PAGES; i++) {
356*433d6423SLionel Sambuc 		int size = 0;
357*433d6423SLionel Sambuc 		while(i < NUMBER_PHYSICAL_PAGES && page_isfree(i)) {
358*433d6423SLionel Sambuc 			size++;
359*433d6423SLionel Sambuc 			i++;
360*433d6423SLionel Sambuc 		}
361*433d6423SLionel Sambuc 		if(size == 0) continue;
362*433d6423SLionel Sambuc 		(*nodes)++;
363*433d6423SLionel Sambuc 		(*pages)+= size;
364*433d6423SLionel Sambuc 		if(size > *largest)
365*433d6423SLionel Sambuc 			*largest = size;
366*433d6423SLionel Sambuc 	}
367*433d6423SLionel Sambuc }
368*433d6423SLionel Sambuc 
findbit(int low,int startscan,int pages,int memflags,int * len)369*433d6423SLionel Sambuc static int findbit(int low, int startscan, int pages, int memflags, int *len)
370*433d6423SLionel Sambuc {
371*433d6423SLionel Sambuc 	int run_length = 0, i;
372*433d6423SLionel Sambuc 	int freerange_start = startscan;
373*433d6423SLionel Sambuc 
374*433d6423SLionel Sambuc 	for(i = startscan; i >= low; i--) {
375*433d6423SLionel Sambuc 		if(!page_isfree(i)) {
376*433d6423SLionel Sambuc 			int pi;
377*433d6423SLionel Sambuc 			int chunk = i/BITCHUNK_BITS, moved = 0;
378*433d6423SLionel Sambuc 			run_length = 0;
379*433d6423SLionel Sambuc 			pi = i;
380*433d6423SLionel Sambuc 			while(chunk > 0 &&
381*433d6423SLionel Sambuc 			   !MAP_CHUNK(free_pages_bitmap, chunk*BITCHUNK_BITS)) {
382*433d6423SLionel Sambuc 				chunk--;
383*433d6423SLionel Sambuc 				moved = 1;
384*433d6423SLionel Sambuc 			}
385*433d6423SLionel Sambuc 			if(moved) { i = chunk * BITCHUNK_BITS + BITCHUNK_BITS; }
386*433d6423SLionel Sambuc 			continue;
387*433d6423SLionel Sambuc 		}
388*433d6423SLionel Sambuc 		if(!run_length) { freerange_start = i; run_length = 1; }
389*433d6423SLionel Sambuc 		else { freerange_start--; run_length++; }
390*433d6423SLionel Sambuc 		assert(run_length <= pages);
391*433d6423SLionel Sambuc 		if(run_length == pages) {
392*433d6423SLionel Sambuc 			/* good block found! */
393*433d6423SLionel Sambuc 			*len = run_length;
394*433d6423SLionel Sambuc 			return freerange_start;
395*433d6423SLionel Sambuc 		}
396*433d6423SLionel Sambuc 	}
397*433d6423SLionel Sambuc 
398*433d6423SLionel Sambuc 	return NO_MEM;
399*433d6423SLionel Sambuc }
400*433d6423SLionel Sambuc 
401*433d6423SLionel Sambuc /*===========================================================================*
402*433d6423SLionel Sambuc  *				alloc_pages				     *
403*433d6423SLionel Sambuc  *===========================================================================*/
alloc_pages(int pages,int memflags)404*433d6423SLionel Sambuc static phys_bytes alloc_pages(int pages, int memflags)
405*433d6423SLionel Sambuc {
406*433d6423SLionel Sambuc 	phys_bytes boundary16 = 16 * 1024 * 1024 / VM_PAGE_SIZE;
407*433d6423SLionel Sambuc 	phys_bytes boundary1  =  1 * 1024 * 1024 / VM_PAGE_SIZE;
408*433d6423SLionel Sambuc 	phys_bytes mem = NO_MEM, i;	/* page number */
409*433d6423SLionel Sambuc 	int maxpage = NUMBER_PHYSICAL_PAGES - 1;
410*433d6423SLionel Sambuc 	static int lastscan = -1;
411*433d6423SLionel Sambuc 	int startscan, run_length;
412*433d6423SLionel Sambuc 
413*433d6423SLionel Sambuc 	if(memflags & PAF_LOWER16MB)
414*433d6423SLionel Sambuc 		maxpage = boundary16 - 1;
415*433d6423SLionel Sambuc 	else if(memflags & PAF_LOWER1MB)
416*433d6423SLionel Sambuc 		maxpage = boundary1 - 1;
417*433d6423SLionel Sambuc 	else {
418*433d6423SLionel Sambuc 		/* no position restrictions: check page cache */
419*433d6423SLionel Sambuc 		if(pages == 1) {
420*433d6423SLionel Sambuc 			while(free_page_cache_size > 0) {
421*433d6423SLionel Sambuc 				i = free_page_cache[free_page_cache_size-1];
422*433d6423SLionel Sambuc 				if(page_isfree(i)) {
423*433d6423SLionel Sambuc 					free_page_cache_size--;
424*433d6423SLionel Sambuc 					mem = i;
425*433d6423SLionel Sambuc 					assert(mem != NO_MEM);
426*433d6423SLionel Sambuc 					run_length = 1;
427*433d6423SLionel Sambuc 					break;
428*433d6423SLionel Sambuc 				}
429*433d6423SLionel Sambuc 				free_page_cache_size--;
430*433d6423SLionel Sambuc 			}
431*433d6423SLionel Sambuc 		}
432*433d6423SLionel Sambuc 	}
433*433d6423SLionel Sambuc 
434*433d6423SLionel Sambuc 	if(lastscan < maxpage && lastscan >= 0)
435*433d6423SLionel Sambuc 		startscan = lastscan;
436*433d6423SLionel Sambuc 	else	startscan = maxpage;
437*433d6423SLionel Sambuc 
438*433d6423SLionel Sambuc 	if(mem == NO_MEM)
439*433d6423SLionel Sambuc 		mem = findbit(0, startscan, pages, memflags, &run_length);
440*433d6423SLionel Sambuc 	if(mem == NO_MEM)
441*433d6423SLionel Sambuc 		mem = findbit(0, maxpage, pages, memflags, &run_length);
442*433d6423SLionel Sambuc 	if(mem == NO_MEM)
443*433d6423SLionel Sambuc 		return NO_MEM;
444*433d6423SLionel Sambuc 
445*433d6423SLionel Sambuc 	/* remember for next time */
446*433d6423SLionel Sambuc 	lastscan = mem;
447*433d6423SLionel Sambuc 
448*433d6423SLionel Sambuc 	for(i = mem; i < mem + pages; i++) {
449*433d6423SLionel Sambuc 		UNSET_BIT(free_pages_bitmap, i);
450*433d6423SLionel Sambuc 	}
451*433d6423SLionel Sambuc 
452*433d6423SLionel Sambuc 	if(memflags & PAF_CLEAR) {
453*433d6423SLionel Sambuc 		int s;
454*433d6423SLionel Sambuc 		if ((s= sys_memset(NONE, 0, CLICK_SIZE*mem,
455*433d6423SLionel Sambuc 			VM_PAGE_SIZE*pages)) != OK)
456*433d6423SLionel Sambuc 			panic("alloc_mem: sys_memset failed: %d", s);
457*433d6423SLionel Sambuc 	}
458*433d6423SLionel Sambuc 
459*433d6423SLionel Sambuc 	return mem;
460*433d6423SLionel Sambuc }
461*433d6423SLionel Sambuc 
462*433d6423SLionel Sambuc /*===========================================================================*
463*433d6423SLionel Sambuc  *				free_pages				     *
464*433d6423SLionel Sambuc  *===========================================================================*/
free_pages(phys_bytes pageno,int npages)465*433d6423SLionel Sambuc static void free_pages(phys_bytes pageno, int npages)
466*433d6423SLionel Sambuc {
467*433d6423SLionel Sambuc 	int i, lim = pageno + npages - 1;
468*433d6423SLionel Sambuc 
469*433d6423SLionel Sambuc #if JUNKFREE
470*433d6423SLionel Sambuc        if(sys_memset(NONE, 0xa5a5a5a5, VM_PAGE_SIZE * pageno,
471*433d6423SLionel Sambuc                VM_PAGE_SIZE * npages) != OK)
472*433d6423SLionel Sambuc                        panic("free_pages: sys_memset failed");
473*433d6423SLionel Sambuc #endif
474*433d6423SLionel Sambuc 
475*433d6423SLionel Sambuc 	for(i = pageno; i <= lim; i++) {
476*433d6423SLionel Sambuc 		SET_BIT(free_pages_bitmap, i);
477*433d6423SLionel Sambuc 		if(free_page_cache_size < PAGE_CACHE_MAX) {
478*433d6423SLionel Sambuc 			free_page_cache[free_page_cache_size++] = i;
479*433d6423SLionel Sambuc 		}
480*433d6423SLionel Sambuc 	}
481*433d6423SLionel Sambuc }
482*433d6423SLionel Sambuc 
483*433d6423SLionel Sambuc /*===========================================================================*
484*433d6423SLionel Sambuc  *				printmemstats				     *
485*433d6423SLionel Sambuc  *===========================================================================*/
printmemstats(void)486*433d6423SLionel Sambuc void printmemstats(void)
487*433d6423SLionel Sambuc {
488*433d6423SLionel Sambuc 	int nodes, pages, largest;
489*433d6423SLionel Sambuc         memstats(&nodes, &pages, &largest);
490*433d6423SLionel Sambuc         printf("%d blocks, %d pages (%lukB) free, largest %d pages (%lukB)\n",
491*433d6423SLionel Sambuc                 nodes, pages, (unsigned long) pages * (VM_PAGE_SIZE/1024),
492*433d6423SLionel Sambuc 		largest, (unsigned long) largest * (VM_PAGE_SIZE/1024));
493*433d6423SLionel Sambuc }
494*433d6423SLionel Sambuc 
495*433d6423SLionel Sambuc 
496*433d6423SLionel Sambuc #if SANITYCHECKS
497*433d6423SLionel Sambuc 
498*433d6423SLionel Sambuc /*===========================================================================*
499*433d6423SLionel Sambuc  *				usedpages_reset				     *
500*433d6423SLionel Sambuc  *===========================================================================*/
usedpages_reset(void)501*433d6423SLionel Sambuc void usedpages_reset(void)
502*433d6423SLionel Sambuc {
503*433d6423SLionel Sambuc 	memset(pagemap, 0, sizeof(pagemap));
504*433d6423SLionel Sambuc }
505*433d6423SLionel Sambuc 
506*433d6423SLionel Sambuc /*===========================================================================*
507*433d6423SLionel Sambuc  *				usedpages_add				     *
508*433d6423SLionel Sambuc  *===========================================================================*/
usedpages_add_f(phys_bytes addr,phys_bytes len,const char * file,int line)509*433d6423SLionel Sambuc int usedpages_add_f(phys_bytes addr, phys_bytes len, const char *file, int line)
510*433d6423SLionel Sambuc {
511*433d6423SLionel Sambuc 	u32_t pagestart, pages;
512*433d6423SLionel Sambuc 
513*433d6423SLionel Sambuc 	if(!incheck)
514*433d6423SLionel Sambuc 		return OK;
515*433d6423SLionel Sambuc 
516*433d6423SLionel Sambuc 	assert(!(addr % VM_PAGE_SIZE));
517*433d6423SLionel Sambuc 	assert(!(len % VM_PAGE_SIZE));
518*433d6423SLionel Sambuc 	assert(len > 0);
519*433d6423SLionel Sambuc 
520*433d6423SLionel Sambuc 	pagestart = addr / VM_PAGE_SIZE;
521*433d6423SLionel Sambuc 	pages = len / VM_PAGE_SIZE;
522*433d6423SLionel Sambuc 
523*433d6423SLionel Sambuc 	while(pages > 0) {
524*433d6423SLionel Sambuc 		phys_bytes thisaddr;
525*433d6423SLionel Sambuc 		assert(pagestart > 0);
526*433d6423SLionel Sambuc 		assert(pagestart < NUMBER_PHYSICAL_PAGES);
527*433d6423SLionel Sambuc 		thisaddr = pagestart * VM_PAGE_SIZE;
528*433d6423SLionel Sambuc 		assert(pagestart < NUMBER_PHYSICAL_PAGES);
529*433d6423SLionel Sambuc 		if(pagemap[pagestart].used) {
530*433d6423SLionel Sambuc 			static int warnings = 0;
531*433d6423SLionel Sambuc 			if(warnings++ < 100)
532*433d6423SLionel Sambuc 				printf("%s:%d: usedpages_add: addr 0x%lx reused, first %s:%d\n",
533*433d6423SLionel Sambuc 					file, line, thisaddr, pagemap[pagestart].file, pagemap[pagestart].line);
534*433d6423SLionel Sambuc 			util_stacktrace();
535*433d6423SLionel Sambuc 			return EFAULT;
536*433d6423SLionel Sambuc 		}
537*433d6423SLionel Sambuc 		pagemap[pagestart].used = 1;
538*433d6423SLionel Sambuc 		pagemap[pagestart].file = file;
539*433d6423SLionel Sambuc 		pagemap[pagestart].line = line;
540*433d6423SLionel Sambuc 		pages--;
541*433d6423SLionel Sambuc 		pagestart++;
542*433d6423SLionel Sambuc 	}
543*433d6423SLionel Sambuc 
544*433d6423SLionel Sambuc 	return OK;
545*433d6423SLionel Sambuc }
546*433d6423SLionel Sambuc 
547*433d6423SLionel Sambuc #endif
548*433d6423SLionel Sambuc 
549