7 * Uses the address space to do most of the hard work.
8 * The address space from mbegin to mend is scanned
9 * in order. Pages are allocated, used to fill successive
10 * malloc requests, and then left alone. Free decrements
11 * a ref count maintained in the page; the page is freed
12 * when the ref count hits zero.
14 * If we need to allocate a large amount (more than a page)
15 * we can't put a ref count at the end of each page,
16 * so we mark the pte entry with the bit PTE_CONTINUED.
20 MAXMALLOC
= 1024*1024 /* max size of one allocated chunk */
23 #define PTE_CONTINUED 0x400
25 static uint8_t *mbegin
= (uint8_t*) 0x08000000;
26 static uint8_t *mend
= (uint8_t*) 0x10000000;
30 isfree(void *v
, size_t n
)
32 uintptr_t va
, end_va
= (uintptr_t) v
+ n
;
34 for (va
= (uintptr_t) v
; va
< end_va
; va
+= PGSIZE
)
35 if (va
>= (uintptr_t) mend
36 || ((vpd
[PDX(va
)] & PTE_P
) && (vpt
[PGNUM(va
)] & PTE_P
)))
57 if ((uintptr_t) mptr
% PGSIZE
){
59 * we're in the middle of a partially
60 * allocated page - can we add this chunk?
61 * the +4 below is for the ref count.
63 ref
= (uint32_t*) (ROUNDUP(mptr
, PGSIZE
) - 4);
64 if ((uintptr_t) mptr
/ PGSIZE
== (uintptr_t) (mptr
+ n
- 1 + 4) / PGSIZE
) {
71 * stop working on this page and move on.
73 free(mptr
); /* drop reference to this page */
74 mptr
= ROUNDDOWN(mptr
+ PGSIZE
, PGSIZE
);
78 * now we need to find some address space for this chunk.
79 * if it's less than a page we leave it open for allocation.
80 * runs of more than a page can't have ref counts so we
81 * flag the PTE entries instead.
85 if (isfree(mptr
, n
+ 4))
91 return 0; /* out of address space */
96 * allocate at mptr - the +4 makes sure we allocate a ref count.
98 for (i
= 0; i
< n
+ 4; i
+= PGSIZE
){
99 cont
= (i
+ PGSIZE
< n
+ 4) ? PTE_CONTINUED
: 0;
100 if (sys_page_alloc(0, mptr
+ i
, PTE_P
|PTE_U
|PTE_W
|cont
) < 0){
101 for (; i
>= 0; i
-= PGSIZE
)
102 sys_page_unmap(0, mptr
+ i
);
103 return 0; /* out of physical memory */
107 ref
= (uint32_t*) (mptr
+ i
- 4);
108 *ref
= 2; /* reference for mptr, reference for returned block */
122 assert(mbegin
<= (uint8_t*) v
&& (uint8_t*) v
< mend
);
124 c
= ROUNDDOWN(v
, PGSIZE
);
126 while (vpt
[PGNUM(c
)] & PTE_CONTINUED
) {
127 sys_page_unmap(0, c
);
129 assert(mbegin
<= c
&& c
< mend
);
133 * c is just a piece of this page, so dec the ref count
134 * and maybe free the page.
136 ref
= (uint32_t*) (c
+ PGSIZE
- 4);
138 sys_page_unmap(0, c
);