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 #include <sys/stat.h>
28 #include <sys/param.h>
29 #include <sys/mman.h>
30 #include <sys/endian.h>
31
32 #include <errno.h>
33 #include <err.h>
34 #include <fcntl.h>
35 #include <stdbool.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40
41 #include "mpsutil.h"
42
43 MPS_TABLE(top, flash);
44
45 static int
flash_save(int argc,char ** argv)46 flash_save(int argc, char **argv)
47 {
48 const char *firmware_file;
49 unsigned char *firmware_buffer = NULL;
50 int error, fd, size;
51 bool bios = false;
52 ssize_t written = 0, ret = 0;
53
54 if (argc < 2) {
55 warnx("missing argument: expecting 'firmware' or bios'");
56 return (EINVAL);
57 }
58
59 if (strcmp(argv[1], "bios") == 0) {
60 bios = true;
61 } else if (strcmp(argv[1], "firmware") != 0) {
62 warnx("Invalid argument '%s', expecting 'firmware' or 'bios'",
63 argv[1]);
64 }
65
66 if (argc > 4) {
67 warnx("save %s: extra arguments", argv[1]);
68 return (EINVAL);
69 }
70
71 firmware_file = argv[1];
72 if (argc == 3) {
73 firmware_file = argv[2];
74 }
75
76 fd = mps_open(mps_unit);
77 if (fd < 0) {
78 error = errno;
79 warn("mps_open");
80 return (error);
81 }
82
83 if ((size = mps_firmware_get(fd, &firmware_buffer, bios)) < 0) {
84 warnx("Fail to save %s", argv[1]);
85 close(fd);
86 return (1);
87 }
88
89 close(fd);
90 if (size > 0) {
91 fd = open(firmware_file, O_CREAT | O_TRUNC | O_RDWR, 0644);
92 if (fd <0) {
93 error = errno;
94 warn("open");
95 free(firmware_buffer);
96 return (error);
97 }
98 while (written != size) {
99 if ((ret = write(fd, firmware_buffer + written, size - written)) <0) {
100 error = errno;
101 warn("write");
102 free(firmware_buffer);
103 close(fd);
104 return (error);
105 }
106 written += ret;
107 }
108 close(fd);
109 }
110 free(firmware_buffer);
111 printf("%s successfully saved as %s\n", argv[1], firmware_file);
112 return (0);
113 }
114
115 MPS_COMMAND(flash, save, flash_save, "[firmware|bios] [file]",
116 "Save firmware/bios into a file");
117
118 static int
flash_update(int argc,char ** argv)119 flash_update(int argc, char **argv)
120 {
121 int error, fd;
122 unsigned char *mem = NULL;
123 struct stat st;
124 bool bios = false;
125 MPI2_FW_IMAGE_HEADER *fwheader;
126 MPI2_IOC_FACTS_REPLY *facts;
127
128 if (argc < 2) {
129 warnx("missing argument: expecting 'firmware' or bios'");
130 return (EINVAL);
131 }
132
133 if (strcmp(argv[1], "bios") == 0) {
134 bios = true;
135 } else if (strcmp(argv[1], "firmware") != 0) {
136 warnx("Invalid argument '%s', expecting 'firmware' or 'bios'",
137 argv[1]);
138 }
139
140 if (argc > 4) {
141 warnx("update firmware: extra arguments");
142 return (EINVAL);
143 }
144
145 if (argc != 3) {
146 warnx("no firmware specified");
147 return (EINVAL);
148 }
149
150 if (stat(argv[2], &st) == -1) {
151 error = errno;
152 warn("stat");
153 return (error);
154 }
155
156 fd = open(argv[2], O_RDONLY);
157 if (fd < 0) {
158 error = errno;
159 warn("open");
160 return (error);
161 }
162
163 mem = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
164 if (mem == MAP_FAILED) {
165 error = errno;
166 warn("mmap");
167 close(fd);
168 return (error);
169 }
170 close(fd);
171
172 fd = mps_open(mps_unit);
173 if (fd < 0) {
174 error = errno;
175 warn("mps_open");
176 munmap(mem, st.st_size);
177 return (error);
178 }
179
180 if ((facts = mps_get_iocfacts(fd)) == NULL) {
181 warnx("could not get controller IOCFacts\n");
182 munmap(mem, st.st_size);
183 close(fd);
184 return (EINVAL);
185 }
186
187 if (bios) {
188 /* Check boot record magic number */
189 if (((mem[0x01]<<8) + mem[0x00]) != 0xaa55) {
190 warnx("Invalid bios: no boot record magic number");
191 munmap(mem, st.st_size);
192 close(fd);
193 free(facts);
194 return (1);
195 }
196 if ((st.st_size % 512) != 0) {
197 warnx("Invalid bios: size not a multiple of 512");
198 munmap(mem, st.st_size);
199 close(fd);
200 free(facts);
201 return (1);
202 }
203 } else {
204 fwheader = (MPI2_FW_IMAGE_HEADER *)mem;
205 if (le16toh(fwheader->VendorID) != MPI2_MFGPAGE_VENDORID_LSI) {
206 warnx("Invalid firmware:");
207 warnx(" Expected Vendor ID: %04x",
208 MPI2_MFGPAGE_VENDORID_LSI);
209 warnx(" Image Vendor ID: %04x", le16toh(fwheader->VendorID));
210 munmap(mem, st.st_size);
211 close(fd);
212 free(facts);
213 return (1);
214 }
215
216 if (le16toh(fwheader->ProductID) != facts->ProductID) {
217 warnx("Invalid image:");
218 warnx(" Expected Product ID: %04x", facts->ProductID);
219 warnx(" Image Product ID: %04x", le16toh(fwheader->ProductID));
220 munmap(mem, st.st_size);
221 close(fd);
222 free(facts);
223 return (1);
224 }
225 }
226
227 printf("Updating %s...\n", argv[1]);
228 if (mps_firmware_send(fd, mem, st.st_size, bios) < 0) {
229 warnx("Fail to update %s", argv[1]);
230 munmap(mem, st.st_size);
231 close(fd);
232 free(facts);
233 return (1);
234 }
235
236 munmap(mem, st.st_size);
237 close(fd);
238 free(facts);
239 printf("%s successfully updated\n", argv[1]);
240 return (0);
241 }
242
243 MPS_COMMAND(flash, update, flash_update, "[firmware|bios] file",
244 "Update firmware/bios");
245