1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 2015-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   * @file
26   * @brief Utility assertion macros
27   *
28   * @see "NV_ASSERT" confluence page for additional documentation
29   */
30 
31 #ifndef _NV_UTILS_ASSERT_H_
32 #define _NV_UTILS_ASSERT_H_
33 
34 #ifdef __cplusplus
35 extern "C" {
36 #endif
37 
38 /**
39  * @defgroup NV_UTILS_ASSERT Utility Assertion Macros
40  *
41  * @brief Provides a light abstraction layer for common assert macro patterns.
42  *
43  * NvPort and NvPrintf are used for debug and logging primitives.
44  * If an environment cannot use these directly then it can override
45  * the NV_PORT_HEADER and NV_PRINTF_HEADER defines in its makefile
46  * to point to appropriate replacements.
47  * @{
48  */
49 #include "nvstatus.h"
50 #include "nvmacro.h"
51 
52 // Include portability header, falling back to NvPort if not provided.
53 #ifndef NV_PORT_HEADER
54 #define NV_PORT_HEADER "nvport/nvport.h"
55 #endif
56 #include NV_PORT_HEADER
57 
58 // Include printf header, falling back to NvPrintf if not provided.
59 #ifndef NV_PRINTF_HEADER
60 #define NV_PRINTF_HEADER "utils/nvprintf.h"
61 #endif
62 #include NV_PRINTF_HEADER
63 
64 /*
65  * Use __builtin_expect to improve branch predictions on the GNU compiler.
66  *
67  * Note that these macros convert the parameter to bool.  They should
68  * only be used in 'if' statements.
69  *
70  * '!= 0' is used (instead of a cast to NvBool or !!) to avoid 'will always
71  * evaluate as 'true'' warnings in some gcc versions.
72  */
73 #if defined(__GNUC__) && __GNUC__ >= 3
74 #define NV_LIKELY(expr)   __builtin_expect(((expr) != 0), 1)
75 #define NV_UNLIKELY(expr) __builtin_expect(((expr) != 0), 0)
76 #else
77 #define NV_LIKELY(expr)   ((expr) != 0)
78 #define NV_UNLIKELY(expr) ((expr) != 0)
79 #endif
80 
81 /*
82  * Set this to pass expression, function name, file name, and line number
83  * to the nvAssertFailed functions.
84  *
85  * NOTE: NV_PRINTF_STRINGS_ALLOWED defaults to:
86  *           defined(DEBUG) || defined(NV_MODS) || defined(QA_BUILD)
87  *
88  *       RM_ASSERT used this condition to decide whether to print assert strings:
89  *           defined(DEBUG) || defined(ASSERT_BUILD) || defined(QA_BUILD)
90  */
91 #if !defined(NV_ASSERT_FAILED_USES_STRINGS)
92 #if (NV_PRINTF_STRINGS_ALLOWED && (defined(DEBUG) || defined(ASSERT_BUILD) || defined(QA_BUILD)))
93 #define NV_ASSERT_FAILED_USES_STRINGS  1
94 #else
95 #define NV_ASSERT_FAILED_USES_STRINGS  0
96 #endif
97 #endif
98 
99 // Hook NV_ASSERT into RCDB.
100 #if !defined(NV_JOURNAL_ASSERT_ENABLE)
101 #if defined(NVRM) && (NVOS_IS_WINDOWS || NVOS_IS_UNIX || NVOS_IS_LIBOS) && !defined(NVWATCH) && !defined(NV_MODS)
102 #define NV_JOURNAL_ASSERT_ENABLE            1
103 #else
104 #define NV_JOURNAL_ASSERT_ENABLE            0
105 #endif
106 #endif
107 
108 #if !defined(COVERITY_ASSERT_FAIL)
109 #if defined(__COVERITY__)
110 void __coverity_panic__(void);
111 #define COVERITY_ASSERT_FAIL() __coverity_panic__()
112 #else  // defined(__COVERITY__)
113 #define COVERITY_ASSERT_FAIL() ((void) 0)
114 #endif // defined(__COVERITY__)
115 #endif // !defined(COVERITY_ASSERT_FAIL)
116 
117 /*
118  * NV_ASSERT_FAILED, NV_ASSERT_OK_FAILED, NV_CHECK_FAILED, and NV_CHECK_OK_FAILED
119  * These macros are defined in three flavors:
120  *
121  * normal - expr/file/line are concatenated with format string for NVLOG.
122  *          expr/file/line are passed in as parameters to a helper function
123  *          for NV_PRINTF.
124  *
125  * normal for GSP-RM - expr/file/line are omitted, since each NV_PRINTF line
126  *           already has them.  NVLOG is not used.
127  *
128  * _FUNC -  expr/file/line are passed in as parameters to a helper function
129  *          for both NVLOG and NV_PRINTF.
130  *          The _FUNC macros are used for pre-compiled headers on most platforms.
131  */
132 #if defined(GSP_PLUGIN_BUILD) || (defined(NVRM) && NVOS_IS_LIBOS)
133 
134 void nvAssertInit(void);
135 void nvAssertDestroy(void);
136 
137 #if NV_JOURNAL_ASSERT_ENABLE
138 void nvAssertFailed(void);
139 void nvAssertOkFailed(NvU32 status);
140 #else
141 #define nvAssertFailed(...)
142 #define nvAssertOkFailed(...)
143 #endif
144 
145 #define NV_ASSERT_FAILED(exprStr)                                              \
146     do {                                                                       \
147         NV_LOG_SPECIAL(LEVEL_ERROR, RM_GSP_LOG_SPECIAL_ASSERT_FAILED,          \
148                        exprStr "\n");                                          \
149         nvAssertFailed();                                                      \
150         COVERITY_ASSERT_FAIL();                                                \
151         PORT_BREAKPOINT();                                                     \
152     } while(0)
153 
154 #define NV_ASSERT_OK_FAILED(exprStr, status)                                   \
155     do {                                                                       \
156         NV_LOG_SPECIAL(LEVEL_ERROR, RM_GSP_LOG_SPECIAL_ASSERT_OK_FAILED,       \
157                        exprStr "\n", status);                                  \
158         nvAssertOkFailed(status);                                              \
159         COVERITY_ASSERT_FAIL();                                                \
160         PORT_BREAKPOINT();                                                     \
161     } while(0)
162 
163 #define NV_CHECK_FAILED(level, exprStr)                                        \
164    do {                                                                        \
165         NV_LOG_SPECIAL(level, RM_GSP_LOG_SPECIAL_CHECK_FAILED,                 \
166                        exprStr "\n");                                          \
167     } while(0)                                                                 \
168 
169 #define NV_CHECK_OK_FAILED(level, exprStr, status)                             \
170     do {                                                                       \
171         NV_LOG_SPECIAL(level, RM_GSP_LOG_SPECIAL_CHECK_OK_FAILED,              \
172                        exprStr "\n", status);                                  \
173     } while (0)
174 
175 #else // defined(GSP_PLUGIN_BUILD) || (defined(NVRM) && NVOS_IS_LIBOS)
176 
177 #if NV_ASSERT_FAILED_USES_STRINGS
178 #define NV_ASSERT_FAILED_FUNC_COMMA_PARAM(exprStr)   , exprStr, __FILE__, __LINE__
179 #define NV_ASSERT_FAILED_FUNC_PARAM(exprStr)         exprStr, __FILE__, __LINE__
180 #define NV_ASSERT_FAILED_FUNC_COMMA_TYPE             ,const char *pszExpr, const char *pszFileName, NvU32 lineNum
181 #define NV_ASSERT_FAILED_FUNC_TYPE                   const char *pszExpr, const char *pszFileName, NvU32 lineNum
182 #else
183 #define NV_ASSERT_FAILED_FUNC_COMMA_PARAM(exprStr)   , __LINE__
184 #define NV_ASSERT_FAILED_FUNC_PARAM(exprStr)         __LINE__
185 #define NV_ASSERT_FAILED_FUNC_COMMA_TYPE             , NvU32 lineNum
186 #define NV_ASSERT_FAILED_FUNC_TYPE                   NvU32 lineNum
187 #endif
188 
189 void nvAssertInit(void);
190 void nvAssertDestroy(void);
191 
192 // Helper function prototypes for _FAILED macros below.
193 #if NV_PRINTF_ENABLED || NV_JOURNAL_ASSERT_ENABLE
194 void nvAssertFailed(NV_ASSERT_FAILED_FUNC_TYPE);
195 void nvAssertOkFailed(NvU32 status NV_ASSERT_FAILED_FUNC_COMMA_TYPE);
196 void nvCheckFailed(NvU32 level NV_ASSERT_FAILED_FUNC_COMMA_TYPE);
197 void nvCheckOkFailed(NvU32 level, NvU32 status NV_ASSERT_FAILED_FUNC_COMMA_TYPE);
198 void nvAssertFailedNoLog(NV_ASSERT_FAILED_FUNC_TYPE);
199 void nvAssertOkFailedNoLog(NvU32 status NV_ASSERT_FAILED_FUNC_COMMA_TYPE);
200 void nvCheckFailedNoLog(NvU32 level NV_ASSERT_FAILED_FUNC_COMMA_TYPE);
201 void nvCheckOkFailedNoLog(NvU32 level, NvU32 status NV_ASSERT_FAILED_FUNC_COMMA_TYPE);
202 #else // NV_PRINTF_ENABLED || NV_JOURNAL_ASSERT_ENABLE
203 #define nvAssertFailed(...)
204 #define nvAssertOkFailed(...)
205 #define nvCheckFailed(...)
206 #define nvCheckOkFailed(...)
207 #define nvAssertFailedNoLog(...)
208 #define nvAssertOkFailedNoLog(...)
209 #define nvCheckFailedNoLog(...)
210 #define nvCheckOkFailedNoLog(...)
211 #endif // NV_PRINTF_ENABLED || NV_JOURNAL_ASSERT_ENABLE
212 
213 #define NV_ASSERT_LOG(level, fmt, ...)                                         \
214     NVLOG_PRINTF(NV_PRINTF_MODULE, NVLOG_ROUTE_RM, level,                      \
215     NV_PRINTF_ADD_PREFIX(fmt), ##__VA_ARGS__)
216 
217 #define NV_ASSERT_FAILED(exprStr)                                              \
218     do {                                                                       \
219         NV_ASSERT_LOG(LEVEL_ERROR, "Assertion failed: " exprStr);              \
220         nvAssertFailedNoLog(NV_ASSERT_FAILED_FUNC_PARAM(exprStr));             \
221         COVERITY_ASSERT_FAIL();                                                \
222         PORT_BREAKPOINT_CHECKED();                                             \
223     } while(0)
224 
225 #define NV_ASSERT_OK_FAILED(exprStr, status)                                   \
226     do {                                                                       \
227         NV_ASSERT_LOG(LEVEL_ERROR, "Assertion failed: 0x%08X returned from "   \
228             exprStr, status);                                                  \
229         nvAssertOkFailedNoLog(status                                           \
230             NV_ASSERT_FAILED_FUNC_COMMA_PARAM(exprStr));                       \
231         COVERITY_ASSERT_FAIL();                                                \
232         PORT_BREAKPOINT_CHECKED();                                             \
233     } while(0)
234 
235 #define NV_CHECK_FAILED(level, exprStr)                                        \
236     do {                                                                       \
237         NV_ASSERT_LOG(level, "Check failed: " exprStr);                        \
238         if (NV_PRINTF_LEVEL_ENABLED(level))                                    \
239         {                                                                      \
240             nvCheckFailedNoLog(level                                           \
241                 NV_ASSERT_FAILED_FUNC_COMMA_PARAM(exprStr));                   \
242         }                                                                      \
243     } while(0)
244 
245 #define NV_CHECK_OK_FAILED(level, exprStr, status)                             \
246     do {                                                                       \
247         NV_ASSERT_LOG(level, "Check failed: 0x%08X returned from "             \
248             exprStr, status);                                                  \
249         if (NV_PRINTF_LEVEL_ENABLED(level))                                    \
250         {                                                                      \
251             nvCheckOkFailedNoLog(level, status                                 \
252                  NV_ASSERT_FAILED_FUNC_COMMA_PARAM(exprStr));                  \
253         }                                                                      \
254     } while(0)
255 
256 #define NV_ASSERT_FAILED_FUNC(exprStr)                                         \
257     do {                                                                       \
258         nvAssertFailed(NV_ASSERT_FAILED_FUNC_PARAM(exprStr));                  \
259         COVERITY_ASSERT_FAIL();                                                \
260         PORT_BREAKPOINT_CHECKED();                                             \
261     } while(0)
262 
263 #define NV_ASSERT_OK_FAILED_FUNC(exprStr, status)                              \
264     do {                                                                       \
265         nvAssertOkFail(status NV_ASSERT_FAILED_FUNC_COMMA_PARAM(exprStr));     \
266         COVERITY_ASSERT_FAIL();                                                \
267         PORT_BREAKPOINT_CHECKED();                                             \
268     } while(0)
269 
270 #define NV_CHECK_FAILED_FUNC(level, exprStr)                                   \
271     if (NV_PRINTF_LEVEL_ENABLED(level))                                        \
272     {                                                                          \
273         nvCheckFailed(level NV_ASSERT_FAILED_FUNC_COMMA_PARAM(exprStr))        \
274     }
275 
276 #define NV_CHECK_OK_FAILED_FUNC(level, exprStr, status)                        \
277     if (NV_PRINTF_LEVEL_ENABLED(level))                                        \
278     {                                                                          \
279         nvCheckOkFailed(level, status                                          \
280             NV_ASSERT_FAILED_FUNC_COMMA_PARAM(exprStr))                        \
281     }
282 
283 #endif // defined(GSP_PLUGIN_BUILD) || (defined(NVRM) && NVOS_IS_LIBOS)
284 
285 /*
286  * Defines for precompiled headers.
287  *
288  * On platforms other than GSP-RM, the _INLINE macros cannot be used inside
289  * precompiled headers due to conflicting NVLOG_PRINT_IDs.
290  */
291 #if defined(GSP_PLUGIN_BUILD) || (defined(NVRM) && NVOS_IS_LIBOS)
292 #define NV_ASSERT_FAILED_PRECOMP    NV_ASSERT_FAILED
293 #else
294 #define NV_ASSERT_FAILED_PRECOMP    NV_ASSERT_FAILED_FUNC
295 #endif
296 
297 // *****************************************************************************
298 // *                       NV_ASSERT family of macros                          *
299 // *****************************************************************************
300 /**
301  * General notes:
302  *
303  * Assert that an expression is true.  If not, do the actions defined
304  * in NV_ASSERT_FAILED as well as an "other action":
305  *   Print an error message in the debug output
306  *   Log an error message in NvLog
307  *   Mark as an error condition for coverity
308  *   Breakpoint
309  *   Log an assert record to the journal
310  *   "Other action" as defined by each macro below.
311  *
312  * The actions are enabled or omitted based on platform and build, and the
313  * implementations are platform dependent.
314  *
315  * The expression is always evaluated even if assertion failures are not logged
316  * in the environment.  Use @ref NV_ASSERT_CHECKED if the expression should only
317  * be evaluated in checked builds.
318  *
319  * USE GENEROUSLY FOR any condition that requires immediate action from NVIDIA.
320  * Expect to be ARBed on bugs when an assert you added shows up internally
321  * or in the field.
322  *
323  * DO NOT USE for normal run-time conditions, such as a user application
324  * passing a bad parameter.
325  */
326 
327 /**
328  * Assert that an expression is true.
329  *
330  * @param[in] expr  Expression that evaluates to a truth value.
331  */
332 #define NV_ASSERT(expr)                                                        \
333     NV_ASSERT_OR_ELSE_STR(expr, #expr, /* no other action */)
334 
335 /**
336  * Assert that an expression is true only in checked builds.
337  *
338  * @note The expression is only evaluated in checked builds so should
339  *       not contain required side-effects.
340  *       Also to prevent side effects, no "other action" is permitted.
341  *
342  * @param[in] expr  Expression that evaluates to a truth value.
343  */
344 #if PORT_IS_CHECKED_BUILD
345 #define NV_ASSERT_CHECKED(expr)                                                \
346     NV_ASSERT_OR_ELSE_STR(expr, #expr, /* no other action */)
347 #define NV_ASSERT_CHECKED_PRECOMP(expr)                                        \
348     NV_ASSERT_OR_ELSE_STR_PRECOMP(expr, #expr, /* no other action */)
349 #else
350 #define NV_ASSERT_CHECKED(expr)  ((void)0)
351 #define NV_ASSERT_CHECKED_PRECOMP(expr)  ((void)0)
352 #endif
353 
354 /**
355  * Assert that an expression is true or else do something.
356  *
357  * This macro can't use NV_ASSERT_OR_ELSE_STR when NV_PRINTF is passed in as
358  * the elseStmt parameter.
359  *
360  * @param[in] expr     Expression that evaluates to a truth value.
361  * @param[in] elseStmt Statement to evaluate if the expression is false.
362  */
363 #define NV_ASSERT_OR_ELSE(expr, elseStmt)                                      \
364     if (1)                                                                     \
365     {                                                                          \
366         PORT_COVERAGE_PUSH_OFF();                                              \
367         if (NV_UNLIKELY(!(expr)))                                              \
368         {                                                                      \
369             NV_ASSERT_FAILED(#expr);                                           \
370             elseStmt;                                                          \
371         }                                                                      \
372         PORT_COVERAGE_POP();                                                   \
373     } else ((void) 0)
374 
375 /**
376  * Assert that an expression is true or else goto a label.
377  *
378  * @param[in] expr  Expression that evaluates to a truth value.
379  * @param[in] label Label to jump to when the expression is false.
380  */
381 #define NV_ASSERT_OR_GOTO(expr, label)                                         \
382     NV_ASSERT_OR_ELSE_STR(expr, #expr, goto label)
383 
384 /**
385  * Assert that an expression is true or else return a value.
386  *
387  * @param[in] expr   Expression that evaluates to a truth value.
388  * @param[in] retval Value to return if the expression is false.
389  */
390 #define NV_ASSERT_OR_RETURN(expr, retval)                                      \
391     NV_ASSERT_OR_ELSE_STR(expr, #expr, return (retval))
392 
393 /**
394  * Assert that an expression is true or else return void.
395  *
396  * @param[in] expr   Expression that evaluates to a truth value.
397  */
398 #define NV_ASSERT_OR_RETURN_VOID(expr)                                         \
399     NV_ASSERT_OR_ELSE_STR(expr, #expr, return)
400 
401 /**
402  * Assert that an expression is true or else do something.
403  *
404  * Although it can be used directly, this second level macro is designed to be
405  * called from other macros.  Passing expr through multiple levels of macros
406  * before it is stringified expands it.  This is especially bad for DRF macros,
407  * which result in an embedded %, breaking the format string in the
408  * NV_ASSERT_FAILED_INLINE macro defined above.  The macros in this header
409  * always pass the stringified expr as a into the second level macros as
410  * a separate parameter.
411  *
412  * @param[in] expr     Expression that evaluates to a truth value.
413  * @param[in] exprStr  Expression as a string.
414  * @param[in] elseStmt Statement to evaluate if the expression is false.
415  */
416 #define NV_ASSERT_OR_ELSE_STR(expr, exprStr, elseStmt)                         \
417     do                                                                         \
418     {                                                                          \
419         PORT_COVERAGE_PUSH_OFF();                                              \
420         if (NV_UNLIKELY(!(expr)))                                              \
421         {                                                                      \
422             NV_ASSERT_FAILED(exprStr);                                         \
423             elseStmt;                                                          \
424         }                                                                      \
425         PORT_COVERAGE_POP();                                                   \
426     } while (0)
427 
428 // *****************************************************************************
429 // *                     NV_ASSERT_OK family of macros                         *
430 // *****************************************************************************
431 /**
432  * General notes:
433  *
434  * Assert that an expression evaluates to NV_OK.  If not, do the actions defined
435  * in NV_ASSERT_OK_FAILED as well as an "other action":
436  *   Print an error message in the debug output, including decoded NV_STATUS.
437  *   Log an error message in NvLog.
438  *   Mark as an error condition for coverity.
439  *   Breakpoint.
440  *   Log an assert record to the journal.
441  *   "Other action" as defined by each macro below.
442  *
443  * The actions are enabled or omitted based on platform and build, and the
444  * implementations are platform dependent.
445  *
446  * The expression is always evaluated even if assertion failures are not logged
447  * in the environment.  Use @ref NV_ASSERT_OK_CHECKED if the expression should
448  * only be evaluated in checked builds.
449  *
450  * USE GENEROUSLY FOR any condition that requires immediate action from NVIDIA.
451  * Expect to be ARBed on bugs when an assert you added shows up internally
452  * or in the field.
453  *
454  * DO NOT USE for normal run-time conditions, such as a user application
455  * passing a bad parameter.
456  */
457 
458 /**
459  * Assert that an expression evaluates to NV_OK.
460  *
461  * @param[in] expr Expression that evaluates to an NV_STATUS.
462  */
463 #define NV_ASSERT_OK(expr)                                                     \
464     do                                                                         \
465     {                                                                          \
466         NV_STATUS rm_pvt_status;                                               \
467         NV_ASSERT_OK_OR_ELSE_STR(rm_pvt_status, expr, #expr,                   \
468                                  /* no other action */);                       \
469     } while(0)
470 
471 /**
472  * Assert that an expression evaluates to NV_OK only in checked builds.
473  *
474  * @note The expression is only evaluated in checked builds so should
475  *       not contain required side-effects.
476  *       Also to prevent side effects, no "other action" is permitted,
477  *       and the status parameter is omitted.
478  *
479  * @param[in] expr Expression that evaluates to an NV_STATUS.
480  */
481 #if PORT_IS_CHECKED_BUILD
482 #define NV_ASSERT_OK_CHECKED(expr)                                             \
483     do                                                                         \
484     {                                                                          \
485         NV_STATUS rm_pvt_status;                                               \
486         NV_ASSERT_OK_OR_ELSE_STR(rm_pvt_status, expr, #expr,                   \
487             return rm_pvt_status);                                             \
488     } while(0)
489 #else
490 #define NV_ASSERT_OK_CHECKED(expr)  ((void)0)
491 #endif
492 
493 /*!
494  * Call a function that returns NV_STATUS and assert that the
495  * return values is NV_OK. In case this was a first failure
496  * update global status @ref status.
497  *
498  * @param[in] status The NV_STATUS variable to capture the status
499  * @param[in] expr   Expression that evaluates to an NV_STATUS.
500  */
501 #define NV_ASSERT_OK_OR_CAPTURE_FIRST_ERROR(status, expr)                      \
502     do                                                                         \
503     {                                                                          \
504         NV_STATUS rm_pvt_status;                                               \
505         NV_ASSERT_OK_OR_ELSE_STR(rm_pvt_status, expr, #expr,                   \
506             if (status == NV_OK) status = rm_pvt_status);                      \
507     } while (0)
508 
509 /**
510  * Assert that an expression evaluates to NV_OK or else do something.
511  *
512  * This macro can't use NV_ASSERT_OK_OR_ELSE_STR when NV_PRINTF is passed in as
513  * the elseStmt parameter.
514  *
515  * @param[in] status   The NV_STATUS variable to capture the status
516  * @param[in] expr     Expression that evaluates to an NV_STATUS.
517  * @param[in] elseStmt Statement to evaluate if the expression is false.
518  */
519 #define NV_ASSERT_OK_OR_ELSE(status, expr, elseStmt)                           \
520     do                                                                         \
521     {                                                                          \
522         status = (expr);                                                       \
523         PORT_COVERAGE_PUSH_OFF();                                              \
524         if (NV_UNLIKELY(NV_OK != status))                                      \
525         {                                                                      \
526             NV_ASSERT_OK_FAILED(#expr, status);                                \
527             elseStmt;                                                          \
528         }                                                                      \
529         PORT_COVERAGE_POP();                                                   \
530     } while(0)
531 
532 /**
533  * Assert that an expression evaluates to NV_OK or else goto a label.
534  *
535  * @param[in] status The NV_STATUS variable to capture the status
536  * @param[in] expr Expression that evaluates to an NV_STATUS.
537  * @param[in] label Label to jump to when the expression is false.
538 */
539 #define NV_ASSERT_OK_OR_GOTO(status, expr, label)                              \
540     NV_ASSERT_OK_OR_ELSE_STR(status, expr, #expr, goto label);
541 
542 /**
543  * Assert that an expression evaluates to NV_TRUE or else goto a label.
544  *
545  * @param[in] status The NV_STATUS variable to capture the status
546  * @param[in] cond   Condition that evaluates to either NV_TRUE or NV_FALSE.
547  * @param[in] error  Error to be reflected in @ref status when @cond evaluates
548                      to NV_FALSE.
549  * @param[in] label  Label to jump to when @ref cond evaluates to NV_FALSE.
550 */
551 #define NV_ASSERT_TRUE_OR_GOTO(status, cond, error, label)                     \
552     NV_ASSERT_OK_OR_ELSE_STR(status, ((cond) ? NV_OK : (error)),               \
553         #cond, goto label);
554 
555 /**
556  * Assert that an expression evaluates to NV_OK or else return the status.
557  *
558  * @param[in] expr Expression that evaluates to an NV_STATUS.
559  */
560 #define NV_ASSERT_OK_OR_RETURN(expr)                                           \
561     do                                                                         \
562     {                                                                          \
563         NV_STATUS rm_pvt_status;                                               \
564         NV_ASSERT_OK_OR_ELSE_STR(rm_pvt_status, expr, #expr,                   \
565             return rm_pvt_status);                                             \
566     } while(0)
567 
568 /**
569  * Assert that an expression evaluates to NV_OK or else do something.
570  *
571  * Although it can be used directly, this second level macro is designed to be
572  * called from other macros.  Passing expr through multiple levels of macros
573  * before it is stringified expands it.  This is especially bad for DRF macros,
574  * which result in an embedded %, breaking the format string in the
575  * NV_ASSERT_OK_FAILED_INLINE macro defined above.  The macros in this header
576  * always pass the stringified expr as a into the second level macros as
577  * a separate parameter.
578  *
579  * @param[in] status   The NV_STATUS variable to capture the status
580  * @param[in] expr     Expression that evaluates to an NV_STATUS.
581  * @param[in] exprStr  Expression as a string.
582  * @param[in] elseStmt Statement to evaluate if the expression is false.
583  */
584 #define NV_ASSERT_OK_OR_ELSE_STR(status, expr, exprStr, elseStmt)              \
585     do                                                                         \
586     {                                                                          \
587         status = (expr);                                                       \
588         PORT_COVERAGE_PUSH_OFF();                                              \
589         if (NV_UNLIKELY(NV_OK != status))                                      \
590         {                                                                      \
591             NV_ASSERT_OK_FAILED(exprStr, status);                              \
592             elseStmt;                                                          \
593         }                                                                      \
594         PORT_COVERAGE_POP();                                                   \
595     } while(0)
596 
597 // *****************************************************************************
598 // *                       NV_CHECK family of macros                           *
599 // *****************************************************************************
600 /**
601  * General notes:
602  *
603  * Check that an expression is true.  If not, do the following actions:
604  *   Print a message in the debug output at user specified level.
605  *   Log a message in NvLog at user specified level.
606  *   "Other action" as defined by each macro below.
607  *
608  * The actions are enabled or omitted based on platform and build, and the
609  * implementations are platform dependent.
610  *
611  * The expression is always evaluated even if check failures are not logged
612  * in the environment.  Use @ref NV_CHECK_CHECKED if the expression should only
613  * be evaluated in checked builds.
614  *
615  * USE FOR error conditions that DO NOT require immediate action from NVIDIA,
616  * but may be useful in diagnosing other issues.
617  */
618 
619 /**
620  * Check that an expression is true.
621  *
622  * @param[in] level NV_PRINTF LEVEL to print at
623  * @param[in] expr  Expression that evaluates to a truth value.
624  */
625 #define NV_CHECK(level, expr)                                                  \
626     NV_CHECK_OR_ELSE_STR(level, expr, #expr, /* no other action */)
627 
628 /**
629  * Check that an expression is true only in checked builds.
630  *
631  * @note The expression is only evaluated in checked builds so should
632  *       not contain required side-effects.
633  *       Also to prevent side effects, no "other action" is permitted.
634  *
635  * @param[in] level NV_PRINTF LEVEL to print at
636  * @param[in] expr  Expression that evaluates to a truth value.
637  */
638 #if PORT_IS_CHECKED_BUILD
639 #define NV_CHECK_CHECKED(level, expr)                                          \
640     NV_CHECK_OR_ELSE_STR(level, expr, #expr, /* no other action */)
641 #else
642 #define NV_CHECK_CHECKED(level, expr)  ((void)0)
643 #endif
644 
645 /**
646  * Check that an expression is true or else do something.
647  *
648  * This macro can't use NV_CHECK_OR_ELSE_STR when NV_PRINTF is passed in as
649  * the elseStmt parameter.
650  *
651  * @param[in] level NV_PRINTF LEVEL to print at
652  * @param[in] expr     Expression that evaluates to a truth value.
653  * @param[in] elseStmt Statement to evaluate if the expression is false.
654  */
655 #define NV_CHECK_OR_ELSE(level, expr, elseStmt)                                \
656     do                                                                         \
657     {                                                                          \
658         if (NV_UNLIKELY(!(expr)))                                              \
659         {                                                                      \
660             NV_CHECK_FAILED(level, #expr);                                     \
661             elseStmt;                                                          \
662         }                                                                      \
663     } while (0)
664 
665 /**
666  * Check that an expression is true or else goto a label.
667  *
668  * @param[in] level NV_PRINTF LEVEL to print at
669  * @param[in] expr  Expression that evaluates to a truth value.
670  * @param[in] label Label to jump to when the expression is false.
671  */
672 #define NV_CHECK_OR_GOTO(level, expr, label)                                   \
673     NV_CHECK_OR_ELSE_STR(level, expr, #expr, goto label)
674 
675 /**
676  * Check that an expression is true or else return a value.
677  *
678  * @param[in] level NV_PRINTF LEVEL to print at
679  * @param[in] expr  Expression that evaluates to a truth value.
680  * @param[in] retval Value to return if the expression is false.
681  */
682 #define NV_CHECK_OR_RETURN(level, expr, retval)                                \
683     NV_CHECK_OR_ELSE_STR(level, expr, #expr, return (retval))
684 
685 /**
686  * Check that an expression is true or else return void.
687  *
688  * @param[in] level NV_PRINTF LEVEL to print at
689  * @param[in] expr  Expression that evaluates to a truth value.
690  */
691 #define NV_CHECK_OR_RETURN_VOID(level, expr)                                   \
692     NV_CHECK_OR_ELSE_STR(level, expr, #expr, return)
693 
694 /**
695  * Check that an expression is true or else do something.
696  *
697  * Although it can be used directly, this second level macro is designed to be
698  * called from other macros.  Passing expr through multiple levels of macros
699  * before it is stringified expands it.  This is especially bad for DRF macros,
700  * which result in an embedded %, breaking the format string in the
701  * NV_CHECK_FAILED_INLINE macro defined above.  The macros in this header
702  * always pass the stringified expr as a into the second level macros as
703  * a separate parameter.
704  *
705  * @param[in] level    NV_PRINTF LEVEL to print at
706  * @param[in] expr     Expression that evaluates to a truth value.
707  * @param[in] exprStr  Expression as a string.
708  * @param[in] elseStmt Statement to evaluate if the expression is false.
709  */
710 #define NV_CHECK_OR_ELSE_STR(level, expr, exprStr, elseStmt)                   \
711     do                                                                         \
712     {                                                                          \
713         if (NV_UNLIKELY(!(expr)))                                              \
714         {                                                                      \
715             NV_CHECK_FAILED(level, exprStr);                                   \
716             elseStmt;                                                          \
717         }                                                                      \
718     } while (0)
719 
720 
721 // *****************************************************************************
722 // *                       NV_CHECK_OK family of macros                        *
723 // *****************************************************************************
724 /**
725  * General notes:
726  *
727  * Check that an expression evaluates to NV_OK.  If not, do the following actions:
728  *   Print a message in the debug output at user specified.
729  *   Log a message in NvLog at user specified level.
730  *   "Other action" as defined by each macro below.
731  *
732  * The actions are enabled or omitted based on platform and build, and the
733  * implementations are platform dependent.
734  *
735  * The expression is always evaluated even if assertion failures are not logged
736  * in the environment.  Use @ref NV_ASSERT_OK_CHECKED if the expression should
737  * only be evaluated in checked builds.
738  *
739  * USE FOR error conditions that DO NOT require immediate action from NVIDIA,
740  * but may be useful in diagnosing other issues.
741  */
742 
743 /**
744  * Check that an expression evaluates to NV_OK.
745  *
746  * @param[in] status The NV_STATUS variable to capture the status
747  * @param[in] level NV_PRINTF LEVEL to print at
748  * @param[in] expr  Expression that evaluates to an NV_STATUS.
749  */
750 #define NV_CHECK_OK(status, level, expr)                                       \
751     do                                                                         \
752     {                                                                          \
753         NV_CHECK_OK_OR_ELSE_STR(status, level, expr, #expr,                    \
754                                 /* no other action */);                        \
755     } while(0)
756 
757 /**
758  * Check that an expression evaluates to NV_OK only in checked builds.
759  *
760  * @note The expression is only evaluated in checked builds so should
761  *       not contain required side-effects.
762  *       Also to prevent side effects, no "other action" is permitted,
763  *       and the status parameter is omitted.
764  *
765  * @param[in] level NV_PRINTF LEVEL to print at
766  * @param[in] expr Expression that evaluates to an NV_STATUS.
767  */
768 #if PORT_IS_CHECKED_BUILD
769 #define NV_CHECK_OK_CHECKED(level, expr)                                       \
770     do                                                                         \
771     {                                                                          \
772         NV_STATUS rm_pvt_status;                                               \
773         NV_CHECK_OK_OR_ELSE_STR(rm_pvt_status, level, expr, #expr,             \
774                                 /* no other action */);                        \
775     } while(0)
776 #else
777 #define NV_CHECK_OK_CHECKED(level, expr)  ((void)0)
778 #endif
779 
780 /*!
781  * Call a function that returns NV_STATUS and check that the return values is
782  * NV_OK. If an error is returned, record the error code. In case this was a
783  * first failure update global status @ref status.
784  *
785  * @param[in] status The NV_STATUS variable to capture the status
786  * @param[in] level  NV_PRINTF LEVEL to print at
787  * @param[in] expr   Expression that evaluates to an NV_STATUS.
788  */
789 #define NV_CHECK_OK_OR_CAPTURE_FIRST_ERROR(status, level, expr)                \
790     do                                                                         \
791     {                                                                          \
792         NV_STATUS rm_pvt_status;                                               \
793         NV_CHECK_OK_OR_ELSE_STR(rm_pvt_status, level, expr, #expr,             \
794             if (status == NV_OK) status = rm_pvt_status);                      \
795     } while (0)
796 
797 /**
798  * Check that an expression evaluates to NV_OK or else do something.
799  *
800  * This macro can't use NV_CHECK_OK_OR_ELSE_STR when NV_PRINTF is passed in as
801  * the elseStmt parameter.
802  *
803  * @param[in] status   The NV_STATUS variable to capture the status
804  * @param[in] level    NV_PRINTF LEVEL to print at
805  * @param[in] expr     Expression that evaluates to an NV_STATUS.
806  * @param[in] elseStmt Statement to evaluate if the expression returns error.
807  */
808 #define NV_CHECK_OK_OR_ELSE(status, level, expr, elseStmt)                     \
809     do                                                                         \
810     {                                                                          \
811         status = (expr);                                                       \
812         if (NV_UNLIKELY(NV_OK != status))                                      \
813         {                                                                      \
814             NV_CHECK_OK_FAILED(level, #expr, status);                          \
815             elseStmt;                                                          \
816         }                                                                      \
817     } while (0)
818 
819 /**
820  * Check that an expression evaluates to NV_OK or else goto a label.
821  *
822  * @param[in] status The NV_STATUS variable to capture the status
823  * @param[in] level  NV_PRINTF LEVEL to print at
824  * @param[in] expr   Expression that evaluates to an NV_STATUS.
825  * @param[in] label  Label to jump to when the expression returns error.
826  */
827 #define NV_CHECK_OK_OR_GOTO(status, level, expr, label)                        \
828     NV_CHECK_OK_OR_ELSE_STR(status, level, expr, #expr, goto label)
829 
830 /**
831  * Check that an expression evaluates to NV_TRUE or else goto a label.
832  *
833  * @param[in] status The NV_STATUS variable to capture the status
834  * @param[in] level  NV_PRINTF LEVEL to print at
835  * @param[in] expr   Expression that evaluates to either NV_TRUE or NV_FALSE.
836  * @param[in] error  Error to be reflected in @p status when @p expr evaluates
837                      to NV_FALSE.
838  * @param[in] label  Label to jump to when @p expr evaluates to NV_FALSE.
839 */
840 #define NV_CHECK_TRUE_OR_GOTO(status, level, expr, error, label)       \
841     NV_CHECK_OK_OR_ELSE_STR(status, level, ((expr) ? NV_OK : (error)), \
842         #expr, goto label);
843 
844 /**
845  * Check that an expression evaluates to NV_OK or return the status.
846  *
847  * @param[in] level NV_PRINTF LEVEL to print at
848  * @param[in] expr  Expression that evaluates to an NV_STATUS.
849  */
850 #define NV_CHECK_OK_OR_RETURN(level, expr)                                     \
851     do                                                                         \
852     {                                                                          \
853         NV_STATUS rm_pvt_status;                                               \
854         NV_CHECK_OK_OR_ELSE_STR(rm_pvt_status, level, expr, #expr,             \
855             return rm_pvt_status);                                             \
856     } while(0)
857 
858 
859 /**
860  * Check that an expression evaluates to NV_OK or else record the error code and
861  * do something.
862  *
863  * Although it can be used directly, this second level macro is designed to be
864  * called from other macros.  Passing expr through multiple levels of macros
865  * before it is stringified expands it.  This is especially bad for DRF macros,
866  * which result in an embedded %, breaking the format string in the
867  * NV_CHECK_OK_FAILED_INLINE macro defined above.  The macros in this header
868  * always pass the stringified expr as a into the second level macros as
869  * a separate parameter.
870  *
871  * @param[in] status   The NV_STATUS variable to capture the status
872  * @param[in] level    NV_PRINTF LEVEL to print at
873  * @param[in] expr     Expression that evaluates to an NV_STATUS.
874  * @param[in] exprStr  Expression as a string.
875  * @param[in] elseStmt Statement to evaluate if the expression returns error.
876  */
877 #define NV_CHECK_OK_OR_ELSE_STR(status, level, expr, exprStr, elseStmt)        \
878     do                                                                         \
879     {                                                                          \
880         status = (expr);                                                       \
881         if (NV_UNLIKELY(NV_OK != status))                                      \
882         {                                                                      \
883             NV_CHECK_OK_FAILED(level, exprStr, status);                        \
884             elseStmt;                                                          \
885         }                                                                      \
886     } while (0)
887 
888 
889 // *****************************************************************************
890 // *                 NV_ASSERT_PRECOMP family of macros                        *
891 // *****************************************************************************
892 /**
893  * General notes:
894  *
895  * Exactly the same as the NV_ASSERT macros, but always safe to use in
896  * precompiled headers.
897  *
898  * On platforms other than GSP-RM, the _INLINE macros cannot be used inside
899  * precompiled headers due to conflicting NVLOG_PRINT_IDs.  The PRECOMP macros
900  * work around this issue by calling helper functions for NvLog.
901  *
902  * Hoping for a better solution, only the macro variants that are currently
903  * used in precompiled headers are defined.
904  *
905  * See the NV_ASSERT documentation above for parameters and use cases.
906  */
907 #define NV_ASSERT_PRECOMP(expr)                                                \
908     NV_ASSERT_OR_ELSE_STR_PRECOMP(expr, #expr, /* no other action */)
909 
910 #define NV_ASSERT_OR_RETURN_PRECOMP(expr, retval)                              \
911     NV_ASSERT_OR_ELSE_STR_PRECOMP(expr, #expr, return (retval))
912 
913 #define NV_ASSERT_OR_RETURN_VOID_PRECOMP(expr)                              \
914     NV_ASSERT_OR_ELSE_STR_PRECOMP(expr, #expr, return)
915 
916 #define NV_ASSERT_OR_ELSE_STR_PRECOMP(expr, exprStr, elseStmt)                 \
917     do                                                                         \
918     {                                                                          \
919         PORT_COVERAGE_PUSH_OFF();                                              \
920         if (NV_UNLIKELY(!(expr)))                                              \
921         {                                                                      \
922             NV_ASSERT_FAILED_PRECOMP(exprStr);                                 \
923             elseStmt;                                                          \
924         }                                                                      \
925         PORT_COVERAGE_POP();                                                   \
926     } while (0)
927 
928 /**
929  * @def NV_CHECKED_ONLY
930  * @brief Compile a piece of code only in checked builds.
931  *
932  * This macro helps avoid #ifdefs to improve readability but should be
933  * used sparingly.
934  *
935  * Cases that make heavy use of this should likely define a wrapper
936  * macro or other abstraction for the build variation.
937  * For example NV_CHECKED_ONLY(NV_PRINTF(...)) is not a good use case.
938  *
939  * A typical use case is declaring and setting a canary value:
940  * ~~~{.c}
941  * typedef struct
942  * {
943  *     NV_CHECKED_ONLY(NvU32 canary);
944  *     ...
945  * } MY_STRUCT;
946  *
947  * void initMyStruct(MY_STRUCT *pStruct)
948  * {
949  *     NV_CHECKED_ONLY(pStruct->canaray = 0xDEADBEEF);
950  *     ...
951  * }
952  *
953  * void destroyMyStruct(MY_STRUCT *pStruct)
954  * {
955  *     NV_ASSERT_CHECKED(pStruct->canaray == 0xDEADBEEF);
956  *     ...
957  * }
958  * ~~~
959  */
960 #if PORT_IS_CHECKED_BUILD
961 #define NV_CHECKED_ONLY NV_EXPAND
962 #else
963 #define NV_CHECKED_ONLY NV_DISCARD
964 #endif
965 
966 // Verify prerequisites are defined.
967 #ifndef PORT_IS_CHECKED_BUILD
968 #error "NV_PORT_HEADER must define PORT_IS_CHECKED_BUILD"
969 #endif
970 #ifndef PORT_BREAKPOINT_CHECKED
971 #error "NV_PORT_HEADER must define PORT_BREAKPOINT_CHECKED"
972 #endif
973 #ifndef PORT_COVERAGE_PUSH_OFF
974 #error "NV_PORT_HEADER must define PORT_COVERAGE_PUSH_OFF"
975 #endif
976 #ifndef PORT_COVERAGE_POP
977 #error "NV_PORT_HEADER must define PORT_COVERAGE_POP"
978 #endif
979 #ifndef NV_PRINTF
980 #error "NV_PRINTF_HEADER must define NV_PRINTF"
981 #endif
982 
983 
984 #ifdef __cplusplus
985 }
986 #endif //__cplusplus
987 /// @}
988 #endif // _NV_UTILS_ASSERT_H_
989