blob: f7f68b380d9efd0c95f1077ca69678cf0e9f7025 [file] [log] [blame]
Uwe Hermann75f51072008-03-04 16:29:54 +00001/*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2005-2008 coresystems GmbH
5 * (Written by Stefan Reinauer <stepan@coresystems.de> for coresystems GmbH)
Stefan Tauner949ccc82013-09-15 14:01:06 +00006 * Copyright (C) 2011-2013 Stefan Tauner
Uwe Hermann75f51072008-03-04 16:29:54 +00007 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2 of the License.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
Uwe Hermann75f51072008-03-04 16:29:54 +000016 */
17
Nico Huber70461a92019-06-15 14:56:19 +020018#include <errno.h>
Carl-Daniel Hailfinger831e8f42010-05-30 22:24:40 +000019#include <stdio.h>
Ollie Lho184a4042005-11-26 21:55:36 +000020#include <stdlib.h>
21#include <string.h>
Carl-Daniel Hailfingercb6ad162010-11-02 03:12:51 +000022#include <limits.h>
Uwe Hermann0846f892007-08-23 13:34:59 +000023#include "flash.h"
Carl-Daniel Hailfinger5b997c32010-07-27 22:41:39 +000024#include "programmer.h"
Nico Huber3a9939b2016-04-27 15:56:14 +020025#include "layout.h"
Ollie Lho184a4042005-11-26 21:55:36 +000026
Jacob Garberafc3ad62019-06-24 16:05:28 -060027static struct romentry entries[MAX_ROMLAYOUT];
Nico Huber3a97fd52019-06-15 15:44:39 +020028static struct flashrom_layout global_layout = { entries, MAX_ROMLAYOUT, 0 };
Stefan Taunerc70bc8a2013-08-30 22:22:57 +000029
Nico Huber305f4172013-06-14 11:55:26 +020030struct flashrom_layout *get_global_layout(void)
Nico Huber3a9939b2016-04-27 15:56:14 +020031{
Nico Huber2b94cdb2019-06-15 18:19:26 +020032 return &global_layout;
Nico Huber3a9939b2016-04-27 15:56:14 +020033}
34
dhendrixbeaefe02017-09-03 18:06:53 -070035const struct flashrom_layout *get_layout(const struct flashrom_flashctx *const flashctx)
36{
37 if (flashctx->layout && flashctx->layout->num_entries)
38 return flashctx->layout;
39 else
Nico Huber5bd990c2019-06-16 19:46:46 +020040 return flashctx->default_layout;
dhendrixbeaefe02017-09-03 18:06:53 -070041}
42
Nico Huber354766b2019-06-16 19:28:35 +020043static struct romentry *mutable_layout_next(
44 const struct flashrom_layout *const layout, struct romentry *iterator)
45{
46 const struct romentry *const end = layout->entries + layout->num_entries;
47
48 if (iterator)
49 ++iterator;
50 else
51 iterator = &layout->entries[0];
52
53 if (iterator < end)
54 return iterator;
55 return NULL;
56}
57
Patrick Georgia9095a92010-09-30 17:03:32 +000058#ifndef __LIBPAYLOAD__
Mark Marshallf20b7be2014-05-09 21:16:21 +000059int read_romlayout(const char *name)
Ollie Lho184a4042005-11-26 21:55:36 +000060{
Nico Huber2b94cdb2019-06-15 18:19:26 +020061 struct flashrom_layout *const layout = get_global_layout();
Ollie Lho184a4042005-11-26 21:55:36 +000062 FILE *romlayout;
Nico Huber70461a92019-06-15 14:56:19 +020063 char tempstr[256], tempname[256];
Nico Huber519be662018-12-23 20:03:35 +010064 int ret = 1;
Ollie Lho184a4042005-11-26 21:55:36 +000065
Uwe Hermanna7e05482007-05-09 10:17:44 +000066 romlayout = fopen(name, "r");
67
68 if (!romlayout) {
Carl-Daniel Hailfinger831e8f42010-05-30 22:24:40 +000069 msg_gerr("ERROR: Could not open ROM layout (%s).\n",
Uwe Hermanna7e05482007-05-09 10:17:44 +000070 name);
Ollie Lho184a4042005-11-26 21:55:36 +000071 return -1;
72 }
Uwe Hermanna7e05482007-05-09 10:17:44 +000073
74 while (!feof(romlayout)) {
Ollie Lho184a4042005-11-26 21:55:36 +000075 char *tstr1, *tstr2;
Carl-Daniel Hailfingerda53ada2010-12-04 11:56:52 +000076
Nico Huber3a97fd52019-06-15 15:44:39 +020077 if (layout->num_entries >= layout->capacity) {
78 msg_gerr("Maximum number of ROM images (%zu) in layout "
79 "file reached.\n", layout->capacity);
Nico Huber70461a92019-06-15 14:56:19 +020080 goto _close_ret;
Carl-Daniel Hailfingerda53ada2010-12-04 11:56:52 +000081 }
Nico Huber70461a92019-06-15 14:56:19 +020082 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr, tempname))
Peter Stuge1fec0f32009-01-12 21:00:35 +000083 continue;
Ollie Lho184a4042005-11-26 21:55:36 +000084#if 0
85 // fscanf does not like arbitrary comments like that :( later
Uwe Hermanna7e05482007-05-09 10:17:44 +000086 if (tempstr[0] == '#') {
Ollie Lho184a4042005-11-26 21:55:36 +000087 continue;
88 }
89#endif
Uwe Hermanna7e05482007-05-09 10:17:44 +000090 tstr1 = strtok(tempstr, ":");
91 tstr2 = strtok(NULL, ":");
Uwe Hermann58783e32008-12-22 16:42:59 +000092 if (!tstr1 || !tstr2) {
Stefan Taunereb582572012-09-21 12:52:50 +000093 msg_gerr("Error parsing layout file. Offending string: \"%s\"\n", tempstr);
Nico Huber70461a92019-06-15 14:56:19 +020094 goto _close_ret;
Uwe Hermann58783e32008-12-22 16:42:59 +000095 }
Nico Huber92e0b622019-06-15 15:55:11 +020096 if (flashrom_layout_add_region(layout,
97 strtol(tstr1, NULL, 16), strtol(tstr2, NULL, 16), tempname))
Nico Huber70461a92019-06-15 14:56:19 +020098 goto _close_ret;
Ollie Lho184a4042005-11-26 21:55:36 +000099 }
Nico Huber70461a92019-06-15 14:56:19 +0200100 ret = 0;
Uwe Hermannffec5f32007-08-23 16:08:21 +0000101
Nico Huber70461a92019-06-15 14:56:19 +0200102_close_ret:
103 (void)fclose(romlayout);
104 return ret;
Ollie Lho184a4042005-11-26 21:55:36 +0000105}
Patrick Georgia9095a92010-09-30 17:03:32 +0000106#endif
Ollie Lho184a4042005-11-26 21:55:36 +0000107
Louis Yung-Chieh Lo9bcf2682011-12-25 09:12:16 +0000108/* register an include argument (-i) for later processing */
Arthur Heymansb04fef92019-02-05 17:35:05 +0100109int register_include_arg(struct layout_include_args **args, char *name)
Louis Yung-Chieh Lo9bcf2682011-12-25 09:12:16 +0000110{
Arthur Heymansb04fef92019-02-05 17:35:05 +0100111 struct layout_include_args *tmp;
Louis Yung-Chieh Lo9bcf2682011-12-25 09:12:16 +0000112 if (name == NULL) {
113 msg_gerr("<NULL> is a bad region name.\n");
114 return 1;
115 }
116
Arthur Heymansb04fef92019-02-05 17:35:05 +0100117 tmp = *args;
118 while (tmp) {
119 if (!strcmp(tmp->name, name)) {
120 msg_gerr("Duplicate region name: \"%s\".\n", name);
121 return 1;
122 }
123 tmp = tmp->next;
124 }
125
Angel Pons690a9442021-06-07 12:33:53 +0200126 tmp = malloc(sizeof(*tmp));
Arthur Heymansb04fef92019-02-05 17:35:05 +0100127 if (tmp == NULL) {
Edward O'Callaghana31a5722022-11-12 12:05:36 +1100128 msg_gerr("Out of memory");
Stefan Tauner23bb6d52012-04-15 14:09:16 +0000129 return 1;
130 }
131
Arthur Heymansb04fef92019-02-05 17:35:05 +0100132 tmp->name = name;
133 tmp->next = *args;
134 *args = tmp;
135
Louis Yung-Chieh Lo9bcf2682011-12-25 09:12:16 +0000136 return 0;
137}
138
Arthur Heymans32b9f5c2019-02-05 16:14:55 +0100139/* returns -1 if an entry is not found, 0 if found. */
Nico Huber305f4172013-06-14 11:55:26 +0200140static int find_romentry(struct flashrom_layout *const l, char *name)
Ollie Lho184a4042005-11-26 21:55:36 +0000141{
Nico Huber305f4172013-06-14 11:55:26 +0200142 if (l->num_entries == 0)
Uwe Hermanna7e05482007-05-09 10:17:44 +0000143 return -1;
Ollie Lho184a4042005-11-26 21:55:36 +0000144
Louis Yung-Chieh Lo9bcf2682011-12-25 09:12:16 +0000145 msg_gspew("Looking for region \"%s\"... ", name);
Arthur Heymans32b9f5c2019-02-05 16:14:55 +0100146 if (flashrom_layout_include_region(l, name)) {
147 msg_gspew("not found.\n");
148 return -1;
Ollie Lho184a4042005-11-26 21:55:36 +0000149 }
Arthur Heymans32b9f5c2019-02-05 16:14:55 +0100150 msg_gspew("found.\n");
151 return 0;
Ollie Lho184a4042005-11-26 21:55:36 +0000152}
153
Louis Yung-Chieh Lo9bcf2682011-12-25 09:12:16 +0000154/* process -i arguments
155 * returns 0 to indicate success, >0 to indicate failure
156 */
Arthur Heymansb04fef92019-02-05 17:35:05 +0100157int process_include_args(struct flashrom_layout *l, const struct layout_include_args *const args)
Louis Yung-Chieh Lo9bcf2682011-12-25 09:12:16 +0000158{
Nico Huber519be662018-12-23 20:03:35 +0100159 unsigned int found = 0;
Arthur Heymansb04fef92019-02-05 17:35:05 +0100160 const struct layout_include_args *tmp;
Louis Yung-Chieh Lo9bcf2682011-12-25 09:12:16 +0000161
Arthur Heymansb04fef92019-02-05 17:35:05 +0100162 if (args == NULL)
Louis Yung-Chieh Lo9bcf2682011-12-25 09:12:16 +0000163 return 0;
164
Stefan Tauner23bb6d52012-04-15 14:09:16 +0000165 /* User has specified an area, but no layout file is loaded. */
Nico Huber305f4172013-06-14 11:55:26 +0200166 if (l->num_entries == 0) {
Stefan Tauner23bb6d52012-04-15 14:09:16 +0000167 msg_gerr("Region requested (with -i \"%s\"), "
168 "but no layout data is available.\n",
Arthur Heymansb04fef92019-02-05 17:35:05 +0100169 args->name);
Stefan Tauner23bb6d52012-04-15 14:09:16 +0000170 return 1;
171 }
Louis Yung-Chieh Lo9bcf2682011-12-25 09:12:16 +0000172
Arthur Heymansb04fef92019-02-05 17:35:05 +0100173 tmp = args;
174 while (tmp) {
175 if (find_romentry(l, tmp->name) < 0) {
Stefan Tauner23bb6d52012-04-15 14:09:16 +0000176 msg_gerr("Invalid region specified: \"%s\".\n",
Arthur Heymansb04fef92019-02-05 17:35:05 +0100177 tmp->name);
Louis Yung-Chieh Lo9bcf2682011-12-25 09:12:16 +0000178 return 1;
179 }
Arthur Heymansb04fef92019-02-05 17:35:05 +0100180 tmp = tmp->next;
181 found++;
Louis Yung-Chieh Lo9bcf2682011-12-25 09:12:16 +0000182 }
183
Arthur Heymansb04fef92019-02-05 17:35:05 +0100184 msg_ginfo("Using region%s:", found > 1 ? "s" : "");
185 tmp = args;
186 while (tmp) {
187 msg_ginfo(" \"%s\"%s", tmp->name, found > 1 ? "," : "");
188 found--;
189 tmp = tmp->next;
190 }
Louis Yung-Chieh Lo9bcf2682011-12-25 09:12:16 +0000191 msg_ginfo(".\n");
192 return 0;
193}
194
Arthur Heymansb04fef92019-02-05 17:35:05 +0100195void layout_cleanup(struct layout_include_args **args)
Stefan Tauner949ccc82013-09-15 14:01:06 +0000196{
Nico Huber2b94cdb2019-06-15 18:19:26 +0200197 struct flashrom_layout *const layout = get_global_layout();
Nico Huber519be662018-12-23 20:03:35 +0100198 unsigned int i;
Arthur Heymansb04fef92019-02-05 17:35:05 +0100199 struct layout_include_args *tmp;
200
201 while (*args) {
202 tmp = (*args)->next;
203 free(*args);
204 *args = tmp;
Stefan Tauner949ccc82013-09-15 14:01:06 +0000205 }
Stefan Tauner949ccc82013-09-15 14:01:06 +0000206
Nico Huber2b94cdb2019-06-15 18:19:26 +0200207 for (i = 0; i < layout->num_entries; i++) {
Nico Huber70461a92019-06-15 14:56:19 +0200208 free(layout->entries[i].name);
Edward O'Callaghan405e72a2020-12-19 11:21:49 +1100209 layout->entries[i].included = false;
Stefan Tauner949ccc82013-09-15 14:01:06 +0000210 }
Nico Huber2b94cdb2019-06-15 18:19:26 +0200211 layout->num_entries = 0;
Stefan Tauner949ccc82013-09-15 14:01:06 +0000212}
213
Stefan Tauner8268fdb2013-09-23 14:21:06 +0000214/* Validate and - if needed - normalize layout entries. */
215int normalize_romentries(const struct flashctx *flash)
216{
Nico Huber2b94cdb2019-06-15 18:19:26 +0200217 struct flashrom_layout *const layout = get_global_layout();
Stefan Tauner8268fdb2013-09-23 14:21:06 +0000218 chipsize_t total_size = flash->chip->total_size * 1024;
219 int ret = 0;
220
Nico Huber354766b2019-06-16 19:28:35 +0200221 const struct romentry *entry = NULL;
222 while ((entry = layout_next(layout, entry))) {
223 if (entry->start >= total_size || entry->end >= total_size) {
224 msg_gwarn("Warning: Address range of region \"%s\" "
225 "exceeds the current chip's address space.\n", entry->name);
226 if (entry->included)
Stefan Tauner8268fdb2013-09-23 14:21:06 +0000227 ret = 1;
228 }
Nico Huber354766b2019-06-16 19:28:35 +0200229 if (entry->start > entry->end) {
Stefan Tauner8268fdb2013-09-23 14:21:06 +0000230 msg_gerr("Error: Size of the address range of region \"%s\" is not positive.\n",
Nico Huber354766b2019-06-16 19:28:35 +0200231 entry->name);
Stefan Tauner8268fdb2013-09-23 14:21:06 +0000232 ret = 1;
233 }
234 }
235
236 return ret;
237}
Nico Huber3d7b1e32018-12-22 00:53:14 +0100238
239const struct romentry *layout_next_included_region(
240 const struct flashrom_layout *const l, const chipoff_t where)
241{
Nico Huber354766b2019-06-16 19:28:35 +0200242 const struct romentry *entry = NULL, *lowest = NULL;
Nico Huber3d7b1e32018-12-22 00:53:14 +0100243
Nico Huber354766b2019-06-16 19:28:35 +0200244 while ((entry = layout_next(l, entry))) {
245 if (!entry->included)
Nico Huber3d7b1e32018-12-22 00:53:14 +0100246 continue;
Nico Huber354766b2019-06-16 19:28:35 +0200247 if (entry->end < where)
Nico Huber3d7b1e32018-12-22 00:53:14 +0100248 continue;
Nico Huber354766b2019-06-16 19:28:35 +0200249 if (!lowest || lowest->start > entry->start)
250 lowest = entry;
Nico Huber3d7b1e32018-12-22 00:53:14 +0100251 }
252
253 return lowest;
254}
Nico Huber4f213282019-06-15 17:33:49 +0200255
Nico Huber5ca55232019-06-15 22:29:08 +0200256const struct romentry *layout_next_included(
257 const struct flashrom_layout *const layout, const struct romentry *iterator)
258{
Nico Huber354766b2019-06-16 19:28:35 +0200259 while ((iterator = layout_next(layout, iterator))) {
260 if (iterator->included)
261 break;
Nico Huber5ca55232019-06-15 22:29:08 +0200262 }
Nico Huber354766b2019-06-16 19:28:35 +0200263 return iterator;
264}
265
266const struct romentry *layout_next(
267 const struct flashrom_layout *const layout, const struct romentry *iterator)
268{
269 return mutable_layout_next(layout, (struct romentry *)iterator);
Nico Huber5ca55232019-06-15 22:29:08 +0200270}
271
Nico Huber4f213282019-06-15 17:33:49 +0200272/**
273 * @addtogroup flashrom-layout
274 * @{
275 */
276
277/**
Nico Huber5bd990c2019-06-16 19:46:46 +0200278 * @brief Create a new, empty layout.
279 *
280 * @param layout Pointer to returned layout reference.
281 * @param count Number of layout entries to allocate.
282 *
283 * @return 0 on success,
284 * 1 if out of memory.
285 */
286int flashrom_layout_new(struct flashrom_layout **const layout, const unsigned int count)
287{
288 *layout = malloc(sizeof(**layout) + count * sizeof(struct romentry));
289 if (!*layout) {
290 msg_gerr("Error creating layout: %s\n", strerror(errno));
291 return 1;
292 }
293
294 const struct flashrom_layout tmp = {
295 .entries = (void *)((char *)*layout + sizeof(**layout)),
296 .capacity = count,
297 .num_entries = 0,
298 };
299 **layout = tmp;
300 return 0;
301}
302
303/**
Nico Huber92e0b622019-06-15 15:55:11 +0200304 * @brief Add another region to an existing layout.
305 *
306 * @param layout The existing layout.
307 * @param start Start address of the region.
308 * @param end End address (inclusive) of the region.
309 * @param name Name of the region.
310 *
311 * @return 0 on success,
312 * 1 if out of memory,
313 * 2 if the layout is full already.
314 */
315int flashrom_layout_add_region(
316 struct flashrom_layout *const layout,
317 const size_t start, const size_t end, const char *const name)
318{
319 if (layout->num_entries >= layout->capacity) {
320 msg_gerr("Error adding layout entry: No space left\n");
321 return 2;
322 }
323
324 struct romentry *const entry = &layout->entries[layout->num_entries];
325 entry->start = start;
326 entry->end = end;
327 entry->included = false;
328 entry->name = strdup(name);
329 if (!entry->name) {
330 msg_gerr("Error adding layout entry: %s\n", strerror(errno));
331 return 1;
332 }
333
334 msg_gdbg("Added layout entry %08zx - %08zx named %s\n", start, end, name);
335 ++layout->num_entries;
336 return 0;
337}
338
339/**
Nico Huber4f213282019-06-15 17:33:49 +0200340 * @brief Mark given region as included.
341 *
342 * @param layout The layout to alter.
343 * @param name The name of the region to include.
344 *
345 * @return 0 on success,
346 * 1 if the given name can't be found.
347 */
348int flashrom_layout_include_region(struct flashrom_layout *const layout, const char *name)
349{
Nico Huber354766b2019-06-16 19:28:35 +0200350 struct romentry *entry = NULL;
351 while ((entry = mutable_layout_next(layout, entry))) {
352 if (!strcmp(entry->name, name)) {
353 entry->included = true;
Nico Huber4f213282019-06-15 17:33:49 +0200354 return 0;
355 }
356 }
357 return 1;
358}
359
360/**
361 * @brief Free a layout.
362 *
363 * @param layout Layout to free.
364 */
365void flashrom_layout_release(struct flashrom_layout *const layout)
366{
Nico Huber70461a92019-06-15 14:56:19 +0200367 unsigned int i;
368
369 if (!layout || layout == get_global_layout())
Nico Huber4f213282019-06-15 17:33:49 +0200370 return;
371
Nico Huber70461a92019-06-15 14:56:19 +0200372 for (i = 0; i < layout->num_entries; ++i)
373 free(layout->entries[i].name);
Nico Huber4f213282019-06-15 17:33:49 +0200374 free(layout);
375}
376
377/** @} */ /* end flashrom-layout */