blob: 07869acf50789f95c47b51663b05294b69186deb [file] [log] [blame]
Haojian Zhuang91f56462016-07-28 14:19:36 +08001/*
Antonio Nino Diaz6bca8be2018-08-09 15:30:28 +01002 * Copyright (c) 2016-2018, 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 Zhuang91f56462016-07-28 14:19:36 +080018static uint8_t mbr_sector[PARTITION_BLOCK_SIZE];
19partition_entry_list_t list;
20
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,
60 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[PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) ||
68 (mbr_sector[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 partiton numbers could be found, check & update it.
79 */
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
108static int load_gpt_entry(uintptr_t image_handle, gpt_entry_t *entry)
109{
110 size_t bytes_read;
111 int result;
112
113 assert(entry != NULL);
114 result = io_read(image_handle, (uintptr_t)entry, sizeof(gpt_entry_t),
115 &bytes_read);
116 if (sizeof(gpt_entry_t) != bytes_read)
117 return -EINVAL;
118 return result;
119}
120
121static int verify_partition_gpt(uintptr_t image_handle)
122{
123 gpt_entry_t entry;
124 int result, i;
125
126 for (i = 0; i < list.entry_count; i++) {
127 result = load_gpt_entry(image_handle, &entry);
128 assert(result == 0);
129 result = parse_gpt_entry(&entry, &list.list[i]);
130 if (result != 0) {
131 break;
132 }
133 }
134 if (i == 0) {
135 return -EINVAL;
136 }
137 /*
138 * Only records the valid partition number that is loaded from
139 * partition table.
140 */
141 list.entry_count = i;
142 dump_entries(list.entry_count);
143
144 return 0;
145}
146
147int load_partition_table(unsigned int image_id)
148{
149 uintptr_t dev_handle, image_handle, image_spec = 0;
150 mbr_entry_t mbr_entry;
151 int result;
152
153 result = plat_get_image_source(image_id, &dev_handle, &image_spec);
154 if (result != 0) {
155 WARN("Failed to obtain reference to image id=%u (%i)\n",
156 image_id, result);
157 return result;
158 }
159
160 result = io_open(dev_handle, image_spec, &image_handle);
161 if (result != 0) {
162 WARN("Failed to access image id=%u (%i)\n", image_id, result);
163 return result;
164 }
165
166 result = load_mbr_header(image_handle, &mbr_entry);
167 if (result != 0) {
168 WARN("Failed to access image id=%u (%i)\n", image_id, result);
169 return result;
170 }
171 if (mbr_entry.type == PARTITION_TYPE_GPT) {
172 result = load_gpt_header(image_handle);
173 assert(result == 0);
174 result = io_seek(image_handle, IO_SEEK_SET, GPT_ENTRY_OFFSET);
175 assert(result == 0);
176 result = verify_partition_gpt(image_handle);
177 } else {
178 /* MBR type isn't supported yet. */
179 result = -EINVAL;
180 goto exit;
181 }
182exit:
183 io_close(image_handle);
184 return result;
185}
186
187const partition_entry_t *get_partition_entry(const char *name)
188{
189 int i;
190
191 for (i = 0; i < list.entry_count; i++) {
192 if (strcmp(name, list.list[i].name) == 0) {
193 return &list.list[i];
194 }
195 }
196 return NULL;
197}
198
199const partition_entry_list_t *get_partition_entry_list(void)
200{
201 return &list;
202}
203
204void partition_init(unsigned int image_id)
205{
206 load_partition_table(image_id);
207}