2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: mkernel/mm/freelist.cc
5 * PURPOSE: Handle the list of free physical pages
6 * PROGRAMMER: David Welch (welch@mcmail.com)
9 * 18/08/98: Added a fix from Robert Bergkvist
13 * NOTE: The list of free pages is implemented as an unsorted double linked
14 * list. This should make added or removing pages fast when you don't care
15 * about the physical address. Because the entirety of physical memory is
16 * mapped from 0xd0000000 upwards it is easy to do a mapping between
17 * physical and linear address.
20 /* INCLUDES ****************************************************************/
22 #include <internal/stddef.h>
23 #include <internal/hal/page.h>
24 #include <internal/mm.h>
25 #include <internal/kernel.h>
26 #include <internal/bitops.h>
27 #include <ddk/ntddk.h>
30 #include <internal/debug.h>
32 /* TYPES *******************************************************************/
34 typedef struct _free_page
36 * PURPOSE: At the start of every region of free physical pages
39 struct _free_page
* next
;
40 struct _free_page
* previous
;
41 unsigned int nr_pages
;
44 /* GLOBALS ****************************************************************/
47 * PURPOSE: Points to the first page in the free list
49 free_page_hdr
* free_page_list_head
=NULL
;
51 /* FUNCTIONS *************************************************************/
53 void free_page(unsigned int physical_base
, unsigned int nr
)
55 * FUNCTION: Add a physically continuous range of pages to the free list
57 * physical_base = The first physical address to free
58 * nr = the size of the region (in pages) to free
59 * NOTES: This function attempts to keep the list partially unfragmented
63 free_page_hdr
* hdr
=NULL
;
65 DPRINT("Freeing %x to %x\n",physical_base
,physical_base
71 __asm__("pushf\n\tpop %0\n\tcli\n\t"
77 hdr
= (free_page_hdr
*)physical_to_linear(physical_base
);
79 DPRINT("free_page_hdr %x\n",hdr
);
80 DPRINT("free_page_list_head %x\n",free_page_list_head
);
82 if (free_page_list_head
!=NULL
)
84 free_page_list_head
->previous
=hdr
;
86 hdr
->next
=free_page_list_head
;
89 free_page_list_head
=hdr
;
91 __asm__("push %0\n\tpopf\n\t"
96 unsigned int get_dma_page(unsigned int max_address
)
98 * FUNCTION: Gets a page with a restricted max physical address (i.e.
101 * max_address = The maximum address usable by the caller
103 * The physical address of the page if it succeeds
105 * NOTES: This is very inefficent because the list isn't sorted. On the
106 * other hand sorting the list would be quite expensive especially if dma
107 * is only used infrequently. Perhaps a special cache of dma pages should
111 free_page_hdr
* current
=NULL
;
113 if (free_page_list_head
==NULL
)
115 printk("CRITICAL: Unable to allocate page\n");
116 KeBugCheck(KBUG_OUT_OF_MEMORY
);
120 * Walk the free page list looking for suitable memory
122 current
= free_page_list_head
;
123 while (current
!=NULL
)
125 if ( ((int)current
) < max_address
)
128 * We take the first page from the region
130 free_page_hdr
* nhdr
= (free_page_hdr
*)(((int)current
)+PAGESIZE
);
131 if (current
->previous
!=NULL
)
133 current
->previous
->next
=nhdr
;
135 if (current
->next
!=NULL
)
137 current
->next
->previous
=nhdr
;
139 nhdr
->next
=current
->next
;
140 nhdr
->previous
=current
->previous
;
141 nhdr
->nr_pages
=current
->nr_pages
-1;
142 if (free_page_list_head
==current
)
144 free_page_list_head
=nhdr
;
147 return ((int)current
);
150 current
=current
->next
;
155 unsigned int get_free_page(void)
157 * FUNCTION: Allocates a page
158 * RETURNS: The physical address of the page allocated
164 * This must be atomic wrt everything
167 __asm__("pushf\n\tpop %0\n\tcli\n\t"
171 * If we are totally out of memory then panic
173 if (free_page_list_head
==NULL
)
175 printk("CRITICAL: Unable to allocate page\n");
176 KeBugCheck(KBUG_OUT_OF_MEMORY
);
181 if (free_page_list_head
->nr_pages
>1)
183 free_page_list_head
->nr_pages
--;
184 addr
= ((unsigned int)free_page_list_head
) +
185 (free_page_list_head
->nr_pages
* PAGESIZE
);
189 addr
= (unsigned int)free_page_list_head
;
190 free_page_list_head
= free_page_list_head
-> next
;
193 __asm__("push %0\n\tpopf\n\t"
197 addr
= addr
- (IDMAP_BASE
);
198 DPRINT("allocated %x\n",addr
);