1 /* 2 * SPDX-FileCopyrightText: Copyright (c) 2021-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 * SPDX-License-Identifier: MIT 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be included in 13 * all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 */ 23 24 /*! 25 * KernelGsp functions and helpers for parsing FWSEC ucode from a 26 * VBIOS image. 27 * 28 * TODO: JIRA CORERM-4685: Consider moving stuff in here to, e.g. KernelVbios 29 */ 30 31 #include "gpu/gsp/kernel_gsp.h" 32 33 #include "gpu/mem_mgr/mem_mgr.h" 34 #include "gpu/gpu.h" 35 #include "gpu/vbios/bios_types.h" 36 #include "gpu/mem_mgr/mem_desc.h" 37 38 // --------------------------------------------------------------------------- 39 // BIOS Information Table (BIT) structures and defines 40 // (header, tokens, falcon ucodes) 41 // --------------------------------------------------------------------------- 42 43 #define BIT_HEADER_ID 0xB8FF 44 #define BIT_HEADER_SIGNATURE 0x00544942 // "BIT\0" 45 #define BIT_HEADER_SIZE_OFFSET 8 46 47 struct BIT_HEADER_V1_00 48 { 49 bios_U016 Id; 50 bios_U032 Signature; 51 bios_U016 BCD_Version; 52 bios_U008 HeaderSize; 53 bios_U008 TokenSize; 54 bios_U008 TokenEntries; 55 bios_U008 HeaderChksum; 56 }; 57 #define BIT_HEADER_V1_00_FMT "1w1d1w4b" 58 typedef struct BIT_HEADER_V1_00 BIT_HEADER_V1_00; 59 60 struct BIT_TOKEN_V1_00 61 { 62 bios_U008 TokenId; 63 bios_U008 DataVersion; 64 bios_U016 DataSize; 65 bios_U016 DataPtr; 66 }; 67 #define BIT_TOKEN_V1_00_FMT "2b2w" 68 typedef struct BIT_TOKEN_V1_00 BIT_TOKEN_V1_00; 69 70 #define BIT_TOKEN_BIOSDATA 0x42 71 72 // structure for only version info from BIT_DATA_BIOSDATA_V1 and BIT_DATA_BIOSDATA_V2 73 typedef struct 74 { 75 bios_U032 Version; // BIOS Binary Version Ex. 5.40.00.01.12 = 0x05400001 76 bios_U008 OemVersion; // OEM Version Number Ex. 5.40.00.01.12 = 0x12 77 } BIT_DATA_BIOSDATA_BINVER; 78 79 #define BIT_DATA_BIOSDATA_BINVER_FMT "1d1b" 80 #define BIT_DATA_BIOSDATA_BINVER_SIZE_5 5 81 82 #define BIT_TOKEN_FALCON_DATA 0x70 83 84 typedef struct 85 { 86 bios_U032 FalconUcodeTablePtr; 87 } BIT_DATA_FALCON_DATA_V2; 88 89 #define BIT_DATA_FALCON_DATA_V2_4_FMT "1d" 90 #define BIT_DATA_FALCON_DATA_V2_SIZE_4 4 91 92 typedef struct 93 { 94 bios_U008 Version; 95 bios_U008 HeaderSize; 96 bios_U008 EntrySize; 97 bios_U008 EntryCount; 98 bios_U008 DescVersion; 99 bios_U008 DescSize; 100 } FALCON_UCODE_TABLE_HDR_V1; 101 102 #define FALCON_UCODE_TABLE_HDR_V1_VERSION 1 103 #define FALCON_UCODE_TABLE_HDR_V1_SIZE_6 6 104 #define FALCON_UCODE_TABLE_HDR_V1_6_FMT "6b" 105 106 typedef struct 107 { 108 bios_U008 ApplicationID; 109 bios_U008 TargetID; 110 bios_U032 DescPtr; 111 } FALCON_UCODE_TABLE_ENTRY_V1; 112 113 #define FALCON_UCODE_TABLE_ENTRY_V1_VERSION 1 114 #define FALCON_UCODE_TABLE_ENTRY_V1_SIZE_6 6 115 #define FALCON_UCODE_TABLE_ENTRY_V1_6_FMT "2b1d" 116 117 #define FALCON_UCODE_ENTRY_APPID_FIRMWARE_SEC_LIC 0x05 118 #define FALCON_UCODE_ENTRY_APPID_FWSEC_DBG 0x45 119 #define FALCON_UCODE_ENTRY_APPID_FWSEC_PROD 0x85 120 121 #define NV_BIT_FALCON_UCODE_DESC_HEADER_VDESC_FLAGS_VERSION 0:0 122 #define NV_BIT_FALCON_UCODE_DESC_HEADER_VDESC_FLAGS_VERSION_UNAVAILABLE 0x00 123 #define NV_BIT_FALCON_UCODE_DESC_HEADER_VDESC_FLAGS_VERSION_AVAILABLE 0x01 124 #define NV_BIT_FALCON_UCODE_DESC_HEADER_VDESC_FLAGS_RESERVED 1:1 125 #define NV_BIT_FALCON_UCODE_DESC_HEADER_VDESC_FLAGS_ENCRYPTED 2:2 126 #define NV_BIT_FALCON_UCODE_DESC_HEADER_VDESC_RESERVED 7:3 127 #define NV_BIT_FALCON_UCODE_DESC_HEADER_VDESC_VERSION 15:8 128 #define NV_BIT_FALCON_UCODE_DESC_HEADER_VDESC_VERSION_V1 0x01 129 #define NV_BIT_FALCON_UCODE_DESC_HEADER_VDESC_VERSION_V2 0x02 130 #define NV_BIT_FALCON_UCODE_DESC_HEADER_VDESC_VERSION_V3 0x03 131 #define NV_BIT_FALCON_UCODE_DESC_HEADER_VDESC_VERSION_V4 0x04 132 #define NV_BIT_FALCON_UCODE_DESC_HEADER_VDESC_SIZE 31:16 133 134 typedef struct 135 { 136 bios_U032 vDesc; 137 } FALCON_UCODE_DESC_HEADER; 138 #define FALCON_UCODE_DESC_HEADER_FORMAT "1d" 139 140 typedef struct 141 { 142 FALCON_UCODE_DESC_HEADER Hdr; 143 bios_U032 StoredSize; 144 bios_U032 UncompressedSize; 145 bios_U032 VirtualEntry; 146 bios_U032 InterfaceOffset; 147 bios_U032 IMEMPhysBase; 148 bios_U032 IMEMLoadSize; 149 bios_U032 IMEMVirtBase; 150 bios_U032 IMEMSecBase; 151 bios_U032 IMEMSecSize; 152 bios_U032 DMEMOffset; 153 bios_U032 DMEMPhysBase; 154 bios_U032 DMEMLoadSize; 155 bios_U032 altIMEMLoadSize; 156 bios_U032 altDMEMLoadSize; 157 } FALCON_UCODE_DESC_V2; 158 159 #define FALCON_UCODE_DESC_V2_SIZE_60 60 160 #define FALCON_UCODE_DESC_V2_60_FMT "15d" 161 162 typedef struct { 163 FALCON_UCODE_DESC_HEADER Hdr; 164 bios_U032 StoredSize; 165 bios_U032 PKCDataOffset; 166 bios_U032 InterfaceOffset; 167 bios_U032 IMEMPhysBase; 168 bios_U032 IMEMLoadSize; 169 bios_U032 IMEMVirtBase; 170 bios_U032 DMEMPhysBase; 171 bios_U032 DMEMLoadSize; 172 bios_U016 EngineIdMask; 173 bios_U008 UcodeId; 174 bios_U008 SignatureCount; 175 bios_U016 SignatureVersions; 176 bios_U016 Reserved; 177 } FALCON_UCODE_DESC_V3; 178 179 #define FALCON_UCODE_DESC_V3_SIZE_44 44 180 #define FALCON_UCODE_DESC_V3_44_FMT "9d1w2b2w" 181 #define BCRT30_RSA3K_SIG_SIZE 384 182 183 typedef union 184 { 185 // v1 is unused on platforms supported by GSP-RM 186 FALCON_UCODE_DESC_V2 v2; 187 FALCON_UCODE_DESC_V3 v3; 188 } FALCON_UCODE_DESC_UNION; 189 190 typedef struct FlcnUcodeDescFromBit 191 { 192 NvU32 descVersion; 193 NvU32 descOffset; 194 NvU32 descSize; 195 FALCON_UCODE_DESC_UNION descUnion; 196 } FlcnUcodeDescFromBit; 197 198 199 // --------------------------------------------------------------------------- 200 // Functions for parsing FWSEC falcon ucode from VBIOS image 201 // --------------------------------------------------------------------------- 202 203 /*! 204 * Calculate packed data size based on given data format 205 * 206 * @param[in] format Data format 207 */ 208 static NvU32 209 s_biosStructCalculatePackedSize 210 ( 211 const char *format 212 ) 213 { 214 215 NvU32 packedSize = 0; 216 NvU32 count; 217 char fmt; 218 219 while ((fmt = *format++)) 220 { 221 count = 0; 222 while ((fmt >= '0') && (fmt <= '9')) 223 { 224 count *= 10; 225 count += fmt - '0'; 226 fmt = *format++; 227 } 228 if (count == 0) 229 count = 1; 230 231 switch (fmt) 232 { 233 case 'b': 234 packedSize += count * 1; 235 break; 236 237 case 's': // signed byte 238 packedSize += count * 1; 239 break; 240 241 case 'w': 242 packedSize += count * 2; 243 break; 244 245 case 'd': 246 packedSize += count * 4; 247 break; 248 } 249 } 250 251 return packedSize; 252 } 253 254 /*! 255 * Parse packed little endian data and unpack into padded structure. 256 * 257 * @param[in] packedData Packed little endien data 258 * @param[out] unpackedData Unpacked padded structure 259 * @param[in] format Data format 260 */ 261 static NV_STATUS 262 s_biosUnpackStructure 263 ( 264 const NvU8 *packedData, 265 NvU32 *unpackedData, // out 266 const char *format 267 ) 268 { 269 270 NvU32 count; 271 NvU32 data; 272 char fmt; 273 274 while ((fmt = *format++)) 275 { 276 count = 0; 277 while ((fmt >= '0') && (fmt <= '9')) 278 { 279 count *= 10; 280 count += fmt - '0'; 281 fmt = *format++; 282 } 283 if (count == 0) 284 count = 1; 285 286 while (count--) 287 { 288 switch (fmt) 289 { 290 case 'b': 291 data = *packedData++; 292 break; 293 294 case 's': // signed byte 295 data = *packedData++; 296 if (data & 0x80) 297 data |= ~0xff; 298 break; 299 300 case 'w': 301 data = *packedData++; 302 data |= *packedData++ << 8; 303 break; 304 305 case 'd': 306 data = *packedData++; 307 data |= *packedData++ << 8; 308 data |= *packedData++ << 16; 309 data |= *packedData++ << 24; 310 break; 311 312 default: 313 return NV_ERR_GENERIC; 314 } 315 *unpackedData++ = data; 316 } 317 } 318 319 return NV_OK; 320 } 321 322 /*! 323 * Read packed little endian data and unpack it to padded structure. 324 * 325 * @param[in] pVbiosImg VBIOS image containing packed little endien data 326 * @param[out] pStructure Unpacked padded structure 327 * @param[in] offset Offset within packed data 328 * @param[in] format Data format 329 */ 330 static NV_STATUS 331 s_vbiosReadStructure 332 ( 333 const KernelGspVbiosImg * const pVbiosImg, 334 void *pStructure, // out 335 const NvU32 offset, 336 const char *format 337 ) 338 { 339 340 NvU32 packedSize; 341 NvU32 maxOffset; 342 NvBool bSafe; 343 344 // check for overflow in offset + packedSize 345 packedSize = s_biosStructCalculatePackedSize(format); 346 347 bSafe = portSafeAddU32(offset, packedSize, &maxOffset); 348 if (NV_UNLIKELY(!bSafe || maxOffset > pVbiosImg->biosSize)) 349 { 350 return NV_ERR_INVALID_OFFSET; 351 } 352 353 return s_biosUnpackStructure(pVbiosImg->pImage + offset, pStructure, format); 354 } 355 356 static NvU8 s_vbiosRead8(const KernelGspVbiosImg *pVbiosImg, NvU32 offset, NV_STATUS *pStatus) 357 { 358 bios_U008 data; // ReadStructure expects 'bios' types 359 if (NV_UNLIKELY(*pStatus != NV_OK)) 360 { 361 return 0; 362 } 363 *pStatus = s_vbiosReadStructure(pVbiosImg, &data, offset, "b"); 364 return (NvU8) data; 365 } 366 367 static NvU16 s_vbiosRead16(const KernelGspVbiosImg *pVbiosImg, NvU32 offset, NV_STATUS *pStatus) 368 { 369 bios_U016 data; // ReadStructure expects 'bios' types 370 if (NV_UNLIKELY(*pStatus != NV_OK)) 371 { 372 return 0; 373 } 374 *pStatus = s_vbiosReadStructure(pVbiosImg, &data, offset, "w"); 375 return (NvU16) data; 376 } 377 378 static NvU32 s_vbiosRead32(const KernelGspVbiosImg *pVbiosImg, NvU32 offset, NV_STATUS *pStatus) 379 { 380 bios_U032 data; // ReadStructure expects 'bios' types 381 if (NV_UNLIKELY(*pStatus != NV_OK)) 382 { 383 return 0; 384 } 385 *pStatus = s_vbiosReadStructure(pVbiosImg, &data, offset, "d"); 386 return (NvU32) data; 387 } 388 389 /*! 390 * Find offset of BIT header (BIOS Information Table header) within VBIOS image. 391 * 392 * @param[in] pVbiosImg VBIOS image 393 * @param[out] pBitAddr Offset of BIT header (if found) 394 */ 395 static NV_STATUS 396 s_vbiosFindBitHeader 397 ( 398 const KernelGspVbiosImg * const pVbiosImg, 399 NvU32 *pBitAddr // out 400 ) 401 { 402 403 NV_STATUS status = NV_OK; 404 NvU32 addr; 405 406 NV_ASSERT_OR_RETURN(pVbiosImg != NULL, NV_ERR_INVALID_ARGUMENT); 407 NV_ASSERT_OR_RETURN(pVbiosImg->pImage != NULL, NV_ERR_INVALID_ARGUMENT); 408 NV_ASSERT_OR_RETURN(pVbiosImg->biosSize > 0, NV_ERR_INVALID_ARGUMENT); 409 NV_ASSERT_OR_RETURN(pBitAddr != NULL, NV_ERR_INVALID_ARGUMENT); 410 411 for (addr = 0; addr < pVbiosImg->biosSize - 3; addr++) 412 { 413 if ((s_vbiosRead16(pVbiosImg, addr, &status) == BIT_HEADER_ID) && 414 (s_vbiosRead32(pVbiosImg, addr + 2, &status) == BIT_HEADER_SIGNATURE)) 415 { 416 // found candidate BIT header 417 NvU32 candidateBitAddr = addr; 418 419 // verify BIT header checksum 420 NvU32 headerSize = s_vbiosRead8(pVbiosImg, 421 candidateBitAddr + BIT_HEADER_SIZE_OFFSET, &status); 422 423 NvU32 checksum = 0; 424 NvU32 j; 425 426 for (j = 0; j < headerSize; j++) 427 { 428 checksum += (NvU32) s_vbiosRead8(pVbiosImg, candidateBitAddr + j, &status); 429 } 430 431 NV_ASSERT_OK_OR_RETURN(status); 432 433 if ((checksum & 0xFF) == 0x0) 434 { 435 // found! 436 // candidate BIT header passes checksum, lets use it 437 *pBitAddr = candidateBitAddr; 438 return status; 439 } 440 } 441 442 NV_ASSERT_OK_OR_RETURN(status); 443 } 444 445 // not found 446 return NV_ERR_GENERIC; 447 } 448 449 /*! 450 * Find and parse a ucode desc (from BIT) for FWSEC from VBIOS image. 451 * 452 * @param[in] pVbiosImg VBIOS image 453 * @param[in] bitAddr Offset of BIT header within VBIOS image 454 * @param[in] bUseDebugFwsec Whether to look for debug or prod FWSEC 455 * @param[out] pFwsecUcodeDescFromBit Resulting ucode desc 456 * @param[out] pVbiosVersionCombined (optional) output VBIOS version 457 */ 458 static NV_STATUS 459 s_vbiosParseFwsecUcodeDescFromBit 460 ( 461 const KernelGspVbiosImg * const pVbiosImg, 462 const NvU32 bitAddr, 463 const NvBool bUseDebugFwsec, 464 FlcnUcodeDescFromBit *pFwsecUcodeDescFromBit, // out 465 NvU64 *pVbiosVersionCombined // out 466 ) 467 { 468 469 NV_STATUS status; 470 BIT_HEADER_V1_00 bitHeader; 471 NvU32 tokIdx; 472 473 NV_ASSERT_OR_RETURN(pVbiosImg != NULL, NV_ERR_INVALID_ARGUMENT); 474 NV_ASSERT_OR_RETURN(pVbiosImg->pImage != NULL, NV_ERR_INVALID_ARGUMENT); 475 NV_ASSERT_OR_RETURN(pVbiosImg->biosSize > 0, NV_ERR_INVALID_ARGUMENT); 476 NV_ASSERT_OR_RETURN(pFwsecUcodeDescFromBit != NULL, NV_ERR_INVALID_ARGUMENT); 477 478 // read BIT header 479 status = s_vbiosReadStructure(pVbiosImg, &bitHeader, bitAddr, BIT_HEADER_V1_00_FMT); 480 if (status != NV_OK) 481 { 482 NV_PRINTF(LEVEL_ERROR, "failed to read BIT table structure: 0x%x\n", status); 483 return status; 484 } 485 486 // loop through all BIT tokens 487 for (tokIdx = 0; tokIdx < bitHeader.TokenEntries; tokIdx++) 488 { 489 BIT_TOKEN_V1_00 bitToken; 490 491 BIT_DATA_FALCON_DATA_V2 falconData; 492 FALCON_UCODE_TABLE_HDR_V1 ucodeHeader; 493 NvU32 entryIdx; 494 495 // read BIT token 496 status = s_vbiosReadStructure(pVbiosImg, &bitToken, 497 bitAddr + bitHeader.HeaderSize + 498 tokIdx * bitHeader.TokenSize, 499 BIT_TOKEN_V1_00_FMT); 500 if (status != NV_OK) 501 { 502 NV_PRINTF(LEVEL_ERROR, 503 "failed to read BIT token %u, skipping: 0x%x\n", 504 tokIdx, status); 505 continue; 506 } 507 508 // catch BIOSDATA token (for capturing VBIOS version) 509 if (pVbiosVersionCombined != NULL && 510 bitToken.TokenId == BIT_TOKEN_BIOSDATA && 511 ((bitToken.DataVersion == 1) || (bitToken.DataVersion == 2)) && 512 bitToken.DataSize > BIT_DATA_BIOSDATA_BINVER_SIZE_5) 513 { 514 BIT_DATA_BIOSDATA_BINVER binver; 515 status = s_vbiosReadStructure(pVbiosImg, &binver, 516 bitToken.DataPtr, BIT_DATA_BIOSDATA_BINVER_FMT); 517 if (status != NV_OK) 518 { 519 NV_PRINTF(LEVEL_ERROR, 520 "failed to read BIOSDATA (BIT token %u), skipping: 0x%x\n", 521 tokIdx, status); 522 continue; 523 } 524 525 *pVbiosVersionCombined = (((NvU64) binver.Version) << 8) | ((NvU32) binver.OemVersion); 526 } 527 528 // skip tokens that are not for falcon ucode data v2 529 if (bitToken.TokenId != BIT_TOKEN_FALCON_DATA || 530 bitToken.DataVersion != 2 || 531 bitToken.DataSize < BIT_DATA_FALCON_DATA_V2_SIZE_4) 532 { 533 continue; 534 } 535 536 // read falcon ucode data 537 status = s_vbiosReadStructure(pVbiosImg, &falconData, 538 bitToken.DataPtr, BIT_DATA_FALCON_DATA_V2_4_FMT); 539 if (status != NV_OK) 540 { 541 NV_PRINTF(LEVEL_ERROR, 542 "failed to read Falcon ucode data (BIT token %u), skipping: 0x%x\n", 543 tokIdx, status); 544 continue; 545 } 546 547 // read falcon ucode header 548 status = s_vbiosReadStructure(pVbiosImg, &ucodeHeader, 549 pVbiosImg->expansionRomOffset + 550 falconData.FalconUcodeTablePtr, 551 FALCON_UCODE_TABLE_HDR_V1_6_FMT); 552 if (status != NV_OK) 553 { 554 NV_PRINTF(LEVEL_ERROR, 555 "failed to read Falcon ucode header (BIT token %u), skipping: 0x%x\n", 556 tokIdx, status); 557 continue; 558 } 559 560 // skip headers with undesired version 561 if ((ucodeHeader.Version != FALCON_UCODE_TABLE_HDR_V1_VERSION) || 562 (ucodeHeader.HeaderSize < FALCON_UCODE_TABLE_HDR_V1_SIZE_6) || 563 (ucodeHeader.EntrySize < FALCON_UCODE_TABLE_ENTRY_V1_SIZE_6)) 564 { 565 continue; 566 } 567 568 // loop through falcon ucode entries 569 for (entryIdx = 0; entryIdx < ucodeHeader.EntryCount; entryIdx++) 570 { 571 FALCON_UCODE_TABLE_ENTRY_V1 ucodeEntry; 572 FALCON_UCODE_DESC_HEADER ucodeDescHdr; 573 574 NvU8 ucodeDescVersion; 575 NvU32 ucodeDescSize; 576 NvU32 ucodeDescOffset; 577 const char *ucodeDescFmt; 578 579 status = s_vbiosReadStructure(pVbiosImg, &ucodeEntry, 580 pVbiosImg->expansionRomOffset + 581 falconData.FalconUcodeTablePtr + 582 ucodeHeader.HeaderSize + 583 entryIdx * ucodeHeader.EntrySize, 584 FALCON_UCODE_TABLE_ENTRY_V1_6_FMT); 585 if (status != NV_OK) 586 { 587 NV_PRINTF(LEVEL_ERROR, 588 "failed to read Falcon ucode entry %u (BIT token %u), skipping: 0x%x\n", 589 entryIdx, tokIdx, status); 590 continue; 591 } 592 593 // skip entries that are not FWSEC 594 if (ucodeEntry.ApplicationID != FALCON_UCODE_ENTRY_APPID_FIRMWARE_SEC_LIC && 595 ((bUseDebugFwsec && (ucodeEntry.ApplicationID != FALCON_UCODE_ENTRY_APPID_FWSEC_DBG)) || 596 (!bUseDebugFwsec && (ucodeEntry.ApplicationID != FALCON_UCODE_ENTRY_APPID_FWSEC_PROD)))) 597 { 598 continue; 599 } 600 601 // determine desc version, format, and size 602 status = s_vbiosReadStructure(pVbiosImg, &ucodeDescHdr, 603 pVbiosImg->expansionRomOffset + ucodeEntry.DescPtr, 604 FALCON_UCODE_DESC_HEADER_FORMAT); 605 if (status != NV_OK) 606 { 607 NV_PRINTF(LEVEL_ERROR, 608 "failed to read Falcon ucode desc header for entry %u (BIT token %u), skipping: 0x%x\n", 609 entryIdx, tokIdx, status); 610 continue; 611 } 612 613 // skip entries with desc version not V2 and V3 (FWSEC should be either V2 or V3) 614 if (FLD_TEST_DRF(_BIT, _FALCON_UCODE_DESC_HEADER_VDESC_FLAGS, _VERSION, _UNAVAILABLE, ucodeDescHdr.vDesc)) 615 { 616 NV_PRINTF(LEVEL_ERROR, 617 "unexpected ucode desc version missing for entry %u (BIT token %u), skipping\n", 618 entryIdx, tokIdx); 619 continue; 620 } 621 else 622 { 623 ucodeDescVersion = (NvU8) DRF_VAL(_BIT, _FALCON_UCODE_DESC_HEADER_VDESC, _VERSION, ucodeDescHdr.vDesc); 624 ucodeDescSize = DRF_VAL(_BIT, _FALCON_UCODE_DESC_HEADER_VDESC, _SIZE, ucodeDescHdr.vDesc); 625 } 626 627 if (ucodeDescVersion == NV_BIT_FALCON_UCODE_DESC_HEADER_VDESC_VERSION_V2 && 628 ucodeDescSize >= FALCON_UCODE_DESC_V2_SIZE_60) 629 { 630 ucodeDescFmt = FALCON_UCODE_DESC_V2_60_FMT; 631 } 632 else if (ucodeDescVersion == NV_BIT_FALCON_UCODE_DESC_HEADER_VDESC_VERSION_V3 && 633 ucodeDescSize >= FALCON_UCODE_DESC_V3_SIZE_44) 634 { 635 ucodeDescFmt = FALCON_UCODE_DESC_V3_44_FMT; 636 } 637 else 638 { 639 NV_PRINTF(LEVEL_ERROR, 640 "unexpected ucode desc version 0x%x or size 0x%x for entry %u (BIT token %u), skipping\n", 641 ucodeDescVersion, ucodeDescSize, entryIdx, tokIdx); 642 continue; 643 } 644 645 ucodeDescOffset = ucodeEntry.DescPtr + pVbiosImg->expansionRomOffset; 646 647 status = s_vbiosReadStructure(pVbiosImg, &pFwsecUcodeDescFromBit->descUnion, 648 ucodeDescOffset, ucodeDescFmt); 649 if (status != NV_OK) 650 { 651 NV_PRINTF(LEVEL_ERROR, 652 "failed to read Falcon ucode desc (desc version 0x%x) for entry %u (BIT token %u), skipping: 0x%x\n", 653 ucodeDescVersion, entryIdx, tokIdx, status); 654 continue; 655 } 656 657 pFwsecUcodeDescFromBit->descVersion = ucodeDescVersion; 658 pFwsecUcodeDescFromBit->descOffset = ucodeDescOffset; 659 pFwsecUcodeDescFromBit->descSize = ucodeDescSize; 660 661 return NV_OK; 662 } 663 } 664 665 // not found 666 return NV_ERR_INVALID_DATA; 667 } 668 669 /*! 670 * Fill a KernelGspFlcnUcode structure from a V2 ucode desc (from BIT). 671 * 672 * @param[in] pGpu OBJGPU pointer 673 * @param[in] pVbiosImg VBIOS image 674 * @param[in] pDescV2 V2 ucode desc (from BIT) 675 * @param[in] descOffset Offset of ucode desc (from BIT) in VBIOS image 676 * @param[in] descSize Size of ucode desc (from BIT) 677 * @param[out] pFlcnUcode KernelGspFlcnUcode structure to fill 678 */ 679 static NV_STATUS 680 s_vbiosFillFlcnUcodeFromDescV2 681 ( 682 OBJGPU *pGpu, // for memdesc 683 const KernelGspVbiosImg * const pVbiosImg, 684 const FALCON_UCODE_DESC_V2 * const pDescV2, 685 const NvU32 descOffset, 686 const NvU32 descSize, 687 KernelGspFlcnUcode *pFlcnUcode // out 688 ) 689 { 690 NV_STATUS status; 691 KernelGspFlcnUcodeBootWithLoader *pUcode = NULL; 692 693 NvU8 *pMappedCodeMem = NULL; 694 NvU8 *pMappedDataMem = NULL; 695 696 NvBool bSafe; 697 NvU32 codeSizeAligned; 698 NvU32 dataSizeAligned; 699 700 // offsets within pVbiosImg->pImage 701 NvU32 imageCodeOffset; 702 NvU32 imageCodeMaxOffset; 703 NvU32 imageDataOffset; 704 NvU32 imageDataMaxOffset; 705 706 // offsets within mapped mem 707 NvU32 mappedCodeMaxOffset; 708 NvU32 mappedDataMaxOffset; 709 710 NV_ASSERT(pVbiosImg != NULL); 711 NV_ASSERT(pVbiosImg->pImage != NULL); 712 NV_ASSERT(pDescV2 != NULL); 713 NV_ASSERT(pFlcnUcode != NULL); 714 715 pFlcnUcode->bootType = KGSP_FLCN_UCODE_BOOT_WITH_LOADER; 716 pUcode = &pFlcnUcode->ucodeBootWithLoader; 717 718 pUcode->pCodeMemDesc = NULL; 719 pUcode->pDataMemDesc = NULL; 720 721 pUcode->codeOffset = 0; 722 pUcode->imemSize = pDescV2->IMEMLoadSize; 723 pUcode->imemNsSize = pDescV2->IMEMLoadSize - pDescV2->IMEMSecSize; 724 pUcode->imemNsPa = pDescV2->IMEMPhysBase; 725 pUcode->imemSecSize = NV_ALIGN_UP(pDescV2->IMEMSecSize, 256); 726 pUcode->imemSecPa = pDescV2->IMEMSecBase - pDescV2->IMEMVirtBase + pDescV2->IMEMPhysBase; 727 pUcode->codeEntry = pDescV2->VirtualEntry; // 0? 728 729 pUcode->dataOffset = pDescV2->DMEMOffset; 730 pUcode->dmemSize = pDescV2->DMEMLoadSize; 731 pUcode->dmemPa = pDescV2->DMEMPhysBase; 732 733 pUcode->interfaceOffset = pDescV2->InterfaceOffset; 734 735 codeSizeAligned = NV_ALIGN_UP(pUcode->imemSize, 256); 736 dataSizeAligned = NV_ALIGN_UP(pUcode->dmemSize, 256); 737 738 // verify offsets within pVbiosImg->pImage 739 bSafe = portSafeAddU32(descOffset, descSize, &imageCodeOffset); 740 if (!bSafe || imageCodeOffset >= pVbiosImg->biosSize) 741 { 742 return NV_ERR_INVALID_OFFSET; 743 } 744 745 bSafe = portSafeAddU32(imageCodeOffset, pUcode->imemSize, &imageCodeMaxOffset); 746 if (!bSafe || imageCodeMaxOffset > pVbiosImg->biosSize) 747 { 748 return NV_ERR_INVALID_OFFSET; 749 } 750 751 bSafe = portSafeAddU32(imageCodeOffset, pUcode->dataOffset, &imageDataOffset); 752 if (!bSafe || imageDataOffset >= pVbiosImg->biosSize) 753 { 754 return NV_ERR_INVALID_OFFSET; 755 } 756 757 bSafe = portSafeAddU32(imageDataOffset, pUcode->dmemSize, &imageDataMaxOffset); 758 if (!bSafe || imageDataMaxOffset > pVbiosImg->biosSize) 759 { 760 return NV_ERR_INVALID_OFFSET; 761 } 762 763 // verify offsets within mapped mem 764 if (pUcode->imemNsPa >= codeSizeAligned) 765 { 766 return NV_ERR_INVALID_OFFSET; 767 } 768 769 bSafe = portSafeAddU32(pUcode->imemNsPa, pUcode->imemSize, &mappedCodeMaxOffset); 770 if (!bSafe || mappedCodeMaxOffset > codeSizeAligned) 771 { 772 return NV_ERR_INVALID_OFFSET; 773 } 774 775 if (pUcode->dmemPa >= dataSizeAligned) 776 { 777 return NV_ERR_INVALID_OFFSET; 778 } 779 780 bSafe = portSafeAddU32(pUcode->dmemPa, pUcode->dmemSize, &mappedDataMaxOffset); 781 if (!bSafe || mappedDataMaxOffset > dataSizeAligned) 782 { 783 return NV_ERR_INVALID_OFFSET; 784 } 785 786 NV_ASSERT_OK_OR_RETURN( 787 memdescCreate(&pUcode->pCodeMemDesc, pGpu, codeSizeAligned, 788 256, NV_TRUE, ADDR_SYSMEM, NV_MEMORY_UNCACHED, MEMDESC_FLAGS_PHYSICALLY_CONTIGUOUS)); 789 790 NV_ASSERT_OK_OR_RETURN( 791 memdescCreate(&pUcode->pDataMemDesc, pGpu, dataSizeAligned, 792 256, NV_TRUE, ADDR_SYSMEM, NV_MEMORY_UNCACHED, MEMDESC_FLAGS_PHYSICALLY_CONTIGUOUS)); 793 794 status = memdescAlloc(pUcode->pCodeMemDesc); 795 if (status != NV_OK) 796 { 797 return status; 798 } 799 800 status = memdescAlloc(pUcode->pDataMemDesc); 801 if (status != NV_OK) 802 { 803 return status; 804 } 805 806 pMappedCodeMem = memdescMapInternal(pGpu, pUcode->pCodeMemDesc, TRANSFER_FLAGS_NONE); 807 if (pMappedCodeMem == NULL) 808 { 809 return NV_ERR_INSUFFICIENT_RESOURCES; 810 } 811 812 pMappedDataMem = memdescMapInternal(pGpu, pUcode->pDataMemDesc, TRANSFER_FLAGS_NONE); 813 if (pMappedDataMem == NULL) 814 { 815 memdescUnmapInternal(pGpu, pUcode->pCodeMemDesc, 816 TRANSFER_FLAGS_DESTROY_MAPPING); 817 pMappedCodeMem = NULL; 818 return NV_ERR_INSUFFICIENT_RESOURCES; 819 } 820 821 portMemSet(pMappedCodeMem, 0, codeSizeAligned); 822 portMemCopy(pMappedCodeMem + pUcode->imemNsPa, pUcode->imemSize, 823 pVbiosImg->pImage + imageCodeOffset, pUcode->imemSize); 824 825 portMemSet(pMappedDataMem, 0, dataSizeAligned); 826 portMemCopy(pMappedDataMem + pUcode->dmemPa, pUcode->dmemSize, 827 pVbiosImg->pImage + imageDataOffset, pUcode->dmemSize); 828 829 memdescUnmapInternal(pGpu, pUcode->pCodeMemDesc, 830 TRANSFER_FLAGS_DESTROY_MAPPING); 831 pMappedCodeMem = NULL; 832 memdescUnmapInternal(pGpu, pUcode->pDataMemDesc, 833 TRANSFER_FLAGS_DESTROY_MAPPING); 834 pMappedDataMem = NULL; 835 836 return status; 837 } 838 839 /*! 840 * Fill a KernelGspFlcnUcode structure from a V3 ucode desc (from BIT). 841 * 842 * @param[in] pGpu OBJGPU pointer 843 * @param[in] pVbiosImg VBIOS image 844 * @param[in] pDescV3 V3 ucode desc (from BIT) 845 * @param[in] descOffset Offset of ucode desc (from BIT) in VBIOS image 846 * @param[in] descSize Size of ucode desc (from BIT) 847 * @param[out] pFlcnUcode KernelGspFlcnUcode structure to fill 848 */ 849 static NV_STATUS 850 s_vbiosFillFlcnUcodeFromDescV3 851 ( 852 OBJGPU *pGpu, // for memdesc 853 const KernelGspVbiosImg * const pVbiosImg, 854 const FALCON_UCODE_DESC_V3 * const pDescV3, 855 const NvU32 descOffset, 856 const NvU32 descSize, 857 KernelGspFlcnUcode *pFlcnUcode // out 858 ) 859 { 860 NV_STATUS status; 861 KernelGspFlcnUcodeBootFromHs *pUcode = NULL; 862 863 NvU8 *pMappedUcodeMem = NULL; 864 NvBool bSafe; 865 866 // offsets within pVbiosImg->pImage 867 NvU32 imageOffset; 868 NvU32 imageMaxOffset; 869 870 // offsets with ucode image 871 NvU32 dataMaxOffset; 872 NvU32 sigDataOffset; 873 NvU32 sigDataMaxOffset; 874 875 NV_ASSERT(pVbiosImg != NULL); 876 NV_ASSERT(pVbiosImg->pImage != NULL); 877 NV_ASSERT(pDescV3 != NULL); 878 NV_ASSERT(pFlcnUcode != NULL); 879 880 pFlcnUcode->bootType = KGSP_FLCN_UCODE_BOOT_FROM_HS; 881 pUcode = &pFlcnUcode->ucodeBootFromHs; 882 883 pUcode->pUcodeMemDesc = NULL; 884 pUcode->size = RM_ALIGN_UP(pDescV3->StoredSize, 256); 885 886 pUcode->codeOffset = 0; 887 pUcode->imemSize = pDescV3->IMEMLoadSize; 888 pUcode->imemPa = pDescV3->IMEMPhysBase; 889 pUcode->imemVa = pDescV3->IMEMVirtBase; 890 891 pUcode->dataOffset = pUcode->imemSize; 892 pUcode->dmemSize = pDescV3->DMEMLoadSize; 893 pUcode->dmemPa = pDescV3->DMEMPhysBase; 894 pUcode->dmemVa = FLCN_DMEM_VA_INVALID; 895 896 pUcode->hsSigDmemAddr = pDescV3->PKCDataOffset; 897 pUcode->ucodeId = pDescV3->UcodeId; 898 pUcode->engineIdMask = pDescV3->EngineIdMask; 899 900 pUcode->pSignatures = NULL; 901 pUcode->signaturesTotalSize = 0; 902 pUcode->sigSize = BCRT30_RSA3K_SIG_SIZE; 903 pUcode->sigCount = pDescV3->SignatureCount; 904 905 pUcode->vbiosSigVersions = pDescV3->SignatureVersions; 906 pUcode->interfaceOffset = pDescV3->InterfaceOffset; 907 908 // compute imageOffset and sanity check size 909 bSafe = portSafeAddU32(descOffset, descSize, &imageOffset); 910 if (!bSafe || imageOffset >= pVbiosImg->biosSize) 911 { 912 return NV_ERR_INVALID_OFFSET; 913 } 914 915 bSafe = portSafeAddU32(imageOffset, pUcode->size, &imageMaxOffset); 916 if (!bSafe || imageMaxOffset > pVbiosImg->biosSize) 917 { 918 return NV_ERR_INVALID_OFFSET; 919 } 920 921 // sanity check imemSize 922 if (pUcode->imemSize > pUcode->size) 923 { 924 return NV_ERR_INVALID_OFFSET; 925 } 926 927 // sanity check dataOffset and dataSize 928 if (pUcode->dataOffset >= pUcode->size) 929 { 930 return NV_ERR_INVALID_OFFSET; 931 } 932 933 bSafe = portSafeAddU32(pUcode->dataOffset, pUcode->dmemSize, &dataMaxOffset); 934 if (!bSafe || dataMaxOffset > pUcode->size) 935 { 936 return NV_ERR_INVALID_OFFSET; 937 } 938 939 // sanity check hsSigDmemAddr 940 bSafe = portSafeAddU32(pUcode->dataOffset, pUcode->hsSigDmemAddr, &sigDataOffset); 941 if (!bSafe || sigDataOffset >= pUcode->size) 942 { 943 return NV_ERR_INVALID_OFFSET; 944 } 945 946 bSafe = portSafeAddU32(sigDataOffset, pUcode->sigSize, &sigDataMaxOffset); 947 if (!bSafe || sigDataMaxOffset > pUcode->size) 948 { 949 return NV_ERR_INVALID_OFFSET; 950 } 951 952 // compute signaturesTotalSize and populate pSignatures 953 if (descSize < FALCON_UCODE_DESC_V3_SIZE_44) 954 { 955 return NV_ERR_INVALID_STATE; 956 } 957 pUcode->signaturesTotalSize = descSize - FALCON_UCODE_DESC_V3_SIZE_44; 958 959 pUcode->pSignatures = portMemAllocNonPaged(pUcode->signaturesTotalSize); 960 if (pUcode->pSignatures == NULL) 961 { 962 return NV_ERR_NO_MEMORY; 963 } 964 965 portMemCopy(pUcode->pSignatures, pUcode->signaturesTotalSize, 966 pVbiosImg->pImage + descOffset + FALCON_UCODE_DESC_V3_SIZE_44, pUcode->signaturesTotalSize); 967 968 NV_ASSERT_OK_OR_RETURN( 969 memdescCreate(&pUcode->pUcodeMemDesc, pGpu, pUcode->size, 970 256, NV_TRUE, ADDR_SYSMEM, NV_MEMORY_UNCACHED, MEMDESC_FLAGS_NONE)); 971 972 status = memdescAlloc(pUcode->pUcodeMemDesc); 973 if (status != NV_OK) 974 { 975 return status; 976 } 977 978 pMappedUcodeMem = memdescMapInternal(pGpu, pUcode->pUcodeMemDesc, TRANSFER_FLAGS_NONE); 979 if (pMappedUcodeMem == NULL) 980 { 981 return NV_ERR_INSUFFICIENT_RESOURCES; 982 } 983 984 portMemCopy(pMappedUcodeMem, pUcode->size, 985 pVbiosImg->pImage + imageOffset, pUcode->size); 986 987 memdescUnmapInternal(pGpu, pUcode->pUcodeMemDesc, 988 TRANSFER_FLAGS_DESTROY_MAPPING); 989 pMappedUcodeMem = NULL; 990 991 return status; 992 } 993 994 /*! 995 * Create a new KernelGspFlcnUcode structure from a ucode desc (from BIT). 996 * 997 * The resulting KernelGspFlcnUcode should be freed with kgspFreeFlcnUcode 998 * after use. 999 * 1000 * @param[in] pGpu OBJGPU pointer 1001 * @param[in] pVbiosImg VBIOS image 1002 * @param[in] pFlcnUcodeDescFromBit V2 ucode desc (from BIT) 1003 * @param[out] ppFlcnUcode Pointer to resulting KernelGspFlcnUcode 1004 */ 1005 static NV_STATUS 1006 s_vbiosNewFlcnUcodeFromDesc 1007 ( 1008 OBJGPU *pGpu, // for memdesc 1009 const KernelGspVbiosImg * const pVbiosImg, 1010 const FlcnUcodeDescFromBit * const pFlcnUcodeDescFromBit, 1011 KernelGspFlcnUcode **ppFlcnUcode // out 1012 ) 1013 { 1014 NV_STATUS status; 1015 KernelGspFlcnUcode *pFlcnUcode = NULL; 1016 1017 NV_ASSERT(pGpu != NULL); 1018 NV_ASSERT(pVbiosImg != NULL); 1019 NV_ASSERT(pFlcnUcodeDescFromBit != NULL); 1020 NV_ASSERT(ppFlcnUcode != NULL); 1021 1022 pFlcnUcode = portMemAllocNonPaged(sizeof(*pFlcnUcode)); 1023 if (pFlcnUcode == NULL) 1024 { 1025 return NV_ERR_NO_MEMORY; 1026 } 1027 portMemSet(pFlcnUcode, 0, sizeof(*pFlcnUcode)); 1028 1029 if (pFlcnUcodeDescFromBit->descVersion == NV_BIT_FALCON_UCODE_DESC_HEADER_VDESC_VERSION_V2) 1030 { 1031 status = s_vbiosFillFlcnUcodeFromDescV2(pGpu, pVbiosImg, 1032 &pFlcnUcodeDescFromBit->descUnion.v2, 1033 pFlcnUcodeDescFromBit->descOffset, 1034 pFlcnUcodeDescFromBit->descSize, 1035 pFlcnUcode); 1036 } 1037 else if (pFlcnUcodeDescFromBit->descVersion == NV_BIT_FALCON_UCODE_DESC_HEADER_VDESC_VERSION_V3) 1038 { 1039 status = s_vbiosFillFlcnUcodeFromDescV3(pGpu, pVbiosImg, 1040 &pFlcnUcodeDescFromBit->descUnion.v3, 1041 pFlcnUcodeDescFromBit->descOffset, 1042 pFlcnUcodeDescFromBit->descSize, 1043 pFlcnUcode); 1044 } 1045 else 1046 { 1047 NV_ASSERT(0); 1048 return NV_ERR_INVALID_STATE; 1049 } 1050 1051 if (status != NV_OK) 1052 { 1053 NV_PRINTF(LEVEL_ERROR, 1054 "failed to parse/prepare Falcon ucode (desc: version 0x%x, offset 0x%x, size 0x%x): 0x%x\n", 1055 pFlcnUcodeDescFromBit->descVersion, 1056 pFlcnUcodeDescFromBit->descOffset, 1057 pFlcnUcodeDescFromBit->descSize, 1058 status); 1059 1060 kgspFreeFlcnUcode(pFlcnUcode); 1061 pFlcnUcode = NULL; 1062 } 1063 1064 *ppFlcnUcode = pFlcnUcode; 1065 return NV_OK; 1066 } 1067 1068 /*! 1069 * Parse FWSEC ucode from VBIOS image. 1070 * 1071 * The resulting KernelGspFlcnUcode should be freed with kgspFlcnUcodeFree 1072 * after use. 1073 * 1074 * @param[in] pGpu OBJGPU pointer 1075 * @param[in] pKernelGsp KernelGsp pointer 1076 * @param[in] pVbiosImg VBIOS image 1077 * @param[out] ppFwsecUcode Pointer to resulting KernelGspFlcnUcode 1078 * @param[out] pVbiosVersionCombined (optional) pointer to output VBIOS version 1079 */ 1080 NV_STATUS 1081 kgspParseFwsecUcodeFromVbiosImg_IMPL 1082 ( 1083 OBJGPU *pGpu, 1084 KernelGsp *pKernelGsp, 1085 const KernelGspVbiosImg * const pVbiosImg, 1086 KernelGspFlcnUcode **ppFwsecUcode, // out 1087 NvU64 *pVbiosVersionCombined // out 1088 ) 1089 { 1090 NV_STATUS status; 1091 1092 FlcnUcodeDescFromBit fwsecUcodeDescFromBit; 1093 NvU32 bitAddr; 1094 NvBool bUseDebugFwsec = NV_FALSE; 1095 1096 NV_ASSERT_OR_RETURN(!IS_VIRTUAL(pGpu), NV_ERR_NOT_SUPPORTED); 1097 NV_ASSERT_OR_RETURN(IS_GSP_CLIENT(pGpu), NV_ERR_NOT_SUPPORTED); 1098 1099 NV_ASSERT_OR_RETURN(pVbiosImg != NULL, NV_ERR_INVALID_ARGUMENT); 1100 NV_ASSERT_OR_RETURN(pVbiosImg->pImage != NULL, NV_ERR_INVALID_ARGUMENT); 1101 NV_ASSERT_OR_RETURN(ppFwsecUcode, NV_ERR_INVALID_ARGUMENT); 1102 1103 status = s_vbiosFindBitHeader(pVbiosImg, &bitAddr); 1104 if (status != NV_OK) 1105 { 1106 NV_PRINTF(LEVEL_ERROR, "failed to find BIT header in VBIOS image: 0x%x\n", status); 1107 return status; 1108 } 1109 1110 bUseDebugFwsec = kgspIsDebugModeEnabled_HAL(pGpu, pKernelGsp); 1111 status = s_vbiosParseFwsecUcodeDescFromBit(pVbiosImg, bitAddr, bUseDebugFwsec, 1112 &fwsecUcodeDescFromBit, pVbiosVersionCombined); 1113 if (status != NV_OK) 1114 { 1115 NV_PRINTF(LEVEL_ERROR, "failed to parse FWSEC ucode desc from VBIOS image: 0x%x\n", status); 1116 return status; 1117 } 1118 1119 status = s_vbiosNewFlcnUcodeFromDesc(pGpu, pVbiosImg, &fwsecUcodeDescFromBit, ppFwsecUcode); 1120 if (status != NV_OK) 1121 { 1122 NV_PRINTF(LEVEL_ERROR, 1123 "failed to prepare new flcn ucode for FWSEC: 0x%x\n", 1124 status); 1125 return status; 1126 } 1127 1128 return status; 1129 } 1130