user_accessible_timer.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. /* Copyright (c) 2012, The Linux Foundation. All rights reserved.
  2. *
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License version 2 and
  5. * only version 2 as published by the Free Software Foundation.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. */
  12. #include <linux/export.h>
  13. #include <linux/mm.h>
  14. #include <linux/sched.h>
  15. #include <asm/user_accessible_timer.h>
  16. #include <asm/traps.h>
  17. #define USER_ACCESS_TIMER_OFFSET 0xf30
  18. #define USER_ACCESS_FEATURE_OFFSET 0xf34
  19. #define USER_ACCESS_FEATURE_FLAG 0xffff0f20
  20. static struct vm_area_struct user_timers_vma;
  21. static int __init user_timers_vma_init(void)
  22. {
  23. user_timers_vma.vm_start = CONFIG_ARM_USER_ACCESSIBLE_TIMER_BASE;
  24. user_timers_vma.vm_end = CONFIG_ARM_USER_ACCESSIBLE_TIMER_BASE
  25. + PAGE_SIZE;
  26. user_timers_vma.vm_page_prot = PAGE_READONLY;
  27. user_timers_vma.vm_flags = VM_READ | VM_MAYREAD;
  28. return 0;
  29. }
  30. arch_initcall(user_timers_vma_init);
  31. int in_user_timers_area(struct mm_struct *mm, unsigned long addr)
  32. {
  33. return (addr >= user_timers_vma.vm_start) &&
  34. (addr < user_timers_vma.vm_end);
  35. }
  36. EXPORT_SYMBOL(in_user_timers_area);
  37. struct vm_area_struct *get_user_timers_vma(struct mm_struct *mm)
  38. {
  39. return &user_timers_vma;
  40. }
  41. EXPORT_SYMBOL(get_user_timers_vma);
  42. int get_user_timer_page(struct vm_area_struct *vma,
  43. struct mm_struct *mm, unsigned long start, unsigned int gup_flags,
  44. struct page **pages, int idx, int *goto_next_page)
  45. {
  46. /* Replicates the earlier work done in mm/memory.c */
  47. unsigned long pg = start & PAGE_MASK;
  48. pgd_t *pgd;
  49. pud_t *pud;
  50. pmd_t *pmd;
  51. pte_t *pte;
  52. /* Unset this flag -- this only gets activated if the
  53. * caller should go straight to the next_page label on
  54. * return.
  55. */
  56. *goto_next_page = 0;
  57. /* user gate pages are read-only */
  58. if (gup_flags & FOLL_WRITE)
  59. return idx ? : -EFAULT;
  60. if (pg > TASK_SIZE)
  61. pgd = pgd_offset_k(pg);
  62. else
  63. pgd = pgd_offset_gate(mm, pg);
  64. BUG_ON(pgd_none(*pgd));
  65. pud = pud_offset(pgd, pg);
  66. BUG_ON(pud_none(*pud));
  67. pmd = pmd_offset(pud, pg);
  68. if (pmd_none(*pmd))
  69. return idx ? : -EFAULT;
  70. VM_BUG_ON(pmd_trans_huge(*pmd));
  71. pte = pte_offset_map(pmd, pg);
  72. if (pte_none(*pte)) {
  73. pte_unmap(pte);
  74. return idx ? : -EFAULT;
  75. }
  76. vma = get_user_timers_vma(mm);
  77. if (pages) {
  78. struct page *page;
  79. page = vm_normal_page(vma, start, *pte);
  80. if (!page) {
  81. if (!(gup_flags & FOLL_DUMP) &&
  82. zero_pfn == pte_pfn(*pte))
  83. page = pte_page(*pte);
  84. else {
  85. pte_unmap(pte);
  86. return idx ? : -EFAULT;
  87. }
  88. }
  89. pages[idx] = page;
  90. get_page(page);
  91. }
  92. pte_unmap(pte);
  93. /* In this case, set the next page */
  94. *goto_next_page = 1;
  95. return 0;
  96. }
  97. EXPORT_SYMBOL(get_user_timer_page);
  98. void setup_user_timer_offset(unsigned long addr)
  99. {
  100. #if defined(CONFIG_CPU_USE_DOMAINS)
  101. unsigned long vectors = CONFIG_VECTORS_BASE;
  102. #else
  103. unsigned long vectors = (unsigned long)vectors_page;
  104. #endif
  105. unsigned long *timer_offset = (unsigned long *)(vectors +
  106. USER_ACCESS_TIMER_OFFSET);
  107. *timer_offset = addr;
  108. }
  109. EXPORT_SYMBOL(setup_user_timer_offset);
  110. void set_user_accessible_timer_flag(bool flag)
  111. {
  112. #if defined(CONFIG_CPU_USE_DOMAINS)
  113. unsigned long vectors = CONFIG_VECTORS_BASE;
  114. #else
  115. unsigned long vectors = (unsigned long)vectors_page;
  116. #endif
  117. unsigned long *timer_offset = (unsigned long *)(vectors +
  118. USER_ACCESS_FEATURE_OFFSET);
  119. *timer_offset = (flag ? USER_ACCESS_FEATURE_FLAG : 0);
  120. }
  121. EXPORT_SYMBOL(set_user_accessible_timer_flag);