x86: warn about RAM pages in ioremap()
[sfrench/cifs-2.6.git] / arch / x86 / mm / ioremap.c
index ee6648fe6b15de75a4e0fe53a90f6311fa8b917a..3d0a589d92c40ebcf33882bf9d1b331894953037 100644 (file)
@@ -35,6 +35,18 @@ unsigned long __phys_addr(unsigned long x)
 }
 EXPORT_SYMBOL(__phys_addr);
 
+static inline int phys_addr_valid(unsigned long addr)
+{
+       return addr < (1UL << boot_cpu_data.x86_phys_bits);
+}
+
+#else
+
+static inline int phys_addr_valid(unsigned long addr)
+{
+       return 1;
+}
+
 #endif
 
 int page_is_ram(unsigned long pagenr)
@@ -42,6 +54,22 @@ int page_is_ram(unsigned long pagenr)
        unsigned long addr, end;
        int i;
 
+       /*
+        * A special case is the first 4Kb of memory;
+        * This is a BIOS owned area, not kernel ram, but generally
+        * not listed as such in the E820 table.
+        */
+       if (pagenr == 0)
+               return 0;
+
+       /*
+        * Second special case: Some BIOSen report the PC BIOS
+        * area (640->1Mb) as ram even though it is not.
+        */
+       if (pagenr >= (BIOS_BEGIN >> PAGE_SHIFT) &&
+                   pagenr < (BIOS_END >> PAGE_SHIFT))
+               return 0;
+
        for (i = 0; i < e820.nr_map; i++) {
                /*
                 * Not usable memory:
@@ -51,14 +79,6 @@ int page_is_ram(unsigned long pagenr)
                addr = (e820.map[i].addr + PAGE_SIZE-1) >> PAGE_SHIFT;
                end = (e820.map[i].addr + e820.map[i].size) >> PAGE_SHIFT;
 
-               /*
-                * Sanity check: Some BIOSen report areas as RAM that
-                * are not. Notably the 640->1Mb area, which is the
-                * PCI BIOS area.
-                */
-               if (addr >= (BIOS_BEGIN >> PAGE_SHIFT) &&
-                   end < (BIOS_END >> PAGE_SHIFT))
-                       continue;
 
                if ((pagenr >= addr) && (pagenr < end))
                        return 1;
@@ -98,7 +118,7 @@ static int ioremap_change_attr(unsigned long vaddr, unsigned long size,
  * have to convert them into an offset in a page-aligned mapping, but the
  * caller shouldn't need to know that small detail.
  */
-static void __iomem *__ioremap(unsigned long phys_addr, unsigned long size,
+static void __iomem *__ioremap(resource_size_t phys_addr, unsigned long size,
                               enum ioremap_mode mode)
 {
        unsigned long pfn, offset, last_addr, vaddr;
@@ -110,6 +130,13 @@ static void __iomem *__ioremap(unsigned long phys_addr, unsigned long size,
        if (!size || last_addr < phys_addr)
                return NULL;
 
+       if (!phys_addr_valid(phys_addr)) {
+               printk(KERN_WARNING "ioremap: invalid physical address %lx\n",
+                      phys_addr);
+               WARN_ON_ONCE(1);
+               return NULL;
+       }
+
        /*
         * Don't remap the low PCI/ISA area, it's always mapped..
         */
@@ -119,17 +146,24 @@ static void __iomem *__ioremap(unsigned long phys_addr, unsigned long size,
        /*
         * Don't allow anybody to remap normal RAM that we're using..
         */
-       for (pfn = phys_addr >> PAGE_SHIFT; pfn < max_pfn_mapped &&
-            (pfn << PAGE_SHIFT) < last_addr; pfn++) {
-               if (page_is_ram(pfn) && pfn_valid(pfn) &&
-                   !PageReserved(pfn_to_page(pfn)))
+       for (pfn = phys_addr >> PAGE_SHIFT;
+                               (pfn << PAGE_SHIFT) < last_addr; pfn++) {
+
+               int is_ram = page_is_ram(pfn);
+
+               if (is_ram && pfn_valid(pfn) && !PageReserved(pfn_to_page(pfn)))
                        return NULL;
+               WARN_ON_ONCE(is_ram);
        }
 
        switch (mode) {
        case IOR_MODE_UNCACHED:
        default:
-               prot = PAGE_KERNEL_NOCACHE;
+               /*
+                * FIXME: we will use UC MINUS for now, as video fb drivers
+                * depend on it. Upcoming ioremap_wc() will fix this behavior.
+                */
+               prot = PAGE_KERNEL_UC_MINUS;
                break;
        case IOR_MODE_CACHED:
                prot = PAGE_KERNEL;
@@ -152,7 +186,7 @@ static void __iomem *__ioremap(unsigned long phys_addr, unsigned long size,
        area->phys_addr = phys_addr;
        vaddr = (unsigned long) area->addr;
        if (ioremap_page_range(vaddr, vaddr + size, phys_addr, prot)) {
-               remove_vm_area((void *)(vaddr & PAGE_MASK));
+               free_vm_area(area);
                return NULL;
        }
 
@@ -185,13 +219,13 @@ static void __iomem *__ioremap(unsigned long phys_addr, unsigned long size,
  *
  * Must be freed with iounmap.
  */
-void __iomem *ioremap_nocache(unsigned long phys_addr, unsigned long size)
+void __iomem *ioremap_nocache(resource_size_t phys_addr, unsigned long size)
 {
        return __ioremap(phys_addr, size, IOR_MODE_UNCACHED);
 }
 EXPORT_SYMBOL(ioremap_nocache);
 
-void __iomem *ioremap_cache(unsigned long phys_addr, unsigned long size)
+void __iomem *ioremap_cache(resource_size_t phys_addr, unsigned long size)
 {
        return __ioremap(phys_addr, size, IOR_MODE_CACHED);
 }
@@ -260,41 +294,48 @@ static int __init early_ioremap_debug_setup(char *str)
 early_param("early_ioremap_debug", early_ioremap_debug_setup);
 
 static __initdata int after_paging_init;
-static __initdata unsigned long bm_pte[1024]
-                               __attribute__((aligned(PAGE_SIZE)));
+static pte_t bm_pte[PAGE_SIZE/sizeof(pte_t)]
+               __section(.bss.page_aligned);
 
-static inline unsigned long * __init early_ioremap_pgd(unsigned long addr)
+static inline pmd_t * __init early_ioremap_pmd(unsigned long addr)
 {
-       return (unsigned long *)swapper_pg_dir + ((addr >> 22) & 1023);
+       /* Don't assume we're using swapper_pg_dir at this point */
+       pgd_t *base = __va(read_cr3());
+       pgd_t *pgd = &base[pgd_index(addr)];
+       pud_t *pud = pud_offset(pgd, addr);
+       pmd_t *pmd = pmd_offset(pud, addr);
+
+       return pmd;
 }
 
-static inline unsigned long * __init early_ioremap_pte(unsigned long addr)
+static inline pte_t * __init early_ioremap_pte(unsigned long addr)
 {
-       return bm_pte + ((addr >> PAGE_SHIFT) & 1023);
+       return &bm_pte[pte_index(addr)];
 }
 
 void __init early_ioremap_init(void)
 {
-       unsigned long *pgd;
+       pmd_t *pmd;
 
        if (early_ioremap_debug)
                printk(KERN_INFO "early_ioremap_init()\n");
 
-       pgd = early_ioremap_pgd(fix_to_virt(FIX_BTMAP_BEGIN));
-       *pgd = __pa(bm_pte) | _PAGE_TABLE;
+       pmd = early_ioremap_pmd(fix_to_virt(FIX_BTMAP_BEGIN));
        memset(bm_pte, 0, sizeof(bm_pte));
+       pmd_populate_kernel(&init_mm, pmd, bm_pte);
+
        /*
-        * The boot-ioremap range spans multiple pgds, for which
+        * The boot-ioremap range spans multiple pmds, for which
         * we are not prepared:
         */
-       if (pgd != early_ioremap_pgd(fix_to_virt(FIX_BTMAP_END))) {
+       if (pmd != early_ioremap_pmd(fix_to_virt(FIX_BTMAP_END))) {
                WARN_ON(1);
-               printk(KERN_WARNING "pgd %p != %p\n",
-                      pgd, early_ioremap_pgd(fix_to_virt(FIX_BTMAP_END)));
+               printk(KERN_WARNING "pmd %p != %p\n",
+                      pmd, early_ioremap_pmd(fix_to_virt(FIX_BTMAP_END)));
                printk(KERN_WARNING "fix_to_virt(FIX_BTMAP_BEGIN): %08lx\n",
-                      fix_to_virt(FIX_BTMAP_BEGIN));
+                       fix_to_virt(FIX_BTMAP_BEGIN));
                printk(KERN_WARNING "fix_to_virt(FIX_BTMAP_END):   %08lx\n",
-                      fix_to_virt(FIX_BTMAP_END));
+                       fix_to_virt(FIX_BTMAP_END));
 
                printk(KERN_WARNING "FIX_BTMAP_END:       %d\n", FIX_BTMAP_END);
                printk(KERN_WARNING "FIX_BTMAP_BEGIN:     %d\n",
@@ -304,28 +345,29 @@ void __init early_ioremap_init(void)
 
 void __init early_ioremap_clear(void)
 {
-       unsigned long *pgd;
+       pmd_t *pmd;
 
        if (early_ioremap_debug)
                printk(KERN_INFO "early_ioremap_clear()\n");
 
-       pgd = early_ioremap_pgd(fix_to_virt(FIX_BTMAP_BEGIN));
-       *pgd = 0;
-       paravirt_release_pt(__pa(pgd) >> PAGE_SHIFT);
+       pmd = early_ioremap_pmd(fix_to_virt(FIX_BTMAP_BEGIN));
+       pmd_clear(pmd);
+       paravirt_release_pt(__pa(bm_pte) >> PAGE_SHIFT);
        __flush_tlb_all();
 }
 
 void __init early_ioremap_reset(void)
 {
        enum fixed_addresses idx;
-       unsigned long *pte, phys, addr;
+       unsigned long addr, phys;
+       pte_t *pte;
 
        after_paging_init = 1;
        for (idx = FIX_BTMAP_BEGIN; idx >= FIX_BTMAP_END; idx--) {
                addr = fix_to_virt(idx);
                pte = early_ioremap_pte(addr);
-               if (*pte & _PAGE_PRESENT) {
-                       phys = *pte & PAGE_MASK;
+               if (pte_present(*pte)) {
+                       phys = pte_val(*pte) & PAGE_MASK;
                        set_fixmap(idx, phys);
                }
        }
@@ -334,7 +376,8 @@ void __init early_ioremap_reset(void)
 static void __init __early_set_fixmap(enum fixed_addresses idx,
                                   unsigned long phys, pgprot_t flags)
 {
-       unsigned long *pte, addr = __fix_to_virt(idx);
+       unsigned long addr = __fix_to_virt(idx);
+       pte_t *pte;
 
        if (idx >= __end_of_fixed_addresses) {
                BUG();
@@ -342,9 +385,9 @@ static void __init __early_set_fixmap(enum fixed_addresses idx,
        }
        pte = early_ioremap_pte(addr);
        if (pgprot_val(flags))
-               *pte = (phys & PAGE_MASK) | pgprot_val(flags);
+               set_pte(pte, pfn_pte(phys >> PAGE_SHIFT, flags));
        else
-               *pte = 0;
+               pte_clear(NULL, addr, pte);
        __flush_tlb_one(addr);
 }