blob: 119f81f8c70dadb2239ba3ecf842f3b679ea38bd [file] [log] [blame]
Nico Huber454f6132012-12-10 13:34:10 +00001/*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2012, 2016 secunet Security Networks AG
5 * (Written by Nico Huber <nico.huber@secunet.com> for secunet)
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
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.
Nico Huber454f6132012-12-10 13:34:10 +000016 */
17/**
18 * @mainpage
19 *
20 * Have a look at the Modules section for a function reference.
21 */
22
Nico Huber70461a92019-06-15 14:56:19 +020023#include <errno.h>
Nico Huber454f6132012-12-10 13:34:10 +000024#include <stdlib.h>
25#include <string.h>
26#include <stdarg.h>
27
28#include "flash.h"
Arthur Heymansc82900b2018-01-10 12:48:16 +010029#include "fmap.h"
Nico Huber454f6132012-12-10 13:34:10 +000030#include "programmer.h"
31#include "layout.h"
Nico Huber305f4172013-06-14 11:55:26 +020032#include "hwaccess.h"
33#include "ich_descriptors.h"
Nico Huber454f6132012-12-10 13:34:10 +000034#include "libflashrom.h"
Nikolai Artemievda1c8342021-10-21 00:58:12 +110035#include "writeprotect.h"
Nico Huber454f6132012-12-10 13:34:10 +000036
37/**
38 * @defgroup flashrom-general General
39 * @{
40 */
41
42/** Pointer to log callback function. */
43static flashrom_log_callback *global_log_callback = NULL;
44
45/**
46 * @brief Initialize libflashrom.
47 *
48 * @param perform_selfcheck If not zero, perform a self check.
49 * @return 0 on success
50 */
51int flashrom_init(const int perform_selfcheck)
52{
53 if (perform_selfcheck && selfcheck())
54 return 1;
55 myusec_calibrate_delay();
56 return 0;
57}
58
59/**
60 * @brief Shut down libflashrom.
61 * @return 0 on success
62 */
63int flashrom_shutdown(void)
64{
65 return 0; /* TODO: nothing to do? */
66}
67
68/* TODO: flashrom_set_loglevel()? do we need it?
69 For now, let the user decide in his callback. */
70
71/**
72 * @brief Set the log callback function.
73 *
74 * Set a callback function which will be invoked whenever libflashrom wants
75 * to output messages. This allows frontends to do whatever they see fit with
76 * such messages, e.g. write them to syslog, or to file, or print them in a
77 * GUI window, etc.
78 *
79 * @param log_callback Pointer to the new log callback function.
80 */
81void flashrom_set_log_callback(flashrom_log_callback *const log_callback)
82{
83 global_log_callback = log_callback;
84}
85/** @private */
Nico Huberd152fb92017-06-19 12:57:10 +020086int print(const enum flashrom_log_level level, const char *const fmt, ...)
Nico Huber454f6132012-12-10 13:34:10 +000087{
88 if (global_log_callback) {
89 int ret;
90 va_list args;
91 va_start(args, fmt);
Nico Huberd152fb92017-06-19 12:57:10 +020092 ret = global_log_callback(level, fmt, args);
Nico Huber454f6132012-12-10 13:34:10 +000093 va_end(args);
94 return ret;
95 }
96 return 0;
97}
98
99/** @} */ /* end flashrom-general */
100
101
102
103/**
104 * @defgroup flashrom-query Querying
105 * @{
106 */
107
Artur Raglis71b706f2019-06-05 19:24:52 +0200108/**
109 * @brief Returns flashrom version
110 * @return flashrom version
111 */
112const char *flashrom_version_info(void)
113{
114 return flashrom_version;
115}
116
117/**
118 * @brief Returns list of supported programmers
119 * @return List of supported programmers, or NULL if an error occurred
120 */
121const char **flashrom_supported_programmers(void)
122{
123 enum programmer p = 0;
124 const char **supported_programmers = malloc((PROGRAMMER_INVALID + 1) * sizeof(char*));
125
126 if (supported_programmers != NULL) {
127 for (; p < PROGRAMMER_INVALID; ++p) {
128 supported_programmers[p] = programmer_table[p].name;
129 }
130 } else {
131 msg_gerr("Memory allocation error!\n");
132 }
133
134 return supported_programmers;
135}
136
137/**
138 * @brief Returns list of supported flash chips
139 * @return List of supported flash chips, or NULL if an error occurred
140 */
141struct flashrom_flashchip_info *flashrom_supported_flash_chips(void)
142{
Nico Huber961f4a12019-10-04 17:34:22 +0200143 unsigned int i = 0;
Artur Raglis71b706f2019-06-05 19:24:52 +0200144 struct flashrom_flashchip_info *supported_flashchips =
145 malloc(flashchips_size * sizeof(*supported_flashchips));
146
147 if (supported_flashchips != NULL) {
148 for (; i < flashchips_size; ++i) {
149 supported_flashchips[i].vendor = flashchips[i].vendor;
150 supported_flashchips[i].name = flashchips[i].name;
151 supported_flashchips[i].tested.erase =
152 (enum flashrom_test_state)flashchips[i].tested.erase;
153 supported_flashchips[i].tested.probe =
154 (enum flashrom_test_state)flashchips[i].tested.probe;
155 supported_flashchips[i].tested.read =
156 (enum flashrom_test_state)flashchips[i].tested.read;
157 supported_flashchips[i].tested.write =
158 (enum flashrom_test_state)flashchips[i].tested.write;
159 supported_flashchips[i].total_size = flashchips[i].total_size;
160 }
161 } else {
162 msg_gerr("Memory allocation error!\n");
163 }
164
165 return supported_flashchips;
166}
167
168/**
169 * @brief Returns list of supported mainboards
170 * @return List of supported mainboards, or NULL if an error occurred
171 */
172struct flashrom_board_info *flashrom_supported_boards(void)
173{
Jonathan Liu7f15de12019-10-06 16:22:04 +1100174#if CONFIG_INTERNAL == 1
Artur Raglis71b706f2019-06-05 19:24:52 +0200175 int boards_known_size = 0;
176 int i = 0;
177 const struct board_info *binfo = boards_known;
178
179 while ((binfo++)->vendor)
180 ++boards_known_size;
181 binfo = boards_known;
182 /* add place for {0} */
183 ++boards_known_size;
184
185 struct flashrom_board_info *supported_boards =
186 malloc(boards_known_size * sizeof(*binfo));
187
188 if (supported_boards != NULL) {
189 for (; i < boards_known_size; ++i) {
190 supported_boards[i].vendor = binfo[i].vendor;
191 supported_boards[i].name = binfo[i].name;
Angel Ponsb428c312020-05-27 12:15:51 +0200192 supported_boards[i].working =
193 (enum flashrom_test_state) binfo[i].working;
Artur Raglis71b706f2019-06-05 19:24:52 +0200194 }
195 } else {
196 msg_gerr("Memory allocation error!\n");
197 }
198
199 return supported_boards;
Jonathan Liu7f15de12019-10-06 16:22:04 +1100200#else
201 return NULL;
202#endif
Artur Raglis71b706f2019-06-05 19:24:52 +0200203}
204
205/**
206 * @brief Returns list of supported chipsets
207 * @return List of supported chipsets, or NULL if an error occurred
208 */
209struct flashrom_chipset_info *flashrom_supported_chipsets(void)
210{
Jonathan Liu7f15de12019-10-06 16:22:04 +1100211#if CONFIG_INTERNAL == 1
Artur Raglis71b706f2019-06-05 19:24:52 +0200212 int chipset_enables_size = 0;
213 int i = 0;
214 const struct penable *chipset = chipset_enables;
215
216 while ((chipset++)->vendor_name)
217 ++chipset_enables_size;
218 chipset = chipset_enables;
219 /* add place for {0}*/
220 ++chipset_enables_size;
221
222 struct flashrom_chipset_info *supported_chipsets =
223 malloc(chipset_enables_size * sizeof(*supported_chipsets));
224
225 if (supported_chipsets != NULL) {
226 for (; i < chipset_enables_size; ++i) {
227 supported_chipsets[i].vendor = chipset[i].vendor_name;
228 supported_chipsets[i].chipset = chipset[i].device_name;
229 supported_chipsets[i].vendor_id = chipset[i].vendor_id;
230 supported_chipsets[i].chipset_id = chipset[i].device_id;
Angel Ponsb428c312020-05-27 12:15:51 +0200231 supported_chipsets[i].status =
232 (enum flashrom_test_state) chipset[i].status;
Artur Raglis71b706f2019-06-05 19:24:52 +0200233 }
234 } else {
235 msg_gerr("Memory allocation error!\n");
236 }
237
238 return supported_chipsets;
Jonathan Liu7f15de12019-10-06 16:22:04 +1100239#else
240 return NULL;
241#endif
Artur Raglis71b706f2019-06-05 19:24:52 +0200242}
243
244/**
245 * @brief Frees memory allocated by libflashrom API
246 * @param Pointer to block of memory which should be freed
247 * @return 0 on success
248 */
249int flashrom_data_free(void *const p)
250{
251 free(p);
252 return 0;
253}
Nico Huber454f6132012-12-10 13:34:10 +0000254
255/** @} */ /* end flashrom-query */
256
257
258
259/**
260 * @defgroup flashrom-prog Programmers
261 * @{
262 */
263
264/**
265 * @brief Initialize the specified programmer.
266 *
267 * Currently, only one programmer may be initialized at a time.
268 *
269 * @param[out] flashprog Points to a pointer of type struct flashrom_programmer
270 * that will be set if programmer initialization succeeds.
271 * *flashprog has to be shutdown by the caller with @ref
272 * flashrom_programmer_shutdown.
273 * @param[in] prog_name Name of the programmer to initialize.
274 * @param[in] prog_param Pointer to programmer specific parameters.
275 * @return 0 on success
276 */
277int flashrom_programmer_init(struct flashrom_programmer **const flashprog,
278 const char *const prog_name, const char *const prog_param)
279{
280 unsigned prog;
281
282 for (prog = 0; prog < PROGRAMMER_INVALID; prog++) {
283 if (strcmp(prog_name, programmer_table[prog].name) == 0)
284 break;
285 }
286 if (prog >= PROGRAMMER_INVALID) {
287 msg_ginfo("Error: Unknown programmer \"%s\". Valid choices are:\n", prog_name);
288 list_programmers_linebreak(0, 80, 0);
289 return 1;
290 }
291 return programmer_init(prog, prog_param);
292}
293
294/**
295 * @brief Shut down the initialized programmer.
296 *
297 * @param flashprog The programmer to shut down.
298 * @return 0 on success
299 */
300int flashrom_programmer_shutdown(struct flashrom_programmer *const flashprog)
301{
302 return programmer_shutdown();
303}
304
305/* TODO: flashrom_programmer_capabilities()? */
306
307/** @} */ /* end flashrom-prog */
308
309
310
311/**
312 * @defgroup flashrom-flash Flash chips
313 * @{
314 */
315
316/**
317 * @brief Probe for a flash chip.
318 *
319 * Probes for a flash chip and returns a flash context, that can be used
320 * later with flash chip and @ref flashrom-ops "image operations", if
321 * exactly one matching chip is found.
322 *
323 * @param[out] flashctx Points to a pointer of type struct flashrom_flashctx
324 * that will be set if exactly one chip is found. *flashctx
325 * has to be freed by the caller with @ref flashrom_flash_release.
326 * @param[in] flashprog The flash programmer used to access the chip.
327 * @param[in] chip_name Name of a chip to probe for, or NULL to probe for
328 * all known chips.
329 * @return 0 on success,
330 * 3 if multiple chips were found,
331 * 2 if no chip was found,
332 * or 1 on any other error.
333 */
334int flashrom_flash_probe(struct flashrom_flashctx **const flashctx,
335 const struct flashrom_programmer *const flashprog,
336 const char *const chip_name)
337{
338 int i, ret = 2;
339 struct flashrom_flashctx second_flashctx = { 0, };
340
341 chip_to_probe = chip_name; /* chip_to_probe is global in flashrom.c */
342
343 *flashctx = malloc(sizeof(**flashctx));
344 if (!*flashctx)
345 return 1;
346 memset(*flashctx, 0, sizeof(**flashctx));
347
348 for (i = 0; i < registered_master_count; ++i) {
349 int flash_idx = -1;
350 if (!ret || (flash_idx = probe_flash(&registered_masters[i], 0, *flashctx, 0)) != -1) {
351 ret = 0;
352 /* We found one chip, now check that there is no second match. */
353 if (probe_flash(&registered_masters[i], flash_idx + 1, &second_flashctx, 0) != -1) {
354 ret = 3;
355 break;
356 }
357 }
358 }
359 if (ret) {
360 free(*flashctx);
361 *flashctx = NULL;
362 }
363 return ret;
364}
365
366/**
367 * @brief Returns the size of the specified flash chip in bytes.
368 *
369 * @param flashctx The queried flash context.
370 * @return Size of flash chip in bytes.
371 */
372size_t flashrom_flash_getsize(const struct flashrom_flashctx *const flashctx)
373{
374 return flashctx->chip->total_size * 1024;
375}
376
377/**
378 * @brief Free a flash context.
379 *
380 * @param flashctx Flash context to free.
381 */
382void flashrom_flash_release(struct flashrom_flashctx *const flashctx)
383{
384 free(flashctx);
385}
386
387/**
388 * @brief Set a flag in the given flash context.
389 *
390 * @param flashctx Flash context to alter.
391 * @param flag Flag that is to be set / cleared.
392 * @param value Value to set.
393 */
394void flashrom_flag_set(struct flashrom_flashctx *const flashctx,
395 const enum flashrom_flag flag, const bool value)
396{
397 switch (flag) {
398 case FLASHROM_FLAG_FORCE: flashctx->flags.force = value; break;
399 case FLASHROM_FLAG_FORCE_BOARDMISMATCH: flashctx->flags.force_boardmismatch = value; break;
400 case FLASHROM_FLAG_VERIFY_AFTER_WRITE: flashctx->flags.verify_after_write = value; break;
401 case FLASHROM_FLAG_VERIFY_WHOLE_CHIP: flashctx->flags.verify_whole_chip = value; break;
402 }
403}
404
405/**
406 * @brief Return the current value of a flag in the given flash context.
407 *
408 * @param flashctx Flash context to read from.
409 * @param flag Flag to be read.
410 * @return Current value of the flag.
411 */
412bool flashrom_flag_get(const struct flashrom_flashctx *const flashctx, const enum flashrom_flag flag)
413{
414 switch (flag) {
415 case FLASHROM_FLAG_FORCE: return flashctx->flags.force;
416 case FLASHROM_FLAG_FORCE_BOARDMISMATCH: return flashctx->flags.force_boardmismatch;
417 case FLASHROM_FLAG_VERIFY_AFTER_WRITE: return flashctx->flags.verify_after_write;
418 case FLASHROM_FLAG_VERIFY_WHOLE_CHIP: return flashctx->flags.verify_whole_chip;
419 default: return false;
420 }
421}
422
423/** @} */ /* end flashrom-flash */
424
425
426
427/**
428 * @defgroup flashrom-layout Layout handling
429 * @{
430 */
431
432/**
Nico Huber305f4172013-06-14 11:55:26 +0200433 * @brief Read a layout from the Intel ICH descriptor in the flash.
434 *
435 * Optionally verify that the layout matches the one in the given
436 * descriptor dump.
437 *
438 * @param[out] layout Points to a struct flashrom_layout pointer that
439 * gets set if the descriptor is read and parsed
440 * successfully.
441 * @param[in] flashctx Flash context to read the descriptor from flash.
442 * @param[in] dump The descriptor dump to compare to or NULL.
443 * @param[in] len The length of the descriptor dump.
444 *
445 * @return 0 on success,
446 * 6 if descriptor parsing isn't implemented for the host,
447 * 5 if the descriptors don't match,
448 * 4 if the descriptor dump couldn't be parsed,
449 * 3 if the descriptor on flash couldn't be parsed,
450 * 2 if the descriptor on flash couldn't be read,
451 * 1 on any other error.
452 */
453int flashrom_layout_read_from_ifd(struct flashrom_layout **const layout, struct flashctx *const flashctx,
454 const void *const dump, const size_t len)
455{
456#ifndef __FLASHROM_LITTLE_ENDIAN__
457 return 6;
458#else
459 struct ich_layout dump_layout;
460 int ret = 1;
461
462 void *const desc = malloc(0x1000);
463 struct ich_layout *const chip_layout = malloc(sizeof(*chip_layout));
464 if (!desc || !chip_layout) {
465 msg_gerr("Out of memory!\n");
466 goto _free_ret;
467 }
468
469 if (prepare_flash_access(flashctx, true, false, false, false))
470 goto _free_ret;
471
472 msg_cinfo("Reading ich descriptor... ");
473 if (flashctx->chip->read(flashctx, desc, 0, 0x1000)) {
474 msg_cerr("Read operation failed!\n");
475 msg_cinfo("FAILED.\n");
476 ret = 2;
477 goto _finalize_ret;
478 }
479 msg_cinfo("done.\n");
480
481 if (layout_from_ich_descriptors(chip_layout, desc, 0x1000)) {
Patrick Rudolph911b8d82019-06-06 11:23:55 +0200482 msg_cerr("Couldn't parse the descriptor!\n");
Nico Huber305f4172013-06-14 11:55:26 +0200483 ret = 3;
484 goto _finalize_ret;
485 }
486
487 if (dump) {
488 if (layout_from_ich_descriptors(&dump_layout, dump, len)) {
Patrick Rudolph911b8d82019-06-06 11:23:55 +0200489 msg_cerr("Couldn't parse the descriptor!\n");
Nico Huber305f4172013-06-14 11:55:26 +0200490 ret = 4;
491 goto _finalize_ret;
492 }
493
494 if (chip_layout->base.num_entries != dump_layout.base.num_entries ||
495 memcmp(chip_layout->entries, dump_layout.entries, sizeof(dump_layout.entries))) {
Patrick Rudolph911b8d82019-06-06 11:23:55 +0200496 msg_cerr("Descriptors don't match!\n");
Nico Huber305f4172013-06-14 11:55:26 +0200497 ret = 5;
498 goto _finalize_ret;
499 }
500 }
501
502 *layout = (struct flashrom_layout *)chip_layout;
503 ret = 0;
504
505_finalize_ret:
506 finalize_flash_access(flashctx);
507_free_ret:
508 if (ret)
509 free(chip_layout);
510 free(desc);
511 return ret;
512#endif
513}
514
Nico Huberee13d0c2019-06-07 17:47:40 +0200515#ifdef __FLASHROM_LITTLE_ENDIAN__
Arthur Heymansc82900b2018-01-10 12:48:16 +0100516static int flashrom_layout_parse_fmap(struct flashrom_layout **layout,
517 struct flashctx *const flashctx, const struct fmap *const fmap)
518{
519 int i;
520 struct flashrom_layout *l = get_global_layout();
521
522 if (!fmap || !l)
523 return 1;
524
525 if (l->num_entries + fmap->nareas > MAX_ROMLAYOUT) {
526 msg_gerr("Cannot add fmap entries to layout - Too many entries.\n");
527 return 1;
528 }
529
530 for (i = 0; i < fmap->nareas; i++) {
531 l->entries[l->num_entries].start = fmap->areas[i].offset;
532 l->entries[l->num_entries].end = fmap->areas[i].offset + fmap->areas[i].size - 1;
533 l->entries[l->num_entries].included = false;
Nico Huber70461a92019-06-15 14:56:19 +0200534 l->entries[l->num_entries].name =
535 strndup((const char *)fmap->areas[i].name, FMAP_STRLEN);
536 if (!l->entries[l->num_entries].name) {
537 msg_gerr("Error adding layout entry: %s\n", strerror(errno));
538 return 1;
539 }
Arthur Heymansc82900b2018-01-10 12:48:16 +0100540 msg_gdbg("fmap %08x - %08x named %s\n",
541 l->entries[l->num_entries].start,
542 l->entries[l->num_entries].end,
543 l->entries[l->num_entries].name);
544 l->num_entries++;
545 }
546
547 *layout = l;
548 return 0;
549}
Nico Huberee13d0c2019-06-07 17:47:40 +0200550#endif /* __FLASHROM_LITTLE_ENDIAN__ */
Arthur Heymansc82900b2018-01-10 12:48:16 +0100551
552/**
553 * @brief Read a layout by searching the flash chip for fmap.
554 *
555 * @param[out] layout Points to a struct flashrom_layout pointer that
556 * gets set if the fmap is read and parsed successfully.
557 * @param[in] flashctx Flash context
558 * @param[in] offset Offset to begin searching for fmap.
559 * @param[in] offset Length of address space to search.
560 *
561 * @return 0 on success,
562 * 3 if fmap parsing isn't implemented for the host,
563 * 2 if the fmap couldn't be read,
564 * 1 on any other error.
565 */
566int flashrom_layout_read_fmap_from_rom(struct flashrom_layout **const layout,
567 struct flashctx *const flashctx, off_t offset, size_t len)
568{
569#ifndef __FLASHROM_LITTLE_ENDIAN__
570 return 3;
571#else
572 struct fmap *fmap = NULL;
573 int ret = 0;
574
575 msg_gdbg("Attempting to read fmap from ROM content.\n");
576 if (fmap_read_from_rom(&fmap, flashctx, offset, len)) {
577 msg_gerr("Failed to read fmap from ROM.\n");
578 return 1;
579 }
580
581 msg_gdbg("Adding fmap layout to global layout.\n");
582 if (flashrom_layout_parse_fmap(layout, flashctx, fmap)) {
583 msg_gerr("Failed to add fmap regions to layout.\n");
584 ret = 1;
585 }
586
587 free(fmap);
588 return ret;
589#endif
590}
591
592/**
593 * @brief Read a layout by searching buffer for fmap.
594 *
595 * @param[out] layout Points to a struct flashrom_layout pointer that
596 * gets set if the fmap is read and parsed successfully.
597 * @param[in] flashctx Flash context
598 * @param[in] buffer Buffer to search in
599 * @param[in] size Size of buffer to search
600 *
601 * @return 0 on success,
602 * 3 if fmap parsing isn't implemented for the host,
603 * 2 if the fmap couldn't be read,
604 * 1 on any other error.
605 */
606int flashrom_layout_read_fmap_from_buffer(struct flashrom_layout **const layout,
607 struct flashctx *const flashctx, const uint8_t *const buf, size_t size)
608{
609#ifndef __FLASHROM_LITTLE_ENDIAN__
610 return 3;
611#else
612 struct fmap *fmap = NULL;
613 int ret = 1;
614
615 if (!buf || !size)
616 goto _ret;
617
618 msg_gdbg("Attempting to read fmap from buffer.\n");
619 if (fmap_read_from_buffer(&fmap, buf, size)) {
620 msg_gerr("Failed to read fmap from buffer.\n");
621 goto _ret;
622 }
623
624 msg_gdbg("Adding fmap layout to global layout.\n");
625 if (flashrom_layout_parse_fmap(layout, flashctx, fmap)) {
626 msg_gerr("Failed to add fmap regions to layout.\n");
627 goto _free_ret;
628 }
629
630 ret = 0;
631_free_ret:
632 free(fmap);
633_ret:
634 return ret;
635#endif
636}
637
Nico Huber305f4172013-06-14 11:55:26 +0200638/**
Nico Huber454f6132012-12-10 13:34:10 +0000639 * @brief Set the active layout for a flash context.
640 *
641 * Note: This just sets a pointer. The caller must not release the layout
642 * as long as he uses it through the given flash context.
643 *
644 * @param flashctx Flash context whose layout will be set.
645 * @param layout Layout to bet set.
646 */
647void flashrom_layout_set(struct flashrom_flashctx *const flashctx, const struct flashrom_layout *const layout)
648{
649 flashctx->layout = layout;
650}
651
652/** @} */ /* end flashrom-layout */
Nikolai Artemievda1c8342021-10-21 00:58:12 +1100653
654
655/**
656 * @defgroup flashrom-wp
657 * @{
658 */
659
660/**
661 * @brief Create a new empty WP configuration.
662 *
663 * @param[out] cfg Points to a pointer of type struct flashrom_wp_cfg that will
664 * be set if creation succeeds. *cfg has to be freed by the
665 * caller with @ref flashrom_wp_cfg_release.
666 * @return 0 on success
667 * >0 on failure
668 */
669enum flashrom_wp_result flashrom_wp_cfg_new(struct flashrom_wp_cfg **cfg)
670{
671 *cfg = calloc(1, sizeof(**cfg));
672 return *cfg ? 0 : FLASHROM_WP_ERR_OTHER;
673}
674
675/**
676 * @brief Free a WP configuration.
677 *
678 * @param[out] cfg Pointer to the flashrom_wp_cfg to free.
679 */
680void flashrom_wp_cfg_release(struct flashrom_wp_cfg *cfg)
681{
682 free(cfg);
683}
684
685/**
686 * @brief Set the protection mode for a WP configuration.
687 *
688 * @param[in] mode The protection mode to set.
689 * @param[out] cfg Pointer to the flashrom_wp_cfg structure to modify.
690 */
691void flashrom_wp_set_mode(struct flashrom_wp_cfg *cfg, enum flashrom_wp_mode mode)
692{
693 cfg->mode = mode;
694}
695
696/**
697 * @brief Get the protection mode from a WP configuration.
698 *
699 * @param[in] cfg The WP configuration to get the protection mode from.
700 * @return The configuration's protection mode.
701 */
702enum flashrom_wp_mode flashrom_wp_get_mode(const struct flashrom_wp_cfg *cfg)
703{
704 return cfg->mode;
705}
706
707/**
708 * @brief Set the protection range for a WP configuration.
709 *
710 * @param[out] cfg Pointer to the flashrom_wp_cfg structure to modify.
711 * @param[in] start The range's start address.
712 * @param[in] len The range's length.
713 */
714void flashrom_wp_set_range(struct flashrom_wp_cfg *cfg, size_t start, size_t len)
715{
716 cfg->range.start = start;
717 cfg->range.len = len;
718}
719
720/**
721 * @brief Get the protection range from a WP configuration.
722 *
723 * @param[out] start Points to a size_t to write the range start to.
724 * @param[out] len Points to a size_t to write the range length to.
725 * @param[in] cfg The WP configuration to get the range from.
726 */
727void flashrom_wp_get_range(size_t *start, size_t *len, const struct flashrom_wp_cfg *cfg)
728{
729 *start = cfg->range.start;
730 *len = cfg->range.len;
731}
732
733/**
734 * @brief Write a WP configuration to a flash chip.
735 *
736 * @param[in] flash The flash context used to access the chip.
737 * @param[in] cfg The WP configuration to write to the chip.
738 * @return 0 on success
739 * >0 on failure
740 */
741enum flashrom_wp_result flashrom_wp_write_cfg(struct flashctx *flash, const struct flashrom_wp_cfg *cfg)
742{
743 /*
744 * TODO: Call custom implementation if the programmer is opaque, as
745 * direct WP operations require SPI access. In particular, linux_mtd
746 * has its own WP operations we should use instead.
747 */
748 if (flash->mst->buses_supported & BUS_SPI)
749 return wp_write_cfg(flash, cfg);
750
751 return FLASHROM_WP_ERR_OTHER;
752}
753
754/**
755 * @brief Read the current WP configuration from a flash chip.
756 *
757 * @param[out] cfg Pointer to a struct flashrom_wp_cfg to store the chip's
758 * configuration in.
759 * @param[in] flash The flash context used to access the chip.
760 * @return 0 on success
761 * >0 on failure
762 */
763enum flashrom_wp_result flashrom_wp_read_cfg(struct flashrom_wp_cfg *cfg, struct flashctx *flash)
764{
765 /*
766 * TODO: Call custom implementation if the programmer is opaque, as
767 * direct WP operations require SPI access. In particular, linux_mtd
768 * has its own WP operations we should use instead.
769 */
770 if (flash->mst->buses_supported & BUS_SPI)
771 return wp_read_cfg(cfg, flash);
772
773 return FLASHROM_WP_ERR_OTHER;
774}
775
776/** @} */ /* end flashrom-wp */