pageattr.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  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. }
  98. #ifdef CONFIG_DEBUG_PAGEALLOC
  99. void kernel_map_pages(struct page *page, int numpages, int enable)
  100. {
  101. unsigned long address;
  102. pgd_t *pgd;
  103. pud_t *pud;
  104. pmd_t *pmd;
  105. pte_t *pte;
  106. int i;
  107. for (i = 0; i < numpages; i++) {
  108. address = page_to_phys(page + i);
  109. pgd = pgd_offset_k(address);
  110. pud = pud_offset(pgd, address);
  111. pmd = pmd_offset(pud, address);
  112. pte = pte_offset_kernel(pmd, address);
  113. if (!enable) {
  114. __ptep_ipte(address, pte);
  115. pte_val(*pte) = _PAGE_TYPE_EMPTY;
  116. continue;
  117. }
  118. pte_val(*pte) = __pa(address);
  119. }
  120. }
  121. #ifdef CONFIG_HIBERNATION
  122. bool kernel_page_present(struct page *page)
  123. {
  124. unsigned long addr;
  125. int cc;
  126. addr = page_to_phys(page);
  127. asm volatile(
  128. " lra %1,0(%1)\n"
  129. " ipm %0\n"
  130. " srl %0,28"
  131. : "=d" (cc), "+a" (addr) : : "cc");
  132. return cc == 0;
  133. }
  134. #endif /* CONFIG_HIBERNATION */
  135. #endif /* CONFIG_DEBUG_PAGEALLOC */