aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSergei Shtylyov <sshtylyov@ru.mvista.com>2006-04-16 15:27:21 -0400
committerRalf Baechle <ralf@linux-mips.org>2006-05-31 19:28:30 -0400
commit6e9538917c5f62c1a1598da9b898702800801b98 (patch)
tree03ee3776796394870e60f74773f6b23b090dad83
parent343fdc39713d9c2fe836523e8f2dfc6a3ac39122 (diff)
[MIPS] Fix marking buddy of pte global for MIPS32 w/36-bit physical address
In case of CONFIG_64BIT_PHYS_ADDR, set_pte() and pte_clear() functions only set _PAGE_GLOBAL bit in the pte_low field of the buddy PTEs, forgetting to propagate ito to pte_high. Thus, the both pages might not really be made global for the CPU (since it AND's the G-bit of the odd / even PTEs together to decide whether they're global or not). Thus, if only a single page is allocated via vmalloc() or ioremap(), it's not really global for CPU (and it must be, since this is kernel mapping), and thus its ASID is compared against the current process' one -- so, we'll get into trouble sooner or later... Also, pte_none() will fail on global pages because _PAGE_GLOBAL bit is set in both pte_low and pte_high, and pte_val() will return u64 value consisting of those fields concateneted. Signed-off-by: Sergei Shtylyov <sshtylyov@ru.mvista.com> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
-rw-r--r--include/asm-mips/pgtable.h88
1 files changed, 49 insertions, 39 deletions
diff --git a/include/asm-mips/pgtable.h b/include/asm-mips/pgtable.h
index 702a28fa7a34..174a3cda8c26 100644
--- a/include/asm-mips/pgtable.h
+++ b/include/asm-mips/pgtable.h
@@ -82,10 +82,11 @@ extern void paging_init(void);
82#define pmd_page(pmd) (pfn_to_page(pmd_phys(pmd) >> PAGE_SHIFT)) 82#define pmd_page(pmd) (pfn_to_page(pmd_phys(pmd) >> PAGE_SHIFT))
83#define pmd_page_kernel(pmd) pmd_val(pmd) 83#define pmd_page_kernel(pmd) pmd_val(pmd)
84 84
85#define pte_none(pte) (!(pte_val(pte) & ~_PAGE_GLOBAL))
86#define pte_present(pte) (pte_val(pte) & _PAGE_PRESENT)
87
88#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32_R1) 85#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32_R1)
86
87#define pte_none(pte) (!(((pte).pte_low | (pte).pte_high) & ~_PAGE_GLOBAL))
88#define pte_present(pte) ((pte).pte_low & _PAGE_PRESENT)
89
89static inline void set_pte(pte_t *ptep, pte_t pte) 90static inline void set_pte(pte_t *ptep, pte_t pte)
90{ 91{
91 ptep->pte_high = pte.pte_high; 92 ptep->pte_high = pte.pte_high;
@@ -93,27 +94,35 @@ static inline void set_pte(pte_t *ptep, pte_t pte)
93 ptep->pte_low = pte.pte_low; 94 ptep->pte_low = pte.pte_low;
94 //printk("pte_high %x pte_low %x\n", ptep->pte_high, ptep->pte_low); 95 //printk("pte_high %x pte_low %x\n", ptep->pte_high, ptep->pte_low);
95 96
96 if (pte_val(pte) & _PAGE_GLOBAL) { 97 if (pte.pte_low & _PAGE_GLOBAL) {
97 pte_t *buddy = ptep_buddy(ptep); 98 pte_t *buddy = ptep_buddy(ptep);
98 /* 99 /*
99 * Make sure the buddy is global too (if it's !none, 100 * Make sure the buddy is global too (if it's !none,
100 * it better already be global) 101 * it better already be global)
101 */ 102 */
102 if (pte_none(*buddy)) 103 if (pte_none(*buddy)) {
103 buddy->pte_low |= _PAGE_GLOBAL; 104 buddy->pte_low |= _PAGE_GLOBAL;
105 buddy->pte_high |= _PAGE_GLOBAL;
106 }
104 } 107 }
105} 108}
106#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval) 109#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
107 110
108static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) 111static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
109{ 112{
113 pte_t null = __pte(0);
114
110 /* Preserve global status for the pair */ 115 /* Preserve global status for the pair */
111 if (pte_val(*ptep_buddy(ptep)) & _PAGE_GLOBAL) 116 if (ptep_buddy(ptep)->pte_low & _PAGE_GLOBAL)
112 set_pte_at(mm, addr, ptep, __pte(_PAGE_GLOBAL)); 117 null.pte_low = null.pte_high = _PAGE_GLOBAL;
113 else 118
114 set_pte_at(mm, addr, ptep, __pte(0)); 119 set_pte_at(mm, addr, ptep, null);
115} 120}
116#else 121#else
122
123#define pte_none(pte) (!(pte_val(pte) & ~_PAGE_GLOBAL))
124#define pte_present(pte) (pte_val(pte) & _PAGE_PRESENT)
125
117/* 126/*
118 * Certain architectures need to do special things when pte's 127 * Certain architectures need to do special things when pte's
119 * within a page table are directly modified. Thus, the following 128 * within a page table are directly modified. Thus, the following
@@ -174,75 +183,76 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
174 */ 183 */
175static inline int pte_user(pte_t pte) { BUG(); return 0; } 184static inline int pte_user(pte_t pte) { BUG(); return 0; }
176#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32_R1) 185#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32_R1)
177static inline int pte_read(pte_t pte) { return (pte).pte_low & _PAGE_READ; } 186static inline int pte_read(pte_t pte) { return pte.pte_low & _PAGE_READ; }
178static inline int pte_write(pte_t pte) { return (pte).pte_low & _PAGE_WRITE; } 187static inline int pte_write(pte_t pte) { return pte.pte_low & _PAGE_WRITE; }
179static inline int pte_dirty(pte_t pte) { return (pte).pte_low & _PAGE_MODIFIED; } 188static inline int pte_dirty(pte_t pte) { return pte.pte_low & _PAGE_MODIFIED; }
180static inline int pte_young(pte_t pte) { return (pte).pte_low & _PAGE_ACCESSED; } 189static inline int pte_young(pte_t pte) { return pte.pte_low & _PAGE_ACCESSED; }
181static inline int pte_file(pte_t pte) { return (pte).pte_low & _PAGE_FILE; } 190static inline int pte_file(pte_t pte) { return pte.pte_low & _PAGE_FILE; }
191
182static inline pte_t pte_wrprotect(pte_t pte) 192static inline pte_t pte_wrprotect(pte_t pte)
183{ 193{
184 (pte).pte_low &= ~(_PAGE_WRITE | _PAGE_SILENT_WRITE); 194 pte.pte_low &= ~(_PAGE_WRITE | _PAGE_SILENT_WRITE);
185 (pte).pte_high &= ~_PAGE_SILENT_WRITE; 195 pte.pte_high &= ~_PAGE_SILENT_WRITE;
186 return pte; 196 return pte;
187} 197}
188 198
189static inline pte_t pte_rdprotect(pte_t pte) 199static inline pte_t pte_rdprotect(pte_t pte)
190{ 200{
191 (pte).pte_low &= ~(_PAGE_READ | _PAGE_SILENT_READ); 201 pte.pte_low &= ~(_PAGE_READ | _PAGE_SILENT_READ);
192 (pte).pte_high &= ~_PAGE_SILENT_READ; 202 pte.pte_high &= ~_PAGE_SILENT_READ;
193 return pte; 203 return pte;
194} 204}
195 205
196static inline pte_t pte_mkclean(pte_t pte) 206static inline pte_t pte_mkclean(pte_t pte)
197{ 207{
198 (pte).pte_low &= ~(_PAGE_MODIFIED|_PAGE_SILENT_WRITE); 208 pte.pte_low &= ~(_PAGE_MODIFIED | _PAGE_SILENT_WRITE);
199 (pte).pte_high &= ~_PAGE_SILENT_WRITE; 209 pte.pte_high &= ~_PAGE_SILENT_WRITE;
200 return pte; 210 return pte;
201} 211}
202 212
203static inline pte_t pte_mkold(pte_t pte) 213static inline pte_t pte_mkold(pte_t pte)
204{ 214{
205 (pte).pte_low &= ~(_PAGE_ACCESSED|_PAGE_SILENT_READ); 215 pte.pte_low &= ~(_PAGE_ACCESSED | _PAGE_SILENT_READ);
206 (pte).pte_high &= ~_PAGE_SILENT_READ; 216 pte.pte_high &= ~_PAGE_SILENT_READ;
207 return pte; 217 return pte;
208} 218}
209 219
210static inline pte_t pte_mkwrite(pte_t pte) 220static inline pte_t pte_mkwrite(pte_t pte)
211{ 221{
212 (pte).pte_low |= _PAGE_WRITE; 222 pte.pte_low |= _PAGE_WRITE;
213 if ((pte).pte_low & _PAGE_MODIFIED) { 223 if (pte.pte_low & _PAGE_MODIFIED) {
214 (pte).pte_low |= _PAGE_SILENT_WRITE; 224 pte.pte_low |= _PAGE_SILENT_WRITE;
215 (pte).pte_high |= _PAGE_SILENT_WRITE; 225 pte.pte_high |= _PAGE_SILENT_WRITE;
216 } 226 }
217 return pte; 227 return pte;
218} 228}
219 229
220static inline pte_t pte_mkread(pte_t pte) 230static inline pte_t pte_mkread(pte_t pte)
221{ 231{
222 (pte).pte_low |= _PAGE_READ; 232 pte.pte_low |= _PAGE_READ;
223 if ((pte).pte_low & _PAGE_ACCESSED) { 233 if (pte.pte_low & _PAGE_ACCESSED) {
224 (pte).pte_low |= _PAGE_SILENT_READ; 234 pte.pte_low |= _PAGE_SILENT_READ;
225 (pte).pte_high |= _PAGE_SILENT_READ; 235 pte.pte_high |= _PAGE_SILENT_READ;
226 } 236 }
227 return pte; 237 return pte;
228} 238}
229 239
230static inline pte_t pte_mkdirty(pte_t pte) 240static inline pte_t pte_mkdirty(pte_t pte)
231{ 241{
232 (pte).pte_low |= _PAGE_MODIFIED; 242 pte.pte_low |= _PAGE_MODIFIED;
233 if ((pte).pte_low & _PAGE_WRITE) { 243 if (pte.pte_low & _PAGE_WRITE) {
234 (pte).pte_low |= _PAGE_SILENT_WRITE; 244 pte.pte_low |= _PAGE_SILENT_WRITE;
235 (pte).pte_high |= _PAGE_SILENT_WRITE; 245 pte.pte_high |= _PAGE_SILENT_WRITE;
236 } 246 }
237 return pte; 247 return pte;
238} 248}
239 249
240static inline pte_t pte_mkyoung(pte_t pte) 250static inline pte_t pte_mkyoung(pte_t pte)
241{ 251{
242 (pte).pte_low |= _PAGE_ACCESSED; 252 pte.pte_low |= _PAGE_ACCESSED;
243 if ((pte).pte_low & _PAGE_READ) 253 if (pte.pte_low & _PAGE_READ)
244 (pte).pte_low |= _PAGE_SILENT_READ; 254 pte.pte_low |= _PAGE_SILENT_READ;
245 (pte).pte_high |= _PAGE_SILENT_READ; 255 pte.pte_high |= _PAGE_SILENT_READ;
246 return pte; 256 return pte;
247} 257}
248#else 258#else