gpt.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. /* gpt.c - Read GUID Partition Tables (GPT). */
  2. /*
  3. * GRUB -- GRand Unified Bootloader
  4. * Copyright (C) 2002,2005,2006,2007,2008 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/disk.h>
  20. #include <grub/misc.h>
  21. #include <grub/mm.h>
  22. #include <grub/partition.h>
  23. #include <grub/dl.h>
  24. #include <grub/msdos_partition.h>
  25. #include <grub/gpt_partition.h>
  26. #include <grub/i18n.h>
  27. #ifdef GRUB_UTIL
  28. #include <grub/emu/misc.h>
  29. #endif
  30. GRUB_MOD_LICENSE ("GPLv3+");
  31. static grub_uint8_t grub_gpt_magic[8] =
  32. {
  33. 0x45, 0x46, 0x49, 0x20, 0x50, 0x41, 0x52, 0x54
  34. };
  35. static const grub_guid_t grub_gpt_partition_type_empty = GRUB_GPT_PARTITION_TYPE_EMPTY;
  36. #ifdef GRUB_UTIL
  37. static const grub_guid_t grub_gpt_partition_type_bios_boot = GRUB_GPT_PARTITION_TYPE_BIOS_BOOT;
  38. #endif
  39. /* 512 << 7 = 65536 byte sectors. */
  40. #define MAX_SECTOR_LOG 7
  41. static struct grub_partition_map grub_gpt_partition_map;
  42. grub_err_t
  43. grub_gpt_partition_map_iterate (grub_disk_t disk,
  44. grub_partition_iterate_hook_t hook,
  45. void *hook_data)
  46. {
  47. struct grub_partition part;
  48. struct grub_gpt_header gpt;
  49. struct grub_gpt_partentry entry;
  50. struct grub_msdos_partition_mbr mbr;
  51. grub_uint64_t entries;
  52. unsigned int i;
  53. int last_offset = 0;
  54. int sector_log = 0;
  55. /* Read the protective MBR. */
  56. if (grub_disk_read (disk, 0, 0, sizeof (mbr), &mbr))
  57. return grub_errno;
  58. /* Check if it is valid. */
  59. if (mbr.signature != grub_cpu_to_le16_compile_time (GRUB_PC_PARTITION_SIGNATURE))
  60. return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature");
  61. /* Make sure the MBR is a protective MBR and not a normal MBR. */
  62. for (i = 0; i < 4; i++)
  63. if (mbr.entries[i].type == GRUB_PC_PARTITION_TYPE_GPT_DISK)
  64. break;
  65. if (i == 4)
  66. return grub_error (GRUB_ERR_BAD_PART_TABLE, "no GPT partition map found");
  67. /* Read the GPT header. */
  68. for (sector_log = 0; sector_log < MAX_SECTOR_LOG; sector_log++)
  69. {
  70. if (grub_disk_read (disk, 1 << sector_log, 0, sizeof (gpt), &gpt))
  71. return grub_errno;
  72. if (grub_memcmp (gpt.magic, grub_gpt_magic, sizeof (grub_gpt_magic)) == 0)
  73. break;
  74. }
  75. if (sector_log == MAX_SECTOR_LOG)
  76. return grub_error (GRUB_ERR_BAD_PART_TABLE, "no valid GPT header");
  77. grub_dprintf ("gpt", "Read a valid GPT header\n");
  78. entries = grub_le_to_cpu64 (gpt.partitions) << sector_log;
  79. for (i = 0; i < grub_le_to_cpu32 (gpt.maxpart); i++)
  80. {
  81. if (grub_disk_read (disk, entries, last_offset,
  82. sizeof (entry), &entry))
  83. return grub_errno;
  84. if (grub_memcmp (&grub_gpt_partition_type_empty, &entry.type,
  85. sizeof (grub_gpt_partition_type_empty)))
  86. {
  87. /* Calculate the first block and the size of the partition. */
  88. part.start = grub_le_to_cpu64 (entry.start) << sector_log;
  89. part.len = (grub_le_to_cpu64 (entry.end)
  90. - grub_le_to_cpu64 (entry.start) + 1) << sector_log;
  91. part.offset = entries;
  92. part.number = i;
  93. part.index = last_offset;
  94. part.partmap = &grub_gpt_partition_map;
  95. part.parent = disk->partition;
  96. grub_dprintf ("gpt", "GPT entry %d: start=%lld, length=%lld\n", i,
  97. (unsigned long long) part.start,
  98. (unsigned long long) part.len);
  99. if (hook (disk, &part, hook_data))
  100. return grub_errno;
  101. }
  102. last_offset += grub_le_to_cpu32 (gpt.partentry_size);
  103. if (last_offset == GRUB_DISK_SECTOR_SIZE)
  104. {
  105. last_offset = 0;
  106. entries++;
  107. }
  108. }
  109. return GRUB_ERR_NONE;
  110. }
  111. #ifdef GRUB_UTIL
  112. /* Context for gpt_partition_map_embed. */
  113. struct gpt_partition_map_embed_ctx
  114. {
  115. grub_disk_addr_t start, len;
  116. };
  117. /* Helper for gpt_partition_map_embed. */
  118. static int
  119. find_usable_region (grub_disk_t disk __attribute__ ((unused)),
  120. const grub_partition_t p, void *data)
  121. {
  122. struct gpt_partition_map_embed_ctx *ctx = data;
  123. struct grub_gpt_partentry gptdata;
  124. grub_partition_t p2;
  125. p2 = disk->partition;
  126. disk->partition = p->parent;
  127. if (grub_disk_read (disk, p->offset, p->index,
  128. sizeof (gptdata), &gptdata))
  129. {
  130. disk->partition = p2;
  131. return 0;
  132. }
  133. disk->partition = p2;
  134. /* If there's an embed region, it is in a dedicated partition. */
  135. if (! grub_memcmp (&gptdata.type, &grub_gpt_partition_type_bios_boot, 16))
  136. {
  137. ctx->start = p->start;
  138. ctx->len = p->len;
  139. return 1;
  140. }
  141. return 0;
  142. }
  143. static grub_err_t
  144. gpt_partition_map_embed (struct grub_disk *disk, unsigned int *nsectors,
  145. unsigned int max_nsectors,
  146. grub_embed_type_t embed_type,
  147. grub_disk_addr_t **sectors,
  148. int warn_short)
  149. {
  150. struct gpt_partition_map_embed_ctx ctx = {
  151. .start = 0,
  152. .len = 0
  153. };
  154. unsigned i;
  155. grub_err_t err;
  156. if (embed_type != GRUB_EMBED_PCBIOS)
  157. return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
  158. "GPT currently supports only PC-BIOS embedding");
  159. err = grub_gpt_partition_map_iterate (disk, find_usable_region, &ctx);
  160. if (err)
  161. return err;
  162. if (ctx.len == 0)
  163. return grub_error (GRUB_ERR_FILE_NOT_FOUND,
  164. N_("this GPT partition label contains no BIOS Boot Partition;"
  165. " embedding won't be possible"));
  166. if (ctx.len < GRUB_MIN_RECOMMENDED_MBR_GAP)
  167. grub_util_warn ("Your BIOS Boot Partition is under 1 MiB, please increase its size.");
  168. if (ctx.len < *nsectors)
  169. return grub_error (GRUB_ERR_OUT_OF_RANGE,
  170. N_("your BIOS Boot Partition is too small;"
  171. " embedding won't be possible"));
  172. *nsectors = ctx.len;
  173. if (*nsectors > max_nsectors)
  174. *nsectors = max_nsectors;
  175. *sectors = grub_calloc (*nsectors, sizeof (**sectors));
  176. if (!*sectors)
  177. return grub_errno;
  178. for (i = 0; i < *nsectors; i++)
  179. (*sectors)[i] = ctx.start + i;
  180. return GRUB_ERR_NONE;
  181. }
  182. #endif
  183. /* Partition map type. */
  184. static struct grub_partition_map grub_gpt_partition_map =
  185. {
  186. .name = "gpt",
  187. .iterate = grub_gpt_partition_map_iterate,
  188. #ifdef GRUB_UTIL
  189. .embed = gpt_partition_map_embed
  190. #endif
  191. };
  192. GRUB_MOD_INIT(part_gpt)
  193. {
  194. COMPILE_TIME_ASSERT(sizeof(grub_guid_t) == 16);
  195. COMPILE_TIME_ASSERT(sizeof(grub_packed_guid_t) == 16);
  196. COMPILE_TIME_ASSERT(sizeof(struct grub_gpt_partentry) == 128);
  197. grub_partition_map_register (&grub_gpt_partition_map);
  198. }
  199. GRUB_MOD_FINI(part_gpt)
  200. {
  201. grub_partition_map_unregister (&grub_gpt_partition_map);
  202. }