diff options
author | Stuart Menefy <stuart.menefy@st.com> | 2006-11-21 15:38:05 +0900 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2006-12-06 10:45:38 +0900 |
commit | 99a596f93be10001c50894bcab69e458a49a3b8c (patch) | |
tree | 16faf593cc3f7a2c39f3079f0f64f410e530e1c4 /arch/sh/mm | |
parent | 6e4662ff49c6b94e16a47bfddb920576963b5a20 (diff) |
sh: pmd rework.
Remove extra bits from the pmd structure and store a kernel logical
address rather than a physical address. This allows it to be directly
dereferenced. Another piece of wierdness inherited from x86.
Signed-off-by: Stuart Menefy <stuart.menefy@st.com>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/mm')
-rw-r--r-- | arch/sh/mm/fault.c | 40 | ||||
-rw-r--r-- | arch/sh/mm/init.c | 26 |
2 files changed, 49 insertions, 17 deletions
diff --git a/arch/sh/mm/fault.c b/arch/sh/mm/fault.c index 43bed2cb00e..128907ef7fc 100644 --- a/arch/sh/mm/fault.c +++ b/arch/sh/mm/fault.c @@ -46,6 +46,45 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, mm = tsk->mm; si_code = SEGV_MAPERR; + if (unlikely(address >= TASK_SIZE)) { + /* + * Synchronize this task's top level page-table + * with the 'reference' page table. + * + * Do _not_ use "tsk" here. We might be inside + * an interrupt in the middle of a task switch.. + */ + int offset = pgd_index(address); + pgd_t *pgd, *pgd_k; + pud_t *pud, *pud_k; + pmd_t *pmd, *pmd_k; + + pgd = get_TTB() + offset; + pgd_k = swapper_pg_dir + offset; + + /* This will never happen with the folded page table. */ + if (!pgd_present(*pgd)) { + if (!pgd_present(*pgd_k)) + goto bad_area_nosemaphore; + set_pgd(pgd, *pgd_k); + return; + } + + pud = pud_offset(pgd, address); + pud_k = pud_offset(pgd_k, address); + if (pud_present(*pud) || !pud_present(*pud_k)) + goto bad_area_nosemaphore; + set_pud(pud, *pud_k); + + pmd = pmd_offset(pud, address); + pmd_k = pmd_offset(pud_k, address); + if (pmd_present(*pmd) || !pmd_present(*pmd_k)) + goto bad_area_nosemaphore; + set_pmd(pmd, *pmd_k); + + return; + } + /* * If we're in an interrupt or have no user * context, we must not take the fault.. @@ -109,6 +148,7 @@ survive: bad_area: up_read(&mm->mmap_sem); +bad_area_nosemaphore: if (user_mode(regs)) { info.si_signo = SIGSEGV; info.si_errno = 0; diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c index 8c8d3911838..462bfeac6d9 100644 --- a/arch/sh/mm/init.c +++ b/arch/sh/mm/init.c @@ -84,30 +84,22 @@ static void set_pte_phys(unsigned long addr, unsigned long phys, pgprot_t prot) pmd_t *pmd; pte_t *pte; - pgd = swapper_pg_dir + pgd_index(addr); + pgd = pgd_offset_k(addr); if (pgd_none(*pgd)) { pgd_ERROR(*pgd); return; } - pud = pud_offset(pgd, addr); - if (pud_none(*pud)) { - pmd = (pmd_t *)get_zeroed_page(GFP_ATOMIC); - set_pud(pud, __pud(__pa(pmd) | _PAGE_TABLE)); - if (pmd != pmd_offset(pud, 0)) { - pud_ERROR(*pud); - return; - } + pud = pud_alloc(NULL, pgd, addr); + if (unlikely(!pud)) { + pud_ERROR(*pud); + return; } - pmd = pmd_offset(pud, addr); - if (pmd_none(*pmd)) { - pte = (pte_t *)get_zeroed_page(GFP_ATOMIC); - set_pmd(pmd, __pmd(__pa(pte) | _PAGE_TABLE)); - if (pte != pte_offset_kernel(pmd, 0)) { - pmd_ERROR(*pmd); - return; - } + pmd = pmd_alloc(NULL, pud, addr); + if (unlikely(!pmd)) { + pmd_ERROR(*pmd); + return; } pte = pte_offset_kernel(pmd, addr); |