relocator.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. /*
  2. * GRUB -- GRand Unified Bootloader
  3. * Copyright (C) 2010 Free Software Foundation, Inc.
  4. *
  5. * GRUB is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * GRUB is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include <grub/relocator.h>
  19. #include <grub/relocator_private.h>
  20. #include <grub/memory.h>
  21. #include <grub/efi/efi.h>
  22. #include <grub/efi/api.h>
  23. #include <grub/term.h>
  24. #define NEXT_MEMORY_DESCRIPTOR(desc, size) \
  25. ((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size)))
  26. unsigned
  27. grub_relocator_firmware_get_max_events (void)
  28. {
  29. grub_efi_uintn_t mmapsize = 0, descriptor_size = 0;
  30. grub_efi_uint32_t descriptor_version = 0;
  31. grub_efi_uintn_t key;
  32. grub_efi_get_memory_map (&mmapsize, NULL, &key, &descriptor_size,
  33. &descriptor_version);
  34. /* Since grub_relocator_firmware_fill_events uses malloc
  35. we need some reserve. Hence +10. */
  36. return 2 * (mmapsize / descriptor_size + 10);
  37. }
  38. unsigned
  39. grub_relocator_firmware_fill_events (struct grub_relocator_mmap_event *events)
  40. {
  41. grub_efi_uintn_t mmapsize = 0, desc_size = 0;
  42. grub_efi_uint32_t descriptor_version = 0;
  43. grub_efi_memory_descriptor_t *descs = NULL;
  44. grub_efi_uintn_t key;
  45. int counter = 0;
  46. grub_efi_memory_descriptor_t *desc;
  47. grub_efi_get_memory_map (&mmapsize, NULL, &key, &desc_size,
  48. &descriptor_version);
  49. descs = grub_malloc (mmapsize);
  50. if (!descs)
  51. return 0;
  52. grub_efi_get_memory_map (&mmapsize, descs, &key, &desc_size,
  53. &descriptor_version);
  54. for (desc = descs;
  55. (char *) desc < ((char *) descs + mmapsize);
  56. desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))
  57. {
  58. grub_uint64_t start = desc->physical_start;
  59. grub_uint64_t end = desc->physical_start + (desc->num_pages << 12);
  60. /* post-4G addresses are never supported on 32-bit EFI.
  61. Moreover it has been reported that some 64-bit EFI contrary to the
  62. spec don't map post-4G pages. So if you enable post-4G allocations,
  63. map pages manually or check that they are mapped.
  64. */
  65. if (end >= 0x100000000ULL)
  66. end = 0x100000000ULL;
  67. if (end <= start)
  68. continue;
  69. if (desc->type != GRUB_EFI_CONVENTIONAL_MEMORY)
  70. continue;
  71. events[counter].type = REG_FIRMWARE_START;
  72. events[counter].pos = start;
  73. counter++;
  74. events[counter].type = REG_FIRMWARE_END;
  75. events[counter].pos = end;
  76. counter++;
  77. }
  78. return counter;
  79. }
  80. int
  81. grub_relocator_firmware_alloc_region (grub_addr_t start, grub_size_t size)
  82. {
  83. grub_efi_boot_services_t *b;
  84. grub_efi_physical_address_t address = start;
  85. grub_efi_status_t status;
  86. if (grub_efi_is_finished)
  87. return 1;
  88. #ifdef DEBUG_RELOCATOR_NOMEM_DPRINTF
  89. grub_dprintf ("relocator", "EFI alloc: %llx, %llx\n",
  90. (unsigned long long) start, (unsigned long long) size);
  91. #endif
  92. b = grub_efi_system_table->boot_services;
  93. status = b->allocate_pages (GRUB_EFI_ALLOCATE_ADDRESS,
  94. GRUB_EFI_LOADER_DATA, size >> 12, &address);
  95. return (status == GRUB_EFI_SUCCESS);
  96. }
  97. void
  98. grub_relocator_firmware_free_region (grub_addr_t start, grub_size_t size)
  99. {
  100. grub_efi_boot_services_t *b;
  101. if (grub_efi_is_finished)
  102. return;
  103. b = grub_efi_system_table->boot_services;
  104. b->free_pages (start, size >> 12);
  105. }