diff options
author | Stuart Menefy <stuart.menefy@st.com> | 2006-11-21 01:38:05 -0500 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2006-12-05 20:45:38 -0500 |
commit | 99a596f93be10001c50894bcab69e458a49a3b8c (patch) | |
tree | 16faf593cc3f7a2c39f3079f0f64f410e530e1c4 | |
parent | 6e4662ff49c6b94e16a47bfddb920576963b5a20 (diff) |
sh: pmd rework.
Remove extra bits from the pmd structure and store a kernel logical
address rather than a physical address. This allows it to be directly
dereferenced. Another piece of wierdness inherited from x86.
Signed-off-by: Stuart Menefy <stuart.menefy@st.com>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
-rw-r--r-- | arch/sh/mm/fault.c | 40 | ||||
-rw-r--r-- | arch/sh/mm/init.c | 26 | ||||
-rw-r--r-- | include/asm-sh/pgalloc.h | 20 | ||||
-rw-r--r-- | include/asm-sh/pgtable.h | 38 |
4 files changed, 76 insertions, 48 deletions
diff --git a/arch/sh/mm/fault.c b/arch/sh/mm/fault.c index 43bed2cb00e3..128907ef7fcd 100644 --- a/arch/sh/mm/fault.c +++ b/arch/sh/mm/fault.c | |||
@@ -46,6 +46,45 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, | |||
46 | mm = tsk->mm; | 46 | mm = tsk->mm; |
47 | si_code = SEGV_MAPERR; | 47 | si_code = SEGV_MAPERR; |
48 | 48 | ||
49 | if (unlikely(address >= TASK_SIZE)) { | ||
50 | /* | ||
51 | * Synchronize this task's top level page-table | ||
52 | * with the 'reference' page table. | ||
53 | * | ||
54 | * Do _not_ use "tsk" here. We might be inside | ||
55 | * an interrupt in the middle of a task switch.. | ||
56 | */ | ||
57 | int offset = pgd_index(address); | ||
58 | pgd_t *pgd, *pgd_k; | ||
59 | pud_t *pud, *pud_k; | ||
60 | pmd_t *pmd, *pmd_k; | ||
61 | |||
62 | pgd = get_TTB() + offset; | ||
63 | pgd_k = swapper_pg_dir + offset; | ||
64 | |||
65 | /* This will never happen with the folded page table. */ | ||
66 | if (!pgd_present(*pgd)) { | ||
67 | if (!pgd_present(*pgd_k)) | ||
68 | goto bad_area_nosemaphore; | ||
69 | set_pgd(pgd, *pgd_k); | ||
70 | return; | ||
71 | } | ||
72 | |||
73 | pud = pud_offset(pgd, address); | ||
74 | pud_k = pud_offset(pgd_k, address); | ||
75 | if (pud_present(*pud) || !pud_present(*pud_k)) | ||
76 | goto bad_area_nosemaphore; | ||
77 | set_pud(pud, *pud_k); | ||
78 | |||
79 | pmd = pmd_offset(pud, address); | ||
80 | pmd_k = pmd_offset(pud_k, address); | ||
81 | if (pmd_present(*pmd) || !pmd_present(*pmd_k)) | ||
82 | goto bad_area_nosemaphore; | ||
83 | set_pmd(pmd, *pmd_k); | ||
84 | |||
85 | return; | ||
86 | } | ||
87 | |||
49 | /* | 88 | /* |
50 | * If we're in an interrupt or have no user | 89 | * If we're in an interrupt or have no user |
51 | * context, we must not take the fault.. | 90 | * context, we must not take the fault.. |
@@ -109,6 +148,7 @@ survive: | |||
109 | bad_area: | 148 | bad_area: |
110 | up_read(&mm->mmap_sem); | 149 | up_read(&mm->mmap_sem); |
111 | 150 | ||
151 | bad_area_nosemaphore: | ||
112 | if (user_mode(regs)) { | 152 | if (user_mode(regs)) { |
113 | info.si_signo = SIGSEGV; | 153 | info.si_signo = SIGSEGV; |
114 | info.si_errno = 0; | 154 | info.si_errno = 0; |
diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c index 8c8d39118387..462bfeac6d9c 100644 --- a/arch/sh/mm/init.c +++ b/arch/sh/mm/init.c | |||
@@ -84,30 +84,22 @@ static void set_pte_phys(unsigned long addr, unsigned long phys, pgprot_t prot) | |||
84 | pmd_t *pmd; | 84 | pmd_t *pmd; |
85 | pte_t *pte; | 85 | pte_t *pte; |
86 | 86 | ||
87 | pgd = swapper_pg_dir + pgd_index(addr); | 87 | pgd = pgd_offset_k(addr); |
88 | if (pgd_none(*pgd)) { | 88 | if (pgd_none(*pgd)) { |
89 | pgd_ERROR(*pgd); | 89 | pgd_ERROR(*pgd); |
90 | return; | 90 | return; |
91 | } | 91 | } |
92 | 92 | ||
93 | pud = pud_offset(pgd, addr); | 93 | pud = pud_alloc(NULL, pgd, addr); |
94 | if (pud_none(*pud)) { | 94 | if (unlikely(!pud)) { |
95 | pmd = (pmd_t *)get_zeroed_page(GFP_ATOMIC); | 95 | pud_ERROR(*pud); |
96 | set_pud(pud, __pud(__pa(pmd) | _PAGE_TABLE)); | 96 | return; |
97 | if (pmd != pmd_offset(pud, 0)) { | ||
98 | pud_ERROR(*pud); | ||
99 | return; | ||
100 | } | ||
101 | } | 97 | } |
102 | 98 | ||
103 | pmd = pmd_offset(pud, addr); | 99 | pmd = pmd_alloc(NULL, pud, addr); |
104 | if (pmd_none(*pmd)) { | 100 | if (unlikely(!pmd)) { |
105 | pte = (pte_t *)get_zeroed_page(GFP_ATOMIC); | 101 | pmd_ERROR(*pmd); |
106 | set_pmd(pmd, __pmd(__pa(pte) | _PAGE_TABLE)); | 102 | return; |
107 | if (pte != pte_offset_kernel(pmd, 0)) { | ||
108 | pmd_ERROR(*pmd); | ||
109 | return; | ||
110 | } | ||
111 | } | 103 | } |
112 | 104 | ||
113 | pte = pte_offset_kernel(pmd, addr); | 105 | pte = pte_offset_kernel(pmd, addr); |
diff --git a/include/asm-sh/pgalloc.h b/include/asm-sh/pgalloc.h index e841465ab4d2..888e4529e6fe 100644 --- a/include/asm-sh/pgalloc.h +++ b/include/asm-sh/pgalloc.h | |||
@@ -1,13 +1,16 @@ | |||
1 | #ifndef __ASM_SH_PGALLOC_H | 1 | #ifndef __ASM_SH_PGALLOC_H |
2 | #define __ASM_SH_PGALLOC_H | 2 | #define __ASM_SH_PGALLOC_H |
3 | 3 | ||
4 | #define pmd_populate_kernel(mm, pmd, pte) \ | 4 | static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, |
5 | set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte))) | 5 | pte_t *pte) |
6 | { | ||
7 | set_pmd(pmd, __pmd((unsigned long)pte)); | ||
8 | } | ||
6 | 9 | ||
7 | static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, | 10 | static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, |
8 | struct page *pte) | 11 | struct page *pte) |
9 | { | 12 | { |
10 | set_pmd(pmd, __pmd(_PAGE_TABLE + page_to_phys(pte))); | 13 | set_pmd(pmd, __pmd((unsigned long)page_address(pte))); |
11 | } | 14 | } |
12 | 15 | ||
13 | /* | 16 | /* |
@@ -15,7 +18,16 @@ static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, | |||
15 | */ | 18 | */ |
16 | static inline pgd_t *pgd_alloc(struct mm_struct *mm) | 19 | static inline pgd_t *pgd_alloc(struct mm_struct *mm) |
17 | { | 20 | { |
18 | return (pgd_t *)__get_free_page(GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO); | 21 | pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL | __GFP_REPEAT); |
22 | |||
23 | if (pgd) { | ||
24 | memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t)); | ||
25 | memcpy(pgd + USER_PTRS_PER_PGD, | ||
26 | swapper_pg_dir + USER_PTRS_PER_PGD, | ||
27 | (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); | ||
28 | } | ||
29 | |||
30 | return pgd; | ||
19 | } | 31 | } |
20 | 32 | ||
21 | static inline void pgd_free(pgd_t *pgd) | 33 | static inline void pgd_free(pgd_t *pgd) |
diff --git a/include/asm-sh/pgtable.h b/include/asm-sh/pgtable.h index 22c3d0b3e11a..b1f21e765640 100644 --- a/include/asm-sh/pgtable.h +++ b/include/asm-sh/pgtable.h | |||
@@ -203,26 +203,18 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; | |||
203 | #ifndef __ASSEMBLY__ | 203 | #ifndef __ASSEMBLY__ |
204 | 204 | ||
205 | #if defined(CONFIG_X2TLB) /* SH-X2 TLB */ | 205 | #if defined(CONFIG_X2TLB) /* SH-X2 TLB */ |
206 | #define _PAGE_TABLE \ | ||
207 | (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY | \ | ||
208 | _PAGE_EXT(_PAGE_EXT_USER_READ | _PAGE_EXT_USER_WRITE)) | ||
209 | |||
210 | #define _KERNPG_TABLE \ | ||
211 | (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY | \ | ||
212 | _PAGE_EXT(_PAGE_EXT_KERN_READ | _PAGE_EXT_KERN_WRITE)) | ||
213 | |||
214 | #define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_CACHABLE | \ | 206 | #define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_CACHABLE | \ |
215 | _PAGE_ACCESSED | _PAGE_FLAGS_HARD) | 207 | _PAGE_ACCESSED | _PAGE_FLAGS_HARD) |
216 | 208 | ||
217 | #define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \ | 209 | #define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \ |
218 | _PAGE_CACHABLE | _PAGE_FLAGS_HARD | \ | 210 | _PAGE_CACHABLE | _PAGE_FLAGS_HARD | \ |
219 | _PAGE_EXT(_PAGE_EXT_USER_READ | \ | 211 | _PAGE_EXT(_PAGE_EXT_USER_READ | \ |
220 | _PAGE_EXT_USER_WRITE)) | 212 | _PAGE_EXT_USER_WRITE)) |
221 | 213 | ||
222 | #define PAGE_EXECREAD __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \ | 214 | #define PAGE_EXECREAD __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \ |
223 | _PAGE_CACHABLE | _PAGE_FLAGS_HARD | \ | 215 | _PAGE_CACHABLE | _PAGE_FLAGS_HARD | \ |
224 | _PAGE_EXT(_PAGE_EXT_USER_EXEC | \ | 216 | _PAGE_EXT(_PAGE_EXT_USER_EXEC | \ |
225 | _PAGE_EXT_USER_READ)) | 217 | _PAGE_EXT_USER_READ)) |
226 | 218 | ||
227 | #define PAGE_COPY PAGE_EXECREAD | 219 | #define PAGE_COPY PAGE_EXECREAD |
228 | 220 | ||
@@ -237,14 +229,14 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; | |||
237 | #define PAGE_RWX __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \ | 229 | #define PAGE_RWX __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \ |
238 | _PAGE_CACHABLE | _PAGE_FLAGS_HARD | \ | 230 | _PAGE_CACHABLE | _PAGE_FLAGS_HARD | \ |
239 | _PAGE_EXT(_PAGE_EXT_USER_WRITE | \ | 231 | _PAGE_EXT(_PAGE_EXT_USER_WRITE | \ |
240 | _PAGE_EXT_USER_READ | \ | 232 | _PAGE_EXT_USER_READ | \ |
241 | _PAGE_EXT_USER_EXEC)) | 233 | _PAGE_EXT_USER_EXEC)) |
242 | 234 | ||
243 | #define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_CACHABLE | \ | 235 | #define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_CACHABLE | \ |
244 | _PAGE_DIRTY | _PAGE_ACCESSED | \ | 236 | _PAGE_DIRTY | _PAGE_ACCESSED | \ |
245 | _PAGE_HW_SHARED | _PAGE_FLAGS_HARD | \ | 237 | _PAGE_HW_SHARED | _PAGE_FLAGS_HARD | \ |
246 | _PAGE_EXT(_PAGE_EXT_KERN_READ | \ | 238 | _PAGE_EXT(_PAGE_EXT_KERN_READ | \ |
247 | _PAGE_EXT_KERN_WRITE | \ | 239 | _PAGE_EXT_KERN_WRITE | \ |
248 | _PAGE_EXT_KERN_EXEC)) | 240 | _PAGE_EXT_KERN_EXEC)) |
249 | 241 | ||
250 | #define PAGE_KERNEL_NOCACHE \ | 242 | #define PAGE_KERNEL_NOCACHE \ |
@@ -252,30 +244,25 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; | |||
252 | _PAGE_ACCESSED | _PAGE_HW_SHARED | \ | 244 | _PAGE_ACCESSED | _PAGE_HW_SHARED | \ |
253 | _PAGE_FLAGS_HARD | \ | 245 | _PAGE_FLAGS_HARD | \ |
254 | _PAGE_EXT(_PAGE_EXT_KERN_READ | \ | 246 | _PAGE_EXT(_PAGE_EXT_KERN_READ | \ |
255 | _PAGE_EXT_KERN_WRITE | \ | 247 | _PAGE_EXT_KERN_WRITE | \ |
256 | _PAGE_EXT_KERN_EXEC)) | 248 | _PAGE_EXT_KERN_EXEC)) |
257 | 249 | ||
258 | #define PAGE_KERNEL_RO __pgprot(_PAGE_PRESENT | _PAGE_CACHABLE | \ | 250 | #define PAGE_KERNEL_RO __pgprot(_PAGE_PRESENT | _PAGE_CACHABLE | \ |
259 | _PAGE_DIRTY | _PAGE_ACCESSED | \ | 251 | _PAGE_DIRTY | _PAGE_ACCESSED | \ |
260 | _PAGE_HW_SHARED | _PAGE_FLAGS_HARD | \ | 252 | _PAGE_HW_SHARED | _PAGE_FLAGS_HARD | \ |
261 | _PAGE_EXT(_PAGE_EXT_KERN_READ | \ | 253 | _PAGE_EXT(_PAGE_EXT_KERN_READ | \ |
262 | _PAGE_EXT_KERN_EXEC)) | 254 | _PAGE_EXT_KERN_EXEC)) |
263 | 255 | ||
264 | #define PAGE_KERNEL_PCC(slot, type) \ | 256 | #define PAGE_KERNEL_PCC(slot, type) \ |
265 | __pgprot(_PAGE_PRESENT | _PAGE_DIRTY | \ | 257 | __pgprot(_PAGE_PRESENT | _PAGE_DIRTY | \ |
266 | _PAGE_ACCESSED | _PAGE_FLAGS_HARD | \ | 258 | _PAGE_ACCESSED | _PAGE_FLAGS_HARD | \ |
267 | _PAGE_EXT(_PAGE_EXT_KERN_READ | \ | 259 | _PAGE_EXT(_PAGE_EXT_KERN_READ | \ |
268 | _PAGE_EXT_KERN_WRITE | \ | 260 | _PAGE_EXT_KERN_WRITE | \ |
269 | _PAGE_EXT_KERN_EXEC) \ | 261 | _PAGE_EXT_KERN_EXEC) \ |
270 | (slot ? _PAGE_PCC_AREA5 : _PAGE_PCC_AREA6) | \ | 262 | (slot ? _PAGE_PCC_AREA5 : _PAGE_PCC_AREA6) | \ |
271 | (type)) | 263 | (type)) |
272 | 264 | ||
273 | #elif defined(CONFIG_MMU) /* SH-X TLB */ | 265 | #elif defined(CONFIG_MMU) /* SH-X TLB */ |
274 | #define _PAGE_TABLE \ | ||
275 | (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY) | ||
276 | #define _KERNPG_TABLE \ | ||
277 | (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY) | ||
278 | |||
279 | #define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_CACHABLE | \ | 266 | #define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_CACHABLE | \ |
280 | _PAGE_ACCESSED | _PAGE_FLAGS_HARD) | 267 | _PAGE_ACCESSED | _PAGE_FLAGS_HARD) |
281 | 268 | ||
@@ -390,9 +377,9 @@ static inline void set_pte(pte_t *ptep, pte_t pte) | |||
390 | #define pte_clear(mm,addr,xp) do { set_pte_at(mm, addr, xp, __pte(0)); } while (0) | 377 | #define pte_clear(mm,addr,xp) do { set_pte_at(mm, addr, xp, __pte(0)); } while (0) |
391 | 378 | ||
392 | #define pmd_none(x) (!pmd_val(x)) | 379 | #define pmd_none(x) (!pmd_val(x)) |
393 | #define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT) | 380 | #define pmd_present(x) (pmd_val(x)) |
394 | #define pmd_clear(xp) do { set_pmd(xp, __pmd(0)); } while (0) | 381 | #define pmd_clear(xp) do { set_pmd(xp, __pmd(0)); } while (0) |
395 | #define pmd_bad(x) ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE) | 382 | #define pmd_bad(x) (pmd_val(x) & ~PAGE_MASK) |
396 | 383 | ||
397 | #define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT)) | 384 | #define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT)) |
398 | #define pte_page(x) phys_to_page(pte_val(x)&PTE_PHYS_MASK) | 385 | #define pte_page(x) phys_to_page(pte_val(x)&PTE_PHYS_MASK) |
@@ -477,11 +464,8 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) | |||
477 | return pte; | 464 | return pte; |
478 | } | 465 | } |
479 | 466 | ||
480 | #define pmd_page_vaddr(pmd) \ | 467 | #define pmd_page_vaddr(pmd) pmd_val(pmd) |
481 | ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK)) | 468 | #define pmd_page(pmd) (virt_to_page(pmd_val(pmd))) |
482 | |||
483 | #define pmd_page(pmd) \ | ||
484 | (phys_to_page(pmd_val(pmd))) | ||
485 | 469 | ||
486 | /* to find an entry in a page-table-directory. */ | 470 | /* to find an entry in a page-table-directory. */ |
487 | #define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) | 471 | #define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) |