blob: 68133eaf4f1b7951c33e11b4c23ebfdc79598ec0 [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>
Antonio Nino Diaz00086e32018-08-16 16:46:06 +01008#include <stdio.h>
Haojian Zhuang91f56462016-07-28 14:19:36 +08009#include <string.h>
10
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000011#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
Haojian Zhuang42a746d2019-09-14 18:01:16 +080018static uint8_t mbr_sector[PLAT_PARTITION_BLOCK_SIZE];
Florian La Roche231c2442019-01-27 14:30:12 +010019static partition_entry_list_t list;
Haojian Zhuang91f56462016-07-28 14:19:36 +080020
21#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
22static 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++) {
Antonio Nino Diaz00086e32018-08-16 16:46:06 +010029 len = snprintf(name, EFI_NAMELEN, "%s", list.list[i].name);
Haojian Zhuang91f56462016-07-28 14:19:36 +080030 for (j = 0; j < EFI_NAMELEN - len - 1; j++) {
31 name[len + j] = ' ';
32 }
33 name[EFI_NAMELEN - 1] = '\0';
Yann Gautierb74e90d2018-10-04 19:04:17 +020034 VERBOSE("%d: %s %llx-%llx\n", i + 1, name, list.list[i].start,
Haojian Zhuang91f56462016-07-28 14:19:36 +080035 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 */
46static 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,
Haojian Zhuang42a746d2019-09-14 18:01:16 +080060 PLAT_PARTITION_BLOCK_SIZE, &bytes_read);
Haojian Zhuang91f56462016-07-28 14:19:36 +080061 if (result != 0) {
62 WARN("Failed to read data (%i)\n", result);
63 return result;
64 }
65
66 /* Check MBR boot signature. */
Haojian Zhuang42a746d2019-09-14 18:01:16 +080067 if ((mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) ||
68 (mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) {
Haojian Zhuang91f56462016-07-28 14:19:36 +080069 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.
Paul Beesley1fbc97b2019-01-11 18:26:51 +000078 * If partition numbers could be found, check & update it.
Haojian Zhuang91f56462016-07-28 14:19:36 +080079 */
80static 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
Loh Tien Hock8defbae2019-02-11 10:56:28 +0800108static 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,
Haojian Zhuang42a746d2019-09-14 18:01:16 +0800123 PLAT_PARTITION_BLOCK_SIZE, &bytes_read);
Loh Tien Hock8defbae2019-02-11 10:56:28 +0800124 if (result != 0) {
125 WARN("Failed to read data (%i)\n", result);
126 return result;
127 }
128
129 /* Check MBR boot signature. */
Haojian Zhuang42a746d2019-09-14 18:01:16 +0800130 if ((mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) ||
131 (mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) {
Loh Tien Hock8defbae2019-02-11 10:56:28 +0800132 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
142static 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
Haojian Zhuang91f56462016-07-28 14:19:36 +0800159static 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
172static 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
198int 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 {
Loh Tien Hock8defbae2019-02-11 10:56:28 +0800229 result = load_mbr_entries(image_handle);
Haojian Zhuang91f56462016-07-28 14:19:36 +0800230 }
Loh Tien Hock8defbae2019-02-11 10:56:28 +0800231
Haojian Zhuang91f56462016-07-28 14:19:36 +0800232 io_close(image_handle);
233 return result;
234}
235
236const 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
248const partition_entry_list_t *get_partition_entry_list(void)
249{
250 return &list;
251}
252
253void partition_init(unsigned int image_id)
254{
255 load_partition_table(image_id);
256}