1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 2018-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 #ifndef LIBOS_LOGGER_H_
25 #define LIBOS_LOGGER_H_
26 
27 #include "nvtypes.h"
28 #include <stdarg.h>
29 #include "libos_printf_arg.h"
30 
31 #if defined(NVRM)
32 #include "nvctassert.h"
33 #include "utils/nvprintf_level.h"
34 #endif
35 
36 /**
37  *  @brief The log metadata structures and format strings are stripped
38  *         These structures are emitted into the .logging section
39  *         which is stripped from the image as the final build step.
40  *
41  */
42 typedef struct
43 {
44     NV_DECLARE_ALIGNED(const char *filename, 8);
45     NV_DECLARE_ALIGNED(const char *format, 8);
46     NV_DECLARE_ALIGNED(NvU32 lineNumber, 8);
47     NvU8 argumentCount; //! Count of arguments not including format string.
48     NvU8 printLevel;
49 } libosLogMetadata;
50 
51 /**
52  *  @brief The log metadata structure extended for accomodating remote
53  *         task's symbol resolution.
54  *         It contains a flag 'version_extended', containing its high bit
55  *         set so that this extended struct can be differentiated from
56  *         the original struct.
57  *
58  */
59 typedef struct
60 {
61     NV_DECLARE_ALIGNED(NvU64 versionExtended, 8);
62     NV_DECLARE_ALIGNED(const char *elfSectionName, 8);
63     libosLogMetadata meta;
64 } libosLogMetadata_extended;
65 
66 /*!
67  *  Count arguments
68  *
69  */
70 #define LIBOS_MACRO_GET_COUNT(...)                                                                           \
71     LIBOS_MACRO_GET_19TH(__VA_ARGS__, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
72 #define LIBOS_MACRO_GET_19TH(                                                                                \
73     _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, N, ...)                 \
74     N
75 
76 /*!
77  *  Utility
78  *
79  */
80 #define LIBOS_MACRO_PASTE(fmt, b)             fmt##b
81 #define LIBOS_MACRO_PASTE_EVAL(fmt, b)        LIBOS_MACRO_PASTE(fmt, b)
82 #define LIBOS_MACRO_FIRST(format_string, ...) format_string
83 
84 /*!
85  *  Cast remaining log arguments to integers for storage
86  *
87  */
88 static inline LibosPrintfArgument LibosPrintfArgumentU64(NvU64 i) {
89     LibosPrintfArgument r;
90     r.i = i;
91     return r;
92 }
93 
94 static inline LibosPrintfArgument LibosPrintfArgumentS64(NvS64 i) {
95     LibosPrintfArgument r;
96     r.i = (NvU64)i;
97     return r;
98 }
99 
100 #if !defined(NVRM) && !defined(PMU_RTOS) && LIBOS_CONFIG_FLOAT
101     static inline LibosPrintfArgument LibosPrintfArgumentFloat(float f) {
102         LibosPrintfArgument r;
103         r.f = f;
104         return r;
105     }
106     static inline LibosPrintfArgument LibosPrintfArgumentDouble(double f) {
107         LibosPrintfArgument r;
108         r.f = f;
109         return r;
110     }
111 
112 #   define LIBOS_LOG_BUILD_ARG(a)  _Generic((a),                                 \
113                                     float: LibosPrintfArgumentFloat(a),          \
114                                     double: LibosPrintfArgumentDouble(a),        \
115                                     default : LibosPrintfArgumentU64((NvU64)a)),
116 
117 #else
118 #   define LIBOS_LOG_BUILD_ARG(a)  (NvU64)(a),
119 #endif
120 
121 #define LIBOS_LOG_BUILD_1(fmt)
122 #define LIBOS_LOG_BUILD_2(fmt, b)       LIBOS_LOG_BUILD_ARG(b)
123 #define LIBOS_LOG_BUILD_3(fmt, b, c)    LIBOS_LOG_BUILD_ARG(b) LIBOS_LOG_BUILD_ARG(c)
124 #define LIBOS_LOG_BUILD_4(fmt, b, c, d) LIBOS_LOG_BUILD_ARG(b) LIBOS_LOG_BUILD_ARG(c) LIBOS_LOG_BUILD_ARG(d)
125 #define LIBOS_LOG_BUILD_5(fmt, b, c, d, e)                                                                   \
126     LIBOS_LOG_BUILD_ARG(b) LIBOS_LOG_BUILD_ARG(c) LIBOS_LOG_BUILD_ARG(d) LIBOS_LOG_BUILD_ARG(e)
127 #define LIBOS_LOG_BUILD_6(fmt, b, c, d, e, f)                                                                \
128     LIBOS_LOG_BUILD_ARG(b)                                                                                   \
129     LIBOS_LOG_BUILD_ARG(c) LIBOS_LOG_BUILD_ARG(d) LIBOS_LOG_BUILD_ARG(e) LIBOS_LOG_BUILD_ARG(f)
130 #define LIBOS_LOG_BUILD_7(fmt, b, c, d, e, f, g)                                                             \
131     LIBOS_LOG_BUILD_ARG(b)                                                                                   \
132     LIBOS_LOG_BUILD_ARG(c) LIBOS_LOG_BUILD_ARG(d) LIBOS_LOG_BUILD_ARG(e) LIBOS_LOG_BUILD_ARG(f)              \
133         LIBOS_LOG_BUILD_ARG(g)
134 #define LIBOS_LOG_BUILD_8(fmt, b, c, d, e, f, g, h)                                                          \
135     LIBOS_LOG_BUILD_ARG(b)                                                                                   \
136     LIBOS_LOG_BUILD_ARG(c) LIBOS_LOG_BUILD_ARG(d) LIBOS_LOG_BUILD_ARG(e) LIBOS_LOG_BUILD_ARG(f)              \
137         LIBOS_LOG_BUILD_ARG(g) LIBOS_LOG_BUILD_ARG(h)
138 #define LIBOS_LOG_BUILD_9(fmt, b, c, d, e, f, g, h, i)                                                       \
139     LIBOS_LOG_BUILD_ARG(b)                                                                                   \
140     LIBOS_LOG_BUILD_ARG(c) LIBOS_LOG_BUILD_ARG(d) LIBOS_LOG_BUILD_ARG(e) LIBOS_LOG_BUILD_ARG(f)              \
141         LIBOS_LOG_BUILD_ARG(g) LIBOS_LOG_BUILD_ARG(h) LIBOS_LOG_BUILD_ARG(i)
142 #define LIBOS_LOG_BUILD_10(fmt, b, c, d, e, f, g, h, i, j)                                                   \
143     LIBOS_LOG_BUILD_ARG(b)                                                                                   \
144     LIBOS_LOG_BUILD_ARG(c) LIBOS_LOG_BUILD_ARG(d) LIBOS_LOG_BUILD_ARG(e) LIBOS_LOG_BUILD_ARG(f)              \
145         LIBOS_LOG_BUILD_ARG(g) LIBOS_LOG_BUILD_ARG(h) LIBOS_LOG_BUILD_ARG(i) LIBOS_LOG_BUILD_ARG(j)
146 #define LIBOS_LOG_BUILD_11(fmt, b, c, d, e, f, g, h, i, j, k)                                                \
147     LIBOS_LOG_BUILD_ARG(b)                                                                                   \
148     LIBOS_LOG_BUILD_ARG(c) LIBOS_LOG_BUILD_ARG(d) LIBOS_LOG_BUILD_ARG(e) LIBOS_LOG_BUILD_ARG(f)              \
149         LIBOS_LOG_BUILD_ARG(g) LIBOS_LOG_BUILD_ARG(h) LIBOS_LOG_BUILD_ARG(i) LIBOS_LOG_BUILD_ARG(j)          \
150             LIBOS_LOG_BUILD_ARG(k)
151 #define LIBOS_LOG_BUILD_12(fmt, b, c, d, e, f, g, h, i, j, k, l)                                             \
152     LIBOS_LOG_BUILD_ARG(b)                                                                                   \
153     LIBOS_LOG_BUILD_ARG(c) LIBOS_LOG_BUILD_ARG(d) LIBOS_LOG_BUILD_ARG(e) LIBOS_LOG_BUILD_ARG(f)              \
154         LIBOS_LOG_BUILD_ARG(g) LIBOS_LOG_BUILD_ARG(h) LIBOS_LOG_BUILD_ARG(i) LIBOS_LOG_BUILD_ARG(j)          \
155             LIBOS_LOG_BUILD_ARG(k) LIBOS_LOG_BUILD_ARG(l)
156 #define LIBOS_LOG_BUILD_13(fmt, b, c, d, e, f, g, h, i, j, k, l, m)                                          \
157     LIBOS_LOG_BUILD_ARG(b)                                                                                   \
158     LIBOS_LOG_BUILD_ARG(c) LIBOS_LOG_BUILD_ARG(d) LIBOS_LOG_BUILD_ARG(e) LIBOS_LOG_BUILD_ARG(f)              \
159         LIBOS_LOG_BUILD_ARG(g) LIBOS_LOG_BUILD_ARG(h) LIBOS_LOG_BUILD_ARG(i) LIBOS_LOG_BUILD_ARG(j)          \
160             LIBOS_LOG_BUILD_ARG(k) LIBOS_LOG_BUILD_ARG(l) LIBOS_LOG_BUILD_ARG(m)
161 #define LIBOS_LOG_BUILD_14(fmt, b, c, d, e, f, g, h, i, j, k, l, m, n)                                       \
162     LIBOS_LOG_BUILD_ARG(b)                                                                                   \
163     LIBOS_LOG_BUILD_ARG(c) LIBOS_LOG_BUILD_ARG(d) LIBOS_LOG_BUILD_ARG(e) LIBOS_LOG_BUILD_ARG(f)              \
164         LIBOS_LOG_BUILD_ARG(g) LIBOS_LOG_BUILD_ARG(h) LIBOS_LOG_BUILD_ARG(i) LIBOS_LOG_BUILD_ARG(j)          \
165             LIBOS_LOG_BUILD_ARG(k) LIBOS_LOG_BUILD_ARG(l) LIBOS_LOG_BUILD_ARG(m) LIBOS_LOG_BUILD_ARG(n)
166 #define LIBOS_LOG_BUILD_15(fmt, b, c, d, e, f, g, h, i, j, k, l, m, n, o)                                    \
167     LIBOS_LOG_BUILD_ARG(b)                                                                                   \
168     LIBOS_LOG_BUILD_ARG(c) LIBOS_LOG_BUILD_ARG(d) LIBOS_LOG_BUILD_ARG(e) LIBOS_LOG_BUILD_ARG(f)              \
169         LIBOS_LOG_BUILD_ARG(g) LIBOS_LOG_BUILD_ARG(h) LIBOS_LOG_BUILD_ARG(i) LIBOS_LOG_BUILD_ARG(j)          \
170             LIBOS_LOG_BUILD_ARG(k) LIBOS_LOG_BUILD_ARG(l) LIBOS_LOG_BUILD_ARG(m) LIBOS_LOG_BUILD_ARG(n)      \
171                 LIBOS_LOG_BUILD_ARG(o)
172 #define LIBOS_LOG_BUILD_16(fmt, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p)                                 \
173     LIBOS_LOG_BUILD_ARG(b)                                                                                   \
174     LIBOS_LOG_BUILD_ARG(c) LIBOS_LOG_BUILD_ARG(d) LIBOS_LOG_BUILD_ARG(e) LIBOS_LOG_BUILD_ARG(f)              \
175         LIBOS_LOG_BUILD_ARG(g) LIBOS_LOG_BUILD_ARG(h) LIBOS_LOG_BUILD_ARG(i) LIBOS_LOG_BUILD_ARG(j)          \
176             LIBOS_LOG_BUILD_ARG(k) LIBOS_LOG_BUILD_ARG(l) LIBOS_LOG_BUILD_ARG(m) LIBOS_LOG_BUILD_ARG(n)      \
177                 LIBOS_LOG_BUILD_ARG(o) LIBOS_LOG_BUILD_ARG(p)
178 #define LIBOS_LOG_BUILD_17(fmt, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q)                              \
179     LIBOS_LOG_BUILD_ARG(b)                                                                                   \
180     LIBOS_LOG_BUILD_ARG(c) LIBOS_LOG_BUILD_ARG(d) LIBOS_LOG_BUILD_ARG(e) LIBOS_LOG_BUILD_ARG(f)              \
181         LIBOS_LOG_BUILD_ARG(g) LIBOS_LOG_BUILD_ARG(h) LIBOS_LOG_BUILD_ARG(i) LIBOS_LOG_BUILD_ARG(j)          \
182             LIBOS_LOG_BUILD_ARG(k) LIBOS_LOG_BUILD_ARG(l) LIBOS_LOG_BUILD_ARG(m) LIBOS_LOG_BUILD_ARG(n)      \
183                 LIBOS_LOG_BUILD_ARG(o) LIBOS_LOG_BUILD_ARG(p) LIBOS_LOG_BUILD_ARG(q)
184 #define LIBOS_LOG_BUILD_18(fmt, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r)                           \
185     LIBOS_LOG_BUILD_ARG(b)                                                                                   \
186     LIBOS_LOG_BUILD_ARG(c) LIBOS_LOG_BUILD_ARG(d) LIBOS_LOG_BUILD_ARG(e) LIBOS_LOG_BUILD_ARG(f)              \
187         LIBOS_LOG_BUILD_ARG(g) LIBOS_LOG_BUILD_ARG(h) LIBOS_LOG_BUILD_ARG(i) LIBOS_LOG_BUILD_ARG(j)          \
188             LIBOS_LOG_BUILD_ARG(k) LIBOS_LOG_BUILD_ARG(l) LIBOS_LOG_BUILD_ARG(m) LIBOS_LOG_BUILD_ARG(n)      \
189                 LIBOS_LOG_BUILD_ARG(o) LIBOS_LOG_BUILD_ARG(p) LIBOS_LOG_BUILD_ARG(q) LIBOS_LOG_BUILD_ARG(r)
190 
191 #define LIBOS_LOG_BUILD_APPLY(F, ...) F(__VA_ARGS__)
192 #define APPLY_REMAINDER(...)                                                                                 \
193     LIBOS_LOG_BUILD_APPLY(                                                                                   \
194         LIBOS_MACRO_PASTE_EVAL(LIBOS_LOG_BUILD_, LIBOS_MACRO_GET_COUNT(__VA_ARGS__)), __VA_ARGS__)
195 
196 // Defines for clients that cannot include nvprintf.h
197 #define LOG_LEVEL_INFO    1
198 #define LOG_LEVEL_WARNING 3
199 #define LOG_LEVEL_ERROR   4
200 
201 #if defined(NVRM) && !defined(NVOC)
202 // Verify log levels are in sync with RM
203 ct_assert(LOG_LEVEL_INFO == LEVEL_INFO);
204 ct_assert(LOG_LEVEL_WARNING == LEVEL_WARNING);
205 ct_assert(LOG_LEVEL_ERROR == LEVEL_ERROR);
206 #endif
207 
208 //
209 // Store string literal in LIBOS_SECTION_LOGGING so that it can be passed as %s format argument.
210 // This uses GNU statement expression extension.
211 //
212 #if defined(__GNUC__)
213 #define MAKE_LIBOS_LOGGING_STR(str) \
214 ({                                                                  \
215     static LIBOS_SECTION_LOGGING const char libos_pvt_str[] = str;  \
216     libos_pvt_str;                                                     \
217 })
218 #else
219 #define MAKE_LIBOS_LOGGING_STR(str) str
220 #endif
221 
222 #define LIBOS_SECTION_LOGGING __attribute__((section(".logging")))
223 
224 // The compiler used for Windows doesn't have access to the format attribute
225 #if defined(__GNUC__)
226 __attribute__((format(printf, 1, 2)))
227 #endif
228 static inline void gccFakePrintf(const char *pFmt, ...)
229 {
230     (void)pFmt;
231 }
232 
233 #if defined(DEBUG)
234 #define LIBOS_CHECK_PRINTF_FMT(...) gccFakePrintf(__VA_ARGS__)
235 #else
236 #define LIBOS_CHECK_PRINTF_FMT(...)
237 #endif // defined(DEBUG)
238 
239 void LibosLogTokens(const libosLogMetadata * metadata, const LibosPrintfArgument * tokens, NvU64 count);
240 
241 /*!
242  *  Cast remaining log arguments to integers for storage
243  *
244  */
245 #define LibosLog(level, ...)                                                                                   \
246     do                                                                                                         \
247     {                                                                                                          \
248         if (0)                                                                                                 \
249             LIBOS_CHECK_PRINTF_FMT(__VA_ARGS__);                                                               \
250         static const LIBOS_SECTION_LOGGING char libos_pvt_format[]         = {LIBOS_MACRO_FIRST(__VA_ARGS__)}; \
251         static const LIBOS_SECTION_LOGGING char libos_pvt_file[]           = {__FILE__};                       \
252         static const LIBOS_SECTION_LOGGING libosLogMetadata libos_pvt_meta = {                                 \
253             .filename      = &libos_pvt_file[0],                                                               \
254             .format        = &libos_pvt_format[0],                                                             \
255             .lineNumber    = __LINE__,                                                                         \
256             .argumentCount = LIBOS_MACRO_GET_COUNT(__VA_ARGS__) - 1,                                           \
257             .printLevel    = level};                                                                           \
258         const LibosPrintfArgument tokens[] = { APPLY_REMAINDER(__VA_ARGS__) };                                 \
259         LibosLogTokens(&libos_pvt_meta, &tokens[0], sizeof(tokens) / sizeof(*tokens));                         \
260     } while (0)
261 
262 #ifdef LIBOS_LOGGING_METADATA_SPLIT
263 /*!
264  * When the METADATA_SPLIT feature is enabled, libos print data is split between 4 input sections (all of which
265  * must be dropped from the final image). The default .logging is used for str literals and custom strings which
266  * are directly referenced by pointer (for %s substitution); .logging_const is used for format strings and the
267  * aux metadata; and .logging_metadata is used for metadata vars.
268  *
269  * The idea is to have a split where  metadata-only changes (i.e. changing what data gets printed, line number changes
270  * in file with prints, file renames) will usually not affect the main image, and can be bundled together and
271  * relied upon to trigger custom ucode build release behavior.
272  * The only exception is renaming headers with prints inside static inline functions; since these don't overlap
273  * with basenames, and we can't reliably get a nonvolatile version of a header file name here, such name changes
274  * alone won't be able to trigger ucode releases.
275  */
276 #    define LIBOS_SECTION_LOGGING_CONST    __attribute__((section(".logging_const")))
277 #    define LIBOS_SECTION_LOGGING_METADATA __attribute__((section(".logging_metadata")))
278 #    define LIBOS_LOGGING_AUX_METADATA_DUMP \
279     static const LIBOS_SECTION_LOGGING_CONST int  libos_dummy_line[] LIBOS_ATTR_USED = {__LINE__};
280 #else // LIBOS_LOGGING_VOLATILE_METADATA_SPLIT
281 #    define LIBOS_SECTION_LOGGING_CONST  LIBOS_SECTION_LOGGING
282 #    define LIBOS_SECTION_LOGGING_METADATA  LIBOS_SECTION_LOGGING
283 #    define LIBOS_LOGGING_AUX_METADATA_DUMP
284 #endif // LIBOS_LOGGING_VOLATILE_METADATA_SPLIT
285 
286 /*!
287  *  Used for log variables which we want to dump; clients may want to pick these up to check for metadata changes
288  */
289 #define LIBOS_ATTR_USED                __attribute__((used))
290 
291 /*!
292  *  Cast remaining log arguments to integers for storage
293  */
294 #define LIBOS_LOG_INTERNAL(dispatcher, level, ...)                                                             \
295     do                                                                                                         \
296     {                                                                                                          \
297         static const LIBOS_SECTION_LOGGING_CONST char libos_pvt_format[]   = {LIBOS_MACRO_FIRST(__VA_ARGS__)}; \
298         static const LIBOS_SECTION_LOGGING_CONST char libos_pvt_file[]     = {__FILE__};                       \
299         if (0)                                                                                                 \
300             LIBOS_CHECK_PRINTF_FMT(__VA_ARGS__);                                                               \
301         LIBOS_LOGGING_AUX_METADATA_DUMP;                                                                       \
302         static const LIBOS_SECTION_LOGGING_METADATA libosLogMetadata libos_pvt_meta = {                        \
303             .filename      = &libos_pvt_file[0],                                                               \
304             .format        = &libos_pvt_format[0],                                                             \
305             .lineNumber    = __LINE__,                                                                         \
306             .argumentCount = LIBOS_MACRO_GET_COUNT(__VA_ARGS__) - 1,                                           \
307             .printLevel    = level};                                                                           \
308         const NvU64 tokens[] = {APPLY_REMAINDER(__VA_ARGS__)(NvU64) & libos_pvt_meta};                         \
309         dispatcher(sizeof(tokens) / sizeof(*tokens), &tokens[0]);                                              \
310     } while (0)
311 
312 /*!
313  *  Cast remaining log arguments to integers for storage
314  *  This macro is used when logging for other task's address
315  */
316 #define LIBOS_LOG_ADDRESS(dispatcher, taskElfSectionName, level, ...)                                          \
317     do                                                                                                         \
318     {                                                                                                          \
319         static const LIBOS_SECTION_LOGGING_CONST char libos_pvt_format[]   = {LIBOS_MACRO_FIRST(__VA_ARGS__)}; \
320         static const LIBOS_SECTION_LOGGING_CONST char libos_pvt_file[]     = {__FILE__};                       \
321         static const LIBOS_SECTION_LOGGING_CONST char libos_pvt_elf_name[] = {taskElfSectionName};             \
322         LIBOS_LOGGING_AUX_METADATA_DUMP;                                                                       \
323         const libosLogMetadata libos_pvt_meta = {                                                              \
324             .filename      = &libos_pvt_file[0],                                                               \
325             .format        = &libos_pvt_format[0],                                                             \
326             .lineNumber    = __LINE__,                                                                         \
327             .argumentCount = LIBOS_MACRO_GET_COUNT(__VA_ARGS__) - 1,                                           \
328             .printLevel    = level};                                                                           \
329         static const LIBOS_SECTION_LOGGING_METADATA libosLogMetadata_extended libos_pvt_meta_ex = {            \
330             .versionExtended = 0x8000000000000000ULL,                                                          \
331             .elfSectionName  = &libos_pvt_elf_name[0],                                                         \
332             .meta            = libos_pvt_meta};                                                                \
333         const NvU64 tokens[] = {APPLY_REMAINDER(__VA_ARGS__)(NvU64) & libos_pvt_meta_ex};                      \
334         dispatcher(sizeof(tokens) / sizeof(*tokens), &tokens[0]);                                              \
335     } while (0)
336 
337 #endif
338