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