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