remap.c 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. #include <linux/vmalloc.h>
  2. #include <asm/pgalloc.h>
  3. #include <asm/cacheflush.h>
  4. static inline void
  5. remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
  6. unsigned long phys_addr, unsigned long flags)
  7. {
  8. unsigned long end;
  9. unsigned long pfn;
  10. address &= ~PMD_MASK;
  11. end = address + size;
  12. if (end > PMD_SIZE)
  13. end = PMD_SIZE;
  14. if (address >= end)
  15. BUG();
  16. pfn = phys_addr >> PAGE_SHIFT;
  17. do {
  18. if (!pte_none(*pte)) {
  19. printk("remap_area_pte: page already exists\n");
  20. BUG();
  21. }
  22. set_pte(pte, pfn_pte(pfn,
  23. __pgprot(_PAGE_VALID | _PAGE_ASM |
  24. _PAGE_KRE | _PAGE_KWE | flags)));
  25. address += PAGE_SIZE;
  26. pfn++;
  27. pte++;
  28. } while (address && (address < end));
  29. }
  30. static inline int
  31. remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
  32. unsigned long phys_addr, unsigned long flags)
  33. {
  34. unsigned long end;
  35. address &= ~PGDIR_MASK;
  36. end = address + size;
  37. if (end > PGDIR_SIZE)
  38. end = PGDIR_SIZE;
  39. phys_addr -= address;
  40. if (address >= end)
  41. BUG();
  42. do {
  43. pte_t * pte = pte_alloc_kernel(pmd, address);
  44. if (!pte)
  45. return -ENOMEM;
  46. remap_area_pte(pte, address, end - address,
  47. address + phys_addr, flags);
  48. address = (address + PMD_SIZE) & PMD_MASK;
  49. pmd++;
  50. } while (address && (address < end));
  51. return 0;
  52. }
  53. int
  54. __alpha_remap_area_pages(unsigned long address, unsigned long phys_addr,
  55. unsigned long size, unsigned long flags)
  56. {
  57. pgd_t * dir;
  58. int error = 0;
  59. unsigned long end = address + size;
  60. phys_addr -= address;
  61. dir = pgd_offset(&init_mm, address);
  62. flush_cache_all();
  63. if (address >= end)
  64. BUG();
  65. do {
  66. pmd_t *pmd;
  67. pmd = pmd_alloc(&init_mm, dir, address);
  68. error = -ENOMEM;
  69. if (!pmd)
  70. break;
  71. if (remap_area_pmd(pmd, address, end - address,
  72. phys_addr + address, flags))
  73. break;
  74. error = 0;
  75. address = (address + PGDIR_SIZE) & PGDIR_MASK;
  76. dir++;
  77. } while (address && (address < end));
  78. return error;
  79. }