blob: 8bf6848dfe48134516c3980228c42799bb715cab [file] [log] [blame]
Haojian Zhuang91f56462016-07-28 14:19:36 +08001/*
2 * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
9 *
10 * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * Neither the name of ARM nor the names of its contributors may be used
15 * to endorse or promote products derived from this software without specific
16 * prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <assert.h>
32#include <debug.h>
33#include <io_storage.h>
34#include <gpt.h>
35#include <mbr.h>
36#include <partition.h>
37#include <platform.h>
38#include <string.h>
39
40static uint8_t mbr_sector[PARTITION_BLOCK_SIZE];
41partition_entry_list_t list;
42
43#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
44static void dump_entries(int num)
45{
46 char name[EFI_NAMELEN];
47 int i, j, len;
48
49 VERBOSE("Partition table with %d entries:\n", num);
50 for (i = 0; i < num; i++) {
51 len = snprintf(name, EFI_NAMELEN, "%s", list.list[i].name);
52 for (j = 0; j < EFI_NAMELEN - len - 1; j++) {
53 name[len + j] = ' ';
54 }
55 name[EFI_NAMELEN - 1] = '\0';
56 VERBOSE("%d: %s %lx-%lx\n", i + 1, name, list.list[i].start,
57 list.list[i].start + list.list[i].length - 4);
58 }
59}
60#else
61#define dump_entries(num) ((void)num)
62#endif
63
64/*
65 * Load the first sector that carries MBR header.
66 * The MBR boot signature should be always valid whether it's MBR or GPT.
67 */
68static int load_mbr_header(uintptr_t image_handle, mbr_entry_t *mbr_entry)
69{
70 size_t bytes_read;
71 uintptr_t offset;
72 int result;
73
74 assert(mbr_entry != NULL);
75 /* MBR partition table is in LBA0. */
76 result = io_seek(image_handle, IO_SEEK_SET, MBR_OFFSET);
77 if (result != 0) {
78 WARN("Failed to seek (%i)\n", result);
79 return result;
80 }
81 result = io_read(image_handle, (uintptr_t)&mbr_sector,
82 PARTITION_BLOCK_SIZE, &bytes_read);
83 if (result != 0) {
84 WARN("Failed to read data (%i)\n", result);
85 return result;
86 }
87
88 /* Check MBR boot signature. */
89 if ((mbr_sector[PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) ||
90 (mbr_sector[PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) {
91 return -ENOENT;
92 }
93 offset = (uintptr_t)&mbr_sector + MBR_PRIMARY_ENTRY_OFFSET;
94 memcpy(mbr_entry, (void *)offset, sizeof(mbr_entry_t));
95 return 0;
96}
97
98/*
99 * Load GPT header and check the GPT signature.
100 * If partiton numbers could be found, check & update it.
101 */
102static int load_gpt_header(uintptr_t image_handle)
103{
104 gpt_header_t header;
105 size_t bytes_read;
106 int result;
107
108 result = io_seek(image_handle, IO_SEEK_SET, GPT_HEADER_OFFSET);
109 if (result != 0) {
110 return result;
111 }
112 result = io_read(image_handle, (uintptr_t)&header,
113 sizeof(gpt_header_t), &bytes_read);
114 if ((result != 0) || (sizeof(gpt_header_t) != bytes_read)) {
115 return result;
116 }
117 if (memcmp(header.signature, GPT_SIGNATURE,
118 sizeof(header.signature)) != 0) {
119 return -EINVAL;
120 }
121
122 /* partition numbers can't exceed PLAT_PARTITION_MAX_ENTRIES */
123 list.entry_count = header.list_num;
124 if (list.entry_count > PLAT_PARTITION_MAX_ENTRIES) {
125 list.entry_count = PLAT_PARTITION_MAX_ENTRIES;
126 }
127 return 0;
128}
129
130static int load_gpt_entry(uintptr_t image_handle, gpt_entry_t *entry)
131{
132 size_t bytes_read;
133 int result;
134
135 assert(entry != NULL);
136 result = io_read(image_handle, (uintptr_t)entry, sizeof(gpt_entry_t),
137 &bytes_read);
138 if (sizeof(gpt_entry_t) != bytes_read)
139 return -EINVAL;
140 return result;
141}
142
143static int verify_partition_gpt(uintptr_t image_handle)
144{
145 gpt_entry_t entry;
146 int result, i;
147
148 for (i = 0; i < list.entry_count; i++) {
149 result = load_gpt_entry(image_handle, &entry);
150 assert(result == 0);
151 result = parse_gpt_entry(&entry, &list.list[i]);
152 if (result != 0) {
153 break;
154 }
155 }
156 if (i == 0) {
157 return -EINVAL;
158 }
159 /*
160 * Only records the valid partition number that is loaded from
161 * partition table.
162 */
163 list.entry_count = i;
164 dump_entries(list.entry_count);
165
166 return 0;
167}
168
169int load_partition_table(unsigned int image_id)
170{
171 uintptr_t dev_handle, image_handle, image_spec = 0;
172 mbr_entry_t mbr_entry;
173 int result;
174
175 result = plat_get_image_source(image_id, &dev_handle, &image_spec);
176 if (result != 0) {
177 WARN("Failed to obtain reference to image id=%u (%i)\n",
178 image_id, result);
179 return result;
180 }
181
182 result = io_open(dev_handle, image_spec, &image_handle);
183 if (result != 0) {
184 WARN("Failed to access image id=%u (%i)\n", image_id, result);
185 return result;
186 }
187
188 result = load_mbr_header(image_handle, &mbr_entry);
189 if (result != 0) {
190 WARN("Failed to access image id=%u (%i)\n", image_id, result);
191 return result;
192 }
193 if (mbr_entry.type == PARTITION_TYPE_GPT) {
194 result = load_gpt_header(image_handle);
195 assert(result == 0);
196 result = io_seek(image_handle, IO_SEEK_SET, GPT_ENTRY_OFFSET);
197 assert(result == 0);
198 result = verify_partition_gpt(image_handle);
199 } else {
200 /* MBR type isn't supported yet. */
201 result = -EINVAL;
202 goto exit;
203 }
204exit:
205 io_close(image_handle);
206 return result;
207}
208
209const partition_entry_t *get_partition_entry(const char *name)
210{
211 int i;
212
213 for (i = 0; i < list.entry_count; i++) {
214 if (strcmp(name, list.list[i].name) == 0) {
215 return &list.list[i];
216 }
217 }
218 return NULL;
219}
220
221const partition_entry_list_t *get_partition_entry_list(void)
222{
223 return &list;
224}
225
226void partition_init(unsigned int image_id)
227{
228 load_partition_table(image_id);
229}