diff options
Diffstat (limited to 'arch/s390/kernel/vdso.c')
-rw-r--r-- | arch/s390/kernel/vdso.c | 123 |
1 files changed, 120 insertions, 3 deletions
diff --git a/arch/s390/kernel/vdso.c b/arch/s390/kernel/vdso.c index 10a6ccef4412..25a6a82f1c02 100644 --- a/arch/s390/kernel/vdso.c +++ b/arch/s390/kernel/vdso.c | |||
@@ -31,9 +31,6 @@ | |||
31 | #include <asm/sections.h> | 31 | #include <asm/sections.h> |
32 | #include <asm/vdso.h> | 32 | #include <asm/vdso.h> |
33 | 33 | ||
34 | /* Max supported size for symbol names */ | ||
35 | #define MAX_SYMNAME 64 | ||
36 | |||
37 | #if defined(CONFIG_32BIT) || defined(CONFIG_COMPAT) | 34 | #if defined(CONFIG_32BIT) || defined(CONFIG_COMPAT) |
38 | extern char vdso32_start, vdso32_end; | 35 | extern char vdso32_start, vdso32_end; |
39 | static void *vdso32_kbase = &vdso32_start; | 36 | static void *vdso32_kbase = &vdso32_start; |
@@ -71,6 +68,119 @@ static union { | |||
71 | struct vdso_data *vdso_data = &vdso_data_store.data; | 68 | struct vdso_data *vdso_data = &vdso_data_store.data; |
72 | 69 | ||
73 | /* | 70 | /* |
71 | * Setup vdso data page. | ||
72 | */ | ||
73 | static void vdso_init_data(struct vdso_data *vd) | ||
74 | { | ||
75 | unsigned int facility_list; | ||
76 | |||
77 | facility_list = stfl(); | ||
78 | vd->ectg_available = switch_amode && (facility_list & 1); | ||
79 | } | ||
80 | |||
81 | #ifdef CONFIG_64BIT | ||
82 | /* | ||
83 | * Setup per cpu vdso data page. | ||
84 | */ | ||
85 | static void vdso_init_per_cpu_data(int cpu, struct vdso_per_cpu_data *vpcd) | ||
86 | { | ||
87 | } | ||
88 | |||
89 | /* | ||
90 | * Allocate/free per cpu vdso data. | ||
91 | */ | ||
92 | #ifdef CONFIG_64BIT | ||
93 | #define SEGMENT_ORDER 2 | ||
94 | #else | ||
95 | #define SEGMENT_ORDER 1 | ||
96 | #endif | ||
97 | |||
98 | int vdso_alloc_per_cpu(int cpu, struct _lowcore *lowcore) | ||
99 | { | ||
100 | unsigned long segment_table, page_table, page_frame; | ||
101 | u32 *psal, *aste; | ||
102 | int i; | ||
103 | |||
104 | lowcore->vdso_per_cpu_data = __LC_PASTE; | ||
105 | |||
106 | if (!switch_amode || !vdso_enabled) | ||
107 | return 0; | ||
108 | |||
109 | segment_table = __get_free_pages(GFP_KERNEL, SEGMENT_ORDER); | ||
110 | page_table = get_zeroed_page(GFP_KERNEL | GFP_DMA); | ||
111 | page_frame = get_zeroed_page(GFP_KERNEL); | ||
112 | if (!segment_table || !page_table || !page_frame) | ||
113 | goto out; | ||
114 | |||
115 | clear_table((unsigned long *) segment_table, _SEGMENT_ENTRY_EMPTY, | ||
116 | PAGE_SIZE << SEGMENT_ORDER); | ||
117 | clear_table((unsigned long *) page_table, _PAGE_TYPE_EMPTY, | ||
118 | 256*sizeof(unsigned long)); | ||
119 | |||
120 | *(unsigned long *) segment_table = _SEGMENT_ENTRY + page_table; | ||
121 | *(unsigned long *) page_table = _PAGE_RO + page_frame; | ||
122 | |||
123 | psal = (u32 *) (page_table + 256*sizeof(unsigned long)); | ||
124 | aste = psal + 32; | ||
125 | |||
126 | for (i = 4; i < 32; i += 4) | ||
127 | psal[i] = 0x80000000; | ||
128 | |||
129 | lowcore->paste[4] = (u32)(addr_t) psal; | ||
130 | psal[0] = 0x20000000; | ||
131 | psal[2] = (u32)(addr_t) aste; | ||
132 | *(unsigned long *) (aste + 2) = segment_table + | ||
133 | _ASCE_TABLE_LENGTH + _ASCE_USER_BITS + _ASCE_TYPE_SEGMENT; | ||
134 | aste[4] = (u32)(addr_t) psal; | ||
135 | lowcore->vdso_per_cpu_data = page_frame; | ||
136 | |||
137 | vdso_init_per_cpu_data(cpu, (struct vdso_per_cpu_data *) page_frame); | ||
138 | return 0; | ||
139 | |||
140 | out: | ||
141 | free_page(page_frame); | ||
142 | free_page(page_table); | ||
143 | free_pages(segment_table, SEGMENT_ORDER); | ||
144 | return -ENOMEM; | ||
145 | } | ||
146 | |||
147 | #ifdef CONFIG_HOTPLUG_CPU | ||
148 | void vdso_free_per_cpu(int cpu, struct _lowcore *lowcore) | ||
149 | { | ||
150 | unsigned long segment_table, page_table, page_frame; | ||
151 | u32 *psal, *aste; | ||
152 | |||
153 | if (!switch_amode || !vdso_enabled) | ||
154 | return; | ||
155 | |||
156 | psal = (u32 *)(addr_t) lowcore->paste[4]; | ||
157 | aste = (u32 *)(addr_t) psal[2]; | ||
158 | segment_table = *(unsigned long *)(aste + 2) & PAGE_MASK; | ||
159 | page_table = *(unsigned long *) segment_table; | ||
160 | page_frame = *(unsigned long *) page_table; | ||
161 | |||
162 | free_page(page_frame); | ||
163 | free_page(page_table); | ||
164 | free_pages(segment_table, SEGMENT_ORDER); | ||
165 | } | ||
166 | #endif /* CONFIG_HOTPLUG_CPU */ | ||
167 | |||
168 | static void __vdso_init_cr5(void *dummy) | ||
169 | { | ||
170 | unsigned long cr5; | ||
171 | |||
172 | cr5 = offsetof(struct _lowcore, paste); | ||
173 | __ctl_load(cr5, 5, 5); | ||
174 | } | ||
175 | |||
176 | static void vdso_init_cr5(void) | ||
177 | { | ||
178 | if (switch_amode && vdso_enabled) | ||
179 | on_each_cpu(__vdso_init_cr5, NULL, 1); | ||
180 | } | ||
181 | #endif /* CONFIG_64BIT */ | ||
182 | |||
183 | /* | ||
74 | * This is called from binfmt_elf, we create the special vma for the | 184 | * This is called from binfmt_elf, we create the special vma for the |
75 | * vDSO and insert it into the mm struct tree | 185 | * vDSO and insert it into the mm struct tree |
76 | */ | 186 | */ |
@@ -172,6 +282,9 @@ static int __init vdso_init(void) | |||
172 | { | 282 | { |
173 | int i; | 283 | int i; |
174 | 284 | ||
285 | if (!vdso_enabled) | ||
286 | return 0; | ||
287 | vdso_init_data(vdso_data); | ||
175 | #if defined(CONFIG_32BIT) || defined(CONFIG_COMPAT) | 288 | #if defined(CONFIG_32BIT) || defined(CONFIG_COMPAT) |
176 | /* Calculate the size of the 32 bit vDSO */ | 289 | /* Calculate the size of the 32 bit vDSO */ |
177 | vdso32_pages = ((&vdso32_end - &vdso32_start | 290 | vdso32_pages = ((&vdso32_end - &vdso32_start |
@@ -208,6 +321,10 @@ static int __init vdso_init(void) | |||
208 | } | 321 | } |
209 | vdso64_pagelist[vdso64_pages - 1] = virt_to_page(vdso_data); | 322 | vdso64_pagelist[vdso64_pages - 1] = virt_to_page(vdso_data); |
210 | vdso64_pagelist[vdso64_pages] = NULL; | 323 | vdso64_pagelist[vdso64_pages] = NULL; |
324 | #ifndef CONFIG_SMP | ||
325 | BUG_ON(vdso_alloc_per_cpu(0, S390_lowcore)); | ||
326 | #endif | ||
327 | vdso_init_cr5(); | ||
211 | #endif /* CONFIG_64BIT */ | 328 | #endif /* CONFIG_64BIT */ |
212 | 329 | ||
213 | get_page(virt_to_page(vdso_data)); | 330 | get_page(virt_to_page(vdso_data)); |