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