aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStuart Menefy <stuart.menefy@st.com>2006-11-21 01:38:05 -0500
committerPaul Mundt <lethal@linux-sh.org>2006-12-05 20:45:38 -0500
commit99a596f93be10001c50894bcab69e458a49a3b8c (patch)
tree16faf593cc3f7a2c39f3079f0f64f410e530e1c4
parent6e4662ff49c6b94e16a47bfddb920576963b5a20 (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.c40
-rw-r--r--arch/sh/mm/init.c26
-rw-r--r--include/asm-sh/pgalloc.h20
-rw-r--r--include/asm-sh/pgtable.h38
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:
109bad_area: 148bad_area:
110 up_read(&mm->mmap_sem); 149 up_read(&mm->mmap_sem);
111 150
151bad_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) \ 4static 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
7static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, 10static 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 */
16static inline pgd_t *pgd_alloc(struct mm_struct *mm) 19static 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
21static inline void pgd_free(pgd_t *pgd) 33static 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))