18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/************************************************************ 38c2ecf20Sopenharmony_ci * EFI GUID Partition Table handling 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * http://www.uefi.org/specs/ 68c2ecf20Sopenharmony_ci * http://www.intel.com/technology/efi/ 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * efi.[ch] by Matt Domsch <Matt_Domsch@dell.com> 98c2ecf20Sopenharmony_ci * Copyright 2000,2001,2002,2004 Dell Inc. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * TODO: 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * Changelog: 148c2ecf20Sopenharmony_ci * Mon August 5th, 2013 Davidlohr Bueso <davidlohr@hp.com> 158c2ecf20Sopenharmony_ci * - detect hybrid MBRs, tighter pMBR checking & cleanups. 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * Mon Nov 09 2004 Matt Domsch <Matt_Domsch@dell.com> 188c2ecf20Sopenharmony_ci * - test for valid PMBR and valid PGPT before ever reading 198c2ecf20Sopenharmony_ci * AGPT, allow override with 'gpt' kernel command line option. 208c2ecf20Sopenharmony_ci * - check for first/last_usable_lba outside of size of disk 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * Tue Mar 26 2002 Matt Domsch <Matt_Domsch@dell.com> 238c2ecf20Sopenharmony_ci * - Ported to 2.5.7-pre1 and 2.5.7-dj2 248c2ecf20Sopenharmony_ci * - Applied patch to avoid fault in alternate header handling 258c2ecf20Sopenharmony_ci * - cleaned up find_valid_gpt 268c2ecf20Sopenharmony_ci * - On-disk structure and copy in memory is *always* LE now - 278c2ecf20Sopenharmony_ci * swab fields as needed 288c2ecf20Sopenharmony_ci * - remove print_gpt_header() 298c2ecf20Sopenharmony_ci * - only use first max_p partition entries, to keep the kernel minor number 308c2ecf20Sopenharmony_ci * and partition numbers tied. 318c2ecf20Sopenharmony_ci * 328c2ecf20Sopenharmony_ci * Mon Feb 04 2002 Matt Domsch <Matt_Domsch@dell.com> 338c2ecf20Sopenharmony_ci * - Removed __PRIPTR_PREFIX - not being used 348c2ecf20Sopenharmony_ci * 358c2ecf20Sopenharmony_ci * Mon Jan 14 2002 Matt Domsch <Matt_Domsch@dell.com> 368c2ecf20Sopenharmony_ci * - Ported to 2.5.2-pre11 + library crc32 patch Linus applied 378c2ecf20Sopenharmony_ci * 388c2ecf20Sopenharmony_ci * Thu Dec 6 2001 Matt Domsch <Matt_Domsch@dell.com> 398c2ecf20Sopenharmony_ci * - Added compare_gpts(). 408c2ecf20Sopenharmony_ci * - moved le_efi_guid_to_cpus() back into this file. GPT is the only 418c2ecf20Sopenharmony_ci * thing that keeps EFI GUIDs on disk. 428c2ecf20Sopenharmony_ci * - Changed gpt structure names and members to be simpler and more Linux-like. 438c2ecf20Sopenharmony_ci * 448c2ecf20Sopenharmony_ci * Wed Oct 17 2001 Matt Domsch <Matt_Domsch@dell.com> 458c2ecf20Sopenharmony_ci * - Removed CONFIG_DEVFS_VOLUMES_UUID code entirely per Martin Wilck 468c2ecf20Sopenharmony_ci * 478c2ecf20Sopenharmony_ci * Wed Oct 10 2001 Matt Domsch <Matt_Domsch@dell.com> 488c2ecf20Sopenharmony_ci * - Changed function comments to DocBook style per Andreas Dilger suggestion. 498c2ecf20Sopenharmony_ci * 508c2ecf20Sopenharmony_ci * Mon Oct 08 2001 Matt Domsch <Matt_Domsch@dell.com> 518c2ecf20Sopenharmony_ci * - Change read_lba() to use the page cache per Al Viro's work. 528c2ecf20Sopenharmony_ci * - print u64s properly on all architectures 538c2ecf20Sopenharmony_ci * - fixed debug_printk(), now Dprintk() 548c2ecf20Sopenharmony_ci * 558c2ecf20Sopenharmony_ci * Mon Oct 01 2001 Matt Domsch <Matt_Domsch@dell.com> 568c2ecf20Sopenharmony_ci * - Style cleanups 578c2ecf20Sopenharmony_ci * - made most functions static 588c2ecf20Sopenharmony_ci * - Endianness addition 598c2ecf20Sopenharmony_ci * - remove test for second alternate header, as it's not per spec, 608c2ecf20Sopenharmony_ci * and is unnecessary. There's now a method to read/write the last 618c2ecf20Sopenharmony_ci * sector of an odd-sized disk from user space. No tools have ever 628c2ecf20Sopenharmony_ci * been released which used this code, so it's effectively dead. 638c2ecf20Sopenharmony_ci * - Per Asit Mallick of Intel, added a test for a valid PMBR. 648c2ecf20Sopenharmony_ci * - Added kernel command line option 'gpt' to override valid PMBR test. 658c2ecf20Sopenharmony_ci * 668c2ecf20Sopenharmony_ci * Wed Jun 6 2001 Martin Wilck <Martin.Wilck@Fujitsu-Siemens.com> 678c2ecf20Sopenharmony_ci * - added devfs volume UUID support (/dev/volumes/uuids) for 688c2ecf20Sopenharmony_ci * mounting file systems by the partition GUID. 698c2ecf20Sopenharmony_ci * 708c2ecf20Sopenharmony_ci * Tue Dec 5 2000 Matt Domsch <Matt_Domsch@dell.com> 718c2ecf20Sopenharmony_ci * - Moved crc32() to linux/lib, added efi_crc32(). 728c2ecf20Sopenharmony_ci * 738c2ecf20Sopenharmony_ci * Thu Nov 30 2000 Matt Domsch <Matt_Domsch@dell.com> 748c2ecf20Sopenharmony_ci * - Replaced Intel's CRC32 function with an equivalent 758c2ecf20Sopenharmony_ci * non-license-restricted version. 768c2ecf20Sopenharmony_ci * 778c2ecf20Sopenharmony_ci * Wed Oct 25 2000 Matt Domsch <Matt_Domsch@dell.com> 788c2ecf20Sopenharmony_ci * - Fixed the last_lba() call to return the proper last block 798c2ecf20Sopenharmony_ci * 808c2ecf20Sopenharmony_ci * Thu Oct 12 2000 Matt Domsch <Matt_Domsch@dell.com> 818c2ecf20Sopenharmony_ci * - Thanks to Andries Brouwer for his debugging assistance. 828c2ecf20Sopenharmony_ci * - Code works, detects all the partitions. 838c2ecf20Sopenharmony_ci * 848c2ecf20Sopenharmony_ci ************************************************************/ 858c2ecf20Sopenharmony_ci#include <linux/kernel.h> 868c2ecf20Sopenharmony_ci#include <linux/crc32.h> 878c2ecf20Sopenharmony_ci#include <linux/ctype.h> 888c2ecf20Sopenharmony_ci#include <linux/math64.h> 898c2ecf20Sopenharmony_ci#include <linux/slab.h> 908c2ecf20Sopenharmony_ci#include "check.h" 918c2ecf20Sopenharmony_ci#include "efi.h" 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci/* This allows a kernel command line option 'gpt' to override 948c2ecf20Sopenharmony_ci * the test for invalid PMBR. Not __initdata because reloading 958c2ecf20Sopenharmony_ci * the partition tables happens after init too. 968c2ecf20Sopenharmony_ci */ 978c2ecf20Sopenharmony_cistatic int force_gpt; 988c2ecf20Sopenharmony_cistatic int __init 998c2ecf20Sopenharmony_ciforce_gpt_fn(char *str) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci force_gpt = 1; 1028c2ecf20Sopenharmony_ci return 1; 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci__setup("gpt", force_gpt_fn); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci/** 1088c2ecf20Sopenharmony_ci * efi_crc32() - EFI version of crc32 function 1098c2ecf20Sopenharmony_ci * @buf: buffer to calculate crc32 of 1108c2ecf20Sopenharmony_ci * @len: length of buf 1118c2ecf20Sopenharmony_ci * 1128c2ecf20Sopenharmony_ci * Description: Returns EFI-style CRC32 value for @buf 1138c2ecf20Sopenharmony_ci * 1148c2ecf20Sopenharmony_ci * This function uses the little endian Ethernet polynomial 1158c2ecf20Sopenharmony_ci * but seeds the function with ~0, and xor's with ~0 at the end. 1168c2ecf20Sopenharmony_ci * Note, the EFI Specification, v1.02, has a reference to 1178c2ecf20Sopenharmony_ci * Dr. Dobbs Journal, May 1994 (actually it's in May 1992). 1188c2ecf20Sopenharmony_ci */ 1198c2ecf20Sopenharmony_cistatic inline u32 1208c2ecf20Sopenharmony_ciefi_crc32(const void *buf, unsigned long len) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci return (crc32(~0L, buf, len) ^ ~0L); 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci/** 1268c2ecf20Sopenharmony_ci * last_lba(): return number of last logical block of device 1278c2ecf20Sopenharmony_ci * @bdev: block device 1288c2ecf20Sopenharmony_ci * 1298c2ecf20Sopenharmony_ci * Description: Returns last LBA value on success, 0 on error. 1308c2ecf20Sopenharmony_ci * This is stored (by sd and ide-geometry) in 1318c2ecf20Sopenharmony_ci * the part[0] entry for this disk, and is the number of 1328c2ecf20Sopenharmony_ci * physical sectors available on the disk. 1338c2ecf20Sopenharmony_ci */ 1348c2ecf20Sopenharmony_cistatic u64 last_lba(struct block_device *bdev) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci if (!bdev || !bdev->bd_inode) 1378c2ecf20Sopenharmony_ci return 0; 1388c2ecf20Sopenharmony_ci return div_u64(bdev->bd_inode->i_size, 1398c2ecf20Sopenharmony_ci bdev_logical_block_size(bdev)) - 1ULL; 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic inline int pmbr_part_valid(gpt_mbr_record *part) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci if (part->os_type != EFI_PMBR_OSTYPE_EFI_GPT) 1458c2ecf20Sopenharmony_ci goto invalid; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci /* set to 0x00000001 (i.e., the LBA of the GPT Partition Header) */ 1488c2ecf20Sopenharmony_ci if (le32_to_cpu(part->starting_lba) != GPT_PRIMARY_PARTITION_TABLE_LBA) 1498c2ecf20Sopenharmony_ci goto invalid; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci return GPT_MBR_PROTECTIVE; 1528c2ecf20Sopenharmony_ciinvalid: 1538c2ecf20Sopenharmony_ci return 0; 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci/** 1578c2ecf20Sopenharmony_ci * is_pmbr_valid(): test Protective MBR for validity 1588c2ecf20Sopenharmony_ci * @mbr: pointer to a legacy mbr structure 1598c2ecf20Sopenharmony_ci * @total_sectors: amount of sectors in the device 1608c2ecf20Sopenharmony_ci * 1618c2ecf20Sopenharmony_ci * Description: Checks for a valid protective or hybrid 1628c2ecf20Sopenharmony_ci * master boot record (MBR). The validity of a pMBR depends 1638c2ecf20Sopenharmony_ci * on all of the following properties: 1648c2ecf20Sopenharmony_ci * 1) MSDOS signature is in the last two bytes of the MBR 1658c2ecf20Sopenharmony_ci * 2) One partition of type 0xEE is found 1668c2ecf20Sopenharmony_ci * 1678c2ecf20Sopenharmony_ci * In addition, a hybrid MBR will have up to three additional 1688c2ecf20Sopenharmony_ci * primary partitions, which point to the same space that's 1698c2ecf20Sopenharmony_ci * marked out by up to three GPT partitions. 1708c2ecf20Sopenharmony_ci * 1718c2ecf20Sopenharmony_ci * Returns 0 upon invalid MBR, or GPT_MBR_PROTECTIVE or 1728c2ecf20Sopenharmony_ci * GPT_MBR_HYBRID depending on the device layout. 1738c2ecf20Sopenharmony_ci */ 1748c2ecf20Sopenharmony_cistatic int is_pmbr_valid(legacy_mbr *mbr, sector_t total_sectors) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci uint32_t sz = 0; 1778c2ecf20Sopenharmony_ci int i, part = 0, ret = 0; /* invalid by default */ 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci if (!mbr || le16_to_cpu(mbr->signature) != MSDOS_MBR_SIGNATURE) 1808c2ecf20Sopenharmony_ci goto done; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 1838c2ecf20Sopenharmony_ci ret = pmbr_part_valid(&mbr->partition_record[i]); 1848c2ecf20Sopenharmony_ci if (ret == GPT_MBR_PROTECTIVE) { 1858c2ecf20Sopenharmony_ci part = i; 1868c2ecf20Sopenharmony_ci /* 1878c2ecf20Sopenharmony_ci * Ok, we at least know that there's a protective MBR, 1888c2ecf20Sopenharmony_ci * now check if there are other partition types for 1898c2ecf20Sopenharmony_ci * hybrid MBR. 1908c2ecf20Sopenharmony_ci */ 1918c2ecf20Sopenharmony_ci goto check_hybrid; 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci if (ret != GPT_MBR_PROTECTIVE) 1968c2ecf20Sopenharmony_ci goto done; 1978c2ecf20Sopenharmony_cicheck_hybrid: 1988c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) 1998c2ecf20Sopenharmony_ci if ((mbr->partition_record[i].os_type != 2008c2ecf20Sopenharmony_ci EFI_PMBR_OSTYPE_EFI_GPT) && 2018c2ecf20Sopenharmony_ci (mbr->partition_record[i].os_type != 0x00)) 2028c2ecf20Sopenharmony_ci ret = GPT_MBR_HYBRID; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci /* 2058c2ecf20Sopenharmony_ci * Protective MBRs take up the lesser of the whole disk 2068c2ecf20Sopenharmony_ci * or 2 TiB (32bit LBA), ignoring the rest of the disk. 2078c2ecf20Sopenharmony_ci * Some partitioning programs, nonetheless, choose to set 2088c2ecf20Sopenharmony_ci * the size to the maximum 32-bit limitation, disregarding 2098c2ecf20Sopenharmony_ci * the disk size. 2108c2ecf20Sopenharmony_ci * 2118c2ecf20Sopenharmony_ci * Hybrid MBRs do not necessarily comply with this. 2128c2ecf20Sopenharmony_ci * 2138c2ecf20Sopenharmony_ci * Consider a bad value here to be a warning to support dd'ing 2148c2ecf20Sopenharmony_ci * an image from a smaller disk to a larger disk. 2158c2ecf20Sopenharmony_ci */ 2168c2ecf20Sopenharmony_ci if (ret == GPT_MBR_PROTECTIVE) { 2178c2ecf20Sopenharmony_ci sz = le32_to_cpu(mbr->partition_record[part].size_in_lba); 2188c2ecf20Sopenharmony_ci if (sz != (uint32_t) total_sectors - 1 && sz != 0xFFFFFFFF) 2198c2ecf20Sopenharmony_ci pr_debug("GPT: mbr size in lba (%u) different than whole disk (%u).\n", 2208c2ecf20Sopenharmony_ci sz, min_t(uint32_t, 2218c2ecf20Sopenharmony_ci total_sectors - 1, 0xFFFFFFFF)); 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_cidone: 2248c2ecf20Sopenharmony_ci return ret; 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci/** 2288c2ecf20Sopenharmony_ci * read_lba(): Read bytes from disk, starting at given LBA 2298c2ecf20Sopenharmony_ci * @state: disk parsed partitions 2308c2ecf20Sopenharmony_ci * @lba: the Logical Block Address of the partition table 2318c2ecf20Sopenharmony_ci * @buffer: destination buffer 2328c2ecf20Sopenharmony_ci * @count: bytes to read 2338c2ecf20Sopenharmony_ci * 2348c2ecf20Sopenharmony_ci * Description: Reads @count bytes from @state->bdev into @buffer. 2358c2ecf20Sopenharmony_ci * Returns number of bytes read on success, 0 on error. 2368c2ecf20Sopenharmony_ci */ 2378c2ecf20Sopenharmony_cistatic size_t read_lba(struct parsed_partitions *state, 2388c2ecf20Sopenharmony_ci u64 lba, u8 *buffer, size_t count) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci size_t totalreadcount = 0; 2418c2ecf20Sopenharmony_ci struct block_device *bdev = state->bdev; 2428c2ecf20Sopenharmony_ci sector_t n = lba * (bdev_logical_block_size(bdev) / 512); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci if (!buffer || lba > last_lba(bdev)) 2458c2ecf20Sopenharmony_ci return 0; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci while (count) { 2488c2ecf20Sopenharmony_ci int copied = 512; 2498c2ecf20Sopenharmony_ci Sector sect; 2508c2ecf20Sopenharmony_ci unsigned char *data = read_part_sector(state, n++, §); 2518c2ecf20Sopenharmony_ci if (!data) 2528c2ecf20Sopenharmony_ci break; 2538c2ecf20Sopenharmony_ci if (copied > count) 2548c2ecf20Sopenharmony_ci copied = count; 2558c2ecf20Sopenharmony_ci memcpy(buffer, data, copied); 2568c2ecf20Sopenharmony_ci put_dev_sector(sect); 2578c2ecf20Sopenharmony_ci buffer += copied; 2588c2ecf20Sopenharmony_ci totalreadcount +=copied; 2598c2ecf20Sopenharmony_ci count -= copied; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci return totalreadcount; 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci/** 2658c2ecf20Sopenharmony_ci * alloc_read_gpt_entries(): reads partition entries from disk 2668c2ecf20Sopenharmony_ci * @state: disk parsed partitions 2678c2ecf20Sopenharmony_ci * @gpt: GPT header 2688c2ecf20Sopenharmony_ci * 2698c2ecf20Sopenharmony_ci * Description: Returns ptes on success, NULL on error. 2708c2ecf20Sopenharmony_ci * Allocates space for PTEs based on information found in @gpt. 2718c2ecf20Sopenharmony_ci * Notes: remember to free pte when you're done! 2728c2ecf20Sopenharmony_ci */ 2738c2ecf20Sopenharmony_cistatic gpt_entry *alloc_read_gpt_entries(struct parsed_partitions *state, 2748c2ecf20Sopenharmony_ci gpt_header *gpt) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci size_t count; 2778c2ecf20Sopenharmony_ci gpt_entry *pte; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci if (!gpt) 2808c2ecf20Sopenharmony_ci return NULL; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci count = (size_t)le32_to_cpu(gpt->num_partition_entries) * 2838c2ecf20Sopenharmony_ci le32_to_cpu(gpt->sizeof_partition_entry); 2848c2ecf20Sopenharmony_ci if (!count) 2858c2ecf20Sopenharmony_ci return NULL; 2868c2ecf20Sopenharmony_ci pte = kmalloc(count, GFP_KERNEL); 2878c2ecf20Sopenharmony_ci if (!pte) 2888c2ecf20Sopenharmony_ci return NULL; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci if (read_lba(state, le64_to_cpu(gpt->partition_entry_lba), 2918c2ecf20Sopenharmony_ci (u8 *) pte, count) < count) { 2928c2ecf20Sopenharmony_ci kfree(pte); 2938c2ecf20Sopenharmony_ci pte=NULL; 2948c2ecf20Sopenharmony_ci return NULL; 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci return pte; 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci/** 3008c2ecf20Sopenharmony_ci * alloc_read_gpt_header(): Allocates GPT header, reads into it from disk 3018c2ecf20Sopenharmony_ci * @state: disk parsed partitions 3028c2ecf20Sopenharmony_ci * @lba: the Logical Block Address of the partition table 3038c2ecf20Sopenharmony_ci * 3048c2ecf20Sopenharmony_ci * Description: returns GPT header on success, NULL on error. Allocates 3058c2ecf20Sopenharmony_ci * and fills a GPT header starting at @ from @state->bdev. 3068c2ecf20Sopenharmony_ci * Note: remember to free gpt when finished with it. 3078c2ecf20Sopenharmony_ci */ 3088c2ecf20Sopenharmony_cistatic gpt_header *alloc_read_gpt_header(struct parsed_partitions *state, 3098c2ecf20Sopenharmony_ci u64 lba) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci gpt_header *gpt; 3128c2ecf20Sopenharmony_ci unsigned ssz = bdev_logical_block_size(state->bdev); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci gpt = kmalloc(ssz, GFP_KERNEL); 3158c2ecf20Sopenharmony_ci if (!gpt) 3168c2ecf20Sopenharmony_ci return NULL; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci if (read_lba(state, lba, (u8 *) gpt, ssz) < ssz) { 3198c2ecf20Sopenharmony_ci kfree(gpt); 3208c2ecf20Sopenharmony_ci gpt=NULL; 3218c2ecf20Sopenharmony_ci return NULL; 3228c2ecf20Sopenharmony_ci } 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci return gpt; 3258c2ecf20Sopenharmony_ci} 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci/** 3288c2ecf20Sopenharmony_ci * is_gpt_valid() - tests one GPT header and PTEs for validity 3298c2ecf20Sopenharmony_ci * @state: disk parsed partitions 3308c2ecf20Sopenharmony_ci * @lba: logical block address of the GPT header to test 3318c2ecf20Sopenharmony_ci * @gpt: GPT header ptr, filled on return. 3328c2ecf20Sopenharmony_ci * @ptes: PTEs ptr, filled on return. 3338c2ecf20Sopenharmony_ci * 3348c2ecf20Sopenharmony_ci * Description: returns 1 if valid, 0 on error. 3358c2ecf20Sopenharmony_ci * If valid, returns pointers to newly allocated GPT header and PTEs. 3368c2ecf20Sopenharmony_ci */ 3378c2ecf20Sopenharmony_cistatic int is_gpt_valid(struct parsed_partitions *state, u64 lba, 3388c2ecf20Sopenharmony_ci gpt_header **gpt, gpt_entry **ptes) 3398c2ecf20Sopenharmony_ci{ 3408c2ecf20Sopenharmony_ci u32 crc, origcrc; 3418c2ecf20Sopenharmony_ci u64 lastlba, pt_size; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci if (!ptes) 3448c2ecf20Sopenharmony_ci return 0; 3458c2ecf20Sopenharmony_ci if (!(*gpt = alloc_read_gpt_header(state, lba))) 3468c2ecf20Sopenharmony_ci return 0; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci /* Check the GUID Partition Table signature */ 3498c2ecf20Sopenharmony_ci if (le64_to_cpu((*gpt)->signature) != GPT_HEADER_SIGNATURE) { 3508c2ecf20Sopenharmony_ci pr_debug("GUID Partition Table Header signature is wrong:" 3518c2ecf20Sopenharmony_ci "%lld != %lld\n", 3528c2ecf20Sopenharmony_ci (unsigned long long)le64_to_cpu((*gpt)->signature), 3538c2ecf20Sopenharmony_ci (unsigned long long)GPT_HEADER_SIGNATURE); 3548c2ecf20Sopenharmony_ci goto fail; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci /* Check the GUID Partition Table header size is too big */ 3588c2ecf20Sopenharmony_ci if (le32_to_cpu((*gpt)->header_size) > 3598c2ecf20Sopenharmony_ci bdev_logical_block_size(state->bdev)) { 3608c2ecf20Sopenharmony_ci pr_debug("GUID Partition Table Header size is too large: %u > %u\n", 3618c2ecf20Sopenharmony_ci le32_to_cpu((*gpt)->header_size), 3628c2ecf20Sopenharmony_ci bdev_logical_block_size(state->bdev)); 3638c2ecf20Sopenharmony_ci goto fail; 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci /* Check the GUID Partition Table header size is too small */ 3678c2ecf20Sopenharmony_ci if (le32_to_cpu((*gpt)->header_size) < sizeof(gpt_header)) { 3688c2ecf20Sopenharmony_ci pr_debug("GUID Partition Table Header size is too small: %u < %zu\n", 3698c2ecf20Sopenharmony_ci le32_to_cpu((*gpt)->header_size), 3708c2ecf20Sopenharmony_ci sizeof(gpt_header)); 3718c2ecf20Sopenharmony_ci goto fail; 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci /* Check the GUID Partition Table CRC */ 3758c2ecf20Sopenharmony_ci origcrc = le32_to_cpu((*gpt)->header_crc32); 3768c2ecf20Sopenharmony_ci (*gpt)->header_crc32 = 0; 3778c2ecf20Sopenharmony_ci crc = efi_crc32((const unsigned char *) (*gpt), le32_to_cpu((*gpt)->header_size)); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci if (crc != origcrc) { 3808c2ecf20Sopenharmony_ci pr_debug("GUID Partition Table Header CRC is wrong: %x != %x\n", 3818c2ecf20Sopenharmony_ci crc, origcrc); 3828c2ecf20Sopenharmony_ci goto fail; 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci (*gpt)->header_crc32 = cpu_to_le32(origcrc); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci /* Check that the my_lba entry points to the LBA that contains 3878c2ecf20Sopenharmony_ci * the GUID Partition Table */ 3888c2ecf20Sopenharmony_ci if (le64_to_cpu((*gpt)->my_lba) != lba) { 3898c2ecf20Sopenharmony_ci pr_debug("GPT my_lba incorrect: %lld != %lld\n", 3908c2ecf20Sopenharmony_ci (unsigned long long)le64_to_cpu((*gpt)->my_lba), 3918c2ecf20Sopenharmony_ci (unsigned long long)lba); 3928c2ecf20Sopenharmony_ci goto fail; 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci /* Check the first_usable_lba and last_usable_lba are 3968c2ecf20Sopenharmony_ci * within the disk. 3978c2ecf20Sopenharmony_ci */ 3988c2ecf20Sopenharmony_ci lastlba = last_lba(state->bdev); 3998c2ecf20Sopenharmony_ci if (le64_to_cpu((*gpt)->first_usable_lba) > lastlba) { 4008c2ecf20Sopenharmony_ci pr_debug("GPT: first_usable_lba incorrect: %lld > %lld\n", 4018c2ecf20Sopenharmony_ci (unsigned long long)le64_to_cpu((*gpt)->first_usable_lba), 4028c2ecf20Sopenharmony_ci (unsigned long long)lastlba); 4038c2ecf20Sopenharmony_ci goto fail; 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci if (le64_to_cpu((*gpt)->last_usable_lba) > lastlba) { 4068c2ecf20Sopenharmony_ci pr_debug("GPT: last_usable_lba incorrect: %lld > %lld\n", 4078c2ecf20Sopenharmony_ci (unsigned long long)le64_to_cpu((*gpt)->last_usable_lba), 4088c2ecf20Sopenharmony_ci (unsigned long long)lastlba); 4098c2ecf20Sopenharmony_ci goto fail; 4108c2ecf20Sopenharmony_ci } 4118c2ecf20Sopenharmony_ci if (le64_to_cpu((*gpt)->last_usable_lba) < le64_to_cpu((*gpt)->first_usable_lba)) { 4128c2ecf20Sopenharmony_ci pr_debug("GPT: last_usable_lba incorrect: %lld > %lld\n", 4138c2ecf20Sopenharmony_ci (unsigned long long)le64_to_cpu((*gpt)->last_usable_lba), 4148c2ecf20Sopenharmony_ci (unsigned long long)le64_to_cpu((*gpt)->first_usable_lba)); 4158c2ecf20Sopenharmony_ci goto fail; 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci /* Check that sizeof_partition_entry has the correct value */ 4188c2ecf20Sopenharmony_ci if (le32_to_cpu((*gpt)->sizeof_partition_entry) != sizeof(gpt_entry)) { 4198c2ecf20Sopenharmony_ci pr_debug("GUID Partition Entry Size check failed.\n"); 4208c2ecf20Sopenharmony_ci goto fail; 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci /* Sanity check partition table size */ 4248c2ecf20Sopenharmony_ci pt_size = (u64)le32_to_cpu((*gpt)->num_partition_entries) * 4258c2ecf20Sopenharmony_ci le32_to_cpu((*gpt)->sizeof_partition_entry); 4268c2ecf20Sopenharmony_ci if (pt_size > KMALLOC_MAX_SIZE) { 4278c2ecf20Sopenharmony_ci pr_debug("GUID Partition Table is too large: %llu > %lu bytes\n", 4288c2ecf20Sopenharmony_ci (unsigned long long)pt_size, KMALLOC_MAX_SIZE); 4298c2ecf20Sopenharmony_ci goto fail; 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci if (!(*ptes = alloc_read_gpt_entries(state, *gpt))) 4338c2ecf20Sopenharmony_ci goto fail; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci /* Check the GUID Partition Entry Array CRC */ 4368c2ecf20Sopenharmony_ci crc = efi_crc32((const unsigned char *) (*ptes), pt_size); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci if (crc != le32_to_cpu((*gpt)->partition_entry_array_crc32)) { 4398c2ecf20Sopenharmony_ci pr_debug("GUID Partition Entry Array CRC check failed.\n"); 4408c2ecf20Sopenharmony_ci goto fail_ptes; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci /* We're done, all's well */ 4448c2ecf20Sopenharmony_ci return 1; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci fail_ptes: 4478c2ecf20Sopenharmony_ci kfree(*ptes); 4488c2ecf20Sopenharmony_ci *ptes = NULL; 4498c2ecf20Sopenharmony_ci fail: 4508c2ecf20Sopenharmony_ci kfree(*gpt); 4518c2ecf20Sopenharmony_ci *gpt = NULL; 4528c2ecf20Sopenharmony_ci return 0; 4538c2ecf20Sopenharmony_ci} 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci/** 4568c2ecf20Sopenharmony_ci * is_pte_valid() - tests one PTE for validity 4578c2ecf20Sopenharmony_ci * @pte:pte to check 4588c2ecf20Sopenharmony_ci * @lastlba: last lba of the disk 4598c2ecf20Sopenharmony_ci * 4608c2ecf20Sopenharmony_ci * Description: returns 1 if valid, 0 on error. 4618c2ecf20Sopenharmony_ci */ 4628c2ecf20Sopenharmony_cistatic inline int 4638c2ecf20Sopenharmony_ciis_pte_valid(const gpt_entry *pte, const u64 lastlba) 4648c2ecf20Sopenharmony_ci{ 4658c2ecf20Sopenharmony_ci if ((!efi_guidcmp(pte->partition_type_guid, NULL_GUID)) || 4668c2ecf20Sopenharmony_ci le64_to_cpu(pte->starting_lba) > lastlba || 4678c2ecf20Sopenharmony_ci le64_to_cpu(pte->ending_lba) > lastlba) 4688c2ecf20Sopenharmony_ci return 0; 4698c2ecf20Sopenharmony_ci return 1; 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci/** 4738c2ecf20Sopenharmony_ci * compare_gpts() - Search disk for valid GPT headers and PTEs 4748c2ecf20Sopenharmony_ci * @pgpt: primary GPT header 4758c2ecf20Sopenharmony_ci * @agpt: alternate GPT header 4768c2ecf20Sopenharmony_ci * @lastlba: last LBA number 4778c2ecf20Sopenharmony_ci * 4788c2ecf20Sopenharmony_ci * Description: Returns nothing. Sanity checks pgpt and agpt fields 4798c2ecf20Sopenharmony_ci * and prints warnings on discrepancies. 4808c2ecf20Sopenharmony_ci * 4818c2ecf20Sopenharmony_ci */ 4828c2ecf20Sopenharmony_cistatic void 4838c2ecf20Sopenharmony_cicompare_gpts(gpt_header *pgpt, gpt_header *agpt, u64 lastlba) 4848c2ecf20Sopenharmony_ci{ 4858c2ecf20Sopenharmony_ci int error_found = 0; 4868c2ecf20Sopenharmony_ci if (!pgpt || !agpt) 4878c2ecf20Sopenharmony_ci return; 4888c2ecf20Sopenharmony_ci if (le64_to_cpu(pgpt->my_lba) != le64_to_cpu(agpt->alternate_lba)) { 4898c2ecf20Sopenharmony_ci pr_warn("GPT:Primary header LBA != Alt. header alternate_lba\n"); 4908c2ecf20Sopenharmony_ci pr_warn("GPT:%lld != %lld\n", 4918c2ecf20Sopenharmony_ci (unsigned long long)le64_to_cpu(pgpt->my_lba), 4928c2ecf20Sopenharmony_ci (unsigned long long)le64_to_cpu(agpt->alternate_lba)); 4938c2ecf20Sopenharmony_ci error_found++; 4948c2ecf20Sopenharmony_ci } 4958c2ecf20Sopenharmony_ci if (le64_to_cpu(pgpt->alternate_lba) != le64_to_cpu(agpt->my_lba)) { 4968c2ecf20Sopenharmony_ci pr_warn("GPT:Primary header alternate_lba != Alt. header my_lba\n"); 4978c2ecf20Sopenharmony_ci pr_warn("GPT:%lld != %lld\n", 4988c2ecf20Sopenharmony_ci (unsigned long long)le64_to_cpu(pgpt->alternate_lba), 4998c2ecf20Sopenharmony_ci (unsigned long long)le64_to_cpu(agpt->my_lba)); 5008c2ecf20Sopenharmony_ci error_found++; 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci if (le64_to_cpu(pgpt->first_usable_lba) != 5038c2ecf20Sopenharmony_ci le64_to_cpu(agpt->first_usable_lba)) { 5048c2ecf20Sopenharmony_ci pr_warn("GPT:first_usable_lbas don't match.\n"); 5058c2ecf20Sopenharmony_ci pr_warn("GPT:%lld != %lld\n", 5068c2ecf20Sopenharmony_ci (unsigned long long)le64_to_cpu(pgpt->first_usable_lba), 5078c2ecf20Sopenharmony_ci (unsigned long long)le64_to_cpu(agpt->first_usable_lba)); 5088c2ecf20Sopenharmony_ci error_found++; 5098c2ecf20Sopenharmony_ci } 5108c2ecf20Sopenharmony_ci if (le64_to_cpu(pgpt->last_usable_lba) != 5118c2ecf20Sopenharmony_ci le64_to_cpu(agpt->last_usable_lba)) { 5128c2ecf20Sopenharmony_ci pr_warn("GPT:last_usable_lbas don't match.\n"); 5138c2ecf20Sopenharmony_ci pr_warn("GPT:%lld != %lld\n", 5148c2ecf20Sopenharmony_ci (unsigned long long)le64_to_cpu(pgpt->last_usable_lba), 5158c2ecf20Sopenharmony_ci (unsigned long long)le64_to_cpu(agpt->last_usable_lba)); 5168c2ecf20Sopenharmony_ci error_found++; 5178c2ecf20Sopenharmony_ci } 5188c2ecf20Sopenharmony_ci if (efi_guidcmp(pgpt->disk_guid, agpt->disk_guid)) { 5198c2ecf20Sopenharmony_ci pr_warn("GPT:disk_guids don't match.\n"); 5208c2ecf20Sopenharmony_ci error_found++; 5218c2ecf20Sopenharmony_ci } 5228c2ecf20Sopenharmony_ci if (le32_to_cpu(pgpt->num_partition_entries) != 5238c2ecf20Sopenharmony_ci le32_to_cpu(agpt->num_partition_entries)) { 5248c2ecf20Sopenharmony_ci pr_warn("GPT:num_partition_entries don't match: " 5258c2ecf20Sopenharmony_ci "0x%x != 0x%x\n", 5268c2ecf20Sopenharmony_ci le32_to_cpu(pgpt->num_partition_entries), 5278c2ecf20Sopenharmony_ci le32_to_cpu(agpt->num_partition_entries)); 5288c2ecf20Sopenharmony_ci error_found++; 5298c2ecf20Sopenharmony_ci } 5308c2ecf20Sopenharmony_ci if (le32_to_cpu(pgpt->sizeof_partition_entry) != 5318c2ecf20Sopenharmony_ci le32_to_cpu(agpt->sizeof_partition_entry)) { 5328c2ecf20Sopenharmony_ci pr_warn("GPT:sizeof_partition_entry values don't match: " 5338c2ecf20Sopenharmony_ci "0x%x != 0x%x\n", 5348c2ecf20Sopenharmony_ci le32_to_cpu(pgpt->sizeof_partition_entry), 5358c2ecf20Sopenharmony_ci le32_to_cpu(agpt->sizeof_partition_entry)); 5368c2ecf20Sopenharmony_ci error_found++; 5378c2ecf20Sopenharmony_ci } 5388c2ecf20Sopenharmony_ci if (le32_to_cpu(pgpt->partition_entry_array_crc32) != 5398c2ecf20Sopenharmony_ci le32_to_cpu(agpt->partition_entry_array_crc32)) { 5408c2ecf20Sopenharmony_ci pr_warn("GPT:partition_entry_array_crc32 values don't match: " 5418c2ecf20Sopenharmony_ci "0x%x != 0x%x\n", 5428c2ecf20Sopenharmony_ci le32_to_cpu(pgpt->partition_entry_array_crc32), 5438c2ecf20Sopenharmony_ci le32_to_cpu(agpt->partition_entry_array_crc32)); 5448c2ecf20Sopenharmony_ci error_found++; 5458c2ecf20Sopenharmony_ci } 5468c2ecf20Sopenharmony_ci if (le64_to_cpu(pgpt->alternate_lba) != lastlba) { 5478c2ecf20Sopenharmony_ci pr_warn("GPT:Primary header thinks Alt. header is not at the end of the disk.\n"); 5488c2ecf20Sopenharmony_ci pr_warn("GPT:%lld != %lld\n", 5498c2ecf20Sopenharmony_ci (unsigned long long)le64_to_cpu(pgpt->alternate_lba), 5508c2ecf20Sopenharmony_ci (unsigned long long)lastlba); 5518c2ecf20Sopenharmony_ci error_found++; 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci if (le64_to_cpu(agpt->my_lba) != lastlba) { 5558c2ecf20Sopenharmony_ci pr_warn("GPT:Alternate GPT header not at the end of the disk.\n"); 5568c2ecf20Sopenharmony_ci pr_warn("GPT:%lld != %lld\n", 5578c2ecf20Sopenharmony_ci (unsigned long long)le64_to_cpu(agpt->my_lba), 5588c2ecf20Sopenharmony_ci (unsigned long long)lastlba); 5598c2ecf20Sopenharmony_ci error_found++; 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci if (error_found) 5638c2ecf20Sopenharmony_ci pr_warn("GPT: Use GNU Parted to correct GPT errors.\n"); 5648c2ecf20Sopenharmony_ci return; 5658c2ecf20Sopenharmony_ci} 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci/** 5688c2ecf20Sopenharmony_ci * find_valid_gpt() - Search disk for valid GPT headers and PTEs 5698c2ecf20Sopenharmony_ci * @state: disk parsed partitions 5708c2ecf20Sopenharmony_ci * @gpt: GPT header ptr, filled on return. 5718c2ecf20Sopenharmony_ci * @ptes: PTEs ptr, filled on return. 5728c2ecf20Sopenharmony_ci * 5738c2ecf20Sopenharmony_ci * Description: Returns 1 if valid, 0 on error. 5748c2ecf20Sopenharmony_ci * If valid, returns pointers to newly allocated GPT header and PTEs. 5758c2ecf20Sopenharmony_ci * Validity depends on PMBR being valid (or being overridden by the 5768c2ecf20Sopenharmony_ci * 'gpt' kernel command line option) and finding either the Primary 5778c2ecf20Sopenharmony_ci * GPT header and PTEs valid, or the Alternate GPT header and PTEs 5788c2ecf20Sopenharmony_ci * valid. If the Primary GPT header is not valid, the Alternate GPT header 5798c2ecf20Sopenharmony_ci * is not checked unless the 'gpt' kernel command line option is passed. 5808c2ecf20Sopenharmony_ci * This protects against devices which misreport their size, and forces 5818c2ecf20Sopenharmony_ci * the user to decide to use the Alternate GPT. 5828c2ecf20Sopenharmony_ci */ 5838c2ecf20Sopenharmony_cistatic int find_valid_gpt(struct parsed_partitions *state, gpt_header **gpt, 5848c2ecf20Sopenharmony_ci gpt_entry **ptes) 5858c2ecf20Sopenharmony_ci{ 5868c2ecf20Sopenharmony_ci int good_pgpt = 0, good_agpt = 0, good_pmbr = 0; 5878c2ecf20Sopenharmony_ci gpt_header *pgpt = NULL, *agpt = NULL; 5888c2ecf20Sopenharmony_ci gpt_entry *pptes = NULL, *aptes = NULL; 5898c2ecf20Sopenharmony_ci legacy_mbr *legacymbr; 5908c2ecf20Sopenharmony_ci sector_t total_sectors = i_size_read(state->bdev->bd_inode) >> 9; 5918c2ecf20Sopenharmony_ci u64 lastlba; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci if (!ptes) 5948c2ecf20Sopenharmony_ci return 0; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci lastlba = last_lba(state->bdev); 5978c2ecf20Sopenharmony_ci if (!force_gpt) { 5988c2ecf20Sopenharmony_ci /* This will be added to the EFI Spec. per Intel after v1.02. */ 5998c2ecf20Sopenharmony_ci legacymbr = kzalloc(sizeof(*legacymbr), GFP_KERNEL); 6008c2ecf20Sopenharmony_ci if (!legacymbr) 6018c2ecf20Sopenharmony_ci goto fail; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci read_lba(state, 0, (u8 *)legacymbr, sizeof(*legacymbr)); 6048c2ecf20Sopenharmony_ci good_pmbr = is_pmbr_valid(legacymbr, total_sectors); 6058c2ecf20Sopenharmony_ci kfree(legacymbr); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci if (!good_pmbr) 6088c2ecf20Sopenharmony_ci goto fail; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci pr_debug("Device has a %s MBR\n", 6118c2ecf20Sopenharmony_ci good_pmbr == GPT_MBR_PROTECTIVE ? 6128c2ecf20Sopenharmony_ci "protective" : "hybrid"); 6138c2ecf20Sopenharmony_ci } 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci good_pgpt = is_gpt_valid(state, GPT_PRIMARY_PARTITION_TABLE_LBA, 6168c2ecf20Sopenharmony_ci &pgpt, &pptes); 6178c2ecf20Sopenharmony_ci if (good_pgpt) 6188c2ecf20Sopenharmony_ci good_agpt = is_gpt_valid(state, 6198c2ecf20Sopenharmony_ci le64_to_cpu(pgpt->alternate_lba), 6208c2ecf20Sopenharmony_ci &agpt, &aptes); 6218c2ecf20Sopenharmony_ci if (!good_agpt && force_gpt) 6228c2ecf20Sopenharmony_ci good_agpt = is_gpt_valid(state, lastlba, &agpt, &aptes); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci /* The obviously unsuccessful case */ 6258c2ecf20Sopenharmony_ci if (!good_pgpt && !good_agpt) 6268c2ecf20Sopenharmony_ci goto fail; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci compare_gpts(pgpt, agpt, lastlba); 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci /* The good cases */ 6318c2ecf20Sopenharmony_ci if (good_pgpt) { 6328c2ecf20Sopenharmony_ci *gpt = pgpt; 6338c2ecf20Sopenharmony_ci *ptes = pptes; 6348c2ecf20Sopenharmony_ci kfree(agpt); 6358c2ecf20Sopenharmony_ci kfree(aptes); 6368c2ecf20Sopenharmony_ci if (!good_agpt) 6378c2ecf20Sopenharmony_ci pr_warn("Alternate GPT is invalid, using primary GPT.\n"); 6388c2ecf20Sopenharmony_ci return 1; 6398c2ecf20Sopenharmony_ci } 6408c2ecf20Sopenharmony_ci else if (good_agpt) { 6418c2ecf20Sopenharmony_ci *gpt = agpt; 6428c2ecf20Sopenharmony_ci *ptes = aptes; 6438c2ecf20Sopenharmony_ci kfree(pgpt); 6448c2ecf20Sopenharmony_ci kfree(pptes); 6458c2ecf20Sopenharmony_ci pr_warn("Primary GPT is invalid, using alternate GPT.\n"); 6468c2ecf20Sopenharmony_ci return 1; 6478c2ecf20Sopenharmony_ci } 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci fail: 6508c2ecf20Sopenharmony_ci kfree(pgpt); 6518c2ecf20Sopenharmony_ci kfree(agpt); 6528c2ecf20Sopenharmony_ci kfree(pptes); 6538c2ecf20Sopenharmony_ci kfree(aptes); 6548c2ecf20Sopenharmony_ci *gpt = NULL; 6558c2ecf20Sopenharmony_ci *ptes = NULL; 6568c2ecf20Sopenharmony_ci return 0; 6578c2ecf20Sopenharmony_ci} 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci/** 6608c2ecf20Sopenharmony_ci * utf16_le_to_7bit(): Naively converts a UTF-16LE string to 7-bit ASCII characters 6618c2ecf20Sopenharmony_ci * @in: input UTF-16LE string 6628c2ecf20Sopenharmony_ci * @size: size of the input string 6638c2ecf20Sopenharmony_ci * @out: output string ptr, should be capable to store @size+1 characters 6648c2ecf20Sopenharmony_ci * 6658c2ecf20Sopenharmony_ci * Description: Converts @size UTF16-LE symbols from @in string to 7-bit 6668c2ecf20Sopenharmony_ci * ASCII characters and stores them to @out. Adds trailing zero to @out array. 6678c2ecf20Sopenharmony_ci */ 6688c2ecf20Sopenharmony_cistatic void utf16_le_to_7bit(const __le16 *in, unsigned int size, u8 *out) 6698c2ecf20Sopenharmony_ci{ 6708c2ecf20Sopenharmony_ci unsigned int i = 0; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci out[size] = 0; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci while (i < size) { 6758c2ecf20Sopenharmony_ci u8 c = le16_to_cpu(in[i]) & 0xff; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci if (c && !isprint(c)) 6788c2ecf20Sopenharmony_ci c = '!'; 6798c2ecf20Sopenharmony_ci out[i] = c; 6808c2ecf20Sopenharmony_ci i++; 6818c2ecf20Sopenharmony_ci } 6828c2ecf20Sopenharmony_ci} 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci/** 6858c2ecf20Sopenharmony_ci * efi_partition(struct parsed_partitions *state) 6868c2ecf20Sopenharmony_ci * @state: disk parsed partitions 6878c2ecf20Sopenharmony_ci * 6888c2ecf20Sopenharmony_ci * Description: called from check.c, if the disk contains GPT 6898c2ecf20Sopenharmony_ci * partitions, sets up partition entries in the kernel. 6908c2ecf20Sopenharmony_ci * 6918c2ecf20Sopenharmony_ci * If the first block on the disk is a legacy MBR, 6928c2ecf20Sopenharmony_ci * it will get handled by msdos_partition(). 6938c2ecf20Sopenharmony_ci * If it's a Protective MBR, we'll handle it here. 6948c2ecf20Sopenharmony_ci * 6958c2ecf20Sopenharmony_ci * We do not create a Linux partition for GPT, but 6968c2ecf20Sopenharmony_ci * only for the actual data partitions. 6978c2ecf20Sopenharmony_ci * Returns: 6988c2ecf20Sopenharmony_ci * -1 if unable to read the partition table 6998c2ecf20Sopenharmony_ci * 0 if this isn't our partition table 7008c2ecf20Sopenharmony_ci * 1 if successful 7018c2ecf20Sopenharmony_ci * 7028c2ecf20Sopenharmony_ci */ 7038c2ecf20Sopenharmony_ciint efi_partition(struct parsed_partitions *state) 7048c2ecf20Sopenharmony_ci{ 7058c2ecf20Sopenharmony_ci gpt_header *gpt = NULL; 7068c2ecf20Sopenharmony_ci gpt_entry *ptes = NULL; 7078c2ecf20Sopenharmony_ci u32 i; 7088c2ecf20Sopenharmony_ci unsigned ssz = bdev_logical_block_size(state->bdev) / 512; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci if (!find_valid_gpt(state, &gpt, &ptes) || !gpt || !ptes) { 7118c2ecf20Sopenharmony_ci kfree(gpt); 7128c2ecf20Sopenharmony_ci kfree(ptes); 7138c2ecf20Sopenharmony_ci return 0; 7148c2ecf20Sopenharmony_ci } 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci pr_debug("GUID Partition Table is valid! Yea!\n"); 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci for (i = 0; i < le32_to_cpu(gpt->num_partition_entries) && i < state->limit-1; i++) { 7198c2ecf20Sopenharmony_ci struct partition_meta_info *info; 7208c2ecf20Sopenharmony_ci unsigned label_max; 7218c2ecf20Sopenharmony_ci u64 start = le64_to_cpu(ptes[i].starting_lba); 7228c2ecf20Sopenharmony_ci u64 size = le64_to_cpu(ptes[i].ending_lba) - 7238c2ecf20Sopenharmony_ci le64_to_cpu(ptes[i].starting_lba) + 1ULL; 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci if (!is_pte_valid(&ptes[i], last_lba(state->bdev))) 7268c2ecf20Sopenharmony_ci continue; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci put_partition(state, i+1, start * ssz, size * ssz); 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci /* If this is a RAID volume, tell md */ 7318c2ecf20Sopenharmony_ci if (!efi_guidcmp(ptes[i].partition_type_guid, PARTITION_LINUX_RAID_GUID)) 7328c2ecf20Sopenharmony_ci state->parts[i + 1].flags = ADDPART_FLAG_RAID; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci info = &state->parts[i + 1].info; 7358c2ecf20Sopenharmony_ci efi_guid_to_str(&ptes[i].unique_partition_guid, info->uuid); 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci /* Naively convert UTF16-LE to 7 bits. */ 7388c2ecf20Sopenharmony_ci label_max = min(ARRAY_SIZE(info->volname) - 1, 7398c2ecf20Sopenharmony_ci ARRAY_SIZE(ptes[i].partition_name)); 7408c2ecf20Sopenharmony_ci utf16_le_to_7bit(ptes[i].partition_name, label_max, info->volname); 7418c2ecf20Sopenharmony_ci state->parts[i + 1].has_info = true; 7428c2ecf20Sopenharmony_ci } 7438c2ecf20Sopenharmony_ci kfree(ptes); 7448c2ecf20Sopenharmony_ci kfree(gpt); 7458c2ecf20Sopenharmony_ci strlcat(state->pp_buf, "\n", PAGE_SIZE); 7468c2ecf20Sopenharmony_ci return 1; 7478c2ecf20Sopenharmony_ci} 748