pgd.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. /*
  2. * linux/arch/arm/mm/pgd.c
  3. *
  4. * Copyright (C) 1998-2005 Russell King
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License version 2 as
  8. * published by the Free Software Foundation.
  9. */
  10. #include <linux/mm.h>
  11. #include <linux/gfp.h>
  12. #include <linux/highmem.h>
  13. #include <linux/slab.h>
  14. #include <asm/pgalloc.h>
  15. #include <asm/page.h>
  16. #include <asm/tlbflush.h>
  17. #include "mm.h"
  18. #ifdef CONFIG_ARM_LPAE
  19. #define __pgd_alloc() kmalloc(PTRS_PER_PGD * sizeof(pgd_t), GFP_KERNEL)
  20. #define __pgd_free(pgd) kfree(pgd)
  21. #else
  22. #define __pgd_alloc() (pgd_t *)__get_free_pages(GFP_KERNEL, 2)
  23. #define __pgd_free(pgd) free_pages((unsigned long)pgd, 2)
  24. #endif
  25. /*
  26. * need to get a 16k page for level 1
  27. */
  28. pgd_t *pgd_alloc(struct mm_struct *mm)
  29. {
  30. pgd_t *new_pgd, *init_pgd;
  31. pud_t *new_pud, *init_pud;
  32. pmd_t *new_pmd, *init_pmd;
  33. pte_t *new_pte, *init_pte;
  34. new_pgd = __pgd_alloc();
  35. if (!new_pgd)
  36. goto no_pgd;
  37. memset(new_pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
  38. /*
  39. * Copy over the kernel and IO PGD entries
  40. */
  41. init_pgd = pgd_offset_k(0);
  42. memcpy(new_pgd + USER_PTRS_PER_PGD, init_pgd + USER_PTRS_PER_PGD,
  43. (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
  44. clean_dcache_area(new_pgd, PTRS_PER_PGD * sizeof(pgd_t));
  45. #ifdef CONFIG_ARM_LPAE
  46. /*
  47. * Allocate PMD table for modules and pkmap mappings.
  48. */
  49. new_pud = pud_alloc(mm, new_pgd + pgd_index(MODULES_VADDR),
  50. MODULES_VADDR);
  51. if (!new_pud)
  52. goto no_pud;
  53. new_pmd = pmd_alloc(mm, new_pud, 0);
  54. if (!new_pmd)
  55. goto no_pmd;
  56. #endif
  57. if (!vectors_high()) {
  58. /*
  59. * On ARM, first page must always be allocated since it
  60. * contains the machine vectors. The vectors are always high
  61. * with LPAE.
  62. */
  63. new_pud = pud_alloc(mm, new_pgd, 0);
  64. if (!new_pud)
  65. goto no_pud;
  66. new_pmd = pmd_alloc(mm, new_pud, 0);
  67. if (!new_pmd)
  68. goto no_pmd;
  69. new_pte = pte_alloc_map(mm, NULL, new_pmd, 0);
  70. if (!new_pte)
  71. goto no_pte;
  72. init_pud = pud_offset(init_pgd, 0);
  73. init_pmd = pmd_offset(init_pud, 0);
  74. init_pte = pte_offset_map(init_pmd, 0);
  75. set_pte_ext(new_pte, *init_pte, 0);
  76. pte_unmap(init_pte);
  77. pte_unmap(new_pte);
  78. }
  79. return new_pgd;
  80. no_pte:
  81. pmd_free(mm, new_pmd);
  82. no_pmd:
  83. pud_free(mm, new_pud);
  84. no_pud:
  85. __pgd_free(new_pgd);
  86. no_pgd:
  87. return NULL;
  88. }
  89. void pgd_free(struct mm_struct *mm, pgd_t *pgd_base)
  90. {
  91. pgd_t *pgd;
  92. pud_t *pud;
  93. pmd_t *pmd;
  94. pgtable_t pte;
  95. if (!pgd_base)
  96. return;
  97. pgd = pgd_base + pgd_index(0);
  98. if (pgd_none_or_clear_bad(pgd))
  99. goto no_pgd;
  100. pud = pud_offset(pgd, 0);
  101. if (pud_none_or_clear_bad(pud))
  102. goto no_pud;
  103. pmd = pmd_offset(pud, 0);
  104. if (pmd_none_or_clear_bad(pmd))
  105. goto no_pmd;
  106. pte = pmd_pgtable(*pmd);
  107. pmd_clear(pmd);
  108. pte_free(mm, pte);
  109. no_pmd:
  110. pud_clear(pud);
  111. pmd_free(mm, pmd);
  112. no_pud:
  113. pgd_clear(pgd);
  114. pud_free(mm, pud);
  115. no_pgd:
  116. #ifdef CONFIG_ARM_LPAE
  117. /*
  118. * Free modules/pkmap or identity pmd tables.
  119. */
  120. for (pgd = pgd_base; pgd < pgd_base + PTRS_PER_PGD; pgd++) {
  121. if (pgd_none_or_clear_bad(pgd))
  122. continue;
  123. if (pgd_val(*pgd) & L_PGD_SWAPPER)
  124. continue;
  125. pud = pud_offset(pgd, 0);
  126. if (pud_none_or_clear_bad(pud))
  127. continue;
  128. pmd = pmd_offset(pud, 0);
  129. pud_clear(pud);
  130. pmd_free(mm, pmd);
  131. pgd_clear(pgd);
  132. pud_free(mm, pud);
  133. }
  134. #endif
  135. __pgd_free(pgd_base);
  136. }