]> git.saurik.com Git - apple/xnu.git/blame - libkern/os/log.c
xnu-4903.270.47.tar.gz
[apple/xnu.git] / libkern / os / log.c
CommitLineData
39037602
A
1#include <stddef.h>
2#undef offset
3
4#include <kern/cpu_data.h>
5#include <os/base.h>
6#include <os/object.h>
7#include <os/log.h>
8#include <stdbool.h>
9#include <stdint.h>
10
11#include <vm/vm_kern.h>
12#include <mach/vm_statistics.h>
13#include <kern/debug.h>
14#include <libkern/libkern.h>
15#include <libkern/kernel_mach_header.h>
16#include <pexpert/pexpert.h>
17#include <uuid/uuid.h>
18#include <sys/msgbuf.h>
19
20#include <mach/mach_time.h>
21#include <kern/thread.h>
22#include <kern/simple_lock.h>
23#include <kern/kalloc.h>
24#include <kern/clock.h>
25#include <kern/assert.h>
26
27#include <firehose/tracepoint_private.h>
813fb2f6 28#include <firehose/chunk_private.h>
39037602
A
29#include <os/firehose_buffer_private.h>
30#include <os/firehose.h>
31
32#include <os/log_private.h>
33#include "trace_internal.h"
34
35#include "log_encode.h"
36
d9a64523
A
37/* on embedded, with no kext loading or unloads,
38 * make the kernel use the libtrace shared cache path for logging
39 */
40#define FIREHOSE_USES_SHARED_CACHE NO_KEXTD
41
42#if FIREHOSE_USES_SHARED_CACHE
43extern vm_offset_t segLOWESTTEXT;
44#endif
45
39037602
A
46struct os_log_s {
47 int a;
48};
49
50struct os_log_s _os_log_default;
51struct os_log_s _os_log_replay;
52extern vm_offset_t kernel_firehose_addr;
813fb2f6 53extern firehose_chunk_t firehose_boot_chunk;
39037602
A
54
55extern void bsd_log_lock(void);
56extern void bsd_log_unlock(void);
cc8bc92a 57extern void logwakeup(struct msgbuf *);
39037602
A
58
59decl_lck_spin_data(extern, oslog_stream_lock)
0a7de745
A
60#define stream_lock() lck_spin_lock(&oslog_stream_lock)
61#define stream_unlock() lck_spin_unlock(&oslog_stream_lock)
62
39037602
A
63extern void oslog_streamwakeup(void);
64void oslog_streamwrite_locked(firehose_tracepoint_id_u ftid,
0a7de745 65 uint64_t stamp, const void *pubdata, size_t publen);
39037602
A
66extern void oslog_streamwrite_metadata_locked(oslog_stream_buf_entry_t m_entry);
67
68extern int oslog_stream_open;
69
70extern void *OSKextKextForAddress(const void *);
71
72/* Counters for persistence mode */
73uint32_t oslog_p_total_msgcount = 0;
74uint32_t oslog_p_metadata_saved_msgcount = 0;
75uint32_t oslog_p_metadata_dropped_msgcount = 0;
76uint32_t oslog_p_error_count = 0;
77uint32_t oslog_p_saved_msgcount = 0;
78uint32_t oslog_p_dropped_msgcount = 0;
79uint32_t oslog_p_boot_dropped_msgcount = 0;
80
81/* Counters for streaming mode */
82uint32_t oslog_s_total_msgcount = 0;
83uint32_t oslog_s_error_count = 0;
84uint32_t oslog_s_metadata_msgcount = 0;
85
86static bool oslog_boot_done = false;
5ba3f43e
A
87extern boolean_t early_boot_complete;
88
89#ifdef XNU_KERNEL_PRIVATE
90bool startup_serial_logging_active = true;
91uint64_t startup_serial_num_procs = 300;
92#endif /* XNU_KERNEL_PRIVATE */
39037602
A
93
94// XXX
95firehose_tracepoint_id_t
96firehose_debug_trace(firehose_stream_t stream, firehose_tracepoint_id_t trace_id,
0a7de745 97 uint64_t timestamp, const char *format, const void *pubdata, size_t publen);
39037602
A
98
99static inline firehose_tracepoint_id_t
100_firehose_trace(firehose_stream_t stream, firehose_tracepoint_id_u ftid,
0a7de745 101 uint64_t stamp, const void *pubdata, size_t publen);
39037602
A
102
103static oslog_stream_buf_entry_t
104oslog_stream_create_buf_entry(oslog_stream_link_type_t type, firehose_tracepoint_id_u ftid,
0a7de745 105 uint64_t stamp, const void* pubdata, size_t publen);
39037602
A
106
107static void
108_os_log_with_args_internal(os_log_t oslog __unused, os_log_type_t type __unused,
0a7de745 109 const char *format, va_list args, void *addr, void *dso);
39037602
A
110
111static void
112_os_log_to_msgbuf_internal(const char *format, va_list args, bool safe, bool logging);
113
114static void
115_os_log_to_log_internal(os_log_t oslog, os_log_type_t type,
0a7de745 116 const char *format, va_list args, void *addr, void *dso);
39037602
A
117
118
119static void
120_os_log_actual(os_log_t oslog, os_log_type_t type, const char *format, void
0a7de745 121 *dso, void *addr, os_log_buffer_context_t context);
39037602
A
122
123bool
124os_log_info_enabled(os_log_t log __unused)
125{
126 return true;
127}
128
129bool
130os_log_debug_enabled(os_log_t log __unused)
131{
132 return true;
133}
134
135os_log_t
136os_log_create(const char *subsystem __unused, const char *category __unused)
137{
138 return &_os_log_default;
139}
140
141bool
142_os_log_string_is_public(const char *str __unused)
143{
144 return true;
145}
146
0a7de745 147__attribute__((noinline, not_tail_called)) void
39037602
A
148_os_log_internal(void *dso, os_log_t log, uint8_t type, const char *message, ...)
149{
0a7de745
A
150 va_list args;
151 void *addr = __builtin_return_address(0);
39037602 152
0a7de745 153 va_start(args, message);
39037602 154
0a7de745 155 _os_log_with_args_internal(log, type, message, args, addr, dso);
39037602 156
0a7de745 157 va_end(args);
39037602 158
0a7de745 159 return;
39037602
A
160}
161
162#pragma mark - shim functions
163
0a7de745 164__attribute__((noinline, not_tail_called)) void
39037602
A
165os_log_with_args(os_log_t oslog, os_log_type_t type, const char *format, va_list args, void *addr)
166{
0a7de745
A
167 // if no address passed, look it up
168 if (addr == NULL) {
169 addr = __builtin_return_address(0);
170 }
39037602 171
0a7de745 172 _os_log_with_args_internal(oslog, type, format, args, addr, NULL);
39037602
A
173}
174
175static void
176_os_log_with_args_internal(os_log_t oslog, os_log_type_t type,
0a7de745 177 const char *format, va_list args, void *addr, void *dso)
39037602 178{
0a7de745
A
179 uint32_t logging_config = atm_get_diagnostic_config();
180 boolean_t safe;
181 boolean_t logging;
39037602 182
0a7de745
A
183 if (format[0] == '\0') {
184 return;
185 }
5ba3f43e 186
0a7de745
A
187 /* early boot can log to dmesg for later replay (27307943) */
188 safe = (!early_boot_complete || oslog_is_safe());
5ba3f43e
A
189
190 if (logging_config & ATM_TRACE_DISABLE || logging_config & ATM_TRACE_OFF) {
191 logging = false;
192 } else {
193 logging = true;
194 }
39037602 195
0a7de745
A
196 if (oslog != &_os_log_replay) {
197 _os_log_to_msgbuf_internal(format, args, safe, logging);
198 }
39037602 199
0a7de745
A
200 if (safe && logging) {
201 _os_log_to_log_internal(oslog, type, format, args, addr, dso);
202 }
39037602
A
203}
204
205static void
206_os_log_to_msgbuf_internal(const char *format, va_list args, bool safe, bool logging)
207{
0a7de745
A
208 static int msgbufreplay = -1;
209 va_list args_copy;
39037602 210
cc8bc92a 211#if DEVELOPMENT || DEBUG
0a7de745
A
212 if (safe) {
213 bsd_log_lock();
214 }
cc8bc92a 215#else
0a7de745 216 bsd_log_lock();
cc8bc92a 217#endif
39037602 218
0a7de745
A
219 if (!safe) {
220 if (-1 == msgbufreplay) {
221 msgbufreplay = msgbufp->msg_bufx;
222 }
223 } else if (logging && (-1 != msgbufreplay)) {
224 uint32_t i;
225 uint32_t localbuff_size;
226 int newl, position;
227 char *localbuff, *p, *s, *next, ch;
228
229 position = msgbufreplay;
230 msgbufreplay = -1;
231 localbuff_size = (msgbufp->msg_size + 2); /* + '\n' + '\0' */
232 /* Size for non-blocking */
233 if (localbuff_size > 4096) {
234 localbuff_size = 4096;
235 }
236 bsd_log_unlock();
237 /* Allocate a temporary non-circular buffer */
238 if ((localbuff = (char *)kalloc_noblock(localbuff_size))) {
239 /* in between here, the log could become bigger, but that's fine */
240 bsd_log_lock();
241 /*
242 * The message buffer is circular; start at the replay pointer, and
243 * make one loop up to write pointer - 1.
244 */
245 p = msgbufp->msg_bufc + position;
246 for (i = newl = 0; p != msgbufp->msg_bufc + msgbufp->msg_bufx - 1; ++p) {
247 if (p >= msgbufp->msg_bufc + msgbufp->msg_size) {
248 p = msgbufp->msg_bufc;
249 }
250 ch = *p;
251 if (ch == '\0') {
252 continue;
253 }
254 newl = (ch == '\n');
255 localbuff[i++] = ch;
256 if (i >= (localbuff_size - 2)) {
257 break;
258 }
259 }
260 bsd_log_unlock();
261
262 if (!newl) {
263 localbuff[i++] = '\n';
264 }
265 localbuff[i++] = 0;
266
267 s = localbuff;
268 while ((next = strchr(s, '\n'))) {
269 next++;
270 ch = next[0];
271 next[0] = 0;
272 os_log(&_os_log_replay, "%s", s);
273 next[0] = ch;
274 s = next;
275 }
276 kfree(localbuff, localbuff_size);
277 }
278 bsd_log_lock();
279 }
39037602 280
0a7de745
A
281 va_copy(args_copy, args);
282 vprintf_log_locked(format, args_copy);
283 va_end(args_copy);
39037602 284
cc8bc92a 285#if DEVELOPMENT || DEBUG
0a7de745
A
286 if (safe) {
287 bsd_log_unlock();
288 logwakeup(msgbufp);
289 }
cc8bc92a 290#else
0a7de745
A
291 bsd_log_unlock();
292 if (safe) {
293 logwakeup(msgbufp);
294 }
cc8bc92a 295#endif
39037602
A
296}
297
298static void
299_os_log_to_log_internal(os_log_t oslog, os_log_type_t type,
0a7de745 300 const char *format, va_list args, void *addr, void *dso)
39037602 301{
0a7de745
A
302 struct os_log_buffer_context_s context;
303 unsigned char buffer_data[OS_LOG_BUFFER_MAX_SIZE] __attribute__((aligned(8)));
304 os_log_buffer_t buffer = (os_log_buffer_t)buffer_data;
305 uint8_t pubdata[OS_LOG_BUFFER_MAX_SIZE];
306 va_list args_copy;
307
308 if (addr == NULL) {
309 return;
310 }
d9a64523
A
311
312#if FIREHOSE_USES_SHARED_CACHE
0a7de745 313 dso = (void *) segLOWESTTEXT;
d9a64523 314#else /* FIREHOSE_USES_SHARED_CACHE */
0a7de745
A
315 if (dso == NULL) {
316 dso = (void *) OSKextKextForAddress(format);
317 if (dso == NULL) {
318 return;
319 }
320 }
39037602 321
0a7de745
A
322 if (!_os_trace_addr_in_text_segment(dso, format)) {
323 return;
324 }
39037602 325
0a7de745
A
326 void *dso_addr = (void *) OSKextKextForAddress(addr);
327 if (dso != dso_addr) {
328 return;
329 }
d9a64523 330#endif /* FIREHOSE_USES_SHARED_CACHE */
39037602 331
0a7de745
A
332 memset(&context, 0, sizeof(context));
333 memset(buffer, 0, OS_LOG_BUFFER_MAX_SIZE);
39037602 334
0a7de745
A
335 context.shimmed = true;
336 context.buffer = buffer;
337 context.content_sz = OS_LOG_BUFFER_MAX_SIZE - sizeof(*buffer);
338 context.pubdata = pubdata;
339 context.pubdata_sz = sizeof(pubdata);
39037602 340
0a7de745 341 va_copy(args_copy, args);
39037602 342
0a7de745
A
343 (void)hw_atomic_add(&oslog_p_total_msgcount, 1);
344 if (_os_log_encode(format, args_copy, 0, &context)) {
345 _os_log_actual(oslog, type, format, dso, addr, &context);
346 } else {
347 (void)hw_atomic_add(&oslog_p_error_count, 1);
348 }
39037602 349
0a7de745 350 va_end(args_copy);
39037602
A
351}
352
813fb2f6
A
353static inline size_t
354_os_trace_write_location_for_address(uint8_t buf[static sizeof(uint64_t)],
0a7de745 355 void *dso, const void *address, firehose_tracepoint_flags_t *flags)
39037602 356{
d9a64523 357#if FIREHOSE_USES_SHARED_CACHE
0a7de745
A
358 *flags = _firehose_tracepoint_flags_pc_style_shared_cache;
359 memcpy(buf, (uint32_t[]){ (uintptr_t)address - (uintptr_t)dso },
360 sizeof(uint32_t));
d9a64523
A
361 return sizeof(uint32_t);
362
363#else /* FIREHOSE_USES_SHARED_CACHE */
0a7de745 364 kernel_mach_header_t *mh = dso;
39037602
A
365
366 if (mh->filetype == MH_EXECUTE) {
813fb2f6 367 *flags = _firehose_tracepoint_flags_pc_style_main_exe;
d9a64523 368
813fb2f6 369 memcpy(buf, (uint32_t[]){ (uintptr_t)address - (uintptr_t)dso },
0a7de745 370 sizeof(uint32_t));
813fb2f6 371 return sizeof(uint32_t);
39037602 372 } else {
813fb2f6
A
373 *flags = _firehose_tracepoint_flags_pc_style_absolute;
374 memcpy(buf, (uintptr_t[]){ VM_KERNEL_UNSLIDE(address) }, sizeof(uintptr_t));
375#if __LP64__
376 return 6; // 48 bits are enough
377#else
378 return sizeof(uintptr_t);
379#endif
39037602 380 }
d9a64523 381#endif /* !FIREHOSE_USES_SHARED_CACHE */
39037602
A
382}
383
384
385OS_ALWAYS_INLINE
813fb2f6
A
386static inline size_t
387_os_log_buffer_pack(uint8_t *buffdata, size_t buffdata_sz,
0a7de745 388 os_log_buffer_context_t ctx)
39037602 389{
813fb2f6
A
390 os_log_buffer_t buffer = ctx->buffer;
391 size_t buffer_sz = sizeof(*ctx->buffer) + ctx->content_sz;
392 size_t total_sz = buffer_sz + ctx->pubdata_sz;
39037602 393
813fb2f6
A
394 if (total_sz > buffdata_sz) {
395 return 0;
396 }
39037602 397
813fb2f6
A
398 memcpy(buffdata, buffer, buffer_sz);
399 memcpy(&buffdata[buffer_sz], ctx->pubdata, ctx->pubdata_sz);
400 return total_sz;
39037602
A
401}
402
403static void
404_os_log_actual(os_log_t oslog __unused, os_log_type_t type, const char *format,
0a7de745 405 void *dso, void *addr, os_log_buffer_context_t context)
39037602
A
406{
407 firehose_stream_t stream;
408 firehose_tracepoint_flags_t flags = 0;
409 firehose_tracepoint_id_u trace_id;
39037602 410 uint8_t buffdata[OS_LOG_BUFFER_MAX_SIZE];
813fb2f6 411 size_t addr_len = 0, buffdata_sz;
39037602
A
412 uint64_t timestamp;
413 uint64_t thread_id;
414
39037602 415 // dso == the start of the binary that was loaded
813fb2f6
A
416 addr_len = _os_trace_write_location_for_address(buffdata, dso, addr, &flags);
417 buffdata_sz = _os_log_buffer_pack(buffdata + addr_len,
0a7de745 418 sizeof(buffdata) - addr_len, context);
813fb2f6
A
419 if (buffdata_sz == 0) {
420 return;
421 }
422 buffdata_sz += addr_len;
39037602
A
423
424 timestamp = firehose_tracepoint_time(firehose_activity_flags_default);
425 thread_id = thread_tid(current_thread());
426
39037602
A
427 // create trace_id after we've set additional flags
428 trace_id.ftid_value = FIREHOSE_TRACE_ID_MAKE(firehose_tracepoint_namespace_log,
0a7de745 429 type, flags, _os_trace_offset(dso, format, flags));
39037602 430
39037602
A
431 if (FALSE) {
432 firehose_debug_trace(stream, trace_id.ftid_value, timestamp,
0a7de745 433 format, buffdata, buffdata_sz);
39037602 434 }
39037602
A
435 if (type == OS_LOG_TYPE_INFO || type == OS_LOG_TYPE_DEBUG) {
436 stream = firehose_stream_memory;
0a7de745 437 } else {
39037602
A
438 stream = firehose_stream_persist;
439 }
39037602
A
440 _firehose_trace(stream, trace_id, timestamp, buffdata, buffdata_sz);
441}
442
443static inline firehose_tracepoint_id_t
444_firehose_trace(firehose_stream_t stream, firehose_tracepoint_id_u ftid,
0a7de745 445 uint64_t stamp, const void *pubdata, size_t publen)
39037602
A
446{
447 const uint16_t ft_size = offsetof(struct firehose_tracepoint_s, ft_data);
448 const size_t _firehose_chunk_payload_size =
0a7de745 449 sizeof(((struct firehose_chunk_s *)0)->fc_data);
39037602
A
450
451 firehose_tracepoint_t ft;
452
453 if (slowpath(ft_size + publen > _firehose_chunk_payload_size)) {
454 // We'll need to have some handling here. For now - return 0
455 (void)hw_atomic_add(&oslog_p_error_count, 1);
456 return 0;
457 }
458
459 if (oslog_stream_open && (stream != firehose_stream_metadata)) {
0a7de745 460 stream_lock();
39037602 461 if (!oslog_stream_open) {
0a7de745 462 stream_unlock();
39037602
A
463 goto out;
464 }
465
466 oslog_s_total_msgcount++;
467 oslog_streamwrite_locked(ftid, stamp, pubdata, publen);
0a7de745 468 stream_unlock();
39037602
A
469 oslog_streamwakeup();
470 }
471
472out:
473 ft = __firehose_buffer_tracepoint_reserve(stamp, stream, (uint16_t)publen, 0, NULL);
474 if (!fastpath(ft)) {
475 if (oslog_boot_done) {
476 if (stream == firehose_stream_metadata) {
477 (void)hw_atomic_add(&oslog_p_metadata_dropped_msgcount, 1);
0a7de745 478 } else {
39037602
A
479 // If we run out of space in the persistence buffer we're
480 // dropping the message.
481 (void)hw_atomic_add(&oslog_p_dropped_msgcount, 1);
482 }
483 return 0;
484 }
813fb2f6
A
485 firehose_chunk_t fbc = firehose_boot_chunk;
486 long offset;
39037602
A
487
488 //only stream available during boot is persist
813fb2f6 489 offset = firehose_chunk_tracepoint_try_reserve(fbc, stamp,
0a7de745 490 firehose_stream_persist, 0, publen, 0, NULL);
813fb2f6 491 if (offset <= 0) {
39037602
A
492 (void)hw_atomic_add(&oslog_p_boot_dropped_msgcount, 1);
493 return 0;
494 }
813fb2f6
A
495
496 ft = firehose_chunk_tracepoint_begin(fbc, stamp, publen,
0a7de745 497 thread_tid(current_thread()), offset);
813fb2f6
A
498 memcpy(ft->ft_data, pubdata, publen);
499 firehose_chunk_tracepoint_end(fbc, ft, ftid);
500 (void)hw_atomic_add(&oslog_p_saved_msgcount, 1);
501 return ftid.ftid_value;
39037602
A
502 }
503 if (!oslog_boot_done) {
504 oslog_boot_done = true;
505 }
506 memcpy(ft->ft_data, pubdata, publen);
507
508 __firehose_buffer_tracepoint_flush(ft, ftid);
509 if (stream == firehose_stream_metadata) {
510 (void)hw_atomic_add(&oslog_p_metadata_saved_msgcount, 1);
0a7de745 511 } else {
39037602
A
512 (void)hw_atomic_add(&oslog_p_saved_msgcount, 1);
513 }
514 return ftid.ftid_value;
515}
516
517static oslog_stream_buf_entry_t
518oslog_stream_create_buf_entry(oslog_stream_link_type_t type, firehose_tracepoint_id_u ftid,
0a7de745 519 uint64_t stamp, const void* pubdata, size_t publen)
39037602
A
520{
521 oslog_stream_buf_entry_t m_entry = NULL;
522 firehose_tracepoint_t ft = NULL;
523 size_t m_entry_len = 0;
524
525 if (!pubdata) {
526 return NULL;
527 }
528
529 m_entry_len = sizeof(struct oslog_stream_buf_entry_s) +
0a7de745 530 sizeof(struct firehose_tracepoint_s) + publen;
39037602
A
531 m_entry = (oslog_stream_buf_entry_t) kalloc(m_entry_len);
532 if (!m_entry) {
533 return NULL;
534 }
535
536 m_entry->type = type;
537 m_entry->timestamp = stamp;
538 m_entry->size = sizeof(struct firehose_tracepoint_s) + publen;
539
540 ft = m_entry->metadata;
541 ft->ft_thread = thread_tid(current_thread());
542 ft->ft_id.ftid_value = ftid.ftid_value;
543 ft->ft_length = publen;
544 memcpy(ft->ft_data, pubdata, publen);
545
546 return m_entry;
547}
548
549#ifdef KERNEL
550void
551firehose_trace_metadata(firehose_stream_t stream, firehose_tracepoint_id_u ftid,
0a7de745 552 uint64_t stamp, const void *pubdata, size_t publen)
39037602
A
553{
554 oslog_stream_buf_entry_t m_entry = NULL;
555
556 // If streaming mode is not on, only log the metadata
557 // in the persistence buffer
558
0a7de745 559 stream_lock();
39037602 560 if (!oslog_stream_open) {
0a7de745 561 stream_unlock();
39037602
A
562 goto finish;
563 }
0a7de745 564 stream_unlock();
39037602
A
565
566 // Setup and write the stream metadata entry
567 m_entry = oslog_stream_create_buf_entry(oslog_stream_link_type_metadata, ftid,
0a7de745 568 stamp, pubdata, publen);
39037602
A
569 if (!m_entry) {
570 (void)hw_atomic_add(&oslog_s_error_count, 1);
571 goto finish;
572 }
573
0a7de745 574 stream_lock();
39037602 575 if (!oslog_stream_open) {
0a7de745 576 stream_unlock();
39037602 577 kfree(m_entry, sizeof(struct oslog_stream_buf_entry_s) +
0a7de745 578 sizeof(struct firehose_tracepoint_s) + publen);
39037602
A
579 goto finish;
580 }
581 oslog_s_metadata_msgcount++;
582 oslog_streamwrite_metadata_locked(m_entry);
0a7de745 583 stream_unlock();
39037602
A
584
585finish:
586 _firehose_trace(stream, ftid, stamp, pubdata, publen);
587}
588#endif
589
590firehose_tracepoint_id_t
591firehose_debug_trace(firehose_stream_t stream, firehose_tracepoint_id_t trace_id,
0a7de745 592 uint64_t timestamp, const char *format, const void *pubdata, size_t publen)
39037602
A
593{
594 kprintf("[os_log stream 0x%x trace_id 0x%llx timestamp %llu format '%s' data %p len %lu]\n",
0a7de745
A
595 (unsigned int)stream, (unsigned long long)trace_id, timestamp,
596 format, pubdata, publen);
39037602
A
597 size_t i;
598 const unsigned char *cdata = (const unsigned char *)pubdata;
0a7de745 599 for (i = 0; i < publen; i += 8) {
39037602 600 kprintf(">oslog 0x%08x: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
0a7de745
A
601 (unsigned int)i,
602 (i + 0) < publen ? cdata[i + 0] : 0,
603 (i + 1) < publen ? cdata[i + 1] : 0,
604 (i + 2) < publen ? cdata[i + 2] : 0,
605 (i + 3) < publen ? cdata[i + 3] : 0,
606 (i + 4) < publen ? cdata[i + 4] : 0,
607 (i + 5) < publen ? cdata[i + 5] : 0,
608 (i + 6) < publen ? cdata[i + 6] : 0,
609 (i + 7) < publen ? cdata[i + 7] : 0
610 );
39037602
A
611 }
612 return trace_id;
613}
614
615void
0a7de745
A
616__firehose_buffer_push_to_logd(firehose_buffer_t fb __unused, bool for_io __unused)
617{
618 oslogwakeup();
619 return;
39037602
A
620}
621
622void
813fb2f6
A
623__firehose_allocate(vm_offset_t *addr, vm_size_t size __unused)
624{
0a7de745
A
625 firehose_chunk_t kernel_buffer = (firehose_chunk_t)kernel_firehose_addr;
626
627 if (kernel_firehose_addr) {
628 *addr = kernel_firehose_addr;
629 } else {
630 *addr = 0;
631 return;
632 }
633 // Now that we are done adding logs to this chunk, set the number of writers to 0
634 // Without this, logd won't flush when the page is full
635 firehose_boot_chunk->fc_pos.fcp_refcnt = 0;
636 memcpy(&kernel_buffer[FIREHOSE_BUFFER_KERNEL_CHUNK_COUNT - 1], (const void *)firehose_boot_chunk, FIREHOSE_CHUNK_SIZE);
637 return;
39037602
A
638}
639// There isnt a lock held in this case.
640void
0a7de745
A
641__firehose_critical_region_enter(void)
642{
643 disable_preemption();
644 return;
39037602
A
645}
646
647void
0a7de745
A
648__firehose_critical_region_leave(void)
649{
650 enable_preemption();
651 return;
39037602
A
652}
653
d9a64523
A
654#ifdef CONFIG_XNUPOST
655
656#include <tests/xnupost.h>
657#define TESTOSLOGFMT(fn_name) "%u^%llu/%llu^kernel^0^test^" fn_name
658#define TESTOSLOGPFX "TESTLOG:%u#"
659#define TESTOSLOG(fn_name) TESTOSLOGPFX TESTOSLOGFMT(fn_name "#")
660
661extern u_int32_t RandomULong(void);
662extern uint32_t find_pattern_in_buffer(char * pattern, uint32_t len, int expected_count);
663void test_oslog_default_helper(uint32_t uniqid, uint64_t count);
664void test_oslog_info_helper(uint32_t uniqid, uint64_t count);
665void test_oslog_debug_helper(uint32_t uniqid, uint64_t count);
666void test_oslog_error_helper(uint32_t uniqid, uint64_t count);
667void test_oslog_fault_helper(uint32_t uniqid, uint64_t count);
668void _test_log_loop(void * arg __unused, wait_result_t wres __unused);
669void test_oslog_handleOSLogCtl(int32_t * in, int32_t * out, int32_t len);
670kern_return_t test_stresslog_dropmsg(uint32_t uniqid);
671
672kern_return_t test_os_log(void);
673kern_return_t test_os_log_parallel(void);
674
675#define GENOSLOGHELPER(fname, ident, callout_f) \
676 void fname(uint32_t uniqid, uint64_t count) \
677 { \
0a7de745
A
678 int32_t datalen = 0; \
679 uint32_t checksum = 0; \
680 char databuffer[256]; \
681 T_LOG("Doing os_log of %llu TESTLOG msgs for fn " ident, count); \
682 for (uint64_t i = 0; i < count; i++) \
683 { \
684 datalen = snprintf(databuffer, sizeof(databuffer), TESTOSLOGFMT(ident), uniqid, i + 1, count); \
685 checksum = crc32(0, databuffer, datalen); \
686 callout_f(OS_LOG_DEFAULT, TESTOSLOG(ident), checksum, uniqid, i + 1, count); \
687 /*T_LOG(TESTOSLOG(ident), checksum, uniqid, i + 1, count);*/ \
688 } \
d9a64523
A
689 }
690
691GENOSLOGHELPER(test_oslog_info_helper, "oslog_info_helper", os_log_info);
692GENOSLOGHELPER(test_oslog_fault_helper, "oslog_fault_helper", os_log_fault);
693GENOSLOGHELPER(test_oslog_debug_helper, "oslog_debug_helper", os_log_debug);
694GENOSLOGHELPER(test_oslog_error_helper, "oslog_error_helper", os_log_error);
695GENOSLOGHELPER(test_oslog_default_helper, "oslog_default_helper", os_log);
696
0a7de745
A
697kern_return_t
698test_os_log()
d9a64523 699{
0a7de745
A
700 char databuffer[256];
701 uint32_t uniqid = RandomULong();
702 uint32_t match_count = 0;
703 uint32_t checksum = 0;
704 uint32_t total_msg = 0;
705 uint32_t saved_msg = 0;
706 uint32_t dropped_msg = 0;
707 int datalen = 0;
708 uint64_t a = mach_absolute_time();
709 uint64_t seqno = 1;
710 uint64_t total_seqno = 2;
711
712 os_log_t log_handle = os_log_create("com.apple.xnu.test.t1", "kpost");
713
714 T_ASSERT_EQ_PTR(&_os_log_default, log_handle, "os_log_create returns valid value.");
715 T_ASSERT_EQ_INT(TRUE, os_log_info_enabled(log_handle), "os_log_info is enabled");
716 T_ASSERT_EQ_INT(TRUE, os_log_debug_enabled(log_handle), "os_log_debug is enabled");
717 T_ASSERT_EQ_PTR(&_os_log_default, OS_LOG_DEFAULT, "ensure OS_LOG_DEFAULT is _os_log_default");
718
719 total_msg = oslog_p_total_msgcount;
720 saved_msg = oslog_p_saved_msgcount;
721 dropped_msg = oslog_p_dropped_msgcount;
722 T_LOG("oslog internal counters total %u , saved %u, dropped %u", total_msg, saved_msg, dropped_msg);
723
724 T_LOG("Validating with uniqid %u u64 %llu", uniqid, a);
725 T_ASSERT_NE_UINT(0, uniqid, "random number should not be zero");
726 T_ASSERT_NE_ULLONG(0, a, "absolute time should not be zero");
727
728 datalen = snprintf(databuffer, sizeof(databuffer), TESTOSLOGFMT("printf_only"), uniqid, seqno, total_seqno);
729 checksum = crc32(0, databuffer, datalen);
730 printf(TESTOSLOG("printf_only") "mat%llu\n", checksum, uniqid, seqno, total_seqno, a);
731
732 seqno += 1;
733 datalen = snprintf(databuffer, sizeof(databuffer), TESTOSLOGFMT("printf_only"), uniqid, seqno, total_seqno);
734 checksum = crc32(0, databuffer, datalen);
735 printf(TESTOSLOG("printf_only") "mat%llu\n", checksum, uniqid, seqno, total_seqno, a);
736
737 datalen = snprintf(databuffer, sizeof(databuffer), "kernel^0^test^printf_only#mat%llu", a);
738 match_count = find_pattern_in_buffer(databuffer, datalen, total_seqno);
739 T_EXPECT_EQ_UINT(match_count, 2, "verify printf_only goes to systemlog buffer");
740
741 uint32_t logging_config = atm_get_diagnostic_config();
742 T_LOG("checking atm_diagnostic_config 0x%X", logging_config);
743
744 if ((logging_config & ATM_TRACE_OFF) || (logging_config & ATM_TRACE_DISABLE)) {
745 T_LOG("ATM_TRACE_OFF / ATM_TRACE_DISABLE is set. Would not see oslog messages. skipping the rest of test.");
746 return KERN_SUCCESS;
747 }
d9a64523 748
0a7de745
A
749 /* for enabled logging printfs should be saved in oslog as well */
750 T_EXPECT_GE_UINT((oslog_p_total_msgcount - total_msg), 2, "atleast 2 msgs should be seen by oslog system");
d9a64523 751
0a7de745
A
752 a = mach_absolute_time();
753 total_seqno = 1;
754 seqno = 1;
755 total_msg = oslog_p_total_msgcount;
756 saved_msg = oslog_p_saved_msgcount;
757 dropped_msg = oslog_p_dropped_msgcount;
758 datalen = snprintf(databuffer, sizeof(databuffer), TESTOSLOGFMT("oslog_info"), uniqid, seqno, total_seqno);
759 checksum = crc32(0, databuffer, datalen);
760 os_log_info(log_handle, TESTOSLOG("oslog_info") "mat%llu", checksum, uniqid, seqno, total_seqno, a);
761 T_EXPECT_GE_UINT((oslog_p_total_msgcount - total_msg), 1, "total message count in buffer");
d9a64523 762
0a7de745
A
763 datalen = snprintf(databuffer, sizeof(databuffer), "kernel^0^test^oslog_info#mat%llu", a);
764 match_count = find_pattern_in_buffer(databuffer, datalen, total_seqno);
765 T_EXPECT_EQ_UINT(match_count, 1, "verify oslog_info does not go to systemlog buffer");
d9a64523 766
0a7de745
A
767 total_msg = oslog_p_total_msgcount;
768 test_oslog_info_helper(uniqid, 10);
769 T_EXPECT_GE_UINT(oslog_p_total_msgcount - total_msg, 10, "test_oslog_info_helper: Should have seen 10 msgs");
d9a64523 770
0a7de745
A
771 total_msg = oslog_p_total_msgcount;
772 test_oslog_debug_helper(uniqid, 10);
773 T_EXPECT_GE_UINT(oslog_p_total_msgcount - total_msg, 10, "test_oslog_debug_helper:Should have seen 10 msgs");
d9a64523 774
0a7de745
A
775 total_msg = oslog_p_total_msgcount;
776 test_oslog_error_helper(uniqid, 10);
777 T_EXPECT_GE_UINT(oslog_p_total_msgcount - total_msg, 10, "test_oslog_error_helper:Should have seen 10 msgs");
d9a64523 778
0a7de745
A
779 total_msg = oslog_p_total_msgcount;
780 test_oslog_default_helper(uniqid, 10);
781 T_EXPECT_GE_UINT(oslog_p_total_msgcount - total_msg, 10, "test_oslog_default_helper:Should have seen 10 msgs");
d9a64523 782
0a7de745
A
783 total_msg = oslog_p_total_msgcount;
784 test_oslog_fault_helper(uniqid, 10);
785 T_EXPECT_GE_UINT(oslog_p_total_msgcount - total_msg, 10, "test_oslog_fault_helper:Should have seen 10 msgs");
d9a64523 786
0a7de745
A
787 T_LOG("oslog internal counters total %u , saved %u, dropped %u", oslog_p_total_msgcount, oslog_p_saved_msgcount,
788 oslog_p_dropped_msgcount);
d9a64523 789
0a7de745 790 return KERN_SUCCESS;
d9a64523
A
791}
792
793static uint32_t _test_log_loop_count = 0;
0a7de745
A
794void
795_test_log_loop(void * arg __unused, wait_result_t wres __unused)
d9a64523 796{
0a7de745
A
797 uint32_t uniqid = RandomULong();
798 test_oslog_debug_helper(uniqid, 100);
799 (void)hw_atomic_add(&_test_log_loop_count, 100);
d9a64523
A
800}
801
0a7de745
A
802kern_return_t
803test_os_log_parallel(void)
d9a64523 804{
0a7de745
A
805 thread_t thread[2];
806 kern_return_t kr;
807 uint32_t uniqid = RandomULong();
d9a64523 808
0a7de745
A
809 printf("oslog internal counters total %u , saved %u, dropped %u", oslog_p_total_msgcount, oslog_p_saved_msgcount,
810 oslog_p_dropped_msgcount);
d9a64523 811
0a7de745
A
812 kr = kernel_thread_start(_test_log_loop, NULL, &thread[0]);
813 T_ASSERT_EQ_INT(kr, KERN_SUCCESS, "kernel_thread_start returned successfully");
d9a64523 814
0a7de745
A
815 kr = kernel_thread_start(_test_log_loop, NULL, &thread[1]);
816 T_ASSERT_EQ_INT(kr, KERN_SUCCESS, "kernel_thread_start returned successfully");
d9a64523 817
0a7de745 818 test_oslog_info_helper(uniqid, 100);
d9a64523 819
0a7de745
A
820 /* wait until other thread has also finished */
821 while (_test_log_loop_count < 200) {
822 delay(1000);
823 }
d9a64523 824
0a7de745
A
825 thread_deallocate(thread[0]);
826 thread_deallocate(thread[1]);
d9a64523 827
0a7de745
A
828 T_LOG("oslog internal counters total %u , saved %u, dropped %u", oslog_p_total_msgcount, oslog_p_saved_msgcount,
829 oslog_p_dropped_msgcount);
830 T_PASS("parallel_logging tests is now complete");
d9a64523 831
0a7de745 832 return KERN_SUCCESS;
d9a64523
A
833}
834
0a7de745
A
835void
836test_oslog_handleOSLogCtl(int32_t * in, int32_t * out, int32_t len)
d9a64523 837{
0a7de745
A
838 if (!in || !out || len != 4) {
839 return;
840 }
841 switch (in[0]) {
842 case 1:
843 {
844 /* send out counters */
845 out[1] = oslog_p_total_msgcount;
846 out[2] = oslog_p_saved_msgcount;
847 out[3] = oslog_p_dropped_msgcount;
848 out[0] = KERN_SUCCESS;
849 break;
850 }
851 case 2:
852 {
853 /* mini stress run */
854 out[0] = test_os_log_parallel();
855 break;
856 }
857 case 3:
858 {
859 /* drop msg tests */
860 out[1] = RandomULong();
861 out[0] = test_stresslog_dropmsg(out[1]);
862 break;
863 }
864 case 4:
865 {
866 /* invoke log helpers */
867 uint32_t uniqid = in[3];
868 int32_t msgcount = in[2];
869 if (uniqid == 0 || msgcount == 0) {
870 out[0] = KERN_INVALID_VALUE;
871 return;
872 }
873
874 switch (in[1]) {
875 case OS_LOG_TYPE_INFO: test_oslog_info_helper(uniqid, msgcount); break;
876 case OS_LOG_TYPE_DEBUG: test_oslog_debug_helper(uniqid, msgcount); break;
877 case OS_LOG_TYPE_ERROR: test_oslog_error_helper(uniqid, msgcount); break;
878 case OS_LOG_TYPE_FAULT: test_oslog_fault_helper(uniqid, msgcount); break;
879 case OS_LOG_TYPE_DEFAULT:
880 default: test_oslog_default_helper(uniqid, msgcount); break;
881 }
882 out[0] = KERN_SUCCESS;
883 break;
884 /* end of case 4 */
885 }
886 default:
887 {
888 out[0] = KERN_INVALID_VALUE;
889 break;
890 }
891 }
892 return;
d9a64523
A
893}
894
0a7de745
A
895kern_return_t
896test_stresslog_dropmsg(uint32_t uniqid)
d9a64523 897{
0a7de745
A
898 uint32_t total, saved, dropped;
899 total = oslog_p_total_msgcount;
900 saved = oslog_p_saved_msgcount;
901 dropped = oslog_p_dropped_msgcount;
902 uniqid = RandomULong();
903 test_oslog_debug_helper(uniqid, 100);
904 while ((oslog_p_dropped_msgcount - dropped) == 0) {
905 test_oslog_debug_helper(uniqid, 100);
906 }
907 printf("test_stresslog_dropmsg: logged %u msgs, saved %u and caused a drop of %u msgs. \n", oslog_p_total_msgcount - total,
908 oslog_p_saved_msgcount - saved, oslog_p_dropped_msgcount - dropped);
909 return KERN_SUCCESS;
d9a64523
A
910}
911
912#endif