gpt_misc.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. /* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
  2. * Use of this source code is governed by a BSD-style license that can be
  3. * found in the LICENSE file.
  4. */
  5. #include "2sysincludes.h"
  6. #include "2common.h"
  7. #include "sysincludes.h"
  8. #include "cgptlib.h"
  9. #include "cgptlib_internal.h"
  10. #include "crc32.h"
  11. #include "gpt.h"
  12. #include "utility.h"
  13. #include "vboot_api.h"
  14. /**
  15. * Allocate and read GPT data from the drive.
  16. *
  17. * The sector_bytes and gpt_drive_sectors fields should be filled on input. The
  18. * primary and secondary header and entries are filled on output.
  19. *
  20. * Returns 0 if successful, 1 if error.
  21. */
  22. int AllocAndReadGptData(VbExDiskHandle_t disk_handle, GptData *gptdata)
  23. {
  24. uint64_t max_entries_bytes = MAX_NUMBER_OF_ENTRIES * sizeof(GptEntry);
  25. int primary_valid = 0, secondary_valid = 0;
  26. /* No data to be written yet */
  27. gptdata->modified = 0;
  28. /* This should get overwritten by GptInit() */
  29. gptdata->ignored = 0;
  30. /* Allocate all buffers */
  31. gptdata->primary_header = (uint8_t *)malloc(gptdata->sector_bytes);
  32. gptdata->secondary_header =
  33. (uint8_t *)malloc(gptdata->sector_bytes);
  34. gptdata->primary_entries = (uint8_t *)malloc(max_entries_bytes);
  35. gptdata->secondary_entries = (uint8_t *)malloc(max_entries_bytes);
  36. if (gptdata->primary_header == NULL ||
  37. gptdata->secondary_header == NULL ||
  38. gptdata->primary_entries == NULL ||
  39. gptdata->secondary_entries == NULL)
  40. return 1;
  41. /* Read primary header from the drive, skipping the protective MBR */
  42. if (0 != VbExDiskRead(disk_handle, 1, 1, gptdata->primary_header)) {
  43. VB2_DEBUG("Read error in primary GPT header\n");
  44. memset(gptdata->primary_header, 0, gptdata->sector_bytes);
  45. }
  46. /* Only read primary GPT if the primary header is valid */
  47. GptHeader* primary_header = (GptHeader*)gptdata->primary_header;
  48. if (0 == CheckHeader(primary_header, 0,
  49. gptdata->streaming_drive_sectors,
  50. gptdata->gpt_drive_sectors,
  51. gptdata->flags)) {
  52. primary_valid = 1;
  53. uint64_t entries_bytes =
  54. (uint64_t)primary_header->number_of_entries
  55. * primary_header->size_of_entry;
  56. uint64_t entries_sectors = entries_bytes
  57. / gptdata->sector_bytes;
  58. if (0 != VbExDiskRead(disk_handle,
  59. primary_header->entries_lba,
  60. entries_sectors,
  61. gptdata->primary_entries)) {
  62. VB2_DEBUG("Read error in primary GPT entries\n");
  63. primary_valid = 0;
  64. }
  65. } else {
  66. VB2_DEBUG("Primary GPT header is %s\n",
  67. memcmp(primary_header->signature,
  68. GPT_HEADER_SIGNATURE_IGNORED,
  69. GPT_HEADER_SIGNATURE_SIZE)
  70. ? "invalid" : "being ignored");
  71. }
  72. /* Read secondary header from the end of the drive */
  73. if (0 != VbExDiskRead(disk_handle, gptdata->gpt_drive_sectors - 1, 1,
  74. gptdata->secondary_header)) {
  75. VB2_DEBUG("Read error in secondary GPT header\n");
  76. memset(gptdata->secondary_header, 0, gptdata->sector_bytes);
  77. }
  78. /* Only read secondary GPT if the secondary header is valid */
  79. GptHeader* secondary_header = (GptHeader*)gptdata->secondary_header;
  80. if (0 == CheckHeader(secondary_header, 1,
  81. gptdata->streaming_drive_sectors,
  82. gptdata->gpt_drive_sectors,
  83. gptdata->flags)) {
  84. secondary_valid = 1;
  85. uint64_t entries_bytes =
  86. (uint64_t)secondary_header->number_of_entries
  87. * secondary_header->size_of_entry;
  88. uint64_t entries_sectors = entries_bytes
  89. / gptdata->sector_bytes;
  90. if (0 != VbExDiskRead(disk_handle,
  91. secondary_header->entries_lba,
  92. entries_sectors,
  93. gptdata->secondary_entries)) {
  94. VB2_DEBUG("Read error in secondary GPT entries\n");
  95. secondary_valid = 0;
  96. }
  97. } else {
  98. VB2_DEBUG("Secondary GPT header is %s\n",
  99. memcmp(secondary_header->signature,
  100. GPT_HEADER_SIGNATURE_IGNORED,
  101. GPT_HEADER_SIGNATURE_SIZE)
  102. ? "invalid" : "being ignored");
  103. }
  104. /* Return 0 if least one GPT header was valid */
  105. return (primary_valid || secondary_valid) ? 0 : 1;
  106. }
  107. /**
  108. * Write any changes for the GPT data back to the drive, then free the buffers.
  109. *
  110. * Returns 0 if successful, 1 if error.
  111. */
  112. int WriteAndFreeGptData(VbExDiskHandle_t disk_handle, GptData *gptdata)
  113. {
  114. int skip_primary = 0;
  115. GptHeader *header;
  116. uint64_t entries_bytes, entries_sectors;
  117. int ret = 1;
  118. header = (GptHeader *)gptdata->primary_header;
  119. if (!header)
  120. header = (GptHeader *)gptdata->secondary_header;
  121. if (!header)
  122. return 1; /* No headers at all, so nothing to write */
  123. entries_bytes = (uint64_t)header->number_of_entries
  124. * header->size_of_entry;
  125. entries_sectors = entries_bytes / gptdata->sector_bytes;
  126. /*
  127. * TODO(namnguyen): Preserve padding between primary GPT header and
  128. * its entries.
  129. */
  130. uint64_t entries_lba = GPT_PMBR_SECTORS + GPT_HEADER_SECTORS;
  131. if (gptdata->primary_header) {
  132. GptHeader *h = (GptHeader *)(gptdata->primary_header);
  133. entries_lba = h->entries_lba;
  134. if (gptdata->ignored & MASK_PRIMARY) {
  135. VB2_DEBUG("Not updating primary GPT: "
  136. "marked to be ignored.\n");
  137. skip_primary = 1;
  138. } else if (gptdata->modified & GPT_MODIFIED_HEADER1) {
  139. if (!memcmp(h->signature, GPT_HEADER_SIGNATURE2,
  140. GPT_HEADER_SIGNATURE_SIZE)) {
  141. VB2_DEBUG("Not updating primary GPT: "
  142. "legacy mode is enabled.\n");
  143. skip_primary = 1;
  144. } else {
  145. VB2_DEBUG("Updating GPT header 1\n");
  146. if (0 != VbExDiskWrite(disk_handle, 1, 1,
  147. gptdata->primary_header))
  148. goto fail;
  149. }
  150. }
  151. }
  152. if (gptdata->primary_entries && !skip_primary) {
  153. if (gptdata->modified & GPT_MODIFIED_ENTRIES1) {
  154. VB2_DEBUG("Updating GPT entries 1\n");
  155. if (0 != VbExDiskWrite(disk_handle, entries_lba,
  156. entries_sectors,
  157. gptdata->primary_entries))
  158. goto fail;
  159. }
  160. }
  161. entries_lba = (gptdata->gpt_drive_sectors - entries_sectors -
  162. GPT_HEADER_SECTORS);
  163. if (gptdata->secondary_header && !(gptdata->ignored & MASK_SECONDARY)) {
  164. GptHeader *h = (GptHeader *)(gptdata->secondary_header);
  165. entries_lba = h->entries_lba;
  166. if (gptdata->modified & GPT_MODIFIED_HEADER2) {
  167. VB2_DEBUG("Updating GPT header 2\n");
  168. if (0 != VbExDiskWrite(disk_handle,
  169. gptdata->gpt_drive_sectors - 1, 1,
  170. gptdata->secondary_header))
  171. goto fail;
  172. }
  173. }
  174. if (gptdata->secondary_entries && !(gptdata->ignored & MASK_SECONDARY)){
  175. if (gptdata->modified & GPT_MODIFIED_ENTRIES2) {
  176. VB2_DEBUG("Updating GPT entries 2\n");
  177. if (0 != VbExDiskWrite(disk_handle,
  178. entries_lba, entries_sectors,
  179. gptdata->secondary_entries))
  180. goto fail;
  181. }
  182. }
  183. ret = 0;
  184. fail:
  185. /* Avoid leaking memory on disk write failure */
  186. if (gptdata->primary_header)
  187. free(gptdata->primary_header);
  188. if (gptdata->primary_entries)
  189. free(gptdata->primary_entries);
  190. if (gptdata->secondary_entries)
  191. free(gptdata->secondary_entries);
  192. if (gptdata->secondary_header)
  193. free(gptdata->secondary_header);
  194. /* Success */
  195. return ret;
  196. }
  197. int IsUnusedEntry(const GptEntry *e)
  198. {
  199. static Guid zero = {{{0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0}}}};
  200. return !memcmp(&zero, (const uint8_t*)(&e->type), sizeof(zero));
  201. }
  202. /*
  203. * Func: GptGetEntrySize
  204. * Desc: This function returns size(in lba) of a partition represented by
  205. * given GPT entry.
  206. */
  207. size_t GptGetEntrySizeLba(const GptEntry *e)
  208. {
  209. return (e->ending_lba - e->starting_lba + 1);
  210. }
  211. /*
  212. * Func: GptGetEntrySize
  213. * Desc: This function returns size(in bytes) of a partition represented by
  214. * given GPT entry.
  215. */
  216. size_t GptGetEntrySizeBytes(const GptData *gpt, const GptEntry *e)
  217. {
  218. return GptGetEntrySizeLba(e) * gpt->sector_bytes;
  219. }