]> git.saurik.com Git - apple/xnu.git/blob - pexpert/arm/pe_kprintf.c
xnu-4903.270.47.tar.gz
[apple/xnu.git] / pexpert / arm / pe_kprintf.c
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 */
17 void (*PE_kputc)(char c) = 0;
18
19 SECURITY_READ_ONLY_LATE(unsigned int) disable_serial_output = TRUE;
20
21 decl_simple_lock_data(static, kprintf_lock)
22
23 void
24 PE_init_kprintf(boolean_t vm_initialized)
25 {
26 unsigned int boot_arg;
27
28 if (PE_state.initialized == FALSE) {
29 panic("Platform Expert not initialized");
30 }
31
32 if (!vm_initialized) {
33 simple_lock_init(&kprintf_lock, 0);
34
35 if (PE_parse_boot_argn("debug", &boot_arg, sizeof(boot_arg))) {
36 if (boot_arg & DB_KPRT) {
37 disable_serial_output = FALSE;
38 }
39 }
40
41 if (serial_init()) {
42 PE_kputc = serial_putc;
43 } else {
44 PE_kputc = cnputc;
45 }
46 }
47 }
48
49 #ifdef MP_DEBUG
50 static void
51 _kprintf(const char *format, ...)
52 {
53 va_list listp;
54
55 va_start(listp, format);
56 _doprnt_log(format, &listp, PE_kputc, 16);
57 va_end(listp);
58 }
59 #define MP_DEBUG_KPRINTF(x...) _kprintf(x)
60 #else /* MP_DEBUG */
61 #define MP_DEBUG_KPRINTF(x...)
62 #endif /* MP_DEBUG */
63
64 #if CONFIG_NO_KPRINTF_STRINGS
65 /* Prevent CPP from breaking the definition below */
66 #undef kprintf
67 #endif
68
69 static int cpu_last_locked = 0;
70
71 __attribute__((noinline, not_tail_called))
72 void
73 kprintf(const char *fmt, ...)
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) {
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);
87 while (!simple_lock_try(&kprintf_lock, LCK_GRP_NULL)) {
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 */
113 if (state == TRUE) {
114 ml_spin_debug_clear_self();
115 }
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);
124 } else {
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
134 void
135 serial_putc(char c)
136 {
137 uart_putc(c);
138 }
139
140 int
141 serial_getc(void)
142 {
143 return uart_getc();
144 }