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/fault.c | |
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/fault.c')
-rw-r--r-- | arch/sh/mm/fault.c | 40 |
1 files changed, 40 insertions, 0 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; |