log.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  1. /*
  2. * Copyright (c) 2017-2019 Richard Braun.
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include <assert.h>
  18. #include <errno.h>
  19. #include <limits.h>
  20. #include <stdarg.h>
  21. #include <stdbool.h>
  22. #include <stddef.h>
  23. #include <stdio.h>
  24. #include <stdint.h>
  25. #include <string.h>
  26. #include <kern/arg.h>
  27. #include <kern/bulletin.h>
  28. #include <kern/init.h>
  29. #include <kern/log.h>
  30. #include <kern/macros.h>
  31. #include <kern/mbuf.h>
  32. #include <kern/panic.h>
  33. #include <kern/shell.h>
  34. #include <kern/spinlock.h>
  35. #include <kern/thread.h>
  36. #include <machine/boot.h>
  37. #include <machine/cpu.h>
  38. #define LOG_BUFFER_SIZE 16384
  39. #if !ISP2(LOG_BUFFER_SIZE)
  40. #error "log buffer size must be a power-of-two"
  41. #endif
  42. #define LOG_MSG_SIZE 128
  43. #define LOG_PRINT_LEVEL LOG_INFO
  44. static struct thread *log_thread;
  45. static struct mbuf log_mbuf;
  46. static char log_buffer[LOG_BUFFER_SIZE];
  47. static unsigned int log_nr_overruns;
  48. static struct bulletin log_bulletin;
  49. /*
  50. * Global lock.
  51. *
  52. * Interrupts must be disabled when holding this lock.
  53. */
  54. static struct spinlock log_lock;
  55. struct log_record {
  56. uint8_t level;
  57. char msg[LOG_MSG_SIZE];
  58. };
  59. struct log_consumer {
  60. struct mbuf *mbuf;
  61. size_t index;
  62. };
  63. static void
  64. log_consumer_init(struct log_consumer *ctx, struct mbuf *mbuf)
  65. {
  66. ctx->mbuf = mbuf;
  67. ctx->index = mbuf_start(mbuf);
  68. }
  69. static int
  70. log_consumer_pop(struct log_consumer *ctx, struct log_record *record)
  71. {
  72. size_t size;
  73. int error;
  74. for (;;) {
  75. size = sizeof(*record);
  76. error = mbuf_read(ctx->mbuf, &ctx->index, record, &size);
  77. if (error != EINVAL) {
  78. break;
  79. } else {
  80. ctx->index = mbuf_start(ctx->mbuf);
  81. }
  82. }
  83. return error;
  84. }
  85. static const char *
  86. log_level2str(unsigned int level)
  87. {
  88. switch (level) {
  89. case LOG_EMERG:
  90. return "emerg";
  91. case LOG_ALERT:
  92. return "alert";
  93. case LOG_CRIT:
  94. return "crit";
  95. case LOG_ERR:
  96. return "error";
  97. case LOG_WARNING:
  98. return "warning";
  99. case LOG_NOTICE:
  100. return "notice";
  101. case LOG_INFO:
  102. return "info";
  103. case LOG_DEBUG:
  104. return "debug";
  105. default:
  106. return NULL;
  107. }
  108. }
  109. static void
  110. log_print_record(const struct log_record *record, unsigned int level)
  111. {
  112. if (record->level > level) {
  113. return;
  114. }
  115. if (record->level <= LOG_WARNING) {
  116. printf("%7s %s\n", log_level2str(record->level), record->msg);
  117. } else {
  118. printf("%s\n", record->msg);
  119. }
  120. }
  121. static void
  122. log_run(void *arg)
  123. {
  124. struct log_consumer ctx;
  125. unsigned long flags;
  126. bool published;
  127. (void)arg;
  128. published = false;
  129. spinlock_lock_intr_save(&log_lock, &flags);
  130. log_consumer_init(&ctx, &log_mbuf);
  131. for (;;) {
  132. struct log_record record;
  133. for (;;) {
  134. int error;
  135. error = log_consumer_pop(&ctx, &record);
  136. if (!error) {
  137. break;
  138. } else if (log_nr_overruns != 0) {
  139. record.level = LOG_ERR;
  140. snprintf(record.msg, sizeof(record.msg),
  141. "log: buffer overruns, %u messages dropped",
  142. log_nr_overruns);
  143. log_nr_overruns = 0;
  144. break;
  145. }
  146. if (!published) {
  147. spinlock_unlock_intr_restore(&log_lock, flags);
  148. bulletin_publish(&log_bulletin, 0);
  149. spinlock_lock_intr_save(&log_lock, &flags);
  150. published = true;
  151. }
  152. thread_sleep(&log_lock, &log_mbuf, "log_mbuf");
  153. }
  154. spinlock_unlock_intr_restore(&log_lock, flags);
  155. log_print_record(&record, LOG_PRINT_LEVEL);
  156. spinlock_lock_intr_save(&log_lock, &flags);
  157. }
  158. }
  159. #ifdef CONFIG_SHELL
  160. static void
  161. log_dump(unsigned int level)
  162. {
  163. struct log_consumer ctx;
  164. struct log_record record;
  165. unsigned long flags;
  166. int error;
  167. spinlock_lock_intr_save(&log_lock, &flags);
  168. log_consumer_init(&ctx, &log_mbuf);
  169. for (;;) {
  170. error = log_consumer_pop(&ctx, &record);
  171. if (error) {
  172. break;
  173. }
  174. spinlock_unlock_intr_restore(&log_lock, flags);
  175. log_print_record(&record, level);
  176. spinlock_lock_intr_save(&log_lock, &flags);
  177. }
  178. spinlock_unlock_intr_restore(&log_lock, flags);
  179. }
  180. static void
  181. log_shell_dump(struct shell *shell, int argc, char **argv)
  182. {
  183. unsigned int level;
  184. int ret;
  185. (void)shell;
  186. if (argc != 2) {
  187. level = LOG_PRINT_LEVEL;
  188. } else {
  189. ret = sscanf(argv[1], "%u", &level);
  190. if ((ret != 1) || (level >= LOG_NR_LEVELS)) {
  191. printf("log: dump: invalid arguments\n");
  192. return;
  193. }
  194. }
  195. log_dump(level);
  196. }
  197. static struct shell_cmd log_shell_cmds[] = {
  198. SHELL_CMD_INITIALIZER2("log_dump", log_shell_dump,
  199. "log_dump [<level>]",
  200. "dump the log buffer",
  201. "Only records of level less than or equal to the given level"
  202. " are printed. Level may be one of :\n"
  203. " 0: emergency\n"
  204. " 1: alert\n"
  205. " 2: critical\n"
  206. " 3: error\n"
  207. " 4: warning\n"
  208. " 5: notice\n"
  209. " 6: info\n"
  210. " 7: debug"),
  211. };
  212. static int __init
  213. log_setup_shell(void)
  214. {
  215. SHELL_REGISTER_CMDS(log_shell_cmds, shell_get_main_cmd_set());
  216. return 0;
  217. }
  218. INIT_OP_DEFINE(log_setup_shell,
  219. INIT_OP_DEP(log_setup, true),
  220. INIT_OP_DEP(shell_setup, true));
  221. #endif /* CONFIG_SHELL */
  222. static int __init
  223. log_setup(void)
  224. {
  225. mbuf_init(&log_mbuf, log_buffer, sizeof(log_buffer),
  226. sizeof(struct log_record));
  227. spinlock_init(&log_lock);
  228. bulletin_init(&log_bulletin);
  229. boot_log_info();
  230. arg_log_info();
  231. cpu_log_info(cpu_current());
  232. return 0;
  233. }
  234. INIT_OP_DEFINE(log_setup,
  235. INIT_OP_DEP(arg_setup, true),
  236. INIT_OP_DEP(cpu_setup, true),
  237. INIT_OP_DEP(spinlock_setup, true));
  238. static int __init
  239. log_start(void)
  240. {
  241. struct thread_attr attr;
  242. int error;
  243. thread_attr_init(&attr, THREAD_KERNEL_PREFIX "log_run");
  244. thread_attr_set_detached(&attr);
  245. error = thread_create(&log_thread, &attr, log_run, NULL);
  246. if (error) {
  247. panic("log: unable to create thread");
  248. }
  249. return 0;
  250. }
  251. INIT_OP_DEFINE(log_start,
  252. INIT_OP_DEP(log_setup, true),
  253. INIT_OP_DEP(thread_setup, true));
  254. int
  255. log_msg(unsigned int level, const char *format, ...)
  256. {
  257. va_list ap;
  258. int ret;
  259. va_start(ap, format);
  260. ret = log_vmsg(level, format, ap);
  261. va_end(ap);
  262. return ret;
  263. }
  264. int
  265. log_vmsg(unsigned int level, const char *format, va_list ap)
  266. {
  267. struct log_record record;
  268. unsigned long flags;
  269. int error, nr_chars;
  270. size_t size;
  271. char *ptr;
  272. assert(level < LOG_NR_LEVELS);
  273. record.level = level;
  274. nr_chars = vsnprintf(record.msg, sizeof(record.msg), format, ap);
  275. if ((unsigned int)nr_chars >= sizeof(record.msg)) {
  276. log_msg(LOG_ERR, "log: message too large");
  277. goto out;
  278. }
  279. ptr = strchr(record.msg, '\n');
  280. if (ptr != NULL) {
  281. *ptr = '\0';
  282. nr_chars = ptr - record.msg;
  283. }
  284. assert(nr_chars >= 0);
  285. size = offsetof(struct log_record, msg) + nr_chars + 1;
  286. spinlock_lock_intr_save(&log_lock, &flags);
  287. error = mbuf_push(&log_mbuf, &record, size, true);
  288. if (error) {
  289. log_nr_overruns++;
  290. }
  291. thread_wakeup(log_thread);
  292. spinlock_unlock_intr_restore(&log_lock, flags);
  293. out:
  294. return nr_chars;
  295. }
  296. int
  297. log_emerg(const char *format, ...)
  298. {
  299. va_list ap;
  300. int ret;
  301. va_start(ap, format);
  302. ret = log_vemerg(format, ap);
  303. va_end(ap);
  304. return ret;
  305. }
  306. int
  307. log_alert(const char *format, ...)
  308. {
  309. va_list ap;
  310. int ret;
  311. va_start(ap, format);
  312. ret = log_valert(format, ap);
  313. va_end(ap);
  314. return ret;
  315. }
  316. int
  317. log_crit(const char *format, ...)
  318. {
  319. va_list ap;
  320. int ret;
  321. va_start(ap, format);
  322. ret = log_vcrit(format, ap);
  323. va_end(ap);
  324. return ret;
  325. }
  326. int
  327. log_err(const char *format, ...)
  328. {
  329. va_list ap;
  330. int ret;
  331. va_start(ap, format);
  332. ret = log_verr(format, ap);
  333. va_end(ap);
  334. return ret;
  335. }
  336. int
  337. log_warning(const char *format, ...)
  338. {
  339. va_list ap;
  340. int ret;
  341. va_start(ap, format);
  342. ret = log_vwarning(format, ap);
  343. va_end(ap);
  344. return ret;
  345. }
  346. int
  347. log_notice(const char *format, ...)
  348. {
  349. va_list ap;
  350. int ret;
  351. va_start(ap, format);
  352. ret = log_vnotice(format, ap);
  353. va_end(ap);
  354. return ret;
  355. }
  356. int
  357. log_info(const char *format, ...)
  358. {
  359. va_list ap;
  360. int ret;
  361. va_start(ap, format);
  362. ret = log_vinfo(format, ap);
  363. va_end(ap);
  364. return ret;
  365. }
  366. int
  367. log_debug(const char *format, ...)
  368. {
  369. va_list ap;
  370. int ret;
  371. va_start(ap, format);
  372. ret = log_vdebug(format, ap);
  373. va_end(ap);
  374. return ret;
  375. }
  376. int
  377. log_vemerg(const char *format, va_list ap)
  378. {
  379. return log_vmsg(LOG_EMERG, format, ap);
  380. }
  381. int
  382. log_valert(const char *format, va_list ap)
  383. {
  384. return log_vmsg(LOG_ALERT, format, ap);
  385. }
  386. int
  387. log_vcrit(const char *format, va_list ap)
  388. {
  389. return log_vmsg(LOG_CRIT, format, ap);
  390. }
  391. int
  392. log_verr(const char *format, va_list ap)
  393. {
  394. return log_vmsg(LOG_ERR, format, ap);
  395. }
  396. int
  397. log_vwarning(const char *format, va_list ap)
  398. {
  399. return log_vmsg(LOG_WARNING, format, ap);
  400. }
  401. int
  402. log_vnotice(const char *format, va_list ap)
  403. {
  404. return log_vmsg(LOG_NOTICE, format, ap);
  405. }
  406. int
  407. log_vinfo(const char *format, va_list ap)
  408. {
  409. return log_vmsg(LOG_INFO, format, ap);
  410. }
  411. int
  412. log_vdebug(const char *format, va_list ap)
  413. {
  414. return log_vmsg(LOG_DEBUG, format, ap);
  415. }
  416. struct bulletin *
  417. log_get_bulletin(void)
  418. {
  419. return &log_bulletin;
  420. }