12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2abe1ee3aSTim Abbott
3a7f290daSBenjamin Herrenschmidt /*
4a7f290daSBenjamin Herrenschmidt * Copyright (C) 2004 Benjamin Herrenschmidt, IBM Corp.
5a7f290daSBenjamin Herrenschmidt * <benh@kernel.crashing.org>
6a7f290daSBenjamin Herrenschmidt */
7a7f290daSBenjamin Herrenschmidt
8a7f290daSBenjamin Herrenschmidt #include <linux/errno.h>
9a7f290daSBenjamin Herrenschmidt #include <linux/sched.h>
10a7f290daSBenjamin Herrenschmidt #include <linux/kernel.h>
11a7f290daSBenjamin Herrenschmidt #include <linux/mm.h>
12a7f290daSBenjamin Herrenschmidt #include <linux/smp.h>
13a7f290daSBenjamin Herrenschmidt #include <linux/stddef.h>
14a7f290daSBenjamin Herrenschmidt #include <linux/unistd.h>
15a7f290daSBenjamin Herrenschmidt #include <linux/slab.h>
16a7f290daSBenjamin Herrenschmidt #include <linux/user.h>
17a7f290daSBenjamin Herrenschmidt #include <linux/elf.h>
18a7f290daSBenjamin Herrenschmidt #include <linux/security.h>
1995f72d1eSYinghai Lu #include <linux/memblock.h>
20bc9d5bfcSChristophe Leroy #include <linux/syscalls.h>
2174205b3fSChristophe Leroy #include <linux/time_namespace.h>
22ab037dd8SChristophe Leroy #include <vdso/datapage.h>
23a7f290daSBenjamin Herrenschmidt
24bc9d5bfcSChristophe Leroy #include <asm/syscall.h>
25a7f290daSBenjamin Herrenschmidt #include <asm/processor.h>
26a7f290daSBenjamin Herrenschmidt #include <asm/mmu.h>
27a7f290daSBenjamin Herrenschmidt #include <asm/mmu_context.h>
28a7f290daSBenjamin Herrenschmidt #include <asm/machdep.h>
29a7f290daSBenjamin Herrenschmidt #include <asm/cputable.h>
30a7f290daSBenjamin Herrenschmidt #include <asm/sections.h>
31e8222502SBenjamin Herrenschmidt #include <asm/firmware.h>
32a7f290daSBenjamin Herrenschmidt #include <asm/vdso.h>
33a7f290daSBenjamin Herrenschmidt #include <asm/vdso_datapage.h>
34b88c4767SRobert Jennings #include <asm/setup.h>
350909c8c2SBenjamin Herrenschmidt
36348aa303SAndreas Schwab /* The alignment of the vDSO */
37348aa303SAndreas Schwab #define VDSO_ALIGNMENT (1 << 16)
38348aa303SAndreas Schwab
39e0d00591SMichael Ellerman extern char vdso32_start, vdso32_end;
40a7f290daSBenjamin Herrenschmidt extern char vdso64_start, vdso64_end;
41a7f290daSBenjamin Herrenschmidt
427e92e01bSRohan McLure long sys_ni_syscall(void);
437e92e01bSRohan McLure
44a7f290daSBenjamin Herrenschmidt /*
45a7f290daSBenjamin Herrenschmidt * The vdso data page (aka. systemcfg for old ppc64 fans) is here.
46a7f290daSBenjamin Herrenschmidt * Once the early boot kernel code no longer needs to muck around
47a7f290daSBenjamin Herrenschmidt * with it, it will become dynamically allocated
48a7f290daSBenjamin Herrenschmidt */
49a7f290daSBenjamin Herrenschmidt static union {
50ab037dd8SChristophe Leroy struct vdso_arch_data data;
51a7f290daSBenjamin Herrenschmidt u8 page[PAGE_SIZE];
52abe1ee3aSTim Abbott } vdso_data_store __page_aligned_data;
53ab037dd8SChristophe Leroy struct vdso_arch_data *vdso_data = &vdso_data_store.data;
54a7f290daSBenjamin Herrenschmidt
5574205b3fSChristophe Leroy enum vvar_pages {
5674205b3fSChristophe Leroy VVAR_DATA_PAGE_OFFSET,
5774205b3fSChristophe Leroy VVAR_TIMENS_PAGE_OFFSET,
5874205b3fSChristophe Leroy VVAR_NR_PAGES,
5974205b3fSChristophe Leroy };
6074205b3fSChristophe Leroy
vdso_mremap(const struct vm_special_mapping * sm,struct vm_area_struct * new_vma,unsigned long text_size)61526a9c4aSChristophe Leroy static int vdso_mremap(const struct vm_special_mapping *sm, struct vm_area_struct *new_vma,
62526a9c4aSChristophe Leroy unsigned long text_size)
63526a9c4aSChristophe Leroy {
64526a9c4aSChristophe Leroy unsigned long new_size = new_vma->vm_end - new_vma->vm_start;
65526a9c4aSChristophe Leroy
661c4bce67SDmitry Safonov if (new_size != text_size)
67526a9c4aSChristophe Leroy return -EINVAL;
68526a9c4aSChristophe Leroy
691c4bce67SDmitry Safonov current->mm->context.vdso = (void __user *)new_vma->vm_start;
70526a9c4aSChristophe Leroy
71526a9c4aSChristophe Leroy return 0;
72526a9c4aSChristophe Leroy }
73526a9c4aSChristophe Leroy
vdso32_mremap(const struct vm_special_mapping * sm,struct vm_area_struct * new_vma)74526a9c4aSChristophe Leroy static int vdso32_mremap(const struct vm_special_mapping *sm, struct vm_area_struct *new_vma)
75526a9c4aSChristophe Leroy {
76526a9c4aSChristophe Leroy return vdso_mremap(sm, new_vma, &vdso32_end - &vdso32_start);
77526a9c4aSChristophe Leroy }
78526a9c4aSChristophe Leroy
vdso64_mremap(const struct vm_special_mapping * sm,struct vm_area_struct * new_vma)79526a9c4aSChristophe Leroy static int vdso64_mremap(const struct vm_special_mapping *sm, struct vm_area_struct *new_vma)
80526a9c4aSChristophe Leroy {
81526a9c4aSChristophe Leroy return vdso_mremap(sm, new_vma, &vdso64_end - &vdso64_start);
82526a9c4aSChristophe Leroy }
83a7f290daSBenjamin Herrenschmidt
8474205b3fSChristophe Leroy static vm_fault_t vvar_fault(const struct vm_special_mapping *sm,
8574205b3fSChristophe Leroy struct vm_area_struct *vma, struct vm_fault *vmf);
8674205b3fSChristophe Leroy
871c4bce67SDmitry Safonov static struct vm_special_mapping vvar_spec __ro_after_init = {
881c4bce67SDmitry Safonov .name = "[vvar]",
8974205b3fSChristophe Leroy .fault = vvar_fault,
901c4bce67SDmitry Safonov };
911c4bce67SDmitry Safonov
92c1bab643SChristophe Leroy static struct vm_special_mapping vdso32_spec __ro_after_init = {
93c1bab643SChristophe Leroy .name = "[vdso]",
94526a9c4aSChristophe Leroy .mremap = vdso32_mremap,
95c1bab643SChristophe Leroy };
96c1bab643SChristophe Leroy
97c1bab643SChristophe Leroy static struct vm_special_mapping vdso64_spec __ro_after_init = {
98c1bab643SChristophe Leroy .name = "[vdso]",
99526a9c4aSChristophe Leroy .mremap = vdso64_mremap,
100c1bab643SChristophe Leroy };
101c1bab643SChristophe Leroy
10274205b3fSChristophe Leroy #ifdef CONFIG_TIME_NS
arch_get_vdso_data(void * vvar_page)10374205b3fSChristophe Leroy struct vdso_data *arch_get_vdso_data(void *vvar_page)
10474205b3fSChristophe Leroy {
10574205b3fSChristophe Leroy return ((struct vdso_arch_data *)vvar_page)->data;
10674205b3fSChristophe Leroy }
10774205b3fSChristophe Leroy
10874205b3fSChristophe Leroy /*
10974205b3fSChristophe Leroy * The vvar mapping contains data for a specific time namespace, so when a task
11074205b3fSChristophe Leroy * changes namespace we must unmap its vvar data for the old namespace.
11174205b3fSChristophe Leroy * Subsequent faults will map in data for the new namespace.
11274205b3fSChristophe Leroy *
11374205b3fSChristophe Leroy * For more details see timens_setup_vdso_data().
11474205b3fSChristophe Leroy */
vdso_join_timens(struct task_struct * task,struct time_namespace * ns)11574205b3fSChristophe Leroy int vdso_join_timens(struct task_struct *task, struct time_namespace *ns)
11674205b3fSChristophe Leroy {
11774205b3fSChristophe Leroy struct mm_struct *mm = task->mm;
118405e6691SMatthew Wilcox (Oracle) VMA_ITERATOR(vmi, mm, 0);
11974205b3fSChristophe Leroy struct vm_area_struct *vma;
12074205b3fSChristophe Leroy
12174205b3fSChristophe Leroy mmap_read_lock(mm);
122405e6691SMatthew Wilcox (Oracle) for_each_vma(vmi, vma) {
12374205b3fSChristophe Leroy if (vma_is_special_mapping(vma, &vvar_spec))
124*e9adcfecSMike Kravetz zap_vma_pages(vma);
12574205b3fSChristophe Leroy }
12674205b3fSChristophe Leroy mmap_read_unlock(mm);
127405e6691SMatthew Wilcox (Oracle)
12874205b3fSChristophe Leroy return 0;
12974205b3fSChristophe Leroy }
13074205b3fSChristophe Leroy #endif
13174205b3fSChristophe Leroy
vvar_fault(const struct vm_special_mapping * sm,struct vm_area_struct * vma,struct vm_fault * vmf)13274205b3fSChristophe Leroy static vm_fault_t vvar_fault(const struct vm_special_mapping *sm,
13374205b3fSChristophe Leroy struct vm_area_struct *vma, struct vm_fault *vmf)
13474205b3fSChristophe Leroy {
13574205b3fSChristophe Leroy struct page *timens_page = find_timens_vvar_page(vma);
13674205b3fSChristophe Leroy unsigned long pfn;
13774205b3fSChristophe Leroy
13874205b3fSChristophe Leroy switch (vmf->pgoff) {
13974205b3fSChristophe Leroy case VVAR_DATA_PAGE_OFFSET:
14074205b3fSChristophe Leroy if (timens_page)
14174205b3fSChristophe Leroy pfn = page_to_pfn(timens_page);
14274205b3fSChristophe Leroy else
14374205b3fSChristophe Leroy pfn = virt_to_pfn(vdso_data);
14474205b3fSChristophe Leroy break;
14574205b3fSChristophe Leroy #ifdef CONFIG_TIME_NS
14674205b3fSChristophe Leroy case VVAR_TIMENS_PAGE_OFFSET:
14774205b3fSChristophe Leroy /*
14874205b3fSChristophe Leroy * If a task belongs to a time namespace then a namespace
14974205b3fSChristophe Leroy * specific VVAR is mapped with the VVAR_DATA_PAGE_OFFSET and
15074205b3fSChristophe Leroy * the real VVAR page is mapped with the VVAR_TIMENS_PAGE_OFFSET
15174205b3fSChristophe Leroy * offset.
15274205b3fSChristophe Leroy * See also the comment near timens_setup_vdso_data().
15374205b3fSChristophe Leroy */
15474205b3fSChristophe Leroy if (!timens_page)
15574205b3fSChristophe Leroy return VM_FAULT_SIGBUS;
15674205b3fSChristophe Leroy pfn = virt_to_pfn(vdso_data);
15774205b3fSChristophe Leroy break;
15874205b3fSChristophe Leroy #endif /* CONFIG_TIME_NS */
15974205b3fSChristophe Leroy default:
16074205b3fSChristophe Leroy return VM_FAULT_SIGBUS;
16174205b3fSChristophe Leroy }
16274205b3fSChristophe Leroy
16374205b3fSChristophe Leroy return vmf_insert_pfn(vma, vmf->address, pfn);
16474205b3fSChristophe Leroy }
16574205b3fSChristophe Leroy
166a7f290daSBenjamin Herrenschmidt /*
167a7f290daSBenjamin Herrenschmidt * This is called from binfmt_elf, we create the special vma for the
168a7f290daSBenjamin Herrenschmidt * vDSO and insert it into the mm struct tree
169a7f290daSBenjamin Herrenschmidt */
__arch_setup_additional_pages(struct linux_binprm * bprm,int uses_interp)170b2df3f60SChristophe Leroy static int __arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
171a7f290daSBenjamin Herrenschmidt {
1721c4bce67SDmitry Safonov unsigned long vdso_size, vdso_base, mappings_size;
173c1bab643SChristophe Leroy struct vm_special_mapping *vdso_spec;
17474205b3fSChristophe Leroy unsigned long vvar_size = VVAR_NR_PAGES * PAGE_SIZE;
1751c4bce67SDmitry Safonov struct mm_struct *mm = current->mm;
176c1bab643SChristophe Leroy struct vm_area_struct *vma;
177a7f290daSBenjamin Herrenschmidt
178cab175f9SDenis Kirjanov if (is_32bit_task()) {
179c1bab643SChristophe Leroy vdso_spec = &vdso32_spec;
1807461a4f7SChristophe Leroy vdso_size = &vdso32_end - &vdso32_start;
181a7f290daSBenjamin Herrenschmidt } else {
182c1bab643SChristophe Leroy vdso_spec = &vdso64_spec;
1837461a4f7SChristophe Leroy vdso_size = &vdso64_end - &vdso64_start;
184a7f290daSBenjamin Herrenschmidt }
185a7f290daSBenjamin Herrenschmidt
1861c4bce67SDmitry Safonov mappings_size = vdso_size + vvar_size;
1871c4bce67SDmitry Safonov mappings_size += (VDSO_ALIGNMENT - 1) & PAGE_MASK;
188a7f290daSBenjamin Herrenschmidt
189a7f290daSBenjamin Herrenschmidt /*
1908a8f7866SChristophe Leroy * Pick a base address for the vDSO in process space.
191348aa303SAndreas Schwab * Add enough to the size so that the result can be aligned.
192a7f290daSBenjamin Herrenschmidt */
1938a8f7866SChristophe Leroy vdso_base = get_unmapped_area(NULL, 0, mappings_size, 0, 0);
194b2df3f60SChristophe Leroy if (IS_ERR_VALUE(vdso_base))
195b2df3f60SChristophe Leroy return vdso_base;
196a7f290daSBenjamin Herrenschmidt
197348aa303SAndreas Schwab /* Add required alignment. */
198348aa303SAndreas Schwab vdso_base = ALIGN(vdso_base, VDSO_ALIGNMENT);
199348aa303SAndreas Schwab
200a7f290daSBenjamin Herrenschmidt /*
201f2053f1aSAnton Blanchard * Put vDSO base into mm struct. We need to do this before calling
202f2053f1aSAnton Blanchard * install_special_mapping or the perf counter mmap tracking code
203c1bab643SChristophe Leroy * will fail to recognise it as a vDSO.
204f2053f1aSAnton Blanchard */
2051c4bce67SDmitry Safonov mm->context.vdso = (void __user *)vdso_base + vvar_size;
2061c4bce67SDmitry Safonov
2071c4bce67SDmitry Safonov vma = _install_special_mapping(mm, vdso_base, vvar_size,
2081c4bce67SDmitry Safonov VM_READ | VM_MAYREAD | VM_IO |
2091c4bce67SDmitry Safonov VM_DONTDUMP | VM_PFNMAP, &vvar_spec);
2101c4bce67SDmitry Safonov if (IS_ERR(vma))
2111c4bce67SDmitry Safonov return PTR_ERR(vma);
212f2053f1aSAnton Blanchard
213f2053f1aSAnton Blanchard /*
214a7f290daSBenjamin Herrenschmidt * our vma flags don't have VM_WRITE so by default, the process isn't
215a7f290daSBenjamin Herrenschmidt * allowed to write those pages.
216a7f290daSBenjamin Herrenschmidt * gdb can break that with ptrace interface, and thus trigger COW on
217a7f290daSBenjamin Herrenschmidt * those pages but it's then your responsibility to never do that on
218a7f290daSBenjamin Herrenschmidt * the "data" page of the vDSO or you'll stop getting kernel updates
219a7f290daSBenjamin Herrenschmidt * and your nice userland gettimeofday will be totally dead.
220a7f290daSBenjamin Herrenschmidt * It's fine to use that for setting breakpoints in the vDSO code
221909af768SJason Baron * pages though.
2223a0cfadbSRoland McGrath */
2231c4bce67SDmitry Safonov vma = _install_special_mapping(mm, vdso_base + vvar_size, vdso_size,
224c1bab643SChristophe Leroy VM_READ | VM_EXEC | VM_MAYREAD |
225c1bab643SChristophe Leroy VM_MAYWRITE | VM_MAYEXEC, vdso_spec);
2261c4bce67SDmitry Safonov if (IS_ERR(vma))
2271c4bce67SDmitry Safonov do_munmap(mm, vdso_base, vvar_size, NULL);
2281c4bce67SDmitry Safonov
229c1bab643SChristophe Leroy return PTR_ERR_OR_ZERO(vma);
230f2053f1aSAnton Blanchard }
231c13e4ca2SRoland McGrath
arch_setup_additional_pages(struct linux_binprm * bprm,int uses_interp)232b2df3f60SChristophe Leroy int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
233b2df3f60SChristophe Leroy {
234b2df3f60SChristophe Leroy struct mm_struct *mm = current->mm;
235b2df3f60SChristophe Leroy int rc;
236b2df3f60SChristophe Leroy
237c102f076SChristophe Leroy mm->context.vdso = NULL;
238b2df3f60SChristophe Leroy
239b2df3f60SChristophe Leroy if (mmap_write_lock_killable(mm))
240b2df3f60SChristophe Leroy return -EINTR;
241b2df3f60SChristophe Leroy
242b2df3f60SChristophe Leroy rc = __arch_setup_additional_pages(bprm, uses_interp);
243b2df3f60SChristophe Leroy if (rc)
244c102f076SChristophe Leroy mm->context.vdso = NULL;
245b2df3f60SChristophe Leroy
246d8ed45c5SMichel Lespinasse mmap_write_unlock(mm);
247a5bba930SBenjamin Herrenschmidt return rc;
248a7f290daSBenjamin Herrenschmidt }
249a7f290daSBenjamin Herrenschmidt
250ed07f635SChristophe Leroy #define VDSO_DO_FIXUPS(type, value, bits, sec) do { \
251ed07f635SChristophe Leroy void *__start = (void *)VDSO##bits##_SYMBOL(&vdso##bits##_start, sec##_start); \
252ed07f635SChristophe Leroy void *__end = (void *)VDSO##bits##_SYMBOL(&vdso##bits##_start, sec##_end); \
253ed07f635SChristophe Leroy \
254ed07f635SChristophe Leroy do_##type##_fixups((value), __start, __end); \
255ed07f635SChristophe Leroy } while (0)
256a7f290daSBenjamin Herrenschmidt
vdso_fixup_features(void)257a4ccd64aSChristophe Leroy static void __init vdso_fixup_features(void)
2580909c8c2SBenjamin Herrenschmidt {
2590909c8c2SBenjamin Herrenschmidt #ifdef CONFIG_PPC64
260ed07f635SChristophe Leroy VDSO_DO_FIXUPS(feature, cur_cpu_spec->cpu_features, 64, ftr_fixup);
261ed07f635SChristophe Leroy VDSO_DO_FIXUPS(feature, cur_cpu_spec->mmu_features, 64, mmu_ftr_fixup);
262ed07f635SChristophe Leroy VDSO_DO_FIXUPS(feature, powerpc_firmware_features, 64, fw_ftr_fixup);
263ed07f635SChristophe Leroy VDSO_DO_FIXUPS(lwsync, cur_cpu_spec->cpu_features, 64, lwsync_fixup);
2640909c8c2SBenjamin Herrenschmidt #endif /* CONFIG_PPC64 */
2650909c8c2SBenjamin Herrenschmidt
266e0d00591SMichael Ellerman #ifdef CONFIG_VDSO32
267ed07f635SChristophe Leroy VDSO_DO_FIXUPS(feature, cur_cpu_spec->cpu_features, 32, ftr_fixup);
268ed07f635SChristophe Leroy VDSO_DO_FIXUPS(feature, cur_cpu_spec->mmu_features, 32, mmu_ftr_fixup);
2690909c8c2SBenjamin Herrenschmidt #ifdef CONFIG_PPC64
270ed07f635SChristophe Leroy VDSO_DO_FIXUPS(feature, powerpc_firmware_features, 32, fw_ftr_fixup);
2710909c8c2SBenjamin Herrenschmidt #endif /* CONFIG_PPC64 */
272ed07f635SChristophe Leroy VDSO_DO_FIXUPS(lwsync, cur_cpu_spec->cpu_features, 32, lwsync_fixup);
273e0d00591SMichael Ellerman #endif
274a7f290daSBenjamin Herrenschmidt }
275a7f290daSBenjamin Herrenschmidt
276a7f290daSBenjamin Herrenschmidt /*
277a7f290daSBenjamin Herrenschmidt * Called from setup_arch to initialize the bitmap of available
278a7f290daSBenjamin Herrenschmidt * syscalls in the systemcfg page
279a7f290daSBenjamin Herrenschmidt */
vdso_setup_syscall_map(void)280a7f290daSBenjamin Herrenschmidt static void __init vdso_setup_syscall_map(void)
281a7f290daSBenjamin Herrenschmidt {
282a7f290daSBenjamin Herrenschmidt unsigned int i;
283a7f290daSBenjamin Herrenschmidt
284f43194e4SRashmica Gupta for (i = 0; i < NR_syscalls; i++) {
2858640de0dSRohan McLure if (sys_call_table[i] != (void *)&sys_ni_syscall)
2861bb30b7aSChristophe Leroy vdso_data->syscall_map[i >> 5] |= 0x80000000UL >> (i & 0x1f);
2870a7601b6SMichal Suchanek if (IS_ENABLED(CONFIG_COMPAT) &&
2888640de0dSRohan McLure compat_sys_call_table[i] != (void *)&sys_ni_syscall)
2891bb30b7aSChristophe Leroy vdso_data->compat_syscall_map[i >> 5] |= 0x80000000UL >> (i & 0x1f);
290a7f290daSBenjamin Herrenschmidt }
291a7f290daSBenjamin Herrenschmidt }
292a7f290daSBenjamin Herrenschmidt
29318ad51ddSAnton Blanchard #ifdef CONFIG_PPC64
vdso_getcpu_init(void)294061d19f2SPaul Gortmaker int vdso_getcpu_init(void)
29518ad51ddSAnton Blanchard {
29618ad51ddSAnton Blanchard unsigned long cpu, node, val;
29718ad51ddSAnton Blanchard
29818ad51ddSAnton Blanchard /*
2999d378dfaSScott Wood * SPRG_VDSO contains the CPU in the bottom 16 bits and the NUMA node
3009d378dfaSScott Wood * in the next 16 bits. The VDSO uses this to implement getcpu().
30118ad51ddSAnton Blanchard */
30218ad51ddSAnton Blanchard cpu = get_cpu();
30318ad51ddSAnton Blanchard WARN_ON_ONCE(cpu > 0xffff);
30418ad51ddSAnton Blanchard
30518ad51ddSAnton Blanchard node = cpu_to_node(cpu);
30618ad51ddSAnton Blanchard WARN_ON_ONCE(node > 0xffff);
30718ad51ddSAnton Blanchard
308a9f675f9SMilton Miller val = (cpu & 0xffff) | ((node & 0xffff) << 16);
3099d378dfaSScott Wood mtspr(SPRN_SPRG_VDSO_WRITE, val);
3109d378dfaSScott Wood get_paca()->sprg_vdso = val;
31118ad51ddSAnton Blanchard
31218ad51ddSAnton Blanchard put_cpu();
31318ad51ddSAnton Blanchard
31418ad51ddSAnton Blanchard return 0;
31518ad51ddSAnton Blanchard }
31618ad51ddSAnton Blanchard /* We need to call this before SMP init */
31718ad51ddSAnton Blanchard early_initcall(vdso_getcpu_init);
31818ad51ddSAnton Blanchard #endif
319a7f290daSBenjamin Herrenschmidt
vdso_setup_pages(void * start,void * end)3203cf63825SChristophe Leroy static struct page ** __init vdso_setup_pages(void *start, void *end)
321a7f290daSBenjamin Herrenschmidt {
322a7f290daSBenjamin Herrenschmidt int i;
3233cf63825SChristophe Leroy struct page **pagelist;
3243cf63825SChristophe Leroy int pages = (end - start) >> PAGE_SHIFT;
325a7f290daSBenjamin Herrenschmidt
3263cf63825SChristophe Leroy pagelist = kcalloc(pages + 1, sizeof(struct page *), GFP_KERNEL);
3273cf63825SChristophe Leroy if (!pagelist)
3283cf63825SChristophe Leroy panic("%s: Cannot allocate page list for VDSO", __func__);
3293cf63825SChristophe Leroy
330511157abSChristophe Leroy for (i = 0; i < pages; i++)
3311c4bce67SDmitry Safonov pagelist[i] = virt_to_page(start + i * PAGE_SIZE);
3323cf63825SChristophe Leroy
3333cf63825SChristophe Leroy return pagelist;
3343cf63825SChristophe Leroy }
3353cf63825SChristophe Leroy
vdso_init(void)3363cf63825SChristophe Leroy static int __init vdso_init(void)
3373cf63825SChristophe Leroy {
338a7f290daSBenjamin Herrenschmidt #ifdef CONFIG_PPC64
339a7f290daSBenjamin Herrenschmidt /*
34006fe9fb4SDirk Hohndel * Fill up the "systemcfg" stuff for backward compatibility
341a7f290daSBenjamin Herrenschmidt */
34231fe5bf6SSegher Boessenkool strcpy((char *)vdso_data->eye_catcher, "SYSTEMCFG:PPC64");
343a7f290daSBenjamin Herrenschmidt vdso_data->version.major = SYSTEMCFG_MAJOR;
344a7f290daSBenjamin Herrenschmidt vdso_data->version.minor = SYSTEMCFG_MINOR;
345a7f290daSBenjamin Herrenschmidt vdso_data->processor = mfspr(SPRN_PVR);
346e8222502SBenjamin Herrenschmidt /*
3471d9a4731SStephen Rothwell * Fake the old platform number for pSeries and add
348e8222502SBenjamin Herrenschmidt * in LPAR bit if necessary
349e8222502SBenjamin Herrenschmidt */
3501d9a4731SStephen Rothwell vdso_data->platform = 0x100;
351e8222502SBenjamin Herrenschmidt if (firmware_has_feature(FW_FEATURE_LPAR))
352e8222502SBenjamin Herrenschmidt vdso_data->platform |= 1;
35395f72d1eSYinghai Lu vdso_data->physicalMemorySize = memblock_phys_mem_size();
354e2827fe5SBenjamin Herrenschmidt vdso_data->dcache_size = ppc64_caches.l1d.size;
355e2827fe5SBenjamin Herrenschmidt vdso_data->dcache_line_size = ppc64_caches.l1d.line_size;
356e2827fe5SBenjamin Herrenschmidt vdso_data->icache_size = ppc64_caches.l1i.size;
357e2827fe5SBenjamin Herrenschmidt vdso_data->icache_line_size = ppc64_caches.l1i.line_size;
358e2827fe5SBenjamin Herrenschmidt vdso_data->dcache_block_size = ppc64_caches.l1d.block_size;
359e2827fe5SBenjamin Herrenschmidt vdso_data->icache_block_size = ppc64_caches.l1i.block_size;
360e2827fe5SBenjamin Herrenschmidt vdso_data->dcache_log_block_size = ppc64_caches.l1d.log_block_size;
361e2827fe5SBenjamin Herrenschmidt vdso_data->icache_log_block_size = ppc64_caches.l1i.log_block_size;
3624fe0e3c1SChristophe Leroy #endif /* CONFIG_PPC64 */
363fbe48175SOlof Johansson
364a7f290daSBenjamin Herrenschmidt vdso_setup_syscall_map();
3650909c8c2SBenjamin Herrenschmidt
366a4ccd64aSChristophe Leroy vdso_fixup_features();
367a7f290daSBenjamin Herrenschmidt
3684fe0e3c1SChristophe Leroy if (IS_ENABLED(CONFIG_VDSO32))
369c1bab643SChristophe Leroy vdso32_spec.pages = vdso_setup_pages(&vdso32_start, &vdso32_end);
370c13e4ca2SRoland McGrath
3714fe0e3c1SChristophe Leroy if (IS_ENABLED(CONFIG_PPC64))
372c1bab643SChristophe Leroy vdso64_spec.pages = vdso_setup_pages(&vdso64_start, &vdso64_end);
373a7f290daSBenjamin Herrenschmidt
3747ac9a137SBenjamin Herrenschmidt smp_wmb();
3757ac9a137SBenjamin Herrenschmidt
3767ac9a137SBenjamin Herrenschmidt return 0;
377a7f290daSBenjamin Herrenschmidt }
3787ac9a137SBenjamin Herrenschmidt arch_initcall(vdso_init);
379