Commit 40684ddb83a500f25d813fab7323a190a707402c
Committed by
Tom Rini
1 parent
fae2bf22a2
Exists in
master
and in
54 other branches
gpt: Support for GPT (GUID Partition Table) restoration
The restoration of GPT table (both primary and secondary) is now possible. Function 'gpt_restore' presents example of partition restoration process. Signed-off-by: Lukasz Majewski <l.majewski@samsung.com> Signed-off-by: Piotr Wilczek <p.wilczek@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Showing 2 changed files with 330 additions and 3 deletions Side-by-side Diff
disk/part_efi.c
... | ... | @@ -37,6 +37,8 @@ |
37 | 37 | #include <part_efi.h> |
38 | 38 | #include <linux/ctype.h> |
39 | 39 | |
40 | +DECLARE_GLOBAL_DATA_PTR; | |
41 | + | |
40 | 42 | #if defined(CONFIG_CMD_IDE) || \ |
41 | 43 | defined(CONFIG_CMD_SATA) || \ |
42 | 44 | defined(CONFIG_CMD_SCSI) || \ |
43 | 45 | |
44 | 46 | |
... | ... | @@ -62,13 +64,10 @@ |
62 | 64 | |
63 | 65 | static int pmbr_part_valid(struct partition *part); |
64 | 66 | static int is_pmbr_valid(legacy_mbr * mbr); |
65 | - | |
66 | 67 | static int is_gpt_valid(block_dev_desc_t * dev_desc, unsigned long long lba, |
67 | 68 | gpt_header * pgpt_head, gpt_entry ** pgpt_pte); |
68 | - | |
69 | 69 | static gpt_entry *alloc_read_gpt_entries(block_dev_desc_t * dev_desc, |
70 | 70 | gpt_header * pgpt_head); |
71 | - | |
72 | 71 | static int is_pte_valid(gpt_entry * pte); |
73 | 72 | |
74 | 73 | static char *print_efiname(gpt_entry *pte) |
... | ... | @@ -114,6 +113,7 @@ |
114 | 113 | sizeof(efi_guid_t)); |
115 | 114 | } |
116 | 115 | |
116 | +#ifdef CONFIG_EFI_PARTITION | |
117 | 117 | /* |
118 | 118 | * Public Functions (include/part.h) |
119 | 119 | */ |
... | ... | @@ -224,6 +224,281 @@ |
224 | 224 | } |
225 | 225 | return 0; |
226 | 226 | } |
227 | + | |
228 | +/** | |
229 | + * set_protective_mbr(): Set the EFI protective MBR | |
230 | + * @param dev_desc - block device descriptor | |
231 | + * | |
232 | + * @return - zero on success, otherwise error | |
233 | + */ | |
234 | +static int set_protective_mbr(block_dev_desc_t *dev_desc) | |
235 | +{ | |
236 | + legacy_mbr *p_mbr; | |
237 | + | |
238 | + /* Setup the Protective MBR */ | |
239 | + p_mbr = calloc(1, sizeof(p_mbr)); | |
240 | + if (p_mbr == NULL) { | |
241 | + printf("%s: calloc failed!\n", __func__); | |
242 | + return -1; | |
243 | + } | |
244 | + /* Append signature */ | |
245 | + p_mbr->signature = MSDOS_MBR_SIGNATURE; | |
246 | + p_mbr->partition_record[0].sys_ind = EFI_PMBR_OSTYPE_EFI_GPT; | |
247 | + p_mbr->partition_record[0].start_sect = 1; | |
248 | + p_mbr->partition_record[0].nr_sects = (u32) dev_desc->lba; | |
249 | + | |
250 | + /* Write MBR sector to the MMC device */ | |
251 | + if (dev_desc->block_write(dev_desc->dev, 0, 1, p_mbr) != 1) { | |
252 | + printf("** Can't write to device %d **\n", | |
253 | + dev_desc->dev); | |
254 | + free(p_mbr); | |
255 | + return -1; | |
256 | + } | |
257 | + | |
258 | + free(p_mbr); | |
259 | + return 0; | |
260 | +} | |
261 | + | |
262 | +/** | |
263 | + * string_uuid(); Convert UUID stored as string to bytes | |
264 | + * | |
265 | + * @param uuid - UUID represented as string | |
266 | + * @param dst - GUID buffer | |
267 | + * | |
268 | + * @return return 0 on successful conversion | |
269 | + */ | |
270 | +static int string_uuid(char *uuid, u8 *dst) | |
271 | +{ | |
272 | + efi_guid_t guid; | |
273 | + u16 b, c, d; | |
274 | + u64 e; | |
275 | + u32 a; | |
276 | + u8 *p; | |
277 | + u8 i; | |
278 | + | |
279 | + const u8 uuid_str_len = 36; | |
280 | + | |
281 | + /* The UUID is written in text: */ | |
282 | + /* 1 9 14 19 24 */ | |
283 | + /* xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx */ | |
284 | + | |
285 | + debug("%s: uuid: %s\n", __func__, uuid); | |
286 | + | |
287 | + if (strlen(uuid) != uuid_str_len) | |
288 | + return -1; | |
289 | + | |
290 | + for (i = 0; i < uuid_str_len; i++) { | |
291 | + if ((i == 8) || (i == 13) || (i == 18) || (i == 23)) { | |
292 | + if (uuid[i] != '-') | |
293 | + return -1; | |
294 | + } else { | |
295 | + if (!isxdigit(uuid[i])) | |
296 | + return -1; | |
297 | + } | |
298 | + } | |
299 | + | |
300 | + a = (u32)simple_strtoul(uuid, NULL, 16); | |
301 | + b = (u16)simple_strtoul(uuid + 9, NULL, 16); | |
302 | + c = (u16)simple_strtoul(uuid + 14, NULL, 16); | |
303 | + d = (u16)simple_strtoul(uuid + 19, NULL, 16); | |
304 | + e = (u64)simple_strtoull(uuid + 24, NULL, 16); | |
305 | + | |
306 | + p = (u8 *) &e; | |
307 | + guid = EFI_GUID(a, b, c, d >> 8, d & 0xFF, | |
308 | + *(p + 5), *(p + 4), *(p + 3), | |
309 | + *(p + 2), *(p + 1) , *p); | |
310 | + | |
311 | + memcpy(dst, guid.b, sizeof(efi_guid_t)); | |
312 | + | |
313 | + return 0; | |
314 | +} | |
315 | + | |
316 | +int write_gpt_table(block_dev_desc_t *dev_desc, | |
317 | + gpt_header *gpt_h, gpt_entry *gpt_e) | |
318 | +{ | |
319 | + const int pte_blk_num = (gpt_h->num_partition_entries | |
320 | + * sizeof(gpt_entry)) / dev_desc->blksz; | |
321 | + | |
322 | + u32 calc_crc32; | |
323 | + u64 val; | |
324 | + | |
325 | + debug("max lba: %x\n", (u32) dev_desc->lba); | |
326 | + /* Setup the Protective MBR */ | |
327 | + if (set_protective_mbr(dev_desc) < 0) | |
328 | + goto err; | |
329 | + | |
330 | + /* Generate CRC for the Primary GPT Header */ | |
331 | + calc_crc32 = efi_crc32((const unsigned char *)gpt_e, | |
332 | + le32_to_cpu(gpt_h->num_partition_entries) * | |
333 | + le32_to_cpu(gpt_h->sizeof_partition_entry)); | |
334 | + gpt_h->partition_entry_array_crc32 = cpu_to_le32(calc_crc32); | |
335 | + | |
336 | + calc_crc32 = efi_crc32((const unsigned char *)gpt_h, | |
337 | + le32_to_cpu(gpt_h->header_size)); | |
338 | + gpt_h->header_crc32 = cpu_to_le32(calc_crc32); | |
339 | + | |
340 | + /* Write the First GPT to the block right after the Legacy MBR */ | |
341 | + if (dev_desc->block_write(dev_desc->dev, 1, 1, gpt_h) != 1) | |
342 | + goto err; | |
343 | + | |
344 | + if (dev_desc->block_write(dev_desc->dev, 2, pte_blk_num, gpt_e) | |
345 | + != pte_blk_num) | |
346 | + goto err; | |
347 | + | |
348 | + /* recalculate the values for the Second GPT Header */ | |
349 | + val = le64_to_cpu(gpt_h->my_lba); | |
350 | + gpt_h->my_lba = gpt_h->alternate_lba; | |
351 | + gpt_h->alternate_lba = cpu_to_le64(val); | |
352 | + gpt_h->header_crc32 = 0; | |
353 | + | |
354 | + calc_crc32 = efi_crc32((const unsigned char *)gpt_h, | |
355 | + le32_to_cpu(gpt_h->header_size)); | |
356 | + gpt_h->header_crc32 = cpu_to_le32(calc_crc32); | |
357 | + | |
358 | + if (dev_desc->block_write(dev_desc->dev, | |
359 | + le32_to_cpu(gpt_h->last_usable_lba + 1), | |
360 | + pte_blk_num, gpt_e) != pte_blk_num) | |
361 | + goto err; | |
362 | + | |
363 | + if (dev_desc->block_write(dev_desc->dev, | |
364 | + le32_to_cpu(gpt_h->my_lba), 1, gpt_h) != 1) | |
365 | + goto err; | |
366 | + | |
367 | + debug("GPT successfully written to block device!\n"); | |
368 | + return 0; | |
369 | + | |
370 | + err: | |
371 | + printf("** Can't write to device %d **\n", dev_desc->dev); | |
372 | + return -1; | |
373 | +} | |
374 | + | |
375 | +int gpt_fill_pte(gpt_header *gpt_h, gpt_entry *gpt_e, | |
376 | + disk_partition_t *partitions, int parts) | |
377 | +{ | |
378 | + u32 offset = (u32)le32_to_cpu(gpt_h->first_usable_lba); | |
379 | + ulong start; | |
380 | + int i, k; | |
381 | + size_t name_len; | |
382 | +#ifdef CONFIG_PARTITION_UUIDS | |
383 | + char *str_uuid; | |
384 | +#endif | |
385 | + | |
386 | + for (i = 0; i < parts; i++) { | |
387 | + /* partition starting lba */ | |
388 | + start = partitions[i].start; | |
389 | + if (start && (start < offset)) { | |
390 | + printf("Partition overlap\n"); | |
391 | + return -1; | |
392 | + } | |
393 | + if (start) { | |
394 | + gpt_e[i].starting_lba = cpu_to_le64(start); | |
395 | + offset = start + partitions[i].size; | |
396 | + } else { | |
397 | + gpt_e[i].starting_lba = cpu_to_le64(offset); | |
398 | + offset += partitions[i].size; | |
399 | + } | |
400 | + if (offset >= gpt_h->last_usable_lba) { | |
401 | + printf("Partitions layout exceds disk size\n"); | |
402 | + return -1; | |
403 | + } | |
404 | + /* partition ending lba */ | |
405 | + if ((i == parts - 1) && (partitions[i].size == 0)) | |
406 | + /* extend the last partition to maximuim */ | |
407 | + gpt_e[i].ending_lba = gpt_h->last_usable_lba; | |
408 | + else | |
409 | + gpt_e[i].ending_lba = cpu_to_le64(offset - 1); | |
410 | + | |
411 | + /* partition type GUID */ | |
412 | + memcpy(gpt_e[i].partition_type_guid.b, | |
413 | + &PARTITION_BASIC_DATA_GUID, 16); | |
414 | + | |
415 | +#ifdef CONFIG_PARTITION_UUIDS | |
416 | + str_uuid = partitions[i].uuid; | |
417 | + if (string_uuid(str_uuid, gpt_e[i].unique_partition_guid.b)) { | |
418 | + printf("Partition no. %d: invalid guid: %s\n", | |
419 | + i, str_uuid); | |
420 | + return -1; | |
421 | + } | |
422 | +#endif | |
423 | + | |
424 | + /* partition attributes */ | |
425 | + memset(&gpt_e[i].attributes, 0, | |
426 | + sizeof(gpt_entry_attributes)); | |
427 | + | |
428 | + /* partition name */ | |
429 | + name_len = sizeof(gpt_e[i].partition_name) | |
430 | + / sizeof(efi_char16_t); | |
431 | + for (k = 0; k < name_len; k++) | |
432 | + gpt_e[i].partition_name[k] = | |
433 | + (efi_char16_t)(partitions[i].name[k]); | |
434 | + | |
435 | + debug("%s: name: %s offset[%d]: 0x%x size[%d]: 0x%lx\n", | |
436 | + __func__, partitions[i].name, i, | |
437 | + offset, i, partitions[i].size); | |
438 | + } | |
439 | + | |
440 | + return 0; | |
441 | +} | |
442 | + | |
443 | +int gpt_fill_header(block_dev_desc_t *dev_desc, gpt_header *gpt_h, | |
444 | + char *str_guid, int parts_count) | |
445 | +{ | |
446 | + gpt_h->signature = cpu_to_le64(GPT_HEADER_SIGNATURE); | |
447 | + gpt_h->revision = cpu_to_le32(GPT_HEADER_REVISION_V1); | |
448 | + gpt_h->header_size = cpu_to_le32(sizeof(gpt_header)); | |
449 | + gpt_h->my_lba = cpu_to_le64(1); | |
450 | + gpt_h->alternate_lba = cpu_to_le64(dev_desc->lba - 1); | |
451 | + gpt_h->first_usable_lba = cpu_to_le64(34); | |
452 | + gpt_h->last_usable_lba = cpu_to_le64(dev_desc->lba - 34); | |
453 | + gpt_h->partition_entry_lba = cpu_to_le64(2); | |
454 | + gpt_h->num_partition_entries = cpu_to_le32(GPT_ENTRY_NUMBERS); | |
455 | + gpt_h->sizeof_partition_entry = cpu_to_le32(sizeof(gpt_entry)); | |
456 | + gpt_h->header_crc32 = 0; | |
457 | + gpt_h->partition_entry_array_crc32 = 0; | |
458 | + | |
459 | + if (string_uuid(str_guid, gpt_h->disk_guid.b)) | |
460 | + return -1; | |
461 | + | |
462 | + return 0; | |
463 | +} | |
464 | + | |
465 | +int gpt_restore(block_dev_desc_t *dev_desc, char *str_disk_guid, | |
466 | + disk_partition_t *partitions, int parts_count) | |
467 | +{ | |
468 | + int ret; | |
469 | + | |
470 | + gpt_header *gpt_h = calloc(1, sizeof(gpt_header)); | |
471 | + if (gpt_h == NULL) { | |
472 | + printf("%s: calloc failed!\n", __func__); | |
473 | + return -1; | |
474 | + } | |
475 | + | |
476 | + gpt_entry *gpt_e = calloc(GPT_ENTRY_NUMBERS, sizeof(gpt_entry)); | |
477 | + if (gpt_e == NULL) { | |
478 | + printf("%s: calloc failed!\n", __func__); | |
479 | + free(gpt_h); | |
480 | + return -1; | |
481 | + } | |
482 | + | |
483 | + /* Generate Primary GPT header (LBA1) */ | |
484 | + ret = gpt_fill_header(dev_desc, gpt_h, str_disk_guid, parts_count); | |
485 | + if (ret) | |
486 | + goto err; | |
487 | + | |
488 | + /* Generate partition entries */ | |
489 | + ret = gpt_fill_pte(gpt_h, gpt_e, partitions, parts_count); | |
490 | + if (ret) | |
491 | + goto err; | |
492 | + | |
493 | + /* Write GPT partition table */ | |
494 | + ret = write_gpt_table(dev_desc, gpt_h, gpt_e); | |
495 | + | |
496 | +err: | |
497 | + free(gpt_e); | |
498 | + free(gpt_h); | |
499 | + return ret; | |
500 | +} | |
501 | +#endif | |
227 | 502 | |
228 | 503 | /* |
229 | 504 | * Private functions |
include/part.h
... | ... | @@ -176,10 +176,62 @@ |
176 | 176 | #endif |
177 | 177 | |
178 | 178 | #ifdef CONFIG_EFI_PARTITION |
179 | +#include <part_efi.h> | |
179 | 180 | /* disk/part_efi.c */ |
180 | 181 | int get_partition_info_efi (block_dev_desc_t * dev_desc, int part, disk_partition_t *info); |
181 | 182 | void print_part_efi (block_dev_desc_t *dev_desc); |
182 | 183 | int test_part_efi (block_dev_desc_t *dev_desc); |
184 | + | |
185 | +/** | |
186 | + * write_gpt_table() - Write the GUID Partition Table to disk | |
187 | + * | |
188 | + * @param dev_desc - block device descriptor | |
189 | + * @param gpt_h - pointer to GPT header representation | |
190 | + * @param gpt_e - pointer to GPT partition table entries | |
191 | + * | |
192 | + * @return - zero on success, otherwise error | |
193 | + */ | |
194 | +int write_gpt_table(block_dev_desc_t *dev_desc, | |
195 | + gpt_header *gpt_h, gpt_entry *gpt_e); | |
196 | + | |
197 | +/** | |
198 | + * gpt_fill_pte(): Fill the GPT partition table entry | |
199 | + * | |
200 | + * @param gpt_h - GPT header representation | |
201 | + * @param gpt_e - GPT partition table entries | |
202 | + * @param partitions - list of partitions | |
203 | + * @param parts - number of partitions | |
204 | + * | |
205 | + * @return zero on success | |
206 | + */ | |
207 | +int gpt_fill_pte(gpt_header *gpt_h, gpt_entry *gpt_e, | |
208 | + disk_partition_t *partitions, int parts); | |
209 | + | |
210 | +/** | |
211 | + * gpt_fill_header(): Fill the GPT header | |
212 | + * | |
213 | + * @param dev_desc - block device descriptor | |
214 | + * @param gpt_h - GPT header representation | |
215 | + * @param str_guid - disk guid string representation | |
216 | + * @param parts_count - number of partitions | |
217 | + * | |
218 | + * @return - error on str_guid conversion error | |
219 | + */ | |
220 | +int gpt_fill_header(block_dev_desc_t *dev_desc, gpt_header *gpt_h, | |
221 | + char *str_guid, int parts_count); | |
222 | + | |
223 | +/** | |
224 | + * gpt_restore(): Restore GPT partition table | |
225 | + * | |
226 | + * @param dev_desc - block device descriptor | |
227 | + * @param str_disk_guid - disk GUID | |
228 | + * @param partitions - list of partitions | |
229 | + * @param parts - number of partitions | |
230 | + * | |
231 | + * @return zero on success | |
232 | + */ | |
233 | +int gpt_restore(block_dev_desc_t *dev_desc, char *str_disk_guid, | |
234 | + disk_partition_t *partitions, const int parts_count); | |
183 | 235 | #endif |
184 | 236 | |
185 | 237 | #endif /* _PART_H */ |