Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 99a596f9 authored by Stuart Menefy's avatar Stuart Menefy Committed by Paul Mundt
Browse files

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: default avatarStuart Menefy <stuart.menefy@st.com>
Signed-off-by: default avatarPaul Mundt <lethal@linux-sh.org>
parent 6e4662ff
Loading
Loading
Loading
Loading
+40 −0
Original line number Diff line number Diff line
@@ -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 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
bad_area:
	up_read(&mm->mmap_sem);

bad_area_nosemaphore:
	if (user_mode(regs)) {
		info.si_signo = SIGSEGV;
		info.si_errno = 0;
+9 −17
Original line number Diff line number Diff line
@@ -84,31 +84,23 @@ 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 = 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 = pmd_alloc(NULL, pud, addr);
	if (unlikely(!pmd)) {
		pmd_ERROR(*pmd);
		return;
	}
	}

	pte = pte_offset_kernel(pmd, addr);
	if (!pte_none(*pte)) {
+16 −4
Original line number Diff line number Diff line
#ifndef __ASM_SH_PGALLOC_H
#define __ASM_SH_PGALLOC_H

#define pmd_populate_kernel(mm, pmd, pte) \
		set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte)))
static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd,
				       pte_t *pte)
{
	set_pmd(pmd, __pmd((unsigned long)pte));
}

static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd,
				struct page *pte)
{
	set_pmd(pmd, __pmd(_PAGE_TABLE + page_to_phys(pte)));
	set_pmd(pmd, __pmd((unsigned long)page_address(pte)));
}

/*
@@ -15,7 +18,16 @@ static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd,
 */
static inline pgd_t *pgd_alloc(struct mm_struct *mm)
{
	return (pgd_t *)__get_free_page(GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO);
	pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL | __GFP_REPEAT);

	if (pgd) {
		memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
		memcpy(pgd + USER_PTRS_PER_PGD,
		       swapper_pg_dir + USER_PTRS_PER_PGD,
		       (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
	}

	return pgd;
}

static inline void pgd_free(pgd_t *pgd)
+11 −27
Original line number Diff line number Diff line
@@ -203,14 +203,6 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
#ifndef __ASSEMBLY__

#if defined(CONFIG_X2TLB) /* SH-X2 TLB */
#define _PAGE_TABLE \
	(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY | \
	 _PAGE_EXT(_PAGE_EXT_USER_READ | _PAGE_EXT_USER_WRITE))

#define _KERNPG_TABLE \
	(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY | \
	 _PAGE_EXT(_PAGE_EXT_KERN_READ | _PAGE_EXT_KERN_WRITE))

#define PAGE_NONE	__pgprot(_PAGE_PROTNONE | _PAGE_CACHABLE | \
				 _PAGE_ACCESSED | _PAGE_FLAGS_HARD)

@@ -271,11 +263,6 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
				 (type))

#elif defined(CONFIG_MMU) /* SH-X TLB */
#define _PAGE_TABLE \
	(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
#define _KERNPG_TABLE \
	(_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)

#define PAGE_NONE	__pgprot(_PAGE_PROTNONE | _PAGE_CACHABLE | \
				 _PAGE_ACCESSED | _PAGE_FLAGS_HARD)

@@ -390,9 +377,9 @@ static inline void set_pte(pte_t *ptep, pte_t pte)
#define pte_clear(mm,addr,xp) do { set_pte_at(mm, addr, xp, __pte(0)); } while (0)

#define pmd_none(x)	(!pmd_val(x))
#define pmd_present(x)	(pmd_val(x) & _PAGE_PRESENT)
#define pmd_present(x)	(pmd_val(x))
#define pmd_clear(xp)	do { set_pmd(xp, __pmd(0)); } while (0)
#define	pmd_bad(x)	((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE)
#define	pmd_bad(x)	(pmd_val(x) & ~PAGE_MASK)

#define pages_to_mb(x)	((x) >> (20-PAGE_SHIFT))
#define pte_page(x)	phys_to_page(pte_val(x)&PTE_PHYS_MASK)
@@ -477,11 +464,8 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
	return pte;
}

#define pmd_page_vaddr(pmd) \
((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))

#define pmd_page(pmd) \
	(phys_to_page(pmd_val(pmd)))
#define pmd_page_vaddr(pmd)	pmd_val(pmd)
#define pmd_page(pmd)		(virt_to_page(pmd_val(pmd)))

/* to find an entry in a page-table-directory. */
#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))