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