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