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