diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-22 22:23:34 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-22 22:23:34 -0400 |
commit | 56d61a0e26c5a61c66d1ac259a59960295939da9 (patch) | |
tree | a23a30a966fe4220060682179294087cba1f9c57 /include/asm-s390/pgtable.h | |
parent | 5f48b338cd28f4095697a174d7e3e72084aca893 (diff) | |
parent | 190a1d722a59725706daf832bc8a511ed62f249d (diff) |
Merge branch 'for-linus' of git://git390.osdl.marist.edu/pub/scm/linux-2.6
* 'for-linus' of git://git390.osdl.marist.edu/pub/scm/linux-2.6:
[S390] 4level-fixup cleanup
[S390] Cleanup page table definitions.
[S390] Introduce follow_table in uaccess_pt.c
[S390] Remove unused user_seg from thread structure.
[S390] tlb flush fix.
[S390] kernel: Fix dump on panic for DASDs under LPAR.
[S390] struct class_device -> struct device conversion.
[S390] cio: Fix incomplete commit for uevent suppression.
[S390] cio: Use to_channelpath() for device to channel path conversion.
[S390] Add per-cpu idle time / idle count sysfs attributes.
[S390] Update default configuration.
Diffstat (limited to 'include/asm-s390/pgtable.h')
-rw-r--r-- | include/asm-s390/pgtable.h | 429 |
1 files changed, 223 insertions, 206 deletions
diff --git a/include/asm-s390/pgtable.h b/include/asm-s390/pgtable.h index 39bb5192dc31..f2cc25b74adf 100644 --- a/include/asm-s390/pgtable.h +++ b/include/asm-s390/pgtable.h | |||
@@ -13,8 +13,6 @@ | |||
13 | #ifndef _ASM_S390_PGTABLE_H | 13 | #ifndef _ASM_S390_PGTABLE_H |
14 | #define _ASM_S390_PGTABLE_H | 14 | #define _ASM_S390_PGTABLE_H |
15 | 15 | ||
16 | #include <asm-generic/4level-fixup.h> | ||
17 | |||
18 | /* | 16 | /* |
19 | * The Linux memory management assumes a three-level page table setup. For | 17 | * The Linux memory management assumes a three-level page table setup. For |
20 | * s390 31 bit we "fold" the mid level into the top-level page table, so | 18 | * s390 31 bit we "fold" the mid level into the top-level page table, so |
@@ -35,9 +33,6 @@ | |||
35 | #include <asm/bug.h> | 33 | #include <asm/bug.h> |
36 | #include <asm/processor.h> | 34 | #include <asm/processor.h> |
37 | 35 | ||
38 | struct vm_area_struct; /* forward declaration (include/linux/mm.h) */ | ||
39 | struct mm_struct; | ||
40 | |||
41 | extern pgd_t swapper_pg_dir[] __attribute__ ((aligned (4096))); | 36 | extern pgd_t swapper_pg_dir[] __attribute__ ((aligned (4096))); |
42 | extern void paging_init(void); | 37 | extern void paging_init(void); |
43 | extern void vmem_map_init(void); | 38 | extern void vmem_map_init(void); |
@@ -63,14 +58,18 @@ extern char empty_zero_page[PAGE_SIZE]; | |||
63 | */ | 58 | */ |
64 | #ifndef __s390x__ | 59 | #ifndef __s390x__ |
65 | # define PMD_SHIFT 22 | 60 | # define PMD_SHIFT 22 |
61 | # define PUD_SHIFT 22 | ||
66 | # define PGDIR_SHIFT 22 | 62 | # define PGDIR_SHIFT 22 |
67 | #else /* __s390x__ */ | 63 | #else /* __s390x__ */ |
68 | # define PMD_SHIFT 21 | 64 | # define PMD_SHIFT 21 |
65 | # define PUD_SHIFT 31 | ||
69 | # define PGDIR_SHIFT 31 | 66 | # define PGDIR_SHIFT 31 |
70 | #endif /* __s390x__ */ | 67 | #endif /* __s390x__ */ |
71 | 68 | ||
72 | #define PMD_SIZE (1UL << PMD_SHIFT) | 69 | #define PMD_SIZE (1UL << PMD_SHIFT) |
73 | #define PMD_MASK (~(PMD_SIZE-1)) | 70 | #define PMD_MASK (~(PMD_SIZE-1)) |
71 | #define PUD_SIZE (1UL << PUD_SHIFT) | ||
72 | #define PUD_MASK (~(PUD_SIZE-1)) | ||
74 | #define PGDIR_SIZE (1UL << PGDIR_SHIFT) | 73 | #define PGDIR_SIZE (1UL << PGDIR_SHIFT) |
75 | #define PGDIR_MASK (~(PGDIR_SIZE-1)) | 74 | #define PGDIR_MASK (~(PGDIR_SIZE-1)) |
76 | 75 | ||
@@ -83,10 +82,12 @@ extern char empty_zero_page[PAGE_SIZE]; | |||
83 | #ifndef __s390x__ | 82 | #ifndef __s390x__ |
84 | # define PTRS_PER_PTE 1024 | 83 | # define PTRS_PER_PTE 1024 |
85 | # define PTRS_PER_PMD 1 | 84 | # define PTRS_PER_PMD 1 |
85 | # define PTRS_PER_PUD 1 | ||
86 | # define PTRS_PER_PGD 512 | 86 | # define PTRS_PER_PGD 512 |
87 | #else /* __s390x__ */ | 87 | #else /* __s390x__ */ |
88 | # define PTRS_PER_PTE 512 | 88 | # define PTRS_PER_PTE 512 |
89 | # define PTRS_PER_PMD 1024 | 89 | # define PTRS_PER_PMD 1024 |
90 | # define PTRS_PER_PUD 1 | ||
90 | # define PTRS_PER_PGD 2048 | 91 | # define PTRS_PER_PGD 2048 |
91 | #endif /* __s390x__ */ | 92 | #endif /* __s390x__ */ |
92 | 93 | ||
@@ -96,6 +97,8 @@ extern char empty_zero_page[PAGE_SIZE]; | |||
96 | printk("%s:%d: bad pte %p.\n", __FILE__, __LINE__, (void *) pte_val(e)) | 97 | printk("%s:%d: bad pte %p.\n", __FILE__, __LINE__, (void *) pte_val(e)) |
97 | #define pmd_ERROR(e) \ | 98 | #define pmd_ERROR(e) \ |
98 | printk("%s:%d: bad pmd %p.\n", __FILE__, __LINE__, (void *) pmd_val(e)) | 99 | printk("%s:%d: bad pmd %p.\n", __FILE__, __LINE__, (void *) pmd_val(e)) |
100 | #define pud_ERROR(e) \ | ||
101 | printk("%s:%d: bad pud %p.\n", __FILE__, __LINE__, (void *) pud_val(e)) | ||
99 | #define pgd_ERROR(e) \ | 102 | #define pgd_ERROR(e) \ |
100 | printk("%s:%d: bad pgd %p.\n", __FILE__, __LINE__, (void *) pgd_val(e)) | 103 | printk("%s:%d: bad pgd %p.\n", __FILE__, __LINE__, (void *) pgd_val(e)) |
101 | 104 | ||
@@ -195,7 +198,7 @@ extern unsigned long vmalloc_end; | |||
195 | * I Segment-Invalid Bit: Segment is not available for address-translation | 198 | * I Segment-Invalid Bit: Segment is not available for address-translation |
196 | * TT Type 01 | 199 | * TT Type 01 |
197 | * TF | 200 | * TF |
198 | * TL Table lenght | 201 | * TL Table length |
199 | * | 202 | * |
200 | * The 64 bit regiontable origin of S390 has following format: | 203 | * The 64 bit regiontable origin of S390 has following format: |
201 | * | region table origon | DTTL | 204 | * | region table origon | DTTL |
@@ -221,6 +224,8 @@ extern unsigned long vmalloc_end; | |||
221 | /* Hardware bits in the page table entry */ | 224 | /* Hardware bits in the page table entry */ |
222 | #define _PAGE_RO 0x200 /* HW read-only bit */ | 225 | #define _PAGE_RO 0x200 /* HW read-only bit */ |
223 | #define _PAGE_INVALID 0x400 /* HW invalid bit */ | 226 | #define _PAGE_INVALID 0x400 /* HW invalid bit */ |
227 | |||
228 | /* Software bits in the page table entry */ | ||
224 | #define _PAGE_SWT 0x001 /* SW pte type bit t */ | 229 | #define _PAGE_SWT 0x001 /* SW pte type bit t */ |
225 | #define _PAGE_SWX 0x002 /* SW pte type bit x */ | 230 | #define _PAGE_SWX 0x002 /* SW pte type bit x */ |
226 | 231 | ||
@@ -264,60 +269,75 @@ extern unsigned long vmalloc_end; | |||
264 | 269 | ||
265 | #ifndef __s390x__ | 270 | #ifndef __s390x__ |
266 | 271 | ||
267 | /* Bits in the segment table entry */ | 272 | /* Bits in the segment table address-space-control-element */ |
268 | #define _PAGE_TABLE_LEN 0xf /* only full page-tables */ | 273 | #define _ASCE_SPACE_SWITCH 0x80000000UL /* space switch event */ |
269 | #define _PAGE_TABLE_COM 0x10 /* common page-table */ | 274 | #define _ASCE_ORIGIN_MASK 0x7ffff000UL /* segment table origin */ |
270 | #define _PAGE_TABLE_INV 0x20 /* invalid page-table */ | 275 | #define _ASCE_PRIVATE_SPACE 0x100 /* private space control */ |
271 | #define _SEG_PRESENT 0x001 /* Software (overlap with PTL) */ | 276 | #define _ASCE_ALT_EVENT 0x80 /* storage alteration event control */ |
272 | 277 | #define _ASCE_TABLE_LENGTH 0x7f /* 128 x 64 entries = 8k */ | |
273 | /* Bits int the storage key */ | ||
274 | #define _PAGE_CHANGED 0x02 /* HW changed bit */ | ||
275 | #define _PAGE_REFERENCED 0x04 /* HW referenced bit */ | ||
276 | |||
277 | #define _USER_SEG_TABLE_LEN 0x7f /* user-segment-table up to 2 GB */ | ||
278 | #define _KERNEL_SEG_TABLE_LEN 0x7f /* kernel-segment-table up to 2 GB */ | ||
279 | |||
280 | /* | ||
281 | * User and Kernel pagetables are identical | ||
282 | */ | ||
283 | #define _PAGE_TABLE _PAGE_TABLE_LEN | ||
284 | #define _KERNPG_TABLE _PAGE_TABLE_LEN | ||
285 | |||
286 | /* | ||
287 | * The Kernel segment-tables includes the User segment-table | ||
288 | */ | ||
289 | 278 | ||
290 | #define _SEGMENT_TABLE (_USER_SEG_TABLE_LEN|0x80000000|0x100) | 279 | /* Bits in the segment table entry */ |
291 | #define _KERNSEG_TABLE _KERNEL_SEG_TABLE_LEN | 280 | #define _SEGMENT_ENTRY_ORIGIN 0x7fffffc0UL /* page table origin */ |
281 | #define _SEGMENT_ENTRY_INV 0x20 /* invalid segment table entry */ | ||
282 | #define _SEGMENT_ENTRY_COMMON 0x10 /* common segment bit */ | ||
283 | #define _SEGMENT_ENTRY_PTL 0x0f /* page table length */ | ||
292 | 284 | ||
293 | #define USER_STD_MASK 0x00000080UL | 285 | #define _SEGMENT_ENTRY (_SEGMENT_ENTRY_PTL) |
286 | #define _SEGMENT_ENTRY_EMPTY (_SEGMENT_ENTRY_INV) | ||
294 | 287 | ||
295 | #else /* __s390x__ */ | 288 | #else /* __s390x__ */ |
296 | 289 | ||
290 | /* Bits in the segment/region table address-space-control-element */ | ||
291 | #define _ASCE_ORIGIN ~0xfffUL/* segment table origin */ | ||
292 | #define _ASCE_PRIVATE_SPACE 0x100 /* private space control */ | ||
293 | #define _ASCE_ALT_EVENT 0x80 /* storage alteration event control */ | ||
294 | #define _ASCE_SPACE_SWITCH 0x40 /* space switch event */ | ||
295 | #define _ASCE_REAL_SPACE 0x20 /* real space control */ | ||
296 | #define _ASCE_TYPE_MASK 0x0c /* asce table type mask */ | ||
297 | #define _ASCE_TYPE_REGION1 0x0c /* region first table type */ | ||
298 | #define _ASCE_TYPE_REGION2 0x08 /* region second table type */ | ||
299 | #define _ASCE_TYPE_REGION3 0x04 /* region third table type */ | ||
300 | #define _ASCE_TYPE_SEGMENT 0x00 /* segment table type */ | ||
301 | #define _ASCE_TABLE_LENGTH 0x03 /* region table length */ | ||
302 | |||
303 | /* Bits in the region table entry */ | ||
304 | #define _REGION_ENTRY_ORIGIN ~0xfffUL/* region/segment table origin */ | ||
305 | #define _REGION_ENTRY_INV 0x20 /* invalid region table entry */ | ||
306 | #define _REGION_ENTRY_TYPE_MASK 0x0c /* region/segment table type mask */ | ||
307 | #define _REGION_ENTRY_TYPE_R1 0x0c /* region first table type */ | ||
308 | #define _REGION_ENTRY_TYPE_R2 0x08 /* region second table type */ | ||
309 | #define _REGION_ENTRY_TYPE_R3 0x04 /* region third table type */ | ||
310 | #define _REGION_ENTRY_LENGTH 0x03 /* region third length */ | ||
311 | |||
312 | #define _REGION1_ENTRY (_REGION_ENTRY_TYPE_R1 | _REGION_ENTRY_LENGTH) | ||
313 | #define _REGION1_ENTRY_EMPTY (_REGION_ENTRY_TYPE_R1 | _REGION_ENTRY_INV) | ||
314 | #define _REGION2_ENTRY (_REGION_ENTRY_TYPE_R2 | _REGION_ENTRY_LENGTH) | ||
315 | #define _REGION2_ENTRY_EMPTY (_REGION_ENTRY_TYPE_R2 | _REGION_ENTRY_INV) | ||
316 | #define _REGION3_ENTRY (_REGION_ENTRY_TYPE_R3 | _REGION_ENTRY_LENGTH) | ||
317 | #define _REGION3_ENTRY_EMPTY (_REGION_ENTRY_TYPE_R3 | _REGION_ENTRY_INV) | ||
318 | |||
297 | /* Bits in the segment table entry */ | 319 | /* Bits in the segment table entry */ |
298 | #define _PMD_ENTRY_INV 0x20 /* invalid segment table entry */ | 320 | #define _SEGMENT_ENTRY_ORIGIN ~0x7ffUL/* segment table origin */ |
299 | #define _PMD_ENTRY 0x00 | 321 | #define _SEGMENT_ENTRY_RO 0x200 /* page protection bit */ |
322 | #define _SEGMENT_ENTRY_INV 0x20 /* invalid segment table entry */ | ||
323 | |||
324 | #define _SEGMENT_ENTRY (0) | ||
325 | #define _SEGMENT_ENTRY_EMPTY (_SEGMENT_ENTRY_INV) | ||
300 | 326 | ||
301 | /* Bits in the region third table entry */ | 327 | #endif /* __s390x__ */ |
302 | #define _PGD_ENTRY_INV 0x20 /* invalid region table entry */ | ||
303 | #define _PGD_ENTRY 0x07 | ||
304 | 328 | ||
305 | /* | 329 | /* |
306 | * User and kernel page directory | 330 | * A user page table pointer has the space-switch-event bit, the |
331 | * private-space-control bit and the storage-alteration-event-control | ||
332 | * bit set. A kernel page table pointer doesn't need them. | ||
307 | */ | 333 | */ |
308 | #define _REGION_THIRD 0x4 | 334 | #define _ASCE_USER_BITS (_ASCE_SPACE_SWITCH | _ASCE_PRIVATE_SPACE | \ |
309 | #define _REGION_THIRD_LEN 0x3 | 335 | _ASCE_ALT_EVENT) |
310 | #define _REGION_TABLE (_REGION_THIRD|_REGION_THIRD_LEN|0x40|0x100) | ||
311 | #define _KERN_REGION_TABLE (_REGION_THIRD|_REGION_THIRD_LEN) | ||
312 | |||
313 | #define USER_STD_MASK 0x0000000000000080UL | ||
314 | 336 | ||
315 | /* Bits in the storage key */ | 337 | /* Bits int the storage key */ |
316 | #define _PAGE_CHANGED 0x02 /* HW changed bit */ | 338 | #define _PAGE_CHANGED 0x02 /* HW changed bit */ |
317 | #define _PAGE_REFERENCED 0x04 /* HW referenced bit */ | 339 | #define _PAGE_REFERENCED 0x04 /* HW referenced bit */ |
318 | 340 | ||
319 | #endif /* __s390x__ */ | ||
320 | |||
321 | /* | 341 | /* |
322 | * Page protection definitions. | 342 | * Page protection definitions. |
323 | */ | 343 | */ |
@@ -358,65 +378,38 @@ extern unsigned long vmalloc_end; | |||
358 | #define __S111 PAGE_EX_RW | 378 | #define __S111 PAGE_EX_RW |
359 | 379 | ||
360 | #ifndef __s390x__ | 380 | #ifndef __s390x__ |
361 | # define PMD_SHADOW_SHIFT 1 | 381 | # define PxD_SHADOW_SHIFT 1 |
362 | # define PGD_SHADOW_SHIFT 1 | ||
363 | #else /* __s390x__ */ | 382 | #else /* __s390x__ */ |
364 | # define PMD_SHADOW_SHIFT 2 | 383 | # define PxD_SHADOW_SHIFT 2 |
365 | # define PGD_SHADOW_SHIFT 2 | ||
366 | #endif /* __s390x__ */ | 384 | #endif /* __s390x__ */ |
367 | 385 | ||
368 | static inline struct page *get_shadow_page(struct page *page) | 386 | static inline struct page *get_shadow_page(struct page *page) |
369 | { | 387 | { |
370 | if (s390_noexec && !list_empty(&page->lru)) | 388 | if (s390_noexec && page->index) |
371 | return virt_to_page(page->lru.next); | 389 | return virt_to_page((void *)(addr_t) page->index); |
372 | return NULL; | ||
373 | } | ||
374 | |||
375 | static inline pte_t *get_shadow_pte(pte_t *ptep) | ||
376 | { | ||
377 | unsigned long pteptr = (unsigned long) (ptep); | ||
378 | |||
379 | if (s390_noexec) { | ||
380 | unsigned long offset = pteptr & (PAGE_SIZE - 1); | ||
381 | void *addr = (void *) (pteptr ^ offset); | ||
382 | struct page *page = virt_to_page(addr); | ||
383 | if (!list_empty(&page->lru)) | ||
384 | return (pte_t *) ((unsigned long) page->lru.next | | ||
385 | offset); | ||
386 | } | ||
387 | return NULL; | 390 | return NULL; |
388 | } | 391 | } |
389 | 392 | ||
390 | static inline pmd_t *get_shadow_pmd(pmd_t *pmdp) | 393 | static inline void *get_shadow_pte(void *table) |
391 | { | 394 | { |
392 | unsigned long pmdptr = (unsigned long) (pmdp); | 395 | unsigned long addr, offset; |
396 | struct page *page; | ||
393 | 397 | ||
394 | if (s390_noexec) { | 398 | addr = (unsigned long) table; |
395 | unsigned long offset = pmdptr & | 399 | offset = addr & (PAGE_SIZE - 1); |
396 | ((PAGE_SIZE << PMD_SHADOW_SHIFT) - 1); | 400 | page = virt_to_page((void *)(addr ^ offset)); |
397 | void *addr = (void *) (pmdptr ^ offset); | 401 | return (void *)(addr_t)(page->index ? (page->index | offset) : 0UL); |
398 | struct page *page = virt_to_page(addr); | ||
399 | if (!list_empty(&page->lru)) | ||
400 | return (pmd_t *) ((unsigned long) page->lru.next | | ||
401 | offset); | ||
402 | } | ||
403 | return NULL; | ||
404 | } | 402 | } |
405 | 403 | ||
406 | static inline pgd_t *get_shadow_pgd(pgd_t *pgdp) | 404 | static inline void *get_shadow_table(void *table) |
407 | { | 405 | { |
408 | unsigned long pgdptr = (unsigned long) (pgdp); | 406 | unsigned long addr, offset; |
407 | struct page *page; | ||
409 | 408 | ||
410 | if (s390_noexec) { | 409 | addr = (unsigned long) table; |
411 | unsigned long offset = pgdptr & | 410 | offset = addr & ((PAGE_SIZE << PxD_SHADOW_SHIFT) - 1); |
412 | ((PAGE_SIZE << PGD_SHADOW_SHIFT) - 1); | 411 | page = virt_to_page((void *)(addr ^ offset)); |
413 | void *addr = (void *) (pgdptr ^ offset); | 412 | return (void *)(addr_t)(page->index ? (page->index | offset) : 0UL); |
414 | struct page *page = virt_to_page(addr); | ||
415 | if (!list_empty(&page->lru)) | ||
416 | return (pgd_t *) ((unsigned long) page->lru.next | | ||
417 | offset); | ||
418 | } | ||
419 | return NULL; | ||
420 | } | 413 | } |
421 | 414 | ||
422 | /* | 415 | /* |
@@ -424,7 +417,8 @@ static inline pgd_t *get_shadow_pgd(pgd_t *pgdp) | |||
424 | * within a page table are directly modified. Thus, the following | 417 | * within a page table are directly modified. Thus, the following |
425 | * hook is made available. | 418 | * hook is made available. |
426 | */ | 419 | */ |
427 | static inline void set_pte(pte_t *pteptr, pte_t pteval) | 420 | static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, |
421 | pte_t *pteptr, pte_t pteval) | ||
428 | { | 422 | { |
429 | pte_t *shadow_pte = get_shadow_pte(pteptr); | 423 | pte_t *shadow_pte = get_shadow_pte(pteptr); |
430 | 424 | ||
@@ -437,7 +431,6 @@ static inline void set_pte(pte_t *pteptr, pte_t pteval) | |||
437 | pte_val(*shadow_pte) = _PAGE_TYPE_EMPTY; | 431 | pte_val(*shadow_pte) = _PAGE_TYPE_EMPTY; |
438 | } | 432 | } |
439 | } | 433 | } |
440 | #define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval) | ||
441 | 434 | ||
442 | /* | 435 | /* |
443 | * pgd/pmd/pte query functions | 436 | * pgd/pmd/pte query functions |
@@ -448,47 +441,50 @@ static inline int pgd_present(pgd_t pgd) { return 1; } | |||
448 | static inline int pgd_none(pgd_t pgd) { return 0; } | 441 | static inline int pgd_none(pgd_t pgd) { return 0; } |
449 | static inline int pgd_bad(pgd_t pgd) { return 0; } | 442 | static inline int pgd_bad(pgd_t pgd) { return 0; } |
450 | 443 | ||
451 | static inline int pmd_present(pmd_t pmd) { return pmd_val(pmd) & _SEG_PRESENT; } | 444 | static inline int pud_present(pud_t pud) { return 1; } |
452 | static inline int pmd_none(pmd_t pmd) { return pmd_val(pmd) & _PAGE_TABLE_INV; } | 445 | static inline int pud_none(pud_t pud) { return 0; } |
453 | static inline int pmd_bad(pmd_t pmd) | 446 | static inline int pud_bad(pud_t pud) { return 0; } |
454 | { | ||
455 | return (pmd_val(pmd) & (~PAGE_MASK & ~_PAGE_TABLE_INV)) != _PAGE_TABLE; | ||
456 | } | ||
457 | 447 | ||
458 | #else /* __s390x__ */ | 448 | #else /* __s390x__ */ |
459 | 449 | ||
460 | static inline int pgd_present(pgd_t pgd) | 450 | static inline int pgd_present(pgd_t pgd) { return 1; } |
451 | static inline int pgd_none(pgd_t pgd) { return 0; } | ||
452 | static inline int pgd_bad(pgd_t pgd) { return 0; } | ||
453 | |||
454 | static inline int pud_present(pud_t pud) | ||
461 | { | 455 | { |
462 | return (pgd_val(pgd) & ~PAGE_MASK) == _PGD_ENTRY; | 456 | return pud_val(pud) & _REGION_ENTRY_ORIGIN; |
463 | } | 457 | } |
464 | 458 | ||
465 | static inline int pgd_none(pgd_t pgd) | 459 | static inline int pud_none(pud_t pud) |
466 | { | 460 | { |
467 | return pgd_val(pgd) & _PGD_ENTRY_INV; | 461 | return pud_val(pud) & _REGION_ENTRY_INV; |
468 | } | 462 | } |
469 | 463 | ||
470 | static inline int pgd_bad(pgd_t pgd) | 464 | static inline int pud_bad(pud_t pud) |
471 | { | 465 | { |
472 | return (pgd_val(pgd) & (~PAGE_MASK & ~_PGD_ENTRY_INV)) != _PGD_ENTRY; | 466 | unsigned long mask = ~_REGION_ENTRY_ORIGIN & ~_REGION_ENTRY_INV; |
467 | return (pud_val(pud) & mask) != _REGION3_ENTRY; | ||
473 | } | 468 | } |
474 | 469 | ||
470 | #endif /* __s390x__ */ | ||
471 | |||
475 | static inline int pmd_present(pmd_t pmd) | 472 | static inline int pmd_present(pmd_t pmd) |
476 | { | 473 | { |
477 | return (pmd_val(pmd) & ~PAGE_MASK) == _PMD_ENTRY; | 474 | return pmd_val(pmd) & _SEGMENT_ENTRY_ORIGIN; |
478 | } | 475 | } |
479 | 476 | ||
480 | static inline int pmd_none(pmd_t pmd) | 477 | static inline int pmd_none(pmd_t pmd) |
481 | { | 478 | { |
482 | return pmd_val(pmd) & _PMD_ENTRY_INV; | 479 | return pmd_val(pmd) & _SEGMENT_ENTRY_INV; |
483 | } | 480 | } |
484 | 481 | ||
485 | static inline int pmd_bad(pmd_t pmd) | 482 | static inline int pmd_bad(pmd_t pmd) |
486 | { | 483 | { |
487 | return (pmd_val(pmd) & (~PAGE_MASK & ~_PMD_ENTRY_INV)) != _PMD_ENTRY; | 484 | unsigned long mask = ~_SEGMENT_ENTRY_ORIGIN & ~_SEGMENT_ENTRY_INV; |
485 | return (pmd_val(pmd) & mask) != _SEGMENT_ENTRY; | ||
488 | } | 486 | } |
489 | 487 | ||
490 | #endif /* __s390x__ */ | ||
491 | |||
492 | static inline int pte_none(pte_t pte) | 488 | static inline int pte_none(pte_t pte) |
493 | { | 489 | { |
494 | return (pte_val(pte) & _PAGE_INVALID) && !(pte_val(pte) & _PAGE_SWT); | 490 | return (pte_val(pte) & _PAGE_INVALID) && !(pte_val(pte) & _PAGE_SWT); |
@@ -508,7 +504,8 @@ static inline int pte_file(pte_t pte) | |||
508 | return (pte_val(pte) & mask) == _PAGE_TYPE_FILE; | 504 | return (pte_val(pte) & mask) == _PAGE_TYPE_FILE; |
509 | } | 505 | } |
510 | 506 | ||
511 | #define pte_same(a,b) (pte_val(a) == pte_val(b)) | 507 | #define __HAVE_ARCH_PTE_SAME |
508 | #define pte_same(a,b) (pte_val(a) == pte_val(b)) | ||
512 | 509 | ||
513 | /* | 510 | /* |
514 | * query functions pte_write/pte_dirty/pte_young only work if | 511 | * query functions pte_write/pte_dirty/pte_young only work if |
@@ -543,58 +540,52 @@ static inline int pte_young(pte_t pte) | |||
543 | 540 | ||
544 | #ifndef __s390x__ | 541 | #ifndef __s390x__ |
545 | 542 | ||
546 | static inline void pgd_clear(pgd_t * pgdp) { } | 543 | #define pgd_clear(pgd) do { } while (0) |
544 | #define pud_clear(pud) do { } while (0) | ||
547 | 545 | ||
548 | static inline void pmd_clear_kernel(pmd_t * pmdp) | 546 | static inline void pmd_clear_kernel(pmd_t * pmdp) |
549 | { | 547 | { |
550 | pmd_val(pmdp[0]) = _PAGE_TABLE_INV; | 548 | pmd_val(pmdp[0]) = _SEGMENT_ENTRY_EMPTY; |
551 | pmd_val(pmdp[1]) = _PAGE_TABLE_INV; | 549 | pmd_val(pmdp[1]) = _SEGMENT_ENTRY_EMPTY; |
552 | pmd_val(pmdp[2]) = _PAGE_TABLE_INV; | 550 | pmd_val(pmdp[2]) = _SEGMENT_ENTRY_EMPTY; |
553 | pmd_val(pmdp[3]) = _PAGE_TABLE_INV; | 551 | pmd_val(pmdp[3]) = _SEGMENT_ENTRY_EMPTY; |
554 | } | ||
555 | |||
556 | static inline void pmd_clear(pmd_t * pmdp) | ||
557 | { | ||
558 | pmd_t *shadow_pmd = get_shadow_pmd(pmdp); | ||
559 | |||
560 | pmd_clear_kernel(pmdp); | ||
561 | if (shadow_pmd) | ||
562 | pmd_clear_kernel(shadow_pmd); | ||
563 | } | 552 | } |
564 | 553 | ||
565 | #else /* __s390x__ */ | 554 | #else /* __s390x__ */ |
566 | 555 | ||
567 | static inline void pgd_clear_kernel(pgd_t * pgdp) | 556 | #define pgd_clear(pgd) do { } while (0) |
557 | |||
558 | static inline void pud_clear_kernel(pud_t *pud) | ||
568 | { | 559 | { |
569 | pgd_val(*pgdp) = _PGD_ENTRY_INV | _PGD_ENTRY; | 560 | pud_val(*pud) = _REGION3_ENTRY_EMPTY; |
570 | } | 561 | } |
571 | 562 | ||
572 | static inline void pgd_clear(pgd_t * pgdp) | 563 | static inline void pud_clear(pud_t * pud) |
573 | { | 564 | { |
574 | pgd_t *shadow_pgd = get_shadow_pgd(pgdp); | 565 | pud_t *shadow = get_shadow_table(pud); |
575 | 566 | ||
576 | pgd_clear_kernel(pgdp); | 567 | pud_clear_kernel(pud); |
577 | if (shadow_pgd) | 568 | if (shadow) |
578 | pgd_clear_kernel(shadow_pgd); | 569 | pud_clear_kernel(shadow); |
579 | } | 570 | } |
580 | 571 | ||
581 | static inline void pmd_clear_kernel(pmd_t * pmdp) | 572 | static inline void pmd_clear_kernel(pmd_t * pmdp) |
582 | { | 573 | { |
583 | pmd_val(*pmdp) = _PMD_ENTRY_INV | _PMD_ENTRY; | 574 | pmd_val(*pmdp) = _SEGMENT_ENTRY_EMPTY; |
584 | pmd_val1(*pmdp) = _PMD_ENTRY_INV | _PMD_ENTRY; | 575 | pmd_val1(*pmdp) = _SEGMENT_ENTRY_EMPTY; |
585 | } | 576 | } |
586 | 577 | ||
578 | #endif /* __s390x__ */ | ||
579 | |||
587 | static inline void pmd_clear(pmd_t * pmdp) | 580 | static inline void pmd_clear(pmd_t * pmdp) |
588 | { | 581 | { |
589 | pmd_t *shadow_pmd = get_shadow_pmd(pmdp); | 582 | pmd_t *shadow_pmd = get_shadow_table(pmdp); |
590 | 583 | ||
591 | pmd_clear_kernel(pmdp); | 584 | pmd_clear_kernel(pmdp); |
592 | if (shadow_pmd) | 585 | if (shadow_pmd) |
593 | pmd_clear_kernel(shadow_pmd); | 586 | pmd_clear_kernel(shadow_pmd); |
594 | } | 587 | } |
595 | 588 | ||
596 | #endif /* __s390x__ */ | ||
597 | |||
598 | static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) | 589 | static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) |
599 | { | 590 | { |
600 | pte_t *shadow_pte = get_shadow_pte(ptep); | 591 | pte_t *shadow_pte = get_shadow_pte(ptep); |
@@ -663,24 +654,19 @@ static inline pte_t pte_mkyoung(pte_t pte) | |||
663 | return pte; | 654 | return pte; |
664 | } | 655 | } |
665 | 656 | ||
666 | static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep) | 657 | #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG |
658 | static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, | ||
659 | unsigned long addr, pte_t *ptep) | ||
667 | { | 660 | { |
668 | return 0; | 661 | return 0; |
669 | } | 662 | } |
670 | 663 | ||
671 | static inline int | 664 | #define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH |
672 | ptep_clear_flush_young(struct vm_area_struct *vma, | 665 | static inline int ptep_clear_flush_young(struct vm_area_struct *vma, |
673 | unsigned long address, pte_t *ptep) | 666 | unsigned long address, pte_t *ptep) |
674 | { | 667 | { |
675 | /* No need to flush TLB; bits are in storage key */ | 668 | /* No need to flush TLB; bits are in storage key */ |
676 | return ptep_test_and_clear_young(vma, address, ptep); | 669 | return 0; |
677 | } | ||
678 | |||
679 | static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) | ||
680 | { | ||
681 | pte_t pte = *ptep; | ||
682 | pte_clear(mm, addr, ptep); | ||
683 | return pte; | ||
684 | } | 670 | } |
685 | 671 | ||
686 | static inline void __ptep_ipte(unsigned long address, pte_t *ptep) | 672 | static inline void __ptep_ipte(unsigned long address, pte_t *ptep) |
@@ -709,6 +695,32 @@ static inline void ptep_invalidate(unsigned long address, pte_t *ptep) | |||
709 | __ptep_ipte(address, ptep); | 695 | __ptep_ipte(address, ptep); |
710 | } | 696 | } |
711 | 697 | ||
698 | /* | ||
699 | * This is hard to understand. ptep_get_and_clear and ptep_clear_flush | ||
700 | * both clear the TLB for the unmapped pte. The reason is that | ||
701 | * ptep_get_and_clear is used in common code (e.g. change_pte_range) | ||
702 | * to modify an active pte. The sequence is | ||
703 | * 1) ptep_get_and_clear | ||
704 | * 2) set_pte_at | ||
705 | * 3) flush_tlb_range | ||
706 | * On s390 the tlb needs to get flushed with the modification of the pte | ||
707 | * if the pte is active. The only way how this can be implemented is to | ||
708 | * have ptep_get_and_clear do the tlb flush. In exchange flush_tlb_range | ||
709 | * is a nop. | ||
710 | */ | ||
711 | #define __HAVE_ARCH_PTEP_GET_AND_CLEAR | ||
712 | #define ptep_get_and_clear(__mm, __address, __ptep) \ | ||
713 | ({ \ | ||
714 | pte_t __pte = *(__ptep); \ | ||
715 | if (atomic_read(&(__mm)->mm_users) > 1 || \ | ||
716 | (__mm) != current->active_mm) \ | ||
717 | ptep_invalidate(__address, __ptep); \ | ||
718 | else \ | ||
719 | pte_clear((__mm), (__address), (__ptep)); \ | ||
720 | __pte; \ | ||
721 | }) | ||
722 | |||
723 | #define __HAVE_ARCH_PTEP_CLEAR_FLUSH | ||
712 | static inline pte_t ptep_clear_flush(struct vm_area_struct *vma, | 724 | static inline pte_t ptep_clear_flush(struct vm_area_struct *vma, |
713 | unsigned long address, pte_t *ptep) | 725 | unsigned long address, pte_t *ptep) |
714 | { | 726 | { |
@@ -717,12 +729,40 @@ static inline pte_t ptep_clear_flush(struct vm_area_struct *vma, | |||
717 | return pte; | 729 | return pte; |
718 | } | 730 | } |
719 | 731 | ||
720 | static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep) | 732 | /* |
733 | * The batched pte unmap code uses ptep_get_and_clear_full to clear the | ||
734 | * ptes. Here an optimization is possible. tlb_gather_mmu flushes all | ||
735 | * tlbs of an mm if it can guarantee that the ptes of the mm_struct | ||
736 | * cannot be accessed while the batched unmap is running. In this case | ||
737 | * full==1 and a simple pte_clear is enough. See tlb.h. | ||
738 | */ | ||
739 | #define __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL | ||
740 | static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, | ||
741 | unsigned long addr, | ||
742 | pte_t *ptep, int full) | ||
721 | { | 743 | { |
722 | pte_t old_pte = *ptep; | 744 | pte_t pte = *ptep; |
723 | set_pte_at(mm, addr, ptep, pte_wrprotect(old_pte)); | 745 | |
746 | if (full) | ||
747 | pte_clear(mm, addr, ptep); | ||
748 | else | ||
749 | ptep_invalidate(addr, ptep); | ||
750 | return pte; | ||
724 | } | 751 | } |
725 | 752 | ||
753 | #define __HAVE_ARCH_PTEP_SET_WRPROTECT | ||
754 | #define ptep_set_wrprotect(__mm, __addr, __ptep) \ | ||
755 | ({ \ | ||
756 | pte_t __pte = *(__ptep); \ | ||
757 | if (pte_write(__pte)) { \ | ||
758 | if (atomic_read(&(__mm)->mm_users) > 1 || \ | ||
759 | (__mm) != current->active_mm) \ | ||
760 | ptep_invalidate(__addr, __ptep); \ | ||
761 | set_pte_at(__mm, __addr, __ptep, pte_wrprotect(__pte)); \ | ||
762 | } \ | ||
763 | }) | ||
764 | |||
765 | #define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS | ||
726 | #define ptep_set_access_flags(__vma, __addr, __ptep, __entry, __dirty) \ | 766 | #define ptep_set_access_flags(__vma, __addr, __ptep, __entry, __dirty) \ |
727 | ({ \ | 767 | ({ \ |
728 | int __changed = !pte_same(*(__ptep), __entry); \ | 768 | int __changed = !pte_same(*(__ptep), __entry); \ |
@@ -740,11 +780,13 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, | |||
740 | * should therefore only be called if it is not mapped in any | 780 | * should therefore only be called if it is not mapped in any |
741 | * address space. | 781 | * address space. |
742 | */ | 782 | */ |
783 | #define __HAVE_ARCH_PAGE_TEST_DIRTY | ||
743 | static inline int page_test_dirty(struct page *page) | 784 | static inline int page_test_dirty(struct page *page) |
744 | { | 785 | { |
745 | return (page_get_storage_key(page_to_phys(page)) & _PAGE_CHANGED) != 0; | 786 | return (page_get_storage_key(page_to_phys(page)) & _PAGE_CHANGED) != 0; |
746 | } | 787 | } |
747 | 788 | ||
789 | #define __HAVE_ARCH_PAGE_CLEAR_DIRTY | ||
748 | static inline void page_clear_dirty(struct page *page) | 790 | static inline void page_clear_dirty(struct page *page) |
749 | { | 791 | { |
750 | page_set_storage_key(page_to_phys(page), PAGE_DEFAULT_KEY); | 792 | page_set_storage_key(page_to_phys(page), PAGE_DEFAULT_KEY); |
@@ -753,6 +795,7 @@ static inline void page_clear_dirty(struct page *page) | |||
753 | /* | 795 | /* |
754 | * Test and clear referenced bit in storage key. | 796 | * Test and clear referenced bit in storage key. |
755 | */ | 797 | */ |
798 | #define __HAVE_ARCH_PAGE_TEST_AND_CLEAR_YOUNG | ||
756 | static inline int page_test_and_clear_young(struct page *page) | 799 | static inline int page_test_and_clear_young(struct page *page) |
757 | { | 800 | { |
758 | unsigned long physpage = page_to_phys(page); | 801 | unsigned long physpage = page_to_phys(page); |
@@ -784,63 +827,48 @@ static inline pte_t mk_pte(struct page *page, pgprot_t pgprot) | |||
784 | return mk_pte_phys(physpage, pgprot); | 827 | return mk_pte_phys(physpage, pgprot); |
785 | } | 828 | } |
786 | 829 | ||
787 | static inline pte_t pfn_pte(unsigned long pfn, pgprot_t pgprot) | 830 | #define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) |
788 | { | 831 | #define pud_index(address) (((address) >> PUD_SHIFT) & (PTRS_PER_PUD-1)) |
789 | unsigned long physpage = __pa((pfn) << PAGE_SHIFT); | 832 | #define pmd_index(address) (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1)) |
790 | 833 | #define pte_index(address) (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE-1)) | |
791 | return mk_pte_phys(physpage, pgprot); | ||
792 | } | ||
793 | |||
794 | #ifdef __s390x__ | ||
795 | |||
796 | static inline pmd_t pfn_pmd(unsigned long pfn, pgprot_t pgprot) | ||
797 | { | ||
798 | unsigned long physpage = __pa((pfn) << PAGE_SHIFT); | ||
799 | |||
800 | return __pmd(physpage + pgprot_val(pgprot)); | ||
801 | } | ||
802 | |||
803 | #endif /* __s390x__ */ | ||
804 | |||
805 | #define pte_pfn(x) (pte_val(x) >> PAGE_SHIFT) | ||
806 | #define pte_page(x) pfn_to_page(pte_pfn(x)) | ||
807 | 834 | ||
808 | #define pmd_page_vaddr(pmd) (pmd_val(pmd) & PAGE_MASK) | 835 | #define pgd_offset(mm, address) ((mm)->pgd + pgd_index(address)) |
836 | #define pgd_offset_k(address) pgd_offset(&init_mm, address) | ||
809 | 837 | ||
810 | #define pmd_page(pmd) pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT) | 838 | #ifndef __s390x__ |
811 | 839 | ||
812 | #define pgd_page_vaddr(pgd) (pgd_val(pgd) & PAGE_MASK) | 840 | #define pmd_deref(pmd) (pmd_val(pmd) & _SEGMENT_ENTRY_ORIGIN) |
841 | #define pud_deref(pmd) ({ BUG(); 0UL; }) | ||
842 | #define pgd_deref(pmd) ({ BUG(); 0UL; }) | ||
813 | 843 | ||
814 | #define pgd_page(pgd) pfn_to_page(pgd_val(pgd) >> PAGE_SHIFT) | 844 | #define pud_offset(pgd, address) ((pud_t *) pgd) |
845 | #define pmd_offset(pud, address) ((pmd_t *) pud + pmd_index(address)) | ||
815 | 846 | ||
816 | /* to find an entry in a page-table-directory */ | 847 | #else /* __s390x__ */ |
817 | #define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) | ||
818 | #define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address)) | ||
819 | 848 | ||
820 | /* to find an entry in a kernel page-table-directory */ | 849 | #define pmd_deref(pmd) (pmd_val(pmd) & _SEGMENT_ENTRY_ORIGIN) |
821 | #define pgd_offset_k(address) pgd_offset(&init_mm, address) | 850 | #define pud_deref(pud) (pud_val(pud) & _REGION_ENTRY_ORIGIN) |
851 | #define pgd_deref(pgd) ({ BUG(); 0UL; }) | ||
822 | 852 | ||
823 | #ifndef __s390x__ | 853 | #define pud_offset(pgd, address) ((pud_t *) pgd) |
824 | 854 | ||
825 | /* Find an entry in the second-level page table.. */ | 855 | static inline pmd_t *pmd_offset(pud_t *pud, unsigned long address) |
826 | static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address) | ||
827 | { | 856 | { |
828 | return (pmd_t *) dir; | 857 | pmd_t *pmd = (pmd_t *) pud_deref(*pud); |
858 | return pmd + pmd_index(address); | ||
829 | } | 859 | } |
830 | 860 | ||
831 | #else /* __s390x__ */ | 861 | #endif /* __s390x__ */ |
832 | 862 | ||
833 | /* Find an entry in the second-level page table.. */ | 863 | #define pfn_pte(pfn,pgprot) mk_pte_phys(__pa((pfn) << PAGE_SHIFT),(pgprot)) |
834 | #define pmd_index(address) (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1)) | 864 | #define pte_pfn(x) (pte_val(x) >> PAGE_SHIFT) |
835 | #define pmd_offset(dir,addr) \ | 865 | #define pte_page(x) pfn_to_page(pte_pfn(x)) |
836 | ((pmd_t *) pgd_page_vaddr(*(dir)) + pmd_index(addr)) | ||
837 | 866 | ||
838 | #endif /* __s390x__ */ | 867 | #define pmd_page(pmd) pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT) |
839 | 868 | ||
840 | /* Find an entry in the third-level page table.. */ | 869 | /* Find an entry in the lowest level page table.. */ |
841 | #define pte_index(address) (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE-1)) | 870 | #define pte_offset(pmd, addr) ((pte_t *) pmd_deref(*(pmd)) + pte_index(addr)) |
842 | #define pte_offset_kernel(pmd, address) \ | 871 | #define pte_offset_kernel(pmd, address) pte_offset(pmd,address) |
843 | ((pte_t *) pmd_page_vaddr(*(pmd)) + pte_index(address)) | ||
844 | #define pte_offset_map(pmd, address) pte_offset_kernel(pmd, address) | 872 | #define pte_offset_map(pmd, address) pte_offset_kernel(pmd, address) |
845 | #define pte_offset_map_nested(pmd, address) pte_offset_kernel(pmd, address) | 873 | #define pte_offset_map_nested(pmd, address) pte_offset_kernel(pmd, address) |
846 | #define pte_unmap(pte) do { } while (0) | 874 | #define pte_unmap(pte) do { } while (0) |
@@ -930,17 +958,6 @@ extern int remove_shared_memory(unsigned long start, unsigned long size); | |||
930 | #define __HAVE_ARCH_MEMMAP_INIT | 958 | #define __HAVE_ARCH_MEMMAP_INIT |
931 | extern void memmap_init(unsigned long, int, unsigned long, unsigned long); | 959 | extern void memmap_init(unsigned long, int, unsigned long, unsigned long); |
932 | 960 | ||
933 | #define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS | ||
934 | #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG | ||
935 | #define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH | ||
936 | #define __HAVE_ARCH_PTEP_GET_AND_CLEAR | ||
937 | #define __HAVE_ARCH_PTEP_CLEAR_FLUSH | ||
938 | #define __HAVE_ARCH_PTEP_SET_WRPROTECT | ||
939 | #define __HAVE_ARCH_PTE_SAME | ||
940 | #define __HAVE_ARCH_PAGE_TEST_DIRTY | ||
941 | #define __HAVE_ARCH_PAGE_CLEAR_DIRTY | ||
942 | #define __HAVE_ARCH_PAGE_TEST_AND_CLEAR_YOUNG | ||
943 | #include <asm-generic/pgtable.h> | 961 | #include <asm-generic/pgtable.h> |
944 | 962 | ||
945 | #endif /* _S390_PAGE_H */ | 963 | #endif /* _S390_PAGE_H */ |
946 | |||