inline: use the gcc inline version instead of the c99 one.
[profile/mobile/platform/kernel/u-boot-tm1.git] / disk / part_efi.c
1 /*
2  * Copyright (C) 2008 RuggedCom, Inc.
3  * Richard Retanubun <RichardRetanubun@RuggedCom.com>
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  */
23
24 /*
25  * Problems with CONFIG_SYS_64BIT_LBA:
26  *
27  * struct disk_partition.start in include/part.h is sized as ulong.
28  * When CONFIG_SYS_64BIT_LBA is activated, lbaint_t changes from ulong to uint64_t.
29  * For now, it is cast back to ulong at assignment.
30  *
31  * This limits the maximum size of addressable storage to < 2 Terra Bytes
32  */
33  #include <linux/ctype.h>
34 #include <common.h>
35 #include <command.h>
36 #include <ide.h>
37 #include <malloc.h>
38 #include "part_efi.h"
39 #include "part_uefi.h"
40
41 #if defined(CONFIG_CMD_IDE) || \
42     defined(CONFIG_CMD_MG_DISK) || \
43     defined(CONFIG_CMD_SATA) || \
44     defined(CONFIG_CMD_SCSI) || \
45     defined(CONFIG_CMD_USB) || \
46     defined(CONFIG_MMC) || \
47     defined(CONFIG_SYSTEMACE)
48
49 /* Convert char[2] in little endian format to the host format integer
50  */
51 static inline unsigned short le16_to_int(unsigned char *le16)
52 {
53         return ((le16[1] << 8) + le16[0]);
54 }
55
56 /* Convert char[4] in little endian format to the host format integer
57  */
58 static inline unsigned long le32_to_int(unsigned char *le32)
59 {
60         return ((le32[3] << 24) + (le32[2] << 16) + (le32[1] << 8) + le32[0]);
61 }
62
63 /* Convert char[8] in little endian format to the host format integer
64  */
65 static inline unsigned long long le64_to_int(unsigned char *le64)
66 {
67         return (((unsigned long long)le64[7] << 56) +
68                 ((unsigned long long)le64[6] << 48) +
69                 ((unsigned long long)le64[5] << 40) +
70                 ((unsigned long long)le64[4] << 32) +
71                 ((unsigned long long)le64[3] << 24) +
72                 ((unsigned long long)le64[2] << 16) +
73                 ((unsigned long long)le64[1] << 8) +
74                 (unsigned long long)le64[0]);
75 }
76
77 /**
78  * efi_crc32() - EFI version of crc32 function
79  * @buf: buffer to calculate crc32 of
80  * @len - length of buf
81  *
82  * Description: Returns EFI-style CRC32 value for @buf
83  */
84 static inline unsigned long efi_crc32(const void *buf, unsigned long len)
85 {
86         return crc32(0, buf, len);
87 }
88
89 /*
90  * Private function prototypes
91  */
92
93 static int pmbr_part_valid(struct partition *part);
94 static int is_pmbr_valid(legacy_mbr * mbr);
95
96 static int is_gpt_valid(block_dev_desc_t * dev_desc, unsigned long long lba,
97                                 gpt_header * pgpt_head, gpt_entry ** pgpt_pte);
98 #ifdef CONFIG_EMMC_BOOT
99 static int format_gpt_valid(block_dev_desc_t * dev_desc, unsigned long long lba,
100                                 gpt_header * pgpt_head, gpt_entry ** pgpt_pte);
101 #endif
102 static gpt_entry *alloc_read_gpt_entries(block_dev_desc_t * dev_desc,
103                                 gpt_header * pgpt_head);
104
105 static int is_pte_valid(gpt_entry * pte);
106
107 #define PARTNAME_SZ     (72 / sizeof(efi_char16_t))
108 static char *print_efiname(gpt_entry *pte)
109 {
110         static char name[PARTNAME_SZ + 1];
111         int i;
112         for (i = 0; i < PARTNAME_SZ; i++) {
113                 u8 c;
114                 c = pte->partition_name[i] & 0xff;
115                 c = (c && !isprint(c)) ? '.' : c;
116                 name[i] = c;
117         }
118         name[PARTNAME_SZ] = 0;
119         return name;
120 }
121
122
123 /*
124  * Public Functions (include/part.h)
125  */
126
127 void print_part_efi(block_dev_desc_t * dev_desc)
128 {
129         gpt_header gpt_head;
130         gpt_entry *pgpt_pte = NULL;
131         int i = 0;
132
133         if (!dev_desc) {
134                 debug("%s: Invalid Argument(s)\n", __FUNCTION__);
135                 return;
136         }
137         /* This function validates AND fills in the GPT header and PTE */
138         if (is_gpt_valid(dev_desc, GPT_PRIMARY_PARTITION_TABLE_LBA,
139                          &(gpt_head), &pgpt_pte) != 1) {
140                 debug("%s: *** ERROR: Invalid GPT ***\n", __FUNCTION__);
141                 return;
142         }
143
144         debug("%s: gpt-entry at 0x%08X\n", __FUNCTION__, (unsigned int)pgpt_pte);
145
146         debug("Part  Start LBA  End LBA\n");
147         for (i = 0; i < le32_to_int(gpt_head.num_partition_entries); i++) {
148
149                 if (is_pte_valid(&(pgpt_pte)[i])) {
150                         debug("%s%d  0x%llX    0x%llX\n", GPT_ENTRY_NAME,
151                                 (i + 1),
152                                 le64_to_int((pgpt_pte)[i].starting_lba),
153                                 le64_to_int((pgpt_pte)[i].ending_lba));
154                 } else {
155                         break;  /* Stop at the first non valid PTE */
156                 }
157         }
158
159         /* Remember to free pte */
160         if (pgpt_pte != NULL) {
161                 debug("%s: Freeing pgpt_pte\n", __FUNCTION__);
162                 free(pgpt_pte);
163         }
164         return;
165 }
166
167 int get_partition_info_efi(block_dev_desc_t * dev_desc, int part,
168                                 disk_partition_t * info)
169 {
170         gpt_header gpt_head;
171         gpt_entry *pgpt_pte = NULL;
172
173         /* "part" argument must be at least 1 */
174         if (!dev_desc || !info || part < 1) {
175                 debug("%s: Invalid Argument(s)\n", __FUNCTION__);
176                 return -1;
177         }
178
179         /* This function validates AND fills in the GPT header and PTE */
180         if (is_gpt_valid(dev_desc, GPT_PRIMARY_PARTITION_TABLE_LBA,
181                         &(gpt_head), &pgpt_pte) != 1) {
182                 debug("%s: *** ERROR: Invalid Main GPT ***\n", __FUNCTION__);
183                 if(is_gpt_valid(dev_desc, dev_desc->lba -1, &(gpt_head), &pgpt_pte) != 1){
184                         debug("%s: *** ERROR: Invalid alternate GPT ***\n", __FUNCTION__);
185                         return -1;
186
187                 }
188         }
189
190         /* The ulong casting limits the maximum disk size to 2 TB */
191         info->start = (ulong) le64_to_int((pgpt_pte)[part - 1].starting_lba);
192         /* The ending LBA is inclusive, to calculate size, add 1 to it */
193         info->size = ((ulong)le64_to_int((pgpt_pte)[part - 1].ending_lba) + 1)
194                      - info->start;
195         info->blksz = GPT_BLOCK_SIZE;
196
197         sprintf((char *)info->name, "%s", print_efiname(&((pgpt_pte)[part - 1])));
198         sprintf((char *)info->type, "U-Boot");
199
200         debug("%s: start 0x%lX, size 0x%lX, name %s", __FUNCTION__,
201                 info->start, info->size, info->name);
202
203         /* Remember to free pte */
204         if (pgpt_pte != NULL) {
205                 debug("%s: Freeing pgpt_pte\n", __FUNCTION__);
206                 free(pgpt_pte);
207         }
208         return 0;
209 }
210
211 int get_partition_info_by_name_efi(block_dev_desc_t * dev_desc, wchar_t* partition_name,
212                                 disk_partition_t * info)
213 {
214         gpt_header gpt_head;
215         gpt_entry *pgpt_pte = NULL;
216         int ret = -1;
217         unsigned int i,j,partition_nums=0;
218         wchar_t disk_parition[MAX_UTF_PARTITION_NAME_LEN];
219
220         if (!dev_desc || !info || !partition_name) {
221                 debug("%s: Invalid Argument(s)\n", __FUNCTION__);
222                 return -1;
223         }
224
225         /* This function validates AND fills in the GPT header and PTE */
226         if (is_gpt_valid(dev_desc, GPT_PRIMARY_PARTITION_TABLE_LBA,
227                         &(gpt_head), &pgpt_pte) != 1) {
228                 debug("%s: *** ERROR: Invalid Main GPT ***\n", __FUNCTION__);
229                 if(is_gpt_valid(dev_desc, dev_desc->lba -1, &(gpt_head), &pgpt_pte) != 1){
230                         debug("%s: *** ERROR: Invalid alternate GPT ***\n", __FUNCTION__);
231                         return -1;
232
233                 }
234         }
235
236         /*Get the partition info*/
237         partition_nums = le32_to_int(gpt_head.num_partition_entries);
238         for(i=0;i<partition_nums;i++)
239         {
240                 for(j=0;j<MAX_UTF_PARTITION_NAME_LEN;j++)
241                 {
242                         disk_parition[j] = (wchar_t)pgpt_pte[i].partition_name[j];
243                 }
244
245                 if(0 == wcscmp(disk_parition, partition_name))
246                 {
247                         /* The ulong casting limits the maximum disk size to 2 TB */
248                         info->start = (ulong) le64_to_int((pgpt_pte)[i].starting_lba);
249                         /* The ending LBA is inclusive, to calculate size, add 1 to it */
250                         info->size = ((ulong)le64_to_int((pgpt_pte)[i].ending_lba) + 1) - info->start;
251                         info->blksz = GPT_BLOCK_SIZE;
252
253                         sprintf((char *)info->name, "%s", print_efiname(&((pgpt_pte)[i])));
254                         sprintf((char *)info->type, "U-Boot");
255
256                         debug("%s: start 0x%lX, size 0x%lX, name %s", __FUNCTION__,
257                                 info->start, info->size, info->name);
258                         ret = 0;
259                         break;
260                 }
261         }
262
263         /* Remember to free pte */
264         if (pgpt_pte != NULL) {
265                 debug("%s: Freeing pgpt_pte\n", __FUNCTION__);
266                 free(pgpt_pte);
267         }
268
269         return ret;
270 }
271
272 int get_partition_num_by_name_efi(block_dev_desc_t *dev_desc, const char *partition_name)
273 {
274         gpt_header gpt_head;
275         gpt_entry *pgpt_pte = NULL;
276         int ret = -1;
277         unsigned int i, j, partition_nums = 0;
278         int part_name_len = (72 / sizeof(efi_char16_t));
279
280         if (!dev_desc || !partition_name) {
281                 debug("%s: Invalid Argument(s)\n", __FUNCTION__);
282                 return -1;
283         }
284
285         /* This function validates AND fills in the GPT header and PTE */
286         if (is_gpt_valid(dev_desc, GPT_PRIMARY_PARTITION_TABLE_LBA,
287                         &(gpt_head), &pgpt_pte) != 1) {
288                 debug("%s: *** ERROR: Invalid Main GPT ***\n", __FUNCTION__);
289                 if (is_gpt_valid(dev_desc, dev_desc->lba -1, &(gpt_head), &pgpt_pte) != 1){
290                         debug("%s: *** ERROR: Invalid alternate GPT ***\n", __FUNCTION__);
291                         return -1;
292
293                 }
294         }
295
296         partition_nums = le32_to_int(gpt_head.num_partition_entries);
297         for (i = 0; i < partition_nums; i++) {
298                 for (j = 0; j < part_name_len; j++) {
299                         if (partition_name[j] != pgpt_pte[i].partition_name[j])
300                                 break;
301                         if (partition_name[j] == 0 && pgpt_pte[i].partition_name[j] == 0) {
302                                 ret = i + 1;
303                                 goto free;
304                         }
305                 }
306         }
307
308 free:
309         /* Remember to free pte */
310         if (pgpt_pte != NULL) {
311                 debug("%s: Freeing pgpt_pte\n", __FUNCTION__);
312                 free(pgpt_pte);
313         }
314
315         return ret;
316 }
317
318 int get_all_partition_info_efi(block_dev_desc_t * dev_desc, PARTITION_CFG * info, unsigned int *total_partition_num)
319 {
320         gpt_header gpt_head;
321         gpt_entry *pgpt_pte = NULL;
322         unsigned int i,j, partition_nums = 0;
323
324         if (!dev_desc || !info) {
325                 debug("%s: Invalid Argument(s)\n", __FUNCTION__);
326                 return -1;
327         }
328
329         /* This function validates AND fills in the GPT header and PTE */
330         if (is_gpt_valid(dev_desc, GPT_PRIMARY_PARTITION_TABLE_LBA,
331                         &(gpt_head), &pgpt_pte) != 1) {
332                 debug("%s: *** ERROR: Invalid Main GPT ***\n", __FUNCTION__);
333                 if(is_gpt_valid(dev_desc, dev_desc->lba -1, &(gpt_head), &pgpt_pte) != 1){
334                         debug("%s: *** ERROR: Invalid alternate GPT ***\n", __FUNCTION__);
335                         return -1;
336
337                 }
338         }
339
340         partition_nums = le32_to_int(gpt_head.num_partition_entries);
341
342         //TODO:partitions shuld beyond MAX PARTITION NUM
343         for(i=0;i<partition_nums;i++)
344         {
345                 /* The ulong casting limits the maximum disk size to 2 TB */
346                 info[i].partition_offset = (ulong) le64_to_int((pgpt_pte)[i].starting_lba);
347                 /* The ending LBA is inclusive, to calculate size, add 1 to it */
348                 info[i].partition_size = ((ulong)le64_to_int((pgpt_pte)[i].ending_lba) + 1) - info[i].partition_offset;
349                 //TODO: We write partition index at unique_partition_guid.b[15]
350                 info[i].partition_index = pgpt_pte[i].unique_partition_guid.b[15];
351
352                 for(j=0;j<MAX_UTF_PARTITION_NAME_LEN;j++)
353                 {
354                         info[i].partition_name[j] = (wchar_t)pgpt_pte[i].partition_name[j];
355                 }
356
357                 debug("%s: start 0x%lX, size 0x%lX, name %S", __FUNCTION__,
358                         info[i].partition_offset, info[i].partition_size, info[i].partition_name);
359         }
360
361         *total_partition_num = partition_nums;
362
363         /* Remember to free pte */
364         if (pgpt_pte != NULL) {
365                 debug("%s: Freeing pgpt_pte\n", __FUNCTION__);
366                 free(pgpt_pte);
367         }
368         return 0;
369 }
370
371
372 int get_partition_info_efi_with_partnum(block_dev_desc_t * dev_desc, int part,
373                 disk_partition_t * info, unsigned long total, unsigned long sdidx, int sdpart, disk_partition_t *sdinfo)
374 {
375         gpt_header gpt_head;
376         gpt_entry *pgpt_pte = NULL;
377
378         /* "part" argument must be at least 1 */
379         if (!dev_desc || !info || part < 1) {
380                 debug("%s: Invalid Argument(s)\n", __FUNCTION__);
381                 return -1;
382         }
383
384         /* This function validates AND fills in the GPT header and PTE */
385         if (is_gpt_valid(dev_desc, GPT_PRIMARY_PARTITION_TABLE_LBA,
386                         &(gpt_head), &pgpt_pte) != 1) {
387                 debug("%s: *** ERROR: Invalid Main GPT ***\n", __FUNCTION__);
388                 if(is_gpt_valid(dev_desc, dev_desc->lba -1, &(gpt_head), &pgpt_pte) != 1){
389                         debug("%s: *** ERROR: Invalid alternate GPT ***\n", __FUNCTION__);
390                         return -1;
391
392                 }
393         }
394
395         /* The ulong casting limits the maximum disk size to 2 TB */
396         info->start = (ulong) le64_to_int((pgpt_pte)[part - 1].starting_lba);
397         /* The ending LBA is inclusive, to calculate size, add 1 to it */
398         info->size = ((ulong)le64_to_int((pgpt_pte)[part - 1].ending_lba) + 1)
399                      - info->start;
400         info->blksz = GPT_BLOCK_SIZE;
401
402         sprintf((char *)info->name, "%s",
403                         print_efiname(&((pgpt_pte)[part - 1])));
404         sprintf((char *)info->type, "U-Boot");
405
406         debug("%s: start 0x%lX, size 0x%lX, name %s\n", __FUNCTION__,
407                 info->start, info->size, info->name);
408
409         /* copy sd info */
410         if (sdidx < (le32_to_int(gpt_head.num_partition_entries))) {
411                 sdinfo->start = (ulong) le64_to_int((pgpt_pte)[sdpart - 1].starting_lba);
412                 sdinfo->size = ((ulong)le64_to_int((pgpt_pte)[sdpart - 1].ending_lba) + 1) - sdinfo->start;
413         }
414
415         /* Remember to free pte */
416         if (pgpt_pte != NULL) {
417                 debug("%s: Freeing pgpt_pte\n", __FUNCTION__);
418                 free(pgpt_pte);
419         }
420
421         if (total == 0)
422                 return 0;
423         else if (total != le32_to_int(gpt_head.num_partition_entries))
424                 return -1;
425         else
426                 return 0;
427 }
428
429 int test_part_efi(block_dev_desc_t * dev_desc)
430 {
431         legacy_mbr legacymbr;
432
433         /* Read legacy MBR from block 0 and validate it */
434         if ((dev_desc->block_read(dev_desc->dev, 0, 1, (ulong *) & legacymbr) != 1)
435                 || (is_pmbr_valid(&legacymbr) != 1)) {
436                 return -1;
437         }
438         return 0;
439 }
440
441 /*
442  * Private functions
443  */
444 /*
445  * pmbr_part_valid(): Check for EFI partition signature
446  *
447  * Returns: 1 if EFI GPT partition type is found.
448  */
449 static int pmbr_part_valid(struct partition *part)
450 {
451         if (part->sys_ind == EFI_PMBR_OSTYPE_EFI_GPT &&
452                 le32_to_int(part->start_sect) == 1UL) {
453                 return 1;
454         }
455
456         return 0;
457 }
458
459 /*
460  * is_pmbr_valid(): test Protective MBR for validity
461  *
462  * Returns: 1 if PMBR is valid, 0 otherwise.
463  * Validity depends on two things:
464  *  1) MSDOS signature is in the last two bytes of the MBR
465  *  2) One partition of type 0xEE is found, checked by pmbr_part_valid()
466  */
467 static int is_pmbr_valid(legacy_mbr * mbr)
468 {
469         int i = 0;
470
471         if (!mbr || le16_to_int(mbr->signature) != MSDOS_MBR_SIGNATURE) {
472                 return 0;
473         }
474
475         for (i = 0; i < 4; i++) {
476                 if (pmbr_part_valid(&mbr->partition_record[i])) {
477                         return 1;
478                 }
479         }
480         return 0;
481 }
482
483 /**
484  * is_gpt_valid() - tests one GPT header and PTEs for validity
485  *
486  * lba is the logical block address of the GPT header to test
487  * gpt is a GPT header ptr, filled on return.
488  * ptes is a PTEs ptr, filled on return.
489  *
490  * Description: returns 1 if valid,  0 on error.
491  * If valid, returns pointers to PTEs.
492  */
493 static int is_gpt_valid(block_dev_desc_t * dev_desc, unsigned long long lba,
494                         gpt_header * pgpt_head, gpt_entry ** pgpt_pte)
495 {
496         unsigned char crc32_backup[4] = { 0 };
497         unsigned long calc_crc32;
498         unsigned long long lastlba;
499         //debug("Enter is_gpt_valid 0x%16Lx \n", lba);
500         if (!dev_desc || !pgpt_head) {
501                 debug("%s: Invalid Argument(s)\n", __FUNCTION__);
502                 return 0;
503         }
504
505         /* Read GPT Header from device */
506         if (dev_desc->block_read(dev_desc->dev, lba, 1, pgpt_head) != 1) {
507                 debug("*** ERROR: Can't read GPT header ***\n");
508                 return 0;
509         }
510
511         /* Check the GPT header signature */
512         if (le64_to_int(pgpt_head->signature) != GPT_HEADER_SIGNATURE) {
513                 debug("GUID Partition Table Header signature is wrong:"
514                         "0x%llX != 0x%llX\n",
515                         (unsigned long long)le64_to_int(pgpt_head->signature),
516                         (unsigned long long)GPT_HEADER_SIGNATURE);
517                 return 0;
518         }
519
520         /* Check the GUID Partition Table CRC */
521         memcpy(crc32_backup, pgpt_head->header_crc32, sizeof(crc32_backup));
522         memset(pgpt_head->header_crc32, 0, sizeof(pgpt_head->header_crc32));
523
524         calc_crc32 = efi_crc32((const unsigned char *)pgpt_head,
525                 le32_to_int(pgpt_head->header_size));
526
527         memcpy(pgpt_head->header_crc32, crc32_backup, sizeof(crc32_backup));
528
529         if (calc_crc32 != le32_to_int(crc32_backup)) {
530                 debug("GUID Partition Table Header CRC is wrong:"
531                         "0x%08lX != 0x%08lX\n",
532                         le32_to_int(crc32_backup), calc_crc32);
533                 return 0;
534         }
535
536         /* Check that the my_lba entry points to the LBA that contains the GPT */
537         if (le64_to_int(pgpt_head->my_lba) != lba) {
538                 debug("GPT: my_lba incorrect: %llX != %llX\n",
539                         (unsigned long long)le64_to_int(pgpt_head->my_lba),
540                         (unsigned long long)lba);
541                 return 0;
542         }
543
544         /* Check the first_usable_lba and last_usable_lba are within the disk. */
545         lastlba = (unsigned long long)dev_desc->lba;
546         if (le64_to_int(pgpt_head->first_usable_lba) > lastlba) {
547                 debug("GPT: first_usable_lba incorrect: %llX > %llX\n",
548                         le64_to_int(pgpt_head->first_usable_lba), lastlba);
549                 return 0;
550         }
551         if (le64_to_int(pgpt_head->last_usable_lba) > lastlba) {
552                 debug("GPT: last_usable_lba incorrect: %llX > %llX\n",
553                         le64_to_int(pgpt_head->last_usable_lba), lastlba);
554                 return 0;
555         }
556
557         debug("GPT: first_usable_lba: %llX last_usable_lba %llX last lba %llX\n",
558                 le64_to_int(pgpt_head->first_usable_lba),
559                 le64_to_int(pgpt_head->last_usable_lba), lastlba);
560
561         /* Read and allocate Partition Table Entries */
562         *pgpt_pte = alloc_read_gpt_entries(dev_desc, pgpt_head);
563         if (*pgpt_pte == NULL) {
564                 debug("GPT: Failed to allocate memory for PTE\n");
565                 return 0;
566         }
567
568         /* Check the GUID Partition Table Entry Array CRC */
569         calc_crc32 = efi_crc32((const unsigned char *)*pgpt_pte,
570                 le32_to_int(pgpt_head->num_partition_entries) *
571                 le32_to_int(pgpt_head->sizeof_partition_entry));
572
573         if (calc_crc32 != le32_to_int(pgpt_head->partition_entry_array_crc32)) {
574                 debug("GUID Partition Table Entry Array CRC is wrong:"
575                         "0x%08lX != 0x%08lX\n",
576                         le32_to_int(pgpt_head->partition_entry_array_crc32),
577                         calc_crc32);
578
579                 if (*pgpt_pte != NULL) {
580                         free(*pgpt_pte);
581                 }
582                 return 0;
583         }
584
585         /* We're done, all's well */
586         return 1;
587 }
588
589 #ifdef CONFIG_EMMC_BOOT
590 /**
591  * format_gpt_valid() - tests one GPT header and PTEs for validity
592  *
593  * lba is the logical block address of the GPT header to test
594  * gpt is a GPT header ptr, filled on return.
595  * ptes is a PTEs ptr, filled on return.
596  *
597  * Description: returns 1 if valid,  0 on error.
598  * If valid, returns pointers to PTEs.
599  */
600 static int format_gpt_valid(block_dev_desc_t * dev_desc, unsigned long long lba,
601                         gpt_header * pgpt_head, gpt_entry ** pgpt_pte)
602 {
603         unsigned char crc32_backup[4] = { 0 };
604         unsigned long calc_crc32;
605         unsigned long long lastlba;
606         int idx;
607
608         if (!dev_desc || !pgpt_head) {
609                 debug("%s: Invalid Argument(s)\n", __FUNCTION__);
610                 return 0;
611         }
612         
613         memset(pgpt_head, 0, sizeof(gpt_header));
614
615         /* set GPT Header from device */
616         for (idx = 0; idx < 8; idx ++) {
617                 pgpt_head->signature[idx] = (GPT_HEADER_SIGNATURE >> (8 * idx)) & 0xff;
618                 debug("signature[%d] = 0x%02x\n", idx, pgpt_head->signature[idx]);
619         }
620
621         if (dev_desc->block_write(dev_desc->dev, lba, 1, pgpt_head) != 1) {
622                 debug("*** ERROR: Can't write GPT header ***\n");
623                 return 0;
624         }
625 #if 1
626         //richardfeng mask
627         /* Check the GPT header signature */
628         if (le64_to_int(pgpt_head->signature) != GPT_HEADER_SIGNATURE) {
629                 debug("GUID Partition Table Header signature is wrong:"
630                         "0x%llX != 0x%llX\n",
631                         (unsigned long long)le64_to_int(pgpt_head->signature),
632                         (unsigned long long)GPT_HEADER_SIGNATURE);
633                 return 0;
634         }
635
636         /* Check the GUID Partition Table CRC */
637         memcpy(crc32_backup, pgpt_head->header_crc32, sizeof(crc32_backup));
638         memset(pgpt_head->header_crc32, 0, sizeof(pgpt_head->header_crc32));
639
640         calc_crc32 = efi_crc32((const unsigned char *)pgpt_head,
641                 le32_to_int(pgpt_head->header_size));
642
643         memcpy(pgpt_head->header_crc32, crc32_backup, sizeof(crc32_backup));
644
645         if (calc_crc32 != le32_to_int(crc32_backup)) {
646                 debug("GUID Partition Table Header CRC is wrong:"
647                         "0x%08lX != 0x%08lX\n",
648                         le32_to_int(crc32_backup), calc_crc32);
649                 return 0;
650         }
651
652         /* Check that the my_lba entry points to the LBA that contains the GPT */
653         if (le64_to_int(pgpt_head->my_lba) != lba) {
654                 debug("GPT: my_lba incorrect: %llX != %llX\n",
655                         (unsigned long long)le64_to_int(pgpt_head->my_lba),
656                         (unsigned long long)lba);
657                 return 0;
658         }
659
660         /* Check the first_usable_lba and last_usable_lba are within the disk. */
661         lastlba = (unsigned long long)dev_desc->lba;
662         if (le64_to_int(pgpt_head->first_usable_lba) > lastlba) {
663                 debug("GPT: first_usable_lba incorrect: %llX > %llX\n",
664                         le64_to_int(pgpt_head->first_usable_lba), lastlba);
665                 return 0;
666         }
667         if (le64_to_int(pgpt_head->last_usable_lba) > lastlba) {
668                 debug("GPT: last_usable_lba incorrect: %llX > %llX\n",
669                         le64_to_int(pgpt_head->last_usable_lba), lastlba);
670                 return 0;
671         }
672
673         debug("GPT: first_usable_lba: %llX last_usable_lba %llX last lba %llX\n",
674                 le64_to_int(pgpt_head->first_usable_lba),
675                 le64_to_int(pgpt_head->last_usable_lba), lastlba);
676
677         /* Read and allocate Partition Table Entries */
678         *pgpt_pte = alloc_read_gpt_entries(dev_desc, pgpt_head);
679         if (*pgpt_pte == NULL) {
680                 debug("GPT: Failed to allocate memory for PTE\n");
681                 return 0;
682         }
683
684         /* Check the GUID Partition Table Entry Array CRC */
685         calc_crc32 = efi_crc32((const unsigned char *)*pgpt_pte,
686                 le32_to_int(pgpt_head->num_partition_entries) *
687                 le32_to_int(pgpt_head->sizeof_partition_entry));
688
689         if (calc_crc32 != le32_to_int(pgpt_head->partition_entry_array_crc32)) {
690                 debug("GUID Partition Table Entry Array CRC is wrong:"
691                         "0x%08lX != 0x%08lX\n",
692                         le32_to_int(pgpt_head->partition_entry_array_crc32),
693                         calc_crc32);
694
695                 if (*pgpt_pte != NULL) {
696                         free(*pgpt_pte);
697                 }
698                 return 0;
699         }
700 #endif
701         /* We're done, all's well */
702         return 1;
703 }
704 #endif
705
706 /**
707  * alloc_read_gpt_entries(): reads partition entries from disk
708  * @dev_desc
709  * @gpt - GPT header
710  *
711  * Description: Returns ptes on success,  NULL on error.
712  * Allocates space for PTEs based on information found in @gpt.
713  * Notes: remember to free pte when you're done!
714  */
715 static gpt_entry *alloc_read_gpt_entries(block_dev_desc_t * dev_desc,
716                                          gpt_header * pgpt_head)
717 {
718         size_t count = 0;
719         gpt_entry *pte = NULL;
720
721         if (!dev_desc || !pgpt_head) {
722                 debug("%s: Invalid Argument(s)\n", __FUNCTION__);
723                 return NULL;
724         }
725
726         count = le32_to_int(pgpt_head->num_partition_entries) *
727                 le32_to_int(pgpt_head->sizeof_partition_entry);
728
729         debug("%s: count = %lu * %lu = %u\n", __FUNCTION__,
730                 le32_to_int(pgpt_head->num_partition_entries),
731                 le32_to_int(pgpt_head->sizeof_partition_entry), count);
732         if(count % GPT_BLOCK_SIZE){
733                 size_t ntemp;
734                 ntemp = count/GPT_BLOCK_SIZE +1;
735                 count = ntemp * GPT_BLOCK_SIZE;
736         }
737         /* Allocate memory for PTE, remember to FREE */
738         if (count != 0) {
739                 pte = malloc(count);
740         }
741
742         if (count == 0 || pte == NULL) {
743                 debug("%s: ERROR: Can't allocate 0x%X bytes for GPT Entries\n",
744                         __FUNCTION__, count);
745                 return NULL;
746         }
747
748         /* Read GPT Entries from device */
749         if (dev_desc->block_read (dev_desc->dev,
750                 (unsigned long)le64_to_int(pgpt_head->partition_entry_lba),
751                 (lbaint_t) (count / GPT_BLOCK_SIZE), pte)
752                 != (count / GPT_BLOCK_SIZE)) {
753
754                 debug("*** ERROR: Can't read GPT Entries ***\n");
755                 free(pte);
756                 return NULL;
757         }
758         return pte;
759 }
760
761 /**
762  * is_pte_valid(): validates a single Partition Table Entry
763  * @gpt_entry - Pointer to a single Partition Table Entry
764  *
765  * Description: returns 1 if valid,  0 on error.
766  */
767 static int is_pte_valid(gpt_entry * pte)
768 {
769         efi_guid_t unused_guid;
770
771         if (!pte) {
772                 debug("%s: Invalid Argument(s)\n", __FUNCTION__);
773                 return 0;
774         }
775
776         /* Only one validation for now:
777          * The GUID Partition Type != Unused Entry (ALL-ZERO)
778          */
779         memset(unused_guid.b, 0, sizeof(unused_guid.b));
780
781         if (memcmp(pte->partition_type_guid.b, unused_guid.b,
782                 sizeof(unused_guid.b)) == 0) {
783
784                 debug("%s: Found an unused PTE GUID at 0x%08X\n", __FUNCTION__,
785                 (unsigned int)pte);
786
787                 return 0;
788         } else {
789                 return 1;
790         }
791 }
792 #endif