]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/x86/mm/init_64.c
x86: introduce /dev/mem restrictions with a config option
[linux-2.6-omap-h63xx.git] / arch / x86 / mm / init_64.c
index 52f54ee4559f39586b475aac0050de06f87e444d..49c274ee2fba64ea9b48713b96f814fc0afa5d23 100644 (file)
@@ -47,9 +47,6 @@
 #include <asm/numa.h>
 #include <asm/cacheflush.h>
 
-const struct dma_mapping_ops *dma_ops;
-EXPORT_SYMBOL(dma_ops);
-
 static unsigned long dma_reserve __initdata;
 
 DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
@@ -313,7 +310,7 @@ __meminit void early_iounmap(void *addr, unsigned long size)
        __flush_tlb_all();
 }
 
-static void __meminit
+static unsigned long __meminit
 phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end)
 {
        int i = pmd_index(address);
@@ -335,21 +332,26 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end)
                set_pte((pte_t *)pmd,
                        pfn_pte(address >> PAGE_SHIFT, PAGE_KERNEL_LARGE));
        }
+       return address;
 }
 
-static void __meminit
+static unsigned long __meminit
 phys_pmd_update(pud_t *pud, unsigned long address, unsigned long end)
 {
        pmd_t *pmd = pmd_offset(pud, 0);
+       unsigned long last_map_addr;
+
        spin_lock(&init_mm.page_table_lock);
-       phys_pmd_init(pmd, address, end);
+       last_map_addr = phys_pmd_init(pmd, address, end);
        spin_unlock(&init_mm.page_table_lock);
        __flush_tlb_all();
+       return last_map_addr;
 }
 
-static void __meminit
+static unsigned long __meminit
 phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end)
 {
+       unsigned long last_map_addr = end;
        int i = pud_index(addr);
 
        for (; i < PTRS_PER_PUD; i++, addr = (addr & PUD_MASK) + PUD_SIZE) {
@@ -368,13 +370,14 @@ phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end)
 
                if (pud_val(*pud)) {
                        if (!pud_large(*pud))
-                               phys_pmd_update(pud, addr, end);
+                               last_map_addr = phys_pmd_update(pud, addr, end);
                        continue;
                }
 
                if (direct_gbpages) {
                        set_pte((pte_t *)pud,
                                pfn_pte(addr >> PAGE_SHIFT, PAGE_KERNEL_LARGE));
+                       last_map_addr = (addr & PUD_MASK) + PUD_SIZE;
                        continue;
                }
 
@@ -382,12 +385,14 @@ phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end)
 
                spin_lock(&init_mm.page_table_lock);
                set_pud(pud, __pud(pmd_phys | _KERNPG_TABLE));
-               phys_pmd_init(pmd, addr, end);
+               last_map_addr = phys_pmd_init(pmd, addr, end);
                spin_unlock(&init_mm.page_table_lock);
 
                unmap_low_page(pmd);
        }
        __flush_tlb_all();
+
+       return last_map_addr >> PAGE_SHIFT;
 }
 
 static void __init find_early_table_space(unsigned long end)
@@ -427,7 +432,10 @@ static void __init init_gbpages(void)
                direct_gbpages = 0;
 }
 
-static void __init memtest(unsigned long start_phys, unsigned long size, unsigned pattern)
+#ifdef CONFIG_MEMTEST_BOOTPARAM
+
+static void __init memtest(unsigned long start_phys, unsigned long size,
+                                unsigned pattern)
 {
        unsigned long i;
        unsigned long *start;
@@ -470,7 +478,7 @@ static void __init memtest(unsigned long start_phys, unsigned long size, unsigne
                                last_bad += incr;
                        } else {
                                if (start_bad) {
-                                       printk(KERN_INFO "  %016lxx bad mem addr %016lx - %016lx reserved\n",
+                                       printk(KERN_CONT "\n  %016lx bad mem addr %016lx - %016lx reserved",
                                                val, start_bad, last_bad + incr);
                                        reserve_early(start_bad, last_bad - start_bad, "BAD RAM");
                                }
@@ -479,18 +487,19 @@ static void __init memtest(unsigned long start_phys, unsigned long size, unsigne
                }
        }
        if (start_bad) {
-               printk(KERN_INFO "  %016lx bad mem addr %016lx - %016lx reserved\n",
+               printk(KERN_CONT "\n  %016lx bad mem addr %016lx - %016lx reserved",
                        val, start_bad, last_bad + incr);
                reserve_early(start_bad, last_bad - start_bad, "BAD RAM");
        }
 
 }
 
-static int __initdata memtest_pattern;
+static int memtest_pattern __initdata = CONFIG_MEMTEST_BOOTPARAM_VALUE;
+
 static int __init parse_memtest(char *arg)
 {
        if (arg)
-               memtest_pattern = simple_strtoul(arg, NULL, 0) + 1;
+               memtest_pattern = simple_strtoul(arg, NULL, 0);
        return 0;
 }
 
@@ -501,8 +510,10 @@ static void __init early_memtest(unsigned long start, unsigned long end)
        unsigned long t_start, t_size;
        unsigned pattern;
 
-       if (memtest_pattern)
-               printk(KERN_INFO "early_memtest: pattern num %d", memtest_pattern);
+       if (!memtest_pattern)
+               return;
+
+       printk(KERN_INFO "early_memtest: pattern num %d", memtest_pattern);
        for (pattern = 0; pattern < memtest_pattern; pattern++) {
                t_start = start;
                t_size = 0;
@@ -523,18 +534,22 @@ static void __init early_memtest(unsigned long start, unsigned long end)
                        t_start += t_size;
                }
        }
-       if (memtest_pattern)
-               printk(KERN_CONT "\n");
+       printk(KERN_CONT "\n");
+}
+#else
+static void __init early_memtest(unsigned long start, unsigned long end)
+{
 }
