Move round_up/down to kernel.h
[safe/jmp/linux-2.6] / arch / x86 / mm / init_32.c
index 5ca9c6c..262867a 100644 (file)
 #include <asm/paravirt.h>
 #include <asm/setup.h>
 #include <asm/cacheflush.h>
+#include <asm/page_types.h>
+#include <asm/init.h>
 
-unsigned long max_low_pfn_mapped;
-unsigned long max_pfn_mapped;
-
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
 unsigned long highstart_pfn, highend_pfn;
 
 static noinline int do_test_wp_bit(void);
 
-
-extern unsigned long __initdata e820_table_start;
-extern unsigned long __meminitdata e820_table_end;
-extern unsigned long __meminitdata e820_table_top;
+bool __read_mostly __vmalloc_start_set = false;
 
 static __init void *alloc_low_page(void)
 {
@@ -89,7 +84,7 @@ static pmd_t * __init one_md_table_init(pgd_t *pgd)
 #ifdef CONFIG_X86_PAE
        if (!(pgd_val(*pgd) & _PAGE_PRESENT)) {
                if (after_bootmem)
-                       pmd_table = (pmd_t *)alloc_bootmem_low_pages(PAGE_SIZE);
+                       pmd_table = (pmd_t *)alloc_bootmem_pages(PAGE_SIZE);
                else
                        pmd_table = (pmd_t *)alloc_low_page();
                paravirt_alloc_pmd(&init_mm, __pa(pmd_table) >> PAGE_SHIFT);
@@ -116,12 +111,12 @@ static pte_t * __init one_page_table_init(pmd_t *pmd)
                pte_t *page_table = NULL;
 
                if (after_bootmem) {
-#ifdef CONFIG_DEBUG_PAGEALLOC
+#if defined(CONFIG_DEBUG_PAGEALLOC) || defined(CONFIG_KMEMCHECK)
                        page_table = (pte_t *) alloc_bootmem_pages(PAGE_SIZE);
 #endif
                        if (!page_table)
                                page_table =
-                               (pte_t *)alloc_bootmem_low_pages(PAGE_SIZE);
+                               (pte_t *)alloc_bootmem_pages(PAGE_SIZE);
                } else
                        page_table = (pte_t *)alloc_low_page();
 
@@ -133,6 +128,23 @@ static pte_t * __init one_page_table_init(pmd_t *pmd)
        return pte_offset_kernel(pmd, 0);
 }
 
+pmd_t * __init populate_extra_pmd(unsigned long vaddr)
+{
+       int pgd_idx = pgd_index(vaddr);
+       int pmd_idx = pmd_index(vaddr);
+
+       return one_md_table_init(swapper_pg_dir + pgd_idx) + pmd_idx;
+}
+
+pte_t * __init populate_extra_pte(unsigned long vaddr)
+{
+       int pte_idx = pte_index(vaddr);
+       pmd_t *pmd;
+
+       pmd = populate_extra_pmd(vaddr);
+       return one_page_table_init(pmd) + pte_idx;
+}
+
 static pte_t *__init page_table_kmap_check(pte_t *pte, pmd_t *pmd,
                                           unsigned long vaddr, pte_t *lastpte)
 {
@@ -400,7 +412,7 @@ static void __init permanent_kmaps_init(pgd_t *pgd_base)
        pkmap_page_table = pte;
 }
 
-static void __init add_one_highpage_init(struct page *page, int pfn)
+static void __init add_one_highpage_init(struct page *page)
 {
        ClearPageReserved(page);
        init_page_count(page);
@@ -433,7 +445,7 @@ static int __init add_highpages_work_fn(unsigned long start_pfn,
                if (!pfn_valid(node_pfn))
                        continue;
                page = pfn_to_page(node_pfn);
-               add_one_highpage_init(page, node_pfn);
+               add_one_highpage_init(page);
        }
 
        return 0;
@@ -552,7 +564,7 @@ static inline void save_pg_dir(void)
 }
 #endif /* !CONFIG_ACPI_SLEEP */
 
-void zap_low_mappings(void)
+void zap_low_mappings(bool early)
 {
        int i;
 
@@ -569,64 +581,16 @@ void zap_low_mappings(void)
                set_pgd(swapper_pg_dir+i, __pgd(0));
 #endif
        }
-       flush_tlb_all();
-}
 
-int nx_enabled;
+       if (early)
+               __flush_tlb();
+       else
+               flush_tlb_all();
+}
 
 pteval_t __supported_pte_mask __read_mostly = ~(_PAGE_NX | _PAGE_GLOBAL | _PAGE_IOMAP);
 EXPORT_SYMBOL_GPL(__supported_pte_mask);
 
