Merge branch 'fix/hda' into for-linus
[pandora-kernel.git] / arch / um / kernel / mem.c
1 /*
2  * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
3  * Licensed under the GPL
4  */
5
6 #include <linux/stddef.h>
7 #include <linux/bootmem.h>
8 #include <linux/highmem.h>
9 #include <linux/mm.h>
10 #include <linux/swap.h>
11 #include <linux/slab.h>
12 #include <asm/fixmap.h>
13 #include <asm/page.h>
14 #include "as-layout.h"
15 #include "init.h"
16 #include "kern.h"
17 #include "kern_util.h"
18 #include "mem_user.h"
19 #include "os.h"
20
21 /* allocated in paging_init, zeroed in mem_init, and unchanged thereafter */
22 unsigned long *empty_zero_page = NULL;
23 /* allocated in paging_init and unchanged thereafter */
24 static unsigned long *empty_bad_page = NULL;
25
26 /*
27  * Initialized during boot, and readonly for initializing page tables
28  * afterwards
29  */
30 pgd_t swapper_pg_dir[PTRS_PER_PGD];
31
32 /* Initialized at boot time, and readonly after that */
33 unsigned long long highmem;
34 int kmalloc_ok = 0;
35
36 /* Used during early boot */
37 static unsigned long brk_end;
38
39 #ifdef CONFIG_HIGHMEM
40 static void setup_highmem(unsigned long highmem_start,
41                           unsigned long highmem_len)
42 {
43         struct page *page;
44         unsigned long highmem_pfn;
45         int i;
46
47         highmem_pfn = __pa(highmem_start) >> PAGE_SHIFT;
48         for (i = 0; i < highmem_len >> PAGE_SHIFT; i++) {
49                 page = &mem_map[highmem_pfn + i];
50                 ClearPageReserved(page);
51                 init_page_count(page);
52                 __free_page(page);
53         }
54 }
55 #endif
56
57 void __init mem_init(void)
58 {
59         /* clear the zero-page */
60         memset(empty_zero_page, 0, PAGE_SIZE);
61
62         /* Map in the area just after the brk now that kmalloc is about
63          * to be turned on.
64          */
65         brk_end = (unsigned long) UML_ROUND_UP(sbrk(0));
66         map_memory(brk_end, __pa(brk_end), uml_reserved - brk_end, 1, 1, 0);
67         free_bootmem(__pa(brk_end), uml_reserved - brk_end);
68         uml_reserved = brk_end;
69
70         /* this will put all low memory onto the freelists */
71         totalram_pages = free_all_bootmem();
72         max_low_pfn = totalram_pages;
73 #ifdef CONFIG_HIGHMEM
74         totalhigh_pages = highmem >> PAGE_SHIFT;
75         totalram_pages += totalhigh_pages;
76 #endif
77         num_physpages = totalram_pages;
78         max_pfn = totalram_pages;
79         printk(KERN_INFO "Memory: %luk available\n",
80                nr_free_pages() << (PAGE_SHIFT-10));
81         kmalloc_ok = 1;
82
83 #ifdef CONFIG_HIGHMEM
84         setup_highmem(end_iomem, highmem);
85 #endif
86 }
87
88 /*
89  * Create a page table and place a pointer to it in a middle page
90  * directory entry.
91  */
92 static void __init one_page_table_init(pmd_t *pmd)
93 {
94         if (pmd_none(*pmd)) {
95                 pte_t *pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
96                 set_pmd(pmd, __pmd(_KERNPG_TABLE +
97                                            (unsigned long) __pa(pte)));
98                 if (pte != pte_offset_kernel(pmd, 0))
99                         BUG();
100         }
101 }
102
103 static void __init one_md_table_init(pud_t *pud)
104 {
105 #ifdef CONFIG_3_LEVEL_PGTABLES
106         pmd_t *pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE);
107         set_pud(pud, __pud(_KERNPG_TABLE + (unsigned long) __pa(pmd_table)));
108         if (pmd_table != pmd_offset(pud, 0))
109                 BUG();
110 #endif
111 }
112
113 static void __init fixrange_init(unsigned long start, unsigned long end,
114                                  pgd_t *pgd_base)
115 {
116         pgd_t *pgd;
117         pud_t *pud;
118         pmd_t *pmd;
119         int i, j;
120         unsigned long vaddr;
121
122         vaddr = start;
123         i = pgd_index(vaddr);
124         j = pmd_index(vaddr);
125         pgd = pgd_base + i;
126
127         for ( ; (i < PTRS_PER_PGD) && (vaddr < end); pgd++, i++) {
128                 pud = pud_offset(pgd, vaddr);
129                 if (pud_none(*pud))
130                         one_md_table_init(pud);
131                 pmd = pmd_offset(pud, vaddr);
132                 for (; (j < PTRS_PER_PMD) && (vaddr < end); pmd++, j++) {
133                         one_page_table_init(pmd);
134                         vaddr += PMD_SIZE;
135                 }
136                 j = 0;
137         }
138 }
139
140 #ifdef CONFIG_HIGHMEM
141 pte_t *kmap_pte;
142 pgprot_t kmap_prot;
143
144 #define kmap_get_fixmap_pte(vaddr)                                      \
145         pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr), (vaddr)),\
146                                      (vaddr)), (vaddr))
147
148 static void __init kmap_init(void)
149 {
150         unsigned long kmap_vstart;
151
152         /* cache the first kmap pte */
153         kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN);
154         kmap_pte = kmap_get_fixmap_pte(kmap_vstart);
155
156         kmap_prot = PAGE_KERNEL;
157 }
158
159 static void __init init_highmem(void)
160 {
161         pgd_t *pgd;
162         pud_t *pud;
163         pmd_t *pmd;
164         pte_t *pte;
165         unsigned long vaddr;
166
167         /*
168          * Permanent kmaps:
169          */
170         vaddr = PKMAP_BASE;
171         fixrange_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, swapper_pg_dir);
172
173         pgd = swapper_pg_dir + pgd_index(vaddr);
174         pud = pud_offset(pgd, vaddr);
175         pmd = pmd_offset(pud, vaddr);
176         pte = pte_offset_kernel(pmd, vaddr);
177         pkmap_page_table = pte;
178
179         kmap_init();
180 }
181 #endif /* CONFIG_HIGHMEM */
182
183 static void __init fixaddr_user_init( void)
184 {
185 #ifdef CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA
186         long size = FIXADDR_USER_END - FIXADDR_USER_START;
187         pgd_t *pgd;
188         pud_t *pud;
189         pmd_t *pmd;
190         pte_t *pte;
191         phys_t p;
192         unsigned long v, vaddr = FIXADDR_USER_START;
193
194         if (!size)
195                 return;
196
197         fixrange_init( FIXADDR_USER_START, FIXADDR_USER_END, swapper_pg_dir);
198         v = (unsigned long) alloc_bootmem_low_pages(size);
199         memcpy((void *) v , (void *) FIXADDR_USER_START, size);
200         p = __pa(v);
201         for ( ; size > 0; size -= PAGE_SIZE, vaddr += PAGE_SIZE,
202                       p += PAGE_SIZE) {
203                 pgd = swapper_pg_dir + pgd_index(vaddr);
204                 pud = pud_offset(pgd, vaddr);
205                 pmd = pmd_offset(pud, vaddr);
206                 pte = pte_offset_kernel(pmd, vaddr);
207                 pte_set_val(*pte, p, PAGE_READONLY);
208         }
209 #endif
210 }
211
212 void __init paging_init(void)
213 {
214         unsigned long zones_size[MAX_NR_ZONES], vaddr;
215         int i;
216
217         empty_zero_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE);
218         empty_bad_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE);
219         for (i = 0; i < ARRAY_SIZE(zones_size); i++)
220                 zones_size[i] = 0;
221
222         zones_size[ZONE_NORMAL] = (end_iomem >> PAGE_SHIFT) -
223                 (uml_physmem >> PAGE_SHIFT);
224 #ifdef CONFIG_HIGHMEM
225         zones_size[ZONE_HIGHMEM] = highmem >> PAGE_SHIFT;
226 #endif
227         free_area_init(zones_size);
228
229         /*
230          * Fixed mappings, only the page table structure has to be
231          * created - mappings will be set by set_fixmap():
232          */
233         vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK;
234         fixrange_init(vaddr, FIXADDR_TOP, swapper_pg_dir);
235
236         fixaddr_user_init();
237
238 #ifdef CONFIG_HIGHMEM
239         init_highmem();
240 #endif
241 }
242
243 /*
244  * This can't do anything because nothing in the kernel image can be freed
245  * since it's not in kernel physical memory.
246  */
247
248 void free_initmem(void)
249 {
250 }
251
252 #ifdef CONFIG_BLK_DEV_INITRD
253 void free_initrd_mem(unsigned long start, unsigned long end)
254 {
255         if (start < end)
256                 printk(KERN_INFO "Freeing initrd memory: %ldk freed\n",
257                        (end - start) >> 10);
258         for (; start < end; start += PAGE_SIZE) {
259                 ClearPageReserved(virt_to_page(start));
260                 init_page_count(virt_to_page(start));
261                 free_page(start);
262                 totalram_pages++;
263         }
264 }
265 #endif
266
267 /* Allocate and free page tables. */
268
269 pgd_t *pgd_alloc(struct mm_struct *mm)
270 {
271         pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL);
272
273         if (pgd) {
274                 memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
275                 memcpy(pgd + USER_PTRS_PER_PGD,
276                        swapper_pg_dir + USER_PTRS_PER_PGD,
277                        (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
278         }
279         return pgd;
280 }
281
282 void pgd_free(struct mm_struct *mm, pgd_t *pgd)
283 {
284         free_page((unsigned long) pgd);
285 }
286
287 pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
288 {
289         pte_t *pte;
290
291         pte = (pte_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO);
292         return pte;
293 }
294
295 pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long address)
296 {
297         struct page *pte;
298
299         pte = alloc_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO);
300         if (pte)
301                 pgtable_page_ctor(pte);
302         return pte;
303 }
304
305 #ifdef CONFIG_3_LEVEL_PGTABLES
306 pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
307 {
308         pmd_t *pmd = (pmd_t *) __get_free_page(GFP_KERNEL);
309
310         if (pmd)
311                 memset(pmd, 0, PAGE_SIZE);
312
313         return pmd;
314 }
315 #endif
316
317 void *uml_kmalloc(int size, int flags)
318 {
319         return kmalloc(size, flags);
320 }