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