blob: cc47dd65a49984648acb8ef6e16afd27591c7ba3 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * include/asm-s390/pgalloc.h
3 *
4 * S390 version
5 * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
6 * Author(s): Hartmut Penner (hp@de.ibm.com)
7 * Martin Schwidefsky (schwidefsky@de.ibm.com)
8 *
9 * Derived from "include/asm-i386/pgalloc.h"
10 * Copyright (C) 1994 Linus Torvalds
11 */
12
13#ifndef _S390_PGALLOC_H
14#define _S390_PGALLOC_H
15
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include <linux/threads.h>
17#include <linux/gfp.h>
18#include <linux/mm.h>
19
20#define check_pgt_cache() do {} while (0)
21
Martin Schwidefsky3610cce2007-10-22 12:52:47 +020022unsigned long *crst_table_alloc(struct mm_struct *, int);
Martin Schwidefsky146e4b32008-02-09 18:24:35 +010023void crst_table_free(struct mm_struct *, unsigned long *);
Gerald Schaefer9282ed92006-09-20 15:59:37 +020024
Martin Schwidefsky146e4b32008-02-09 18:24:35 +010025unsigned long *page_table_alloc(struct mm_struct *);
26void page_table_free(struct mm_struct *, unsigned long *);
27void disable_noexec(struct mm_struct *, struct task_struct *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070028
Martin Schwidefsky3610cce2007-10-22 12:52:47 +020029static inline void clear_table(unsigned long *s, unsigned long val, size_t n)
Linus Torvalds1da177e2005-04-16 15:20:36 -070030{
Martin Schwidefsky3610cce2007-10-22 12:52:47 +020031 *s = val;
32 n = (n / 256) - 1;
33 asm volatile(
34#ifdef CONFIG_64BIT
35 " mvc 8(248,%0),0(%0)\n"
Gerald Schaefer9282ed92006-09-20 15:59:37 +020036#else
Martin Schwidefsky3610cce2007-10-22 12:52:47 +020037 " mvc 4(252,%0),0(%0)\n"
Gerald Schaefer9282ed92006-09-20 15:59:37 +020038#endif
Martin Schwidefsky3610cce2007-10-22 12:52:47 +020039 "0: mvc 256(256,%0),0(%0)\n"
40 " la %0,256(%0)\n"
41 " brct %1,0b\n"
42 : "+a" (s), "+d" (n));
Linus Torvalds1da177e2005-04-16 15:20:36 -070043}
44
Martin Schwidefsky3610cce2007-10-22 12:52:47 +020045static inline void crst_table_init(unsigned long *crst, unsigned long entry)
Linus Torvalds1da177e2005-04-16 15:20:36 -070046{
Martin Schwidefsky3610cce2007-10-22 12:52:47 +020047 clear_table(crst, entry, sizeof(unsigned long)*2048);
48 crst = get_shadow_table(crst);
49 if (crst)
50 clear_table(crst, entry, sizeof(unsigned long)*2048);
Linus Torvalds1da177e2005-04-16 15:20:36 -070051}
52
53#ifndef __s390x__
Martin Schwidefsky3610cce2007-10-22 12:52:47 +020054
55static inline unsigned long pgd_entry_type(struct mm_struct *mm)
56{
57 return _SEGMENT_ENTRY_EMPTY;
58}
59
Martin Schwidefsky190a1d72007-10-22 12:52:48 +020060#define pud_alloc_one(mm,address) ({ BUG(); ((pud_t *)2); })
Benjamin Herrenschmidt5e541972008-02-04 22:29:14 -080061#define pud_free(mm, x) do { } while (0)
Martin Schwidefsky190a1d72007-10-22 12:52:48 +020062
Martin Schwidefsky3610cce2007-10-22 12:52:47 +020063#define pmd_alloc_one(mm,address) ({ BUG(); ((pmd_t *)2); })
Benjamin Herrenschmidt5e541972008-02-04 22:29:14 -080064#define pmd_free(mm, x) do { } while (0)
Martin Schwidefsky3610cce2007-10-22 12:52:47 +020065
Martin Schwidefsky190a1d72007-10-22 12:52:48 +020066#define pgd_populate(mm, pgd, pud) BUG()
67#define pgd_populate_kernel(mm, pgd, pud) BUG()
68
69#define pud_populate(mm, pud, pmd) BUG()
70#define pud_populate_kernel(mm, pud, pmd) BUG()
Martin Schwidefsky3610cce2007-10-22 12:52:47 +020071
Linus Torvalds1da177e2005-04-16 15:20:36 -070072#else /* __s390x__ */
Martin Schwidefsky3610cce2007-10-22 12:52:47 +020073
74static inline unsigned long pgd_entry_type(struct mm_struct *mm)
Linus Torvalds1da177e2005-04-16 15:20:36 -070075{
Martin Schwidefsky5a216a22008-02-09 18:24:36 +010076 return _REGION2_ENTRY_EMPTY;
Linus Torvalds1da177e2005-04-16 15:20:36 -070077}
78
Martin Schwidefsky5a216a22008-02-09 18:24:36 +010079static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long address)
80{
81 unsigned long *table = crst_table_alloc(mm, mm->context.noexec);
82 if (table)
83 crst_table_init(table, _REGION3_ENTRY_EMPTY);
84 return (pud_t *) table;
85}
86#define pud_free(mm, pud) crst_table_free(mm, (unsigned long *) pud)
Martin Schwidefsky190a1d72007-10-22 12:52:48 +020087
Martin Schwidefsky3610cce2007-10-22 12:52:47 +020088static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070089{
Martin Schwidefsky146e4b32008-02-09 18:24:35 +010090 unsigned long *table = crst_table_alloc(mm, mm->context.noexec);
91 if (table)
92 crst_table_init(table, _SEGMENT_ENTRY_EMPTY);
93 return (pmd_t *) table;
Linus Torvalds1da177e2005-04-16 15:20:36 -070094}
Martin Schwidefsky146e4b32008-02-09 18:24:35 +010095#define pmd_free(mm, pmd) crst_table_free(mm, (unsigned long *) pmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
Martin Schwidefsky5a216a22008-02-09 18:24:36 +010097static inline void pgd_populate_kernel(struct mm_struct *mm,
98 pgd_t *pgd, pud_t *pud)
99{
100 pgd_val(*pgd) = _REGION2_ENTRY | __pa(pud);
101}
102
103static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud)
104{
105 pgd_t *shadow_pgd = get_shadow_table(pgd);
106 pud_t *shadow_pud = get_shadow_table(pud);
107
108 if (shadow_pgd && shadow_pud)
109 pgd_populate_kernel(mm, shadow_pgd, shadow_pud);
110 pgd_populate_kernel(mm, pgd, pud);
111}
Martin Schwidefsky190a1d72007-10-22 12:52:48 +0200112
113static inline void pud_populate_kernel(struct mm_struct *mm,
114 pud_t *pud, pmd_t *pmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115{
Martin Schwidefsky190a1d72007-10-22 12:52:48 +0200116 pud_val(*pud) = _REGION3_ENTRY | __pa(pmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117}
118
Martin Schwidefsky190a1d72007-10-22 12:52:48 +0200119static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
Gerald Schaeferc1821c22007-02-05 21:18:17 +0100120{
Martin Schwidefsky190a1d72007-10-22 12:52:48 +0200121 pud_populate_kernel(mm, pud, pmd);
Martin Schwidefsky146e4b32008-02-09 18:24:35 +0100122 if (mm->context.noexec) {
123 pud = get_shadow_table(pud);
124 pmd = get_shadow_table(pmd);
125 pud_populate_kernel(mm, pud, pmd);
126 }
Gerald Schaeferc1821c22007-02-05 21:18:17 +0100127}
128
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129#endif /* __s390x__ */
130
Martin Schwidefsky3610cce2007-10-22 12:52:47 +0200131static inline pgd_t *pgd_alloc(struct mm_struct *mm)
132{
Martin Schwidefsky146e4b32008-02-09 18:24:35 +0100133 unsigned long *crst;
134
135 INIT_LIST_HEAD(&mm->context.crst_list);
136 INIT_LIST_HEAD(&mm->context.pgtable_list);
137 crst = crst_table_alloc(mm, s390_noexec);
Martin Schwidefsky3610cce2007-10-22 12:52:47 +0200138 if (crst)
139 crst_table_init(crst, pgd_entry_type(mm));
140 return (pgd_t *) crst;
141}
Martin Schwidefsky146e4b32008-02-09 18:24:35 +0100142#define pgd_free(mm, pgd) crst_table_free(mm, (unsigned long *) pgd)
Martin Schwidefsky3610cce2007-10-22 12:52:47 +0200143
Martin Schwidefsky146e4b32008-02-09 18:24:35 +0100144static inline void pmd_populate_kernel(struct mm_struct *mm,
145 pmd_t *pmd, pte_t *pte)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146{
Martin Schwidefsky3610cce2007-10-22 12:52:47 +0200147 pmd_val(*pmd) = _SEGMENT_ENTRY + __pa(pte);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148}
149
Martin Schwidefsky146e4b32008-02-09 18:24:35 +0100150static inline void pmd_populate(struct mm_struct *mm,
151 pmd_t *pmd, pgtable_t pte)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152{
Gerald Schaeferc1821c22007-02-05 21:18:17 +0100153 pmd_populate_kernel(mm, pmd, pte);
Martin Schwidefsky146e4b32008-02-09 18:24:35 +0100154 if (mm->context.noexec) {
155 pmd = get_shadow_table(pmd);
156 pmd_populate_kernel(mm, pmd, pte + PTRS_PER_PTE);
157 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158}
Martin Schwidefsky146e4b32008-02-09 18:24:35 +0100159
160#define pmd_pgtable(pmd) \
161 (pgtable_t)(pmd_val(pmd) & -sizeof(pte_t)*PTRS_PER_PTE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162
163/*
164 * page table entry allocation/free routines.
165 */
Martin Schwidefsky146e4b32008-02-09 18:24:35 +0100166#define pte_alloc_one_kernel(mm, vmaddr) ((pte_t *) page_table_alloc(mm))
167#define pte_alloc_one(mm, vmaddr) ((pte_t *) page_table_alloc(mm))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168
Martin Schwidefsky146e4b32008-02-09 18:24:35 +0100169#define pte_free_kernel(mm, pte) page_table_free(mm, (unsigned long *) pte)
170#define pte_free(mm, pte) page_table_free(mm, (unsigned long *) pte)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172#endif /* _S390_PGALLOC_H */