efi.c 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (C) 2020 Western Digital Corporation or its affiliates.
  4. * Adapted from arch/arm64/kernel/efi.c
  5. */
  6. #include <linux/efi.h>
  7. #include <linux/init.h>
  8. #include <asm/efi.h>
  9. #include <asm/pgtable.h>
  10. #include <asm/pgtable-bits.h>
  11. /*
  12. * Only regions of type EFI_RUNTIME_SERVICES_CODE need to be
  13. * executable, everything else can be mapped with the XN bits
  14. * set. Also take the new (optional) RO/XP bits into account.
  15. */
  16. static __init pgprot_t efimem_to_pgprot_map(efi_memory_desc_t *md)
  17. {
  18. u64 attr = md->attribute;
  19. u32 type = md->type;
  20. if (type == EFI_MEMORY_MAPPED_IO)
  21. return PAGE_KERNEL;
  22. /* R-- */
  23. if ((attr & (EFI_MEMORY_XP | EFI_MEMORY_RO)) ==
  24. (EFI_MEMORY_XP | EFI_MEMORY_RO))
  25. return PAGE_KERNEL_READ;
  26. /* R-X */
  27. if (attr & EFI_MEMORY_RO)
  28. return PAGE_KERNEL_READ_EXEC;
  29. /* RW- */
  30. if (((attr & (EFI_MEMORY_RP | EFI_MEMORY_WP | EFI_MEMORY_XP)) ==
  31. EFI_MEMORY_XP) ||
  32. type != EFI_RUNTIME_SERVICES_CODE)
  33. return PAGE_KERNEL;
  34. /* RWX */
  35. return PAGE_KERNEL_EXEC;
  36. }
  37. int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md)
  38. {
  39. pgprot_t prot = __pgprot(pgprot_val(efimem_to_pgprot_map(md)) &
  40. ~(_PAGE_GLOBAL));
  41. int i;
  42. /* RISC-V maps one page at a time */
  43. for (i = 0; i < md->num_pages; i++)
  44. create_pgd_mapping(mm->pgd, md->virt_addr + i * PAGE_SIZE,
  45. md->phys_addr + i * PAGE_SIZE,
  46. PAGE_SIZE, prot);
  47. return 0;
  48. }
  49. static int __init set_permissions(pte_t *ptep, unsigned long addr, void *data)
  50. {
  51. efi_memory_desc_t *md = data;
  52. pte_t pte = READ_ONCE(*ptep);
  53. unsigned long val;
  54. if (md->attribute & EFI_MEMORY_RO) {
  55. val = pte_val(pte) & ~_PAGE_WRITE;
  56. val = pte_val(pte) | _PAGE_READ;
  57. pte = __pte(val);
  58. }
  59. if (md->attribute & EFI_MEMORY_XP) {
  60. val = pte_val(pte) & ~_PAGE_EXEC;
  61. pte = __pte(val);
  62. }
  63. set_pte(ptep, pte);
  64. return 0;
  65. }
  66. int __init efi_set_mapping_permissions(struct mm_struct *mm,
  67. efi_memory_desc_t *md)
  68. {
  69. BUG_ON(md->type != EFI_RUNTIME_SERVICES_CODE &&
  70. md->type != EFI_RUNTIME_SERVICES_DATA);
  71. /*
  72. * Calling apply_to_page_range() is only safe on regions that are
  73. * guaranteed to be mapped down to pages. Since we are only called
  74. * for regions that have been mapped using efi_create_mapping() above
  75. * (and this is checked by the generic Memory Attributes table parsing
  76. * routines), there is no need to check that again here.
  77. */
  78. return apply_to_page_range(mm, md->virt_addr,
  79. md->num_pages << EFI_PAGE_SHIFT,
  80. set_permissions, md);
  81. }