msdos.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  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.
  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. #include <grub/partition.h>
  20. #include <grub/msdos_partition.h>
  21. #include <grub/disk.h>
  22. #include <grub/mm.h>
  23. #include <grub/misc.h>
  24. #include <grub/dl.h>
  25. static struct grub_partition_map grub_msdos_partition_map;
  26. static grub_err_t
  27. pc_partition_map_iterate (grub_disk_t disk,
  28. int (*hook) (grub_disk_t disk,
  29. const grub_partition_t partition,
  30. void *closure),
  31. void *closure)
  32. {
  33. struct grub_partition p;
  34. struct grub_msdos_partition_mbr mbr;
  35. int labeln = 0;
  36. grub_disk_addr_t lastaddr;
  37. grub_disk_addr_t ext_offset;
  38. p.offset = 0;
  39. ext_offset = 0;
  40. p.number = -1;
  41. p.partmap = &grub_msdos_partition_map;
  42. /* Any value different than `p.offset' will satisfy the check during
  43. first loop. */
  44. lastaddr = !p.offset;
  45. while (1)
  46. {
  47. int i;
  48. struct grub_msdos_partition_entry *e;
  49. /* Read the MBR. */
  50. if (grub_disk_read (disk, p.offset, 0, sizeof (mbr), &mbr))
  51. goto finish;
  52. /* This is our loop-detection algorithm. It works the following way:
  53. It saves last position which was a power of two. Then it compares the
  54. saved value with a current one. This way it's guaranteed that the loop
  55. will be broken by at most third walk.
  56. */
  57. if (labeln && lastaddr == p.offset)
  58. return grub_error (GRUB_ERR_BAD_PART_TABLE, "loop detected");
  59. labeln++;
  60. if ((labeln & (labeln - 1)) == 0)
  61. lastaddr = p.offset;
  62. /* Check if it is valid. */
  63. if (mbr.signature != grub_cpu_to_le16 (GRUB_PC_PARTITION_SIGNATURE))
  64. return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature");
  65. for (i = 0; i < 4; i++)
  66. if (mbr.entries[i].flag & 0x7f)
  67. return grub_error (GRUB_ERR_BAD_PART_TABLE, "bad boot flag");
  68. /* Analyze DOS partitions. */
  69. for (p.index = 0; p.index < 4; p.index++)
  70. {
  71. e = mbr.entries + p.index;
  72. p.start = p.offset + grub_le_to_cpu32 (e->start);
  73. p.len = grub_le_to_cpu32 (e->length);
  74. grub_dprintf ("partition",
  75. "partition %d: flag 0x%x, type 0x%x, start 0x%llx, len 0x%llx\n",
  76. p.index, e->flag, e->type,
  77. (unsigned long long) p.start,
  78. (unsigned long long) p.len);
  79. /* If this is a GPT partition, this MBR is just a dummy. */
  80. if (e->type == GRUB_PC_PARTITION_TYPE_GPT_DISK && p.index == 0)
  81. return grub_error (GRUB_ERR_BAD_PART_TABLE, "dummy mbr");
  82. /* If this partition is a normal one, call the hook. */
  83. if (! grub_msdos_partition_is_empty (e->type)
  84. && ! grub_msdos_partition_is_extended (e->type))
  85. {
  86. p.number++;
  87. if (hook (disk, &p, closure))
  88. return grub_errno;
  89. }
  90. else if (p.number < 4)
  91. /* If this partition is a logical one, shouldn't increase the
  92. partition number. */
  93. p.number++;
  94. }
  95. /* Find an extended partition. */
  96. for (i = 0; i < 4; i++)
  97. {
  98. e = mbr.entries + i;
  99. if (grub_msdos_partition_is_extended (e->type))
  100. {
  101. p.offset = ext_offset + grub_le_to_cpu32 (e->start);
  102. if (! ext_offset)
  103. ext_offset = p.offset;
  104. break;
  105. }
  106. }
  107. /* If no extended partition, the end. */
  108. if (i == 4)
  109. break;
  110. }
  111. finish:
  112. return grub_errno;
  113. }
  114. /* Partition map type. */
  115. static struct grub_partition_map grub_msdos_partition_map =
  116. {
  117. .name = "msdos",
  118. .iterate = pc_partition_map_iterate,
  119. };
  120. GRUB_MOD_INIT(part_msdos)
  121. {
  122. grub_partition_map_register (&grub_msdos_partition_map);
  123. }
  124. GRUB_MOD_FINI(part_msdos)
  125. {
  126. grub_partition_map_unregister (&grub_msdos_partition_map);
  127. }