Skip to content

Commit

Permalink
lib/ioremap: ensure phys_addr actually corresponds to a physical address
Browse files Browse the repository at this point in the history
The current ioremap() code uses a phys_addr variable at each level of page
table, which is confusingly offset by subtracting the base virtual address
being mapped so that adding the current virtual address back on when
iterating through the page table entries gives back the corresponding
physical address.

This is fairly confusing and results in all users of phys_addr having to
add the current virtual address back on.  Instead, this patch just updates
phys_addr when iterating over the page table entries, ensuring that it's
always up-to-date and doesn't require explicit offsetting.

Link: http://lkml.kernel.org/r/1544120495-17438-5-git-send-email-will.deacon@arm.com
Signed-off-by: Will Deacon <will.deacon@arm.com>
Tested-by: Sean Christopherson <sean.j.christopherson@intel.com>
Reviewed-by: Sean Christopherson <sean.j.christopherson@intel.com>
Cc: Chintan Pandya <cpandya@codeaurora.org>
Cc: Toshi Kani <toshi.kani@hpe.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Sean Christopherson <sean.j.christopherson@intel.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
Will Deacon authored and Linus Torvalds committed Dec 28, 2018
1 parent 48e178a commit 36ddc5a
Showing 1 changed file with 12 additions and 16 deletions.
28 changes: 12 additions & 16 deletions lib/ioremap.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,19 +101,18 @@ static inline int ioremap_pmd_range(pud_t *pud, unsigned long addr,
pmd_t *pmd;
unsigned long next;

phys_addr -= addr;
pmd = pmd_alloc(&init_mm, pud, addr);
if (!pmd)
return -ENOMEM;
do {
next = pmd_addr_end(addr, end);

if (ioremap_try_huge_pmd(pmd, addr, next, phys_addr + addr, prot))
if (ioremap_try_huge_pmd(pmd, addr, next, phys_addr, prot))
continue;

if (ioremap_pte_range(pmd, addr, next, phys_addr + addr, prot))
if (ioremap_pte_range(pmd, addr, next, phys_addr, prot))
return -ENOMEM;
} while (pmd++, addr = next, addr != end);
} while (pmd++, phys_addr += (next - addr), addr = next, addr != end);
return 0;
}

Expand Down Expand Up @@ -142,19 +141,18 @@ static inline int ioremap_pud_range(p4d_t *p4d, unsigned long addr,
pud_t *pud;
unsigned long next;

phys_addr -= addr;
pud = pud_alloc(&init_mm, p4d, addr);
if (!pud)
return -ENOMEM;
do {
next = pud_addr_end(addr, end);

if (ioremap_try_huge_pud(pud, addr, next, phys_addr + addr, prot))
if (ioremap_try_huge_pud(pud, addr, next, phys_addr, prot))
continue;

if (ioremap_pmd_range(pud, addr, next, phys_addr + addr, prot))
if (ioremap_pmd_range(pud, addr, next, phys_addr, prot))
return -ENOMEM;
} while (pud++, addr = next, addr != end);
} while (pud++, phys_addr += (next - addr), addr = next, addr != end);
return 0;
}

Expand All @@ -164,7 +162,6 @@ static inline int ioremap_p4d_range(pgd_t *pgd, unsigned long addr,
p4d_t *p4d;
unsigned long next;

phys_addr -= addr;
p4d = p4d_alloc(&init_mm, pgd, addr);
if (!p4d)
return -ENOMEM;
Expand All @@ -173,14 +170,14 @@ static inline int ioremap_p4d_range(pgd_t *pgd, unsigned long addr,

if (ioremap_p4d_enabled() &&
((next - addr) == P4D_SIZE) &&
IS_ALIGNED(phys_addr + addr, P4D_SIZE)) {
if (p4d_set_huge(p4d, phys_addr + addr, prot))
IS_ALIGNED(phys_addr, P4D_SIZE)) {
if (p4d_set_huge(p4d, phys_addr, prot))
continue;
}

if (ioremap_pud_range(p4d, addr, next, phys_addr + addr, prot))
if (ioremap_pud_range(p4d, addr, next, phys_addr, prot))
return -ENOMEM;
} while (p4d++, addr = next, addr != end);
} while (p4d++, phys_addr += (next - addr), addr = next, addr != end);
return 0;
}

Expand All @@ -196,14 +193,13 @@ int ioremap_page_range(unsigned long addr,
BUG_ON(addr >= end);

start = addr;
phys_addr -= addr;
pgd = pgd_offset_k(addr);
do {
next = pgd_addr_end(addr, end);
err = ioremap_p4d_range(pgd, addr, next, phys_addr+addr, prot);
err = ioremap_p4d_range(pgd, addr, next, phys_addr, prot);
if (err)
break;
} while (pgd++, addr = next, addr != end);
} while (pgd++, phys_addr += (next - addr), addr = next, addr != end);

flush_cache_vmap(start, end);

Expand Down

0 comments on commit 36ddc5a

Please sign in to comment.