forked from Minki/linux
caab277b1d
Based on 1 normalized pattern(s): this program is free software you can redistribute it and or modify it under the terms of the gnu general public license version 2 as published by the free software foundation this program is distributed in the hope that it will be useful but without any warranty without even the implied warranty of merchantability or fitness for a particular purpose see the gnu general public license for more details you should have received a copy of the gnu general public license along with this program if not see http www gnu org licenses extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference in 503 file(s). Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Alexios Zavras <alexios.zavras@intel.com> Reviewed-by: Allison Randal <allison@lohutok.net> Reviewed-by: Enrico Weigelt <info@metux.net> Cc: linux-spdx@vger.kernel.org Link: https://lkml.kernel.org/r/20190602204653.811534538@linutronix.de Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
114 lines
2.4 KiB
C
114 lines
2.4 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Copyright (C) 2004 Benjamin Herrenschmidt, IBM Corp.
|
|
* <benh@kernel.crashing.org>
|
|
* Copyright (C) 2012 ARM Limited
|
|
* Copyright (C) 2015 Regents of the University of California
|
|
*/
|
|
|
|
#include <linux/mm.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/binfmts.h>
|
|
#include <linux/err.h>
|
|
|
|
#include <asm/vdso.h>
|
|
|
|
extern char vdso_start[], vdso_end[];
|
|
|
|
static unsigned int vdso_pages;
|
|
static struct page **vdso_pagelist;
|
|
|
|
/*
|
|
* The vDSO data page.
|
|
*/
|
|
static union {
|
|
struct vdso_data data;
|
|
u8 page[PAGE_SIZE];
|
|
} vdso_data_store __page_aligned_data;
|
|
struct vdso_data *vdso_data = &vdso_data_store.data;
|
|
|
|
static int __init vdso_init(void)
|
|
{
|
|
unsigned int i;
|
|
|
|
vdso_pages = (vdso_end - vdso_start) >> PAGE_SHIFT;
|
|
vdso_pagelist =
|
|
kcalloc(vdso_pages + 1, sizeof(struct page *), GFP_KERNEL);
|
|
if (unlikely(vdso_pagelist == NULL)) {
|
|
pr_err("vdso: pagelist allocation failed\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
for (i = 0; i < vdso_pages; i++) {
|
|
struct page *pg;
|
|
|
|
pg = virt_to_page(vdso_start + (i << PAGE_SHIFT));
|
|
vdso_pagelist[i] = pg;
|
|
}
|
|
vdso_pagelist[i] = virt_to_page(vdso_data);
|
|
|
|
return 0;
|
|
}
|
|
arch_initcall(vdso_init);
|
|
|
|
int arch_setup_additional_pages(struct linux_binprm *bprm,
|
|
int uses_interp)
|
|
{
|
|
struct mm_struct *mm = current->mm;
|
|
unsigned long vdso_base, vdso_len;
|
|
int ret;
|
|
|
|
vdso_len = (vdso_pages + 1) << PAGE_SHIFT;
|
|
|
|
down_write(&mm->mmap_sem);
|
|
vdso_base = get_unmapped_area(NULL, 0, vdso_len, 0, 0);
|
|
if (IS_ERR_VALUE(vdso_base)) {
|
|
ret = vdso_base;
|
|
goto end;
|
|
}
|
|
|
|
/*
|
|
* Put vDSO base into mm struct. We need to do this before calling
|
|
* install_special_mapping or the perf counter mmap tracking code
|
|
* will fail to recognise it as a vDSO (since arch_vma_name fails).
|
|
*/
|
|
mm->context.vdso = (void *)vdso_base;
|
|
|
|
ret = install_special_mapping(mm, vdso_base, vdso_len,
|
|
(VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC),
|
|
vdso_pagelist);
|
|
|
|
if (unlikely(ret))
|
|
mm->context.vdso = NULL;
|
|
|
|
end:
|
|
up_write(&mm->mmap_sem);
|
|
return ret;
|
|
}
|
|
|
|
const char *arch_vma_name(struct vm_area_struct *vma)
|
|
{
|
|
if (vma->vm_mm && (vma->vm_start == (long)vma->vm_mm->context.vdso))
|
|
return "[vdso]";
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Function stubs to prevent linker errors when AT_SYSINFO_EHDR is defined
|
|
*/
|
|
|
|
int in_gate_area_no_mm(unsigned long addr)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int in_gate_area(struct mm_struct *mm, unsigned long addr)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
|
|
{
|
|
return NULL;
|
|
}
|