diff options
author | GuanXuetao <gxt@mprc.pku.edu.cn> | 2011-01-15 05:17:56 -0500 |
---|---|---|
committer | GuanXuetao <gxt@mprc.pku.edu.cn> | 2011-03-16 21:19:09 -0400 |
commit | 56372b0b2f533c9a25bd40a0577405f6ddb7cff2 (patch) | |
tree | c428578bf7392232e946756cfe12e9144122c212 /arch/unicore32/include/asm | |
parent | b50f1704e9c441c58cf6dc05e72953ca30e1d4d2 (diff) |
unicore32 core architecture: mm related: fault handling
This patch implements fault handling of memory management.
Signed-off-by: Guan Xuetao <gxt@mprc.pku.edu.cn>
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'arch/unicore32/include/asm')
-rw-r--r-- | arch/unicore32/include/asm/mmu.h | 17 | ||||
-rw-r--r-- | arch/unicore32/include/asm/mmu_context.h | 87 | ||||
-rw-r--r-- | arch/unicore32/include/asm/pgalloc.h | 110 | ||||
-rw-r--r-- | arch/unicore32/include/asm/pgtable-hwdef.h | 55 | ||||
-rw-r--r-- | arch/unicore32/include/asm/pgtable.h | 317 |
5 files changed, 586 insertions, 0 deletions
diff --git a/arch/unicore32/include/asm/mmu.h b/arch/unicore32/include/asm/mmu.h new file mode 100644 index 000000000000..66fa341dc2c6 --- /dev/null +++ b/arch/unicore32/include/asm/mmu.h | |||
@@ -0,0 +1,17 @@ | |||
1 | /* | ||
2 | * linux/arch/unicore32/include/asm/mmu.h | ||
3 | * | ||
4 | * Code specific to PKUnity SoC and UniCore ISA | ||
5 | * | ||
6 | * Copyright (C) 2001-2010 GUAN Xue-tao | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | #ifndef __UNICORE_MMU_H__ | ||
13 | #define __UNICORE_MMU_H__ | ||
14 | |||
15 | typedef unsigned long mm_context_t; | ||
16 | |||
17 | #endif | ||
diff --git a/arch/unicore32/include/asm/mmu_context.h b/arch/unicore32/include/asm/mmu_context.h new file mode 100644 index 000000000000..fb5e4c658f7a --- /dev/null +++ b/arch/unicore32/include/asm/mmu_context.h | |||
@@ -0,0 +1,87 @@ | |||
1 | /* | ||
2 | * linux/arch/unicore32/include/asm/mmu_context.h | ||
3 | * | ||
4 | * Code specific to PKUnity SoC and UniCore ISA | ||
5 | * | ||
6 | * Copyright (C) 2001-2010 GUAN Xue-tao | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | #ifndef __UNICORE_MMU_CONTEXT_H__ | ||
13 | #define __UNICORE_MMU_CONTEXT_H__ | ||
14 | |||
15 | #include <linux/compiler.h> | ||
16 | #include <linux/sched.h> | ||
17 | #include <linux/io.h> | ||
18 | |||
19 | #include <asm/cacheflush.h> | ||
20 | #include <asm/cpu-single.h> | ||
21 | |||
22 | #define init_new_context(tsk, mm) 0 | ||
23 | |||
24 | #define destroy_context(mm) do { } while (0) | ||
25 | |||
26 | /* | ||
27 | * This is called when "tsk" is about to enter lazy TLB mode. | ||
28 | * | ||
29 | * mm: describes the currently active mm context | ||
30 | * tsk: task which is entering lazy tlb | ||
31 | * cpu: cpu number which is entering lazy tlb | ||
32 | * | ||
33 | * tsk->mm will be NULL | ||
34 | */ | ||
35 | static inline void | ||
36 | enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) | ||
37 | { | ||
38 | } | ||
39 | |||
40 | /* | ||
41 | * This is the actual mm switch as far as the scheduler | ||
42 | * is concerned. No registers are touched. We avoid | ||
43 | * calling the CPU specific function when the mm hasn't | ||
44 | * actually changed. | ||
45 | */ | ||
46 | static inline void | ||
47 | switch_mm(struct mm_struct *prev, struct mm_struct *next, | ||
48 | struct task_struct *tsk) | ||
49 | { | ||
50 | unsigned int cpu = smp_processor_id(); | ||
51 | |||
52 | if (!cpumask_test_and_set_cpu(cpu, mm_cpumask(next)) || prev != next) | ||
53 | cpu_switch_mm(next->pgd, next); | ||
54 | } | ||
55 | |||
56 | #define deactivate_mm(tsk, mm) do { } while (0) | ||
57 | #define activate_mm(prev, next) switch_mm(prev, next, NULL) | ||
58 | |||
59 | /* | ||
60 | * We are inserting a "fake" vma for the user-accessible vector page so | ||
61 | * gdb and friends can get to it through ptrace and /proc/<pid>/mem. | ||
62 | * But we also want to remove it before the generic code gets to see it | ||
63 | * during process exit or the unmapping of it would cause total havoc. | ||
64 | * (the macro is used as remove_vma() is static to mm/mmap.c) | ||
65 | */ | ||
66 | #define arch_exit_mmap(mm) \ | ||
67 | do { \ | ||
68 | struct vm_area_struct *high_vma = find_vma(mm, 0xffff0000); \ | ||
69 | if (high_vma) { \ | ||
70 | BUG_ON(high_vma->vm_next); /* it should be last */ \ | ||
71 | if (high_vma->vm_prev) \ | ||
72 | high_vma->vm_prev->vm_next = NULL; \ | ||
73 | else \ | ||
74 | mm->mmap = NULL; \ | ||
75 | rb_erase(&high_vma->vm_rb, &mm->mm_rb); \ | ||
76 | mm->mmap_cache = NULL; \ | ||
77 | mm->map_count--; \ | ||
78 | remove_vma(high_vma); \ | ||
79 | } \ | ||
80 | } while (0) | ||
81 | |||
82 | static inline void arch_dup_mmap(struct mm_struct *oldmm, | ||
83 | struct mm_struct *mm) | ||
84 | { | ||
85 | } | ||
86 | |||
87 | #endif | ||
diff --git a/arch/unicore32/include/asm/pgalloc.h b/arch/unicore32/include/asm/pgalloc.h new file mode 100644 index 000000000000..0213e373a895 --- /dev/null +++ b/arch/unicore32/include/asm/pgalloc.h | |||
@@ -0,0 +1,110 @@ | |||
1 | /* | ||
2 | * linux/arch/unicore32/include/asm/pgalloc.h | ||
3 | * | ||
4 | * Code specific to PKUnity SoC and UniCore ISA | ||
5 | * | ||
6 | * Copyright (C) 2001-2010 GUAN Xue-tao | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | #ifndef __UNICORE_PGALLOC_H__ | ||
13 | #define __UNICORE_PGALLOC_H__ | ||
14 | |||
15 | #include <asm/pgtable-hwdef.h> | ||
16 | #include <asm/processor.h> | ||
17 | #include <asm/cacheflush.h> | ||
18 | #include <asm/tlbflush.h> | ||
19 | |||
20 | #define check_pgt_cache() do { } while (0) | ||
21 | |||
22 | #define _PAGE_USER_TABLE (PMD_TYPE_TABLE | PMD_PRESENT) | ||
23 | #define _PAGE_KERNEL_TABLE (PMD_TYPE_TABLE | PMD_PRESENT) | ||
24 | |||
25 | extern pgd_t *get_pgd_slow(struct mm_struct *mm); | ||
26 | extern void free_pgd_slow(struct mm_struct *mm, pgd_t *pgd); | ||
27 | |||
28 | #define pgd_alloc(mm) get_pgd_slow(mm) | ||
29 | #define pgd_free(mm, pgd) free_pgd_slow(mm, pgd) | ||
30 | |||
31 | #define PGALLOC_GFP (GFP_KERNEL | __GFP_NOTRACK | __GFP_REPEAT | __GFP_ZERO) | ||
32 | |||
33 | /* | ||
34 | * Allocate one PTE table. | ||
35 | */ | ||
36 | static inline pte_t * | ||
37 | pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr) | ||
38 | { | ||
39 | pte_t *pte; | ||
40 | |||
41 | pte = (pte_t *)__get_free_page(PGALLOC_GFP); | ||
42 | if (pte) | ||
43 | clean_dcache_area(pte, PTRS_PER_PTE * sizeof(pte_t)); | ||
44 | |||
45 | return pte; | ||
46 | } | ||
47 | |||
48 | static inline pgtable_t | ||
49 | pte_alloc_one(struct mm_struct *mm, unsigned long addr) | ||
50 | { | ||
51 | struct page *pte; | ||
52 | |||
53 | pte = alloc_pages(PGALLOC_GFP, 0); | ||
54 | if (pte) { | ||
55 | if (!PageHighMem(pte)) { | ||
56 | void *page = page_address(pte); | ||
57 | clean_dcache_area(page, PTRS_PER_PTE * sizeof(pte_t)); | ||
58 | } | ||
59 | pgtable_page_ctor(pte); | ||
60 | } | ||
61 | |||
62 | return pte; | ||
63 | } | ||
64 | |||
65 | /* | ||
66 | * Free one PTE table. | ||
67 | */ | ||
68 | static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte) | ||
69 | { | ||
70 | if (pte) | ||
71 | free_page((unsigned long)pte); | ||
72 | } | ||
73 | |||
74 | static inline void pte_free(struct mm_struct *mm, pgtable_t pte) | ||
75 | { | ||
76 | pgtable_page_dtor(pte); | ||
77 | __free_page(pte); | ||
78 | } | ||
79 | |||
80 | static inline void __pmd_populate(pmd_t *pmdp, unsigned long pmdval) | ||
81 | { | ||
82 | set_pmd(pmdp, __pmd(pmdval)); | ||
83 | flush_pmd_entry(pmdp); | ||
84 | } | ||
85 | |||
86 | /* | ||
87 | * Populate the pmdp entry with a pointer to the pte. This pmd is part | ||
88 | * of the mm address space. | ||
89 | */ | ||
90 | static inline void | ||
91 | pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, pte_t *ptep) | ||
92 | { | ||
93 | unsigned long pte_ptr = (unsigned long)ptep; | ||
94 | |||
95 | /* | ||
96 | * The pmd must be loaded with the physical | ||
97 | * address of the PTE table | ||
98 | */ | ||
99 | __pmd_populate(pmdp, __pa(pte_ptr) | _PAGE_KERNEL_TABLE); | ||
100 | } | ||
101 | |||
102 | static inline void | ||
103 | pmd_populate(struct mm_struct *mm, pmd_t *pmdp, pgtable_t ptep) | ||
104 | { | ||
105 | __pmd_populate(pmdp, | ||
106 | page_to_pfn(ptep) << PAGE_SHIFT | _PAGE_USER_TABLE); | ||
107 | } | ||
108 | #define pmd_pgtable(pmd) pmd_page(pmd) | ||
109 | |||
110 | #endif | ||
diff --git a/arch/unicore32/include/asm/pgtable-hwdef.h b/arch/unicore32/include/asm/pgtable-hwdef.h new file mode 100644 index 000000000000..7314e859cca0 --- /dev/null +++ b/arch/unicore32/include/asm/pgtable-hwdef.h | |||
@@ -0,0 +1,55 @@ | |||
1 | /* | ||
2 | * linux/arch/unicore32/include/asm/pgtable-hwdef.h | ||
3 | * | ||
4 | * Code specific to PKUnity SoC and UniCore ISA | ||
5 | * | ||
6 | * Copyright (C) 2001-2010 GUAN Xue-tao | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | #ifndef __UNICORE_PGTABLE_HWDEF_H__ | ||
13 | #define __UNICORE_PGTABLE_HWDEF_H__ | ||
14 | |||
15 | /* | ||
16 | * Hardware page table definitions. | ||
17 | * | ||
18 | * + Level 1 descriptor (PMD) | ||
19 | * - common | ||
20 | */ | ||
21 | #define PMD_TYPE_MASK (3 << 0) | ||
22 | #define PMD_TYPE_TABLE (0 << 0) | ||
23 | /*#define PMD_TYPE_LARGE (1 << 0) */ | ||
24 | #define PMD_TYPE_INVALID (2 << 0) | ||
25 | #define PMD_TYPE_SECT (3 << 0) | ||
26 | |||
27 | #define PMD_PRESENT (1 << 2) | ||
28 | #define PMD_YOUNG (1 << 3) | ||
29 | |||
30 | /*#define PMD_SECT_DIRTY (1 << 4) */ | ||
31 | #define PMD_SECT_CACHEABLE (1 << 5) | ||
32 | #define PMD_SECT_EXEC (1 << 6) | ||
33 | #define PMD_SECT_WRITE (1 << 7) | ||
34 | #define PMD_SECT_READ (1 << 8) | ||
35 | |||
36 | /* | ||
37 | * + Level 2 descriptor (PTE) | ||
38 | * - common | ||
39 | */ | ||
40 | #define PTE_TYPE_MASK (3 << 0) | ||
41 | #define PTE_TYPE_SMALL (0 << 0) | ||
42 | #define PTE_TYPE_MIDDLE (1 << 0) | ||
43 | #define PTE_TYPE_LARGE (2 << 0) | ||
44 | #define PTE_TYPE_INVALID (3 << 0) | ||
45 | |||
46 | #define PTE_PRESENT (1 << 2) | ||
47 | #define PTE_FILE (1 << 3) /* only when !PRESENT */ | ||
48 | #define PTE_YOUNG (1 << 3) | ||
49 | #define PTE_DIRTY (1 << 4) | ||
50 | #define PTE_CACHEABLE (1 << 5) | ||
51 | #define PTE_EXEC (1 << 6) | ||
52 | #define PTE_WRITE (1 << 7) | ||
53 | #define PTE_READ (1 << 8) | ||
54 | |||
55 | #endif | ||
diff --git a/arch/unicore32/include/asm/pgtable.h b/arch/unicore32/include/asm/pgtable.h new file mode 100644 index 000000000000..68b2f297ac97 --- /dev/null +++ b/arch/unicore32/include/asm/pgtable.h | |||
@@ -0,0 +1,317 @@ | |||
1 | /* | ||
2 | * linux/arch/unicore32/include/asm/pgtable.h | ||
3 | * | ||
4 | * Code specific to PKUnity SoC and UniCore ISA | ||
5 | * | ||
6 | * Copyright (C) 2001-2010 GUAN Xue-tao | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | #ifndef __UNICORE_PGTABLE_H__ | ||
13 | #define __UNICORE_PGTABLE_H__ | ||
14 | |||
15 | #include <asm-generic/pgtable-nopmd.h> | ||
16 | #include <asm/cpu-single.h> | ||
17 | |||
18 | #include <asm/memory.h> | ||
19 | #include <asm/pgtable-hwdef.h> | ||
20 | |||
21 | /* | ||
22 | * Just any arbitrary offset to the start of the vmalloc VM area: the | ||
23 | * current 8MB value just means that there will be a 8MB "hole" after the | ||
24 | * physical memory until the kernel virtual memory starts. That means that | ||
25 | * any out-of-bounds memory accesses will hopefully be caught. | ||
26 | * The vmalloc() routines leaves a hole of 4kB between each vmalloced | ||
27 | * area for the same reason. ;) | ||
28 | * | ||
29 | * Note that platforms may override VMALLOC_START, but they must provide | ||
30 | * VMALLOC_END. VMALLOC_END defines the (exclusive) limit of this space, | ||
31 | * which may not overlap IO space. | ||
32 | */ | ||
33 | #ifndef VMALLOC_START | ||
34 | #define VMALLOC_OFFSET SZ_8M | ||
35 | #define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) \ | ||
36 | & ~(VMALLOC_OFFSET-1)) | ||
37 | #define VMALLOC_END (0xff000000UL) | ||
38 | #endif | ||
39 | |||
40 | #define PTRS_PER_PTE 1024 | ||
41 | #define PTRS_PER_PGD 1024 | ||
42 | |||
43 | /* | ||
44 | * PGDIR_SHIFT determines what a third-level page table entry can map | ||
45 | */ | ||
46 | #define PGDIR_SHIFT 22 | ||
47 | |||
48 | #ifndef __ASSEMBLY__ | ||
49 | extern void __pte_error(const char *file, int line, unsigned long val); | ||
50 | extern void __pgd_error(const char *file, int line, unsigned long val); | ||
51 | |||
52 | #define pte_ERROR(pte) __pte_error(__FILE__, __LINE__, pte_val(pte)) | ||
53 | #define pgd_ERROR(pgd) __pgd_error(__FILE__, __LINE__, pgd_val(pgd)) | ||
54 | #endif /* !__ASSEMBLY__ */ | ||
55 | |||
56 | #define PGDIR_SIZE (1UL << PGDIR_SHIFT) | ||
57 | #define PGDIR_MASK (~(PGDIR_SIZE-1)) | ||
58 | |||
59 | /* | ||
60 | * This is the lowest virtual address we can permit any user space | ||
61 | * mapping to be mapped at. This is particularly important for | ||
62 | * non-high vector CPUs. | ||
63 | */ | ||
64 | #define FIRST_USER_ADDRESS PAGE_SIZE | ||
65 | |||
66 | #define FIRST_USER_PGD_NR 1 | ||
67 | #define USER_PTRS_PER_PGD ((TASK_SIZE/PGDIR_SIZE) - FIRST_USER_PGD_NR) | ||
68 | |||
69 | /* | ||
70 | * section address mask and size definitions. | ||
71 | */ | ||
72 | #define SECTION_SHIFT 22 | ||
73 | #define SECTION_SIZE (1UL << SECTION_SHIFT) | ||
74 | #define SECTION_MASK (~(SECTION_SIZE-1)) | ||
75 | |||
76 | #ifndef __ASSEMBLY__ | ||
77 | |||
78 | /* | ||
79 | * The pgprot_* and protection_map entries will be fixed up in runtime | ||
80 | * to include the cachable bits based on memory policy, as well as any | ||
81 | * architecture dependent bits. | ||
82 | */ | ||
83 | #define _PTE_DEFAULT (PTE_PRESENT | PTE_YOUNG | PTE_CACHEABLE) | ||
84 | |||
85 | extern pgprot_t pgprot_user; | ||
86 | extern pgprot_t pgprot_kernel; | ||
87 | |||
88 | #define PAGE_NONE pgprot_user | ||
89 | #define PAGE_SHARED __pgprot(pgprot_val(pgprot_user | PTE_READ \ | ||
90 | | PTE_WRITE) | ||
91 | #define PAGE_SHARED_EXEC __pgprot(pgprot_val(pgprot_user | PTE_READ \ | ||
92 | | PTE_WRITE \ | ||
93 | | PTE_EXEC) | ||
94 | #define PAGE_COPY __pgprot(pgprot_val(pgprot_user | PTE_READ) | ||
95 | #define PAGE_COPY_EXEC __pgprot(pgprot_val(pgprot_user | PTE_READ \ | ||
96 | | PTE_EXEC) | ||
97 | #define PAGE_READONLY __pgprot(pgprot_val(pgprot_user | PTE_READ) | ||
98 | #define PAGE_READONLY_EXEC __pgprot(pgprot_val(pgprot_user | PTE_READ \ | ||
99 | | PTE_EXEC) | ||
100 | #define PAGE_KERNEL pgprot_kernel | ||
101 | #define PAGE_KERNEL_EXEC __pgprot(pgprot_val(pgprot_kernel | PTE_EXEC)) | ||
102 | |||
103 | #define __PAGE_NONE __pgprot(_PTE_DEFAULT) | ||
104 | #define __PAGE_SHARED __pgprot(_PTE_DEFAULT | PTE_READ \ | ||
105 | | PTE_WRITE) | ||
106 | #define __PAGE_SHARED_EXEC __pgprot(_PTE_DEFAULT | PTE_READ \ | ||
107 | | PTE_WRITE \ | ||
108 | | PTE_EXEC) | ||
109 | #define __PAGE_COPY __pgprot(_PTE_DEFAULT | PTE_READ) | ||
110 | #define __PAGE_COPY_EXEC __pgprot(_PTE_DEFAULT | PTE_READ \ | ||
111 | | PTE_EXEC) | ||
112 | #define __PAGE_READONLY __pgprot(_PTE_DEFAULT | PTE_READ) | ||
113 | #define __PAGE_READONLY_EXEC __pgprot(_PTE_DEFAULT | PTE_READ \ | ||
114 | | PTE_EXEC) | ||
115 | |||
116 | #endif /* __ASSEMBLY__ */ | ||
117 | |||
118 | /* | ||
119 | * The table below defines the page protection levels that we insert into our | ||
120 | * Linux page table version. These get translated into the best that the | ||
121 | * architecture can perform. Note that on UniCore hardware: | ||
122 | * 1) We cannot do execute protection | ||
123 | * 2) If we could do execute protection, then read is implied | ||
124 | * 3) write implies read permissions | ||
125 | */ | ||
126 | #define __P000 __PAGE_NONE | ||
127 | #define __P001 __PAGE_READONLY | ||
128 | #define __P010 __PAGE_COPY | ||
129 | #define __P011 __PAGE_COPY | ||
130 | #define __P100 __PAGE_READONLY_EXEC | ||
131 | #define __P101 __PAGE_READONLY_EXEC | ||
132 | #define __P110 __PAGE_COPY_EXEC | ||
133 | #define __P111 __PAGE_COPY_EXEC | ||
134 | |||
135 | #define __S000 __PAGE_NONE | ||
136 | #define __S001 __PAGE_READONLY | ||
137 | #define __S010 __PAGE_SHARED | ||
138 | #define __S011 __PAGE_SHARED | ||
139 | #define __S100 __PAGE_READONLY_EXEC | ||
140 | #define __S101 __PAGE_READONLY_EXEC | ||
141 | #define __S110 __PAGE_SHARED_EXEC | ||
142 | #define __S111 __PAGE_SHARED_EXEC | ||
143 | |||
144 | #ifndef __ASSEMBLY__ | ||
145 | /* | ||
146 | * ZERO_PAGE is a global shared page that is always zero: used | ||
147 | * for zero-mapped memory areas etc.. | ||
148 | */ | ||
149 | extern struct page *empty_zero_page; | ||
150 | #define ZERO_PAGE(vaddr) (empty_zero_page) | ||
151 | |||
152 | #define pte_pfn(pte) (pte_val(pte) >> PAGE_SHIFT) | ||
153 | #define pfn_pte(pfn, prot) (__pte(((pfn) << PAGE_SHIFT) \ | ||
154 | | pgprot_val(prot))) | ||
155 | |||
156 | #define pte_none(pte) (!pte_val(pte)) | ||
157 | #define pte_clear(mm, addr, ptep) set_pte(ptep, __pte(0)) | ||
158 | #define pte_page(pte) (pfn_to_page(pte_pfn(pte))) | ||
159 | #define pte_offset_kernel(dir, addr) (pmd_page_vaddr(*(dir)) \ | ||
160 | + __pte_index(addr)) | ||
161 | |||
162 | #define pte_offset_map(dir, addr) (pmd_page_vaddr(*(dir)) \ | ||
163 | + __pte_index(addr)) | ||
164 | #define pte_unmap(pte) do { } while (0) | ||
165 | |||
166 | #define set_pte(ptep, pte) cpu_set_pte(ptep, pte) | ||
167 | |||
168 | #define set_pte_at(mm, addr, ptep, pteval) \ | ||
169 | do { \ | ||
170 | set_pte(ptep, pteval); \ | ||
171 | } while (0) | ||
172 | |||
173 | /* | ||
174 | * The following only work if pte_present() is true. | ||
175 | * Undefined behaviour if not.. | ||
176 | */ | ||
177 | #define pte_present(pte) (pte_val(pte) & PTE_PRESENT) | ||
178 | #define pte_write(pte) (pte_val(pte) & PTE_WRITE) | ||
179 | #define pte_dirty(pte) (pte_val(pte) & PTE_DIRTY) | ||
180 | #define pte_young(pte) (pte_val(pte) & PTE_YOUNG) | ||
181 | #define pte_exec(pte) (pte_val(pte) & PTE_EXEC) | ||
182 | #define pte_special(pte) (0) | ||
183 | |||
184 | #define PTE_BIT_FUNC(fn, op) \ | ||
185 | static inline pte_t pte_##fn(pte_t pte) { pte_val(pte) op; return pte; } | ||
186 | |||
187 | PTE_BIT_FUNC(wrprotect, &= ~PTE_WRITE); | ||
188 | PTE_BIT_FUNC(mkwrite, |= PTE_WRITE); | ||
189 | PTE_BIT_FUNC(mkclean, &= ~PTE_DIRTY); | ||
190 | PTE_BIT_FUNC(mkdirty, |= PTE_DIRTY); | ||
191 | PTE_BIT_FUNC(mkold, &= ~PTE_YOUNG); | ||
192 | PTE_BIT_FUNC(mkyoung, |= PTE_YOUNG); | ||
193 | |||
194 | static inline pte_t pte_mkspecial(pte_t pte) { return pte; } | ||
195 | |||
196 | /* | ||
197 | * Mark the prot value as uncacheable. | ||
198 | */ | ||
199 | #define pgprot_noncached(prot) \ | ||
200 | __pgprot(pgprot_val(prot) & ~PTE_CACHEABLE) | ||
201 | #define pgprot_writecombine(prot) \ | ||
202 | __pgprot(pgprot_val(prot) & ~PTE_CACHEABLE) | ||
203 | #define pgprot_dmacoherent(prot) \ | ||
204 | __pgprot(pgprot_val(prot) & ~PTE_CACHEABLE) | ||
205 | |||
206 | #define pmd_none(pmd) (!pmd_val(pmd)) | ||
207 | #define pmd_present(pmd) (pmd_val(pmd) & PMD_PRESENT) | ||
208 | #define pmd_bad(pmd) (((pmd_val(pmd) & \ | ||
209 | (PMD_PRESENT | PMD_TYPE_MASK)) \ | ||
210 | != (PMD_PRESENT | PMD_TYPE_TABLE))) | ||
211 | |||
212 | #define set_pmd(pmdpd, pmdval) \ | ||
213 | do { \ | ||
214 | *(pmdpd) = pmdval; \ | ||
215 | } while (0) | ||
216 | |||
217 | #define pmd_clear(pmdp) \ | ||
218 | do { \ | ||
219 | set_pmd(pmdp, __pmd(0));\ | ||
220 | clean_pmd_entry(pmdp); \ | ||
221 | } while (0) | ||
222 | |||
223 | #define pmd_page_vaddr(pmd) ((pte_t *)__va(pmd_val(pmd) & PAGE_MASK)) | ||
224 | #define pmd_page(pmd) pfn_to_page(__phys_to_pfn(pmd_val(pmd))) | ||
225 | |||
226 | /* | ||
227 | * Conversion functions: convert a page and protection to a page entry, | ||
228 | * and a page entry and page directory to the page they refer to. | ||
229 | */ | ||
230 | #define mk_pte(page, prot) pfn_pte(page_to_pfn(page), prot) | ||
231 | |||
232 | /* to find an entry in a page-table-directory */ | ||
233 | #define pgd_index(addr) ((addr) >> PGDIR_SHIFT) | ||
234 | |||
235 | #define pgd_offset(mm, addr) ((mm)->pgd+pgd_index(addr)) | ||
236 | |||
237 | /* to find an entry in a kernel page-table-directory */ | ||
238 | #define pgd_offset_k(addr) pgd_offset(&init_mm, addr) | ||
239 | |||
240 | /* Find an entry in the third-level page table.. */ | ||
241 | #define __pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) | ||
242 | |||
243 | static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) | ||
244 | { | ||
245 | const unsigned long mask = PTE_EXEC | PTE_WRITE | PTE_READ; | ||
246 | pte_val(pte) = (pte_val(pte) & ~mask) | (pgprot_val(newprot) & mask); | ||
247 | return pte; | ||
248 | } | ||
249 | |||
250 | extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; | ||
251 | |||
252 | /* | ||
253 | * Encode and decode a swap entry. Swap entries are stored in the Linux | ||
254 | * page tables as follows: | ||
255 | * | ||
256 | * 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 | ||
257 | * 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 0 | ||
258 | * <--------------- offset --------------> <--- type --> 0 0 0 0 0 | ||
259 | * | ||
260 | * This gives us up to 127 swap files and 32GB per swap file. Note that | ||
261 | * the offset field is always non-zero. | ||
262 | */ | ||
263 | #define __SWP_TYPE_SHIFT 5 | ||
264 | #define __SWP_TYPE_BITS 7 | ||
265 | #define __SWP_TYPE_MASK ((1 << __SWP_TYPE_BITS) - 1) | ||
266 | #define __SWP_OFFSET_SHIFT (__SWP_TYPE_BITS + __SWP_TYPE_SHIFT) | ||
267 | |||
268 | #define __swp_type(x) (((x).val >> __SWP_TYPE_SHIFT) \ | ||
269 | & __SWP_TYPE_MASK) | ||
270 | #define __swp_offset(x) ((x).val >> __SWP_OFFSET_SHIFT) | ||
271 | #define __swp_entry(type, offset) ((swp_entry_t) { \ | ||
272 | ((type) << __SWP_TYPE_SHIFT) | \ | ||
273 | ((offset) << __SWP_OFFSET_SHIFT) }) | ||
274 | |||
275 | #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) | ||
276 | #define __swp_entry_to_pte(swp) ((pte_t) { (swp).val }) | ||
277 | |||
278 | /* | ||
279 | * It is an error for the kernel to have more swap files than we can | ||
280 | * encode in the PTEs. This ensures that we know when MAX_SWAPFILES | ||
281 | * is increased beyond what we presently support. | ||
282 | */ | ||
283 | #define MAX_SWAPFILES_CHECK() \ | ||
284 | BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > __SWP_TYPE_BITS) | ||
285 | |||
286 | /* | ||
287 | * Encode and decode a file entry. File entries are stored in the Linux | ||
288 | * page tables as follows: | ||
289 | * | ||
290 | * 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 | ||
291 | * 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 0 | ||
292 | * <----------------------- offset ----------------------> 1 0 0 0 | ||
293 | */ | ||
294 | #define pte_file(pte) (pte_val(pte) & PTE_FILE) | ||
295 | #define pte_to_pgoff(x) (pte_val(x) >> 4) | ||
296 | #define pgoff_to_pte(x) __pte(((x) << 4) | PTE_FILE) | ||
297 | |||
298 | #define PTE_FILE_MAX_BITS 28 | ||
299 | |||
300 | /* Needs to be defined here and not in linux/mm.h, as it is arch dependent */ | ||
301 | /* FIXME: this is not correct */ | ||
302 | #define kern_addr_valid(addr) (1) | ||
303 | |||
304 | #include <asm-generic/pgtable.h> | ||
305 | |||
306 | /* | ||
307 | * remap a physical page `pfn' of size `size' with page protection `prot' | ||
308 | * into virtual address `from' | ||
309 | */ | ||
310 | #define io_remap_pfn_range(vma, from, pfn, size, prot) \ | ||
311 | remap_pfn_range(vma, from, pfn, size, prot) | ||
312 | |||
313 | #define pgtable_cache_init() do { } while (0) | ||
314 | |||
315 | #endif /* !__ASSEMBLY__ */ | ||
316 | |||
317 | #endif /* __UNICORE_PGTABLE_H__ */ | ||