]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/mpsutil/mps_flash.c
Merge llvm-project release/14.x llvmorg-14.0.5-0-gc12386ae247c
[FreeBSD/FreeBSD.git] / usr.sbin / mpsutil / mps_flash.c
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$");
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
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
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");