Home | History | Annotate | Download | only in hikey
      1 /*
      2  * Copyright (c) 2014-2015, Linaro Ltd and Contributors. All rights reserved.
      3  * Copyright (c) 2014-2015, Hisilicon Ltd and Contributors. All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are met:
      7  *
      8  * Redistributions of source code must retain the above copyright notice, this
      9  * list of conditions and the following disclaimer.
     10  *
     11  * Redistributions in binary form must reproduce the above copyright notice,
     12  * this list of conditions and the following disclaimer in the documentation
     13  * and/or other materials provided with the distribution.
     14  *
     15  * Neither the name of ARM nor the names of its contributors may be used
     16  * to endorse or promote products derived from this software without specific
     17  * prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
     23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include <debug.h>
     33 #include <dw_mmc.h>
     34 #include <errno.h>
     35 #include <io_storage.h>
     36 #include <mmio.h>
     37 #include <partitions.h>
     38 #include <platform_def.h>
     39 #include <string.h>
     40 #include "hikey_private.h"
     41 
     42 #define EFI_ENTRIES		128
     43 #define EFI_ENTRY_SIZE		(sizeof(struct efi_entry))
     44 #define EFI_MBR_SIZE		512
     45 #define EFI_HEADER_SIZE		512
     46 #define EFI_TOTAL_SIZE		(EFI_MBR_SIZE + EFI_HEADER_SIZE +	\
     47 				EFI_ENTRY_SIZE * EFI_ENTRIES)
     48 
     49 struct efi_header {
     50 	char		signature[8];
     51 	uint32_t	revision;
     52 	uint32_t	size;
     53 	uint32_t	header_crc;
     54 	uint32_t	reserved;
     55 	uint64_t	current_lba;
     56 	uint64_t	backup_lba;
     57 	uint64_t	first_lba;
     58 	uint64_t	last_lba;
     59 	uint8_t		disk_uuid[16];
     60 	/* starting LBA of array of partition entries */
     61 	uint64_t	part_lba;
     62 	/* number of partition entries in array */
     63 	uint32_t	part_num;
     64 	/* size of a single partition entry (usually 128) */
     65 	uint32_t	part_size;
     66 	uint32_t	part_crc;
     67 };
     68 
     69 struct efi_entry {
     70 	uint8_t		type_uuid[16];
     71 	uint8_t		uniq_uuid[16];
     72 	uint64_t	first_lba;
     73 	uint64_t	last_lba;
     74 	uint64_t	attr;
     75 	uint16_t	name[EFI_NAMELEN];
     76 };
     77 
     78 /* the first entry is dummy for ptable (covers both primary & secondary) */
     79 static struct ptentry ptable[EFI_ENTRIES + 1];
     80 static int entries;	/* partition entry entries */
     81 
     82 static void dump_entries(void)
     83 {
     84 	int i;
     85 
     86 	VERBOSE("Partition table with %d entries:\n", entries);
     87 	for (i = 0; i < entries; i++) {
     88 		VERBOSE("%s %llx-%llx\n", ptable[i].name,
     89 			ptable[i].start,
     90 			ptable[i].start + ptable[i].length - 4);
     91 	}
     92 }
     93 
     94 static int convert_ascii_string(uint16_t *str_in, uint8_t *str_out)
     95 {
     96 	uint8_t *name = (uint8_t *)str_in;
     97 	int i;
     98 
     99 	if (name[0] == '\0' || !str_in || !str_out)
    100 		return -EINVAL;
    101 	for (i = 1; i < (EFI_NAMELEN << 1); i += 2) {
    102 		if (name[i] != '\0')
    103 			return -EINVAL;
    104 	}
    105 	for (i = 0; i < (EFI_NAMELEN << 1); i += 2) {
    106 		str_out[i >> 1] = name[i];
    107 		if (name[i] == '\0')
    108 			break;
    109 	}
    110 	return 0;
    111 }
    112 
    113 static int parse_entry(uintptr_t buf)
    114 {
    115 	struct efi_entry *entry = (struct efi_entry *)buf;
    116 	int ret;
    117 
    118 	/* exhaused partition entry */
    119 	if ((entry->first_lba == 0) && (entry->last_lba == 0))
    120 		return 1;
    121 	ret = convert_ascii_string(entry->name, (uint8_t *)ptable[entries].name);
    122 	if (ret < 0)
    123 		return ret;
    124 	ptable[entries].start = (uint64_t)entry->first_lba * 512;
    125 	ptable[entries].length = (uint64_t)(entry->last_lba - entry->first_lba + 1) * 512;
    126 	entries++;
    127 	return 0;
    128 }
    129 
    130 /* create dummy entry for ptable */
    131 static void create_dummy_entry(void)
    132 {
    133 	int bytes;
    134 	ptable[entries].start = 0;
    135 	ptable[entries].length = 0;
    136 	bytes = sprintf(ptable[entries].name, "ptable");
    137 	ptable[entries].name[bytes] = '\0';
    138 	entries++;
    139 }
    140 
    141 struct ptentry *find_ptn(const char *str)
    142 {
    143 	struct ptentry *ptn = NULL;
    144 	int i;
    145 
    146 	for (i = 0; i < entries; i++) {
    147 		if (!strcmp(ptable[i].name, str)) {
    148 			ptn = &ptable[i];
    149 			break;
    150 		}
    151 	}
    152 	return ptn;
    153 }
    154 
    155 int get_partition(void)
    156 {
    157 	int result = IO_FAIL;
    158 	int i, ret, num_entries;
    159 	size_t bytes_read;
    160 	uintptr_t emmc_dev_handle, spec, img_handle;
    161 	unsigned int buf[MMC_BLOCK_SIZE >> 2];
    162 	struct efi_header *hd = NULL;
    163 
    164 	create_dummy_entry();
    165 	result = plat_get_image_source(NORMAL_EMMC_NAME, &emmc_dev_handle,
    166 				       &spec);
    167 	if (result) {
    168 		WARN("failed to open eMMC normal partition\n");
    169 		return result;
    170 	}
    171 	result = io_open(emmc_dev_handle, spec, &img_handle);
    172 	if (result != IO_SUCCESS) {
    173 		WARN("Failed to open eMMC device\n");
    174 		return result;
    175 	}
    176 	result = io_seek(img_handle, IO_SEEK_SET, 0);
    177 	if (result)
    178 		goto exit;
    179 	result = io_read(img_handle, (uintptr_t)buf, EFI_MBR_SIZE,
    180 			 &bytes_read);
    181 	if ((result != IO_SUCCESS) || (bytes_read < EFI_MBR_SIZE)) {
    182 		WARN("Failed to read eMMC (%i)\n", result);
    183 		goto exit;
    184 	}
    185 	/* check the magic number in last word */
    186 	if (buf[(MMC_BLOCK_SIZE >> 2) - 1] != 0xaa550000) {
    187 		WARN("Can't find MBR protection information\n");
    188 		goto exit;
    189 	}
    190 
    191 	result = io_read(img_handle, (uintptr_t)buf, EFI_HEADER_SIZE,
    192 			 &bytes_read);
    193 	if ((result != IO_SUCCESS) || (bytes_read < EFI_HEADER_SIZE)) {
    194 		WARN("Failed to read eMMC (%i)\n", result);
    195 		goto exit;
    196 	}
    197 	hd = (struct efi_header *)((uintptr_t)buf);
    198 	if (strncmp(hd->signature, "EFI PART", 8)) {
    199 		WARN("Failed to find partition table\n");
    200 		goto exit;
    201 	}
    202 	num_entries = hd->part_num;
    203 	for (i = 0; i < num_entries; i++) {
    204 		result = io_read(img_handle, (uintptr_t)buf, EFI_HEADER_SIZE,
    205 				 &bytes_read);
    206 		if ((result != IO_SUCCESS) || (bytes_read < EFI_HEADER_SIZE)) {
    207 			WARN("Failed to read eMMC (%i)\n", result);
    208 			goto exit;
    209 		}
    210 		/* each header contains four partition entries */
    211 		ret = parse_entry((uintptr_t)buf);
    212 		if (ret)
    213 			break;
    214 		ret = parse_entry((uintptr_t)buf + EFI_ENTRY_SIZE);
    215 		if (ret)
    216 			break;
    217 		ret = parse_entry((uintptr_t)buf + EFI_ENTRY_SIZE * 2);
    218 		if (ret)
    219 			break;
    220 		ret = parse_entry((uintptr_t)buf + EFI_ENTRY_SIZE * 3);
    221 		if (ret)
    222 			break;
    223 	}
    224 exit:
    225 	io_close(img_handle);
    226 	update_fip_spec();
    227 	dump_entries();
    228 	return result;
    229 }
    230