Add changes from the Linux-2.6 tree.
[linux-2.6.git] / arch / um / kernel / mem.c
index 09add57..c95855b 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
  * Licensed under the GPL
  */
 #include "mem_user.h"
 #include "uml_uaccess.h"
 #include "os.h"
-
-extern char __binary_start;
+#include "linux/types.h"
+#include "linux/string.h"
+#include "init.h"
+#include "kern_constants.h"
 
 /* Changed during early boot */
 unsigned long *empty_zero_page = NULL;
 unsigned long *empty_bad_page = NULL;
-pgd_t swapper_pg_dir[1024];
-unsigned long highmem;
+pgd_t swapper_pg_dir[PTRS_PER_PGD];
+unsigned long long highmem;
 int kmalloc_ok = 0;
 
 static unsigned long brk_end;
@@ -49,14 +51,11 @@ static void setup_highmem(unsigned long highmem_start,
        unsigned long highmem_pfn;
        int i;
 
-       highmem_start_page = virt_to_page(highmem_start);
-
        highmem_pfn = __pa(highmem_start) >> PAGE_SHIFT;
        for(i = 0; i < highmem_len >> PAGE_SHIFT; i++){
                page = &mem_map[highmem_pfn + i];
                ClearPageReserved(page);
-               set_bit(PG_highmem, &page->flags);
-               set_page_count(page, 1);
+               init_page_count(page);
                __free_page(page);
        }
 }
@@ -64,12 +63,7 @@ static void setup_highmem(unsigned long highmem_start,
 
 void mem_init(void)
 {
-       unsigned long start;
-
        max_low_pfn = (high_physmem - uml_physmem) >> PAGE_SHIFT;
-#ifdef CONFIG_HIGHMEM
-       highmem_start_page = phys_page(__pa(high_physmem));
-#endif
 
         /* clear the zero-page */
         memset((void *) empty_zero_page, 0, PAGE_SIZE);
@@ -83,17 +77,12 @@ void mem_init(void)
        free_bootmem(__pa(brk_end), uml_reserved - brk_end);
        uml_reserved = brk_end;
 
-       /* Fill in any hole at the start of the binary */
-       start = (unsigned long) &__binary_start;
-       if(uml_physmem != start){
-               map_memory(uml_physmem, __pa(uml_physmem), start - uml_physmem,
-                          1, 1, 0);
-       }
-
        /* this will put all low memory onto the freelists */
        totalram_pages = free_all_bootmem();
+#ifdef CONFIG_HIGHMEM
        totalhigh_pages = highmem >> PAGE_SHIFT;
        totalram_pages += totalhigh_pages;
+#endif
        num_physpages = totalram_pages;
        max_pfn = totalram_pages;
        printk(KERN_INFO "Memory: %luk available\n", 
@@ -105,12 +94,37 @@ void mem_init(void)
 #endif
 }
 
+/*
+ * Create a page table and place a pointer to it in a middle page
+ * directory entry.
+ */
+static void __init one_page_table_init(pmd_t *pmd)
+{
+       if (pmd_none(*pmd)) {
+               pte_t *pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
+               set_pmd(pmd, __pmd(_KERNPG_TABLE +
+                                          (unsigned long) __pa(pte)));
+               if (pte != pte_offset_kernel(pmd, 0))
+                       BUG();
+       }
+}
+
+static void __init one_md_table_init(pud_t *pud)
+{
+#ifdef CONFIG_3_LEVEL_PGTABLES
+       pmd_t *pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE);
+       set_pud(pud, __pud(_KERNPG_TABLE + (unsigned long) __pa(pmd_table)));
+       if (pmd_table != pmd_offset(pud, 0))
+               BUG();
+#endif
+}
+
 static void __init fixrange_init(unsigned long start, unsigned long end, 
                                 pgd_t *pgd_base)
 {
        pgd_t *pgd;
+       pud_t *pud;
        pmd_t *pmd;
-       pte_t *pte;
        int i, j;
        unsigned long vaddr;
 
@@ -120,29 +134,27 @@ static void __init fixrange_init(unsigned long start, unsigned long end,
        pgd = pgd_base + i;
 
        for ( ; (i < PTRS_PER_PGD) && (vaddr < end); pgd++, i++) {
-               pmd = (pmd_t *)pgd;
+               pud = pud_offset(pgd, vaddr);
+               if (pud_none(*pud))
+                       one_md_table_init(pud);
+               pmd = pmd_offset(pud, vaddr);
                for (; (j < PTRS_PER_PMD) && (vaddr != end); pmd++, j++) {
-                       if (pmd_none(*pmd)) {
-                               pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
-                               set_pmd(pmd, __pmd(_KERNPG_TABLE + 
-                                                  (unsigned long) __pa(pte)));
-                               if (pte != pte_offset_kernel(pmd, 0))
-                                       BUG();
-                       }
+                       one_page_table_init(pmd);
                        vaddr += PMD_SIZE;
                }
                j = 0;
        }
 }
 
-#if CONFIG_HIGHMEM
+#ifdef CONFIG_HIGHMEM
 pte_t *kmap_pte;
 pgprot_t kmap_prot;
 
 #define kmap_get_fixmap_pte(vaddr)                                     \
-       pte_offset(pmd_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr))
+       pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr), (vaddr)),\
+                         (vaddr)), (vaddr))
 
