mmap.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. /* Mmap management. */
  2. /*
  3. * GRUB -- GRand Unified Bootloader
  4. * Copyright (C) 2009 Free Software Foundation, Inc.
  5. *
  6. * GRUB is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * GRUB is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <grub/machine/memory.h>
  20. #include <grub/memory.h>
  21. #include <grub/misc.h>
  22. #include <grub/term.h>
  23. #include <grub/loader.h>
  24. #define min(a,b) (((a) < (b)) ? (a) : (b))
  25. static void *hooktarget = 0;
  26. extern grub_uint8_t grub_machine_mmaphook_start;
  27. extern grub_uint8_t grub_machine_mmaphook_end;
  28. extern grub_uint8_t grub_machine_mmaphook_int12;
  29. extern grub_uint8_t grub_machine_mmaphook_int15;
  30. static grub_uint16_t grub_machine_mmaphook_int12offset = 0;
  31. static grub_uint16_t grub_machine_mmaphook_int12segment = 0;
  32. extern grub_uint16_t grub_machine_mmaphook_int15offset;
  33. extern grub_uint16_t grub_machine_mmaphook_int15segment;
  34. extern grub_uint16_t grub_machine_mmaphook_mmap_num;
  35. extern grub_uint16_t grub_machine_mmaphook_kblow;
  36. extern grub_uint16_t grub_machine_mmaphook_kbin16mb;
  37. extern grub_uint16_t grub_machine_mmaphook_64kbin4gb;
  38. /* Helper for preboot. */
  39. static int fill_hook (grub_uint64_t addr, grub_uint64_t size,
  40. grub_memory_type_t type, void *data)
  41. {
  42. struct grub_e820_mmap_entry **hookmmapcur = data;
  43. grub_dprintf ("mmap", "mmap chunk %llx-%llx:%x\n", addr, addr + size, type);
  44. (*hookmmapcur)->addr = addr;
  45. (*hookmmapcur)->len = size;
  46. (*hookmmapcur)->type = type;
  47. (*hookmmapcur)++;
  48. return 0;
  49. }
  50. static grub_err_t
  51. preboot (int noreturn __attribute__ ((unused)))
  52. {
  53. struct grub_e820_mmap_entry *hookmmap, *hookmmapcur;
  54. if (! hooktarget)
  55. return grub_error (GRUB_ERR_OUT_OF_MEMORY,
  56. "no space is allocated for memory hook");
  57. grub_dprintf ("mmap", "installing preboot handlers\n");
  58. hookmmapcur = hookmmap = (struct grub_e820_mmap_entry *)
  59. ((grub_uint8_t *) hooktarget + (&grub_machine_mmaphook_end
  60. - &grub_machine_mmaphook_start));
  61. grub_mmap_iterate (fill_hook, &hookmmapcur);
  62. grub_machine_mmaphook_mmap_num = hookmmapcur - hookmmap;
  63. grub_machine_mmaphook_kblow = grub_mmap_get_lower () >> 10;
  64. grub_machine_mmaphook_kbin16mb
  65. = min (grub_mmap_get_upper (),0x3f00000ULL) >> 10;
  66. grub_machine_mmaphook_64kbin4gb
  67. = min (grub_mmap_get_post64 (), 0xfc000000ULL) >> 16;
  68. /* Correct BDA. */
  69. *((grub_uint16_t *) grub_absolute_pointer (0x413)) = grub_mmap_get_lower () >> 10;
  70. /* Save old interrupt handlers. */
  71. grub_machine_mmaphook_int12offset = *((grub_uint16_t *) grub_absolute_pointer (0x48));
  72. grub_machine_mmaphook_int12segment = *((grub_uint16_t *) grub_absolute_pointer (0x4a));
  73. grub_machine_mmaphook_int15offset = *((grub_uint16_t *) grub_absolute_pointer (0x54));
  74. grub_machine_mmaphook_int15segment = *((grub_uint16_t *) grub_absolute_pointer (0x56));
  75. grub_dprintf ("mmap", "hooktarget = %p\n", hooktarget);
  76. /* Install the interrupt handlers. */
  77. grub_memcpy (hooktarget, &grub_machine_mmaphook_start,
  78. &grub_machine_mmaphook_end - &grub_machine_mmaphook_start);
  79. *((grub_uint16_t *) grub_absolute_pointer (0x4a)) = ((grub_addr_t) hooktarget) >> 4;
  80. *((grub_uint16_t *) grub_absolute_pointer (0x56)) = ((grub_addr_t) hooktarget) >> 4;
  81. *((grub_uint16_t *) grub_absolute_pointer (0x48)) = &grub_machine_mmaphook_int12
  82. - &grub_machine_mmaphook_start;
  83. *((grub_uint16_t *) grub_absolute_pointer (0x54)) = &grub_machine_mmaphook_int15
  84. - &grub_machine_mmaphook_start;
  85. return GRUB_ERR_NONE;
  86. }
  87. static grub_err_t
  88. preboot_rest (void)
  89. {
  90. /* Restore old interrupt handlers. */
  91. *((grub_uint16_t *) grub_absolute_pointer (0x48)) = grub_machine_mmaphook_int12offset;
  92. *((grub_uint16_t *) grub_absolute_pointer (0x4a)) = grub_machine_mmaphook_int12segment;
  93. *((grub_uint16_t *) grub_absolute_pointer (0x54)) = grub_machine_mmaphook_int15offset;
  94. *((grub_uint16_t *) grub_absolute_pointer (0x56)) = grub_machine_mmaphook_int15segment;
  95. return GRUB_ERR_NONE;
  96. }
  97. /* Helper for malloc_hook. */
  98. static int
  99. count_hook (grub_uint64_t addr __attribute__ ((unused)),
  100. grub_uint64_t size __attribute__ ((unused)),
  101. grub_memory_type_t type __attribute__ ((unused)), void *data)
  102. {
  103. int *regcount = data;
  104. (*regcount)++;
  105. return 0;
  106. }
  107. static grub_err_t
  108. malloc_hook (void)
  109. {
  110. static int reentry = 0;
  111. static int mmapregion = 0;
  112. static int slots_available = 0;
  113. int hooksize;
  114. int regcount = 0;
  115. if (reentry)
  116. return GRUB_ERR_NONE;
  117. grub_dprintf ("mmap", "registering\n");
  118. grub_mmap_iterate (count_hook, &regcount);
  119. /* Mapping hook itself may introduce up to 2 additional regions. */
  120. regcount += 2;
  121. if (regcount <= slots_available)
  122. return GRUB_ERR_NONE;
  123. if (mmapregion)
  124. {
  125. grub_mmap_free_and_unregister (mmapregion);
  126. mmapregion = 0;
  127. hooktarget = 0;
  128. }
  129. hooksize = &grub_machine_mmaphook_end - &grub_machine_mmaphook_start
  130. + regcount * sizeof (struct grub_e820_mmap_entry);
  131. /* Allocate an integer number of KiB. */
  132. hooksize = ((hooksize - 1) | 0x3ff) + 1;
  133. slots_available = (hooksize - (&grub_machine_mmaphook_end
  134. - &grub_machine_mmaphook_start))
  135. / sizeof (struct grub_e820_mmap_entry);
  136. reentry = 1;
  137. hooktarget
  138. = grub_mmap_malign_and_register (16, ALIGN_UP (hooksize, 16), &mmapregion,
  139. GRUB_MEMORY_RESERVED,
  140. GRUB_MMAP_MALLOC_LOW);
  141. reentry = 0;
  142. if (! hooktarget)
  143. {
  144. slots_available = 0;
  145. return grub_error (GRUB_ERR_OUT_OF_MEMORY, "no space for mmap hook");
  146. }
  147. return GRUB_ERR_NONE;
  148. }
  149. grub_err_t
  150. grub_machine_mmap_register (grub_uint64_t start __attribute__ ((unused)),
  151. grub_uint64_t size __attribute__ ((unused)),
  152. int type __attribute__ ((unused)),
  153. int handle __attribute__ ((unused)))
  154. {
  155. grub_err_t err;
  156. static struct grub_preboot *preb_handle = 0;
  157. err = malloc_hook ();
  158. if (err)
  159. return err;
  160. if (! preb_handle)
  161. {
  162. grub_dprintf ("mmap", "adding preboot\n");
  163. preb_handle
  164. = grub_loader_register_preboot_hook (preboot, preboot_rest,
  165. GRUB_LOADER_PREBOOT_HOOK_PRIO_MEMORY);
  166. if (! preb_handle)
  167. return grub_errno;
  168. }
  169. return GRUB_ERR_NONE;
  170. }
  171. grub_err_t
  172. grub_machine_mmap_unregister (int handle __attribute__ ((unused)))
  173. {
  174. return GRUB_ERR_NONE;
  175. }