···11+/*22+ * This file is subject to the terms and conditions of the GNU General Public33+ * License. See the file "COPYING" in the main directory of this archive44+ * for more details.55+ *66+ * Copyright (C) 1994 - 2001, 2003 by Ralf Baechle77+ * Copyright (C) 1999, 2000, 2001 Silicon Graphics, Inc.88+ */99+1010+#ifndef _ASM_NIOS2_PGALLOC_H1111+#define _ASM_NIOS2_PGALLOC_H1212+1313+#include <linux/mm.h>1414+1515+static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd,1616+ pte_t *pte)1717+{1818+ set_pmd(pmd, __pmd((unsigned long)pte));1919+}2020+2121+static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd,2222+ pgtable_t pte)2323+{2424+ set_pmd(pmd, __pmd((unsigned long)page_address(pte)));2525+}2626+#define pmd_pgtable(pmd) pmd_page(pmd)2727+2828+/*2929+ * Initialize a new pmd table with invalid pointers.3030+ */3131+extern void pmd_init(unsigned long page, unsigned long pagetable);3232+3333+extern pgd_t *pgd_alloc(struct mm_struct *mm);3434+3535+static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)3636+{3737+ free_pages((unsigned long)pgd, PGD_ORDER);3838+}3939+4040+static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,4141+ unsigned long address)4242+{4343+ pte_t *pte;4444+4545+ pte = (pte_t *) __get_free_pages(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO,4646+ PTE_ORDER);4747+4848+ return pte;4949+}5050+5151+static inline pgtable_t pte_alloc_one(struct mm_struct *mm,5252+ unsigned long address)5353+{5454+ struct page *pte;5555+5656+ pte = alloc_pages(GFP_KERNEL | __GFP_REPEAT, PTE_ORDER);5757+ if (pte) {5858+ if (!pgtable_page_ctor(pte)) {5959+ __free_page(pte);6060+ return NULL;6161+ }6262+ clear_highpage(pte);6363+ }6464+ return pte;6565+}6666+6767+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)6868+{6969+ free_pages((unsigned long)pte, PTE_ORDER);7070+}7171+7272+static inline void pte_free(struct mm_struct *mm, struct page *pte)7373+{7474+ pgtable_page_dtor(pte);7575+ __free_pages(pte, PTE_ORDER);7676+}7777+7878+#define __pte_free_tlb(tlb, pte, addr) \7979+ do { \8080+ pgtable_page_dtor(pte); \8181+ tlb_remove_page((tlb), (pte)); \8282+ } while (0)8383+8484+#define check_pgt_cache() do { } while (0)8585+8686+#endif /* _ASM_NIOS2_PGALLOC_H */
+35
arch/nios2/include/asm/pgtable-bits.h
···11+/*22+ * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch>33+ * Copyright (C) 2009 Wind River Systems Inc44+ *55+ * This file is subject to the terms and conditions of the GNU General Public66+ * License. See the file "COPYING" in the main directory of this archive77+ * for more details.88+ */99+1010+#ifndef _ASM_NIOS2_PGTABLE_BITS_H1111+#define _ASM_NIOS2_PGTABLE_BITS_H1212+1313+/*1414+ * These are actual hardware defined protection bits in the tlbacc register1515+ * which looks like this:1616+ *1717+ * 31 30 ... 26 25 24 23 22 21 20 19 18 ... 1 01818+ * ignored........ C R W X G PFN............1919+ */2020+#define _PAGE_GLOBAL (1<<20)2121+#define _PAGE_EXEC (1<<21)2222+#define _PAGE_WRITE (1<<22)2323+#define _PAGE_READ (1<<23)2424+#define _PAGE_CACHED (1<<24) /* C: data access cacheable */2525+2626+/*2727+ * Software defined bits. They are ignored by the hardware and always read back2828+ * as zero, but can be written as non-zero.2929+ */3030+#define _PAGE_PRESENT (1<<25) /* PTE contains a translation */3131+#define _PAGE_ACCESSED (1<<26) /* page referenced */3232+#define _PAGE_DIRTY (1<<27) /* dirty page */3333+#define _PAGE_FILE (1<<28) /* PTE used for file mapping or swap */3434+3535+#endif /* _ASM_NIOS2_PGTABLE_BITS_H */
+310
arch/nios2/include/asm/pgtable.h
···11+/*22+ * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch>33+ * Copyright (C) 2009 Wind River Systems Inc44+ *55+ * Based on asm/pgtable-32.h from mips which is:66+ *77+ * Copyright (C) 1994, 95, 96, 97, 98, 99, 2000, 2003 Ralf Baechle88+ * Copyright (C) 1999, 2000, 2001 Silicon Graphics, Inc.99+ *1010+ * This file is subject to the terms and conditions of the GNU General Public1111+ * License. See the file "COPYING" in the main directory of this archive1212+ * for more details.1313+ */1414+1515+#ifndef _ASM_NIOS2_PGTABLE_H1616+#define _ASM_NIOS2_PGTABLE_H1717+1818+#include <linux/io.h>1919+#include <linux/bug.h>2020+#include <asm/page.h>2121+#include <asm/cacheflush.h>2222+#include <asm/tlbflush.h>2323+2424+#include <asm/pgtable-bits.h>2525+#include <asm-generic/pgtable-nopmd.h>2626+2727+#define FIRST_USER_ADDRESS 02828+2929+#define VMALLOC_START CONFIG_NIOS2_KERNEL_MMU_REGION_BASE3030+#define VMALLOC_END (CONFIG_NIOS2_KERNEL_REGION_BASE - 1)3131+3232+struct mm_struct;3333+3434+/* Helper macro */3535+#define MKP(x, w, r) __pgprot(_PAGE_PRESENT | _PAGE_CACHED | \3636+ ((x) ? _PAGE_EXEC : 0) | \3737+ ((r) ? _PAGE_READ : 0) | \3838+ ((w) ? _PAGE_WRITE : 0))3939+/*4040+ * These are the macros that generic kernel code needs4141+ * (to populate protection_map[])4242+ */4343+4444+/* Remove W bit on private pages for COW support */4545+#define __P000 MKP(0, 0, 0)4646+#define __P001 MKP(0, 0, 1)4747+#define __P010 MKP(0, 0, 0) /* COW */4848+#define __P011 MKP(0, 0, 1) /* COW */4949+#define __P100 MKP(1, 0, 0)5050+#define __P101 MKP(1, 0, 1)5151+#define __P110 MKP(1, 0, 0) /* COW */5252+#define __P111 MKP(1, 0, 1) /* COW */5353+5454+/* Shared pages can have exact HW mapping */5555+#define __S000 MKP(0, 0, 0)5656+#define __S001 MKP(0, 0, 1)5757+#define __S010 MKP(0, 1, 0)5858+#define __S011 MKP(0, 1, 1)5959+#define __S100 MKP(1, 0, 0)6060+#define __S101 MKP(1, 0, 1)6161+#define __S110 MKP(1, 1, 0)6262+#define __S111 MKP(1, 1, 1)6363+6464+/* Used all over the kernel */6565+#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_CACHED | _PAGE_READ | \6666+ _PAGE_WRITE | _PAGE_EXEC | _PAGE_GLOBAL)6767+6868+#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_CACHED | _PAGE_READ | \6969+ _PAGE_WRITE | _PAGE_ACCESSED)7070+7171+#define PAGE_COPY MKP(0, 0, 1)7272+7373+#define PGD_ORDER 07474+#define PTE_ORDER 07575+7676+#define PTRS_PER_PGD ((PAGE_SIZE << PGD_ORDER) / sizeof(pgd_t))7777+#define PTRS_PER_PTE ((PAGE_SIZE << PTE_ORDER) / sizeof(pte_t))7878+7979+#define USER_PTRS_PER_PGD \8080+ (CONFIG_NIOS2_KERNEL_MMU_REGION_BASE / PGDIR_SIZE)8181+8282+#define PGDIR_SHIFT 228383+#define PGDIR_SIZE (1UL << PGDIR_SHIFT)8484+#define PGDIR_MASK (~(PGDIR_SIZE-1))8585+8686+/*8787+ * ZERO_PAGE is a global shared page that is always zero: used8888+ * for zero-mapped memory areas etc..8989+ */9090+extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];9191+#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))9292+9393+extern pgd_t swapper_pg_dir[PTRS_PER_PGD];9494+extern pte_t invalid_pte_table[PAGE_SIZE/sizeof(pte_t)];9595+9696+/*9797+ * (pmds are folded into puds so this doesn't get actually called,9898+ * but the define is needed for a generic inline function.)9999+ */100100+static inline void set_pmd(pmd_t *pmdptr, pmd_t pmdval)101101+{102102+ pmdptr->pud.pgd.pgd = pmdval.pud.pgd.pgd;103103+}104104+105105+/* to find an entry in a page-table-directory */106106+#define pgd_index(addr) (((addr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1))107107+#define pgd_offset(mm, addr) ((mm)->pgd + pgd_index(addr))108108+109109+static inline int pte_write(pte_t pte) \110110+ { return pte_val(pte) & _PAGE_WRITE; }111111+static inline int pte_dirty(pte_t pte) \112112+ { return pte_val(pte) & _PAGE_DIRTY; }113113+static inline int pte_young(pte_t pte) \114114+ { return pte_val(pte) & _PAGE_ACCESSED; }115115+static inline int pte_file(pte_t pte) \116116+ { return pte_val(pte) & _PAGE_FILE; }117117+static inline int pte_special(pte_t pte) { return 0; }118118+119119+#define pgprot_noncached pgprot_noncached120120+121121+static inline pgprot_t pgprot_noncached(pgprot_t _prot)122122+{123123+ unsigned long prot = pgprot_val(_prot);124124+125125+ prot &= ~_PAGE_CACHED;126126+127127+ return __pgprot(prot);128128+}129129+130130+static inline int pte_none(pte_t pte)131131+{132132+ return !(pte_val(pte) & ~(_PAGE_GLOBAL|0xf));133133+}134134+135135+static inline int pte_present(pte_t pte) \136136+ { return pte_val(pte) & _PAGE_PRESENT; }137137+138138+/*139139+ * The following only work if pte_present() is true.140140+ * Undefined behaviour if not..141141+ */142142+static inline pte_t pte_wrprotect(pte_t pte)143143+{144144+ pte_val(pte) &= ~_PAGE_WRITE;145145+ return pte;146146+}147147+148148+static inline pte_t pte_mkclean(pte_t pte)149149+{150150+ pte_val(pte) &= ~_PAGE_DIRTY;151151+ return pte;152152+}153153+154154+static inline pte_t pte_mkold(pte_t pte)155155+{156156+ pte_val(pte) &= ~_PAGE_ACCESSED;157157+ return pte;158158+}159159+160160+static inline pte_t pte_mkwrite(pte_t pte)161161+{162162+ pte_val(pte) |= _PAGE_WRITE;163163+ return pte;164164+}165165+166166+static inline pte_t pte_mkdirty(pte_t pte)167167+{168168+ pte_val(pte) |= _PAGE_DIRTY;169169+ return pte;170170+}171171+172172+static inline pte_t pte_mkspecial(pte_t pte) { return pte; }173173+174174+static inline pte_t pte_mkyoung(pte_t pte)175175+{176176+ pte_val(pte) |= _PAGE_ACCESSED;177177+ return pte;178178+}179179+180180+static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)181181+{182182+ const unsigned long mask = _PAGE_READ | _PAGE_WRITE | _PAGE_EXEC;183183+184184+ pte_val(pte) = (pte_val(pte) & ~mask) | (pgprot_val(newprot) & mask);185185+ return pte;186186+}187187+188188+static inline int pmd_present(pmd_t pmd)189189+{190190+ return (pmd_val(pmd) != (unsigned long) invalid_pte_table)191191+ && (pmd_val(pmd) != 0UL);192192+}193193+194194+static inline void pmd_clear(pmd_t *pmdp)195195+{196196+ pmd_val(*pmdp) = (unsigned long) invalid_pte_table;197197+}198198+199199+#define pte_pfn(pte) (pte_val(pte) & 0xfffff)200200+#define pfn_pte(pfn, prot) (__pte(pfn | pgprot_val(prot)))201201+#define pte_page(pte) (pfn_to_page(pte_pfn(pte)))202202+203203+/*204204+ * Store a linux PTE into the linux page table.205205+ */206206+static inline void set_pte(pte_t *ptep, pte_t pteval)207207+{208208+ *ptep = pteval;209209+}210210+211211+static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,212212+ pte_t *ptep, pte_t pteval)213213+{214214+ unsigned long paddr = page_to_virt(pte_page(pteval));215215+216216+ flush_dcache_range(paddr, paddr + PAGE_SIZE);217217+ set_pte(ptep, pteval);218218+}219219+220220+static inline int pmd_none(pmd_t pmd)221221+{222222+ return (pmd_val(pmd) ==223223+ (unsigned long) invalid_pte_table) || (pmd_val(pmd) == 0UL);224224+}225225+226226+#define pmd_bad(pmd) (pmd_val(pmd) & ~PAGE_MASK)227227+228228+static inline void pte_clear(struct mm_struct *mm,229229+ unsigned long addr, pte_t *ptep)230230+{231231+ pte_t null;232232+233233+ pte_val(null) = (addr >> PAGE_SHIFT) & 0xf;234234+235235+ set_pte_at(mm, addr, ptep, null);236236+ flush_tlb_one(addr);237237+}238238+239239+/*240240+ * Conversion functions: convert a page and protection to a page entry,241241+ * and a page entry and page directory to the page they refer to.242242+ */243243+#define mk_pte(page, prot) (pfn_pte(page_to_pfn(page), prot))244244+245245+#define pte_unmap(pte) do { } while (0)246246+247247+/*248248+ * Conversion functions: convert a page and protection to a page entry,249249+ * and a page entry and page directory to the page they refer to.250250+ */251251+#define pmd_phys(pmd) virt_to_phys((void *)pmd_val(pmd))252252+#define pmd_page(pmd) (pfn_to_page(pmd_phys(pmd) >> PAGE_SHIFT))253253+#define pmd_page_vaddr(pmd) pmd_val(pmd)254254+255255+#define pte_offset_map(dir, addr) \256256+ ((pte_t *) page_address(pmd_page(*dir)) + \257257+ (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)))258258+259259+/* to find an entry in a kernel page-table-directory */260260+#define pgd_offset_k(addr) pgd_offset(&init_mm, addr)261261+262262+/* Get the address to the PTE for a vaddr in specific directory */263263+#define pte_offset_kernel(dir, addr) \264264+ ((pte_t *) pmd_page_vaddr(*(dir)) + \265265+ (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)))266266+267267+#define pte_ERROR(e) \268268+ pr_err("%s:%d: bad pte %08lx.\n", \269269+ __FILE__, __LINE__, pte_val(e))270270+#define pgd_ERROR(e) \271271+ pr_err("%s:%d: bad pgd %08lx.\n", \272272+ __FILE__, __LINE__, pgd_val(e))273273+274274+/*275275+ * Encode and decode a swap entry (must be !pte_none(pte) && !pte_present(pte)276276+ * && !pte_file(pte)):277277+ *278278+ * 31 30 29 28 27 26 25 24 23 22 21 20 19 18 ... 1 0279279+ * 0 0 0 0 type. 0 0 0 0 0 0 offset.........280280+ *281281+ * This gives us up to 2**2 = 4 swap files and 2**20 * 4K = 4G per swap file.282282+ *283283+ * Note that the offset field is always non-zero, thus !pte_none(pte) is always284284+ * true.285285+ */286286+#define __swp_type(swp) (((swp).val >> 26) & 0x3)287287+#define __swp_offset(swp) ((swp).val & 0xfffff)288288+#define __swp_entry(type, off) ((swp_entry_t) { (((type) & 0x3) << 26) \289289+ | ((off) & 0xfffff) })290290+#define __swp_entry_to_pte(swp) ((pte_t) { (swp).val })291291+#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) })292292+293293+/* Encode and decode a nonlinear file mapping entry */294294+#define PTE_FILE_MAX_BITS 25295295+#define pte_to_pgoff(pte) (pte_val(pte) & 0x1ffffff)296296+#define pgoff_to_pte(off) __pte(((off) & 0x1ffffff) | _PAGE_FILE)297297+298298+#define kern_addr_valid(addr) (1)299299+300300+#include <asm-generic/pgtable.h>301301+302302+#define pgtable_cache_init() do { } while (0)303303+304304+extern void __init paging_init(void);305305+extern void __init mmu_init(void);306306+307307+extern void update_mmu_cache(struct vm_area_struct *vma,308308+ unsigned long address, pte_t *pte);309309+310310+#endif /* _ASM_NIOS2_PGTABLE_H */
+74
arch/nios2/mm/pgtable.c
···11+/*22+ * Copyright (C) 2009 Wind River Systems Inc33+ * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com44+ *55+ * This file is subject to the terms and conditions of the GNU General Public66+ * License. See the file "COPYING" in the main directory of this archive77+ * for more details.88+ */99+1010+#include <linux/mm.h>1111+#include <linux/sched.h>1212+1313+#include <asm/pgtable.h>1414+#include <asm/cpuinfo.h>1515+1616+/* pteaddr:1717+ * ptbase | vpn* | zero1818+ * 31-22 | 21-2 | 1-01919+ *2020+ * *vpn is preserved on double fault2121+ *2222+ * tlbacc:2323+ * IG |*flags| pfn2424+ * 31-25|24-20 | 19-02525+ *2626+ * *crwxg2727+ *2828+ * tlbmisc:2929+ * resv |way |rd | we|pid |dbl|bad|perm|d3030+ * 31-24 |23-20 |19 | 20|17-4|3 |2 |1 |03131+ *3232+ */3333+3434+/*3535+ * Initialize a new pgd / pmd table with invalid pointers.3636+ */3737+static void pgd_init(pgd_t *pgd)3838+{3939+ unsigned long *p = (unsigned long *) pgd;4040+ int i;4141+4242+ for (i = 0; i < USER_PTRS_PER_PGD; i += 8) {4343+ p[i + 0] = (unsigned long) invalid_pte_table;4444+ p[i + 1] = (unsigned long) invalid_pte_table;4545+ p[i + 2] = (unsigned long) invalid_pte_table;4646+ p[i + 3] = (unsigned long) invalid_pte_table;4747+ p[i + 4] = (unsigned long) invalid_pte_table;4848+ p[i + 5] = (unsigned long) invalid_pte_table;4949+ p[i + 6] = (unsigned long) invalid_pte_table;5050+ p[i + 7] = (unsigned long) invalid_pte_table;5151+ }5252+}5353+5454+pgd_t *pgd_alloc(struct mm_struct *mm)5555+{5656+ pgd_t *ret, *init;5757+5858+ ret = (pgd_t *) __get_free_pages(GFP_KERNEL, PGD_ORDER);5959+ if (ret) {6060+ init = pgd_offset(&init_mm, 0UL);6161+ pgd_init(ret);6262+ memcpy(ret + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,6363+ (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));6464+ }6565+6666+ return ret;6767+}6868+6969+void __init pagetable_init(void)7070+{7171+ /* Initialize the entire pgd. */7272+ pgd_init(swapper_pg_dir);7373+ pgd_init(swapper_pg_dir + USER_PTRS_PER_PGD);7474+}