-void __init kmap_init(void)
+static void __init kmap_init(void)
 {
        unsigned long kmap_vstart;
 
@@ -156,6 +168,7 @@ void __init kmap_init(void)
 static void init_highmem(void)
 {
        pgd_t *pgd;
+       pud_t *pud;
        pmd_t *pmd;
        pte_t *pte;
        unsigned long vaddr;
@@ -167,7 +180,8 @@ static void init_highmem(void)
        fixrange_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, swapper_pg_dir);
 
        pgd = swapper_pg_dir + pgd_index(vaddr);
-       pmd = pmd_offset(pgd, vaddr);
+       pud = pud_offset(pgd, vaddr);
+       pmd = pmd_offset(pud, vaddr);
        pte = pte_offset_kernel(pmd, vaddr);
        pkmap_page_table = pte;
 
@@ -175,6 +189,33 @@ static void init_highmem(void)
 }
 #endif /* CONFIG_HIGHMEM */
 
+static void __init fixaddr_user_init( void)
+{
+#ifdef CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA
+       long size = FIXADDR_USER_END - FIXADDR_USER_START;
+       pgd_t *pgd;
+       pud_t *pud;
+       pmd_t *pmd;
+       pte_t *pte;
+       unsigned long paddr, vaddr = FIXADDR_USER_START;
+
+       if (  ! size )
+               return;
+
+       fixrange_init( FIXADDR_USER_START, FIXADDR_USER_END, swapper_pg_dir);
+       paddr = (unsigned long)alloc_bootmem_low_pages( size);
+       memcpy( (void *)paddr, (void *)FIXADDR_USER_START, size);
+       paddr = __pa(paddr);
+       for ( ; size > 0; size-=PAGE_SIZE, vaddr+=PAGE_SIZE, paddr+=PAGE_SIZE){
+               pgd = swapper_pg_dir + pgd_index(vaddr);
+               pud = pud_offset(pgd, vaddr);
+               pmd = pmd_offset(pud, vaddr);
+               pte = pte_offset_kernel(pmd, vaddr);
+               pte_set_val( (*pte), paddr, PAGE_READONLY);
+       }
+#endif
+}
+
 void paging_init(void)
 {
        unsigned long zones_size[MAX_NR_ZONES], vaddr;
@@ -182,10 +223,14 @@ void paging_init(void)
 
        empty_zero_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE);
        empty_bad_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE);
-       for(i=0;i<sizeof(zones_size)/sizeof(zones_size[0]);i++) 
+       for(i = 0; i < ARRAY_SIZE(zones_size); i++)
                zones_size[i] = 0;
-       zones_size[0] = (end_iomem >> PAGE_SHIFT) - (uml_physmem >> PAGE_SHIFT);
-       zones_size[2] = highmem >> PAGE_SHIFT;
+
+       zones_size[ZONE_NORMAL] = (end_iomem >> PAGE_SHIFT) -
+               (uml_physmem >> PAGE_SHIFT);
+#ifdef CONFIG_HIGHMEM
+       zones_size[ZONE_HIGHMEM] = highmem >> PAGE_SHIFT;
+#endif
        free_area_init(zones_size);
 
        /*
@@ -195,12 +240,14 @@ void paging_init(void)
        vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK;
        fixrange_init(vaddr, FIXADDR_TOP, swapper_pg_dir);
 
+       fixaddr_user_init();
+
 #ifdef CONFIG_HIGHMEM
        init_highmem();
 #endif
 }
 
-struct page *arch_validate(struct page *page, int mask, int order)
+struct page *arch_validate(struct page *page, gfp_t mask, int order)
 {
        unsigned long addr, zero = 0;
        int i;
@@ -212,7 +259,7 @@ struct page *arch_validate(struct page *page, int mask, int order)
        addr = (unsigned long) page_address(page);
        for(i = 0; i < (1 << order); i++){
                current->thread.fault_addr = (void *) addr;
-               if(__do_copy_to_user((void *) addr, &zero,
+               if(__do_copy_to_user((void __user *) addr, &zero,
                                     sizeof(zero),
                                     &current->thread.fault_addr,
                                     &current->thread.fault_catcher)){
@@ -221,6 +268,7 @@ struct page *arch_validate(struct page *page, int mask, int order)
                }
                addr += PAGE_SIZE;
        }
+
        if(i == (1 << order)) return(page);
        page = alloc_pages(mask, order);
        goto again;
@@ -243,7 +291,7 @@ void free_initrd_mem(unsigned long start, unsigned long end)
                        (end - start) >> 10);
        for (; start < end; start += PAGE_SIZE) {
                ClearPageReserved(virt_to_page(start));
-               set_page_count(virt_to_page(start), 1);
+               init_page_count(virt_to_page(start));
                free_page(start);
                totalram_pages++;
        }
@@ -307,9 +355,7 @@ pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
 {
        pte_t *pte;
 
-       pte = (pte_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT);
-       if (pte)
-               clear_page(pte);
+       pte = (pte_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO);
        return pte;
 }
 
@@ -317,12 +363,20 @@ struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)
 {
        struct page *pte;
    
-       pte = alloc_pages(GFP_KERNEL|__GFP_REPEAT, 0);
-       if (pte)
-               clear_highpage(pte);
+       pte = alloc_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO);
        return pte;
 }
 
+struct iomem_region *iomem_regions = NULL;
+int iomem_size = 0;
+
+extern int parse_iomem(char *str, int *add) __init;
+
+__uml_setup("iomem=", parse_iomem,
+"iomem=<name>,<file>\n"
+"    Configure <file> as an IO memory region named <name>.\n\n"
+);
+
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * Emacs will notice this stuff at the end of the file and automatically