1 /* gpt.c - Read GUID Partition Tables (GPT). */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2002,2005,2006,2007,2008 Free Software Foundation, Inc.
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.
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.
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/>.
20 #include <grub/disk.h>
21 #include <grub/misc.h>
23 #include <grub/partition.h>
25 #include <grub/msdos_partition.h>
26 #include <grub/gpt_partition.h>
27 #include <grub/i18n.h>
29 GRUB_MOD_LICENSE ("GPLv3+");
31 static grub_uint8_t grub_gpt_magic
[8] =
33 0x45, 0x46, 0x49, 0x20, 0x50, 0x41, 0x52, 0x54
36 static const grub_gpt_part_type_t grub_gpt_partition_type_empty
= GRUB_GPT_PARTITION_TYPE_EMPTY
;
39 static const grub_gpt_part_type_t grub_gpt_partition_type_bios_boot
= GRUB_GPT_PARTITION_TYPE_BIOS_BOOT
;
42 /* 512 << 7 = 65536 byte sectors. */
43 #define MAX_SECTOR_LOG 7
45 static struct grub_partition_map grub_gpt_partition_map
;
50 grub_gpt_partition_map_iterate (grub_disk_t disk
,
51 int (*hook
) (grub_disk_t disk
,
52 const grub_partition_t partition
))
54 struct grub_partition part
;
55 struct grub_gpt_header gpt
;
56 struct grub_gpt_partentry entry
;
57 struct grub_msdos_partition_mbr mbr
;
58 grub_uint64_t entries
;
63 /* Read the protective MBR. */
64 if (grub_disk_read (disk
, 0, 0, sizeof (mbr
), &mbr
))
67 /* Check if it is valid. */
68 if (mbr
.signature
!= grub_cpu_to_le16 (GRUB_PC_PARTITION_SIGNATURE
))
69 return grub_error (GRUB_ERR_BAD_PART_TABLE
, "no signature");
71 /* Make sure the MBR is a protective MBR and not a normal MBR. */
72 for (i
= 0; i
< 4; i
++)
73 if (mbr
.entries
[i
].type
== GRUB_PC_PARTITION_TYPE_GPT_DISK
)
76 return grub_error (GRUB_ERR_BAD_PART_TABLE
, "no GPT partition map found");
78 /* Read the GPT header. */
79 for (sector_log
= 0; sector_log
< MAX_SECTOR_LOG
; sector_log
++)
81 if (grub_disk_read (disk
, 1 << sector_log
, 0, sizeof (gpt
), &gpt
))
84 if (grub_memcmp (gpt
.magic
, grub_gpt_magic
, sizeof (grub_gpt_magic
)) == 0)
87 if (sector_log
== MAX_SECTOR_LOG
)
88 return grub_error (GRUB_ERR_BAD_PART_TABLE
, "no valid GPT header");
90 grub_dprintf ("gpt", "Read a valid GPT header\n");
92 entries
= grub_le_to_cpu64 (gpt
.partitions
) << sector_log
;
93 for (i
= 0; i
< grub_le_to_cpu32 (gpt
.maxpart
); i
++)
95 if (grub_disk_read (disk
, entries
, last_offset
,
96 sizeof (entry
), &entry
))
99 if (grub_memcmp (&grub_gpt_partition_type_empty
, &entry
.type
,
100 sizeof (grub_gpt_partition_type_empty
)))
102 /* Calculate the first block and the size of the partition. */
103 part
.start
= grub_le_to_cpu64 (entry
.start
) << sector_log
;
104 part
.len
= (grub_le_to_cpu64 (entry
.end
)
105 - grub_le_to_cpu64 (entry
.start
) + 1) << sector_log
;
106 part
.offset
= entries
;
108 part
.index
= last_offset
;
109 part
.partmap
= &grub_gpt_partition_map
;
110 part
.parent
= disk
->partition
;
112 grub_dprintf ("gpt", "GPT entry %d: start=%lld, length=%lld\n", i
,
113 (unsigned long long) part
.start
,
114 (unsigned long long) part
.len
);
116 if (hook (disk
, &part
))
120 last_offset
+= grub_le_to_cpu32 (gpt
.partentry_size
);
121 if (last_offset
== GRUB_DISK_SECTOR_SIZE
)
128 return GRUB_ERR_NONE
;
133 gpt_partition_map_embed (struct grub_disk
*disk_
, unsigned int *nsectors
,
134 unsigned int max_nsectors
,
135 grub_embed_type_t embed_type
,
136 grub_disk_addr_t
**sectors
)
138 grub_disk_addr_t start
= 0, len
= 0;
142 auto int NESTED_FUNC_ATTR
find_usable_region (grub_disk_t disk
,
143 const grub_partition_t p
);
144 int NESTED_FUNC_ATTR
find_usable_region (grub_disk_t disk
__attribute__ ((unused
)),
145 const grub_partition_t p
)
147 struct grub_gpt_partentry gptdata
;
150 p2
= disk
->partition
;
151 disk
->partition
= p
->parent
;
152 if (grub_disk_read (disk
, p
->offset
, p
->index
,
153 sizeof (gptdata
), &gptdata
))
155 disk
->partition
= p2
;
158 disk
->partition
= p2
;
160 /* If there's an embed region, it is in a dedicated partition. */
161 if (! grub_memcmp (&gptdata
.type
, &grub_gpt_partition_type_bios_boot
, 16))
171 if (embed_type
!= GRUB_EMBED_PCBIOS
)
172 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
,
173 "GPT currently supports only PC-BIOS embedding");
175 err
= grub_gpt_partition_map_iterate (disk_
, find_usable_region
);
180 return grub_error (GRUB_ERR_FILE_NOT_FOUND
,
181 N_("this GPT partition label contains no BIOS Boot Partition;"
182 " embedding won't be possible"));
185 return grub_error (GRUB_ERR_OUT_OF_RANGE
,
186 N_("your BIOS Boot Partition is too small;"
187 " embedding won't be possible"));
190 if (*nsectors
> max_nsectors
)
191 *nsectors
= max_nsectors
;
192 *sectors
= grub_malloc (*nsectors
* sizeof (**sectors
));
195 for (i
= 0; i
< *nsectors
; i
++)
196 (*sectors
)[i
] = start
+ i
;
198 return GRUB_ERR_NONE
;
203 /* Partition map type. */
204 static struct grub_partition_map grub_gpt_partition_map
=
207 .iterate
= grub_gpt_partition_map_iterate
,
209 .embed
= gpt_partition_map_embed
213 GRUB_MOD_INIT(part_gpt
)
215 grub_partition_map_register (&grub_gpt_partition_map
);
218 GRUB_MOD_FINI(part_gpt
)
220 grub_partition_map_unregister (&grub_gpt_partition_map
);