mm-nds32.c 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. // SPDX-License-Identifier: GPL-2.0
  2. // Copyright (C) 2005-2017 Andes Technology Corporation
  3. #include <linux/init_task.h>
  4. #include <asm/pgalloc.h>
  5. #define FIRST_KERNEL_PGD_NR (USER_PTRS_PER_PGD)
  6. /*
  7. * need to get a page for level 1
  8. */
  9. pgd_t *pgd_alloc(struct mm_struct *mm)
  10. {
  11. pgd_t *new_pgd, *init_pgd;
  12. int i;
  13. new_pgd = (pgd_t *) __get_free_pages(GFP_KERNEL, 0);
  14. if (!new_pgd)
  15. return NULL;
  16. for (i = 0; i < PTRS_PER_PGD; i++) {
  17. (*new_pgd) = 1;
  18. new_pgd++;
  19. }
  20. new_pgd -= PTRS_PER_PGD;
  21. init_pgd = pgd_offset_k(0);
  22. memcpy(new_pgd + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR,
  23. (PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t));
  24. cpu_dcache_wb_range((unsigned long)new_pgd,
  25. (unsigned long)new_pgd +
  26. PTRS_PER_PGD * sizeof(pgd_t));
  27. inc_zone_page_state(virt_to_page((unsigned long *)new_pgd),
  28. NR_PAGETABLE);
  29. return new_pgd;
  30. }
  31. void pgd_free(struct mm_struct *mm, pgd_t * pgd)
  32. {
  33. pmd_t *pmd;
  34. struct page *pte;
  35. if (!pgd)
  36. return;
  37. pmd = (pmd_t *) pgd;
  38. if (pmd_none(*pmd))
  39. goto free;
  40. if (pmd_bad(*pmd)) {
  41. pmd_ERROR(*pmd);
  42. pmd_clear(pmd);
  43. goto free;
  44. }
  45. pte = pmd_page(*pmd);
  46. pmd_clear(pmd);
  47. dec_zone_page_state(virt_to_page((unsigned long *)pgd), NR_PAGETABLE);
  48. pte_free(mm, pte);
  49. mm_dec_nr_ptes(mm);
  50. pmd_free(mm, pmd);
  51. free:
  52. free_pages((unsigned long)pgd, 0);
  53. }
  54. /*
  55. * In order to soft-boot, we need to insert a 1:1 mapping in place of
  56. * the user-mode pages. This will then ensure that we have predictable
  57. * results when turning the mmu off
  58. */
  59. void setup_mm_for_reboot(char mode)
  60. {
  61. unsigned long pmdval;
  62. pgd_t *pgd;
  63. pmd_t *pmd;
  64. int i;
  65. if (current->mm && current->mm->pgd)
  66. pgd = current->mm->pgd;
  67. else
  68. pgd = init_mm.pgd;
  69. for (i = 0; i < USER_PTRS_PER_PGD; i++) {
  70. pmdval = (i << PGDIR_SHIFT);
  71. pmd = pmd_offset(pgd + i, i << PGDIR_SHIFT);
  72. set_pmd(pmd, __pmd(pmdval));
  73. }
  74. }