blob: 7706f88affe8d4d1bb2c02dc723fb1ba92274693 [file] [log] [blame]
Haojian Zhuang91f56462016-07-28 14:19:36 +08001/*
Paul Beesley1fbc97b2019-01-11 18:26:51 +00002 * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
Haojian Zhuang91f56462016-07-28 14:19:36 +08003 *
dp-armfa3cf0b2017-05-03 09:38:09 +01004 * SPDX-License-Identifier: BSD-3-Clause
Haojian Zhuang91f56462016-07-28 14:19:36 +08005 */
6
7#include <assert.h>
Manish Pandey9b384b32021-11-12 12:59:09 +00008#include <inttypes.h>
Antonio Nino Diaz00086e32018-08-16 16:46:06 +01009#include <stdio.h>
Haojian Zhuang91f56462016-07-28 14:19:36 +080010#include <string.h>
11
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000012#include <common/debug.h>
13#include <drivers/io/io_storage.h>
Sughosh Ganu47b642e2021-11-10 13:00:30 +053014#include <drivers/partition/efi.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000015#include <drivers/partition/partition.h>
16#include <drivers/partition/gpt.h>
17#include <drivers/partition/mbr.h>
18#include <plat/common/platform.h>
19
Haojian Zhuang42a746d2019-09-14 18:01:16 +080020static uint8_t mbr_sector[PLAT_PARTITION_BLOCK_SIZE];
Florian La Roche231c2442019-01-27 14:30:12 +010021static partition_entry_list_t list;
Haojian Zhuang91f56462016-07-28 14:19:36 +080022
23#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
24static 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++) {
Antonio Nino Diaz00086e32018-08-16 16:46:06 +010031 len = snprintf(name, EFI_NAMELEN, "%s", list.list[i].name);
Haojian Zhuang91f56462016-07-28 14:19:36 +080032 for (j = 0; j < EFI_NAMELEN - len - 1; j++) {
33 name[len + j] = ' ';
34 }
35 name[EFI_NAMELEN - 1] = '\0';
Manish Pandey9b384b32021-11-12 12:59:09 +000036 VERBOSE("%d: %s %" PRIx64 "-%" PRIx64 "\n", i + 1, name, list.list[i].start,
Haojian Zhuang91f56462016-07-28 14:19:36 +080037 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 */
48static 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,
Haojian Zhuang42a746d2019-09-14 18:01:16 +080062 PLAT_PARTITION_BLOCK_SIZE, &bytes_read);
Haojian Zhuang91f56462016-07-28 14:19:36 +080063 if (result != 0) {
64 WARN("Failed to read data (%i)\n", result);
65 return result;
66 }
67
68 /* Check MBR boot signature. */
Haojian Zhuang42a746d2019-09-14 18:01:16 +080069 if ((mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) ||
70 (mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) {
Haojian Zhuang91f56462016-07-28 14:19:36 +080071 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.
Paul Beesley1fbc97b2019-01-11 18:26:51 +000080 * If partition numbers could be found, check & update it.
Haojian Zhuang91f56462016-07-28 14:19:36 +080081 */
82static 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
Loh Tien Hock8defbae2019-02-11 10:56:28 +0800110static 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,
Haojian Zhuang42a746d2019-09-14 18:01:16 +0800125 PLAT_PARTITION_BLOCK_SIZE, &bytes_read);
Loh Tien Hock8defbae2019-02-11 10:56:28 +0800126 if (result != 0) {
127 WARN("Failed to read data (%i)\n", result);
128 return result;
129 }
130
131 /* Check MBR boot signature. */
Haojian Zhuang42a746d2019-09-14 18:01:16 +0800132 if ((mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) ||
133 (mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) {
Loh Tien Hock8defbae2019-02-11 10:56:28 +0800134 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
144static 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
Haojian Zhuang91f56462016-07-28 14:19:36 +0800161static 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
174static 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
200int 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 {
Loh Tien Hock8defbae2019-02-11 10:56:28 +0800231 result = load_mbr_entries(image_handle);
Haojian Zhuang91f56462016-07-28 14:19:36 +0800232 }
Loh Tien Hock8defbae2019-02-11 10:56:28 +0800233
Haojian Zhuang91f56462016-07-28 14:19:36 +0800234 io_close(image_handle);
235 return result;
236}
237
238const 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
Sughosh Ganu47b642e2021-11-10 13:00:30 +0530250const 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
Haojian Zhuang91f56462016-07-28 14:19:36 +0800263const partition_entry_list_t *get_partition_entry_list(void)
264{
265 return &list;
266}
267
268void partition_init(unsigned int image_id)
269{
270 load_partition_table(image_id);
271}