1
/* pc.c - Read PC style partition tables. */
3
* GRUB -- GRand Unified Bootloader
4
* Copyright (C) 2002,2004,2005,2006,2007,2008,2009 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/partition.h>
21
#include <grub/msdos_partition.h>
22
#include <grub/disk.h>
24
#include <grub/misc.h>
27
static struct grub_partition_map grub_msdos_partition_map;
31
grub_partition_msdos_iterate (grub_disk_t disk,
32
int (*hook) (grub_disk_t disk,
33
const grub_partition_t partition))
35
struct grub_partition p;
36
struct grub_msdos_partition_mbr mbr;
38
grub_disk_addr_t lastaddr;
39
grub_disk_addr_t ext_offset;
40
grub_disk_addr_t delta = 0;
42
if (disk->partition && disk->partition->partmap == &grub_msdos_partition_map)
44
if (disk->partition->msdostype == GRUB_PC_PARTITION_TYPE_LINUX_MINIX)
45
delta = disk->partition->start;
47
return grub_error (GRUB_ERR_BAD_PART_TABLE, "no embedding supported");
53
p.partmap = &grub_msdos_partition_map;
55
/* Any value different than `p.offset' will satisfy the check during
62
struct grub_msdos_partition_entry *e;
65
if (grub_disk_read (disk, p.offset, 0, sizeof (mbr), &mbr))
68
/* This is our loop-detection algorithm. It works the following way:
69
It saves last position which was a power of two. Then it compares the
70
saved value with a current one. This way it's guaranteed that the loop
71
will be broken by at most third walk.
73
if (labeln && lastaddr == p.offset)
74
return grub_error (GRUB_ERR_BAD_PART_TABLE, "loop detected");
77
if ((labeln & (labeln - 1)) == 0)
80
/* Check if it is valid. */
81
if (mbr.signature != grub_cpu_to_le16 (GRUB_PC_PARTITION_SIGNATURE))
82
return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature");
84
for (i = 0; i < 4; i++)
85
if (mbr.entries[i].flag & 0x7f)
86
return grub_error (GRUB_ERR_BAD_PART_TABLE, "bad boot flag");
88
/* Analyze DOS partitions. */
89
for (p.index = 0; p.index < 4; p.index++)
91
e = mbr.entries + p.index;
93
p.start = p.offset + grub_le_to_cpu32 (e->start) - delta;
94
p.len = grub_le_to_cpu32 (e->length);
95
p.msdostype = e->type;
97
grub_dprintf ("partition",
98
"partition %d: flag 0x%x, type 0x%x, start 0x%llx, len 0x%llx\n",
99
p.index, e->flag, e->type,
100
(unsigned long long) p.start,
101
(unsigned long long) p.len);
103
/* If this is a GPT partition, this MBR is just a dummy. */
104
if (e->type == GRUB_PC_PARTITION_TYPE_GPT_DISK && p.index == 0)
105
return grub_error (GRUB_ERR_BAD_PART_TABLE, "dummy mbr");
107
/* If this partition is a normal one, call the hook. */
108
if (! grub_msdos_partition_is_empty (e->type)
109
&& ! grub_msdos_partition_is_extended (e->type))
116
else if (p.number < 4)
117
/* If this partition is a logical one, shouldn't increase the
122
/* Find an extended partition. */
123
for (i = 0; i < 4; i++)
127
if (grub_msdos_partition_is_extended (e->type))
129
p.offset = ext_offset + grub_le_to_cpu32 (e->start);
131
ext_offset = p.offset;
137
/* If no extended partition, the end. */
148
pc_partition_map_embed (struct grub_disk *disk, unsigned int *nsectors,
149
grub_embed_type_t embed_type,
150
grub_disk_addr_t **sectors)
152
grub_disk_addr_t end = ~0ULL;
153
struct grub_msdos_partition_mbr mbr;
155
/* Any value different than `p.offset' will satisfy the check during
157
grub_disk_addr_t lastaddr = 1;
158
grub_disk_addr_t ext_offset = 0;
159
grub_disk_addr_t offset = 0;
161
if (embed_type != GRUB_EMBED_PCBIOS)
162
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
163
"PC-style partitions curently support "
164
"only PC-BIOS embedding");
167
return grub_error (GRUB_ERR_OUT_OF_RANGE,
168
"Embedding on MSDOS subpartition isn't supported");
173
struct grub_msdos_partition_entry *e;
177
err = grub_disk_read (disk, offset, 0, sizeof (mbr), &mbr);
181
/* This is our loop-detection algorithm. It works the following way:
182
It saves last position which was a power of two. Then it compares the
183
saved value with a current one. This way it's guaranteed that the loop
184
will be broken by at most third walk.
186
if (labeln && lastaddr == offset)
187
return grub_error (GRUB_ERR_BAD_PART_TABLE, "loop detected");
190
if ((labeln & (labeln - 1)) == 0)
193
/* Check if it is valid. */
194
if (mbr.signature != grub_cpu_to_le16 (GRUB_PC_PARTITION_SIGNATURE))
195
return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature");
197
for (i = 0; i < 4; i++)
198
if (mbr.entries[i].flag & 0x7f)
199
return grub_error (GRUB_ERR_BAD_PART_TABLE, "bad boot flag");
201
/* Analyze DOS partitions. */
202
for (i = 0; i < 4; i++)
206
if (!grub_msdos_partition_is_empty (e->type)
207
&& end > offset + grub_le_to_cpu32 (e->start))
208
end = offset + grub_le_to_cpu32 (e->start);
210
/* If this is a GPT partition, this MBR is just a dummy. */
211
if (e->type == GRUB_PC_PARTITION_TYPE_GPT_DISK && i == 0)
212
return grub_error (GRUB_ERR_BAD_PART_TABLE, "dummy mbr");
215
/* Find an extended partition. */
216
for (i = 0; i < 4; i++)
220
if (grub_msdos_partition_is_extended (e->type))
222
offset = ext_offset + grub_le_to_cpu32 (e->start);
230
/* If no extended partition, the end. */
235
if (end >= *nsectors + 1)
239
*sectors = grub_malloc (*nsectors * sizeof (**sectors));
242
for (i = 0; i < *nsectors; i++)
243
(*sectors)[i] = 1 + i;
244
return GRUB_ERR_NONE;
248
return grub_error (GRUB_ERR_FILE_NOT_FOUND,
249
"This msdos-style partition label has no "
250
"post-MBR gap; embedding won't be possible!");
253
return grub_error (GRUB_ERR_OUT_OF_RANGE,
254
"Your core.img is unusually large. "
255
"It won't fit in the embedding area.");
257
return grub_error (GRUB_ERR_OUT_OF_RANGE,
258
"Your embedding area is unusually small. "
259
"core.img won't fit in it.");
264
/* Partition map type. */
265
static struct grub_partition_map grub_msdos_partition_map =
268
.iterate = grub_partition_msdos_iterate,
270
.embed = pc_partition_map_embed
274
GRUB_MOD_INIT(part_msdos)
276
grub_partition_map_register (&grub_msdos_partition_map);
279
GRUB_MOD_FINI(part_msdos)
281
grub_partition_map_unregister (&grub_msdos_partition_map);