ident_map.c 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. /*
  2. * Helper routines for building identity mapping page tables. This is
  3. * included by both the compressed kernel and the regular kernel.
  4. */
  5. static void ident_pmd_init(struct x86_mapping_info *info, pmd_t *pmd_page,
  6. unsigned long addr, unsigned long end)
  7. {
  8. addr &= PMD_MASK;
  9. for (; addr < end; addr += PMD_SIZE) {
  10. pmd_t *pmd = pmd_page + pmd_index(addr);
  11. if (pmd_present(*pmd))
  12. continue;
  13. set_pmd(pmd, __pmd((addr - info->offset) | info->pmd_flag));
  14. }
  15. }
  16. static int ident_pud_init(struct x86_mapping_info *info, pud_t *pud_page,
  17. unsigned long addr, unsigned long end)
  18. {
  19. unsigned long next;
  20. for (; addr < end; addr = next) {
  21. pud_t *pud = pud_page + pud_index(addr);
  22. pmd_t *pmd;
  23. next = (addr & PUD_MASK) + PUD_SIZE;
  24. if (next > end)
  25. next = end;
  26. if (pud_present(*pud)) {
  27. pmd = pmd_offset(pud, 0);
  28. ident_pmd_init(info, pmd, addr, next);
  29. continue;
  30. }
  31. pmd = (pmd_t *)info->alloc_pgt_page(info->context);
  32. if (!pmd)
  33. return -ENOMEM;
  34. ident_pmd_init(info, pmd, addr, next);
  35. set_pud(pud, __pud(__pa(pmd) | _KERNPG_TABLE));
  36. }
  37. return 0;
  38. }
  39. int kernel_ident_mapping_init(struct x86_mapping_info *info, pgd_t *pgd_page,
  40. unsigned long pstart, unsigned long pend)
  41. {
  42. unsigned long addr = pstart + info->offset;
  43. unsigned long end = pend + info->offset;
  44. unsigned long next;
  45. int result;
  46. for (; addr < end; addr = next) {
  47. pgd_t *pgd = pgd_page + pgd_index(addr);
  48. pud_t *pud;
  49. next = (addr & PGDIR_MASK) + PGDIR_SIZE;
  50. if (next > end)
  51. next = end;
  52. if (pgd_present(*pgd)) {
  53. pud = pud_offset(pgd, 0);
  54. result = ident_pud_init(info, pud, addr, next);
  55. if (result)
  56. return result;
  57. continue;
  58. }
  59. pud = (pud_t *)info->alloc_pgt_page(info->context);
  60. if (!pud)
  61. return -ENOMEM;
  62. result = ident_pud_init(info, pud, addr, next);
  63. if (result)
  64. return result;
  65. set_pgd(pgd, __pgd(__pa(pud) | _KERNPG_TABLE));
  66. }
  67. return 0;
  68. }