18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2011 Richard Weinberger <richrd@nod.at> 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/slab.h> 78c2ecf20Sopenharmony_ci#include <linux/sched.h> 88c2ecf20Sopenharmony_ci#include <linux/mm.h> 98c2ecf20Sopenharmony_ci#include <asm/page.h> 108c2ecf20Sopenharmony_ci#include <asm/elf.h> 118c2ecf20Sopenharmony_ci#include <linux/init.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_cistatic unsigned int __read_mostly vdso_enabled = 1; 148c2ecf20Sopenharmony_ciunsigned long um_vdso_addr; 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ciextern unsigned long task_size; 178c2ecf20Sopenharmony_ciextern char vdso_start[], vdso_end[]; 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic struct page **vdsop; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic int __init init_vdso(void) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci struct page *um_vdso; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci BUG_ON(vdso_end - vdso_start > PAGE_SIZE); 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci um_vdso_addr = task_size - PAGE_SIZE; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci vdsop = kmalloc(sizeof(struct page *), GFP_KERNEL); 308c2ecf20Sopenharmony_ci if (!vdsop) 318c2ecf20Sopenharmony_ci goto oom; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci um_vdso = alloc_page(GFP_KERNEL); 348c2ecf20Sopenharmony_ci if (!um_vdso) { 358c2ecf20Sopenharmony_ci kfree(vdsop); 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci goto oom; 388c2ecf20Sopenharmony_ci } 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci copy_page(page_address(um_vdso), vdso_start); 418c2ecf20Sopenharmony_ci *vdsop = um_vdso; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci return 0; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cioom: 468c2ecf20Sopenharmony_ci printk(KERN_ERR "Cannot allocate vdso\n"); 478c2ecf20Sopenharmony_ci vdso_enabled = 0; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci return -ENOMEM; 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_cisubsys_initcall(init_vdso); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ciint arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci int err; 568c2ecf20Sopenharmony_ci struct mm_struct *mm = current->mm; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci if (!vdso_enabled) 598c2ecf20Sopenharmony_ci return 0; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci if (mmap_write_lock_killable(mm)) 628c2ecf20Sopenharmony_ci return -EINTR; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci err = install_special_mapping(mm, um_vdso_addr, PAGE_SIZE, 658c2ecf20Sopenharmony_ci VM_READ|VM_EXEC| 668c2ecf20Sopenharmony_ci VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC, 678c2ecf20Sopenharmony_ci vdsop); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci mmap_write_unlock(mm); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci return err; 728c2ecf20Sopenharmony_ci} 73