xref: /rk3399_ARM-atf/drivers/partition/partition.c (revision 201b66b7e7a49d7d44f2c31639b87c84e37df0eb)
1*201b66b7SHaojian Zhuang /*
2*201b66b7SHaojian Zhuang  * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
3*201b66b7SHaojian Zhuang  *
4*201b66b7SHaojian Zhuang  * Redistribution and use in source and binary forms, with or without
5*201b66b7SHaojian Zhuang  * modification, are permitted provided that the following conditions are met:
6*201b66b7SHaojian Zhuang  *
7*201b66b7SHaojian Zhuang  * Redistributions of source code must retain the above copyright notice, this
8*201b66b7SHaojian Zhuang  * list of conditions and the following disclaimer.
9*201b66b7SHaojian Zhuang  *
10*201b66b7SHaojian Zhuang  * Redistributions in binary form must reproduce the above copyright notice,
11*201b66b7SHaojian Zhuang  * this list of conditions and the following disclaimer in the documentation
12*201b66b7SHaojian Zhuang  * and/or other materials provided with the distribution.
13*201b66b7SHaojian Zhuang  *
14*201b66b7SHaojian Zhuang  * Neither the name of ARM nor the names of its contributors may be used
15*201b66b7SHaojian Zhuang  * to endorse or promote products derived from this software without specific
16*201b66b7SHaojian Zhuang  * prior written permission.
17*201b66b7SHaojian Zhuang  *
18*201b66b7SHaojian Zhuang  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19*201b66b7SHaojian Zhuang  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20*201b66b7SHaojian Zhuang  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21*201b66b7SHaojian Zhuang  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22*201b66b7SHaojian Zhuang  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23*201b66b7SHaojian Zhuang  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24*201b66b7SHaojian Zhuang  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25*201b66b7SHaojian Zhuang  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26*201b66b7SHaojian Zhuang  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27*201b66b7SHaojian Zhuang  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28*201b66b7SHaojian Zhuang  * POSSIBILITY OF SUCH DAMAGE.
29*201b66b7SHaojian Zhuang  */
30*201b66b7SHaojian Zhuang 
31*201b66b7SHaojian Zhuang #include <assert.h>
32*201b66b7SHaojian Zhuang #include <debug.h>
33*201b66b7SHaojian Zhuang #include <io_storage.h>
34*201b66b7SHaojian Zhuang #include <gpt.h>
35*201b66b7SHaojian Zhuang #include <mbr.h>
36*201b66b7SHaojian Zhuang #include <partition.h>
37*201b66b7SHaojian Zhuang #include <platform.h>
38*201b66b7SHaojian Zhuang #include <string.h>
39*201b66b7SHaojian Zhuang 
40*201b66b7SHaojian Zhuang static uint8_t mbr_sector[PARTITION_BLOCK_SIZE];
41*201b66b7SHaojian Zhuang partition_entry_list_t list;
42*201b66b7SHaojian Zhuang 
43*201b66b7SHaojian Zhuang #if LOG_LEVEL >= LOG_LEVEL_VERBOSE
44*201b66b7SHaojian Zhuang static void dump_entries(int num)
45*201b66b7SHaojian Zhuang {
46*201b66b7SHaojian Zhuang 	char name[EFI_NAMELEN];
47*201b66b7SHaojian Zhuang 	int i, j, len;
48*201b66b7SHaojian Zhuang 
49*201b66b7SHaojian Zhuang 	VERBOSE("Partition table with %d entries:\n", num);
50*201b66b7SHaojian Zhuang 	for (i = 0; i < num; i++) {
51*201b66b7SHaojian Zhuang 		len = snprintf(name, EFI_NAMELEN, "%s", list.list[i].name);
52*201b66b7SHaojian Zhuang 		for (j = 0; j < EFI_NAMELEN - len - 1; j++) {
53*201b66b7SHaojian Zhuang 			name[len + j] = ' ';
54*201b66b7SHaojian Zhuang 		}
55*201b66b7SHaojian Zhuang 		name[EFI_NAMELEN - 1] = '\0';
56*201b66b7SHaojian Zhuang 		VERBOSE("%d: %s %lx-%lx\n", i + 1, name, list.list[i].start,
57*201b66b7SHaojian Zhuang 			list.list[i].start + list.list[i].length - 4);
58*201b66b7SHaojian Zhuang 	}
59*201b66b7SHaojian Zhuang }
60*201b66b7SHaojian Zhuang #else
61*201b66b7SHaojian Zhuang #define dump_entries(num)	((void)num)
62*201b66b7SHaojian Zhuang #endif
63*201b66b7SHaojian Zhuang 
64*201b66b7SHaojian Zhuang /*
65*201b66b7SHaojian Zhuang  * Load the first sector that carries MBR header.
66*201b66b7SHaojian Zhuang  * The MBR boot signature should be always valid whether it's MBR or GPT.
67*201b66b7SHaojian Zhuang  */
68*201b66b7SHaojian Zhuang static int load_mbr_header(uintptr_t image_handle, mbr_entry_t *mbr_entry)
69*201b66b7SHaojian Zhuang {
70*201b66b7SHaojian Zhuang 	size_t bytes_read;
71*201b66b7SHaojian Zhuang 	uintptr_t offset;
72*201b66b7SHaojian Zhuang 	int result;
73*201b66b7SHaojian Zhuang 
74*201b66b7SHaojian Zhuang 	assert(mbr_entry != NULL);
75*201b66b7SHaojian Zhuang 	/* MBR partition table is in LBA0. */
76*201b66b7SHaojian Zhuang 	result = io_seek(image_handle, IO_SEEK_SET, MBR_OFFSET);
77*201b66b7SHaojian Zhuang 	if (result != 0) {
78*201b66b7SHaojian Zhuang 		WARN("Failed to seek (%i)\n", result);
79*201b66b7SHaojian Zhuang 		return result;
80*201b66b7SHaojian Zhuang 	}
81*201b66b7SHaojian Zhuang 	result = io_read(image_handle, (uintptr_t)&mbr_sector,
82*201b66b7SHaojian Zhuang 			 PARTITION_BLOCK_SIZE, &bytes_read);
83*201b66b7SHaojian Zhuang 	if (result != 0) {
84*201b66b7SHaojian Zhuang 		WARN("Failed to read data (%i)\n", result);
85*201b66b7SHaojian Zhuang 		return result;
86*201b66b7SHaojian Zhuang 	}
87*201b66b7SHaojian Zhuang 
88*201b66b7SHaojian Zhuang 	/* Check MBR boot signature. */
89*201b66b7SHaojian Zhuang 	if ((mbr_sector[PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) ||
90*201b66b7SHaojian Zhuang 	    (mbr_sector[PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) {
91*201b66b7SHaojian Zhuang 		return -ENOENT;
92*201b66b7SHaojian Zhuang 	}
93*201b66b7SHaojian Zhuang 	offset = (uintptr_t)&mbr_sector + MBR_PRIMARY_ENTRY_OFFSET;
94*201b66b7SHaojian Zhuang 	memcpy(mbr_entry, (void *)offset, sizeof(mbr_entry_t));
95*201b66b7SHaojian Zhuang 	return 0;
96*201b66b7SHaojian Zhuang }
97*201b66b7SHaojian Zhuang 
98*201b66b7SHaojian Zhuang /*
99*201b66b7SHaojian Zhuang  * Load GPT header and check the GPT signature.
100*201b66b7SHaojian Zhuang  * If partiton numbers could be found, check & update it.
101*201b66b7SHaojian Zhuang  */
102*201b66b7SHaojian Zhuang static int load_gpt_header(uintptr_t image_handle)
103*201b66b7SHaojian Zhuang {
104*201b66b7SHaojian Zhuang 	gpt_header_t header;
105*201b66b7SHaojian Zhuang 	size_t bytes_read;
106*201b66b7SHaojian Zhuang 	int result;
107*201b66b7SHaojian Zhuang 
108*201b66b7SHaojian Zhuang 	result = io_seek(image_handle, IO_SEEK_SET, GPT_HEADER_OFFSET);
109*201b66b7SHaojian Zhuang 	if (result != 0) {
110*201b66b7SHaojian Zhuang 		return result;
111*201b66b7SHaojian Zhuang 	}
112*201b66b7SHaojian Zhuang 	result = io_read(image_handle, (uintptr_t)&header,
113*201b66b7SHaojian Zhuang 			 sizeof(gpt_header_t), &bytes_read);
114*201b66b7SHaojian Zhuang 	if ((result != 0) || (sizeof(gpt_header_t) != bytes_read)) {
115*201b66b7SHaojian Zhuang 		return result;
116*201b66b7SHaojian Zhuang 	}
117*201b66b7SHaojian Zhuang 	if (memcmp(header.signature, GPT_SIGNATURE,
118*201b66b7SHaojian Zhuang 		   sizeof(header.signature)) != 0) {
119*201b66b7SHaojian Zhuang 		return -EINVAL;
120*201b66b7SHaojian Zhuang 	}
121*201b66b7SHaojian Zhuang 
122*201b66b7SHaojian Zhuang 	/* partition numbers can't exceed PLAT_PARTITION_MAX_ENTRIES */
123*201b66b7SHaojian Zhuang 	list.entry_count = header.list_num;
124*201b66b7SHaojian Zhuang 	if (list.entry_count > PLAT_PARTITION_MAX_ENTRIES) {
125*201b66b7SHaojian Zhuang 		list.entry_count = PLAT_PARTITION_MAX_ENTRIES;
126*201b66b7SHaojian Zhuang 	}
127*201b66b7SHaojian Zhuang 	return 0;
128*201b66b7SHaojian Zhuang }
129*201b66b7SHaojian Zhuang 
130*201b66b7SHaojian Zhuang static int load_gpt_entry(uintptr_t image_handle, gpt_entry_t *entry)
131*201b66b7SHaojian Zhuang {
132*201b66b7SHaojian Zhuang 	size_t bytes_read;
133*201b66b7SHaojian Zhuang 	int result;
134*201b66b7SHaojian Zhuang 
135*201b66b7SHaojian Zhuang 	assert(entry != NULL);
136*201b66b7SHaojian Zhuang 	result = io_read(image_handle, (uintptr_t)entry, sizeof(gpt_entry_t),
137*201b66b7SHaojian Zhuang 			 &bytes_read);
138*201b66b7SHaojian Zhuang 	if (sizeof(gpt_entry_t) != bytes_read)
139*201b66b7SHaojian Zhuang 		return -EINVAL;
140*201b66b7SHaojian Zhuang 	return result;
141*201b66b7SHaojian Zhuang }
142*201b66b7SHaojian Zhuang 
143*201b66b7SHaojian Zhuang static int verify_partition_gpt(uintptr_t image_handle)
144*201b66b7SHaojian Zhuang {
145*201b66b7SHaojian Zhuang 	gpt_entry_t entry;
146*201b66b7SHaojian Zhuang 	int result, i;
147*201b66b7SHaojian Zhuang 
148*201b66b7SHaojian Zhuang 	for (i = 0; i < list.entry_count; i++) {
149*201b66b7SHaojian Zhuang 		result = load_gpt_entry(image_handle, &entry);
150*201b66b7SHaojian Zhuang 		assert(result == 0);
151*201b66b7SHaojian Zhuang 		result = parse_gpt_entry(&entry, &list.list[i]);
152*201b66b7SHaojian Zhuang 		if (result != 0) {
153*201b66b7SHaojian Zhuang 			break;
154*201b66b7SHaojian Zhuang 		}
155*201b66b7SHaojian Zhuang 	}
156*201b66b7SHaojian Zhuang 	if (i == 0) {
157*201b66b7SHaojian Zhuang 		return -EINVAL;
158*201b66b7SHaojian Zhuang 	}
159*201b66b7SHaojian Zhuang 	/*
160*201b66b7SHaojian Zhuang 	 * Only records the valid partition number that is loaded from
161*201b66b7SHaojian Zhuang 	 * partition table.
162*201b66b7SHaojian Zhuang 	 */
163*201b66b7SHaojian Zhuang 	list.entry_count = i;
164*201b66b7SHaojian Zhuang 	dump_entries(list.entry_count);
165*201b66b7SHaojian Zhuang 
166*201b66b7SHaojian Zhuang 	return 0;
167*201b66b7SHaojian Zhuang }
168*201b66b7SHaojian Zhuang 
169*201b66b7SHaojian Zhuang int load_partition_table(unsigned int image_id)
170*201b66b7SHaojian Zhuang {
171*201b66b7SHaojian Zhuang 	uintptr_t dev_handle, image_handle, image_spec = 0;
172*201b66b7SHaojian Zhuang 	mbr_entry_t mbr_entry;
173*201b66b7SHaojian Zhuang 	int result;
174*201b66b7SHaojian Zhuang 
175*201b66b7SHaojian Zhuang 	result = plat_get_image_source(image_id, &dev_handle, &image_spec);
176*201b66b7SHaojian Zhuang 	if (result != 0) {
177*201b66b7SHaojian Zhuang 		WARN("Failed to obtain reference to image id=%u (%i)\n",
178*201b66b7SHaojian Zhuang 			image_id, result);
179*201b66b7SHaojian Zhuang 		return result;
180*201b66b7SHaojian Zhuang 	}
181*201b66b7SHaojian Zhuang 
182*201b66b7SHaojian Zhuang 	result = io_open(dev_handle, image_spec, &image_handle);
183*201b66b7SHaojian Zhuang 	if (result != 0) {
184*201b66b7SHaojian Zhuang 		WARN("Failed to access image id=%u (%i)\n", image_id, result);
185*201b66b7SHaojian Zhuang 		return result;
186*201b66b7SHaojian Zhuang 	}
187*201b66b7SHaojian Zhuang 
188*201b66b7SHaojian Zhuang 	result = load_mbr_header(image_handle, &mbr_entry);
189*201b66b7SHaojian Zhuang 	if (result != 0) {
190*201b66b7SHaojian Zhuang 		WARN("Failed to access image id=%u (%i)\n", image_id, result);
191*201b66b7SHaojian Zhuang 		return result;
192*201b66b7SHaojian Zhuang 	}
193*201b66b7SHaojian Zhuang 	if (mbr_entry.type == PARTITION_TYPE_GPT) {
194*201b66b7SHaojian Zhuang 		result = load_gpt_header(image_handle);
195*201b66b7SHaojian Zhuang 		assert(result == 0);
196*201b66b7SHaojian Zhuang 		result = io_seek(image_handle, IO_SEEK_SET, GPT_ENTRY_OFFSET);
197*201b66b7SHaojian Zhuang 		assert(result == 0);
198*201b66b7SHaojian Zhuang 		result = verify_partition_gpt(image_handle);
199*201b66b7SHaojian Zhuang 	} else {
200*201b66b7SHaojian Zhuang 		/* MBR type isn't supported yet. */
201*201b66b7SHaojian Zhuang 		result = -EINVAL;
202*201b66b7SHaojian Zhuang 		goto exit;
203*201b66b7SHaojian Zhuang 	}
204*201b66b7SHaojian Zhuang exit:
205*201b66b7SHaojian Zhuang 	io_close(image_handle);
206*201b66b7SHaojian Zhuang 	return result;
207*201b66b7SHaojian Zhuang }
208*201b66b7SHaojian Zhuang 
209*201b66b7SHaojian Zhuang const partition_entry_t *get_partition_entry(const char *name)
210*201b66b7SHaojian Zhuang {
211*201b66b7SHaojian Zhuang 	int i;
212*201b66b7SHaojian Zhuang 
213*201b66b7SHaojian Zhuang 	for (i = 0; i < list.entry_count; i++) {
214*201b66b7SHaojian Zhuang 		if (strcmp(name, list.list[i].name) == 0) {
215*201b66b7SHaojian Zhuang 			return &list.list[i];
216*201b66b7SHaojian Zhuang 		}
217*201b66b7SHaojian Zhuang 	}
218*201b66b7SHaojian Zhuang 	return NULL;
219*201b66b7SHaojian Zhuang }
220*201b66b7SHaojian Zhuang 
221*201b66b7SHaojian Zhuang const partition_entry_list_t *get_partition_entry_list(void)
222*201b66b7SHaojian Zhuang {
223*201b66b7SHaojian Zhuang 	return &list;
224*201b66b7SHaojian Zhuang }
225*201b66b7SHaojian Zhuang 
226*201b66b7SHaojian Zhuang void partition_init(unsigned int image_id)
227*201b66b7SHaojian Zhuang {
228*201b66b7SHaojian Zhuang 	load_partition_table(image_id);
229*201b66b7SHaojian Zhuang }
230