-#ifdef CONFIG_X86_PAE
-
-static int disable_nx __initdata;
-
-/*
- * noexec = on|off
- *
- * Control non executable mappings.
- *
- * on      Enable
- * off     Disable
- */
-static int __init noexec_setup(char *str)
-{
-       if (!str || !strcmp(str, "on")) {
-               if (cpu_has_nx) {
-                       __supported_pte_mask |= _PAGE_NX;
-                       disable_nx = 0;
-               }
-       } else {
-               if (!strcmp(str, "off")) {
-                       disable_nx = 1;
-                       __supported_pte_mask &= ~_PAGE_NX;
-               } else {
-                       return -EINVAL;
-               }
-       }
-
-       return 0;
-}
-early_param("noexec", noexec_setup);
-
-static void __init set_nx(void)
-{
-       unsigned int v[4], l, h;
-
-       if (cpu_has_pae && (cpuid_eax(0x80000000) > 0x80000001)) {
-               cpuid(0x80000001, &v[0], &v[1], &v[2], &v[3]);
-
-               if ((v[3] & (1 << 20)) && !disable_nx) {
-                       rdmsr(MSR_EFER, l, h);
-                       l |= EFER_NX;
-                       wrmsr(MSR_EFER, l, h);
-                       nx_enabled = 1;
-                       __supported_pte_mask |= _PAGE_NX;
-               }
-       }
-}
-#endif
-
 /* user-defined highmem size */
 static unsigned int highmem_pages = -1;
 
@@ -739,28 +703,30 @@ void __init find_low_pfn_range(void)
 }
 
 #ifndef CONFIG_NEED_MULTIPLE_NODES
-void __init initmem_init(unsigned long start_pfn,
-                                 unsigned long end_pfn)
+void __init initmem_init(unsigned long start_pfn, unsigned long end_pfn,
+                               int acpi, int k8)
 {
 #ifdef CONFIG_HIGHMEM
        highstart_pfn = highend_pfn = max_pfn;
        if (max_pfn > max_low_pfn)
                highstart_pfn = max_low_pfn;
-       memory_present(0, 0, highend_pfn);
        e820_register_active_regions(0, 0, highend_pfn);
+       sparse_memory_present_with_active_regions(0);
        printk(KERN_NOTICE "%ldMB HIGHMEM available.\n",
                pages_to_mb(highend_pfn - highstart_pfn));
        num_physpages = highend_pfn;
        high_memory = (void *) __va(highstart_pfn * PAGE_SIZE - 1) + 1;
 #else
-       memory_present(0, 0, max_low_pfn);
        e820_register_active_regions(0, 0, max_low_pfn);
+       sparse_memory_present_with_active_regions(0);
        num_physpages = max_low_pfn;
        high_memory = (void *) __va(max_low_pfn * PAGE_SIZE - 1) + 1;
 #endif
 #ifdef CONFIG_FLATMEM
        max_mapnr = num_physpages;
 #endif
+       __vmalloc_start_set = true;
+
        printk(KERN_NOTICE "%ldMB LOWMEM available.\n",
                        pages_to_mb(max_low_pfn));
 
@@ -782,6 +748,7 @@ static void __init zone_sizes_init(void)
        free_area_init_nodes(max_zone_pfns);
 }
 
