• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
dump_entries(void)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 
convert_ascii_string(uint16_t * str_in,uint8_t * str_out)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 
parse_entry(uintptr_t buf)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 */
create_dummy_entry(void)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 
find_ptn(const char * str)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 
get_partition(void)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