Upgraded GRUB2 to 2.00 release.
[AROS.git] / arch / all-pc / boot / grub2-aros / grub-core / partmap / gpt.c
blob17f242d1d516564b5edbd48147d2cae3fb320c7d
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.
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>
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>
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;
38 #ifdef GRUB_UTIL
39 static const grub_gpt_part_type_t grub_gpt_partition_type_bios_boot = GRUB_GPT_PARTITION_TYPE_BIOS_BOOT;
40 #endif
42 /* 512 << 7 = 65536 byte sectors. */
43 #define MAX_SECTOR_LOG 7
45 static struct grub_partition_map grub_gpt_partition_map;
49 grub_err_t
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;
59 unsigned int i;
60 int last_offset = 0;
61 int sector_log = 0;
63 /* Read the protective MBR. */
64 if (grub_disk_read (disk, 0, 0, sizeof (mbr), &mbr))
65 return grub_errno;
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)
74 break;
75 if (i == 4)
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))
82 return grub_errno;
84 if (grub_memcmp (gpt.magic, grub_gpt_magic, sizeof (grub_gpt_magic)) == 0)
85 break;
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))
97 return grub_errno;
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;
107 part.number = i;
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))
117 return grub_errno;
120 last_offset += grub_le_to_cpu32 (gpt.partentry_size);
121 if (last_offset == GRUB_DISK_SECTOR_SIZE)
123 last_offset = 0;
124 entries++;
128 return GRUB_ERR_NONE;
131 #ifdef GRUB_UTIL
132 static grub_err_t
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;
139 unsigned i;
140 grub_err_t err;
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;
148 grub_partition_t p2;
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;
156 return 0;
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))
163 start = p->start;
164 len = p->len;
165 return 1;
168 return 0;
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);
176 if (err)
177 return err;
179 if (len == 0)
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"));
184 if (len < *nsectors)
185 return grub_error (GRUB_ERR_OUT_OF_RANGE,
186 N_("your BIOS Boot Partition is too small;"
187 " embedding won't be possible"));
189 *nsectors = len;
190 if (*nsectors > max_nsectors)
191 *nsectors = max_nsectors;
192 *sectors = grub_malloc (*nsectors * sizeof (**sectors));
193 if (!*sectors)
194 return grub_errno;
195 for (i = 0; i < *nsectors; i++)
196 (*sectors)[i] = start + i;
198 return GRUB_ERR_NONE;
200 #endif
203 /* Partition map type. */
204 static struct grub_partition_map grub_gpt_partition_map =
206 .name = "gpt",
207 .iterate = grub_gpt_partition_map_iterate,
208 #ifdef GRUB_UTIL
209 .embed = gpt_partition_map_embed
210 #endif
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);