vdso.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Author: Huacai Chen <chenhuacai@loongson.cn>
  4. * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
  5. */
  6. #include <linux/binfmts.h>
  7. #include <linux/elf.h>
  8. #include <linux/err.h>
  9. #include <linux/init.h>
  10. #include <linux/ioport.h>
  11. #include <linux/kernel.h>
  12. #include <linux/mm.h>
  13. #include <linux/random.h>
  14. #include <linux/sched.h>
  15. #include <linux/slab.h>
  16. #include <linux/time_namespace.h>
  17. #include <linux/timekeeper_internal.h>
  18. #include <asm/page.h>
  19. #include <asm/vdso.h>
  20. #include <vdso/helpers.h>
  21. #include <vdso/vsyscall.h>
  22. #include <vdso/datapage.h>
  23. #include <generated/vdso-offsets.h>
  24. extern char vdso_start[], vdso_end[];
  25. /* Kernel-provided data used by the VDSO. */
  26. static union vdso_data_store generic_vdso_data __page_aligned_data;
  27. static union {
  28. u8 page[LOONGARCH_VDSO_DATA_SIZE];
  29. struct loongarch_vdso_data vdata;
  30. } loongarch_vdso_data __page_aligned_data;
  31. struct vdso_data *vdso_data = generic_vdso_data.data;
  32. struct vdso_pcpu_data *vdso_pdata = loongarch_vdso_data.vdata.pdata;
  33. struct vdso_rng_data *vdso_rng_data = &loongarch_vdso_data.vdata.rng_data;
  34. static int vdso_mremap(const struct vm_special_mapping *sm, struct vm_area_struct *new_vma)
  35. {
  36. current->mm->context.vdso = (void *)(new_vma->vm_start);
  37. return 0;
  38. }
  39. static vm_fault_t vvar_fault(const struct vm_special_mapping *sm,
  40. struct vm_area_struct *vma, struct vm_fault *vmf)
  41. {
  42. unsigned long pfn;
  43. struct page *timens_page = find_timens_vvar_page(vma);
  44. switch (vmf->pgoff) {
  45. case VVAR_GENERIC_PAGE_OFFSET:
  46. if (!timens_page)
  47. pfn = sym_to_pfn(vdso_data);
  48. else
  49. pfn = page_to_pfn(timens_page);
  50. break;
  51. #ifdef CONFIG_TIME_NS
  52. case VVAR_TIMENS_PAGE_OFFSET:
  53. /*
  54. * If a task belongs to a time namespace then a namespace specific
  55. * VVAR is mapped with the VVAR_GENERIC_PAGE_OFFSET and the real
  56. * VVAR page is mapped with the VVAR_TIMENS_PAGE_OFFSET offset.
  57. * See also the comment near timens_setup_vdso_data().
  58. */
  59. if (!timens_page)
  60. return VM_FAULT_SIGBUS;
  61. else
  62. pfn = sym_to_pfn(vdso_data);
  63. break;
  64. #endif /* CONFIG_TIME_NS */
  65. case VVAR_LOONGARCH_PAGES_START ... VVAR_LOONGARCH_PAGES_END:
  66. pfn = sym_to_pfn(&loongarch_vdso_data) + vmf->pgoff - VVAR_LOONGARCH_PAGES_START;
  67. break;
  68. default:
  69. return VM_FAULT_SIGBUS;
  70. }
  71. return vmf_insert_pfn(vma, vmf->address, pfn);
  72. }
  73. struct loongarch_vdso_info vdso_info = {
  74. .vdso = vdso_start,
  75. .code_mapping = {
  76. .name = "[vdso]",
  77. .mremap = vdso_mremap,
  78. },
  79. .data_mapping = {
  80. .name = "[vvar]",
  81. .fault = vvar_fault,
  82. },
  83. .offset_sigreturn = vdso_offset_sigreturn,
  84. };
  85. static int __init init_vdso(void)
  86. {
  87. unsigned long i, cpu, pfn;
  88. BUG_ON(!PAGE_ALIGNED(vdso_info.vdso));
  89. for_each_possible_cpu(cpu)
  90. vdso_pdata[cpu].node = cpu_to_node(cpu);
  91. vdso_info.size = PAGE_ALIGN(vdso_end - vdso_start);
  92. vdso_info.code_mapping.pages =
  93. kcalloc(vdso_info.size / PAGE_SIZE, sizeof(struct page *), GFP_KERNEL);
  94. if (!vdso_info.code_mapping.pages)
  95. return -ENOMEM;
  96. pfn = __phys_to_pfn(__pa_symbol(vdso_info.vdso));
  97. for (i = 0; i < vdso_info.size / PAGE_SIZE; i++)
  98. vdso_info.code_mapping.pages[i] = pfn_to_page(pfn + i);
  99. return 0;
  100. }
  101. subsys_initcall(init_vdso);
  102. #ifdef CONFIG_TIME_NS
  103. struct vdso_data *arch_get_vdso_data(void *vvar_page)
  104. {
  105. return (struct vdso_data *)(vvar_page);
  106. }
  107. /*
  108. * The vvar mapping contains data for a specific time namespace, so when a
  109. * task changes namespace we must unmap its vvar data for the old namespace.
  110. * Subsequent faults will map in data for the new namespace.
  111. *
  112. * For more details see timens_setup_vdso_data().
  113. */
  114. int vdso_join_timens(struct task_struct *task, struct time_namespace *ns)
  115. {
  116. struct mm_struct *mm = task->mm;
  117. struct vm_area_struct *vma;
  118. VMA_ITERATOR(vmi, mm, 0);
  119. mmap_read_lock(mm);
  120. for_each_vma(vmi, vma) {
  121. if (vma_is_special_mapping(vma, &vdso_info.data_mapping))
  122. zap_vma_pages(vma);
  123. }
  124. mmap_read_unlock(mm);
  125. return 0;
  126. }
  127. #endif
  128. static unsigned long vdso_base(void)
  129. {
  130. unsigned long base = STACK_TOP;
  131. if (current->flags & PF_RANDOMIZE) {
  132. base += get_random_u32_below(VDSO_RANDOMIZE_SIZE);
  133. base = PAGE_ALIGN(base);
  134. }
  135. return base;
  136. }
  137. int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
  138. {
  139. int ret;
  140. unsigned long size, data_addr, vdso_addr;
  141. struct mm_struct *mm = current->mm;
  142. struct vm_area_struct *vma;
  143. struct loongarch_vdso_info *info = current->thread.vdso;
  144. if (mmap_write_lock_killable(mm))
  145. return -EINTR;
  146. /*
  147. * Determine total area size. This includes the VDSO data itself
  148. * and the data pages.
  149. */
  150. size = VVAR_SIZE + info->size;
  151. data_addr = get_unmapped_area(NULL, vdso_base(), size, 0, 0);
  152. if (IS_ERR_VALUE(data_addr)) {
  153. ret = data_addr;
  154. goto out;
  155. }
  156. vma = _install_special_mapping(mm, data_addr, VVAR_SIZE,
  157. VM_READ | VM_MAYREAD | VM_PFNMAP,
  158. &info->data_mapping);
  159. if (IS_ERR(vma)) {
  160. ret = PTR_ERR(vma);
  161. goto out;
  162. }
  163. vdso_addr = data_addr + VVAR_SIZE;
  164. vma = _install_special_mapping(mm, vdso_addr, info->size,
  165. VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC,
  166. &info->code_mapping);
  167. if (IS_ERR(vma)) {
  168. ret = PTR_ERR(vma);
  169. goto out;
  170. }
  171. mm->context.vdso = (void *)vdso_addr;
  172. ret = 0;
  173. out:
  174. mmap_write_unlock(mm);
  175. return ret;
  176. }