Indentation fix, cleanup.
[AROS.git] / arch / all-pc / boot / grub2-aros / grub-core / partmap / msdos.c
blob46c406bff1fdbd9aa183e245a7c5779d33f5ad47
1 /* pc.c - Read PC style partition tables. */
2 /*
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>
23 #include <grub/mm.h>
24 #include <grub/misc.h>
25 #include <grub/dl.h>
26 #include <grub/i18n.h>
28 GRUB_MOD_LICENSE ("GPLv3+");
30 static struct grub_partition_map grub_msdos_partition_map;
33 #ifdef GRUB_UTIL
34 #include <grub/emu/misc.h>
36 struct embed_signature
38 const char *name;
39 const char *signature;
40 int signature_len;
41 enum { TYPE_SOFTWARE, TYPE_RAID } type;
44 const char message_warn[][200] = {
45 /* TRANSLATORS: MBR gap and boot track is the same thing and is the space
46 between MBR and first partitition. If your language translates well only
47 "boot track", you can just use it everywhere. Next two messages are about
48 RAID controllers/software bugs which GRUB has to live with. Please spread
49 the message that these are bugs in other software and not merely
50 suboptimal behaviour. */
51 [TYPE_RAID] = N_("Sector %llu is already in use by raid controller `%s';"
52 " avoiding it. "
53 "Please ask the manufacturer not to store data in MBR gap"),
54 [TYPE_SOFTWARE] = N_("Sector %llu is already in use by the program `%s';"
55 " avoiding it. "
56 "This software may cause boot or other problems in "
57 "future. Please ask its authors not to store data "
58 "in the boot track")
62 /* Signatures of other software that may be using sectors in the embedding
63 area. */
64 struct embed_signature embed_signatures[] =
67 .name = "ZISD",
68 .signature = "ZISD",
69 .signature_len = 4,
70 .type = TYPE_SOFTWARE
73 .name = "FlexNet",
74 .signature = "\xd4\x41\xa0\xf5\x03\x00\x03\x00",
75 .signature_len = 8,
76 .type = TYPE_SOFTWARE
79 .name = "FlexNet",
80 .signature = "\xd8\x41\xa0\xf5\x02\x00\x02\x00",
81 .signature_len = 8,
82 .type = TYPE_SOFTWARE
85 /* from Ryan Perkins */
86 .name = "HP Backup and Recovery Manager (?)",
87 .signature = "\x70\x8a\x5d\x46\x35\xc5\x1b\x93"
88 "\xae\x3d\x86\xfd\xb1\x55\x3e\xe0",
89 .signature_len = 16,
90 .type = TYPE_SOFTWARE
93 .name = "HighPoint RAID controller",
94 .signature = "ycgl",
95 .signature_len = 4,
96 .type = TYPE_RAID
99 /* https://bugs.launchpad.net/bugs/987022 */
100 .name = "Acer registration utility (?)",
101 .signature = "GREGRegDone.Tag\x00",
102 .signature_len = 16,
103 .type = TYPE_SOFTWARE
106 #endif
108 grub_err_t
109 grub_partition_msdos_iterate (grub_disk_t disk,
110 grub_partition_iterate_hook_t hook,
111 void *hook_data)
113 struct grub_partition p;
114 struct grub_msdos_partition_mbr mbr;
115 int labeln = 0;
116 grub_disk_addr_t lastaddr;
117 grub_disk_addr_t ext_offset;
118 grub_disk_addr_t delta = 0;
120 if (disk->partition && disk->partition->partmap == &grub_msdos_partition_map)
122 if (disk->partition->msdostype == GRUB_PC_PARTITION_TYPE_LINUX_MINIX)
123 delta = disk->partition->start;
124 else
125 return grub_error (GRUB_ERR_BAD_PART_TABLE, "no embedding supported");
128 p.offset = 0;
129 ext_offset = 0;
130 p.number = -1;
131 p.partmap = &grub_msdos_partition_map;
133 /* Any value different than `p.offset' will satisfy the check during
134 first loop. */
135 lastaddr = !p.offset;
137 while (1)
139 int i;
140 struct grub_msdos_partition_entry *e;
142 /* Read the MBR. */
143 if (grub_disk_read (disk, p.offset, 0, sizeof (mbr), &mbr))
144 goto finish;
146 /* If this is a GPT partition, this MBR is just a dummy. */
147 if (p.offset == 0)
148 for (i = 0; i < 4; i++)
149 if (mbr.entries[i].type == GRUB_PC_PARTITION_TYPE_GPT_DISK)
150 return grub_error (GRUB_ERR_BAD_PART_TABLE, "dummy mbr");
152 /* This is our loop-detection algorithm. It works the following way:
153 It saves last position which was a power of two. Then it compares the
154 saved value with a current one. This way it's guaranteed that the loop
155 will be broken by at most third walk.
157 if (labeln && lastaddr == p.offset)
158 return grub_error (GRUB_ERR_BAD_PART_TABLE, "loop detected");
160 labeln++;
161 if ((labeln & (labeln - 1)) == 0)
162 lastaddr = p.offset;
164 /* Check if it is valid. */
165 if (mbr.signature != grub_cpu_to_le16_compile_time (GRUB_PC_PARTITION_SIGNATURE))
166 return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature");
168 for (i = 0; i < 4; i++)
169 if (mbr.entries[i].flag & 0x7f)
170 return grub_error (GRUB_ERR_BAD_PART_TABLE, "bad boot flag");
172 /* Analyze DOS partitions. */
173 for (p.index = 0; p.index < 4; p.index++)
175 e = mbr.entries + p.index;
177 p.start = p.offset
178 + (grub_le_to_cpu32 (e->start)
179 << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS)) - delta;
180 p.len = grub_le_to_cpu32 (e->length)
181 << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS);
182 p.msdostype = e->type;
184 grub_dprintf ("partition",
185 "partition %d: flag 0x%x, type 0x%x, start 0x%llx, len 0x%llx\n",
186 p.index, e->flag, e->type,
187 (unsigned long long) p.start,
188 (unsigned long long) p.len);
190 /* If this partition is a normal one, call the hook. */
191 if (! grub_msdos_partition_is_empty (e->type)
192 && ! grub_msdos_partition_is_extended (e->type))
194 p.number++;
196 if (hook (disk, &p, hook_data))
197 return grub_errno;
199 else if (p.number < 3)
200 /* If this partition is a logical one, shouldn't increase the
201 partition number. */
202 p.number++;
205 /* Find an extended partition. */
206 for (i = 0; i < 4; i++)
208 e = mbr.entries + i;
210 if (grub_msdos_partition_is_extended (e->type))
212 p.offset = ext_offset
213 + (grub_le_to_cpu32 (e->start)
214 << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS));
215 if (! ext_offset)
216 ext_offset = p.offset;
218 break;
222 /* If no extended partition, the end. */
223 if (i == 4)
224 break;
227 finish:
228 return grub_errno;
231 #ifdef GRUB_UTIL
233 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
235 static grub_err_t
236 pc_partition_map_embed (struct grub_disk *disk, unsigned int *nsectors,
237 unsigned int max_nsectors,
238 grub_embed_type_t embed_type,
239 grub_disk_addr_t **sectors)
241 grub_disk_addr_t end = ~0ULL;
242 struct grub_msdos_partition_mbr mbr;
243 int labeln = 0;
244 /* Any value different than `p.offset' will satisfy the check during
245 first loop. */
246 grub_disk_addr_t lastaddr = 1;
247 grub_disk_addr_t ext_offset = 0;
248 grub_disk_addr_t offset = 0;
250 if (embed_type != GRUB_EMBED_PCBIOS)
251 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
252 "PC-style partitions curently support "
253 "only PC-BIOS embedding");
255 if (disk->partition)
256 return grub_error (GRUB_ERR_OUT_OF_RANGE,
257 "Embedding on MSDOS subpartition isn't supported");
259 while (1)
261 int i;
262 struct grub_msdos_partition_entry *e;
263 grub_err_t err;
265 /* Read the MBR. */
266 err = grub_disk_read (disk, offset, 0, sizeof (mbr), &mbr);
267 if (err)
268 return err;
270 /* This is our loop-detection algorithm. It works the following way:
271 It saves last position which was a power of two. Then it compares the
272 saved value with a current one. This way it's guaranteed that the loop
273 will be broken by at most third walk.
275 if (labeln && lastaddr == offset)
276 return grub_error (GRUB_ERR_BAD_PART_TABLE, "loop detected");
278 labeln++;
279 if ((labeln & (labeln - 1)) == 0)
280 lastaddr = offset;
282 /* Check if it is valid. */
283 if (mbr.signature != grub_cpu_to_le16_compile_time (GRUB_PC_PARTITION_SIGNATURE))
284 return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature");
286 for (i = 0; i < 4; i++)
287 if (mbr.entries[i].flag & 0x7f)
288 return grub_error (GRUB_ERR_BAD_PART_TABLE, "bad boot flag");
290 /* Analyze DOS partitions. */
291 for (i = 0; i < 4; i++)
293 e = mbr.entries + i;
295 if (!grub_msdos_partition_is_empty (e->type)
296 && end > offset
297 + (grub_le_to_cpu32 (e->start)
298 << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS)))
299 end = offset + (grub_le_to_cpu32 (e->start)
300 << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS));
302 /* If this is a GPT partition, this MBR is just a dummy. */
303 if (e->type == GRUB_PC_PARTITION_TYPE_GPT_DISK && i == 0)
304 return grub_error (GRUB_ERR_BAD_PART_TABLE, "dummy mbr");
307 /* Find an extended partition. */
308 for (i = 0; i < 4; i++)
310 e = mbr.entries + i;
312 if (grub_msdos_partition_is_extended (e->type))
314 offset = ext_offset
315 + (grub_le_to_cpu32 (e->start)
316 << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS));
317 if (! ext_offset)
318 ext_offset = offset;
320 break;
324 /* If no extended partition, the end. */
325 if (i == 4)
326 break;
329 if (end >= *nsectors + 1)
331 unsigned i, j;
332 char *embed_signature_check;
333 unsigned int orig_nsectors, avail_nsectors;
335 orig_nsectors = *nsectors;
336 *nsectors = end - 1;
337 avail_nsectors = *nsectors;
338 if (*nsectors > max_nsectors)
339 *nsectors = max_nsectors;
340 *sectors = grub_malloc (*nsectors * sizeof (**sectors));
341 if (!*sectors)
342 return grub_errno;
343 for (i = 0; i < *nsectors; i++)
344 (*sectors)[i] = 1 + i;
346 /* Check for software that is already using parts of the embedding
347 * area.
349 embed_signature_check = grub_malloc (GRUB_DISK_SECTOR_SIZE);
350 for (i = 0; i < *nsectors; i++)
352 if (grub_disk_read (disk, (*sectors)[i], 0, GRUB_DISK_SECTOR_SIZE,
353 embed_signature_check))
354 continue;
356 for (j = 0; j < ARRAY_SIZE (embed_signatures); j++)
357 if (! grub_memcmp (embed_signatures[j].signature,
358 embed_signature_check,
359 embed_signatures[j].signature_len))
360 break;
361 if (j == ARRAY_SIZE (embed_signatures))
362 continue;
363 grub_util_warn (_(message_warn[embed_signatures[j].type]),
364 (*sectors)[i], embed_signatures[j].name);
365 avail_nsectors--;
366 if (avail_nsectors < *nsectors)
367 *nsectors = avail_nsectors;
369 /* Avoid this sector. */
370 for (j = i; j < *nsectors; j++)
371 (*sectors)[j]++;
373 /* Have we run out of space? */
374 if (avail_nsectors < orig_nsectors)
375 break;
377 /* Make sure to check the next sector. */
378 i--;
380 grub_free (embed_signature_check);
382 if (*nsectors < orig_nsectors)
383 return grub_error (GRUB_ERR_OUT_OF_RANGE,
384 N_("other software is using the embedding area, and "
385 "there is not enough room for core.img. Such "
386 "software is often trying to store data in a way "
387 "that avoids detection. We recommend you "
388 "investigate"));
390 return GRUB_ERR_NONE;
393 if (end <= 1)
394 return grub_error (GRUB_ERR_FILE_NOT_FOUND,
395 N_("this msdos-style partition label has no "
396 "post-MBR gap; embedding won't be possible"));
398 if (*nsectors > 62)
399 return grub_error (GRUB_ERR_OUT_OF_RANGE,
400 N_("your core.img is unusually large. "
401 "It won't fit in the embedding area"));
403 return grub_error (GRUB_ERR_OUT_OF_RANGE,
404 N_("your embedding area is unusually small. "
405 "core.img won't fit in it."));
408 #pragma GCC diagnostic error "-Wformat-nonliteral"
410 #endif
413 /* Partition map type. */
414 static struct grub_partition_map grub_msdos_partition_map =
416 .name = "msdos",
417 .iterate = grub_partition_msdos_iterate,
418 #ifdef GRUB_UTIL
419 .embed = pc_partition_map_embed
420 #endif
423 GRUB_MOD_INIT(part_msdos)
425 grub_partition_map_register (&grub_msdos_partition_map);
428 GRUB_MOD_FINI(part_msdos)
430 grub_partition_map_unregister (&grub_msdos_partition_map);