pageattr.c 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. /*
  2. * Copyright IBM Corp. 2011
  3. * Author(s): Jan Glauber <jang@linux.vnet.ibm.com>
  4. */
  5. #include <linux/hugetlb.h>
  6. #include <linux/module.h>
  7. #include <linux/mm.h>
  8. #include <asm/cacheflush.h>
  9. #include <asm/pgtable.h>
  10. #include <asm/page.h>
  11. void storage_key_init_range(unsigned long start, unsigned long end)
  12. {
  13. unsigned long boundary, function, size;
  14. while (start < end) {
  15. if (MACHINE_HAS_EDAT2) {
  16. /* set storage keys for a 2GB frame */
  17. function = 0x22000 | PAGE_DEFAULT_KEY;
  18. size = 1UL << 31;
  19. boundary = (start + size) & ~(size - 1);
  20. if (boundary <= end) {
  21. do {
  22. start = pfmf(function, start);
  23. } while (start < boundary);
  24. continue;
  25. }
  26. }
  27. if (MACHINE_HAS_EDAT1) {
  28. /* set storage keys for a 1MB frame */
  29. function = 0x21000 | PAGE_DEFAULT_KEY;
  30. size = 1UL << 20;
  31. boundary = (start + size) & ~(size - 1);
  32. if (boundary <= end) {
  33. do {
  34. start = pfmf(function, start);
  35. } while (start < boundary);
  36. continue;
  37. }
  38. }
  39. page_set_storage_key(start, PAGE_DEFAULT_KEY, 0);
  40. start += PAGE_SIZE;
  41. }
  42. }
  43. static pte_t *walk_page_table(unsigned long addr)
  44. {
  45. pgd_t *pgdp;
  46. pud_t *pudp;
  47. pmd_t *pmdp;
  48. pte_t *ptep;
  49. pgdp = pgd_offset_k(addr);
  50. if (pgd_none(*pgdp))
  51. return NULL;
  52. pudp = pud_offset(pgdp, addr);
  53. if (pud_none(*pudp) || pud_large(*pudp))
  54. return NULL;
  55. pmdp = pmd_offset(pudp, addr);
  56. if (pmd_none(*pmdp) || pmd_large(*pmdp))
  57. return NULL;
  58. ptep = pte_offset_kernel(pmdp, addr);
  59. if (pte_none(*ptep))
  60. return NULL;
  61. return ptep;
  62. }
  63. static void change_page_attr(unsigned long addr, int numpages,
  64. pte_t (*set) (pte_t))
  65. {
  66. pte_t *ptep, pte;
  67. int i;
  68. for (i = 0; i < numpages; i++) {
  69. ptep = walk_page_table(addr);
  70. if (WARN_ON_ONCE(!ptep))
  71. break;
  72. pte = *ptep;
  73. pte = set(pte);
  74. __ptep_ipte(addr, ptep);
  75. *ptep = pte;
  76. addr += PAGE_SIZE;
  77. }
  78. }
  79. int set_memory_ro(unsigned long addr, int numpages)
  80. {
  81. change_page_attr(addr, numpages, pte_wrprotect);
  82. return 0;
  83. }
  84. int set_memory_rw(unsigned long addr, int numpages)
  85. {
  86. change_page_attr(addr, numpages, pte_mkwrite);
  87. return 0;
  88. }
  89. /* not possible */
  90. int set_memory_nx(unsigned long addr, int numpages)
  91. {
  92. return 0;
  93. }
  94. int set_memory_x(unsigned long addr, int numpages)
  95. {
  96. return 0;
  97. }