From 1ee92a1c79b4a44586490a52132d105972374223 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Sat, 9 Feb 2008 18:24:28 +0100 Subject: [S390] Wire up new timerfd syscalls. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- include/asm-s390/unistd.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/asm-s390/unistd.h b/include/asm-s390/unistd.h index f04acb2670a..583da807ea9 100644 --- a/include/asm-s390/unistd.h +++ b/include/asm-s390/unistd.h @@ -256,7 +256,10 @@ #define __NR_signalfd 316 #define __NR_timerfd 317 #define __NR_eventfd 318 -#define NR_syscalls 319 +#define __NR_timerfd_create 319 +#define __NR_timerfd_settime 320 +#define __NR_timerfd_gettime 321 +#define NR_syscalls 322 /* * There are some system calls that are not present on 64 bit, some -- cgit v1.2.3-18-g5258 From 6d88f827d7c3e73d11a62fdabccca001aece7295 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Sat, 9 Feb 2008 18:24:29 +0100 Subject: [S390] Fix __ffs_word_loop/__ffz_word_loop inlnie assembly. The black art of inline assemblies.. The new __ffs_word_loop/ __ffz_word_loop inline assemblies need an early clobber for the two input/output variables. Signed-off-by: Martin Schwidefsky --- include/asm-s390/bitops.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/asm-s390/bitops.h b/include/asm-s390/bitops.h index 882db054110..ab83c844d04 100644 --- a/include/asm-s390/bitops.h +++ b/include/asm-s390/bitops.h @@ -472,7 +472,7 @@ static inline unsigned long __ffz_word_loop(const unsigned long *addr, " brct %1,0b\n" "1:\n" #endif - : "+a" (bytes), "+d" (size) + : "+&a" (bytes), "+&d" (size) : "d" (-1UL), "a" (addr), "m" (*(addrtype *) addr) : "cc" ); return bytes; @@ -507,7 +507,7 @@ static inline unsigned long __ffs_word_loop(const unsigned long *addr, " brct %1,0b\n" "1:\n" #endif - : "+a" (bytes), "+a" (size) + : "+&a" (bytes), "+&a" (size) : "d" (0UL), "a" (addr), "m" (*(addrtype *) addr) : "cc" ); return bytes; -- cgit v1.2.3-18-g5258 From 522d8dc08b16deb51c128d544ab1cb9c621c950e Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Sat, 9 Feb 2008 18:24:31 +0100 Subject: [S390] VMEM_MAX_PHYS overflow on 31 bit. With the new space saving spinlock_t and a non-debug configuration the struct page only has 32 bytes for 31 bit s390. The causes an overflow in the calculation of VMEM_MAX_PHYS which renders the kernel unbootable. Signed-off-by: Martin Schwidefsky --- include/asm-s390/pgtable.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/asm-s390/pgtable.h b/include/asm-s390/pgtable.h index 3f520754e71..65d33384915 100644 --- a/include/asm-s390/pgtable.h +++ b/include/asm-s390/pgtable.h @@ -127,8 +127,9 @@ extern char empty_zero_page[PAGE_SIZE]; * mapping. This needs to be calculated at compile time since the size of the * VMEM_MAP is static but the size of struct page can change. */ -#define VMEM_MAX_PHYS min(VMALLOC_START, ((VMEM_MAP_END - VMALLOC_END) / \ - sizeof(struct page) * PAGE_SIZE) & ~((16 << 20) - 1)) +#define VMEM_MAX_PAGES ((VMEM_MAP_END - VMALLOC_END) / sizeof(struct page)) +#define VMEM_MAX_PFN min(VMALLOC_START >> PAGE_SHIFT, VMEM_MAX_PAGES) +#define VMEM_MAX_PHYS ((VMEM_MAX_PFN << PAGE_SHIFT) & ~((16 << 20) - 1)) #define VMEM_MAP ((struct page *) VMALLOC_END) /* -- cgit v1.2.3-18-g5258 From 0c1f1dcd8c7792aeff6ef62e9508b0041928ab87 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Sat, 9 Feb 2008 18:24:34 +0100 Subject: [S390] Remove a.out header file. Signed-off-by: Martin Schwidefsky --- include/asm-s390/a.out.h | 32 -------------------------------- 1 file changed, 32 deletions(-) delete mode 100644 include/asm-s390/a.out.h (limited to 'include') diff --git a/include/asm-s390/a.out.h b/include/asm-s390/a.out.h deleted file mode 100644 index 8d6bd9c2952..00000000000 --- a/include/asm-s390/a.out.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * include/asm-s390/a.out.h - * - * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * - * Derived from "include/asm-i386/a.out.h" - * Copyright (C) 1992, Linus Torvalds - * - * I don't think we'll ever need a.out ... - */ - -#ifndef __S390_A_OUT_H__ -#define __S390_A_OUT_H__ - -struct exec -{ - unsigned long a_info; /* Use macros N_MAGIC, etc for access */ - unsigned a_text; /* length of text, in bytes */ - unsigned a_data; /* length of data, in bytes */ - unsigned a_bss; /* length of uninitialized data area for file, in bytes */ - unsigned a_syms; /* length of symbol table data in file, in bytes */ - unsigned a_entry; /* start address */ - unsigned a_trsize; /* length of relocation info for text, in bytes */ - unsigned a_drsize; /* length of relocation info for data, in bytes */ -}; - -#define N_TRSIZE(a) ((a).a_trsize) -#define N_DRSIZE(a) ((a).a_drsize) -#define N_SYMSIZE(a) ((a).a_syms) - -#endif /* __A_OUT_GNU_H__ */ -- cgit v1.2.3-18-g5258 From 146e4b3c8b92071b18f0b2e6f47165bad4f9e825 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Sat, 9 Feb 2008 18:24:35 +0100 Subject: [S390] 1K/2K page table pages. This patch implements 1K/2K page table pages for s390. Signed-off-by: Martin Schwidefsky --- include/asm-s390/elf.h | 13 +++++ include/asm-s390/mmu.h | 8 +++- include/asm-s390/mmu_context.h | 14 ++++-- include/asm-s390/page.h | 36 ++------------ include/asm-s390/pgalloc.h | 79 ++++++++++++++----------------- include/asm-s390/pgtable.h | 105 ++++++++++++++--------------------------- include/asm-s390/tlb.h | 6 +-- include/asm-s390/tlbflush.h | 11 +++-- 8 files changed, 114 insertions(+), 158 deletions(-) (limited to 'include') diff --git a/include/asm-s390/elf.h b/include/asm-s390/elf.h index b73a424d0f9..8181ca5b98f 100644 --- a/include/asm-s390/elf.h +++ b/include/asm-s390/elf.h @@ -115,6 +115,7 @@ typedef s390_regs elf_gregset_t; #include /* for task_struct */ #include /* for save_access_regs */ +#include /* * This is used to ensure we don't load something for the wrong architecture. @@ -214,4 +215,16 @@ do { \ } while (0) #endif /* __s390x__ */ +/* + * An executable for which elf_read_implies_exec() returns TRUE will + * have the READ_IMPLIES_EXEC personality flag set automatically. + */ +#define elf_read_implies_exec(ex, executable_stack) \ +({ \ + if (current->mm->context.noexec && \ + executable_stack != EXSTACK_DISABLE_X) \ + disable_noexec(current->mm, current); \ + current->mm->context.noexec == 0; \ +}) + #endif diff --git a/include/asm-s390/mmu.h b/include/asm-s390/mmu.h index ccd36d26615..13ec4215f43 100644 --- a/include/asm-s390/mmu.h +++ b/include/asm-s390/mmu.h @@ -1,7 +1,11 @@ #ifndef __MMU_H #define __MMU_H -/* Default "unsigned long" context */ -typedef unsigned long mm_context_t; +typedef struct { + struct list_head crst_list; + struct list_head pgtable_list; + unsigned long asce_bits; + int noexec; +} mm_context_t; #endif diff --git a/include/asm-s390/mmu_context.h b/include/asm-s390/mmu_context.h index a77d4ba3c8e..3eaac5efc63 100644 --- a/include/asm-s390/mmu_context.h +++ b/include/asm-s390/mmu_context.h @@ -10,15 +10,17 @@ #define __S390_MMU_CONTEXT_H #include +#include #include static inline int init_new_context(struct task_struct *tsk, struct mm_struct *mm) { - mm->context = _ASCE_TABLE_LENGTH | _ASCE_USER_BITS; + mm->context.asce_bits = _ASCE_TABLE_LENGTH | _ASCE_USER_BITS; #ifdef CONFIG_64BIT - mm->context |= _ASCE_TYPE_REGION3; + mm->context.asce_bits |= _ASCE_TYPE_REGION3; #endif + mm->context.noexec = s390_noexec; return 0; } @@ -32,11 +34,13 @@ static inline int init_new_context(struct task_struct *tsk, static inline void update_mm(struct mm_struct *mm, struct task_struct *tsk) { - S390_lowcore.user_asce = mm->context | __pa(mm->pgd); + pgd_t *pgd = mm->pgd; + + S390_lowcore.user_asce = mm->context.asce_bits | __pa(pgd); if (switch_amode) { /* Load primary space page table origin. */ - pgd_t *shadow_pgd = get_shadow_table(mm->pgd) ? : mm->pgd; - S390_lowcore.user_exec_asce = mm->context | __pa(shadow_pgd); + pgd = mm->context.noexec ? get_shadow_table(pgd) : pgd; + S390_lowcore.user_exec_asce = mm->context.asce_bits | __pa(pgd); asm volatile(LCTL_OPCODE" 1,1,%0\n" : : "m" (S390_lowcore.user_exec_asce) ); } else diff --git a/include/asm-s390/page.h b/include/asm-s390/page.h index 7f29a981f48..fe7f92b6ae6 100644 --- a/include/asm-s390/page.h +++ b/include/asm-s390/page.h @@ -74,43 +74,17 @@ static inline void copy_page(void *to, void *from) typedef struct { unsigned long pgprot; } pgprot_t; typedef struct { unsigned long pte; } pte_t; - -#define pte_val(x) ((x).pte) -#define pgprot_val(x) ((x).pgprot) - -#ifndef __s390x__ - typedef struct { unsigned long pmd; } pmd_t; typedef struct { unsigned long pud; } pud_t; -typedef struct { - unsigned long pgd0; - unsigned long pgd1; - unsigned long pgd2; - unsigned long pgd3; - } pgd_t; - -#define pmd_val(x) ((x).pmd) -#define pud_val(x) ((x).pud) -#define pgd_val(x) ((x).pgd0) - -#else /* __s390x__ */ - -typedef struct { - unsigned long pmd0; - unsigned long pmd1; - } pmd_t; -typedef struct { unsigned long pud; } pud_t; typedef struct { unsigned long pgd; } pgd_t; +typedef pte_t *pgtable_t; -#define pmd_val(x) ((x).pmd0) -#define pmd_val1(x) ((x).pmd1) +#define pgprot_val(x) ((x).pgprot) +#define pte_val(x) ((x).pte) +#define pmd_val(x) ((x).pmd) #define pud_val(x) ((x).pud) #define pgd_val(x) ((x).pgd) -#endif /* __s390x__ */ - -typedef struct page *pgtable_t; - #define __pte(x) ((pte_t) { (x) } ) #define __pmd(x) ((pmd_t) { (x) } ) #define __pgd(x) ((pgd_t) { (x) } ) @@ -167,7 +141,7 @@ static inline int pfn_valid(unsigned long pfn) #define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) -#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \ +#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | \ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) #include diff --git a/include/asm-s390/pgalloc.h b/include/asm-s390/pgalloc.h index 900d44807e1..af4aee856df 100644 --- a/include/asm-s390/pgalloc.h +++ b/include/asm-s390/pgalloc.h @@ -20,10 +20,11 @@ #define check_pgt_cache() do {} while (0) unsigned long *crst_table_alloc(struct mm_struct *, int); -void crst_table_free(unsigned long *); +void crst_table_free(struct mm_struct *, unsigned long *); -unsigned long *page_table_alloc(int); -void page_table_free(unsigned long *); +unsigned long *page_table_alloc(struct mm_struct *); +void page_table_free(struct mm_struct *, unsigned long *); +void disable_noexec(struct mm_struct *, struct task_struct *); static inline void clear_table(unsigned long *s, unsigned long val, size_t n) { @@ -80,12 +81,12 @@ static inline unsigned long pgd_entry_type(struct mm_struct *mm) static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr) { - unsigned long *crst = crst_table_alloc(mm, s390_noexec); - if (crst) - crst_table_init(crst, _SEGMENT_ENTRY_EMPTY); - return (pmd_t *) crst; + unsigned long *table = crst_table_alloc(mm, mm->context.noexec); + if (table) + crst_table_init(table, _SEGMENT_ENTRY_EMPTY); + return (pmd_t *) table; } -#define pmd_free(mm, pmd) crst_table_free((unsigned long *)pmd) +#define pmd_free(mm, pmd) crst_table_free(mm, (unsigned long *) pmd) #define pgd_populate(mm, pgd, pud) BUG() #define pgd_populate_kernel(mm, pgd, pud) BUG() @@ -98,63 +99,55 @@ static inline void pud_populate_kernel(struct mm_struct *mm, static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) { - pud_t *shadow_pud = get_shadow_table(pud); - pmd_t *shadow_pmd = get_shadow_table(pmd); - - if (shadow_pud && shadow_pmd) - pud_populate_kernel(mm, shadow_pud, shadow_pmd); pud_populate_kernel(mm, pud, pmd); + if (mm->context.noexec) { + pud = get_shadow_table(pud); + pmd = get_shadow_table(pmd); + pud_populate_kernel(mm, pud, pmd); + } } #endif /* __s390x__ */ static inline pgd_t *pgd_alloc(struct mm_struct *mm) { - unsigned long *crst = crst_table_alloc(mm, s390_noexec); + unsigned long *crst; + + INIT_LIST_HEAD(&mm->context.crst_list); + INIT_LIST_HEAD(&mm->context.pgtable_list); + crst = crst_table_alloc(mm, s390_noexec); if (crst) crst_table_init(crst, pgd_entry_type(mm)); return (pgd_t *) crst; } -#define pgd_free(mm, pgd) crst_table_free((unsigned long *) pgd) +#define pgd_free(mm, pgd) crst_table_free(mm, (unsigned long *) pgd) -static inline void -pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, pte_t *pte) +static inline void pmd_populate_kernel(struct mm_struct *mm, + pmd_t *pmd, pte_t *pte) { -#ifndef __s390x__ - pmd_val(pmd[0]) = _SEGMENT_ENTRY + __pa(pte); - pmd_val(pmd[1]) = _SEGMENT_ENTRY + __pa(pte+256); - pmd_val(pmd[2]) = _SEGMENT_ENTRY + __pa(pte+512); - pmd_val(pmd[3]) = _SEGMENT_ENTRY + __pa(pte+768); -#else /* __s390x__ */ pmd_val(*pmd) = _SEGMENT_ENTRY + __pa(pte); - pmd_val1(*pmd) = _SEGMENT_ENTRY + __pa(pte+256); -#endif /* __s390x__ */ } -static inline void -pmd_populate(struct mm_struct *mm, pmd_t *pmd, pgtable_t page) +static inline void pmd_populate(struct mm_struct *mm, + pmd_t *pmd, pgtable_t pte) { - pte_t *pte = (pte_t *)page_to_phys(page); - pmd_t *shadow_pmd = get_shadow_table(pmd); - pte_t *shadow_pte = get_shadow_pte(pte); - pmd_populate_kernel(mm, pmd, pte); - if (shadow_pmd && shadow_pte) - pmd_populate_kernel(mm, shadow_pmd, shadow_pte); + if (mm->context.noexec) { + pmd = get_shadow_table(pmd); + pmd_populate_kernel(mm, pmd, pte + PTRS_PER_PTE); + } } -#define pmd_pgtable(pmd) pmd_page(pmd) + +#define pmd_pgtable(pmd) \ + (pgtable_t)(pmd_val(pmd) & -sizeof(pte_t)*PTRS_PER_PTE) /* * page table entry allocation/free routines. */ -#define pte_alloc_one_kernel(mm, vmaddr) \ - ((pte_t *) page_table_alloc(s390_noexec)) -#define pte_alloc_one(mm, vmaddr) \ - virt_to_page(page_table_alloc(s390_noexec)) - -#define pte_free_kernel(mm, pte) \ - page_table_free((unsigned long *) pte) -#define pte_free(mm, pte) \ - page_table_free((unsigned long *) page_to_phys((struct page *) pte)) +#define pte_alloc_one_kernel(mm, vmaddr) ((pte_t *) page_table_alloc(mm)) +#define pte_alloc_one(mm, vmaddr) ((pte_t *) page_table_alloc(mm)) + +#define pte_free_kernel(mm, pte) page_table_free(mm, (unsigned long *) pte) +#define pte_free(mm, pte) page_table_free(mm, (unsigned long *) pte) #endif /* _S390_PGALLOC_H */ diff --git a/include/asm-s390/pgtable.h b/include/asm-s390/pgtable.h index 65d33384915..4fc93771148 100644 --- a/include/asm-s390/pgtable.h +++ b/include/asm-s390/pgtable.h @@ -57,11 +57,11 @@ extern char empty_zero_page[PAGE_SIZE]; * PGDIR_SHIFT determines what a third-level page table entry can map */ #ifndef __s390x__ -# define PMD_SHIFT 22 -# define PUD_SHIFT 22 -# define PGDIR_SHIFT 22 +# define PMD_SHIFT 20 +# define PUD_SHIFT 20 +# define PGDIR_SHIFT 20 #else /* __s390x__ */ -# define PMD_SHIFT 21 +# define PMD_SHIFT 20 # define PUD_SHIFT 31 # define PGDIR_SHIFT 31 #endif /* __s390x__ */ @@ -79,17 +79,14 @@ extern char empty_zero_page[PAGE_SIZE]; * for S390 segment-table entries are combined to one PGD * that leads to 1024 pte per pgd */ +#define PTRS_PER_PTE 256 #ifndef __s390x__ -# define PTRS_PER_PTE 1024 -# define PTRS_PER_PMD 1 -# define PTRS_PER_PUD 1 -# define PTRS_PER_PGD 512 +#define PTRS_PER_PMD 1 #else /* __s390x__ */ -# define PTRS_PER_PTE 512 -# define PTRS_PER_PMD 1024 -# define PTRS_PER_PUD 1 -# define PTRS_PER_PGD 2048 +#define PTRS_PER_PMD 2048 #endif /* __s390x__ */ +#define PTRS_PER_PUD 1 +#define PTRS_PER_PGD 2048 #define FIRST_USER_ADDRESS 0 @@ -376,24 +373,6 @@ extern char empty_zero_page[PAGE_SIZE]; # define PxD_SHADOW_SHIFT 2 #endif /* __s390x__ */ -static inline struct page *get_shadow_page(struct page *page) -{ - if (s390_noexec && page->index) - return virt_to_page((void *)(addr_t) page->index); - return NULL; -} - -static inline void *get_shadow_pte(void *table) -{ - unsigned long addr, offset; - struct page *page; - - addr = (unsigned long) table; - offset = addr & (PAGE_SIZE - 1); - page = virt_to_page((void *)(addr ^ offset)); - return (void *)(addr_t)(page->index ? (page->index | offset) : 0UL); -} - static inline void *get_shadow_table(void *table) { unsigned long addr, offset; @@ -411,17 +390,16 @@ static inline void *get_shadow_table(void *table) * hook is made available. */ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, - pte_t *pteptr, pte_t pteval) + pte_t *ptep, pte_t entry) { - pte_t *shadow_pte = get_shadow_pte(pteptr); - - *pteptr = pteval; - if (shadow_pte) { - if (!(pte_val(pteval) & _PAGE_INVALID) && - (pte_val(pteval) & _PAGE_SWX)) - pte_val(*shadow_pte) = pte_val(pteval) | _PAGE_RO; + *ptep = entry; + if (mm->context.noexec) { + if (!(pte_val(entry) & _PAGE_INVALID) && + (pte_val(entry) & _PAGE_SWX)) + pte_val(entry) |= _PAGE_RO; else - pte_val(*shadow_pte) = _PAGE_TYPE_EMPTY; + pte_val(entry) = _PAGE_TYPE_EMPTY; + ptep[PTRS_PER_PTE] = entry; } } @@ -536,14 +514,6 @@ static inline int pte_young(pte_t pte) #define pgd_clear(pgd) do { } while (0) #define pud_clear(pud) do { } while (0) -static inline void pmd_clear_kernel(pmd_t * pmdp) -{ - pmd_val(pmdp[0]) = _SEGMENT_ENTRY_EMPTY; - pmd_val(pmdp[1]) = _SEGMENT_ENTRY_EMPTY; - pmd_val(pmdp[2]) = _SEGMENT_ENTRY_EMPTY; - pmd_val(pmdp[3]) = _SEGMENT_ENTRY_EMPTY; -} - #else /* __s390x__ */ #define pgd_clear(pgd) do { } while (0) @@ -562,30 +532,27 @@ static inline void pud_clear(pud_t * pud) pud_clear_kernel(shadow); } +#endif /* __s390x__ */ + static inline void pmd_clear_kernel(pmd_t * pmdp) { pmd_val(*pmdp) = _SEGMENT_ENTRY_EMPTY; - pmd_val1(*pmdp) = _SEGMENT_ENTRY_EMPTY; } -#endif /* __s390x__ */ - -static inline void pmd_clear(pmd_t * pmdp) +static inline void pmd_clear(pmd_t *pmd) { - pmd_t *shadow_pmd = get_shadow_table(pmdp); + pmd_t *shadow = get_shadow_table(pmd); - pmd_clear_kernel(pmdp); - if (shadow_pmd) - pmd_clear_kernel(shadow_pmd); + pmd_clear_kernel(pmd); + if (shadow) + pmd_clear_kernel(shadow); } static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { - pte_t *shadow_pte = get_shadow_pte(ptep); - pte_val(*ptep) = _PAGE_TYPE_EMPTY; - if (shadow_pte) - pte_val(*shadow_pte) = _PAGE_TYPE_EMPTY; + if (mm->context.noexec) + pte_val(ptep[PTRS_PER_PTE]) = _PAGE_TYPE_EMPTY; } /* @@ -666,7 +633,7 @@ static inline void __ptep_ipte(unsigned long address, pte_t *ptep) { if (!(pte_val(*ptep) & _PAGE_INVALID)) { #ifndef __s390x__ - /* S390 has 1mb segments, we are emulating 4MB segments */ + /* pto must point to the start of the segment table */ pte_t *pto = (pte_t *) (((unsigned long) ptep) & 0x7ffffc00); #else /* ipte in zarch mode can do the math */ @@ -680,12 +647,12 @@ static inline void __ptep_ipte(unsigned long address, pte_t *ptep) pte_val(*ptep) = _PAGE_TYPE_EMPTY; } -static inline void ptep_invalidate(unsigned long address, pte_t *ptep) +static inline void ptep_invalidate(struct mm_struct *mm, + unsigned long address, pte_t *ptep) { __ptep_ipte(address, ptep); - ptep = get_shadow_pte(ptep); - if (ptep) - __ptep_ipte(address, ptep); + if (mm->context.noexec) + __ptep_ipte(address, ptep + PTRS_PER_PTE); } /* @@ -707,7 +674,7 @@ static inline void ptep_invalidate(unsigned long address, pte_t *ptep) pte_t __pte = *(__ptep); \ if (atomic_read(&(__mm)->mm_users) > 1 || \ (__mm) != current->active_mm) \ - ptep_invalidate(__address, __ptep); \ + ptep_invalidate(__mm, __address, __ptep); \ else \ pte_clear((__mm), (__address), (__ptep)); \ __pte; \ @@ -718,7 +685,7 @@ static inline pte_t ptep_clear_flush(struct vm_area_struct *vma, unsigned long address, pte_t *ptep) { pte_t pte = *ptep; - ptep_invalidate(address, ptep); + ptep_invalidate(vma->vm_mm, address, ptep); return pte; } @@ -739,7 +706,7 @@ static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, if (full) pte_clear(mm, addr, ptep); else - ptep_invalidate(addr, ptep); + ptep_invalidate(mm, addr, ptep); return pte; } @@ -750,7 +717,7 @@ static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, if (pte_write(__pte)) { \ if (atomic_read(&(__mm)->mm_users) > 1 || \ (__mm) != current->active_mm) \ - ptep_invalidate(__addr, __ptep); \ + ptep_invalidate(__mm, __addr, __ptep); \ set_pte_at(__mm, __addr, __ptep, pte_wrprotect(__pte)); \ } \ }) @@ -760,7 +727,7 @@ static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, ({ \ int __changed = !pte_same(*(__ptep), __entry); \ if (__changed) { \ - ptep_invalidate(__addr, __ptep); \ + ptep_invalidate((__vma)->vm_mm, __addr, __ptep); \ set_pte_at((__vma)->vm_mm, __addr, __ptep, __entry); \ } \ __changed; \ diff --git a/include/asm-s390/tlb.h b/include/asm-s390/tlb.h index 3c8177fa9e0..ecac75ec6cb 100644 --- a/include/asm-s390/tlb.h +++ b/include/asm-s390/tlb.h @@ -95,14 +95,14 @@ static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page) * pte_free_tlb frees a pte table and clears the CRSTE for the * page table from the tlb. */ -static inline void pte_free_tlb(struct mmu_gather *tlb, pgtable_t page) +static inline void pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte) { if (!tlb->fullmm) { - tlb->array[tlb->nr_ptes++] = page; + tlb->array[tlb->nr_ptes++] = pte; if (tlb->nr_ptes >= tlb->nr_pmds) tlb_flush_mmu(tlb, 0, 0); } else - pte_free(tlb->mm, page); + pte_free(tlb->mm, pte); } /* diff --git a/include/asm-s390/tlbflush.h b/include/asm-s390/tlbflush.h index 70fa5ae5818..35fb4f9127b 100644 --- a/include/asm-s390/tlbflush.h +++ b/include/asm-s390/tlbflush.h @@ -61,11 +61,12 @@ static inline void __tlb_flush_mm(struct mm_struct * mm) * only ran on the local cpu. */ if (MACHINE_HAS_IDTE) { - pgd_t *shadow = get_shadow_table(mm->pgd); - - if (shadow) - __tlb_flush_idte((unsigned long) shadow | mm->context); - __tlb_flush_idte((unsigned long) mm->pgd | mm->context); + if (mm->context.noexec) + __tlb_flush_idte((unsigned long) + get_shadow_table(mm->pgd) | + mm->context.asce_bits); + __tlb_flush_idte((unsigned long) mm->pgd | + mm->context.asce_bits); return; } preempt_disable(); -- cgit v1.2.3-18-g5258 From 5a216a20837c5f5fa1ca4b8ae8991ffd96b08e6f Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Sat, 9 Feb 2008 18:24:36 +0100 Subject: [S390] Add four level page tables for CONFIG_64BIT=y. Signed-off-by: Martin Schwidefsky --- include/asm-s390/elf.h | 9 +------ include/asm-s390/mmu_context.h | 2 +- include/asm-s390/pgalloc.h | 29 +++++++++++++++++---- include/asm-s390/pgtable.h | 57 +++++++++++++++++++++++++++++++++--------- include/asm-s390/processor.h | 24 ++++++++++-------- include/asm-s390/tlb.h | 33 +++++++++++++++++------- 6 files changed, 109 insertions(+), 45 deletions(-) (limited to 'include') diff --git a/include/asm-s390/elf.h b/include/asm-s390/elf.h index 8181ca5b98f..b760cd4de38 100644 --- a/include/asm-s390/elf.h +++ b/include/asm-s390/elf.h @@ -138,14 +138,7 @@ typedef s390_regs elf_gregset_t; use of this is to invoke "./ld.so someprog" to test out a new version of the loader. We need to make sure that it is out of the way of the program that it will "exec", and that there is sufficient room for the brk. */ - -#ifndef __s390x__ -#define ELF_ET_DYN_BASE ((TASK_SIZE & 0x80000000) \ - ? TASK_SIZE / 3 * 2 \ - : 2 * TASK_SIZE / 3) -#else /* __s390x__ */ -#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2) -#endif /* __s390x__ */ +#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2) /* Wow, the "main" arch needs arch dependent functions too.. :) */ diff --git a/include/asm-s390/mmu_context.h b/include/asm-s390/mmu_context.h index 3eaac5efc63..b3ea3e19992 100644 --- a/include/asm-s390/mmu_context.h +++ b/include/asm-s390/mmu_context.h @@ -18,7 +18,7 @@ static inline int init_new_context(struct task_struct *tsk, { mm->context.asce_bits = _ASCE_TABLE_LENGTH | _ASCE_USER_BITS; #ifdef CONFIG_64BIT - mm->context.asce_bits |= _ASCE_TYPE_REGION3; + mm->context.asce_bits |= _ASCE_TYPE_REGION2; #endif mm->context.noexec = s390_noexec; return 0; diff --git a/include/asm-s390/pgalloc.h b/include/asm-s390/pgalloc.h index af4aee856df..cc47dd65a49 100644 --- a/include/asm-s390/pgalloc.h +++ b/include/asm-s390/pgalloc.h @@ -73,11 +73,17 @@ static inline unsigned long pgd_entry_type(struct mm_struct *mm) static inline unsigned long pgd_entry_type(struct mm_struct *mm) { - return _REGION3_ENTRY_EMPTY; + return _REGION2_ENTRY_EMPTY; } -#define pud_alloc_one(mm,address) ({ BUG(); ((pud_t *)2); }) -#define pud_free(mm, x) do { } while (0) +static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long address) +{ + unsigned long *table = crst_table_alloc(mm, mm->context.noexec); + if (table) + crst_table_init(table, _REGION3_ENTRY_EMPTY); + return (pud_t *) table; +} +#define pud_free(mm, pud) crst_table_free(mm, (unsigned long *) pud) static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr) { @@ -88,8 +94,21 @@ static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr) } #define pmd_free(mm, pmd) crst_table_free(mm, (unsigned long *) pmd) -#define pgd_populate(mm, pgd, pud) BUG() -#define pgd_populate_kernel(mm, pgd, pud) BUG() +static inline void pgd_populate_kernel(struct mm_struct *mm, + pgd_t *pgd, pud_t *pud) +{ + pgd_val(*pgd) = _REGION2_ENTRY | __pa(pud); +} + +static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud) +{ + pgd_t *shadow_pgd = get_shadow_table(pgd); + pud_t *shadow_pud = get_shadow_table(pud); + + if (shadow_pgd && shadow_pud) + pgd_populate_kernel(mm, shadow_pgd, shadow_pud); + pgd_populate_kernel(mm, pgd, pud); +} static inline void pud_populate_kernel(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) diff --git a/include/asm-s390/pgtable.h b/include/asm-s390/pgtable.h index 4fc93771148..8f473a71811 100644 --- a/include/asm-s390/pgtable.h +++ b/include/asm-s390/pgtable.h @@ -63,15 +63,15 @@ extern char empty_zero_page[PAGE_SIZE]; #else /* __s390x__ */ # define PMD_SHIFT 20 # define PUD_SHIFT 31 -# define PGDIR_SHIFT 31 +# define PGDIR_SHIFT 42 #endif /* __s390x__ */ #define PMD_SIZE (1UL << PMD_SHIFT) #define PMD_MASK (~(PMD_SIZE-1)) #define PUD_SIZE (1UL << PUD_SHIFT) #define PUD_MASK (~(PUD_SIZE-1)) -#define PGDIR_SIZE (1UL << PGDIR_SHIFT) -#define PGDIR_MASK (~(PGDIR_SIZE-1)) +#define PGDIR_SIZE (1UL << PGDIR_SHIFT) +#define PGDIR_MASK (~(PGDIR_SIZE-1)) /* * entries per page directory level: the S390 is two-level, so @@ -82,10 +82,11 @@ extern char empty_zero_page[PAGE_SIZE]; #define PTRS_PER_PTE 256 #ifndef __s390x__ #define PTRS_PER_PMD 1 +#define PTRS_PER_PUD 1 #else /* __s390x__ */ #define PTRS_PER_PMD 2048 +#define PTRS_PER_PUD 2048 #endif /* __s390x__ */ -#define PTRS_PER_PUD 1 #define PTRS_PER_PGD 2048 #define FIRST_USER_ADDRESS 0 @@ -418,9 +419,23 @@ static inline int pud_bad(pud_t pud) { return 0; } #else /* __s390x__ */ -static inline int pgd_present(pgd_t pgd) { return 1; } -static inline int pgd_none(pgd_t pgd) { return 0; } -static inline int pgd_bad(pgd_t pgd) { return 0; } +static inline int pgd_present(pgd_t pgd) +{ + return (pgd_val(pgd) & _REGION_ENTRY_ORIGIN) != 0UL; +} + +static inline int pgd_none(pgd_t pgd) +{ + return (pgd_val(pgd) & _REGION_ENTRY_INV) != 0UL; +} + +static inline int pgd_bad(pgd_t pgd) +{ + unsigned long mask = + ~_REGION_ENTRY_ORIGIN & ~_REGION_ENTRY_INV & + ~_REGION_ENTRY_TYPE_MASK & ~_REGION_ENTRY_LENGTH; + return (pgd_val(pgd) & mask) != 0; +} static inline int pud_present(pud_t pud) { @@ -434,8 +449,10 @@ static inline int pud_none(pud_t pud) static inline int pud_bad(pud_t pud) { - unsigned long mask = ~_REGION_ENTRY_ORIGIN & ~_REGION_ENTRY_INV; - return (pud_val(pud) & mask) != _REGION3_ENTRY; + unsigned long mask = + ~_REGION_ENTRY_ORIGIN & ~_REGION_ENTRY_INV & + ~_REGION_ENTRY_TYPE_MASK & ~_REGION_ENTRY_LENGTH; + return (pud_val(pud) & mask) != 0; } #endif /* __s390x__ */ @@ -516,7 +533,19 @@ static inline int pte_young(pte_t pte) #else /* __s390x__ */ -#define pgd_clear(pgd) do { } while (0) +static inline void pgd_clear_kernel(pgd_t * pgd) +{ + pgd_val(*pgd) = _REGION2_ENTRY_EMPTY; +} + +static inline void pgd_clear(pgd_t * pgd) +{ + pgd_t *shadow = get_shadow_table(pgd); + + pgd_clear_kernel(pgd); + if (shadow) + pgd_clear_kernel(shadow); +} static inline void pud_clear_kernel(pud_t *pud) { @@ -808,9 +837,13 @@ static inline pte_t mk_pte(struct page *page, pgprot_t pgprot) #define pmd_deref(pmd) (pmd_val(pmd) & _SEGMENT_ENTRY_ORIGIN) #define pud_deref(pud) (pud_val(pud) & _REGION_ENTRY_ORIGIN) -#define pgd_deref(pgd) ({ BUG(); 0UL; }) +#define pgd_deref(pgd) (pgd_val(pgd) & _REGION_ENTRY_ORIGIN) -#define pud_offset(pgd, address) ((pud_t *) pgd) +static inline pud_t *pud_offset(pgd_t *pgd, unsigned long address) +{ + pud_t *pud = (pud_t *) pgd_deref(*pgd); + return pud + pud_index(address); +} static inline pmd_t *pmd_offset(pud_t *pud, unsigned long address) { diff --git a/include/asm-s390/processor.h b/include/asm-s390/processor.h index e8785634cbd..5a21f457d58 100644 --- a/include/asm-s390/processor.h +++ b/include/asm-s390/processor.h @@ -64,24 +64,28 @@ extern int get_cpu_capability(unsigned int *); */ #ifndef __s390x__ -# define TASK_SIZE (0x80000000UL) -# define TASK_UNMAPPED_BASE (TASK_SIZE / 2) -# define DEFAULT_TASK_SIZE (0x80000000UL) +#define TASK_SIZE (1UL << 31) +#define TASK_UNMAPPED_BASE (1UL << 30) #else /* __s390x__ */ -# define TASK_SIZE_OF(tsk) (test_tsk_thread_flag(tsk, TIF_31BIT) ? \ - (0x80000000UL) : (0x40000000000UL)) -# define TASK_SIZE TASK_SIZE_OF(current) -# define TASK_UNMAPPED_BASE (TASK_SIZE / 2) -# define DEFAULT_TASK_SIZE (0x40000000000UL) +#define TASK_SIZE_OF(tsk) (test_tsk_thread_flag(tsk,TIF_31BIT) ? \ + (1UL << 31) : (1UL << 53)) +#define TASK_UNMAPPED_BASE (test_thread_flag(TIF_31BIT) ? \ + (1UL << 30) : (1UL << 41)) +#define TASK_SIZE TASK_SIZE_OF(current) #endif /* __s390x__ */ #ifdef __KERNEL__ -#define STACK_TOP TASK_SIZE -#define STACK_TOP_MAX DEFAULT_TASK_SIZE +#ifndef __s390x__ +#define STACK_TOP (1UL << 31) +#else /* __s390x__ */ +#define STACK_TOP (1UL << (test_thread_flag(TIF_31BIT) ? 31:53)) +#endif /* __s390x__ */ + +#define STACK_TOP_MAX STACK_TOP #endif diff --git a/include/asm-s390/tlb.h b/include/asm-s390/tlb.h index ecac75ec6cb..9b2ddb7aac4 100644 --- a/include/asm-s390/tlb.h +++ b/include/asm-s390/tlb.h @@ -38,7 +38,7 @@ struct mmu_gather { struct mm_struct *mm; unsigned int fullmm; unsigned int nr_ptes; - unsigned int nr_pmds; + unsigned int nr_pxds; void *array[TLB_NR_PTRS]; }; @@ -53,7 +53,7 @@ static inline struct mmu_gather *tlb_gather_mmu(struct mm_struct *mm, tlb->fullmm = full_mm_flush || (num_online_cpus() == 1) || (atomic_read(&mm->mm_users) <= 1 && mm == current->active_mm); tlb->nr_ptes = 0; - tlb->nr_pmds = TLB_NR_PTRS; + tlb->nr_pxds = TLB_NR_PTRS; if (tlb->fullmm) __tlb_flush_mm(mm); return tlb; @@ -62,12 +62,13 @@ static inline struct mmu_gather *tlb_gather_mmu(struct mm_struct *mm, static inline void tlb_flush_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end) { - if (!tlb->fullmm && (tlb->nr_ptes > 0 || tlb->nr_pmds < TLB_NR_PTRS)) + if (!tlb->fullmm && (tlb->nr_ptes > 0 || tlb->nr_pxds < TLB_NR_PTRS)) __tlb_flush_mm(tlb->mm); while (tlb->nr_ptes > 0) pte_free(tlb->mm, tlb->array[--tlb->nr_ptes]); - while (tlb->nr_pmds < TLB_NR_PTRS) - pmd_free(tlb->mm, (pmd_t *) tlb->array[tlb->nr_pmds++]); + while (tlb->nr_pxds < TLB_NR_PTRS) + /* pgd_free frees the pointer as region or segment table */ + pgd_free(tlb->mm, tlb->array[tlb->nr_pxds++]); } static inline void tlb_finish_mmu(struct mmu_gather *tlb, @@ -99,7 +100,7 @@ static inline void pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte) { if (!tlb->fullmm) { tlb->array[tlb->nr_ptes++] = pte; - if (tlb->nr_ptes >= tlb->nr_pmds) + if (tlb->nr_ptes >= tlb->nr_pxds) tlb_flush_mmu(tlb, 0, 0); } else pte_free(tlb->mm, pte); @@ -113,15 +114,29 @@ static inline void pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd) { #ifdef __s390x__ if (!tlb->fullmm) { - tlb->array[--tlb->nr_pmds] = (struct page *) pmd; - if (tlb->nr_ptes >= tlb->nr_pmds) + tlb->array[--tlb->nr_pxds] = pmd; + if (tlb->nr_ptes >= tlb->nr_pxds) tlb_flush_mmu(tlb, 0, 0); } else pmd_free(tlb->mm, pmd); #endif } -#define pud_free_tlb(tlb, pud) do { } while (0) +/* + * pud_free_tlb frees a pud table and clears the CRSTE for the + * region third table entry from the tlb. + */ +static inline void pud_free_tlb(struct mmu_gather *tlb, pud_t *pud) +{ +#ifdef __s390x__ + if (!tlb->fullmm) { + tlb->array[--tlb->nr_pxds] = pud; + if (tlb->nr_ptes >= tlb->nr_pxds) + tlb_flush_mmu(tlb, 0, 0); + } else + pud_free(tlb->mm, pud); +#endif +} #define tlb_start_vma(tlb, vma) do { } while (0) #define tlb_end_vma(tlb, vma) do { } while (0) -- cgit v1.2.3-18-g5258 From 6252d702c5311ce916caf75ed82e5c8245171c92 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Sat, 9 Feb 2008 18:24:37 +0100 Subject: [S390] dynamic page tables. Add support for different number of page table levels dependent on the highest address used for a process. This will cause a 31 bit process to use a two level page table instead of the four level page table that is the default after the pud has been introduced. Likewise a normal 64 bit process will use three levels instead of four. Only if a process runs out of the 4 tera bytes which can be addressed with a three level page table the fourth level is dynamically added. Then the process can use up to 8 peta byte. Signed-off-by: Martin Schwidefsky --- include/asm-s390/elf.h | 2 +- include/asm-s390/mmu.h | 1 + include/asm-s390/mmu_context.h | 8 ++++---- include/asm-s390/pgalloc.h | 24 +++++++++++++----------- include/asm-s390/pgtable.h | 38 +++++++++++++++++++++++++++++++------- include/asm-s390/processor.h | 25 +++---------------------- include/asm-s390/tlb.h | 10 ++++++++++ 7 files changed, 63 insertions(+), 45 deletions(-) (limited to 'include') diff --git a/include/asm-s390/elf.h b/include/asm-s390/elf.h index b760cd4de38..b3ac262c458 100644 --- a/include/asm-s390/elf.h +++ b/include/asm-s390/elf.h @@ -138,7 +138,7 @@ typedef s390_regs elf_gregset_t; use of this is to invoke "./ld.so someprog" to test out a new version of the loader. We need to make sure that it is out of the way of the program that it will "exec", and that there is sufficient room for the brk. */ -#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2) +#define ELF_ET_DYN_BASE (STACK_TOP / 3 * 2) /* Wow, the "main" arch needs arch dependent functions too.. :) */ diff --git a/include/asm-s390/mmu.h b/include/asm-s390/mmu.h index 13ec4215f43..1698e29c5b2 100644 --- a/include/asm-s390/mmu.h +++ b/include/asm-s390/mmu.h @@ -5,6 +5,7 @@ typedef struct { struct list_head crst_list; struct list_head pgtable_list; unsigned long asce_bits; + unsigned long asce_limit; int noexec; } mm_context_t; diff --git a/include/asm-s390/mmu_context.h b/include/asm-s390/mmu_context.h index b3ea3e19992..b5a34c6f91a 100644 --- a/include/asm-s390/mmu_context.h +++ b/include/asm-s390/mmu_context.h @@ -18,9 +18,11 @@ static inline int init_new_context(struct task_struct *tsk, { mm->context.asce_bits = _ASCE_TABLE_LENGTH | _ASCE_USER_BITS; #ifdef CONFIG_64BIT - mm->context.asce_bits |= _ASCE_TYPE_REGION2; + mm->context.asce_bits |= _ASCE_TYPE_REGION3; #endif mm->context.noexec = s390_noexec; + mm->context.asce_limit = STACK_TOP_MAX; + crst_table_init((unsigned long *) mm->pgd, pgd_entry_type(mm)); return 0; } @@ -47,13 +49,12 @@ static inline void update_mm(struct mm_struct *mm, struct task_struct *tsk) /* Load home space page table origin. */ asm volatile(LCTL_OPCODE" 13,13,%0" : : "m" (S390_lowcore.user_asce) ); + set_fs(current->thread.mm_segment); } static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk) { - if (unlikely(prev == next)) - return; cpu_set(smp_processor_id(), next->cpu_vm_mask); update_mm(next, tsk); } @@ -65,7 +66,6 @@ static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next) { switch_mm(prev, next, current); - set_fs(current->thread.mm_segment); } #endif /* __S390_MMU_CONTEXT_H */ diff --git a/include/asm-s390/pgalloc.h b/include/asm-s390/pgalloc.h index cc47dd65a49..f5b2bf3d7c1 100644 --- a/include/asm-s390/pgalloc.h +++ b/include/asm-s390/pgalloc.h @@ -73,9 +73,16 @@ static inline unsigned long pgd_entry_type(struct mm_struct *mm) static inline unsigned long pgd_entry_type(struct mm_struct *mm) { + if (mm->context.asce_limit <= (1UL << 31)) + return _SEGMENT_ENTRY_EMPTY; + if (mm->context.asce_limit <= (1UL << 42)) + return _REGION3_ENTRY_EMPTY; return _REGION2_ENTRY_EMPTY; } +int crst_table_upgrade(struct mm_struct *, unsigned long limit); +void crst_table_downgrade(struct mm_struct *, unsigned long limit); + static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long address) { unsigned long *table = crst_table_alloc(mm, mm->context.noexec); @@ -102,12 +109,12 @@ static inline void pgd_populate_kernel(struct mm_struct *mm, static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud) { - pgd_t *shadow_pgd = get_shadow_table(pgd); - pud_t *shadow_pud = get_shadow_table(pud); - - if (shadow_pgd && shadow_pud) - pgd_populate_kernel(mm, shadow_pgd, shadow_pud); pgd_populate_kernel(mm, pgd, pud); + if (mm->context.noexec) { + pgd = get_shadow_table(pgd); + pud = get_shadow_table(pud); + pgd_populate_kernel(mm, pgd, pud); + } } static inline void pud_populate_kernel(struct mm_struct *mm, @@ -130,14 +137,9 @@ static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) static inline pgd_t *pgd_alloc(struct mm_struct *mm) { - unsigned long *crst; - INIT_LIST_HEAD(&mm->context.crst_list); INIT_LIST_HEAD(&mm->context.pgtable_list); - crst = crst_table_alloc(mm, s390_noexec); - if (crst) - crst_table_init(crst, pgd_entry_type(mm)); - return (pgd_t *) crst; + return (pgd_t *) crst_table_alloc(mm, s390_noexec); } #define pgd_free(mm, pgd) crst_table_free(mm, (unsigned long *) pgd) diff --git a/include/asm-s390/pgtable.h b/include/asm-s390/pgtable.h index 8f473a71811..65154dc9a9e 100644 --- a/include/asm-s390/pgtable.h +++ b/include/asm-s390/pgtable.h @@ -421,36 +421,54 @@ static inline int pud_bad(pud_t pud) { return 0; } static inline int pgd_present(pgd_t pgd) { + if ((pgd_val(pgd) & _REGION_ENTRY_TYPE_MASK) < _REGION_ENTRY_TYPE_R2) + return 1; return (pgd_val(pgd) & _REGION_ENTRY_ORIGIN) != 0UL; } static inline int pgd_none(pgd_t pgd) { + if ((pgd_val(pgd) & _REGION_ENTRY_TYPE_MASK) < _REGION_ENTRY_TYPE_R2) + return 0; return (pgd_val(pgd) & _REGION_ENTRY_INV) != 0UL; } static inline int pgd_bad(pgd_t pgd) { + /* + * With dynamic page table levels the pgd can be a region table + * entry or a segment table entry. Check for the bit that are + * invalid for either table entry. + */ unsigned long mask = - ~_REGION_ENTRY_ORIGIN & ~_REGION_ENTRY_INV & + ~_SEGMENT_ENTRY_ORIGIN & ~_REGION_ENTRY_INV & ~_REGION_ENTRY_TYPE_MASK & ~_REGION_ENTRY_LENGTH; return (pgd_val(pgd) & mask) != 0; } static inline int pud_present(pud_t pud) { + if ((pud_val(pud) & _REGION_ENTRY_TYPE_MASK) < _REGION_ENTRY_TYPE_R3) + return 1; return (pud_val(pud) & _REGION_ENTRY_ORIGIN) != 0UL; } static inline int pud_none(pud_t pud) { + if ((pud_val(pud) & _REGION_ENTRY_TYPE_MASK) < _REGION_ENTRY_TYPE_R3) + return 0; return (pud_val(pud) & _REGION_ENTRY_INV) != 0UL; } static inline int pud_bad(pud_t pud) { + /* + * With dynamic page table levels the pud can be a region table + * entry or a segment table entry. Check for the bit that are + * invalid for either table entry. + */ unsigned long mask = - ~_REGION_ENTRY_ORIGIN & ~_REGION_ENTRY_INV & + ~_SEGMENT_ENTRY_ORIGIN & ~_REGION_ENTRY_INV & ~_REGION_ENTRY_TYPE_MASK & ~_REGION_ENTRY_LENGTH; return (pud_val(pud) & mask) != 0; } @@ -535,7 +553,8 @@ static inline int pte_young(pte_t pte) static inline void pgd_clear_kernel(pgd_t * pgd) { - pgd_val(*pgd) = _REGION2_ENTRY_EMPTY; + if ((pgd_val(*pgd) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R2) + pgd_val(*pgd) = _REGION2_ENTRY_EMPTY; } static inline void pgd_clear(pgd_t * pgd) @@ -549,10 +568,11 @@ static inline void pgd_clear(pgd_t * pgd) static inline void pud_clear_kernel(pud_t *pud) { - pud_val(*pud) = _REGION3_ENTRY_EMPTY; + if ((pud_val(*pud) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3) + pud_val(*pud) = _REGION3_ENTRY_EMPTY; } -static inline void pud_clear(pud_t * pud) +static inline void pud_clear(pud_t *pud) { pud_t *shadow = get_shadow_table(pud); @@ -841,13 +861,17 @@ static inline pte_t mk_pte(struct page *page, pgprot_t pgprot) static inline pud_t *pud_offset(pgd_t *pgd, unsigned long address) { - pud_t *pud = (pud_t *) pgd_deref(*pgd); + pud_t *pud = (pud_t *) pgd; + if ((pgd_val(*pgd) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R2) + pud = (pud_t *) pgd_deref(*pgd); return pud + pud_index(address); } static inline pmd_t *pmd_offset(pud_t *pud, unsigned long address) { - pmd_t *pmd = (pmd_t *) pud_deref(*pud); + pmd_t *pmd = (pmd_t *) pud; + if ((pud_val(*pud) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3) + pmd = (pmd_t *) pud_deref(*pud); return pmd + pmd_index(address); } diff --git a/include/asm-s390/processor.h b/include/asm-s390/processor.h index 5a21f457d58..51d88912aa2 100644 --- a/include/asm-s390/processor.h +++ b/include/asm-s390/processor.h @@ -81,11 +81,12 @@ extern int get_cpu_capability(unsigned int *); #ifndef __s390x__ #define STACK_TOP (1UL << 31) +#define STACK_TOP_MAX (1UL << 31) #else /* __s390x__ */ -#define STACK_TOP (1UL << (test_thread_flag(TIF_31BIT) ? 31:53)) +#define STACK_TOP (1UL << (test_thread_flag(TIF_31BIT) ? 31:42)) +#define STACK_TOP_MAX (1UL << 42) #endif /* __s390x__ */ -#define STACK_TOP_MAX STACK_TOP #endif @@ -142,8 +143,6 @@ struct stack_frame { /* * Do necessary setup to start up a new thread. */ -#ifndef __s390x__ - #define start_thread(regs, new_psw, new_stackp) do { \ set_fs(USER_DS); \ regs->psw.mask = psw_user_bits; \ @@ -151,24 +150,6 @@ struct stack_frame { regs->gprs[15] = new_stackp ; \ } while (0) -#else /* __s390x__ */ - -#define start_thread(regs, new_psw, new_stackp) do { \ - set_fs(USER_DS); \ - regs->psw.mask = psw_user_bits; \ - regs->psw.addr = new_psw; \ - regs->gprs[15] = new_stackp; \ -} while (0) - -#define start_thread31(regs, new_psw, new_stackp) do { \ - set_fs(USER_DS); \ - regs->psw.mask = psw_user32_bits; \ - regs->psw.addr = new_psw; \ - regs->gprs[15] = new_stackp; \ -} while (0) - -#endif /* __s390x__ */ - /* Forward declaration, a strange C thing */ struct task_struct; struct mm_struct; diff --git a/include/asm-s390/tlb.h b/include/asm-s390/tlb.h index 9b2ddb7aac4..3d8a96d39d9 100644 --- a/include/asm-s390/tlb.h +++ b/include/asm-s390/tlb.h @@ -109,10 +109,15 @@ static inline void pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte) /* * pmd_free_tlb frees a pmd table and clears the CRSTE for the * segment table entry from the tlb. + * If the mm uses a two level page table the single pmd is freed + * as the pgd. pmd_free_tlb checks the asce_limit against 2GB + * to avoid the double free of the pmd in this case. */ static inline void pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd) { #ifdef __s390x__ + if (tlb->mm->context.asce_limit <= (1UL << 31)) + return; if (!tlb->fullmm) { tlb->array[--tlb->nr_pxds] = pmd; if (tlb->nr_ptes >= tlb->nr_pxds) @@ -125,10 +130,15 @@ static inline void pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd) /* * pud_free_tlb frees a pud table and clears the CRSTE for the * region third table entry from the tlb. + * If the mm uses a three level page table the single pud is freed + * as the pgd. pud_free_tlb checks the asce_limit against 4TB + * to avoid the double free of the pud in this case. */ static inline void pud_free_tlb(struct mmu_gather *tlb, pud_t *pud) { #ifdef __s390x__ + if (tlb->mm->context.asce_limit <= (1UL << 42)) + return; if (!tlb->fullmm) { tlb->array[--tlb->nr_pxds] = pud; if (tlb->nr_ptes >= tlb->nr_pxds) -- cgit v1.2.3-18-g5258