1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 2015-2022 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  * Standard printf logging interface
26  */
27 
28 #ifndef NVPRINTF_H
29 #define NVPRINTF_H
30 
31 #include "utils/nvprintf_level.h"
32 
33 #ifdef __cplusplus
34 extern "C" {
35 #endif
36 
37 #if defined(GSP_PLUGIN_BUILD) || (defined(NVRM) && NVOS_IS_LIBOS)
38 
39 /**
40  * GSPRM uses a different system for logging.
41  * The format strings, filename, line number, etc. are stored in a separate
42  * data segment that is not loaded on the GSP, but is available to the decoder.
43  */
44 
45 #include "libos_log.h"
46 
47 /**
48  * Define NV_PRINTF_LEVEL to the minimum level for debug output.  This is compared
49  * to the level for each NV_PRINT to cull them at compile time.
50  */
51 #define NV_PRINTF_LEVEL  LEVEL_NOTICE
52 
53 #undef  NV_PRINTF_ENABLED
54 #define NV_PRINTF_ENABLED              1
55 
56 #undef  NV_PRINTF_STRINGS_ALLOWED
57 #define NV_PRINTF_STRINGS_ALLOWED      0
58 
59 #define NV_PRINTF_STRING_SECTION       LIBOS_SECTION_LOGGING
60 
61 #define MAKE_NV_PRINTF_STR MAKE_LIBOS_LOGGING_STR
62 
63 // NVLOG is not used on GSP-RM.
64 #undef  NVLOG_ENABLED
65 #define NVLOG_ENABLED 0
66 
67 // Direct dmesg printing through NV_PRINTF_STRING is a no-op on GSP-RM
68 #define NV_PRINTF_STRING(module, level, format, ...)
69 
70 #if defined(GSP_PLUGIN_BUILD)
71 void log_vgpu_log_entry(const NvU64 n_args, const NvU64 * args);
72 #define LIBOS_LOG_ENTRY log_vgpu_log_entry
73 #else
74 void log_rm_log_entry(const NvU64 n_args, const NvU64 * args);
75 #define LIBOS_LOG_ENTRY log_rm_log_entry
76 #endif
77 
78 #define NV_PRINTF(level, format, ...) do {                                     \
79     if (NV_PRINTF_LEVEL_ENABLED(level))                                        \
80     {                                                                          \
81         LIBOS_LOG_INTERNAL(LIBOS_LOG_ENTRY, level,                             \
82             format, ##__VA_ARGS__);                                            \
83     }                                                                          \
84 } while (0)
85 
86 #define NV_PRINTF_EX(module, level, format, ...) do {                          \
87     if (NV_PRINTF_LEVEL_ENABLED(level))                                        \
88     {                                                                          \
89         LIBOS_LOG_INTERNAL(LIBOS_LOG_ENTRY, level,                             \
90             format, ##__VA_ARGS__);                                            \
91     }                                                                          \
92 } while (0)
93 
94 #define NV_LOG_SPECIAL(level, special, ...) do {                               \
95     if (NV_PRINTF_LEVEL_ENABLED(level))                                        \
96     {                                                                          \
97         LIBOS_LOG_INTERNAL_SPECIAL(LIBOS_LOG_ENTRY, level,                     \
98             special, ##__VA_ARGS__);                                           \
99     }                                                                          \
100 } while (0)
101 
102 #else // defined(NVRM) && NVOS_IS_LIBOS
103 
104 /**
105  * @defgroup NV_PRINTF Utility Printing Macros
106  *
107  * @brief Provides a light abstraction layer for printf logging.
108  *
109  * NvPort and NvLog are used for portability and logging primitives.
110  * If an environment cannot use these directly then it can override
111  * the NV_PORT_HEADER and NV_LOG_HEADER defines in its makefile
112  * to point to appropriate replacements.
113  * @{
114  */
115 
116 #if defined(NVRM) && !defined(NVWATCH)
117 #undef NV_PRINTF_PREFIX
118 #define NV_PRINTF_PREFIX "NVRM"
119 #undef NV_PRINTF_PREFIX_SEPARATOR
120 #define NV_PRINTF_PREFIX_SEPARATOR ": "
121 #endif
122 
123 #ifndef NV_PRINTF_PREFIX
124 /**
125  * @brief Prefix to prepend to all messages printed by @ref NV_PRINTF.
126  */
127 #define NV_PRINTF_PREFIX ""
128 #endif
129 
130 #ifndef NV_PRINTF_PREFIX_SEPARATOR
131 /**
132  * @brief Separator between prefix  messages printed by @ref NV_PRINTF.
133  *
134  * If defined, it must be a single character followed by an optional space.
135  */
136 #define NV_PRINTF_PREFIX_SEPARATOR ""
137 #endif
138 
139 #ifndef NV_PRINTF_ADD_PREFIX
140 /**
141  * @brief Apply the full prefix string to a format string.
142  *
143  * This is a function-like macro so it can support inserting arguments after the
144  * format string. Example:
145  *    #define NV_PRINTF_ADD_PREFIX(fmt) "%s():"fmt, __FUNCTION__
146  */
147 #define NV_PRINTF_ADD_PREFIX(fmt) NV_PRINTF_PREFIX NV_PRINTF_PREFIX_SEPARATOR fmt
148 #endif
149 
150 // Include portability header, falling back to NvPort if not provided.
151 #ifndef NV_PORT_HEADER
152 #define NV_PORT_HEADER "nvport/nvport.h"
153 #endif
154 #include NV_PORT_HEADER
155 
156 // Include logging header, falling back to NvLog if not provided.
157 #ifndef NV_LOG_HEADER
158 #define NV_LOG_HEADER "nvlog/nvlog_printf.h"
159 #endif
160 #include NV_LOG_HEADER
161 
162 #define NV_PRINTF_STRING_SECTION
163 
164 #define MAKE_NV_PRINTF_STR(str) str
165 
166 /**
167  * @def NV_PRINTF(level, format, args...)
168  * @brief Standard formatted printing/logging interface.
169  *
170  * @param level   - Debug level to print at. One of @ref NV_PRINTF_LEVELS
171  * @param format  - A standard printf format string. Must be a string literal.
172  * @param args... - Arguments for the format string literal, like regular printf
173  *
174  * The logging header can redefine the behavior, but the basic implementation
175  * will just print to standard output, like the printf function.
176  *
177  * This will print to the @ref NV_PRINTF_MODULE module. If the module is not
178  * defined, it will default to GLOBAL. Use @ref NV_PRINTF_EX to specify another
179  * module.
180  *
181  * This will prefix the prints with @ref NV_PRINTF_PREFIX string and function
182  * name. To specify a different (or no) prefix, use @ref NV_PRINTF_EX
183  *
184  * @note The format string must be a string literal. The level can be a variable,
185  * but it may have positive speed and size effects to use the above levels
186  * directly.
187  */
188 #ifndef NV_PRINTF
189 #define NV_PRINTF(level, format, ...) \
190     NV_PRINTF_EX(NV_PRINTF_MODULE, level, NV_PRINTF_ADD_PREFIX(format), ##__VA_ARGS__)
191 #endif
192 
193 /**
194  * @def NV_PRINTF_EX(module, level, format, args...)
195  * @brief Extended version of the standard @ref NV_PRINTF
196  *
197  * This interface allows you to explicitly specify the module to print to and
198  * doesn't perform any automatic prefixing.
199  *
200  * The logging header can redefine the behavior, but the basic implementation
201  * will just print to standard output, like the printf function.
202  *
203  * @note The format string must be a string literal. The level can be a variable,
204  * but it may have positive speed and size effects to use the above levels
205  * directly.
206  */
207 #ifndef NV_PRINTF_EX
208 #define NV_PRINTF_EX(module, level, format, ...)                            \
209     do                                                                      \
210     {                                                                       \
211         NVLOG_PRINTF(module, NVLOG_ROUTE_RM, level, format, ##__VA_ARGS__); \
212         NV_PRINTF_STRING(module, level, format, ##__VA_ARGS__);             \
213     } while (0)
214 #endif
215 
216 /**
217  * @def NV_PRINTF_STRINGS_ALLOWED
218  * @brief This switch controls whether strings are allowed to appear in the
219  * final binary.
220  *
221  * By default, strings are allowed on DEBUG and QA builds, and all MODS builds
222  */
223 #ifndef NV_PRINTF_STRINGS_ALLOWED
224 #if defined(DEBUG) || defined(NV_MODS) || defined(QA_BUILD)
225 #define NV_PRINTF_STRINGS_ALLOWED 1
226 #else
227 #define NV_PRINTF_STRINGS_ALLOWED 0
228 #endif
229 #endif // NV_PRINTF_STRINGS_ALLOWED
230 
231 //
232 // Default values for the compile time switches:
233 // - Strings are allowed on DEBUG and QA builds, and all MODS builds
234 // - NV_PRINTF is only available if strings are allowed
235 // - All levels are available if NV_PRINTF is available.
236 
237 //
238 // Special handling for RM internal prints so we have equivalent functionality
239 // between NV_PRINTF and DBG_PRINTF. This is needed to seamlessly migrate RM to
240 // the new interface. The implementations will eventually be fully extracted and
241 // only depend on other common code, such as NvPort.
242 //
243 #if defined(NVRM) && !defined(NVWATCH)
244 
245 #if NV_PRINTF_STRINGS_ALLOWED
246 
247 // Declare internal RM print function:
248 // This is utDbg_Printf in unit tests and nvDbg_Printf in regular RM builds
249 #if defined(RM_UNITTEST)
250 #define NVRM_PRINTF_FUNCTION utDbg_Printf
251 #else
252 #define NVRM_PRINTF_FUNCTION nvDbg_Printf
253 #endif // defined(RM_UNITTEST)
254 
255 void NVRM_PRINTF_FUNCTION(const char *file,
256                           int line,
257                           const char *function,
258                           int debuglevel,
259                           const char *s,
260                           ...) NVPORT_CHECK_PRINTF_ARGUMENTS(5, 6);
261 
262 #define NV_PRINTF_STRING(module, level, format, ...) \
263      NVRM_PRINTF_FUNCTION(NV_FILE_STR, __LINE__, NV_FUNCTION_STR, level, format, ##__VA_ARGS__)
264 
265 #endif // NV_PRINTF_STRINGS_ALLOWED
266 
267 // RM always has printf enabled
268 #define NV_PRINTF_ENABLED 1
269 
270 #endif // defined(NVRM) && !defined(NVWATCH)
271 
272 //
273 // Default definitions if none are specified
274 //
275 
276 /**
277  * @def NV_PRINTF_ENABLED
278  * @brief This macro evaluates to 1 if NV_PRINTF is available (either as regular
279  * debug prints or binary logging)
280  *
281  * By default, it is available on all builds that allow strings
282  */
283 #ifndef NV_PRINTF_ENABLED
284 #define NV_PRINTF_ENABLED NV_PRINTF_STRINGS_ALLOWED
285 #endif
286 
287 #if NV_PRINTF_STRINGS_ALLOWED
288 #define NV_PRINTF_LEVEL  LEVEL_INFO
289 #else
290 #define NV_PRINTF_LEVEL  LEVEL_NOTICE
291 #endif
292 
293 /**
294  * @def NV_PRINTF_STRING(module, level, format, ...)
295  * @brief Prints the string to the given output, if strings are allowed.
296  */
297 #ifndef NV_PRINTF_STRING
298 #if NV_PRINTF_STRINGS_ALLOWED
299 #define NV_PRINTF_STRING(module, level, format, ...) \
300     portDbgPrintf(format, ##__VA_ARGS__)
301 
302 #if !defined(portDbgPrintf) && !PORT_IS_FUNC_SUPPORTED(portDbgPrintf)
303 #error "NV_PORT_HEADER must implement portDbgPrintf()"
304 #endif
305 
306 #else
307 #define NV_PRINTF_STRING(module, level, format, ...)
308 #endif
309 #endif // NV_PRINTF_STRING
310 
311 #ifndef NVLOG_PRINTF
312 #define NVLOG_PRINTF(...)
313 #endif
314 
315 #endif // defined(NVRM) && NVOS_IS_LIBOS
316 
317 /**
318  * @def NV_PRINTF_COND(condition, leveltrue, levelfalse, format, args...)
319  * @brief NV_PRINTF with conditional print level
320  *
321  * Splits NV_PRINTF calls with a print level based on a variable or ternary
322  * operation, to be handled by preprocessors to remove INFO-level prints
323  *
324  * If condition is true, uses leveltrue, else uses levelfalse
325  */
326 #ifndef NV_PRINTF_COND
327 #define NV_PRINTF_COND(condition, leveltrue, levelfalse, format, ...)       \
328     do {                                                                    \
329         if (condition)                                                      \
330         {                                                                   \
331             NV_PRINTF(leveltrue, format, ##__VA_ARGS__);                    \
332         }                                                                   \
333         else                                                                \
334         {                                                                   \
335             NV_PRINTF(levelfalse, format, ##__VA_ARGS__);                   \
336         }                                                                   \
337     } while (0)
338 #endif
339 
340 //
341 // NV_FILE and NV_FUNCTION macros are used to wrap the __FILE__ and __FUNCTION__
342 // macros, respectively, to enable passing them as parameters on release builds
343 // without linking the strings into the object files.  Instead, this will use
344 // NV_LOG and other utilities to pass values in a way that the same information
345 // can be decoded on retail builds.
346 //
347 // On non-release builds, the strings are directly referenced and included in
348 // the builds (just like their normal references in DBG_PRINTF() and
349 // DBG_BREAKPOINT()).
350 //
351 // In MODS builds, we allow all printfs, but don't automatically include the
352 // __FILE__ or __FUNCTION__ references.
353 //
354 #if NV_PRINTF_STRINGS_ALLOWED && (!defined(NV_MODS) || defined(SIM_BUILD) || defined(DEBUG) || defined(NV_MODS_INTERNAL))
355 #define NV_FILE_STR      __FILE__
356 #define NV_FILE          __FILE__
357 #define NV_FILE_FMT      "%s"
358 #define NV_FILE_TYPE     const char *
359 #define NV_FUNCTION_STR  __FUNCTION__
360 #define NV_FUNCTION      __FUNCTION__
361 #define NV_FUNCTION_FMT  "%s"
362 #define NV_FUNCTION_TYPE const char *
363 #else
364 #ifndef NV_FILE_STR
365 #define NV_FILE_STR      "<file>"
366 #endif
367 #ifdef NVLOG_FILEID
368 #   define NV_FILE          NVLOG_FILEID
369 #else
370 #   define NV_FILE          0
371 #endif
372 #define NV_FILE_FMT      "<fileid:0x%06x>"
373 #define NV_FILE_TYPE     NvU32
374 //
375 // A couple caveats on portUtilExGetStackTrace():
376 //
377 // 1.  portUtilExGetStackTrace is not supported on all builds.  For example, see
378 // GCC support in util-gcc-clang.h.
379 //
380 // 2.  portUtilExGetStackTrace(0) will give us the current IP, which is
381 // current_function()+offset. Commands such as `ln` in windbg can translate the
382 // IP into func+offset. But sometimes, due to inlining/optimizations, the
383 // current function at runtime is not the same as at compile time.  In the
384 // inlining example, if a function using NV_FUNCTION is inlined, the pointer
385 // printed will be calling_function()+offset.
386 //
387 //#define NV_FUNCTION      portUtilExGetStackTrace(0)
388 #define NV_FUNCTION_STR  "<func>"
389 #define NV_FUNCTION      0
390 #define NV_FUNCTION_FMT  "<func:%p>"
391 #define NV_FUNCTION_TYPE NvUPtr
392 #endif
393 
394 #ifdef __cplusplus
395 }
396 #endif //__cplusplus
397 
398 /// @}
399 #endif // NVPRINTF_H
400