1 /*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2009 Carl-Daniel Hailfinger
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17 #include <strings.h>
18 #include <string.h>
19 #include <stdbool.h>
20 #include <stdlib.h>
21
22 #include "flash.h"
23 #include "programmer.h"
24 #include "platform/pci.h"
25
26 #if defined(__i386__) || defined(__x86_64__)
27 #include "hwaccess_x86_io.h"
28 #endif
29
30 bool force_boardmismatch = false;
31
32 enum chipbustype internal_buses_supported = BUS_NONE;
33
34
get_params(const struct programmer_cfg * cfg,bool * boardenable,bool * boardmismatch,bool * force_laptop,bool * not_a_laptop,char ** board_vendor,char ** board_model)35 static int get_params(const struct programmer_cfg *cfg,
36 bool *boardenable, bool *boardmismatch,
37 bool *force_laptop, bool *not_a_laptop,
38 char **board_vendor, char **board_model)
39 {
40 char *arg;
41
42 /* default values. */
43 *force_laptop = false;
44 *not_a_laptop = false;
45 *board_vendor = NULL;
46 *board_model = NULL;
47
48 arg = extract_programmer_param_str(cfg, "boardenable");
49 if (arg && !strcmp(arg,"force")) {
50 *boardenable = true;
51 } else if (arg && !strlen(arg)) {
52 msg_perr("Missing argument for boardenable.\n");
53 free(arg);
54 return 1;
55 } else if (arg) {
56 msg_perr("Unknown argument for boardenable: %s\n", arg);
57 free(arg);
58 return 1;
59 }
60 free(arg);
61
62 arg = extract_programmer_param_str(cfg, "boardmismatch");
63 if (arg && !strcmp(arg,"force")) {
64 *boardmismatch = true;
65 } else if (arg && !strlen(arg)) {
66 msg_perr("Missing argument for boardmismatch.\n");
67 free(arg);
68 return 1;
69 } else if (arg) {
70 msg_perr("Unknown argument for boardmismatch: %s\n", arg);
71 free(arg);
72 return 1;
73 }
74 free(arg);
75
76 arg = extract_programmer_param_str(cfg, "laptop");
77 if (arg && !strcmp(arg, "force_I_want_a_brick"))
78 *force_laptop = true;
79 else if (arg && !strcmp(arg, "this_is_not_a_laptop"))
80 *not_a_laptop = true;
81 else if (arg && !strlen(arg)) {
82 msg_perr("Missing argument for laptop.\n");
83 free(arg);
84 return 1;
85 } else if (arg) {
86 msg_perr("Unknown argument for laptop: %s\n", arg);
87 free(arg);
88 return 1;
89 }
90 free(arg);
91
92 arg = extract_programmer_param_str(cfg, "mainboard");
93 if (arg && strlen(arg)) {
94 if (board_parse_parameter(arg, board_vendor, board_model)) {
95 free(arg);
96 return 1;
97 }
98 } else if (arg && !strlen(arg)) {
99 msg_perr("Missing argument for mainboard.\n");
100 free(arg);
101 return 1;
102 }
103 free(arg);
104
105 return 0;
106 }
107
report_nonwl_laptop_detected(const struct board_cfg * bcfg)108 static void report_nonwl_laptop_detected(const struct board_cfg *bcfg)
109 {
110 const int is_laptop = bcfg->is_laptop;
111 const bool laptop_ok = bcfg->laptop_ok;
112
113 if (!is_laptop || laptop_ok)
114 return;
115
116 msg_pinfo("========================================================================\n");
117 if (is_laptop == 1) {
118 msg_pinfo("You seem to be running flashrom on an unknown laptop. Some\n"
119 "internal buses have been disabled for safety reasons.\n\n");
120 } else {
121 msg_pinfo("You may be running flashrom on an unknown laptop. We could not\n"
122 "detect this for sure because your vendor has not set up the SMBIOS\n"
123 "tables correctly. Some internal buses have been disabled for\n"
124 "safety reasons. You can enforce using all buses by adding\n"
125 " -p internal:laptop=this_is_not_a_laptop\n"
126 "to the command line, but please read the following warning if you\n"
127 "are not sure.\n\n");
128 }
129 msg_perr("Laptops, notebooks and netbooks are difficult to support and we\n"
130 "recommend to use the vendor flashing utility. The embedded controller\n"
131 "(EC) in these machines often interacts badly with flashing.\n"
132 "See the manpage and https://flashrom.org/Laptops for details.\n\n"
133 "If flash is shared with the EC, erase is guaranteed to brick your laptop\n"
134 "and write may brick your laptop.\n"
135 "Read and probe may irritate your EC and cause fan failure, backlight\n"
136 "failure and sudden poweroff.\n"
137 "You have been warned.\n"
138 "========================================================================\n");
139 }
140
internal_init(const struct programmer_cfg * cfg)141 int internal_init(const struct programmer_cfg *cfg)
142 {
143 int ret = 0;
144 bool force_laptop;
145 bool not_a_laptop;
146 char *board_vendor;
147 char *board_model;
148 #if defined(__i386__) || defined(__x86_64__)
149 const char *cb_vendor = NULL;
150 const char *cb_model = NULL;
151 #endif
152 bool force_boardenable = false;
153 struct board_cfg bcfg = {0};
154
155 ret = get_params(cfg,
156 &force_boardenable, &force_boardmismatch,
157 &force_laptop, ¬_a_laptop,
158 &board_vendor, &board_model);
159 if (ret)
160 return ret;
161
162 /* Default to Parallel/LPC/FWH flash devices. If a known host controller
163 * is found, the host controller init routine sets the
164 * internal_buses_supported bitfield.
165 */
166 internal_buses_supported = BUS_NONSPI;
167
168 if (try_mtd(cfg) == 0) {
169 ret = 0;
170 goto internal_init_exit;
171 }
172
173 #if (defined (__i386__) || defined (__x86_64__) || defined(__amd64__))
174 /* Initialize PCI access for flash enables */
175 if (pci_init_common() != 0) {
176 ret = 1;
177 goto internal_init_exit;
178 }
179 #endif // if IS_X86
180
181 if (processor_flash_enable()) {
182 msg_perr("Processor detection/init failed.\n"
183 "Aborting.\n");
184 ret = 1;
185 goto internal_init_exit;
186 }
187
188 #if defined(__i386__) || defined(__x86_64__)
189 if (rget_io_perms()) {
190 ret = 1;
191 goto internal_init_exit;
192 }
193
194 if ((cb_parse_table(&cb_vendor, &cb_model) == 0) && (board_vendor != NULL) && (board_model != NULL)) {
195 if (strcasecmp(board_vendor, cb_vendor) || strcasecmp(board_model, cb_model)) {
196 msg_pwarn("Warning: The mainboard IDs set by -p internal:mainboard (%s:%s) do not\n"
197 " match the current coreboot IDs of the mainboard (%s:%s).\n",
198 board_vendor, board_model, cb_vendor, cb_model);
199 if (!force_boardmismatch) {
200 ret = 1;
201 goto internal_init_exit;
202 }
203 msg_pinfo("Continuing anyway.\n");
204 }
205 }
206
207 bcfg.is_laptop = 2; /* Assume that we don't know by default. */
208
209 dmi_init(&bcfg.is_laptop);
210
211 /* In case Super I/O probing would cause pretty explosions. */
212 board_handle_before_superio(&bcfg, force_boardenable);
213
214 /* Probe for the Super I/O chip and fill global struct superio. */
215 probe_superio();
216 #else
217 /* FIXME: Enable cbtable searching on all non-x86 platforms supported
218 * by coreboot.
219 * FIXME: Find a replacement for DMI on non-x86.
220 * FIXME: Enable Super I/O probing once port I/O is possible.
221 */
222 #endif
223
224 /* Check laptop whitelist. */
225 board_handle_before_laptop(&bcfg, force_boardenable);
226
227 /*
228 * Disable all internal buses by default if we are not sure
229 * this isn't a laptop. Board-enables may override this,
230 * non-legacy buses (SPI and opaque atm) are probed anyway.
231 */
232 if (bcfg.is_laptop && !(bcfg.laptop_ok || force_laptop || (not_a_laptop && bcfg.is_laptop == 2)))
233 internal_buses_supported = BUS_NONE;
234
235 /* try to enable it. Failure IS an option, since not all motherboards
236 * really need this to be done, etc., etc.
237 */
238 struct programmer_cfg icfg = *cfg;
239 icfg.bcfg = &bcfg;
240 ret = chipset_flash_enable(&icfg);
241 if (ret == -2) {
242 msg_perr("WARNING: No chipset found. Flash detection "
243 "will most likely fail.\n");
244 } else if (ret == ERROR_FLASHROM_FATAL) {
245 goto internal_init_exit;
246 }
247
248 #if defined(__i386__) || defined(__x86_64__)
249 /* Probe unconditionally for ITE Super I/O chips. This enables LPC->SPI translation on IT87* and
250 * parallel writes on IT8705F. Also, this handles the manual chip select for Gigabyte's DualBIOS. */
251 init_superio_ite(cfg);
252
253 if (board_flash_enable(&bcfg,
254 board_vendor, board_model, cb_vendor, cb_model, force_boardenable)) {
255 msg_perr("Aborting to be safe.\n");
256 ret = 1;
257 goto internal_init_exit;
258 }
259 #endif
260
261 internal_par_init(internal_buses_supported);
262
263 /* Report if a non-whitelisted laptop is detected that likely uses a legacy bus. */
264 report_nonwl_laptop_detected(&bcfg);
265
266 ret = 0;
267
268 internal_init_exit:
269 free(board_vendor);
270 free(board_model);
271
272 return ret;
273 }
274
275 const struct programmer_entry programmer_internal = {
276 .name = "internal",
277 .type = OTHER,
278 .devs.note = NULL,
279 .init = internal_init,
280 };
281