arch/um/kernel/mem.c: fix a shadowed variable
[sfrench/cifs-2.6.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/gfp.h>
9 #include <linux/highmem.h>
10 #include <linux/mm.h>
11 #include <linux/swap.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 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                (unsigned long) 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 struct page *arch_validate(struct page *page, gfp_t mask, int order)
244 {
245         unsigned long addr, zero = 0;
246         int i;
247
248  again:
249         if (page == NULL)
250                 return page;
251         if (PageHighMem(page))
252                 return page;
253
254         addr = (unsigned long) page_address(page);
255         for (i = 0; i < (1 << order); i++) {
256                 current->thread.fault_addr = (void *) addr;
257                 if (__do_copy_to_user((void __user *) addr, &zero,
258                                      sizeof(zero),
259                                      &current->thread.fault_addr,
260                                      &current->thread.fault_catcher)) {
261                         if (!(mask & __GFP_WAIT))
262                                 return NULL;
263                         else break;
264                 }
265                 addr += PAGE_SIZE;
266         }
267
268         if (i == (1 << order))
269                 return page;
270         page = alloc_pages(mask, order);
271         goto again;
272 }
273
274 /*
275  * This can't do anything because nothing in the kernel image can be freed
276  * since it's not in kernel physical memory.
277  */
278
279 void free_initmem(void)
280 {
281 }
282
283 #ifdef CONFIG_BLK_DEV_INITRD
284 void free_initrd_mem(unsigned long start, unsigned long end)
285 {
286         if (start < end)
287                 printk(KERN_INFO "Freeing initrd memory: %ldk freed\n",
288                        (end - start) >> 10);
289         for (; start < end; start += PAGE_SIZE) {
290                 ClearPageReserved(virt_to_page(start));
291                 init_page_count(virt_to_page(start));
292                 free_page(start);
293                 totalram_pages++;
294         }
295 }
296 #endif
297
298 void show_mem(void)
299 {
300         int pfn, total = 0, reserved = 0;
301         int shared = 0, cached = 0;
302         int high_mem = 0;
303         struct page *page;
304
305         printk(KERN_INFO "Mem-info:\n");
306         show_free_areas();
307         printk(KERN_INFO "Free swap:       %6ldkB\n",
308                nr_swap_pages<<(PAGE_SHIFT-10));
309         pfn = max_mapnr;
310         while (pfn-- > 0) {
311                 page = pfn_to_page(pfn);
312                 total++;
313                 if (PageHighMem(page))
314                         high_mem++;
315                 if (PageReserved(page))
316                         reserved++;
317                 else if (PageSwapCache(page))
318                         cached++;
319                 else if (page_count(page))
320                         shared += page_count(page) - 1;
321         }
322         printk(KERN_INFO "%d pages of RAM\n", total);
323         printk(KERN_INFO "%d pages of HIGHMEM\n", high_mem);
324         printk(KERN_INFO "%d reserved pages\n", reserved);
325         printk(KERN_INFO "%d pages shared\n", shared);
326         printk(KERN_INFO "%d pages swap cached\n", cached);
327 }
328
329 /* Allocate and free page tables. */
330
331 pgd_t *pgd_alloc(struct mm_struct *mm)
332 {
333         pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL);
334
335         if (pgd) {
336                 memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
337                 memcpy(pgd + USER_PTRS_PER_PGD,
338                        swapper_pg_dir + USER_PTRS_PER_PGD,
339                        (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
340         }
341         return pgd;
342 }
343
344 void pgd_free(struct mm_struct *mm, pgd_t *pgd)
345 {
346         free_page((unsigned long) pgd);
347 }
348
349 pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
350 {
351         pte_t *pte;
352
353         pte = (pte_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO);
354         return pte;
355 }
356
357 pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long address)
358 {
359         struct page *pte;
360
361         pte = alloc_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO);
362         if (pte)
363                 pgtable_page_ctor(pte);
364         return pte;
365 }
366
367 #ifdef CONFIG_3_LEVEL_PGTABLES
368 pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
369 {
370         pmd_t *pmd = (pmd_t *) __get_free_page(GFP_KERNEL);
371
372         if (pmd)
373                 memset(pmd, 0, PAGE_SIZE);
374
375         return pmd;
376 }
377 #endif