+#ifndef CONFIG_NO_BOOTMEM
 static unsigned long __init setup_node_bootmem(int nodeid,
                                 unsigned long start_pfn,
                                 unsigned long end_pfn,
@@ -789,11 +756,6 @@ static unsigned long __init setup_node_bootmem(int nodeid,
 {
        unsigned long bootmap_size;
 
-       if (start_pfn > max_low_pfn)
-               return bootmap;
-       if (end_pfn > max_low_pfn)
-               end_pfn = max_low_pfn;
-
        /* don't touch min_low_pfn */
        bootmap_size = init_bootmem_node(NODE_DATA(nodeid),
                                         bootmap >> PAGE_SHIFT,
@@ -803,13 +765,14 @@ static unsigned long __init setup_node_bootmem(int nodeid,
        printk(KERN_INFO "  node %d bootmap %08lx - %08lx\n",
                 nodeid, bootmap, bootmap + bootmap_size);
        free_bootmem_with_active_regions(nodeid, end_pfn);
-       early_res_to_bootmem(start_pfn<<PAGE_SHIFT, end_pfn<<PAGE_SHIFT);
 
        return bootmap + bootmap_size;
 }
+#endif
 
 void __init setup_bootmem_allocator(void)
 {
+#ifndef CONFIG_NO_BOOTMEM
        int nodeid;
        unsigned long bootmap_size, bootmap;
        /*
@@ -821,17 +784,30 @@ void __init setup_bootmem_allocator(void)
        if (bootmap == -1L)
                panic("Cannot find bootmem map of size %ld\n", bootmap_size);
        reserve_early(bootmap, bootmap + bootmap_size, "BOOTMAP");
+#endif
 
        printk(KERN_INFO "  mapped low ram: 0 - %08lx\n",
                 max_pfn_mapped<<PAGE_SHIFT);
        printk(KERN_INFO "  low ram: 0 - %08lx\n", max_low_pfn<<PAGE_SHIFT);
 
+#ifndef CONFIG_NO_BOOTMEM
+       for_each_online_node(nodeid) {
+                unsigned long start_pfn, end_pfn;
+
 #ifdef CONFIG_NEED_MULTIPLE_NODES
-       for_each_online_node(nodeid)
-               bootmap = setup_node_bootmem(nodeid, node_start_pfn[nodeid],
-                                       node_end_pfn[nodeid], bootmap);
+               start_pfn = node_start_pfn[nodeid];
+               end_pfn = node_end_pfn[nodeid];
+               if (start_pfn > max_low_pfn)
+                       continue;
+               if (end_pfn > max_low_pfn)
+                       end_pfn = max_low_pfn;
 #else
-       bootmap = setup_node_bootmem(0, 0, max_low_pfn, bootmap);
+               start_pfn = 0;
+               end_pfn = max_low_pfn;
+#endif
+               bootmap = setup_node_bootmem(nodeid, start_pfn, end_pfn,
+                                                bootmap);
+       }
 #endif
 
        after_bootmem = 1;
@@ -886,8 +862,6 @@ static void __init test_wp_bit(void)
        }
 }
 
-static struct kcore_list kcore_mem, kcore_vmalloc;
-
 void __init mem_init(void)
 {
        int codesize, reservedpages, datasize, initsize;
@@ -915,20 +889,15 @@ void __init mem_init(void)
        datasize =  (unsigned long) &_edata - (unsigned long) &_etext;
        initsize =  (unsigned long) &__init_end - (unsigned long) &__init_begin;
 
-       kclist_add(&kcore_mem, __va(0), max_low_pfn << PAGE_SHIFT);
-       kclist_add(&kcore_vmalloc, (void *)VMALLOC_START,
-                  VMALLOC_END-VMALLOC_START);
-
        printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, "
                        "%dk reserved, %dk data, %dk init, %ldk highmem)\n",
-               (unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
+               nr_free_pages() << (PAGE_SHIFT-10),
                num_physpages << (PAGE_SHIFT-10),
                codesize >> 10,
                reservedpages << (PAGE_SHIFT-10),
                datasize >> 10,
                initsize >> 10,
-               (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10))
-              );
+               totalhigh_pages << (PAGE_SHIFT-10));
 
        printk(KERN_INFO "virtual kernel memory layout:\n"
                "    fixmap  : 0x%08lx - 0x%08lx   (%4ld kB)\n"
@@ -989,7 +958,7 @@ void __init mem_init(void)
                test_wp_bit();
 
        save_pg_dir();
-       zap_low_mappings();
+       zap_low_mappings(true);
 }
 
 #ifdef CONFIG_MEMORY_HOTPLUG
@@ -1032,17 +1001,47 @@ static noinline int do_test_wp_bit(void)
 const int rodata_test_data = 0xC3;
 EXPORT_SYMBOL_GPL(rodata_test_data);
 
+int kernel_set_to_readonly __read_mostly;
+
+void set_kernel_text_rw(void)
+{
+       unsigned long start = PFN_ALIGN(_text);
+       unsigned long size = PFN_ALIGN(_etext) - start;
+
+       if (!kernel_set_to_readonly)
+               return;
+
+       pr_debug("Set kernel text: %lx - %lx for read write\n",
+                start, start+size);
+
+       set_pages_rw(virt_to_page(start), size >> PAGE_SHIFT);
+}
+
+void set_kernel_text_ro(void)
+{
+       unsigned long start = PFN_ALIGN(_text);
+       unsigned long size = PFN_ALIGN(_etext) - start;
+
+       if (!kernel_set_to_readonly)
+               return;
+
+       pr_debug("Set kernel text: %lx - %lx for read only\n",
+                start, start+size);
+
+       set_pages_ro(virt_to_page(start), size >> PAGE_SHIFT);
+}
+
 void mark_rodata_ro(void)
 {
        unsigned long start = PFN_ALIGN(_text);
        unsigned long size = PFN_ALIGN(_etext) - start;
 
-#ifndef CONFIG_DYNAMIC_FTRACE
-       /* Dynamic tracing modifies the kernel text section */
        set_pages_ro(virt_to_page(start), size >> PAGE_SHIFT);
        printk(KERN_INFO "Write protecting the kernel text: %luk\n",
                size >> 10);
 
+       kernel_set_to_readonly = 1;
+
 #ifdef CONFIG_CPA_DEBUG
        printk(KERN_INFO "Testing CPA: Reverting %lx-%lx\n",
                start, start+size);
@@ -1051,7 +1050,6 @@ void mark_rodata_ro(void)
        printk(KERN_INFO "Testing CPA: write protecting again\n");
        set_pages_ro(virt_to_page(start), size>>PAGE_SHIFT);
 #endif
-#endif /* CONFIG_DYNAMIC_FTRACE */
 
        start += size;
        size = (unsigned long)__end_rodata - start;