blob: d6fb4b8e4e7d6f46008d1277f5a5fd16a56f397b [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>
8#include <debug.h>
Haojian Zhuang91f56462016-07-28 14:19:36 +08009#include <gpt.h>
Isla Mitchell99305012017-07-11 14:54:08 +010010#include <io_storage.h>
Haojian Zhuang91f56462016-07-28 14:19:36 +080011#include <mbr.h>
12#include <partition.h>
13#include <platform.h>
Antonio Nino Diaz00086e32018-08-16 16:46:06 +010014#include <stdio.h>
Haojian Zhuang91f56462016-07-28 14:19:36 +080015#include <string.h>
16
17static uint8_t mbr_sector[PARTITION_BLOCK_SIZE];
18partition_entry_list_t list;
19
20#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
21static void dump_entries(int num)
22{
23 char name[EFI_NAMELEN];
24 int i, j, len;
25
26 VERBOSE("Partition table with %d entries:\n", num);
27 for (i = 0; i < num; i++) {
Antonio Nino Diaz00086e32018-08-16 16:46:06 +010028 len = snprintf(name, EFI_NAMELEN, "%s", list.list[i].name);
Haojian Zhuang91f56462016-07-28 14:19:36 +080029 for (j = 0; j < EFI_NAMELEN - len - 1; j++) {
30 name[len + j] = ' ';
31 }
32 name[EFI_NAMELEN - 1] = '\0';
33 VERBOSE("%d: %s %lx-%lx\n", i + 1, name, list.list[i].start,
34 list.list[i].start + list.list[i].length - 4);
35 }
36}
37#else
38#define dump_entries(num) ((void)num)
39#endif
40
41/*
42 * Load the first sector that carries MBR header.
43 * The MBR boot signature should be always valid whether it's MBR or GPT.
44 */
45static int load_mbr_header(uintptr_t image_handle, mbr_entry_t *mbr_entry)
46{
47 size_t bytes_read;
48 uintptr_t offset;
49 int result;
50
51 assert(mbr_entry != NULL);
52 /* MBR partition table is in LBA0. */
53 result = io_seek(image_handle, IO_SEEK_SET, MBR_OFFSET);
54 if (result != 0) {
55 WARN("Failed to seek (%i)\n", result);
56 return result;
57 }
58 result = io_read(image_handle, (uintptr_t)&mbr_sector,
59 PARTITION_BLOCK_SIZE, &bytes_read);
60 if (result != 0) {
61 WARN("Failed to read data (%i)\n", result);
62 return result;
63 }
64
65 /* Check MBR boot signature. */
66 if ((mbr_sector[PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) ||
67 (mbr_sector[PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) {
68 return -ENOENT;
69 }
70 offset = (uintptr_t)&mbr_sector + MBR_PRIMARY_ENTRY_OFFSET;
71 memcpy(mbr_entry, (void *)offset, sizeof(mbr_entry_t));
72 return 0;
73}
74
75/*
76 * Load GPT header and check the GPT signature.
77 * If partiton numbers could be found, check & update it.
78 */
79static int load_gpt_header(uintptr_t image_handle)
80{
81 gpt_header_t header;
82 size_t bytes_read;
83 int result;
84
85 result = io_seek(image_handle, IO_SEEK_SET, GPT_HEADER_OFFSET);
86 if (result != 0) {
87 return result;
88 }
89 result = io_read(image_handle, (uintptr_t)&header,
90 sizeof(gpt_header_t), &bytes_read);
91 if ((result != 0) || (sizeof(gpt_header_t) != bytes_read)) {
92 return result;
93 }
94 if (memcmp(header.signature, GPT_SIGNATURE,
95 sizeof(header.signature)) != 0) {
96 return -EINVAL;
97 }
98
99 /* partition numbers can't exceed PLAT_PARTITION_MAX_ENTRIES */
100 list.entry_count = header.list_num;
101 if (list.entry_count > PLAT_PARTITION_MAX_ENTRIES) {
102 list.entry_count = PLAT_PARTITION_MAX_ENTRIES;
103 }
104 return 0;
105}
106
107static int load_gpt_entry(uintptr_t image_handle, gpt_entry_t *entry)
108{
109 size_t bytes_read;
110 int result;
111
112 assert(entry != NULL);
113 result = io_read(image_handle, (uintptr_t)entry, sizeof(gpt_entry_t),
114 &bytes_read);
115 if (sizeof(gpt_entry_t) != bytes_read)
116 return -EINVAL;
117 return result;
118}
119
120static int verify_partition_gpt(uintptr_t image_handle)
121{
122 gpt_entry_t entry;
123 int result, i;
124
125 for (i = 0; i < list.entry_count; i++) {
126 result = load_gpt_entry(image_handle, &entry);
127 assert(result == 0);
128 result = parse_gpt_entry(&entry, &list.list[i]);
129 if (result != 0) {
130 break;
131 }
132 }
133 if (i == 0) {
134 return -EINVAL;
135 }
136 /*
137 * Only records the valid partition number that is loaded from
138 * partition table.
139 */
140 list.entry_count = i;
141 dump_entries(list.entry_count);
142
143 return 0;
144}
145
146int load_partition_table(unsigned int image_id)
147{
148 uintptr_t dev_handle, image_handle, image_spec = 0;
149 mbr_entry_t mbr_entry;
150 int result;
151
152 result = plat_get_image_source(image_id, &dev_handle, &image_spec);
153 if (result != 0) {
154 WARN("Failed to obtain reference to image id=%u (%i)\n",
155 image_id, result);
156 return result;
157 }
158
159 result = io_open(dev_handle, image_spec, &image_handle);
160 if (result != 0) {
161 WARN("Failed to access image id=%u (%i)\n", image_id, result);
162 return result;
163 }
164
165 result = load_mbr_header(image_handle, &mbr_entry);
166 if (result != 0) {
167 WARN("Failed to access image id=%u (%i)\n", image_id, result);
168 return result;
169 }
170 if (mbr_entry.type == PARTITION_TYPE_GPT) {
171 result = load_gpt_header(image_handle);
172 assert(result == 0);
173 result = io_seek(image_handle, IO_SEEK_SET, GPT_ENTRY_OFFSET);
174 assert(result == 0);
175 result = verify_partition_gpt(image_handle);
176 } else {
177 /* MBR type isn't supported yet. */
178 result = -EINVAL;
179 goto exit;
180 }
181exit:
182 io_close(image_handle);
183 return result;
184}
185
186const partition_entry_t *get_partition_entry(const char *name)
187{
188 int i;
189
190 for (i = 0; i < list.entry_count; i++) {
191 if (strcmp(name, list.list[i].name) == 0) {
192 return &list.list[i];
193 }
194 }
195 return NULL;
196}
197
198const partition_entry_list_t *get_partition_entry_list(void)
199{
200 return &list;
201}
202
203void partition_init(unsigned int image_id)
204{
205 load_partition_table(image_id);
206}