xref: /rk3399_ARM-atf/drivers/partition/partition.c (revision f2de48cb143c20ccd7a9c141df3d34cae74049de)
1 /*
2  * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <assert.h>
8 #include <inttypes.h>
9 #include <stdio.h>
10 #include <string.h>
11 
12 #include <common/debug.h>
13 #include <drivers/io/io_storage.h>
14 #include <drivers/partition/efi.h>
15 #include <drivers/partition/partition.h>
16 #include <drivers/partition/gpt.h>
17 #include <drivers/partition/mbr.h>
18 #include <plat/common/platform.h>
19 
20 static uint8_t mbr_sector[PLAT_PARTITION_BLOCK_SIZE];
21 static partition_entry_list_t list;
22 
23 #if LOG_LEVEL >= LOG_LEVEL_VERBOSE
24 static void dump_entries(int num)
25 {
26 	char name[EFI_NAMELEN];
27 	int i, j, len;
28 
29 	VERBOSE("Partition table with %d entries:\n", num);
30 	for (i = 0; i < num; i++) {
31 		len = snprintf(name, EFI_NAMELEN, "%s", list.list[i].name);
32 		for (j = 0; j < EFI_NAMELEN - len - 1; j++) {
33 			name[len + j] = ' ';
34 		}
35 		name[EFI_NAMELEN - 1] = '\0';
36 		VERBOSE("%d: %s %" PRIx64 "-%" PRIx64 "\n", i + 1, name, list.list[i].start,
37 			list.list[i].start + list.list[i].length - 4);
38 	}
39 }
40 #else
41 #define dump_entries(num)	((void)num)
42 #endif
43 
44 /*
45  * Load the first sector that carries MBR header.
46  * The MBR boot signature should be always valid whether it's MBR or GPT.
47  */
48 static int load_mbr_header(uintptr_t image_handle, mbr_entry_t *mbr_entry)
49 {
50 	size_t bytes_read;
51 	uintptr_t offset;
52 	int result;
53 
54 	assert(mbr_entry != NULL);
55 	/* MBR partition table is in LBA0. */
56 	result = io_seek(image_handle, IO_SEEK_SET, MBR_OFFSET);
57 	if (result != 0) {
58 		WARN("Failed to seek (%i)\n", result);
59 		return result;
60 	}
61 	result = io_read(image_handle, (uintptr_t)&mbr_sector,
62 			 PLAT_PARTITION_BLOCK_SIZE, &bytes_read);
63 	if (result != 0) {
64 		WARN("Failed to read data (%i)\n", result);
65 		return result;
66 	}
67 
68 	/* Check MBR boot signature. */
69 	if ((mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) ||
70 	    (mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) {
71 		return -ENOENT;
72 	}
73 	offset = (uintptr_t)&mbr_sector + MBR_PRIMARY_ENTRY_OFFSET;
74 	memcpy(mbr_entry, (void *)offset, sizeof(mbr_entry_t));
75 	return 0;
76 }
77 
78 /*
79  * Load GPT header and check the GPT signature.
80  * If partition numbers could be found, check & update it.
81  */
82 static int load_gpt_header(uintptr_t image_handle)
83 {
84 	gpt_header_t header;
85 	size_t bytes_read;
86 	int result;
87 
88 	result = io_seek(image_handle, IO_SEEK_SET, GPT_HEADER_OFFSET);
89 	if (result != 0) {
90 		return result;
91 	}
92 	result = io_read(image_handle, (uintptr_t)&header,
93 			 sizeof(gpt_header_t), &bytes_read);
94 	if ((result != 0) || (sizeof(gpt_header_t) != bytes_read)) {
95 		return result;
96 	}
97 	if (memcmp(header.signature, GPT_SIGNATURE,
98 		   sizeof(header.signature)) != 0) {
99 		return -EINVAL;
100 	}
101 
102 	/* partition numbers can't exceed PLAT_PARTITION_MAX_ENTRIES */
103 	list.entry_count = header.list_num;
104 	if (list.entry_count > PLAT_PARTITION_MAX_ENTRIES) {
105 		list.entry_count = PLAT_PARTITION_MAX_ENTRIES;
106 	}
107 	return 0;
108 }
109 
110 static int load_mbr_entry(uintptr_t image_handle, mbr_entry_t *mbr_entry,
111 			int part_number)
112 {
113 	size_t bytes_read;
114 	uintptr_t offset;
115 	int result;
116 
117 	assert(mbr_entry != NULL);
118 	/* MBR partition table is in LBA0. */
119 	result = io_seek(image_handle, IO_SEEK_SET, MBR_OFFSET);
120 	if (result != 0) {
121 		WARN("Failed to seek (%i)\n", result);
122 		return result;
123 	}
124 	result = io_read(image_handle, (uintptr_t)&mbr_sector,
125 			 PLAT_PARTITION_BLOCK_SIZE, &bytes_read);
126 	if (result != 0) {
127 		WARN("Failed to read data (%i)\n", result);
128 		return result;
129 	}
130 
131 	/* Check MBR boot signature. */
132 	if ((mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) ||
133 	    (mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) {
134 		return -ENOENT;
135 	}
136 	offset = (uintptr_t)&mbr_sector +
137 		MBR_PRIMARY_ENTRY_OFFSET +
138 		MBR_PRIMARY_ENTRY_SIZE * part_number;
139 	memcpy(mbr_entry, (void *)offset, sizeof(mbr_entry_t));
140 
141 	return 0;
142 }
143 
144 static int load_mbr_entries(uintptr_t image_handle)
145 {
146 	mbr_entry_t mbr_entry;
147 	int i;
148 
149 	list.entry_count = MBR_PRIMARY_ENTRY_NUMBER;
150 
151 	for (i = 0; i < list.entry_count; i++) {
152 		load_mbr_entry(image_handle, &mbr_entry, i);
153 		list.list[i].start = mbr_entry.first_lba * 512;
154 		list.list[i].length = mbr_entry.sector_nums * 512;
155 		list.list[i].name[0] = mbr_entry.type;
156 	}
157 
158 	return 0;
159 }
160 
161 static int load_gpt_entry(uintptr_t image_handle, gpt_entry_t *entry)
162 {
163 	size_t bytes_read;
164 	int result;
165 
166 	assert(entry != NULL);
167 	result = io_read(image_handle, (uintptr_t)entry, sizeof(gpt_entry_t),
168 			 &bytes_read);
169 	if (sizeof(gpt_entry_t) != bytes_read)
170 		return -EINVAL;
171 	return result;
172 }
173 
174 static int verify_partition_gpt(uintptr_t image_handle)
175 {
176 	gpt_entry_t entry;
177 	int result, i;
178 
179 	for (i = 0; i < list.entry_count; i++) {
180 		result = load_gpt_entry(image_handle, &entry);
181 		assert(result == 0);
182 		result = parse_gpt_entry(&entry, &list.list[i]);
183 		if (result != 0) {
184 			break;
185 		}
186 	}
187 	if (i == 0) {
188 		return -EINVAL;
189 	}
190 	/*
191 	 * Only records the valid partition number that is loaded from
192 	 * partition table.
193 	 */
194 	list.entry_count = i;
195 	dump_entries(list.entry_count);
196 
197 	return 0;
198 }
199 
200 int load_partition_table(unsigned int image_id)
201 {
202 	uintptr_t dev_handle, image_handle, image_spec = 0;
203 	mbr_entry_t mbr_entry;
204 	int result;
205 
206 	result = plat_get_image_source(image_id, &dev_handle, &image_spec);
207 	if (result != 0) {
208 		WARN("Failed to obtain reference to image id=%u (%i)\n",
209 			image_id, result);
210 		return result;
211 	}
212 
213 	result = io_open(dev_handle, image_spec, &image_handle);
214 	if (result != 0) {
215 		WARN("Failed to access image id=%u (%i)\n", image_id, result);
216 		return result;
217 	}
218 
219 	result = load_mbr_header(image_handle, &mbr_entry);
220 	if (result != 0) {
221 		WARN("Failed to access image id=%u (%i)\n", image_id, result);
222 		return result;
223 	}
224 	if (mbr_entry.type == PARTITION_TYPE_GPT) {
225 		result = load_gpt_header(image_handle);
226 		assert(result == 0);
227 		result = io_seek(image_handle, IO_SEEK_SET, GPT_ENTRY_OFFSET);
228 		assert(result == 0);
229 		result = verify_partition_gpt(image_handle);
230 	} else {
231 		result = load_mbr_entries(image_handle);
232 	}
233 
234 	io_close(image_handle);
235 	return result;
236 }
237 
238 const partition_entry_t *get_partition_entry(const char *name)
239 {
240 	int i;
241 
242 	for (i = 0; i < list.entry_count; i++) {
243 		if (strcmp(name, list.list[i].name) == 0) {
244 			return &list.list[i];
245 		}
246 	}
247 	return NULL;
248 }
249 
250 const partition_entry_t *get_partition_entry_by_uuid(const uuid_t *part_uuid)
251 {
252 	int i;
253 
254 	for (i = 0; i < list.entry_count; i++) {
255 		if (guidcmp(part_uuid, &list.list[i].part_guid) == 0) {
256 			return &list.list[i];
257 		}
258 	}
259 
260 	return NULL;
261 }
262 
263 const partition_entry_list_t *get_partition_entry_list(void)
264 {
265 	return &list;
266 }
267 
268 void partition_init(unsigned int image_id)
269 {
270 	load_partition_table(image_id);
271 }
272