1 /*-
2 * Copyright (c) 2015 Baptiste Daroussin <bapt@FreeBSD.org>
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26 #include <sys/cdefs.h>
27 __RCSID("$FreeBSD: stable/12/usr.sbin/mpsutil/mps_flash.c 371121 2021-12-01 19:00:23Z mav $");
28
29 #include <sys/stat.h>
30 #include <sys/param.h>
31 #include <sys/mman.h>
32 #include <sys/endian.h>
33
34 #include <errno.h>
35 #include <err.h>
36 #include <fcntl.h>
37 #include <stdbool.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42
43 #include "mpsutil.h"
44
45 MPS_TABLE(top, flash);
46
47 static int
flash_save(int argc,char ** argv)48 flash_save(int argc, char **argv)
49 {
50 const char *firmware_file;
51 unsigned char *firmware_buffer = NULL;
52 int error, fd, size;
53 bool bios = false;
54 ssize_t written = 0, ret = 0;
55
56 if (argc < 2) {
57 warnx("missing argument: expecting 'firmware' or bios'");
58 return (EINVAL);
59 }
60
61 if (strcmp(argv[1], "bios") == 0) {
62 bios = true;
63 } else if (strcmp(argv[1], "firmware") != 0) {
64 warnx("Invalid argument '%s', expecting 'firmware' or 'bios'",
65 argv[1]);
66 }
67
68 if (argc > 4) {
69 warnx("save %s: extra arguments", argv[1]);
70 return (EINVAL);
71 }
72
73 firmware_file = argv[1];
74 if (argc == 3) {
75 firmware_file = argv[2];
76 }
77
78 fd = mps_open(mps_unit);
79 if (fd < 0) {
80 error = errno;
81 warn("mps_open");
82 return (error);
83 }
84
85 if ((size = mps_firmware_get(fd, &firmware_buffer, bios)) < 0) {
86 warnx("Fail to save %s", argv[1]);
87 close(fd);
88 return (1);
89 }
90
91 close(fd);
92 if (size > 0) {
93 fd = open(firmware_file, O_CREAT | O_TRUNC | O_RDWR, 0644);
94 if (fd <0) {
95 error = errno;
96 warn("open");
97 free(firmware_buffer);
98 return (error);
99 }
100 while (written != size) {
101 if ((ret = write(fd, firmware_buffer + written, size - written)) <0) {
102 error = errno;
103 warn("write");
104 free(firmware_buffer);
105 close(fd);
106 return (error);
107 }
108 written += ret;
109 }
110 close(fd);
111 }
112 free(firmware_buffer);
113 printf("%s successfully saved as %s\n", argv[1], firmware_file);
114 return (0);
115 }
116
117 MPS_COMMAND(flash, save, flash_save, "[firmware|bios] [file]",
118 "Save firmware/bios into a file");
119
120 static int
flash_update(int argc,char ** argv)121 flash_update(int argc, char **argv)
122 {
123 int error, fd;
124 unsigned char *mem = NULL;
125 struct stat st;
126 bool bios = false;
127 MPI2_FW_IMAGE_HEADER *fwheader;
128 MPI2_IOC_FACTS_REPLY *facts;
129
130 if (argc < 2) {
131 warnx("missing argument: expecting 'firmware' or bios'");
132 return (EINVAL);
133 }
134
135 if (strcmp(argv[1], "bios") == 0) {
136 bios = true;
137 } else if (strcmp(argv[1], "firmware") != 0) {
138 warnx("Invalid argument '%s', expecting 'firmware' or 'bios'",
139 argv[1]);
140 }
141
142 if (argc > 4) {
143 warnx("update firmware: extra arguments");
144 return (EINVAL);
145 }
146
147 if (argc != 3) {
148 warnx("no firmware specified");
149 return (EINVAL);
150 }
151
152 if (stat(argv[2], &st) == -1) {
153 error = errno;
154 warn("stat");
155 return (error);
156 }
157
158 fd = open(argv[2], O_RDONLY);
159 if (fd < 0) {
160 error = errno;
161 warn("open");
162 return (error);
163 }
164
165 mem = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
166 if (mem == MAP_FAILED) {
167 error = errno;
168 warn("mmap");
169 close(fd);
170 return (error);
171 }
172 close(fd);
173
174 fd = mps_open(mps_unit);
175 if (fd < 0) {
176 error = errno;
177 warn("mps_open");
178 munmap(mem, st.st_size);
179 return (error);
180 }
181
182 if ((facts = mps_get_iocfacts(fd)) == NULL) {
183 warnx("could not get controller IOCFacts\n");
184 munmap(mem, st.st_size);
185 close(fd);
186 return (EINVAL);
187 }
188
189 if (bios) {
190 /* Check boot record magic number */
191 if (((mem[0x01]<<8) + mem[0x00]) != 0xaa55) {
192 warnx("Invalid bios: no boot record magic number");
193 munmap(mem, st.st_size);
194 close(fd);
195 free(facts);
196 return (1);
197 }
198 if ((st.st_size % 512) != 0) {
199 warnx("Invalid bios: size not a multiple of 512");
200 munmap(mem, st.st_size);
201 close(fd);
202 free(facts);
203 return (1);
204 }
205 } else {
206 fwheader = (MPI2_FW_IMAGE_HEADER *)mem;
207 if (le16toh(fwheader->VendorID) != MPI2_MFGPAGE_VENDORID_LSI) {
208 warnx("Invalid firmware:");
209 warnx(" Expected Vendor ID: %04x",
210 MPI2_MFGPAGE_VENDORID_LSI);
211 warnx(" Image Vendor ID: %04x", le16toh(fwheader->VendorID));
212 munmap(mem, st.st_size);
213 close(fd);
214 free(facts);
215 return (1);
216 }
217
218 if (le16toh(fwheader->ProductID) != facts->ProductID) {
219 warnx("Invalid image:");
220 warnx(" Expected Product ID: %04x", facts->ProductID);
221 warnx(" Image Product ID: %04x", le16toh(fwheader->ProductID));
222 munmap(mem, st.st_size);
223 close(fd);
224 free(facts);
225 return (1);
226 }
227 }
228
229 printf("Updating %s...\n", argv[1]);
230 if (mps_firmware_send(fd, mem, st.st_size, bios) < 0) {
231 warnx("Fail to update %s", argv[1]);
232 munmap(mem, st.st_size);
233 close(fd);
234 free(facts);
235 return (1);
236 }
237
238 munmap(mem, st.st_size);
239 close(fd);
240 free(facts);
241 printf("%s successfully updated\n", argv[1]);
242 return (0);
243 }
244
245 MPS_COMMAND(flash, update, flash_update, "[firmware|bios] file",
246 "Update firmware/bios");
247