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