blob: a77205781f07a60d9eeec13f1673b192b086ff81 [file] [log] [blame]
Stefan Tauner9b32de92014-08-08 23:52:33 +00001/*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
5 * Copyright (C) 2009 Carl-Daniel Hailfinger
6 * Copyright (C) 2011-2014 Stefan Tauner
7 *
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; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
Stefan Tauner9b32de92014-08-08 23:52:33 +000017 */
18
19#include <stdlib.h>
20#include <string.h>
Nico Huber78f3ae92023-02-11 01:40:07 +010021#include <sys/stat.h>
Nico Huber79bb1a12023-02-11 00:30:27 +010022
Stefan Tauner9b32de92014-08-08 23:52:33 +000023#include "flash.h"
Nico Huber79bb1a12023-02-11 00:30:27 +010024#include "cli.h"
25
Nico Huber30cb07b2023-02-11 00:43:54 +010026int cli_check_filename(const char *const filename, const char *const type)
27{
28 if (!filename || (filename[0] == '\0')) {
29 fprintf(stderr, "Error: No %s file specified.\n", type);
30 return 1;
31 }
32 /* Not an error, but maybe the user intended to specify a CLI option instead of a file name. */
33 if (filename[0] == '-' && filename[1] != '\0')
34 fprintf(stderr, "Warning: Supplied %s file name starts with -\n", type);
35 return 0;
36}
37
Nico Huber79bb1a12023-02-11 00:30:27 +010038int cli_parse_flash_args(struct flash_args *const args, const int opt, const char *const optarg)
39{
40 switch (opt) {
41 case OPTION_PROGRAMMER:
42 if (args->prog_name) {
43 fprintf(stderr,
44 "Error: --programmer specified more than once. You can separate multiple\n"
45 "arguments for a programmer with ','. Please see the man page for details.\n");
46 return 1;
47 }
48 const char *const colon = strchr(optarg, ':');
49 if (colon) {
50 args->prog_name = strndup(optarg, colon - optarg);
51 args->prog_args = strdup(colon + 1);
52 } else {
53 args->prog_name = strdup(optarg);
54 }
55 if (!args->prog_name || (colon && !args->prog_args)) {
56 fprintf(stderr, "Out of memory!\n");
57 return 2;
58 }
59 break;
60 case OPTION_CHIP:
61 if (args->chip) {
62 fprintf(stderr, "Error: --chip specified more than once.\n");
63 return 1;
64 }
65 args->chip = strdup(optarg);
66 if (!args->chip) {
67 fprintf(stderr, "Out of memory!\n");
68 return 2;
69 }
70 break;
71 }
72
73 return 0;
74}
Stefan Tauner9b32de92014-08-08 23:52:33 +000075
Nico Huber30cb07b2023-02-11 00:43:54 +010076int cli_parse_layout_args(struct layout_args *const args, const int opt, const char *const optarg)
77{
78 if (args->layoutfile || args->ifd || args->fmap || args->fmapfile) {
79 fprintf(stderr, "Error: Only one layout source may be specified.\n");
80 return 1;
81 }
82
83 switch (opt) {
84 case OPTION_LAYOUT:
85 if (cli_check_filename(optarg, "layout"))
86 return 1;
87
88 args->layoutfile = strdup(optarg);
89 if (!args->layoutfile) {
90 fprintf(stderr, "Out of memory!\n");
91 return 2;
92 }
93 break;
94 case OPTION_IFD:
95 args->ifd = true;
96 break;
97 case OPTION_FMAP:
98 args->fmap = true;
99 break;
100 case OPTION_FMAP_FILE:
101 if (cli_check_filename(optarg, "fmap"))
102 return 1;
103
104 args->fmapfile = strdup(optarg);
105 if (!args->fmapfile) {
106 fprintf(stderr, "Out of memory!\n");
107 return 2;
108 }
109 break;
110 }
111
112 return 0;
113}
114
Nico Huber78f3ae92023-02-11 01:40:07 +0100115int cli_process_layout_args(struct flashprog_layout **const layout,
116 struct flashprog_flashctx *const flash,
117 const struct layout_args *const args)
118{
119 *layout = NULL;
120
121 if (args->layoutfile) {
122 if (layout_from_file(layout, args->layoutfile))
123 return 1;
124 } else if (args->ifd) {
125 if (flashprog_layout_read_from_ifd(layout, flash, NULL, 0))
126 return 1;
127 } else if (args->fmap) {
128 if (flashprog_layout_read_fmap_from_rom(layout, flash, 0, flashprog_flash_getsize(flash)))
129 return 1;
130 } else if (args->fmapfile) {
131 struct stat s;
132 if (stat(args->fmapfile, &s) != 0) {
133 msg_gerr("Failed to stat fmapfile \"%s\"\n", args->fmapfile);
134 return 1;
135 }
136
137 size_t fmapfile_size = s.st_size;
138 uint8_t *fmapfile_buffer = malloc(fmapfile_size);
139 if (!fmapfile_buffer) {
140 fprintf(stderr, "Out of memory!\n");
141 return 1;
142 }
143
144 if (read_buf_from_file(fmapfile_buffer, fmapfile_size, args->fmapfile)) {
145 free(fmapfile_buffer);
146 return 1;
147 }
148
149 if (flashprog_layout_read_fmap_from_buffer(layout, flash, fmapfile_buffer, fmapfile_size)) {
150 free(fmapfile_buffer);
151 return 1;
152 }
153 free(fmapfile_buffer);
154 }
155
156 return 0;
157}
158
Stefan Tauner9b32de92014-08-08 23:52:33 +0000159void print_chip_support_status(const struct flashchip *chip)
160{
161 if (chip->feature_bits & FEATURE_OTP) {
Nico Huberc3b02dc2023-08-12 01:13:45 +0200162 msg_cdbg("This chip may contain one-time programmable memory. flashprog cannot read\n"
Stefan Tauner9b32de92014-08-08 23:52:33 +0000163 "and may never be able to write it, hence it may not be able to completely\n"
164 "clone the contents of this chip (see man page for details).\n");
165 }
166
167 if ((chip->tested.erase == NA) && (chip->tested.write == NA)) {
168 msg_cdbg("This chip's main memory can not be erased/written by design.\n");
169 }
170
171 if ((chip->tested.probe == BAD) || (chip->tested.probe == NT) ||
172 (chip->tested.read == BAD) || (chip->tested.read == NT) ||
173 (chip->tested.erase == BAD) || (chip->tested.erase == NT) ||
Nico Huberbb4f3b02022-12-30 14:28:06 +0100174 (chip->tested.write == BAD) || (chip->tested.write == NT)) {
Stefan Tauner9b32de92014-08-08 23:52:33 +0000175 msg_cinfo("===\n");
176 if ((chip->tested.probe == BAD) ||
177 (chip->tested.read == BAD) ||
178 (chip->tested.erase == BAD) ||
Nico Huberbb4f3b02022-12-30 14:28:06 +0100179 (chip->tested.write == BAD)) {
Stefan Tauner9b32de92014-08-08 23:52:33 +0000180 msg_cinfo("This flash part has status NOT WORKING for operations:");
181 if (chip->tested.probe == BAD)
182 msg_cinfo(" PROBE");
183 if (chip->tested.read == BAD)
184 msg_cinfo(" READ");
185 if (chip->tested.erase == BAD)
186 msg_cinfo(" ERASE");
187 if (chip->tested.write == BAD)
188 msg_cinfo(" WRITE");
189 msg_cinfo("\n");
190 }
191 if ((chip->tested.probe == NT) ||
192 (chip->tested.read == NT) ||
193 (chip->tested.erase == NT) ||
Nico Huberbb4f3b02022-12-30 14:28:06 +0100194 (chip->tested.write == NT)) {
Stefan Tauner9b32de92014-08-08 23:52:33 +0000195 msg_cinfo("This flash part has status UNTESTED for operations:");
196 if (chip->tested.probe == NT)
197 msg_cinfo(" PROBE");
198 if (chip->tested.read == NT)
199 msg_cinfo(" READ");
200 if (chip->tested.erase == NT)
201 msg_cinfo(" ERASE");
202 if (chip->tested.write == NT)
203 msg_cinfo(" WRITE");
204 msg_cinfo("\n");
205 }
206 msg_cinfo("The test status of this chip may have been updated in the latest development\n"
Nico Huberc3b02dc2023-08-12 01:13:45 +0200207 "version of flashprog. If you are running the latest development version,\n"
208 "please email a report to flashprog@flashprog.org if any of the above\n"
Nico Huberac90af62022-12-18 00:22:47 +0000209 "operations work correctly for you with this flash chip. Please include the\n"
Nico Huberc3b02dc2023-08-12 01:13:45 +0200210 "flashprog log file for all operations you tested (see the man page for details),\n"
Nico Huberac90af62022-12-18 00:22:47 +0000211 "and mention which mainboard or programmer you tested in the subject line.\n"
Stefan Tauner9b32de92014-08-08 23:52:33 +0000212 "Thanks for your help!\n");
213 }
214}