···11+/*22+ * linux/arch/unicore32/include/asm/mmu.h33+ *44+ * Code specific to PKUnity SoC and UniCore ISA55+ *66+ * Copyright (C) 2001-2010 GUAN Xue-tao77+ *88+ * This program is free software; you can redistribute it and/or modify99+ * it under the terms of the GNU General Public License version 2 as1010+ * published by the Free Software Foundation.1111+ */1212+#ifndef __UNICORE_MMU_H__1313+#define __UNICORE_MMU_H__1414+1515+typedef unsigned long mm_context_t;1616+1717+#endif
+87
arch/unicore32/include/asm/mmu_context.h
···11+/*22+ * linux/arch/unicore32/include/asm/mmu_context.h33+ *44+ * Code specific to PKUnity SoC and UniCore ISA55+ *66+ * Copyright (C) 2001-2010 GUAN Xue-tao77+ *88+ * This program is free software; you can redistribute it and/or modify99+ * it under the terms of the GNU General Public License version 2 as1010+ * published by the Free Software Foundation.1111+ */1212+#ifndef __UNICORE_MMU_CONTEXT_H__1313+#define __UNICORE_MMU_CONTEXT_H__1414+1515+#include <linux/compiler.h>1616+#include <linux/sched.h>1717+#include <linux/io.h>1818+1919+#include <asm/cacheflush.h>2020+#include <asm/cpu-single.h>2121+2222+#define init_new_context(tsk, mm) 02323+2424+#define destroy_context(mm) do { } while (0)2525+2626+/*2727+ * This is called when "tsk" is about to enter lazy TLB mode.2828+ *2929+ * mm: describes the currently active mm context3030+ * tsk: task which is entering lazy tlb3131+ * cpu: cpu number which is entering lazy tlb3232+ *3333+ * tsk->mm will be NULL3434+ */3535+static inline void3636+enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)3737+{3838+}3939+4040+/*4141+ * This is the actual mm switch as far as the scheduler4242+ * is concerned. No registers are touched. We avoid4343+ * calling the CPU specific function when the mm hasn't4444+ * actually changed.4545+ */4646+static inline void4747+switch_mm(struct mm_struct *prev, struct mm_struct *next,4848+ struct task_struct *tsk)4949+{5050+ unsigned int cpu = smp_processor_id();5151+5252+ if (!cpumask_test_and_set_cpu(cpu, mm_cpumask(next)) || prev != next)5353+ cpu_switch_mm(next->pgd, next);5454+}5555+5656+#define deactivate_mm(tsk, mm) do { } while (0)5757+#define activate_mm(prev, next) switch_mm(prev, next, NULL)5858+5959+/*6060+ * We are inserting a "fake" vma for the user-accessible vector page so6161+ * gdb and friends can get to it through ptrace and /proc/<pid>/mem.6262+ * But we also want to remove it before the generic code gets to see it6363+ * during process exit or the unmapping of it would cause total havoc.6464+ * (the macro is used as remove_vma() is static to mm/mmap.c)6565+ */6666+#define arch_exit_mmap(mm) \6767+do { \6868+ struct vm_area_struct *high_vma = find_vma(mm, 0xffff0000); \6969+ if (high_vma) { \7070+ BUG_ON(high_vma->vm_next); /* it should be last */ \7171+ if (high_vma->vm_prev) \7272+ high_vma->vm_prev->vm_next = NULL; \7373+ else \7474+ mm->mmap = NULL; \7575+ rb_erase(&high_vma->vm_rb, &mm->mm_rb); \7676+ mm->mmap_cache = NULL; \7777+ mm->map_count--; \7878+ remove_vma(high_vma); \7979+ } \8080+} while (0)8181+8282+static inline void arch_dup_mmap(struct mm_struct *oldmm,8383+ struct mm_struct *mm)8484+{8585+}8686+8787+#endif
+110
arch/unicore32/include/asm/pgalloc.h
···11+/*22+ * linux/arch/unicore32/include/asm/pgalloc.h33+ *44+ * Code specific to PKUnity SoC and UniCore ISA55+ *66+ * Copyright (C) 2001-2010 GUAN Xue-tao77+ *88+ * This program is free software; you can redistribute it and/or modify99+ * it under the terms of the GNU General Public License version 2 as1010+ * published by the Free Software Foundation.1111+ */1212+#ifndef __UNICORE_PGALLOC_H__1313+#define __UNICORE_PGALLOC_H__1414+1515+#include <asm/pgtable-hwdef.h>1616+#include <asm/processor.h>1717+#include <asm/cacheflush.h>1818+#include <asm/tlbflush.h>1919+2020+#define check_pgt_cache() do { } while (0)2121+2222+#define _PAGE_USER_TABLE (PMD_TYPE_TABLE | PMD_PRESENT)2323+#define _PAGE_KERNEL_TABLE (PMD_TYPE_TABLE | PMD_PRESENT)2424+2525+extern pgd_t *get_pgd_slow(struct mm_struct *mm);2626+extern void free_pgd_slow(struct mm_struct *mm, pgd_t *pgd);2727+2828+#define pgd_alloc(mm) get_pgd_slow(mm)2929+#define pgd_free(mm, pgd) free_pgd_slow(mm, pgd)3030+3131+#define PGALLOC_GFP (GFP_KERNEL | __GFP_NOTRACK | __GFP_REPEAT | __GFP_ZERO)3232+3333+/*3434+ * Allocate one PTE table.3535+ */3636+static inline pte_t *3737+pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr)3838+{3939+ pte_t *pte;4040+4141+ pte = (pte_t *)__get_free_page(PGALLOC_GFP);4242+ if (pte)4343+ clean_dcache_area(pte, PTRS_PER_PTE * sizeof(pte_t));4444+4545+ return pte;4646+}4747+4848+static inline pgtable_t4949+pte_alloc_one(struct mm_struct *mm, unsigned long addr)5050+{5151+ struct page *pte;5252+5353+ pte = alloc_pages(PGALLOC_GFP, 0);5454+ if (pte) {5555+ if (!PageHighMem(pte)) {5656+ void *page = page_address(pte);5757+ clean_dcache_area(page, PTRS_PER_PTE * sizeof(pte_t));5858+ }5959+ pgtable_page_ctor(pte);6060+ }6161+6262+ return pte;6363+}6464+6565+/*6666+ * Free one PTE table.6767+ */6868+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)6969+{7070+ if (pte)7171+ free_page((unsigned long)pte);7272+}7373+7474+static inline void pte_free(struct mm_struct *mm, pgtable_t pte)7575+{7676+ pgtable_page_dtor(pte);7777+ __free_page(pte);7878+}7979+8080+static inline void __pmd_populate(pmd_t *pmdp, unsigned long pmdval)8181+{8282+ set_pmd(pmdp, __pmd(pmdval));8383+ flush_pmd_entry(pmdp);8484+}8585+8686+/*8787+ * Populate the pmdp entry with a pointer to the pte. This pmd is part8888+ * of the mm address space.8989+ */9090+static inline void9191+pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, pte_t *ptep)9292+{9393+ unsigned long pte_ptr = (unsigned long)ptep;9494+9595+ /*9696+ * The pmd must be loaded with the physical9797+ * address of the PTE table9898+ */9999+ __pmd_populate(pmdp, __pa(pte_ptr) | _PAGE_KERNEL_TABLE);100100+}101101+102102+static inline void103103+pmd_populate(struct mm_struct *mm, pmd_t *pmdp, pgtable_t ptep)104104+{105105+ __pmd_populate(pmdp,106106+ page_to_pfn(ptep) << PAGE_SHIFT | _PAGE_USER_TABLE);107107+}108108+#define pmd_pgtable(pmd) pmd_page(pmd)109109+110110+#endif
+55
arch/unicore32/include/asm/pgtable-hwdef.h
···11+/*22+ * linux/arch/unicore32/include/asm/pgtable-hwdef.h33+ *44+ * Code specific to PKUnity SoC and UniCore ISA55+ *66+ * Copyright (C) 2001-2010 GUAN Xue-tao77+ *88+ * This program is free software; you can redistribute it and/or modify99+ * it under the terms of the GNU General Public License version 2 as1010+ * published by the Free Software Foundation.1111+ */1212+#ifndef __UNICORE_PGTABLE_HWDEF_H__1313+#define __UNICORE_PGTABLE_HWDEF_H__1414+1515+/*1616+ * Hardware page table definitions.1717+ *1818+ * + Level 1 descriptor (PMD)1919+ * - common2020+ */2121+#define PMD_TYPE_MASK (3 << 0)2222+#define PMD_TYPE_TABLE (0 << 0)2323+/*#define PMD_TYPE_LARGE (1 << 0) */2424+#define PMD_TYPE_INVALID (2 << 0)2525+#define PMD_TYPE_SECT (3 << 0)2626+2727+#define PMD_PRESENT (1 << 2)2828+#define PMD_YOUNG (1 << 3)2929+3030+/*#define PMD_SECT_DIRTY (1 << 4) */3131+#define PMD_SECT_CACHEABLE (1 << 5)3232+#define PMD_SECT_EXEC (1 << 6)3333+#define PMD_SECT_WRITE (1 << 7)3434+#define PMD_SECT_READ (1 << 8)3535+3636+/*3737+ * + Level 2 descriptor (PTE)3838+ * - common3939+ */4040+#define PTE_TYPE_MASK (3 << 0)4141+#define PTE_TYPE_SMALL (0 << 0)4242+#define PTE_TYPE_MIDDLE (1 << 0)4343+#define PTE_TYPE_LARGE (2 << 0)4444+#define PTE_TYPE_INVALID (3 << 0)4545+4646+#define PTE_PRESENT (1 << 2)4747+#define PTE_FILE (1 << 3) /* only when !PRESENT */4848+#define PTE_YOUNG (1 << 3)4949+#define PTE_DIRTY (1 << 4)5050+#define PTE_CACHEABLE (1 << 5)5151+#define PTE_EXEC (1 << 6)5252+#define PTE_WRITE (1 << 7)5353+#define PTE_READ (1 << 8)5454+5555+#endif
+317
arch/unicore32/include/asm/pgtable.h
···11+/*22+ * linux/arch/unicore32/include/asm/pgtable.h33+ *44+ * Code specific to PKUnity SoC and UniCore ISA55+ *66+ * Copyright (C) 2001-2010 GUAN Xue-tao77+ *88+ * This program is free software; you can redistribute it and/or modify99+ * it under the terms of the GNU General Public License version 2 as1010+ * published by the Free Software Foundation.1111+ */1212+#ifndef __UNICORE_PGTABLE_H__1313+#define __UNICORE_PGTABLE_H__1414+1515+#include <asm-generic/pgtable-nopmd.h>1616+#include <asm/cpu-single.h>1717+1818+#include <asm/memory.h>1919+#include <asm/pgtable-hwdef.h>2020+2121+/*2222+ * Just any arbitrary offset to the start of the vmalloc VM area: the2323+ * current 8MB value just means that there will be a 8MB "hole" after the2424+ * physical memory until the kernel virtual memory starts. That means that2525+ * any out-of-bounds memory accesses will hopefully be caught.2626+ * The vmalloc() routines leaves a hole of 4kB between each vmalloced2727+ * area for the same reason. ;)2828+ *2929+ * Note that platforms may override VMALLOC_START, but they must provide3030+ * VMALLOC_END. VMALLOC_END defines the (exclusive) limit of this space,3131+ * which may not overlap IO space.3232+ */3333+#ifndef VMALLOC_START3434+#define VMALLOC_OFFSET SZ_8M3535+#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) \3636+ & ~(VMALLOC_OFFSET-1))3737+#define VMALLOC_END (0xff000000UL)3838+#endif3939+4040+#define PTRS_PER_PTE 10244141+#define PTRS_PER_PGD 10244242+4343+/*4444+ * PGDIR_SHIFT determines what a third-level page table entry can map4545+ */4646+#define PGDIR_SHIFT 224747+4848+#ifndef __ASSEMBLY__4949+extern void __pte_error(const char *file, int line, unsigned long val);5050+extern void __pgd_error(const char *file, int line, unsigned long val);5151+5252+#define pte_ERROR(pte) __pte_error(__FILE__, __LINE__, pte_val(pte))5353+#define pgd_ERROR(pgd) __pgd_error(__FILE__, __LINE__, pgd_val(pgd))5454+#endif /* !__ASSEMBLY__ */5555+5656+#define PGDIR_SIZE (1UL << PGDIR_SHIFT)5757+#define PGDIR_MASK (~(PGDIR_SIZE-1))5858+5959+/*6060+ * This is the lowest virtual address we can permit any user space6161+ * mapping to be mapped at. This is particularly important for6262+ * non-high vector CPUs.6363+ */6464+#define FIRST_USER_ADDRESS PAGE_SIZE6565+6666+#define FIRST_USER_PGD_NR 16767+#define USER_PTRS_PER_PGD ((TASK_SIZE/PGDIR_SIZE) - FIRST_USER_PGD_NR)6868+6969+/*7070+ * section address mask and size definitions.7171+ */7272+#define SECTION_SHIFT 227373+#define SECTION_SIZE (1UL << SECTION_SHIFT)7474+#define SECTION_MASK (~(SECTION_SIZE-1))7575+7676+#ifndef __ASSEMBLY__7777+7878+/*7979+ * The pgprot_* and protection_map entries will be fixed up in runtime8080+ * to include the cachable bits based on memory policy, as well as any8181+ * architecture dependent bits.8282+ */8383+#define _PTE_DEFAULT (PTE_PRESENT | PTE_YOUNG | PTE_CACHEABLE)8484+8585+extern pgprot_t pgprot_user;8686+extern pgprot_t pgprot_kernel;8787+8888+#define PAGE_NONE pgprot_user8989+#define PAGE_SHARED __pgprot(pgprot_val(pgprot_user | PTE_READ \9090+ | PTE_WRITE)9191+#define PAGE_SHARED_EXEC __pgprot(pgprot_val(pgprot_user | PTE_READ \9292+ | PTE_WRITE \9393+ | PTE_EXEC)9494+#define PAGE_COPY __pgprot(pgprot_val(pgprot_user | PTE_READ)9595+#define PAGE_COPY_EXEC __pgprot(pgprot_val(pgprot_user | PTE_READ \9696+ | PTE_EXEC)9797+#define PAGE_READONLY __pgprot(pgprot_val(pgprot_user | PTE_READ)9898+#define PAGE_READONLY_EXEC __pgprot(pgprot_val(pgprot_user | PTE_READ \9999+ | PTE_EXEC)100100+#define PAGE_KERNEL pgprot_kernel101101+#define PAGE_KERNEL_EXEC __pgprot(pgprot_val(pgprot_kernel | PTE_EXEC))102102+103103+#define __PAGE_NONE __pgprot(_PTE_DEFAULT)104104+#define __PAGE_SHARED __pgprot(_PTE_DEFAULT | PTE_READ \105105+ | PTE_WRITE)106106+#define __PAGE_SHARED_EXEC __pgprot(_PTE_DEFAULT | PTE_READ \107107+ | PTE_WRITE \108108+ | PTE_EXEC)109109+#define __PAGE_COPY __pgprot(_PTE_DEFAULT | PTE_READ)110110+#define __PAGE_COPY_EXEC __pgprot(_PTE_DEFAULT | PTE_READ \111111+ | PTE_EXEC)112112+#define __PAGE_READONLY __pgprot(_PTE_DEFAULT | PTE_READ)113113+#define __PAGE_READONLY_EXEC __pgprot(_PTE_DEFAULT | PTE_READ \114114+ | PTE_EXEC)115115+116116+#endif /* __ASSEMBLY__ */117117+118118+/*119119+ * The table below defines the page protection levels that we insert into our120120+ * Linux page table version. These get translated into the best that the121121+ * architecture can perform. Note that on UniCore hardware:122122+ * 1) We cannot do execute protection123123+ * 2) If we could do execute protection, then read is implied124124+ * 3) write implies read permissions125125+ */126126+#define __P000 __PAGE_NONE127127+#define __P001 __PAGE_READONLY128128+#define __P010 __PAGE_COPY129129+#define __P011 __PAGE_COPY130130+#define __P100 __PAGE_READONLY_EXEC131131+#define __P101 __PAGE_READONLY_EXEC132132+#define __P110 __PAGE_COPY_EXEC133133+#define __P111 __PAGE_COPY_EXEC134134+135135+#define __S000 __PAGE_NONE136136+#define __S001 __PAGE_READONLY137137+#define __S010 __PAGE_SHARED138138+#define __S011 __PAGE_SHARED139139+#define __S100 __PAGE_READONLY_EXEC140140+#define __S101 __PAGE_READONLY_EXEC141141+#define __S110 __PAGE_SHARED_EXEC142142+#define __S111 __PAGE_SHARED_EXEC143143+144144+#ifndef __ASSEMBLY__145145+/*146146+ * ZERO_PAGE is a global shared page that is always zero: used147147+ * for zero-mapped memory areas etc..148148+ */149149+extern struct page *empty_zero_page;150150+#define ZERO_PAGE(vaddr) (empty_zero_page)151151+152152+#define pte_pfn(pte) (pte_val(pte) >> PAGE_SHIFT)153153+#define pfn_pte(pfn, prot) (__pte(((pfn) << PAGE_SHIFT) \154154+ | pgprot_val(prot)))155155+156156+#define pte_none(pte) (!pte_val(pte))157157+#define pte_clear(mm, addr, ptep) set_pte(ptep, __pte(0))158158+#define pte_page(pte) (pfn_to_page(pte_pfn(pte)))159159+#define pte_offset_kernel(dir, addr) (pmd_page_vaddr(*(dir)) \160160+ + __pte_index(addr))161161+162162+#define pte_offset_map(dir, addr) (pmd_page_vaddr(*(dir)) \163163+ + __pte_index(addr))164164+#define pte_unmap(pte) do { } while (0)165165+166166+#define set_pte(ptep, pte) cpu_set_pte(ptep, pte)167167+168168+#define set_pte_at(mm, addr, ptep, pteval) \169169+ do { \170170+ set_pte(ptep, pteval); \171171+ } while (0)172172+173173+/*174174+ * The following only work if pte_present() is true.175175+ * Undefined behaviour if not..176176+ */177177+#define pte_present(pte) (pte_val(pte) & PTE_PRESENT)178178+#define pte_write(pte) (pte_val(pte) & PTE_WRITE)179179+#define pte_dirty(pte) (pte_val(pte) & PTE_DIRTY)180180+#define pte_young(pte) (pte_val(pte) & PTE_YOUNG)181181+#define pte_exec(pte) (pte_val(pte) & PTE_EXEC)182182+#define pte_special(pte) (0)183183+184184+#define PTE_BIT_FUNC(fn, op) \185185+static inline pte_t pte_##fn(pte_t pte) { pte_val(pte) op; return pte; }186186+187187+PTE_BIT_FUNC(wrprotect, &= ~PTE_WRITE);188188+PTE_BIT_FUNC(mkwrite, |= PTE_WRITE);189189+PTE_BIT_FUNC(mkclean, &= ~PTE_DIRTY);190190+PTE_BIT_FUNC(mkdirty, |= PTE_DIRTY);191191+PTE_BIT_FUNC(mkold, &= ~PTE_YOUNG);192192+PTE_BIT_FUNC(mkyoung, |= PTE_YOUNG);193193+194194+static inline pte_t pte_mkspecial(pte_t pte) { return pte; }195195+196196+/*197197+ * Mark the prot value as uncacheable.198198+ */199199+#define pgprot_noncached(prot) \200200+ __pgprot(pgprot_val(prot) & ~PTE_CACHEABLE)201201+#define pgprot_writecombine(prot) \202202+ __pgprot(pgprot_val(prot) & ~PTE_CACHEABLE)203203+#define pgprot_dmacoherent(prot) \204204+ __pgprot(pgprot_val(prot) & ~PTE_CACHEABLE)205205+206206+#define pmd_none(pmd) (!pmd_val(pmd))207207+#define pmd_present(pmd) (pmd_val(pmd) & PMD_PRESENT)208208+#define pmd_bad(pmd) (((pmd_val(pmd) & \209209+ (PMD_PRESENT | PMD_TYPE_MASK)) \210210+ != (PMD_PRESENT | PMD_TYPE_TABLE)))211211+212212+#define set_pmd(pmdpd, pmdval) \213213+ do { \214214+ *(pmdpd) = pmdval; \215215+ } while (0)216216+217217+#define pmd_clear(pmdp) \218218+ do { \219219+ set_pmd(pmdp, __pmd(0));\220220+ clean_pmd_entry(pmdp); \221221+ } while (0)222222+223223+#define pmd_page_vaddr(pmd) ((pte_t *)__va(pmd_val(pmd) & PAGE_MASK))224224+#define pmd_page(pmd) pfn_to_page(__phys_to_pfn(pmd_val(pmd)))225225+226226+/*227227+ * Conversion functions: convert a page and protection to a page entry,228228+ * and a page entry and page directory to the page they refer to.229229+ */230230+#define mk_pte(page, prot) pfn_pte(page_to_pfn(page), prot)231231+232232+/* to find an entry in a page-table-directory */233233+#define pgd_index(addr) ((addr) >> PGDIR_SHIFT)234234+235235+#define pgd_offset(mm, addr) ((mm)->pgd+pgd_index(addr))236236+237237+/* to find an entry in a kernel page-table-directory */238238+#define pgd_offset_k(addr) pgd_offset(&init_mm, addr)239239+240240+/* Find an entry in the third-level page table.. */241241+#define __pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))242242+243243+static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)244244+{245245+ const unsigned long mask = PTE_EXEC | PTE_WRITE | PTE_READ;246246+ pte_val(pte) = (pte_val(pte) & ~mask) | (pgprot_val(newprot) & mask);247247+ return pte;248248+}249249+250250+extern pgd_t swapper_pg_dir[PTRS_PER_PGD];251251+252252+/*253253+ * Encode and decode a swap entry. Swap entries are stored in the Linux254254+ * page tables as follows:255255+ *256256+ * 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1257257+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0258258+ * <--------------- offset --------------> <--- type --> 0 0 0 0 0259259+ *260260+ * This gives us up to 127 swap files and 32GB per swap file. Note that261261+ * the offset field is always non-zero.262262+ */263263+#define __SWP_TYPE_SHIFT 5264264+#define __SWP_TYPE_BITS 7265265+#define __SWP_TYPE_MASK ((1 << __SWP_TYPE_BITS) - 1)266266+#define __SWP_OFFSET_SHIFT (__SWP_TYPE_BITS + __SWP_TYPE_SHIFT)267267+268268+#define __swp_type(x) (((x).val >> __SWP_TYPE_SHIFT) \269269+ & __SWP_TYPE_MASK)270270+#define __swp_offset(x) ((x).val >> __SWP_OFFSET_SHIFT)271271+#define __swp_entry(type, offset) ((swp_entry_t) { \272272+ ((type) << __SWP_TYPE_SHIFT) | \273273+ ((offset) << __SWP_OFFSET_SHIFT) })274274+275275+#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) })276276+#define __swp_entry_to_pte(swp) ((pte_t) { (swp).val })277277+278278+/*279279+ * It is an error for the kernel to have more swap files than we can280280+ * encode in the PTEs. This ensures that we know when MAX_SWAPFILES281281+ * is increased beyond what we presently support.282282+ */283283+#define MAX_SWAPFILES_CHECK() \284284+ BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > __SWP_TYPE_BITS)285285+286286+/*287287+ * Encode and decode a file entry. File entries are stored in the Linux288288+ * page tables as follows:289289+ *290290+ * 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1291291+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0292292+ * <----------------------- offset ----------------------> 1 0 0 0293293+ */294294+#define pte_file(pte) (pte_val(pte) & PTE_FILE)295295+#define pte_to_pgoff(x) (pte_val(x) >> 4)296296+#define pgoff_to_pte(x) __pte(((x) << 4) | PTE_FILE)297297+298298+#define PTE_FILE_MAX_BITS 28299299+300300+/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */301301+/* FIXME: this is not correct */302302+#define kern_addr_valid(addr) (1)303303+304304+#include <asm-generic/pgtable.h>305305+306306+/*307307+ * remap a physical page `pfn' of size `size' with page protection `prot'308308+ * into virtual address `from'309309+ */310310+#define io_remap_pfn_range(vma, from, pfn, size, prot) \311311+ remap_pfn_range(vma, from, pfn, size, prot)312312+313313+#define pgtable_cache_init() do { } while (0)314314+315315+#endif /* !__ASSEMBLY__ */316316+317317+#endif /* __UNICORE_PGTABLE_H__ */
+523
arch/unicore32/mm/alignment.c
···11+/*22+ * linux/arch/unicore32/mm/alignment.c33+ *44+ * Code specific to PKUnity SoC and UniCore ISA55+ *66+ * Copyright (C) 2001-2010 GUAN Xue-tao77+ *88+ * This program is free software; you can redistribute it and/or modify99+ * it under the terms of the GNU General Public License version 2 as1010+ * published by the Free Software Foundation.1111+ */1212+/*1313+ * TODO:1414+ * FPU ldm/stm not handling1515+ */1616+#include <linux/compiler.h>1717+#include <linux/kernel.h>1818+#include <linux/errno.h>1919+#include <linux/string.h>2020+#include <linux/init.h>2121+#include <linux/sched.h>2222+#include <linux/uaccess.h>2323+2424+#include <asm/tlbflush.h>2525+#include <asm/unaligned.h>2626+2727+#define CODING_BITS(i) (i & 0xe0000120)2828+2929+#define LDST_P_BIT(i) (i & (1 << 28)) /* Preindex */3030+#define LDST_U_BIT(i) (i & (1 << 27)) /* Add offset */3131+#define LDST_W_BIT(i) (i & (1 << 25)) /* Writeback */3232+#define LDST_L_BIT(i) (i & (1 << 24)) /* Load */3333+3434+#define LDST_P_EQ_U(i) ((((i) ^ ((i) >> 1)) & (1 << 27)) == 0)3535+3636+#define LDSTH_I_BIT(i) (i & (1 << 26)) /* half-word immed */3737+#define LDM_S_BIT(i) (i & (1 << 26)) /* write ASR from BSR */3838+#define LDM_H_BIT(i) (i & (1 << 6)) /* select r0-r15 or r16-r31 */3939+4040+#define RN_BITS(i) ((i >> 19) & 31) /* Rn */4141+#define RD_BITS(i) ((i >> 14) & 31) /* Rd */4242+#define RM_BITS(i) (i & 31) /* Rm */4343+4444+#define REGMASK_BITS(i) (((i & 0x7fe00) >> 3) | (i & 0x3f))4545+#define OFFSET_BITS(i) (i & 0x03fff)4646+4747+#define SHIFT_BITS(i) ((i >> 9) & 0x1f)4848+#define SHIFT_TYPE(i) (i & 0xc0)4949+#define SHIFT_LSL 0x005050+#define SHIFT_LSR 0x405151+#define SHIFT_ASR 0x805252+#define SHIFT_RORRRX 0xc05353+5454+union offset_union {5555+ unsigned long un;5656+ signed long sn;5757+};5858+5959+#define TYPE_ERROR 06060+#define TYPE_FAULT 16161+#define TYPE_LDST 26262+#define TYPE_DONE 36363+#define TYPE_SWAP 46464+#define TYPE_COLS 5 /* Coprocessor load/store */6565+6666+#define get8_unaligned_check(val, addr, err) \6767+ __asm__( \6868+ "1: ldb.u %1, [%2], #1\n" \6969+ "2:\n" \7070+ " .pushsection .fixup,\"ax\"\n" \7171+ " .align 2\n" \7272+ "3: mov %0, #1\n" \7373+ " b 2b\n" \7474+ " .popsection\n" \7575+ " .pushsection __ex_table,\"a\"\n" \7676+ " .align 3\n" \7777+ " .long 1b, 3b\n" \7878+ " .popsection\n" \7979+ : "=r" (err), "=&r" (val), "=r" (addr) \8080+ : "0" (err), "2" (addr))8181+8282+#define get8t_unaligned_check(val, addr, err) \8383+ __asm__( \8484+ "1: ldb.u %1, [%2], #1\n" \8585+ "2:\n" \8686+ " .pushsection .fixup,\"ax\"\n" \8787+ " .align 2\n" \8888+ "3: mov %0, #1\n" \8989+ " b 2b\n" \9090+ " .popsection\n" \9191+ " .pushsection __ex_table,\"a\"\n" \9292+ " .align 3\n" \9393+ " .long 1b, 3b\n" \9494+ " .popsection\n" \9595+ : "=r" (err), "=&r" (val), "=r" (addr) \9696+ : "0" (err), "2" (addr))9797+9898+#define get16_unaligned_check(val, addr) \9999+ do { \100100+ unsigned int err = 0, v, a = addr; \101101+ get8_unaligned_check(val, a, err); \102102+ get8_unaligned_check(v, a, err); \103103+ val |= v << 8; \104104+ if (err) \105105+ goto fault; \106106+ } while (0)107107+108108+#define put16_unaligned_check(val, addr) \109109+ do { \110110+ unsigned int err = 0, v = val, a = addr; \111111+ __asm__( \112112+ "1: stb.u %1, [%2], #1\n" \113113+ " mov %1, %1 >> #8\n" \114114+ "2: stb.u %1, [%2]\n" \115115+ "3:\n" \116116+ " .pushsection .fixup,\"ax\"\n" \117117+ " .align 2\n" \118118+ "4: mov %0, #1\n" \119119+ " b 3b\n" \120120+ " .popsection\n" \121121+ " .pushsection __ex_table,\"a\"\n" \122122+ " .align 3\n" \123123+ " .long 1b, 4b\n" \124124+ " .long 2b, 4b\n" \125125+ " .popsection\n" \126126+ : "=r" (err), "=&r" (v), "=&r" (a) \127127+ : "0" (err), "1" (v), "2" (a)); \128128+ if (err) \129129+ goto fault; \130130+ } while (0)131131+132132+#define __put32_unaligned_check(ins, val, addr) \133133+ do { \134134+ unsigned int err = 0, v = val, a = addr; \135135+ __asm__( \136136+ "1: "ins" %1, [%2], #1\n" \137137+ " mov %1, %1 >> #8\n" \138138+ "2: "ins" %1, [%2], #1\n" \139139+ " mov %1, %1 >> #8\n" \140140+ "3: "ins" %1, [%2], #1\n" \141141+ " mov %1, %1 >> #8\n" \142142+ "4: "ins" %1, [%2]\n" \143143+ "5:\n" \144144+ " .pushsection .fixup,\"ax\"\n" \145145+ " .align 2\n" \146146+ "6: mov %0, #1\n" \147147+ " b 5b\n" \148148+ " .popsection\n" \149149+ " .pushsection __ex_table,\"a\"\n" \150150+ " .align 3\n" \151151+ " .long 1b, 6b\n" \152152+ " .long 2b, 6b\n" \153153+ " .long 3b, 6b\n" \154154+ " .long 4b, 6b\n" \155155+ " .popsection\n" \156156+ : "=r" (err), "=&r" (v), "=&r" (a) \157157+ : "0" (err), "1" (v), "2" (a)); \158158+ if (err) \159159+ goto fault; \160160+ } while (0)161161+162162+#define get32_unaligned_check(val, addr) \163163+ do { \164164+ unsigned int err = 0, v, a = addr; \165165+ get8_unaligned_check(val, a, err); \166166+ get8_unaligned_check(v, a, err); \167167+ val |= v << 8; \168168+ get8_unaligned_check(v, a, err); \169169+ val |= v << 16; \170170+ get8_unaligned_check(v, a, err); \171171+ val |= v << 24; \172172+ if (err) \173173+ goto fault; \174174+ } while (0)175175+176176+#define put32_unaligned_check(val, addr) \177177+ __put32_unaligned_check("stb.u", val, addr)178178+179179+#define get32t_unaligned_check(val, addr) \180180+ do { \181181+ unsigned int err = 0, v, a = addr; \182182+ get8t_unaligned_check(val, a, err); \183183+ get8t_unaligned_check(v, a, err); \184184+ val |= v << 8; \185185+ get8t_unaligned_check(v, a, err); \186186+ val |= v << 16; \187187+ get8t_unaligned_check(v, a, err); \188188+ val |= v << 24; \189189+ if (err) \190190+ goto fault; \191191+ } while (0)192192+193193+#define put32t_unaligned_check(val, addr) \194194+ __put32_unaligned_check("stb.u", val, addr)195195+196196+static void197197+do_alignment_finish_ldst(unsigned long addr, unsigned long instr,198198+ struct pt_regs *regs, union offset_union offset)199199+{200200+ if (!LDST_U_BIT(instr))201201+ offset.un = -offset.un;202202+203203+ if (!LDST_P_BIT(instr))204204+ addr += offset.un;205205+206206+ if (!LDST_P_BIT(instr) || LDST_W_BIT(instr))207207+ regs->uregs[RN_BITS(instr)] = addr;208208+}209209+210210+static int211211+do_alignment_ldrhstrh(unsigned long addr, unsigned long instr,212212+ struct pt_regs *regs)213213+{214214+ unsigned int rd = RD_BITS(instr);215215+216216+ /* old value 0x40002120, can't judge swap instr correctly */217217+ if ((instr & 0x4b003fe0) == 0x40000120)218218+ goto swp;219219+220220+ if (LDST_L_BIT(instr)) {221221+ unsigned long val;222222+ get16_unaligned_check(val, addr);223223+224224+ /* signed half-word? */225225+ if (instr & 0x80)226226+ val = (signed long)((signed short)val);227227+228228+ regs->uregs[rd] = val;229229+ } else230230+ put16_unaligned_check(regs->uregs[rd], addr);231231+232232+ return TYPE_LDST;233233+234234+swp:235235+ /* only handle swap word236236+ * for swap byte should not active this alignment exception */237237+ get32_unaligned_check(regs->uregs[RD_BITS(instr)], addr);238238+ put32_unaligned_check(regs->uregs[RM_BITS(instr)], addr);239239+ return TYPE_SWAP;240240+241241+fault:242242+ return TYPE_FAULT;243243+}244244+245245+static int246246+do_alignment_ldrstr(unsigned long addr, unsigned long instr,247247+ struct pt_regs *regs)248248+{249249+ unsigned int rd = RD_BITS(instr);250250+251251+ if (!LDST_P_BIT(instr) && LDST_W_BIT(instr))252252+ goto trans;253253+254254+ if (LDST_L_BIT(instr))255255+ get32_unaligned_check(regs->uregs[rd], addr);256256+ else257257+ put32_unaligned_check(regs->uregs[rd], addr);258258+ return TYPE_LDST;259259+260260+trans:261261+ if (LDST_L_BIT(instr))262262+ get32t_unaligned_check(regs->uregs[rd], addr);263263+ else264264+ put32t_unaligned_check(regs->uregs[rd], addr);265265+ return TYPE_LDST;266266+267267+fault:268268+ return TYPE_FAULT;269269+}270270+271271+/*272272+ * LDM/STM alignment handler.273273+ *274274+ * There are 4 variants of this instruction:275275+ *276276+ * B = rn pointer before instruction, A = rn pointer after instruction277277+ * ------ increasing address ----->278278+ * | | r0 | r1 | ... | rx | |279279+ * PU = 01 B A280280+ * PU = 11 B A281281+ * PU = 00 A B282282+ * PU = 10 A B283283+ */284284+static int285285+do_alignment_ldmstm(unsigned long addr, unsigned long instr,286286+ struct pt_regs *regs)287287+{288288+ unsigned int rd, rn, pc_correction, reg_correction, nr_regs, regbits;289289+ unsigned long eaddr, newaddr;290290+291291+ if (LDM_S_BIT(instr))292292+ goto bad;293293+294294+ pc_correction = 4; /* processor implementation defined */295295+296296+ /* count the number of registers in the mask to be transferred */297297+ nr_regs = hweight16(REGMASK_BITS(instr)) * 4;298298+299299+ rn = RN_BITS(instr);300300+ newaddr = eaddr = regs->uregs[rn];301301+302302+ if (!LDST_U_BIT(instr))303303+ nr_regs = -nr_regs;304304+ newaddr += nr_regs;305305+ if (!LDST_U_BIT(instr))306306+ eaddr = newaddr;307307+308308+ if (LDST_P_EQ_U(instr)) /* U = P */309309+ eaddr += 4;310310+311311+ /*312312+ * This is a "hint" - we already have eaddr worked out by the313313+ * processor for us.314314+ */315315+ if (addr != eaddr) {316316+ printk(KERN_ERR "LDMSTM: PC = %08lx, instr = %08lx, "317317+ "addr = %08lx, eaddr = %08lx\n",318318+ instruction_pointer(regs), instr, addr, eaddr);319319+ show_regs(regs);320320+ }321321+322322+ if (LDM_H_BIT(instr))323323+ reg_correction = 0x10;324324+ else325325+ reg_correction = 0x00;326326+327327+ for (regbits = REGMASK_BITS(instr), rd = 0; regbits;328328+ regbits >>= 1, rd += 1)329329+ if (regbits & 1) {330330+ if (LDST_L_BIT(instr))331331+ get32_unaligned_check(regs->332332+ uregs[rd + reg_correction], eaddr);333333+ else334334+ put32_unaligned_check(regs->335335+ uregs[rd + reg_correction], eaddr);336336+ eaddr += 4;337337+ }338338+339339+ if (LDST_W_BIT(instr))340340+ regs->uregs[rn] = newaddr;341341+ return TYPE_DONE;342342+343343+fault:344344+ regs->UCreg_pc -= pc_correction;345345+ return TYPE_FAULT;346346+347347+bad:348348+ printk(KERN_ERR "Alignment trap: not handling ldm with s-bit set\n");349349+ return TYPE_ERROR;350350+}351351+352352+static int353353+do_alignment(unsigned long addr, unsigned int error_code, struct pt_regs *regs)354354+{355355+ union offset_union offset;356356+ unsigned long instr, instrptr;357357+ int (*handler) (unsigned long addr, unsigned long instr,358358+ struct pt_regs *regs);359359+ unsigned int type;360360+361361+ instrptr = instruction_pointer(regs);362362+ if (instrptr >= PAGE_OFFSET)363363+ instr = *(unsigned long *)instrptr;364364+ else {365365+ __asm__ __volatile__(366366+ "ldw.u %0, [%1]\n"367367+ : "=&r"(instr)368368+ : "r"(instrptr));369369+ }370370+371371+ regs->UCreg_pc += 4;372372+373373+ switch (CODING_BITS(instr)) {374374+ case 0x40000120: /* ldrh or strh */375375+ if (LDSTH_I_BIT(instr))376376+ offset.un = (instr & 0x3e00) >> 4 | (instr & 31);377377+ else378378+ offset.un = regs->uregs[RM_BITS(instr)];379379+ handler = do_alignment_ldrhstrh;380380+ break;381381+382382+ case 0x60000000: /* ldr or str immediate */383383+ case 0x60000100: /* ldr or str immediate */384384+ case 0x60000020: /* ldr or str immediate */385385+ case 0x60000120: /* ldr or str immediate */386386+ offset.un = OFFSET_BITS(instr);387387+ handler = do_alignment_ldrstr;388388+ break;389389+390390+ case 0x40000000: /* ldr or str register */391391+ offset.un = regs->uregs[RM_BITS(instr)];392392+ {393393+ unsigned int shiftval = SHIFT_BITS(instr);394394+395395+ switch (SHIFT_TYPE(instr)) {396396+ case SHIFT_LSL:397397+ offset.un <<= shiftval;398398+ break;399399+400400+ case SHIFT_LSR:401401+ offset.un >>= shiftval;402402+ break;403403+404404+ case SHIFT_ASR:405405+ offset.sn >>= shiftval;406406+ break;407407+408408+ case SHIFT_RORRRX:409409+ if (shiftval == 0) {410410+ offset.un >>= 1;411411+ if (regs->UCreg_asr & PSR_C_BIT)412412+ offset.un |= 1 << 31;413413+ } else414414+ offset.un = offset.un >> shiftval |415415+ offset.un << (32 - shiftval);416416+ break;417417+ }418418+ }419419+ handler = do_alignment_ldrstr;420420+ break;421421+422422+ case 0x80000000: /* ldm or stm */423423+ case 0x80000020: /* ldm or stm */424424+ handler = do_alignment_ldmstm;425425+ break;426426+427427+ default:428428+ goto bad;429429+ }430430+431431+ type = handler(addr, instr, regs);432432+433433+ if (type == TYPE_ERROR || type == TYPE_FAULT)434434+ goto bad_or_fault;435435+436436+ if (type == TYPE_LDST)437437+ do_alignment_finish_ldst(addr, instr, regs, offset);438438+439439+ return 0;440440+441441+bad_or_fault:442442+ if (type == TYPE_ERROR)443443+ goto bad;444444+ regs->UCreg_pc -= 4;445445+ /*446446+ * We got a fault - fix it up, or die.447447+ */448448+ do_bad_area(addr, error_code, regs);449449+ return 0;450450+451451+bad:452452+ /*453453+ * Oops, we didn't handle the instruction.454454+ * However, we must handle fpu instr firstly.455455+ */456456+#ifdef CONFIG_UNICORE_FPU_F64457457+ /* handle co.load/store */458458+#define CODING_COLS 0xc0000000459459+#define COLS_OFFSET_BITS(i) (i & 0x1FF)460460+#define COLS_L_BITS(i) (i & (1<<24))461461+#define COLS_FN_BITS(i) ((i>>14) & 31)462462+ if ((instr & 0xe0000000) == CODING_COLS) {463463+ unsigned int fn = COLS_FN_BITS(instr);464464+ unsigned long val = 0;465465+ if (COLS_L_BITS(instr)) {466466+ get32t_unaligned_check(val, addr);467467+ switch (fn) {468468+#define ASM_MTF(n) case n: \469469+ __asm__ __volatile__("MTF %0, F" __stringify(n) \470470+ : : "r"(val)); \471471+ break;472472+ ASM_MTF(0); ASM_MTF(1); ASM_MTF(2); ASM_MTF(3);473473+ ASM_MTF(4); ASM_MTF(5); ASM_MTF(6); ASM_MTF(7);474474+ ASM_MTF(8); ASM_MTF(9); ASM_MTF(10); ASM_MTF(11);475475+ ASM_MTF(12); ASM_MTF(13); ASM_MTF(14); ASM_MTF(15);476476+ ASM_MTF(16); ASM_MTF(17); ASM_MTF(18); ASM_MTF(19);477477+ ASM_MTF(20); ASM_MTF(21); ASM_MTF(22); ASM_MTF(23);478478+ ASM_MTF(24); ASM_MTF(25); ASM_MTF(26); ASM_MTF(27);479479+ ASM_MTF(28); ASM_MTF(29); ASM_MTF(30); ASM_MTF(31);480480+#undef ASM_MTF481481+ }482482+ } else {483483+ switch (fn) {484484+#define ASM_MFF(n) case n: \485485+ __asm__ __volatile__("MFF %0, F" __stringify(n) \486486+ : : "r"(val)); \487487+ break;488488+ ASM_MFF(0); ASM_MFF(1); ASM_MFF(2); ASM_MFF(3);489489+ ASM_MFF(4); ASM_MFF(5); ASM_MFF(6); ASM_MFF(7);490490+ ASM_MFF(8); ASM_MFF(9); ASM_MFF(10); ASM_MFF(11);491491+ ASM_MFF(12); ASM_MFF(13); ASM_MFF(14); ASM_MFF(15);492492+ ASM_MFF(16); ASM_MFF(17); ASM_MFF(18); ASM_MFF(19);493493+ ASM_MFF(20); ASM_MFF(21); ASM_MFF(22); ASM_MFF(23);494494+ ASM_MFF(24); ASM_MFF(25); ASM_MFF(26); ASM_MFF(27);495495+ ASM_MFF(28); ASM_MFF(29); ASM_MFF(30); ASM_MFF(31);496496+#undef ASM_MFF497497+ }498498+ put32t_unaligned_check(val, addr);499499+ }500500+ return TYPE_COLS;501501+ }502502+fault:503503+ return TYPE_FAULT;504504+#endif505505+ printk(KERN_ERR "Alignment trap: not handling instruction "506506+ "%08lx at [<%08lx>]\n", instr, instrptr);507507+ return 1;508508+}509509+510510+/*511511+ * This needs to be done after sysctl_init, otherwise sys/ will be512512+ * overwritten. Actually, this shouldn't be in sys/ at all since513513+ * it isn't a sysctl, and it doesn't contain sysctl information.514514+ */515515+static int __init alignment_init(void)516516+{517517+ hook_fault_code(1, do_alignment, SIGBUS, BUS_ADRALN,518518+ "alignment exception");519519+520520+ return 0;521521+}522522+523523+fs_initcall(alignment_init);
+24
arch/unicore32/mm/extable.c
···11+/*22+ * linux/arch/unicore32/mm/extable.c33+ *44+ * Code specific to PKUnity SoC and UniCore ISA55+ *66+ * Copyright (C) 2001-2010 GUAN Xue-tao77+ *88+ * This program is free software; you can redistribute it and/or modify99+ * it under the terms of the GNU General Public License version 2 as1010+ * published by the Free Software Foundation.1111+ */1212+#include <linux/module.h>1313+#include <linux/uaccess.h>1414+1515+int fixup_exception(struct pt_regs *regs)1616+{1717+ const struct exception_table_entry *fixup;1818+1919+ fixup = search_exception_tables(instruction_pointer(regs));2020+ if (fixup)2121+ regs->UCreg_pc = fixup->fixup;2222+2323+ return fixup != NULL;2424+}
+479
arch/unicore32/mm/fault.c
···11+/*22+ * linux/arch/unicore32/mm/fault.c33+ *44+ * Code specific to PKUnity SoC and UniCore ISA55+ *66+ * Copyright (C) 2001-2010 GUAN Xue-tao77+ *88+ * This program is free software; you can redistribute it and/or modify99+ * it under the terms of the GNU General Public License version 2 as1010+ * published by the Free Software Foundation.1111+ */1212+#include <linux/module.h>1313+#include <linux/signal.h>1414+#include <linux/mm.h>1515+#include <linux/hardirq.h>1616+#include <linux/init.h>1717+#include <linux/kprobes.h>1818+#include <linux/uaccess.h>1919+#include <linux/page-flags.h>2020+#include <linux/sched.h>2121+#include <linux/io.h>2222+2323+#include <asm/system.h>2424+#include <asm/pgtable.h>2525+#include <asm/tlbflush.h>2626+2727+/*2828+ * Fault status register encodings. We steal bit 31 for our own purposes.2929+ */3030+#define FSR_LNX_PF (1 << 31)3131+3232+static inline int fsr_fs(unsigned int fsr)3333+{3434+ /* xyabcde will be abcde+xy */3535+ return (fsr & 31) + ((fsr & (3 << 5)) >> 5);3636+}3737+3838+/*3939+ * This is useful to dump out the page tables associated with4040+ * 'addr' in mm 'mm'.4141+ */4242+void show_pte(struct mm_struct *mm, unsigned long addr)4343+{4444+ pgd_t *pgd;4545+4646+ if (!mm)4747+ mm = &init_mm;4848+4949+ printk(KERN_ALERT "pgd = %p\n", mm->pgd);5050+ pgd = pgd_offset(mm, addr);5151+ printk(KERN_ALERT "[%08lx] *pgd=%08lx", addr, pgd_val(*pgd));5252+5353+ do {5454+ pmd_t *pmd;5555+ pte_t *pte;5656+5757+ if (pgd_none(*pgd))5858+ break;5959+6060+ if (pgd_bad(*pgd)) {6161+ printk("(bad)");6262+ break;6363+ }6464+6565+ pmd = pmd_offset((pud_t *) pgd, addr);6666+ if (PTRS_PER_PMD != 1)6767+ printk(", *pmd=%08lx", pmd_val(*pmd));6868+6969+ if (pmd_none(*pmd))7070+ break;7171+7272+ if (pmd_bad(*pmd)) {7373+ printk("(bad)");7474+ break;7575+ }7676+7777+ /* We must not map this if we have highmem enabled */7878+ if (PageHighMem(pfn_to_page(pmd_val(*pmd) >> PAGE_SHIFT)))7979+ break;8080+8181+ pte = pte_offset_map(pmd, addr);8282+ printk(", *pte=%08lx", pte_val(*pte));8383+ pte_unmap(pte);8484+ } while (0);8585+8686+ printk("\n");8787+}8888+8989+/*9090+ * Oops. The kernel tried to access some page that wasn't present.9191+ */9292+static void __do_kernel_fault(struct mm_struct *mm, unsigned long addr,9393+ unsigned int fsr, struct pt_regs *regs)9494+{9595+ /*9696+ * Are we prepared to handle this kernel fault?9797+ */9898+ if (fixup_exception(regs))9999+ return;100100+101101+ /*102102+ * No handler, we'll have to terminate things with extreme prejudice.103103+ */104104+ bust_spinlocks(1);105105+ printk(KERN_ALERT106106+ "Unable to handle kernel %s at virtual address %08lx\n",107107+ (addr < PAGE_SIZE) ? "NULL pointer dereference" :108108+ "paging request", addr);109109+110110+ show_pte(mm, addr);111111+ die("Oops", regs, fsr);112112+ bust_spinlocks(0);113113+ do_exit(SIGKILL);114114+}115115+116116+/*117117+ * Something tried to access memory that isn't in our memory map..118118+ * User mode accesses just cause a SIGSEGV119119+ */120120+static void __do_user_fault(struct task_struct *tsk, unsigned long addr,121121+ unsigned int fsr, unsigned int sig, int code,122122+ struct pt_regs *regs)123123+{124124+ struct siginfo si;125125+126126+ tsk->thread.address = addr;127127+ tsk->thread.error_code = fsr;128128+ tsk->thread.trap_no = 14;129129+ si.si_signo = sig;130130+ si.si_errno = 0;131131+ si.si_code = code;132132+ si.si_addr = (void __user *)addr;133133+ force_sig_info(sig, &si, tsk);134134+}135135+136136+void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs)137137+{138138+ struct task_struct *tsk = current;139139+ struct mm_struct *mm = tsk->active_mm;140140+141141+ /*142142+ * If we are in kernel mode at this point, we143143+ * have no context to handle this fault with.144144+ */145145+ if (user_mode(regs))146146+ __do_user_fault(tsk, addr, fsr, SIGSEGV, SEGV_MAPERR, regs);147147+ else148148+ __do_kernel_fault(mm, addr, fsr, regs);149149+}150150+151151+#define VM_FAULT_BADMAP 0x010000152152+#define VM_FAULT_BADACCESS 0x020000153153+154154+/*155155+ * Check that the permissions on the VMA allow for the fault which occurred.156156+ * If we encountered a write fault, we must have write permission, otherwise157157+ * we allow any permission.158158+ */159159+static inline bool access_error(unsigned int fsr, struct vm_area_struct *vma)160160+{161161+ unsigned int mask = VM_READ | VM_WRITE | VM_EXEC;162162+163163+ if (!(fsr ^ 0x12)) /* write? */164164+ mask = VM_WRITE;165165+ if (fsr & FSR_LNX_PF)166166+ mask = VM_EXEC;167167+168168+ return vma->vm_flags & mask ? false : true;169169+}170170+171171+static int __do_pf(struct mm_struct *mm, unsigned long addr, unsigned int fsr,172172+ struct task_struct *tsk)173173+{174174+ struct vm_area_struct *vma;175175+ int fault;176176+177177+ vma = find_vma(mm, addr);178178+ fault = VM_FAULT_BADMAP;179179+ if (unlikely(!vma))180180+ goto out;181181+ if (unlikely(vma->vm_start > addr))182182+ goto check_stack;183183+184184+ /*185185+ * Ok, we have a good vm_area for this186186+ * memory access, so we can handle it.187187+ */188188+good_area:189189+ if (access_error(fsr, vma)) {190190+ fault = VM_FAULT_BADACCESS;191191+ goto out;192192+ }193193+194194+ /*195195+ * If for any reason at all we couldn't handle the fault, make196196+ * sure we exit gracefully rather than endlessly redo the fault.197197+ */198198+ fault = handle_mm_fault(mm, vma, addr & PAGE_MASK,199199+ (!(fsr ^ 0x12)) ? FAULT_FLAG_WRITE : 0);200200+ if (unlikely(fault & VM_FAULT_ERROR))201201+ return fault;202202+ if (fault & VM_FAULT_MAJOR)203203+ tsk->maj_flt++;204204+ else205205+ tsk->min_flt++;206206+ return fault;207207+208208+check_stack:209209+ if (vma->vm_flags & VM_GROWSDOWN && !expand_stack(vma, addr))210210+ goto good_area;211211+out:212212+ return fault;213213+}214214+215215+static int do_pf(unsigned long addr, unsigned int fsr, struct pt_regs *regs)216216+{217217+ struct task_struct *tsk;218218+ struct mm_struct *mm;219219+ int fault, sig, code;220220+221221+ tsk = current;222222+ mm = tsk->mm;223223+224224+ /*225225+ * If we're in an interrupt or have no user226226+ * context, we must not take the fault..227227+ */228228+ if (in_atomic() || !mm)229229+ goto no_context;230230+231231+ /*232232+ * As per x86, we may deadlock here. However, since the kernel only233233+ * validly references user space from well defined areas of the code,234234+ * we can bug out early if this is from code which shouldn't.235235+ */236236+ if (!down_read_trylock(&mm->mmap_sem)) {237237+ if (!user_mode(regs)238238+ && !search_exception_tables(regs->UCreg_pc))239239+ goto no_context;240240+ down_read(&mm->mmap_sem);241241+ } else {242242+ /*243243+ * The above down_read_trylock() might have succeeded in244244+ * which case, we'll have missed the might_sleep() from245245+ * down_read()246246+ */247247+ might_sleep();248248+#ifdef CONFIG_DEBUG_VM249249+ if (!user_mode(regs) &&250250+ !search_exception_tables(regs->UCreg_pc))251251+ goto no_context;252252+#endif253253+ }254254+255255+ fault = __do_pf(mm, addr, fsr, tsk);256256+ up_read(&mm->mmap_sem);257257+258258+ /*259259+ * Handle the "normal" case first - VM_FAULT_MAJOR / VM_FAULT_MINOR260260+ */261261+ if (likely(!(fault &262262+ (VM_FAULT_ERROR | VM_FAULT_BADMAP | VM_FAULT_BADACCESS))))263263+ return 0;264264+265265+ if (fault & VM_FAULT_OOM) {266266+ /*267267+ * We ran out of memory, call the OOM killer, and return to268268+ * userspace (which will retry the fault, or kill us if we269269+ * got oom-killed)270270+ */271271+ pagefault_out_of_memory();272272+ return 0;273273+ }274274+275275+ /*276276+ * If we are in kernel mode at this point, we277277+ * have no context to handle this fault with.278278+ */279279+ if (!user_mode(regs))280280+ goto no_context;281281+282282+ if (fault & VM_FAULT_SIGBUS) {283283+ /*284284+ * We had some memory, but were unable to285285+ * successfully fix up this page fault.286286+ */287287+ sig = SIGBUS;288288+ code = BUS_ADRERR;289289+ } else {290290+ /*291291+ * Something tried to access memory that292292+ * isn't in our memory map..293293+ */294294+ sig = SIGSEGV;295295+ code = fault == VM_FAULT_BADACCESS ? SEGV_ACCERR : SEGV_MAPERR;296296+ }297297+298298+ __do_user_fault(tsk, addr, fsr, sig, code, regs);299299+ return 0;300300+301301+no_context:302302+ __do_kernel_fault(mm, addr, fsr, regs);303303+ return 0;304304+}305305+306306+/*307307+ * First Level Translation Fault Handler308308+ *309309+ * We enter here because the first level page table doesn't contain310310+ * a valid entry for the address.311311+ *312312+ * If the address is in kernel space (>= TASK_SIZE), then we are313313+ * probably faulting in the vmalloc() area.314314+ *315315+ * If the init_task's first level page tables contains the relevant316316+ * entry, we copy the it to this task. If not, we send the process317317+ * a signal, fixup the exception, or oops the kernel.318318+ *319319+ * NOTE! We MUST NOT take any locks for this case. We may be in an320320+ * interrupt or a critical region, and should only copy the information321321+ * from the master page table, nothing more.322322+ */323323+static int do_ifault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)324324+{325325+ unsigned int index;326326+ pgd_t *pgd, *pgd_k;327327+ pmd_t *pmd, *pmd_k;328328+329329+ if (addr < TASK_SIZE)330330+ return do_pf(addr, fsr, regs);331331+332332+ if (user_mode(regs))333333+ goto bad_area;334334+335335+ index = pgd_index(addr);336336+337337+ pgd = cpu_get_pgd() + index;338338+ pgd_k = init_mm.pgd + index;339339+340340+ if (pgd_none(*pgd_k))341341+ goto bad_area;342342+343343+ pmd_k = pmd_offset((pud_t *) pgd_k, addr);344344+ pmd = pmd_offset((pud_t *) pgd, addr);345345+346346+ if (pmd_none(*pmd_k))347347+ goto bad_area;348348+349349+ set_pmd(pmd, *pmd_k);350350+ flush_pmd_entry(pmd);351351+ return 0;352352+353353+bad_area:354354+ do_bad_area(addr, fsr, regs);355355+ return 0;356356+}357357+358358+/*359359+ * This abort handler always returns "fault".360360+ */361361+static int do_bad(unsigned long addr, unsigned int fsr, struct pt_regs *regs)362362+{363363+ return 1;364364+}365365+366366+static int do_good(unsigned long addr, unsigned int fsr, struct pt_regs *regs)367367+{368368+ unsigned int res1, res2;369369+370370+ printk("dabt exception but no error!\n");371371+372372+ __asm__ __volatile__(373373+ "mff %0,f0\n"374374+ "mff %1,f1\n"375375+ : "=r"(res1), "=r"(res2)376376+ :377377+ : "memory");378378+379379+ printk(KERN_EMERG "r0 :%08x r1 :%08x\n", res1, res2);380380+ panic("shut up\n");381381+ return 0;382382+}383383+384384+static struct fsr_info {385385+ int (*fn) (unsigned long addr, unsigned int fsr, struct pt_regs *regs);386386+ int sig;387387+ int code;388388+ const char *name;389389+} fsr_info[] = {390390+ /*391391+ * The following are the standard Unicore-I and UniCore-II aborts.392392+ */393393+ { do_good, SIGBUS, 0, "no error" },394394+ { do_bad, SIGBUS, BUS_ADRALN, "alignment exception" },395395+ { do_bad, SIGBUS, BUS_OBJERR, "external exception" },396396+ { do_bad, SIGBUS, 0, "burst operation" },397397+ { do_bad, SIGBUS, 0, "unknown 00100" },398398+ { do_ifault, SIGSEGV, SEGV_MAPERR, "2nd level pt non-exist"},399399+ { do_bad, SIGBUS, 0, "2nd lvl large pt non-exist" },400400+ { do_bad, SIGBUS, 0, "invalid pte" },401401+ { do_pf, SIGSEGV, SEGV_MAPERR, "page miss" },402402+ { do_bad, SIGBUS, 0, "middle page miss" },403403+ { do_bad, SIGBUS, 0, "large page miss" },404404+ { do_pf, SIGSEGV, SEGV_MAPERR, "super page (section) miss" },405405+ { do_bad, SIGBUS, 0, "unknown 01100" },406406+ { do_bad, SIGBUS, 0, "unknown 01101" },407407+ { do_bad, SIGBUS, 0, "unknown 01110" },408408+ { do_bad, SIGBUS, 0, "unknown 01111" },409409+ { do_bad, SIGBUS, 0, "addr: up 3G or IO" },410410+ { do_pf, SIGSEGV, SEGV_ACCERR, "read unreadable addr" },411411+ { do_pf, SIGSEGV, SEGV_ACCERR, "write unwriteable addr"},412412+ { do_pf, SIGSEGV, SEGV_ACCERR, "exec unexecutable addr"},413413+ { do_bad, SIGBUS, 0, "unknown 10100" },414414+ { do_bad, SIGBUS, 0, "unknown 10101" },415415+ { do_bad, SIGBUS, 0, "unknown 10110" },416416+ { do_bad, SIGBUS, 0, "unknown 10111" },417417+ { do_bad, SIGBUS, 0, "unknown 11000" },418418+ { do_bad, SIGBUS, 0, "unknown 11001" },419419+ { do_bad, SIGBUS, 0, "unknown 11010" },420420+ { do_bad, SIGBUS, 0, "unknown 11011" },421421+ { do_bad, SIGBUS, 0, "unknown 11100" },422422+ { do_bad, SIGBUS, 0, "unknown 11101" },423423+ { do_bad, SIGBUS, 0, "unknown 11110" },424424+ { do_bad, SIGBUS, 0, "unknown 11111" }425425+};426426+427427+void __init hook_fault_code(int nr,428428+ int (*fn) (unsigned long, unsigned int, struct pt_regs *),429429+ int sig, int code, const char *name)430430+{431431+ if (nr < 0 || nr >= ARRAY_SIZE(fsr_info))432432+ BUG();433433+434434+ fsr_info[nr].fn = fn;435435+ fsr_info[nr].sig = sig;436436+ fsr_info[nr].code = code;437437+ fsr_info[nr].name = name;438438+}439439+440440+/*441441+ * Dispatch a data abort to the relevant handler.442442+ */443443+asmlinkage void do_DataAbort(unsigned long addr, unsigned int fsr,444444+ struct pt_regs *regs)445445+{446446+ const struct fsr_info *inf = fsr_info + fsr_fs(fsr);447447+ struct siginfo info;448448+449449+ if (!inf->fn(addr, fsr & ~FSR_LNX_PF, regs))450450+ return;451451+452452+ printk(KERN_ALERT "Unhandled fault: %s (0x%03x) at 0x%08lx\n",453453+ inf->name, fsr, addr);454454+455455+ info.si_signo = inf->sig;456456+ info.si_errno = 0;457457+ info.si_code = inf->code;458458+ info.si_addr = (void __user *)addr;459459+ uc32_notify_die("", regs, &info, fsr, 0);460460+}461461+462462+asmlinkage void do_PrefetchAbort(unsigned long addr,463463+ unsigned int ifsr, struct pt_regs *regs)464464+{465465+ const struct fsr_info *inf = fsr_info + fsr_fs(ifsr);466466+ struct siginfo info;467467+468468+ if (!inf->fn(addr, ifsr | FSR_LNX_PF, regs))469469+ return;470470+471471+ printk(KERN_ALERT "Unhandled prefetch abort: %s (0x%03x) at 0x%08lx\n",472472+ inf->name, ifsr, addr);473473+474474+ info.si_signo = inf->sig;475475+ info.si_errno = 0;476476+ info.si_code = inf->code;477477+ info.si_addr = (void __user *)addr;478478+ uc32_notify_die("", regs, &info, ifsr, 0);479479+}
+533
arch/unicore32/mm/mmu.c
···11+/*22+ * linux/arch/unicore32/mm/mmu.c33+ *44+ * Code specific to PKUnity SoC and UniCore ISA55+ *66+ * Copyright (C) 2001-2010 GUAN Xue-tao77+ *88+ * This program is free software; you can redistribute it and/or modify99+ * it under the terms of the GNU General Public License version 2 as1010+ * published by the Free Software Foundation.1111+ */1212+#include <linux/module.h>1313+#include <linux/kernel.h>1414+#include <linux/errno.h>1515+#include <linux/init.h>1616+#include <linux/mman.h>1717+#include <linux/nodemask.h>1818+#include <linux/memblock.h>1919+#include <linux/fs.h>2020+#include <linux/bootmem.h>2121+#include <linux/io.h>2222+2323+#include <asm/cputype.h>2424+#include <asm/sections.h>2525+#include <asm/setup.h>2626+#include <asm/sizes.h>2727+#include <asm/tlb.h>2828+2929+#include <mach/map.h>3030+3131+#include "mm.h"3232+3333+DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);3434+3535+/*3636+ * empty_zero_page is a special page that is used for3737+ * zero-initialized data and COW.3838+ */3939+struct page *empty_zero_page;4040+EXPORT_SYMBOL(empty_zero_page);4141+4242+/*4343+ * The pmd table for the upper-most set of pages.4444+ */4545+pmd_t *top_pmd;4646+4747+pgprot_t pgprot_user;4848+EXPORT_SYMBOL(pgprot_user);4949+5050+pgprot_t pgprot_kernel;5151+EXPORT_SYMBOL(pgprot_kernel);5252+5353+static int __init noalign_setup(char *__unused)5454+{5555+ cr_alignment &= ~CR_A;5656+ cr_no_alignment &= ~CR_A;5757+ set_cr(cr_alignment);5858+ return 1;5959+}6060+__setup("noalign", noalign_setup);6161+6262+void adjust_cr(unsigned long mask, unsigned long set)6363+{6464+ unsigned long flags;6565+6666+ mask &= ~CR_A;6767+6868+ set &= mask;6969+7070+ local_irq_save(flags);7171+7272+ cr_no_alignment = (cr_no_alignment & ~mask) | set;7373+ cr_alignment = (cr_alignment & ~mask) | set;7474+7575+ set_cr((get_cr() & ~mask) | set);7676+7777+ local_irq_restore(flags);7878+}7979+8080+struct map_desc {8181+ unsigned long virtual;8282+ unsigned long pfn;8383+ unsigned long length;8484+ unsigned int type;8585+};8686+8787+#define PROT_PTE_DEVICE (PTE_PRESENT | PTE_YOUNG | \8888+ PTE_DIRTY | PTE_READ | PTE_WRITE)8989+#define PROT_SECT_DEVICE (PMD_TYPE_SECT | PMD_PRESENT | \9090+ PMD_SECT_READ | PMD_SECT_WRITE)9191+9292+static struct mem_type mem_types[] = {9393+ [MT_DEVICE] = { /* Strongly ordered */9494+ .prot_pte = PROT_PTE_DEVICE,9595+ .prot_l1 = PMD_TYPE_TABLE | PMD_PRESENT,9696+ .prot_sect = PROT_SECT_DEVICE,9797+ },9898+ /*9999+ * MT_KUSER: pte for vecpage -- cacheable,100100+ * and sect for unigfx mmap -- noncacheable101101+ */102102+ [MT_KUSER] = {103103+ .prot_pte = PTE_PRESENT | PTE_YOUNG | PTE_DIRTY |104104+ PTE_CACHEABLE | PTE_READ | PTE_EXEC,105105+ .prot_l1 = PMD_TYPE_TABLE | PMD_PRESENT,106106+ .prot_sect = PROT_SECT_DEVICE,107107+ },108108+ [MT_HIGH_VECTORS] = {109109+ .prot_pte = PTE_PRESENT | PTE_YOUNG | PTE_DIRTY |110110+ PTE_CACHEABLE | PTE_READ | PTE_WRITE |111111+ PTE_EXEC,112112+ .prot_l1 = PMD_TYPE_TABLE | PMD_PRESENT,113113+ },114114+ [MT_MEMORY] = {115115+ .prot_pte = PTE_PRESENT | PTE_YOUNG | PTE_DIRTY |116116+ PTE_WRITE | PTE_EXEC,117117+ .prot_l1 = PMD_TYPE_TABLE | PMD_PRESENT,118118+ .prot_sect = PMD_TYPE_SECT | PMD_PRESENT | PMD_SECT_CACHEABLE |119119+ PMD_SECT_READ | PMD_SECT_WRITE | PMD_SECT_EXEC,120120+ },121121+ [MT_ROM] = {122122+ .prot_sect = PMD_TYPE_SECT | PMD_PRESENT | PMD_SECT_CACHEABLE |123123+ PMD_SECT_READ,124124+ },125125+};126126+127127+const struct mem_type *get_mem_type(unsigned int type)128128+{129129+ return type < ARRAY_SIZE(mem_types) ? &mem_types[type] : NULL;130130+}131131+EXPORT_SYMBOL(get_mem_type);132132+133133+/*134134+ * Adjust the PMD section entries according to the CPU in use.135135+ */136136+static void __init build_mem_type_table(void)137137+{138138+ pgprot_user = __pgprot(PTE_PRESENT | PTE_YOUNG | PTE_CACHEABLE);139139+ pgprot_kernel = __pgprot(PTE_PRESENT | PTE_YOUNG |140140+ PTE_DIRTY | PTE_READ | PTE_WRITE |141141+ PTE_EXEC | PTE_CACHEABLE);142142+}143143+144144+#define vectors_base() (vectors_high() ? 0xffff0000 : 0)145145+146146+static void __init *early_alloc(unsigned long sz)147147+{148148+ void *ptr = __va(memblock_alloc(sz, sz));149149+ memset(ptr, 0, sz);150150+ return ptr;151151+}152152+153153+static pte_t * __init early_pte_alloc(pmd_t *pmd, unsigned long addr,154154+ unsigned long prot)155155+{156156+ if (pmd_none(*pmd)) {157157+ pte_t *pte = early_alloc(PTRS_PER_PTE * sizeof(pte_t));158158+ __pmd_populate(pmd, __pa(pte) | prot);159159+ }160160+ BUG_ON(pmd_bad(*pmd));161161+ return pte_offset_kernel(pmd, addr);162162+}163163+164164+static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr,165165+ unsigned long end, unsigned long pfn,166166+ const struct mem_type *type)167167+{168168+ pte_t *pte = early_pte_alloc(pmd, addr, type->prot_l1);169169+ do {170170+ set_pte(pte, pfn_pte(pfn, __pgprot(type->prot_pte)));171171+ pfn++;172172+ } while (pte++, addr += PAGE_SIZE, addr != end);173173+}174174+175175+static void __init alloc_init_section(pgd_t *pgd, unsigned long addr,176176+ unsigned long end, unsigned long phys,177177+ const struct mem_type *type)178178+{179179+ pmd_t *pmd = pmd_offset((pud_t *)pgd, addr);180180+181181+ /*182182+ * Try a section mapping - end, addr and phys must all be aligned183183+ * to a section boundary.184184+ */185185+ if (((addr | end | phys) & ~SECTION_MASK) == 0) {186186+ pmd_t *p = pmd;187187+188188+ do {189189+ set_pmd(pmd, __pmd(phys | type->prot_sect));190190+ phys += SECTION_SIZE;191191+ } while (pmd++, addr += SECTION_SIZE, addr != end);192192+193193+ flush_pmd_entry(p);194194+ } else {195195+ /*196196+ * No need to loop; pte's aren't interested in the197197+ * individual L1 entries.198198+ */199199+ alloc_init_pte(pmd, addr, end, __phys_to_pfn(phys), type);200200+ }201201+}202202+203203+/*204204+ * Create the page directory entries and any necessary205205+ * page tables for the mapping specified by `md'. We206206+ * are able to cope here with varying sizes and address207207+ * offsets, and we take full advantage of sections.208208+ */209209+static void __init create_mapping(struct map_desc *md)210210+{211211+ unsigned long phys, addr, length, end;212212+ const struct mem_type *type;213213+ pgd_t *pgd;214214+215215+ if (md->virtual != vectors_base() && md->virtual < TASK_SIZE) {216216+ printk(KERN_WARNING "BUG: not creating mapping for "217217+ "0x%08llx at 0x%08lx in user region\n",218218+ __pfn_to_phys((u64)md->pfn), md->virtual);219219+ return;220220+ }221221+222222+ if ((md->type == MT_DEVICE || md->type == MT_ROM) &&223223+ md->virtual >= PAGE_OFFSET && md->virtual < VMALLOC_END) {224224+ printk(KERN_WARNING "BUG: mapping for 0x%08llx at 0x%08lx "225225+ "overlaps vmalloc space\n",226226+ __pfn_to_phys((u64)md->pfn), md->virtual);227227+ }228228+229229+ type = &mem_types[md->type];230230+231231+ addr = md->virtual & PAGE_MASK;232232+ phys = (unsigned long)__pfn_to_phys(md->pfn);233233+ length = PAGE_ALIGN(md->length + (md->virtual & ~PAGE_MASK));234234+235235+ if (type->prot_l1 == 0 && ((addr | phys | length) & ~SECTION_MASK)) {236236+ printk(KERN_WARNING "BUG: map for 0x%08lx at 0x%08lx can not "237237+ "be mapped using pages, ignoring.\n",238238+ __pfn_to_phys(md->pfn), addr);239239+ return;240240+ }241241+242242+ pgd = pgd_offset_k(addr);243243+ end = addr + length;244244+ do {245245+ unsigned long next = pgd_addr_end(addr, end);246246+247247+ alloc_init_section(pgd, addr, next, phys, type);248248+249249+ phys += next - addr;250250+ addr = next;251251+ } while (pgd++, addr != end);252252+}253253+254254+static void * __initdata vmalloc_min = (void *)(VMALLOC_END - SZ_128M);255255+256256+/*257257+ * vmalloc=size forces the vmalloc area to be exactly 'size'258258+ * bytes. This can be used to increase (or decrease) the vmalloc259259+ * area - the default is 128m.260260+ */261261+static int __init early_vmalloc(char *arg)262262+{263263+ unsigned long vmalloc_reserve = memparse(arg, NULL);264264+265265+ if (vmalloc_reserve < SZ_16M) {266266+ vmalloc_reserve = SZ_16M;267267+ printk(KERN_WARNING268268+ "vmalloc area too small, limiting to %luMB\n",269269+ vmalloc_reserve >> 20);270270+ }271271+272272+ if (vmalloc_reserve > VMALLOC_END - (PAGE_OFFSET + SZ_32M)) {273273+ vmalloc_reserve = VMALLOC_END - (PAGE_OFFSET + SZ_32M);274274+ printk(KERN_WARNING275275+ "vmalloc area is too big, limiting to %luMB\n",276276+ vmalloc_reserve >> 20);277277+ }278278+279279+ vmalloc_min = (void *)(VMALLOC_END - vmalloc_reserve);280280+ return 0;281281+}282282+early_param("vmalloc", early_vmalloc);283283+284284+static phys_addr_t lowmem_limit __initdata = SZ_1G;285285+286286+static void __init sanity_check_meminfo(void)287287+{288288+ int i, j;289289+290290+ lowmem_limit = __pa(vmalloc_min - 1) + 1;291291+ memblock_set_current_limit(lowmem_limit);292292+293293+ for (i = 0, j = 0; i < meminfo.nr_banks; i++) {294294+ struct membank *bank = &meminfo.bank[j];295295+ *bank = meminfo.bank[i];296296+ j++;297297+ }298298+ meminfo.nr_banks = j;299299+}300300+301301+static inline void prepare_page_table(void)302302+{303303+ unsigned long addr;304304+ phys_addr_t end;305305+306306+ /*307307+ * Clear out all the mappings below the kernel image.308308+ */309309+ for (addr = 0; addr < MODULES_VADDR; addr += PGDIR_SIZE)310310+ pmd_clear(pmd_off_k(addr));311311+312312+ for ( ; addr < PAGE_OFFSET; addr += PGDIR_SIZE)313313+ pmd_clear(pmd_off_k(addr));314314+315315+ /*316316+ * Find the end of the first block of lowmem.317317+ */318318+ end = memblock.memory.regions[0].base + memblock.memory.regions[0].size;319319+ if (end >= lowmem_limit)320320+ end = lowmem_limit;321321+322322+ /*323323+ * Clear out all the kernel space mappings, except for the first324324+ * memory bank, up to the end of the vmalloc region.325325+ */326326+ for (addr = __phys_to_virt(end);327327+ addr < VMALLOC_END; addr += PGDIR_SIZE)328328+ pmd_clear(pmd_off_k(addr));329329+}330330+331331+/*332332+ * Reserve the special regions of memory333333+ */334334+void __init uc32_mm_memblock_reserve(void)335335+{336336+ /*337337+ * Reserve the page tables. These are already in use,338338+ * and can only be in node 0.339339+ */340340+ memblock_reserve(__pa(swapper_pg_dir), PTRS_PER_PGD * sizeof(pgd_t));341341+342342+#ifdef CONFIG_PUV3_UNIGFX343343+ /*344344+ * These should likewise go elsewhere. They pre-reserve the345345+ * screen/video memory region at the 48M~64M of main system memory.346346+ */347347+ memblock_reserve(PKUNITY_UNIGFX_MMAP_BASE, PKUNITY_UNIGFX_MMAP_SIZE);348348+ memblock_reserve(PKUNITY_UVC_MMAP_BASE, PKUNITY_UVC_MMAP_SIZE);349349+#endif350350+}351351+352352+/*353353+ * Set up device the mappings. Since we clear out the page tables for all354354+ * mappings above VMALLOC_END, we will remove any debug device mappings.355355+ * This means you have to be careful how you debug this function, or any356356+ * called function. This means you can't use any function or debugging357357+ * method which may touch any device, otherwise the kernel _will_ crash.358358+ */359359+static void __init devicemaps_init(void)360360+{361361+ struct map_desc map;362362+ unsigned long addr;363363+ void *vectors;364364+365365+ /*366366+ * Allocate the vector page early.367367+ */368368+ vectors = early_alloc(PAGE_SIZE);369369+370370+ for (addr = VMALLOC_END; addr; addr += PGDIR_SIZE)371371+ pmd_clear(pmd_off_k(addr));372372+373373+ /*374374+ * Create a mapping for UniGFX VRAM375375+ */376376+#ifdef CONFIG_PUV3_UNIGFX377377+ map.pfn = __phys_to_pfn(PKUNITY_UNIGFX_MMAP_BASE);378378+ map.virtual = KUSER_UNIGFX_BASE;379379+ map.length = PKUNITY_UNIGFX_MMAP_SIZE;380380+ map.type = MT_KUSER;381381+ create_mapping(&map);382382+#endif383383+384384+ /*385385+ * Create a mapping for the machine vectors at the high-vectors386386+ * location (0xffff0000). If we aren't using high-vectors, also387387+ * create a mapping at the low-vectors virtual address.388388+ */389389+ map.pfn = __phys_to_pfn(virt_to_phys(vectors));390390+ map.virtual = VECTORS_BASE;391391+ map.length = PAGE_SIZE;392392+ map.type = MT_HIGH_VECTORS;393393+ create_mapping(&map);394394+395395+ /*396396+ * Create a mapping for the kuser page at the special397397+ * location (0xbfff0000) to the same vectors location.398398+ */399399+ map.pfn = __phys_to_pfn(virt_to_phys(vectors));400400+ map.virtual = KUSER_VECPAGE_BASE;401401+ map.length = PAGE_SIZE;402402+ map.type = MT_KUSER;403403+ create_mapping(&map);404404+405405+ /*406406+ * Finally flush the caches and tlb to ensure that we're in a407407+ * consistent state wrt the writebuffer. This also ensures that408408+ * any write-allocated cache lines in the vector page are written409409+ * back. After this point, we can start to touch devices again.410410+ */411411+ local_flush_tlb_all();412412+ flush_cache_all();413413+}414414+415415+static void __init map_lowmem(void)416416+{417417+ struct memblock_region *reg;418418+419419+ /* Map all the lowmem memory banks. */420420+ for_each_memblock(memory, reg) {421421+ phys_addr_t start = reg->base;422422+ phys_addr_t end = start + reg->size;423423+ struct map_desc map;424424+425425+ if (end > lowmem_limit)426426+ end = lowmem_limit;427427+ if (start >= end)428428+ break;429429+430430+ map.pfn = __phys_to_pfn(start);431431+ map.virtual = __phys_to_virt(start);432432+ map.length = end - start;433433+ map.type = MT_MEMORY;434434+435435+ create_mapping(&map);436436+ }437437+}438438+439439+/*440440+ * paging_init() sets up the page tables, initialises the zone memory441441+ * maps, and sets up the zero page, bad page and bad page tables.442442+ */443443+void __init paging_init(void)444444+{445445+ void *zero_page;446446+447447+ build_mem_type_table();448448+ sanity_check_meminfo();449449+ prepare_page_table();450450+ map_lowmem();451451+ devicemaps_init();452452+453453+ top_pmd = pmd_off_k(0xffff0000);454454+455455+ /* allocate the zero page. */456456+ zero_page = early_alloc(PAGE_SIZE);457457+458458+ bootmem_init();459459+460460+ empty_zero_page = virt_to_page(zero_page);461461+ __flush_dcache_page(NULL, empty_zero_page);462462+}463463+464464+/*465465+ * In order to soft-boot, we need to insert a 1:1 mapping in place of466466+ * the user-mode pages. This will then ensure that we have predictable467467+ * results when turning the mmu off468468+ */469469+void setup_mm_for_reboot(char mode)470470+{471471+ unsigned long base_pmdval;472472+ pgd_t *pgd;473473+ int i;474474+475475+ /*476476+ * We need to access to user-mode page tables here. For kernel threads477477+ * we don't have any user-mode mappings so we use the context that we478478+ * "borrowed".479479+ */480480+ pgd = current->active_mm->pgd;481481+482482+ base_pmdval = PMD_SECT_WRITE | PMD_SECT_READ | PMD_TYPE_SECT;483483+484484+ for (i = 0; i < FIRST_USER_PGD_NR + USER_PTRS_PER_PGD; i++, pgd++) {485485+ unsigned long pmdval = (i << PGDIR_SHIFT) | base_pmdval;486486+ pmd_t *pmd;487487+488488+ pmd = pmd_off(pgd, i << PGDIR_SHIFT);489489+ set_pmd(pmd, __pmd(pmdval));490490+ flush_pmd_entry(pmd);491491+ }492492+493493+ local_flush_tlb_all();494494+}495495+496496+/*497497+ * Take care of architecture specific things when placing a new PTE into498498+ * a page table, or changing an existing PTE. Basically, there are two499499+ * things that we need to take care of:500500+ *501501+ * 1. If PG_dcache_clean is not set for the page, we need to ensure502502+ * that any cache entries for the kernels virtual memory503503+ * range are written back to the page.504504+ * 2. If we have multiple shared mappings of the same space in505505+ * an object, we need to deal with the cache aliasing issues.506506+ *507507+ * Note that the pte lock will be held.508508+ */509509+void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr,510510+ pte_t *ptep)511511+{512512+ unsigned long pfn = pte_pfn(*ptep);513513+ struct address_space *mapping;514514+ struct page *page;515515+516516+ if (!pfn_valid(pfn))517517+ return;518518+519519+ /*520520+ * The zero page is never written to, so never has any dirty521521+ * cache lines, and therefore never needs to be flushed.522522+ */523523+ page = pfn_to_page(pfn);524524+ if (page == ZERO_PAGE(0))525525+ return;526526+527527+ mapping = page_mapping(page);528528+ if (!test_and_set_bit(PG_dcache_clean, &page->flags))529529+ __flush_dcache_page(mapping, page);530530+ if (mapping)531531+ if (vma->vm_flags & VM_EXEC)532532+ __flush_icache_all();533533+}
+102
arch/unicore32/mm/pgd.c
···11+/*22+ * linux/arch/unicore32/mm/pgd.c33+ *44+ * Code specific to PKUnity SoC and UniCore ISA55+ *66+ * Copyright (C) 2001-2010 GUAN Xue-tao77+ *88+ * This program is free software; you can redistribute it and/or modify99+ * it under the terms of the GNU General Public License version 2 as1010+ * published by the Free Software Foundation.1111+ */1212+#include <linux/mm.h>1313+#include <linux/gfp.h>1414+#include <linux/highmem.h>1515+1616+#include <asm/pgalloc.h>1717+#include <asm/page.h>1818+#include <asm/tlbflush.h>1919+2020+#include "mm.h"2121+2222+#define FIRST_KERNEL_PGD_NR (FIRST_USER_PGD_NR + USER_PTRS_PER_PGD)2323+2424+/*2525+ * need to get a 4k page for level 12626+ */2727+pgd_t *get_pgd_slow(struct mm_struct *mm)2828+{2929+ pgd_t *new_pgd, *init_pgd;3030+ pmd_t *new_pmd, *init_pmd;3131+ pte_t *new_pte, *init_pte;3232+3333+ new_pgd = (pgd_t *)__get_free_pages(GFP_KERNEL, 0);3434+ if (!new_pgd)3535+ goto no_pgd;3636+3737+ memset(new_pgd, 0, FIRST_KERNEL_PGD_NR * sizeof(pgd_t));3838+3939+ /*4040+ * Copy over the kernel and IO PGD entries4141+ */4242+ init_pgd = pgd_offset_k(0);4343+ memcpy(new_pgd + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR,4444+ (PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t));4545+4646+ clean_dcache_area(new_pgd, PTRS_PER_PGD * sizeof(pgd_t));4747+4848+ if (!vectors_high()) {4949+ /*5050+ * On UniCore, first page must always be allocated since it5151+ * contains the machine vectors.5252+ */5353+ new_pmd = pmd_alloc(mm, (pud_t *)new_pgd, 0);5454+ if (!new_pmd)5555+ goto no_pmd;5656+5757+ new_pte = pte_alloc_map(mm, new_pmd, 0);5858+ if (!new_pte)5959+ goto no_pte;6060+6161+ init_pmd = pmd_offset((pud_t *)init_pgd, 0);6262+ init_pte = pte_offset_map(init_pmd, 0);6363+ set_pte(new_pte, *init_pte);6464+ pte_unmap(init_pte);6565+ pte_unmap(new_pte);6666+ }6767+6868+ return new_pgd;6969+7070+no_pte:7171+ pmd_free(mm, new_pmd);7272+no_pmd:7373+ free_pages((unsigned long)new_pgd, 0);7474+no_pgd:7575+ return NULL;7676+}7777+7878+void free_pgd_slow(struct mm_struct *mm, pgd_t *pgd)7979+{8080+ pmd_t *pmd;8181+ pgtable_t pte;8282+8383+ if (!pgd)8484+ return;8585+8686+ /* pgd is always present and good */8787+ pmd = pmd_off(pgd, 0);8888+ if (pmd_none(*pmd))8989+ goto free;9090+ if (pmd_bad(*pmd)) {9191+ pmd_ERROR(*pmd);9292+ pmd_clear(pmd);9393+ goto free;9494+ }9595+9696+ pte = pmd_pgtable(*pmd);9797+ pmd_clear(pmd);9898+ pte_free(mm, pte);9999+ pmd_free(mm, pmd);100100+free:101101+ free_pages((unsigned long) pgd, 0);102102+}