]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/partmap/gpt.c
Update vtoytool
[Ventoy.git] / GRUB2 / MOD_SRC / grub-2.04 / grub-core / partmap / gpt.c
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
20 #include <grub/disk.h>
21 #include <grub/misc.h>
22 #include <grub/mm.h>
23 #include <grub/partition.h>
24 #include <grub/dl.h>
25 #include <grub/msdos_partition.h>
26 #include <grub/gpt_partition.h>
27 #include <grub/i18n.h>
28
29 GRUB_MOD_LICENSE ("GPLv3+");
30
31 static grub_uint8_t grub_gpt_magic[8] =
32 {
33 0x45, 0x46, 0x49, 0x20, 0x50, 0x41, 0x52, 0x54
34 };
35
36 static const grub_gpt_part_guid_t grub_gpt_partition_type_empty = GRUB_GPT_PARTITION_TYPE_EMPTY;
37
38 #ifdef GRUB_UTIL
39 static const grub_gpt_part_guid_t grub_gpt_partition_type_bios_boot = GRUB_GPT_PARTITION_TYPE_BIOS_BOOT;
40 #endif
41
42 /* 512 << 7 = 65536 byte sectors. */
43 #define MAX_SECTOR_LOG 7
44
45 static struct grub_partition_map grub_gpt_partition_map;
46
47 \f
48
49 grub_err_t
50 grub_gpt_partition_map_iterate (grub_disk_t disk,
51 grub_partition_iterate_hook_t hook,
52 void *hook_data)
53 {
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;
59 unsigned int i;
60 int last_offset = 0;
61 int sector_log = 0;
62
63 /* Read the protective MBR. */
64 if (grub_disk_read (disk, 0, 0, sizeof (mbr), &mbr))
65 return grub_errno;
66
67 /* Check if it is valid. */
68 if (mbr.signature != grub_cpu_to_le16_compile_time (GRUB_PC_PARTITION_SIGNATURE))
69 return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature");
70
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)
74 break;
75 if (i == 4)
76 return grub_error (GRUB_ERR_BAD_PART_TABLE, "no GPT partition map found");
77
78 /* Read the GPT header. */
79 for (sector_log = 0; sector_log < MAX_SECTOR_LOG; sector_log++)
80 {
81 if (grub_disk_read (disk, 1 << sector_log, 0, sizeof (gpt), &gpt))
82 return grub_errno;
83
84 if (grub_memcmp (gpt.magic, grub_gpt_magic, sizeof (grub_gpt_magic)) == 0)
85 break;
86 }
87 if (sector_log == MAX_SECTOR_LOG)
88 return grub_error (GRUB_ERR_BAD_PART_TABLE, "no valid GPT header");
89
90 grub_dprintf ("gpt", "Read a valid GPT header\n");
91
92 entries = grub_le_to_cpu64 (gpt.partitions) << sector_log;
93 for (i = 0; i < grub_le_to_cpu32 (gpt.maxpart); i++)
94 {
95 if (grub_disk_read (disk, entries, last_offset,
96 sizeof (entry), &entry))
97 return grub_errno;
98
99 if (grub_memcmp (&grub_gpt_partition_type_empty, &entry.type,
100 sizeof (grub_gpt_partition_type_empty)))
101 {
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;
107 part.number = i;
108 part.index = last_offset;
109 part.partmap = &grub_gpt_partition_map;
110 part.parent = disk->partition;
111 part.gpt_attrib = entry.attrib;
112
113 grub_dprintf ("gpt", "GPT entry %d: start=%lld, length=%lld\n", i,
114 (unsigned long long) part.start,
115 (unsigned long long) part.len);
116
117 if (hook (disk, &part, hook_data))
118 return grub_errno;
119 }
120
121 last_offset += grub_le_to_cpu32 (gpt.partentry_size);
122 if (last_offset == GRUB_DISK_SECTOR_SIZE)
123 {
124 last_offset = 0;
125 entries++;
126 }
127 }
128
129 return GRUB_ERR_NONE;
130 }
131
132 #ifdef GRUB_UTIL
133 /* Context for gpt_partition_map_embed. */
134 struct gpt_partition_map_embed_ctx
135 {
136 grub_disk_addr_t start, len;
137 };
138
139 /* Helper for gpt_partition_map_embed. */
140 static int
141 find_usable_region (grub_disk_t disk __attribute__ ((unused)),
142 const grub_partition_t p, void *data)
143 {
144 struct gpt_partition_map_embed_ctx *ctx = data;
145 struct grub_gpt_partentry gptdata;
146 grub_partition_t p2;
147
148 p2 = disk->partition;
149 disk->partition = p->parent;
150 if (grub_disk_read (disk, p->offset, p->index,
151 sizeof (gptdata), &gptdata))
152 {
153 disk->partition = p2;
154 return 0;
155 }
156 disk->partition = p2;
157
158 /* If there's an embed region, it is in a dedicated partition. */
159 if (! grub_memcmp (&gptdata.type, &grub_gpt_partition_type_bios_boot, 16))
160 {
161 ctx->start = p->start;
162 ctx->len = p->len;
163 return 1;
164 }
165
166 return 0;
167 }
168
169 static grub_err_t
170 gpt_partition_map_embed (struct grub_disk *disk, unsigned int *nsectors,
171 unsigned int max_nsectors,
172 grub_embed_type_t embed_type,
173 grub_disk_addr_t **sectors)
174 {
175 struct gpt_partition_map_embed_ctx ctx = {
176 .start = 0,
177 .len = 0
178 };
179 unsigned i;
180 grub_err_t err;
181
182 if (embed_type != GRUB_EMBED_PCBIOS)
183 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
184 "GPT currently supports only PC-BIOS embedding");
185
186 err = grub_gpt_partition_map_iterate (disk, find_usable_region, &ctx);
187 if (err)
188 return err;
189
190 if (ctx.len == 0)
191 return grub_error (GRUB_ERR_FILE_NOT_FOUND,
192 N_("this GPT partition label contains no BIOS Boot Partition;"
193 " embedding won't be possible"));
194
195 if (ctx.len < *nsectors)
196 return grub_error (GRUB_ERR_OUT_OF_RANGE,
197 N_("your BIOS Boot Partition is too small;"
198 " embedding won't be possible"));
199
200 *nsectors = ctx.len;
201 if (*nsectors > max_nsectors)
202 *nsectors = max_nsectors;
203 *sectors = grub_malloc (*nsectors * sizeof (**sectors));
204 if (!*sectors)
205 return grub_errno;
206 for (i = 0; i < *nsectors; i++)
207 (*sectors)[i] = ctx.start + i;
208
209 return GRUB_ERR_NONE;
210 }
211 #endif
212
213 \f
214 /* Partition map type. */
215 static struct grub_partition_map grub_gpt_partition_map =
216 {
217 .name = "gpt",
218 .iterate = grub_gpt_partition_map_iterate,
219 #ifdef GRUB_UTIL
220 .embed = gpt_partition_map_embed
221 #endif
222 };
223
224 GRUB_MOD_INIT(part_gpt)
225 {
226 grub_partition_map_register (&grub_gpt_partition_map);
227 }
228
229 GRUB_MOD_FINI(part_gpt)
230 {
231 grub_partition_map_unregister (&grub_gpt_partition_map);
232 }