]> git.saurik.com Git - apple/xnu.git/blame - pexpert/arm/pe_kprintf.c
xnu-4903.270.47.tar.gz
[apple/xnu.git] / pexpert / arm / pe_kprintf.c
CommitLineData
5ba3f43e
A
1/*
2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
3 */
4/*
5 * file: pe_kprintf.c
6 * arm platform expert debugging output initialization.
7 */
8#include <stdarg.h>
9#include <machine/machine_routines.h>
10#include <pexpert/pexpert.h>
11#include <kern/debug.h>
12#include <kern/simple_lock.h>
13#include <os/log_private.h>
14#include <libkern/section_keywords.h>
15
16/* Globals */
0a7de745 17void (*PE_kputc)(char c) = 0;
5ba3f43e
A
18
19SECURITY_READ_ONLY_LATE(unsigned int) disable_serial_output = TRUE;
20
21decl_simple_lock_data(static, kprintf_lock)
22
23void
24PE_init_kprintf(boolean_t vm_initialized)
25{
26 unsigned int boot_arg;
27
0a7de745 28 if (PE_state.initialized == FALSE) {
5ba3f43e 29 panic("Platform Expert not initialized");
0a7de745 30 }
5ba3f43e
A
31
32 if (!vm_initialized) {
33 simple_lock_init(&kprintf_lock, 0);
34
0a7de745
A
35 if (PE_parse_boot_argn("debug", &boot_arg, sizeof(boot_arg))) {
36 if (boot_arg & DB_KPRT) {
5ba3f43e 37 disable_serial_output = FALSE;
0a7de745
A
38 }
39 }
5ba3f43e 40
0a7de745 41 if (serial_init()) {
5ba3f43e 42 PE_kputc = serial_putc;
0a7de745 43 } else {
5ba3f43e 44 PE_kputc = cnputc;
0a7de745 45 }
5ba3f43e
A
46 }
47}
48
49#ifdef MP_DEBUG
0a7de745
A
50static void
51_kprintf(const char *format, ...)
5ba3f43e
A
52{
53 va_list listp;
54
55 va_start(listp, format);
56 _doprnt_log(format, &listp, PE_kputc, 16);
57 va_end(listp);
58}
0a7de745
A
59#define MP_DEBUG_KPRINTF(x...) _kprintf(x)
60#else /* MP_DEBUG */
5ba3f43e 61#define MP_DEBUG_KPRINTF(x...)
0a7de745 62#endif /* MP_DEBUG */
5ba3f43e
A
63
64#if CONFIG_NO_KPRINTF_STRINGS
65/* Prevent CPP from breaking the definition below */
66#undef kprintf
67#endif
68
69static int cpu_last_locked = 0;
70
0a7de745
A
71__attribute__((noinline, not_tail_called))
72void
73kprintf(const char *fmt, ...)
5ba3f43e
A
74{
75 va_list listp;
76 va_list listp2;
77 boolean_t state;
78 void *caller = __builtin_return_address(0);
79
80 if (!disable_serial_output) {
5ba3f43e
A
81 /*
82 * Spin to get kprintf lock but re-enable interrupts while failing.
83 * This allows interrupts to be handled while waiting but
84 * interrupts are disabled once we have the lock.
85 */
86 state = ml_set_interrupts_enabled(FALSE);
0a7de745 87 while (!simple_lock_try(&kprintf_lock, LCK_GRP_NULL)) {
5ba3f43e
A
88 ml_set_interrupts_enabled(state);
89 ml_set_interrupts_enabled(FALSE);
90 }
91
92 if (cpu_number() != cpu_last_locked) {
93 MP_DEBUG_KPRINTF("[cpu%d...]\n", cpu_number());
94 cpu_last_locked = cpu_number();
95 }
96
97 va_start(listp, fmt);
98 va_copy(listp2, listp);
99 _doprnt_log(fmt, &listp, PE_kputc, 16);
100 va_end(listp);
101
102 simple_unlock(&kprintf_lock);
103
104#if INTERRUPT_MASKED_DEBUG
105 /*
106 * kprintf holds interrupts disabled for far too long
107 * and would trip the spin-debugger. If we are about to reenable
108 * interrupts then clear the timer and avoid panicking on the delay.
109 * Otherwise, let the code that printed with interrupt disabled
110 * take the panic when it reenables interrupts.
111 * Hopefully one day this is fixed so that this workaround is unnecessary.
112 */
0a7de745 113 if (state == TRUE) {
5ba3f43e 114 ml_spin_debug_clear_self();
0a7de745 115 }
5ba3f43e
A
116#endif
117 ml_set_interrupts_enabled(state);
118
119 // If interrupts are enabled
120 if (ml_get_interrupts_enabled()) {
121 os_log_with_args(OS_LOG_DEFAULT, OS_LOG_TYPE_DEFAULT, fmt, listp2, caller);
122 }
123 va_end(listp2);
0a7de745 124 } else {
5ba3f43e
A
125 // If interrupts are enabled
126 if (ml_get_interrupts_enabled()) {
127 va_start(listp, fmt);
128 os_log_with_args(OS_LOG_DEFAULT, OS_LOG_TYPE_DEFAULT, fmt, listp, caller);
129 va_end(listp);
130 }
131 }
132}
133
0a7de745 134void
5ba3f43e
A
135serial_putc(char c)
136{
137 uart_putc(c);
138}
139
0a7de745 140int
5ba3f43e
A
141serial_getc(void)
142{
143 return uart_getc();
144}