2 * Copyright (C) 2015 IBM Corporation
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
20 #include <asm/byteorder.h>
23 #include <talloc/talloc.h>
24 #include <flash/flash.h>
25 #include <ccan/endian/endian.h>
27 #include <libflash/arch_flash.h>
28 #include <libflash/blocklevel.h>
29 #include <libflash/libflash.h>
30 #include <libflash/libffs.h>
31 #include <libflash/file.h>
32 #include <libflash/ecc.h>
34 #define SECURE_BOOT_HEADERS_SIZE 4096
35 #define ROM_MAGIC_NUMBER 0x17082011
38 /* Device information */
39 struct blocklevel_device *bl;
40 struct ffs_handle *ffs;
41 uint64_t size; /* raw size of partition */
44 uint32_t erase_granule;
46 /* Partition information */
47 uint32_t attr_part_idx;
48 uint32_t attr_data_pos;
49 uint32_t attr_data_len; /* Includes ECC bytes */
51 /* 'Other Side' info if present */
52 struct flash_info *other_side;
56 static int partition_info(struct flash_info *info, const char *partition)
60 rc = ffs_lookup_part(info->ffs, partition, &info->attr_part_idx);
62 pb_log("Failed to find %s partition\n", partition);
66 return ffs_part_info(info->ffs, info->attr_part_idx, NULL,
67 &info->attr_data_pos, &info->attr_data_len,
71 static struct flash_info *flash_setup_buffer(void *ctx, const char *partition)
73 struct flash_info *info;
74 struct ffs_handle *tmp = NULL;
80 info = talloc_zero(ctx, struct flash_info);
84 rc = arch_flash_init(&info->bl, NULL, true);
86 pb_log("Failed to init mtd device\n");
90 rc = blocklevel_get_info(info->bl, &info->path, &info->size,
91 &info->erase_granule);
93 pb_log("Failed to retrieve blocklevel info\n");
97 rc = ffs_init(0, info->size, info->bl, &info->ffs, 1);
99 pb_log("%s: Failed to init ffs\n", __func__);
103 rc = partition_info(info, partition);
105 pb_log("Failed to retrieve partition info\n");
109 /* Check if there is a second flash side. If there is not, or
110 * we fail to recognise it, ignore it and continue */
111 ffs_next_side(info->ffs, &tmp, info->ecc);
112 if (tmp && ffs_equal(info->ffs, tmp) == false) {
113 pb_debug("Other side present on MTD device\n");
114 info->other_side = talloc_zero(info, struct flash_info);
115 info->other_side->ffs = tmp;
116 info->other_side->bl = info->bl;
117 info->other_side->size = info->size;
118 info->other_side->path = info->path;
119 info->other_side->ecc = info->ecc;
120 info->other_side->erase_granule = info->erase_granule;
121 rc = partition_info(info->other_side, partition);
123 pb_log("Failed to retrieve partition info "
124 "for other side - ignoring\n");
127 pb_debug("%s Details\n", partition);
128 pb_debug("\tName\t\t%s\n", info->path);
129 pb_debug("\tFlash Size\t%lu\n", info->size);
130 pb_debug("\tGranule\t\t%u\n", info->erase_granule);
131 pb_debug("\tECC\t\t%s\n", info->ecc ? "Protected" : "Unprotected");
132 pb_debug("\tCurrent Side info:\n");
133 pb_debug("\tIndex\t\t%u\n", info->attr_part_idx);
134 pb_debug("\tOffset\t\t%u\n", info->attr_data_pos);
135 pb_debug("\tPart. Size\t%u\n", info->attr_data_len);
136 if (info->other_side) {
137 pb_debug("\tOther Side info:\n");
138 pb_debug("\tIndex\t\t%u\n", info->other_side->attr_part_idx);
139 pb_debug("\tOffset\t\t%u\n", info->other_side->attr_data_pos);
140 pb_debug("\tPart. Size\t%u\n", info->other_side->attr_data_len);
145 ffs_close(info->ffs);
147 arch_flash_close(info->bl, NULL);
153 /* See stb_is_container() in Skiboot */
154 static bool is_signed(char *buffer, uint32_t len)
156 if (!buffer || len <= SECURE_BOOT_HEADERS_SIZE)
158 if (be32_to_cpu(*(uint32_t *)buffer) != ROM_MAGIC_NUMBER)
163 int flash_parse_version(void *ctx, char ***versions, bool current)
165 char *saveptr, *tok, **tmp, *buffer;
166 const char *delim = "\n";
167 struct flash_info *info, *cur_info;
171 saveptr = tok = NULL;
174 info = flash_setup_buffer(ctx, "VERSION");
178 if (!current && !info->other_side)
181 cur_info = !current ? info->other_side : info;
183 len = cur_info->attr_data_len - ecc_size(cur_info->attr_data_len);
184 buffer = talloc_array(cur_info, char, len);
186 pb_log("%s: Failed to init buffer!\n", __func__);
190 rc = blocklevel_read(cur_info->bl, cur_info->attr_data_pos,
193 pb_log("Failed to read VERSION partition\n");
197 /* Check if this partition is signed */
198 if (is_signed(buffer, len))
199 buffer += SECURE_BOOT_HEADERS_SIZE;
201 /* open-power-platform */
202 tok = strtok_r(buffer, delim, &saveptr);
204 tmp = talloc_realloc(ctx, tmp, char *, n + 1);
206 pb_log("%s: Failed to allocate memory\n", __func__);
209 tmp[n++] = talloc_strdup(ctx, tok);
212 tok = strtok_r(NULL, delim, &saveptr);
214 /* Ignore leading tab from subsequent lines */
215 tmp = talloc_realloc(ctx, tmp, char *, n + 1);
217 pb_log("%s: Failed to reallocate memory\n", __func__);
221 tmp[n++] = talloc_strdup(ctx, tok + 1);
222 tok = strtok_r(NULL, delim, &saveptr);
226 pb_debug("%d version strings read from %s side\n",
227 n, current ? "current" : "other");
228 arch_flash_close(info->bl, NULL);