+#endif
 
 /*
  * Setup the direct mapping of the physical memory at PAGE_OFFSET.
  * This runs before bootmem is initialized and gets pages directly from
  * the physical memory. To access them they are temporarily mapped.
  */
-void __init_refok init_memory_mapping(unsigned long start, unsigned long end)
+unsigned long __init_refok init_memory_mapping(unsigned long start, unsigned long end)
 {
-       unsigned long next;
+       unsigned long next, last_map_addr = end;
        unsigned long start_phys = start, end_phys = end;
 
        printk(KERN_INFO "init_memory_mapping\n");
@@ -567,7 +582,7 @@ void __init_refok init_memory_mapping(unsigned long start, unsigned long end)
                next = start + PGDIR_SIZE;
                if (next > end)
                        next = end;
-               phys_pud_init(pud, __pa(start), __pa(next));
+               last_map_addr = phys_pud_init(pud, __pa(start), __pa(next));
                if (!after_bootmem)
                        set_pgd(pgd_offset_k(start), mk_kernel_pgd(pud_phys));
                unmap_low_page(pud);
@@ -583,6 +598,8 @@ void __init_refok init_memory_mapping(unsigned long start, unsigned long end)
 
        if (!after_bootmem)
                early_memtest(start_phys, end_phys);
+
+       return last_map_addr;
 }
 
 #ifndef CONFIG_NUMA
@@ -622,11 +639,13 @@ int arch_add_memory(int nid, u64 start, u64 size)
 {
        struct pglist_data *pgdat = NODE_DATA(nid);
        struct zone *zone = pgdat->node_zones + ZONE_NORMAL;
-       unsigned long start_pfn = start >> PAGE_SHIFT;
+       unsigned long last_mapped_pfn, start_pfn = start >> PAGE_SHIFT;
        unsigned long nr_pages = size >> PAGE_SHIFT;
        int ret;
 
-       init_memory_mapping(start, start + size-1);
+       last_mapped_pfn = init_memory_mapping(start, start + size-1);
+       if (last_mapped_pfn > max_pfn_mapped)
+               max_pfn_mapped = last_mapped_pfn;
 
        ret = __add_pages(zone, start_pfn, nr_pages);
        WARN_ON(1);
@@ -645,6 +664,26 @@ EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
 
 #endif /* CONFIG_MEMORY_HOTPLUG */
 
+/*
+ * devmem_is_allowed() checks to see if /dev/mem access to a certain address
+ * is valid. The argument is a physical page number.
+ *
+ *
+ * On x86, access has to be given to the first megabyte of ram because that area
+ * contains bios code and data regions used by X and dosemu and similar apps.
+ * Access has to be given to non-kernel-ram areas as well, these contain the PCI
+ * mmio resources as well as potential bios/acpi data regions.
+ */
+int devmem_is_allowed(unsigned long pagenr)
+{
+       if (pagenr <= 256)
+               return 1;
+       if (!page_is_ram(pagenr))
+               return 1;
+       return 0;
+}
+
+
 static struct kcore_list kcore_mem, kcore_vmalloc, kcore_kernel,
                         kcore_modules, kcore_vsyscall;
 
@@ -781,7 +820,7 @@ void __init reserve_bootmem_generic(unsigned long phys, unsigned len)
                 * This can happen with kdump kernels when accessing
                 * firmware tables:
                 */
-               if (pfn < end_pfn_map)
+               if (pfn < max_pfn_mapped)
                        return;
 
                printk(KERN_ERR "reserve_bootmem: illegal reserve %lx %u\n",