root / Whitix / branches / hybrid / memory / pg_alloc.c

Revision 540, 6.1 kB (checked in by mwhitworth, 3 months ago)

Update APIs.

Line 
1/*  This file is part of Whitix.
2 *
3 *  Whitix is free software; you can redistribute it and/or modify
4 *  it under the terms of the GNU General Public License as published by
5 *  the Free Software Foundation; either version 2 of the License, or
6 *  (at your option) any later version.
7 *
8 *  Whitix is distributed in the hope that it will be useful,
9 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 *  GNU General Public License for more details.
12 *
13 *  You should have received a copy of the GNU General Public License
14 *  along with Whitix; if not, write to the Free Software
15 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
16 *
17 */
18
19/*
20 * Should be updated soon to be more efficent. Perhaps a mixture of stack and
21 * bitmaps? The Linux idea of zones for ISA DMA and normal memory also sounds
22 * like a good idea. i386 specific at the moment.
23 */
24
25#include <bitmap.h>
26#include <pg_alloc.h>
27#include <i386/i386.h>
28#include <i386/virtual.h>
29#include <vmm.h>
30#include <string.h>
31#include <console.h>
32#include <sections.h>
33#include <module.h>
34#include <panic.h>
35
36static BYTE* allocatedBitmap;
37DWORD maxPfn;
38WaitQueue* waitQueues;
39
40/* Each consists of all pages, although some allocated ones are not added to the list in the first place */
41struct PageStack
42{
43        DWORD numPages; /* that are available */
44        DWORD maxPages;
45        struct ListHead list; /* Use singly-linked list! */
46        WaitQueue* waitQueues;
47};
48
49static struct PageStack normal;
50static struct PageStack isa;
51
52#define PSTACK_START_ADDRESS 0x100000
53struct PhysPage* pageArrayPtr=(struct PhysPage*)(PSTACK_START_ADDRESS);
54
55/* Called by PhysInit so that it can reserve pages */
56int PageEarlyInit(DWORD endPfn)
57{
58        DWORD endAddress,numBytes;
59
60        maxPfn=endPfn;
61
62        /* Set up a bitmap, right at the end of the physical memory so we can track reservations */
63        endAddress=(maxPfn << PAGE_SHIFT);
64        numBytes=((maxPfn+7)/8);
65        endAddress-=numBytes;
66        allocatedBitmap=(BYTE*)endAddress;
67        ZeroMemory(allocatedBitmap,numBytes);
68
69        /* Reserve the first page of memory. Important structures may be stored there. */
70        PageReserveArea(0, PAGE_SIZE);
71
72        /* Reserve pages like the kernel's code and data. */
73        PageReserveArea((DWORD)code,(DWORD)end-(DWORD)code);
74
75        /* Reserve the page stack - each page has it's own structure */
76        PageReserveArea((DWORD)PSTACK_START_ADDRESS, maxPfn*sizeof(struct PhysPage));
77       
78        /* And the waitqueues */
79        PageReserveArea((DWORD)PAGE_ALIGN_UP((PSTACK_START_ADDRESS+(maxPfn*sizeof(struct PhysPage)))),((maxPfn+1023) >> 10)*sizeof(WaitQueue));
80
81        return 0;
82}
83
84int PageInit()
85{
86        /*
87         * Create 2 stacks of pages. The disadvantage is that it uses quite a lot of memory,
88         * maximum 4mb for a system with 4gb. But it's the speediest method possible.
89         */
90
91        DWORD i;
92        struct PhysPage* pageArray=pageArrayPtr;
93
94        isa.maxPages=(maxPfn > 4096 ? 4096 : maxPfn); /* If there's more than 16mb, cut it down to 16mb for the ISA page stack */
95        isa.numPages=0;
96        INIT_LIST_HEAD(&isa.list);
97        for (i=0; i<isa.maxPages; i++)
98        {
99                /* Free, can push onto stack */
100                pageArray[i].physAddr=i << 12;
101                if (!BmapGetBit(allocatedBitmap,i))
102                {
103                        ListAdd(&pageArray[i].list,&isa.list);
104                        ++isa.numPages;
105                }
106        }
107
108        normal.numPages=0;
109        INIT_LIST_HEAD(&normal.list);
110
111        if (isa.maxPages < maxPfn) /* i.e. less than 16mb of memory */
112        {
113                normal.maxPages=maxPfn-4096;
114                /* Go through normal memory and it's bitmap and push onto stack */
115                for (i=4096; i<maxPfn; i++)
116                {
117                        pageArray[i].physAddr=i << 12;
118                        /* Don't need the allocation bitmap for 16mb - not really used */
119                        ListAdd(&pageArray[i].list,&normal.list);
120                        ++normal.numPages;
121                }
122        }
123
124        KePrint("Number of ISA DMA pages = %u, number available = %u\nNumber of normal memory pages = %u, number available = %u\n",isa.maxPages,isa.numPages,normal.maxPages,normal.numPages);
125        allocatedBitmap=NULL; /* Can't reserve anymore */
126
127        /* Allocate the waitqueues */
128        waitQueues=(WaitQueue*)PAGE_ALIGN_UP((PSTACK_START_ADDRESS+(maxPfn*sizeof(struct PhysPage))));
129
130        for (i=0; i<((maxPfn+1023) >> 10); i++)
131                INIT_WAITQUEUE_HEAD(&waitQueues[i]);
132
133        return 0;
134}
135
136struct PhysPage* PageListGetHead(struct PageStack* stack)
137{
138        struct PhysPage* page;
139        DWORD flags;
140       
141        IrqSaveFlags(flags);
142
143        page=ListEntry(stack->list.next,struct PhysPage,list);
144        --stack->numPages;
145        ListRemove(stack->list.next);
146        page->refs=1;
147
148        IrqRestoreFlags(flags);
149
150        return page;
151}
152
153struct PhysPage* PageGetStruct(DWORD address)
154{
155        return &pageArrayPtr[address >> 12];
156}
157
158SYMBOL_EXPORT(PageGetStruct);
159
160struct PhysPage* PageAlloc()
161{
162        struct PhysPage* page;
163
164        /* Allocate from the normal page stack first, and then the ISA stack */
165        if (normal.numPages)
166                page=PageListGetHead(&normal);
167        else
168                page=PageAllocLow();
169
170        return page;
171}
172
173SYMBOL_EXPORT(PageAlloc);
174
175struct PhysPage* PageAllocLow()
176{
177        /* Just allocate from the ISA stack */
178        if (!isa.numPages)
179                KernelPanic("System out of memory");
180
181        return PageListGetHead(&isa);
182}
183
184SYMBOL_EXPORT(PageAllocLow);
185
186void PageListPutPage(struct PageStack* stack,struct PhysPage* page)
187{
188        DWORD flags;
189        IrqSaveFlags(flags);
190
191        page->refs=0;
192        ++stack->numPages;
193        ListAdd(&page->list,&stack->list);
194
195        IrqRestoreFlags(flags);
196}
197
198void PageFree(struct PhysPage* page)
199{
200        DWORD pagePfn=page->physAddr >> 12;
201
202        if (pagePfn > 4096) /* Normal */
203        {
204                if (pagePfn >= (normal.maxPages+4096))
205                {
206                        KePrint("PageFree : illegal free\n");
207                        return;
208                }
209
210                PageListPutPage(&normal,page);
211        }else{ /* ISA */
212                if (pagePfn >= isa.maxPages)
213                {
214                        KePrint("PageFree : isa illegal free\n");
215                        return;
216                }
217
218                PageListPutPage(&isa,page);
219        }
220}
221
222SYMBOL_EXPORT(PageFree);
223
224/* Used by bootup code to reserve an area of memory so it isn't added to the page stack */
225
226void PageReserveArea(DWORD start,DWORD size)
227{
228        start=PAGE_ALIGN(start);
229        size=PAGE_ALIGN_UP(size);
230
231        if (!allocatedBitmap) /* Err, someone's reserving memory after the bitmap's gone */
232        {
233                KePrint("PageReserveArea: can't reserve memory!\n");
234                MachineHalt();
235        }
236
237        /* Set all the pages as allocated */
238        while (size)
239        {
240                BmapSetBit(allocatedBitmap,(start >> 12),true);
241                start+=PAGE_SIZE;
242                size-=PAGE_SIZE;
243        }
244}
245
246
247WaitQueue* PageGetWaitQueue(struct PhysPage* page)
248{
249        return &waitQueues[page->physAddr >> 22];
250}
251
252SYMBOL_EXPORT(PageGetWaitQueue);
Note: See TracBrowser for help on using the browser.