kfence.h 1.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. #ifndef _ASM_RISCV_KFENCE_H
  3. #define _ASM_RISCV_KFENCE_H
  4. #include <linux/kfence.h>
  5. #include <linux/pfn.h>
  6. #include <asm-generic/pgalloc.h>
  7. #include <asm/pgtable.h>
  8. static inline int split_pmd_page(unsigned long addr)
  9. {
  10. int i;
  11. unsigned long pfn = PFN_DOWN(__pa((addr & PMD_MASK)));
  12. pmd_t *pmd = pmd_off_k(addr);
  13. pte_t *pte = pte_alloc_one_kernel(&init_mm);
  14. if (!pte)
  15. return -ENOMEM;
  16. for (i = 0; i < PTRS_PER_PTE; i++)
  17. set_pte(pte + i, pfn_pte(pfn + i, PAGE_KERNEL));
  18. set_pmd(pmd, pfn_pmd(PFN_DOWN(__pa(pte)), PAGE_TABLE));
  19. flush_tlb_kernel_range(addr, addr + PMD_SIZE);
  20. return 0;
  21. }
  22. static inline bool arch_kfence_init_pool(void)
  23. {
  24. int ret;
  25. unsigned long addr;
  26. pmd_t *pmd;
  27. for (addr = (unsigned long)__kfence_pool; is_kfence_address((void *)addr);
  28. addr += PAGE_SIZE) {
  29. pmd = pmd_off_k(addr);
  30. if (pmd_leaf(*pmd)) {
  31. ret = split_pmd_page(addr);
  32. if (ret)
  33. return false;
  34. }
  35. }
  36. return true;
  37. }
  38. static inline bool kfence_protect_page(unsigned long addr, bool protect)
  39. {
  40. pte_t *pte = virt_to_kpte(addr);
  41. if (protect)
  42. set_pte(pte, __pte(pte_val(*pte) & ~_PAGE_PRESENT));
  43. else
  44. set_pte(pte, __pte(pte_val(*pte) | _PAGE_PRESENT));
  45. flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
  46. return true;
  47. }
  48. #endif /* _ASM_RISCV_KFENCE_H */