1/* Copyright (c) 2021 Apple Inc. All rights reserved. */
2
3#include <kern/clock.h>
4#include <libkern/libkern.h>
5#include <machine/machine_routines.h>
6#include <os/system_event_log.h>
7
8static const char *
9convert_subsystem_to_string(uint8_t subsystem)
10{
11 switch (subsystem) {
12 case SYSTEM_EVENT_SUBSYSTEM_LAUNCHD:
13 return "launchd";
14 case SYSTEM_EVENT_SUBSYSTEM_TEST:
15 return "test";
16 case SYSTEM_EVENT_SUBSYSTEM_NVRAM:
17 return "nvram";
18 case SYSTEM_EVENT_SUBSYSTEM_PROCESS:
19 return "process";
20 case SYSTEM_EVENT_SUBSYSTEM_PMRD:
21 return "iopmrd";
22 default:
23 break;
24 }
25 return "UNKNOWN";
26}
27
28static const char *
29convert_type_to_string(uint8_t type)
30{
31 switch (type) {
32 case SYSTEM_EVENT_TYPE_INFO:
33 return "INFO";
34 case SYSTEM_EVENT_TYPE_ERROR:
35 return "ERROR";
36 default:
37 break;
38 }
39 return "UNKNOWN";
40}
41
42/* We don't want to interfere with critical tasks.
43 * Skip recording this event if:
44 * 1. Interrupts are disabled.
45 * 2. We are not in a panic.
46 * A suggested improvement is adding events to an MPSC queue to log later on (rdar://84678724).
47 */
48static bool
49is_recording_allowed(void)
50{
51 return ml_get_interrupts_enabled() || panic_active();
52}
53
54static void
55_record_system_event_internal(uint8_t type, uint8_t subsystem, const char *event, const char *payload)
56{
57 const char *type_string = convert_type_to_string(type);
58 const char *subsystem_string = convert_subsystem_to_string(subsystem);
59
60 uint64_t nanosecs;
61 const uint64_t timestamp = mach_continuous_time();
62 absolutetime_to_nanoseconds(abstime: timestamp, result: &nanosecs);
63
64 printf("[System Event] [%llu] [%s] [Subsystem: %s] [Event: %.*s] %s\n", timestamp, type_string, subsystem_string, SYSTEM_EVENT_EVENT_MAX, event, payload);
65}
66
67void
68record_system_event(uint8_t type, uint8_t subsystem, const char *event, const char *format, ...)
69{
70 if (!is_recording_allowed()) {
71 return;
72 }
73
74 va_list args;
75 va_start(args, format);
76 char payload[SYSTEM_EVENT_PAYLOAD_MAX];
77
78 vsnprintf(payload, sizeof(payload), format, args);
79 va_end(args);
80
81 _record_system_event_internal(type, subsystem, event, payload);
82}
83
84void
85record_system_event_no_varargs(uint8_t type, uint8_t subsystem, const char *event, const char *payload)
86{
87 if (!is_recording_allowed()) {
88 return;
89 }
90
91 _record_system_event_internal(type, subsystem, event, payload);
92}
93