gpt.c 6.3 KB

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