diff options
Diffstat (limited to 'arch/x86/mm/pageattr.c')
-rw-r--r-- | arch/x86/mm/pageattr.c | 96 |
1 files changed, 54 insertions, 42 deletions
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index a2d747c06147..23f0aa3d01c1 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c | |||
@@ -228,7 +228,6 @@ repeat: | |||
228 | /** | 228 | /** |
229 | * change_page_attr_addr - Change page table attributes in linear mapping | 229 | * change_page_attr_addr - Change page table attributes in linear mapping |
230 | * @address: Virtual address in linear mapping. | 230 | * @address: Virtual address in linear mapping. |
231 | * @numpages: Number of pages to change | ||
232 | * @prot: New page table attribute (PAGE_*) | 231 | * @prot: New page table attribute (PAGE_*) |
233 | * | 232 | * |
234 | * Change page attributes of a page in the direct mapping. This is a variant | 233 | * Change page attributes of a page in the direct mapping. This is a variant |
@@ -240,10 +239,10 @@ repeat: | |||
240 | * Modules and drivers should use the set_memory_* APIs instead. | 239 | * Modules and drivers should use the set_memory_* APIs instead. |
241 | */ | 240 | */ |
242 | 241 | ||
243 | static int change_page_attr_addr(unsigned long address, int numpages, | 242 | static int change_page_attr_addr(unsigned long address, pgprot_t prot) |
244 | pgprot_t prot) | ||
245 | { | 243 | { |
246 | int err = 0, kernel_map = 0, i; | 244 | int err = 0, kernel_map = 0; |
245 | unsigned long pfn = __pa(address) >> PAGE_SHIFT; | ||
247 | 246 | ||
248 | #ifdef CONFIG_X86_64 | 247 | #ifdef CONFIG_X86_64 |
249 | if (address >= __START_KERNEL_map && | 248 | if (address >= __START_KERNEL_map && |
@@ -254,30 +253,27 @@ static int change_page_attr_addr(unsigned long address, int numpages, | |||
254 | } | 253 | } |
255 | #endif | 254 | #endif |
256 | 255 | ||
257 | for (i = 0; i < numpages; i++, address += PAGE_SIZE) { | 256 | if (!kernel_map || pte_present(pfn_pte(0, prot))) { |
258 | unsigned long pfn = __pa(address) >> PAGE_SHIFT; | 257 | err = __change_page_attr(address, pfn, prot); |
258 | if (err) | ||
259 | return err; | ||
260 | } | ||
259 | 261 | ||
260 | if (!kernel_map || pte_present(pfn_pte(0, prot))) { | ||
261 | err = __change_page_attr(address, pfn, prot); | ||
262 | if (err) | ||
263 | break; | ||
264 | } | ||
265 | #ifdef CONFIG_X86_64 | 262 | #ifdef CONFIG_X86_64 |
266 | /* | 263 | /* |
267 | * Handle kernel mapping too which aliases part of | 264 | * Handle kernel mapping too which aliases part of |
268 | * lowmem: | 265 | * lowmem: |
269 | */ | 266 | */ |
270 | if (__pa(address) < KERNEL_TEXT_SIZE) { | 267 | if (__pa(address) < KERNEL_TEXT_SIZE) { |
271 | unsigned long addr2; | 268 | unsigned long addr2; |
272 | pgprot_t prot2; | 269 | pgprot_t prot2; |
273 | 270 | ||
274 | addr2 = __START_KERNEL_map + __pa(address); | 271 | addr2 = __START_KERNEL_map + __pa(address); |
275 | /* Make sure the kernel mappings stay executable */ | 272 | /* Make sure the kernel mappings stay executable */ |
276 | prot2 = pte_pgprot(pte_mkexec(pfn_pte(0, prot))); | 273 | prot2 = pte_pgprot(pte_mkexec(pfn_pte(0, prot))); |
277 | err = __change_page_attr(addr2, pfn, prot2); | 274 | err = __change_page_attr(addr2, pfn, prot2); |
278 | } | ||
279 | #endif | ||
280 | } | 275 | } |
276 | #endif | ||
281 | 277 | ||
282 | return err; | 278 | return err; |
283 | } | 279 | } |
@@ -307,16 +303,24 @@ static int change_page_attr_set(unsigned long addr, int numpages, | |||
307 | pgprot_t current_prot; | 303 | pgprot_t current_prot; |
308 | int level; | 304 | int level; |
309 | pte_t *pte; | 305 | pte_t *pte; |
306 | int i, ret; | ||
310 | 307 | ||
311 | pte = lookup_address(addr, &level); | 308 | for (i = 0; i < numpages ; i++) { |
312 | if (pte) | ||
313 | current_prot = pte_pgprot(*pte); | ||
314 | else | ||
315 | pgprot_val(current_prot) = 0; | ||
316 | 309 | ||
317 | pgprot_val(prot) = pgprot_val(current_prot) | pgprot_val(prot); | 310 | pte = lookup_address(addr, &level); |
311 | if (pte) | ||
312 | current_prot = pte_pgprot(*pte); | ||
313 | else | ||
314 | pgprot_val(current_prot) = 0; | ||
318 | 315 | ||
319 | return change_page_attr_addr(addr, numpages, prot); | 316 | pgprot_val(prot) = pgprot_val(current_prot) | pgprot_val(prot); |
317 | |||
318 | ret = change_page_attr_addr(addr, prot); | ||
319 | if (ret) | ||
320 | return ret; | ||
321 | addr += PAGE_SIZE; | ||
322 | } | ||
323 | return 0; | ||
320 | } | 324 | } |
321 | 325 | ||
322 | /** | 326 | /** |
@@ -344,16 +348,24 @@ static int change_page_attr_clear(unsigned long addr, int numpages, | |||
344 | pgprot_t current_prot; | 348 | pgprot_t current_prot; |
345 | int level; | 349 | int level; |
346 | pte_t *pte; | 350 | pte_t *pte; |
347 | 351 | int i, ret; | |
348 | pte = lookup_address(addr, &level); | 352 | |
349 | if (pte) | 353 | for (i = 0; i < numpages; i++) { |
350 | current_prot = pte_pgprot(*pte); | 354 | pte = lookup_address(addr, &level); |
351 | else | 355 | if (pte) |
352 | pgprot_val(current_prot) = 0; | 356 | current_prot = pte_pgprot(*pte); |
353 | 357 | else | |
354 | pgprot_val(prot) = pgprot_val(current_prot) & ~pgprot_val(prot); | 358 | pgprot_val(current_prot) = 0; |
355 | 359 | ||
356 | return change_page_attr_addr(addr, numpages, prot); | 360 | pgprot_val(prot) = |
361 | pgprot_val(current_prot) & ~pgprot_val(prot); | ||
362 | |||
363 | ret = change_page_attr_addr(addr, prot); | ||
364 | if (ret) | ||
365 | return ret; | ||
366 | addr += PAGE_SIZE; | ||
367 | } | ||
368 | return 0; | ||
357 | } | 369 | } |
358 | 370 | ||
359 | int set_memory_uc(unsigned long addr, int numpages) | 371 | int set_memory_uc(unsigned long addr, int numpages) |