1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * Mellanox firmware image verification plugin
29  */
30 
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <sys/sysmacros.h>
38 #include <fcntl.h>
39 #include <sys/condvar.h>
40 #include <string.h>
41 #include <strings.h>
42 
43 #include <sys/byteorder.h>
44 
45 #include <libintl.h> /* for gettext(3c) */
46 
47 #include <fwflash/fwflash.h>
48 #include "../hdrs/MELLANOX.h"
49 #include "../hdrs/tavor_ib.h"
50 
51 char vendor[] = "MELLANOX\0";
52 
53 extern int errno;
54 extern struct vrfyplugin *verifier;
55 
56 
57 /* required functions for this plugin */
58 int vendorvrfy(struct devicelist *devicenode);
59 
60 
61 /* helper functions */
62 static int check_guid_ptr(uint8_t *data);
63 
64 
65 int
66 vendorvrfy(struct devicelist *devicenode)
67 {
68 	struct ib_encap_ident	*encap;
69 	uint32_t	sector_sz;
70 	int		*firmware;
71 	uint32_t	vp_fia, vs_fia;
72 	uint32_t	vp_imginfo, vs_imginfo;
73 	struct mlx_xps	*vps;
74 	uint8_t		*vfi;
75 	int		i = 0, a, b, c, d;
76 	char		temppsid[17];
77 	char		rawpsid[16];
78 	int		offset;
79 
80 	encap = (struct ib_encap_ident *)devicenode->ident->encap_ident;
81 
82 	/*
83 	 * NOTE that since verifier->fwimage is an array of ints,
84 	 * we have to divide our actual desired number by 4 to get
85 	 * the right data.
86 	 */
87 	firmware = verifier->fwimage;
88 
89 	/*
90 	 * The actual location of log2_sector_sz can be calculated
91 	 * by adding 0x32 to the value that is written in the
92 	 * log2_sector_sz_ptr field.  The log2_sector_sz_ptr is located
93 	 * at 0x16 byte offset in Invariant Sector.
94 	 */
95 	offset = FLASH_IS_SECTOR_SIZE_OFFSET +
96 	    MLXSWAPBITS32(firmware[FLASH_IS_SECT_SIZE_PTR/4]);
97 
98 	sector_sz = 1 << MLXSWAPBITS32(firmware[offset/4]);
99 
100 	if (sector_sz != encap->sector_sz) {
101 		logmsg(MSG_ERROR,
102 		    gettext("%s firmware image verifier: "
103 		    "Invariant Sector is invalid\n"), verifier->vendor);
104 		logmsg(MSG_ERROR, gettext("Mis-match in sector size: "
105 		    "device's 0x%X file 0x%X\n"), encap->sector_sz, sector_sz);
106 		logmsg(MSG_ERROR, gettext("Firmware image file is not "
107 		    "appropriate for this device.\n"));
108 		/* this is fatal */
109 		return (FWFLASH_FAILURE);
110 	}
111 
112 	/* now verify primary pointer sector */
113 	if ((vps = calloc(1, sizeof (struct mlx_xps))) == NULL) {
114 		logmsg(MSG_ERROR,
115 		    gettext("%s firmware image verifier: "
116 		    "Unable to allocate memory for Primary Pointer "
117 		    "Sector verification\n"), verifier->vendor);
118 		return (FWFLASH_FAILURE);
119 	}
120 	bcopy(&firmware[sector_sz / 4], vps, sizeof (struct mlx_xps));
121 	if ((MLXSWAPBITS32(vps->signature) != FLASH_PS_SIGNATURE) ||
122 	    (vps->xpsresv3 != 0)) {
123 		logmsg(MSG_ERROR,
124 		    gettext("%s firmware image verifier: "
125 		    "Primary Pointer Sector is invalid\n"),
126 		    verifier->vendor);
127 	}
128 	vp_fia = MLXSWAPBITS32(vps->fia);
129 
130 	/*
131 	 * A slight diversion - check the PSID in the last
132 	 * 16 bytes of the first 256bytes in the xPS sectors.
133 	 * This will give us our part number to match. If the
134 	 * part number in the image doesn't match the part number
135 	 * in the encap_ident info (and pn_len > 0) then we reject
136 	 * this image as being incompatible with the HCA.
137 	 *
138 	 * In this bit we're only checking the info.mlx_psid field
139 	 * of the primary image in the on-disk image. If that's
140 	 * invalid we reject the image.
141 	 */
142 
143 	bzero(temppsid, 17);
144 	bcopy(vps->vsdpsid+0xd0, &rawpsid, 16);
145 
146 #if defined(_LITTLE_ENDIAN)
147 	for (i = 0; i < 16; i += 4) {
148 		temppsid[i]   = rawpsid[i+3];
149 		temppsid[i+1] = rawpsid[i+2];
150 		temppsid[i+2] = rawpsid[i+1];
151 		temppsid[i+3] = rawpsid[i];
152 	}
153 	logmsg(MSG_INFO,
154 	    "tavor: have raw '%s', want munged '%s'\n",
155 	    rawpsid, temppsid);
156 #else
157 	bcopy(vps->vsdpsid+0xd0, &temppsid, 16);
158 #endif
159 	logmsg(MSG_INFO, "tavor_vrfy: PSID file '%s' HCA's PSID '%s'\n",
160 	    (temppsid != NULL) ? temppsid : "(null)",
161 	    (encap->info.mlx_psid != NULL) ? encap->info.mlx_psid : "(null)");
162 
163 	if (encap->info.mlx_psid != NULL) {
164 		int resp;
165 		if (strncmp(encap->info.mlx_psid, temppsid, 16) != 0) {
166 			logmsg(MSG_ERROR,
167 			    gettext("%s firmware image verifier: "
168 			    "firmware image file %s is not appropriate "
169 			    "for device "
170 			    "%s (PSID file %s vs PSID device %s)\n"),
171 			    verifier->vendor, verifier->imgfile,
172 			    devicenode->drvname,
173 			    ((temppsid != NULL) ? temppsid : "(null)"),
174 			    encap->info.mlx_psid);
175 
176 			logmsg(MSG_ERROR,
177 			    gettext("Do you want to continue? (Y/N): "));
178 			(void) fflush(stdin);
179 			resp = getchar();
180 			if (resp != 'Y' && resp != 'y') {
181 				free(vps);
182 				logmsg(MSG_ERROR, gettext("Not proceeding with "
183 				    "flash operation of %s on %s\n"),
184 				    verifier->imgfile, devicenode->drvname);
185 				return (FWFLASH_FAILURE);
186 			}
187 		} else {
188 			logmsg(MSG_INFO,
189 			    "%s firmware image verifier: HCA PSID (%s) "
190 			    "matches firmware image %s's PSID\n",
191 			    verifier->vendor,
192 			    encap->info.mlx_psid,
193 			    verifier->imgfile);
194 		}
195 	}
196 
197 
198 	/* now verify secondary pointer sector */
199 	bzero(vps, sizeof (struct mlx_xps));
200 
201 	bcopy(&firmware[sector_sz / 2], vps, sizeof (struct mlx_xps));
202 	if ((MLXSWAPBITS32(vps->signature) != FLASH_PS_SIGNATURE) ||
203 	    (vps->xpsresv3 != 0)) {
204 		logmsg(MSG_ERROR,
205 		    gettext("%s firmware image verifier: "
206 		    "Secondary Pointer Sector is invalid\n"),
207 		    verifier->vendor);
208 	}
209 	vs_fia = MLXSWAPBITS32(vps->fia);
210 
211 	(void) free(vps);
212 
213 	if ((vfi = calloc(1, sector_sz)) == NULL) {
214 		logmsg(MSG_ERROR,
215 		    gettext("%s firmware image verifier: "
216 		    "Unable to allocate space for Primary "
217 		    "Firmware Image verification\n"),
218 		    verifier->vendor);
219 		return (FWFLASH_FAILURE);
220 	}
221 	bcopy(&firmware[vp_fia / 4], vfi, sector_sz);
222 	bcopy(&vfi[XFI_IMGINFO_OFFSET], &i, 4);
223 	vp_imginfo = MLXSWAPBITS32(i);
224 
225 	/* for readability only */
226 	a = (vp_imginfo & 0xff000000) >> 24;
227 	b = (vp_imginfo & 0x00ff0000) >> 16;
228 	c = (vp_imginfo & 0x0000ff00) >> 8;
229 	d = (vp_imginfo & 0x000000ff);
230 
231 	/*
232 	 * It appears to be the case (empirically) that this particular
233 	 * check condition for ImageInfoPtr doesn't hold for A1 firmware
234 	 * images. So if the ((a+b+c+d)%0x100) fails, don't worry unless
235 	 * the contents of the GUID section do not match the Mellanox
236 	 * default GUIDs 2c9000100d05[0123]. The A2++ images also have
237 	 * these default GUIDS.
238 	 *
239 	 * Unfortunately we can't depend on the hwrev field of the image's
240 	 * Invariant Sector for another level of confirmation, since A2++
241 	 * images seem to have that field set to 0xa1 as well as the A1
242 	 * images. Annoying!
243 	 */
244 
245 	if ((((a+b+c+d) % 0x100) == 0) &&
246 	    (vp_imginfo != 0x00000000)) {
247 		logmsg(MSG_INFO,
248 		    "%s firmware image verifier: "
249 		    "Primary Firmware Image Info pointer is valid\n",
250 		    verifier->vendor);
251 	} else {
252 
253 		logmsg(MSG_INFO,
254 		    gettext("%s firmware image verifier: "
255 		    "Primary Firmware Image Info pointer is invalid "
256 		    "(0x%04x)\nChecking GUID section.....\n"),
257 		    verifier->vendor, vp_imginfo);
258 
259 		if (check_guid_ptr(vfi) == FWFLASH_FAILURE) {
260 			logmsg(MSG_INFO,
261 			    gettext("%s firmware image verifier: "
262 			    "Primary Firmware Image GUID section "
263 			    "is invalid\n"),
264 			    verifier->vendor);
265 			i = 1;
266 		} else {
267 			logmsg(MSG_INFO,
268 			    "%s firmware image verifier: "
269 			    "Primary GUID section is ok\n",
270 			    verifier->vendor);
271 		}
272 
273 	}
274 
275 	bzero(vfi, sector_sz);
276 	bcopy(&firmware[vs_fia / 4], vfi, sector_sz);
277 
278 	bcopy(&vfi[XFI_IMGINFO_OFFSET], &i, 4);
279 	vs_imginfo = MLXSWAPBITS32(i);
280 
281 	/* for readability only */
282 	a = (vs_imginfo & 0xff000000) >> 24;
283 	b = (vs_imginfo & 0x00ff0000) >> 16;
284 	c = (vs_imginfo & 0x0000ff00) >> 8;
285 	d = (vs_imginfo & 0x000000ff);
286 
287 	if ((((a+b+c+d) % 0x100) == 0) &&
288 	    (vs_imginfo != 0x00000000)) {
289 		logmsg(MSG_INFO,
290 		    "%s firmware image verifier: "
291 		    "Secondary Firmware Image Info pointer is valid\n",
292 		    verifier->vendor);
293 	} else {
294 		logmsg(MSG_INFO,
295 		    gettext("%s firmware image verifier: "
296 		    "Secondary Firmware Image Info pointer is invalid "
297 		    "(0x%04x)\nChecking GUID section.....\n"),
298 		    verifier->vendor, vp_imginfo);
299 
300 		if (check_guid_ptr(vfi) == FWFLASH_FAILURE) {
301 			logmsg(MSG_INFO,
302 			    gettext("%s firmware image verifier: "
303 			    "Secondary Firmware Image GUID section "
304 			    "is invalid\n"),
305 			    verifier->vendor);
306 			i++;
307 		}
308 	}
309 
310 	free(vfi);
311 
312 	if (i == 2)
313 		logmsg(MSG_WARN, gettext("%s firmware image verifier: "
314 		    "FAILED\n"), verifier->vendor);
315 
316 	return ((i == 2) ? (FWFLASH_FAILURE) : (FWFLASH_SUCCESS));
317 }
318 
319 
320 /*
321  * Very simple function - we're given an array of bytes,
322  * we know that we need to read the value at offset FLASH_GUID_PTR
323  * and jump to that location to read 4x uint64_t of (hopefully)
324  * GUID data. If we can read that data, and it matches the default
325  * Mellanox GUIDs, then we return success. We need all 4 default
326  * GUIDs to match otherwise we return failure.
327  */
328 static int
329 check_guid_ptr(uint8_t *data)
330 {
331 	struct mlx_xfi	xfisect;
332 	struct mlx_guid_sect	guidsect;
333 
334 	bcopy(data, &xfisect, sizeof (xfisect));
335 	bcopy(&data[MLXSWAPBITS32(xfisect.nguidptr) - 16], &guidsect,
336 	    GUIDSECTION_SZ);
337 
338 	logmsg(MSG_INFO, "nodeguid:  %0llx\n",
339 	    MLXSWAPBITS64(guidsect.nodeguid));
340 	logmsg(MSG_INFO, "port1guid: %0llx\n",
341 	    MLXSWAPBITS64(guidsect.port1guid));
342 	logmsg(MSG_INFO, "port2guid: %0llx\n",
343 	    MLXSWAPBITS64(guidsect.port2guid));
344 	logmsg(MSG_INFO, "sysimguid: %0llx\n",
345 	    MLXSWAPBITS64(guidsect.sysimguid));
346 
347 	if ((MLXSWAPBITS64(guidsect.nodeguid) == MLX_DEFAULT_NODE_GUID) &&
348 	    (MLXSWAPBITS64(guidsect.port1guid) == MLX_DEFAULT_P1_GUID) &&
349 	    (MLXSWAPBITS64(guidsect.port2guid) == MLX_DEFAULT_P2_GUID) &&
350 	    ((MLXSWAPBITS64(guidsect.sysimguid) == MLX_DEFAULT_SYSIMG_GUID) ||
351 	    (MLXSWAPBITS64(guidsect.sysimguid) == MLX_DEFAULT_NODE_GUID)) ||
352 	    ((((MLXSWAPBITS64(guidsect.nodeguid) & HIGHBITS64) >> 40)
353 	    == MLX_OUI) ||
354 	    (((MLXSWAPBITS64(guidsect.port1guid) & HIGHBITS64) >> 40)
355 	    == MLX_OUI) ||
356 	    (((MLXSWAPBITS64(guidsect.port2guid) & HIGHBITS64) >> 40)
357 	    == MLX_OUI) ||
358 	    (((MLXSWAPBITS64(guidsect.sysimguid) & HIGHBITS64) >> 40)
359 	    == MLX_OUI))) {
360 		return (FWFLASH_SUCCESS);
361 	} else {
362 		return (FWFLASH_FAILURE);
363 	}
364 }
365