2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
31 #include <i386/cpu_data.h>
32 #include <i386/bit_routines.h>
33 #include <i386/machine_cpu.h>
34 #include <i386/machine_routines.h>
35 #include <i386/misc_protos.h>
36 #include <i386/serial_io.h>
37 #endif /* __x86_64__ */
39 #include <libkern/OSAtomic.h>
40 #include <vm/vm_kern.h>
41 #include <vm/vm_map.h>
42 #include <console/video_console.h>
43 #include <console/serial_protos.h>
44 #include <kern/kalloc.h>
45 #include <kern/thread.h>
46 #include <kern/cpu_data.h>
51 #define MAX_CPU_SLOTS (MAX_CPUS)
60 decl_simple_lock_data(, read_lock
);
61 decl_simple_lock_data(, write_lock
);
64 hw_lock_data_t cnputc_lock
;
65 static volatile uint32_t console_output
= 0;
68 * New allocation mechanism for console buffers
69 * Total allocation: 1 * PAGE_SIZE
70 * - Each cpu gets CPU_CONS_BUF_SIZE buffer
71 * - Kernel wide console ring gets PAGE_SIZE - MAX_CPU_SLOTS * CPU_CONS_BUF_SIZE
73 * At the return from console_init() the memory is setup as follows:
74 * +----------------------------+-------------+-------------+-------------+-------------+
75 * |console ring buffer---------|f2eec075-----|f2eec075-----|f2eec075-----|f2eec075-----|
76 * +----------------------------+-------------+-------------+-------------+-------------+
77 * Each cpu allocation will find the first (f2eec075) and use that buffer.
81 #define CPU_CONS_BUF_SIZE 256
82 #define CPU_BUF_FREE_HEX 0xf2eec075
84 #define KERN_CONSOLE_BUF_SIZE vm_map_round_page(CPU_CONS_BUF_SIZE *(MAX_CPU_SLOTS + 1), PAGE_SIZE - 1)
85 #define KERN_CONSOLE_RING_SIZE (KERN_CONSOLE_BUF_SIZE - (CPU_CONS_BUF_SIZE * MAX_CPU_SLOTS))
88 * A serial line running at 115200 bps can output ~11.5 characters per millisecond.
89 * Synchronous serial logging with preemption+interrupts disabled fundamentally prevents us
90 * from hitting expected scheduling deadlines, but we can at least tone it down a bit.
92 * TODO: IOLog should use asynchronous serial logging instead of the synchronous serial console. (26555148)
94 * Keep interrupt disabled periods shorter than 1ms
96 #define MAX_INT_DISABLED_FLUSH_SIZE 8
97 #define MAX_TOTAL_FLUSH_SIZE (MAX(2, MAX_CPU_SLOTS) * CPU_CONS_BUF_SIZE)
99 typedef struct console_buf
{
103 #define CPU_BUFFER_LEN (CPU_CONS_BUF_SIZE - 3 * (sizeof(char *)))
104 char buf
[CPU_BUFFER_LEN
];
107 extern int serial_getc(void);
108 extern void serial_putc(char);
110 static void _serial_putc(int, int, int);
112 struct console_ops cons_ops
[] = {
114 .putc
= _serial_putc
, .getc
= _serial_getc
,
117 .putc
= vcputc
, .getc
= vcgetc
,
121 uint32_t nconsops
= (sizeof cons_ops
/ sizeof cons_ops
[0]);
123 uint32_t cons_ops_index
= VC_CONS_OPS
;
126 static bool console_suspended
= false;
129 console_ring_lock_init(void)
131 simple_lock_init(&console_ring
.read_lock
, 0);
132 simple_lock_init(&console_ring
.write_lock
, 0);
141 if (!OSCompareAndSwap(0, KERN_CONSOLE_RING_SIZE
, (UInt32
*)&console_ring
.len
))
144 assert(console_ring
.len
> 0);
146 ret
= kmem_alloc(kernel_map
, (vm_offset_t
*)&console_ring
.buffer
, KERN_CONSOLE_BUF_SIZE
, VM_KERN_MEMORY_OSFMK
);
147 if (ret
!= KERN_SUCCESS
) {
148 panic("console_ring_init() failed to allocate ring buffer, error %d\n", ret
);
151 /* setup memory for per cpu console buffers */
152 for (i
= 0; i
< MAX_CPU_SLOTS
; i
++) {
153 p
= (uint32_t *)((uintptr_t)console_ring
.buffer
+ console_ring
.len
+ (i
* sizeof(console_buf_t
)));
154 *p
= CPU_BUF_FREE_HEX
;
157 console_ring
.used
= 0;
158 console_ring
.read_ptr
= console_ring
.buffer
;
159 console_ring
.write_ptr
= console_ring
.buffer
;
160 console_ring_lock_init();
161 hw_lock_init(&cnputc_lock
);
165 console_cpu_alloc(__unused boolean_t boot_processor
)
172 assert(console_ring
.buffer
!= NULL
);
174 /* select the next slot from the per cpu buffers at end of console_ring.buffer */
175 for (i
= 0; i
< MAX_CPU_SLOTS
; i
++) {
176 p
= (uint32_t *)((uintptr_t)console_ring
.buffer
+ console_ring
.len
+ (i
* sizeof(console_buf_t
)));
177 if (OSCompareAndSwap(CPU_BUF_FREE_HEX
, 0, (UInt32
*)p
))
180 assert(i
< MAX_CPU_SLOTS
);
182 cbp
= (console_buf_t
*)(uintptr_t)p
;
183 if ((uintptr_t)cbp
>= (uintptr_t)console_ring
.buffer
+ KERN_CONSOLE_BUF_SIZE
) {
184 printf("console_cpu_alloc() failed to allocate cpu buffer\n");
188 cbp
->buf_base
= (char *)&cbp
->buf
;
189 cbp
->buf_ptr
= cbp
->buf_base
;
190 cbp
->buf_end
= cbp
->buf_base
+ CPU_BUFFER_LEN
;
195 console_cpu_free(void * buf
)
197 assert((uintptr_t)buf
> (uintptr_t)console_ring
.buffer
);
198 assert((uintptr_t)buf
< (uintptr_t)console_ring
.buffer
+ KERN_CONSOLE_BUF_SIZE
);
200 *(uint32_t *)buf
= CPU_BUF_FREE_HEX
;
204 console_ring_space(void)
206 return console_ring
.len
- console_ring
.used
;
210 console_ring_put(char ch
)
212 if (console_ring
.used
< console_ring
.len
) {
214 *console_ring
.write_ptr
++ = ch
;
215 if (console_ring
.write_ptr
- console_ring
.buffer
== console_ring
.len
)
216 console_ring
.write_ptr
= console_ring
.buffer
;
223 static inline boolean_t
224 cpu_buffer_put(console_buf_t
* cbp
, char ch
)
226 if (ch
!= '\0' && cbp
->buf_ptr
< cbp
->buf_end
) {
227 *(cbp
->buf_ptr
++) = ch
;
235 cpu_buffer_size(console_buf_t
* cbp
)
237 return (int)(cbp
->buf_ptr
- cbp
->buf_base
);
241 _cnputs(char * c
, int size
)
243 /* The console device output routines are assumed to be
247 uint32_t lock_timeout_ticks
= UINT32_MAX
;
249 uint32_t lock_timeout_ticks
= LockTimeOut
;
252 mp_disable_preemption();
253 if (!hw_lock_to(&cnputc_lock
, lock_timeout_ticks
)) {
254 /* If we timed out on the lock, and we're in the debugger,
255 * copy lock data for debugging and break the lock.
257 hw_lock_data_t _shadow_lock
;
258 memcpy(&_shadow_lock
, &cnputc_lock
, sizeof(cnputc_lock
));
260 /* Since hw_lock_to takes a pre-emption count...*/
261 mp_enable_preemption();
262 hw_lock_init(&cnputc_lock
);
263 hw_lock_lock(&cnputc_lock
);
265 panic("Lock acquire timeout in _cnputs() lock=%p, lock owner thread=0x%lx, current_thread: %p\n", &_shadow_lock
,
266 _shadow_lock
.lock_data
, current_thread());
271 cons_ops
[cons_ops_index
].putc(0, 0, *c
);
273 cons_ops
[cons_ops_index
].putc(0, 0, '\r');
277 hw_lock_unlock(&cnputc_lock
);
278 mp_enable_preemption();
282 cnputc_unbuffered(char c
)
292 /* Spin (with pre-emption enabled) waiting for console_ring_try_empty()
293 * to complete output. There is a small window here where we could
294 * end up with a stale value of console_output, but it's unlikely,
295 * and _cnputs(), which outputs to the console device, is internally
296 * synchronized. There's something of a conflict between the
297 * character-at-a-time (with pre-emption enabled) unbuffered
298 * output model here, and the buffered output from cnputc(),
299 * whose consumers include printf() ( which outputs a sequence
300 * with pre-emption disabled, and should be safe to call with
301 * interrupts off); we don't want to disable pre-emption indefinitely
302 * here, and spinlocks and mutexes are inappropriate.
304 while (console_output
!= 0)
308 * We disable interrupts to avoid issues caused by rendevous IPIs
309 * and an interruptible core holding the lock while an uninterruptible
310 * core wants it. Stackshot is the prime example of this.
312 state
= ml_set_interrupts_enabled(FALSE
);
314 ml_set_interrupts_enabled(state
);
318 console_ring_try_empty(void)
321 boolean_t handle_tlb_flushes
= (ml_get_interrupts_enabled() == FALSE
);
322 #endif /* __x86_64__ */
325 int total_chars_out
= 0;
326 int size_before_wrap
= 0;
330 if (handle_tlb_flushes
)
331 handle_pending_TLB_flushes();
332 #endif /* __x86_64__ */
335 * Try to get the read lock on the ring buffer to empty it.
336 * If this fails someone else is already emptying...
338 if (!simple_lock_try(&console_ring
.read_lock
)) {
340 * If multiple cores are spinning trying to empty the buffer,
341 * we may suffer lock starvation (get the read lock, but
342 * never the write lock, with other cores unable to get the
343 * read lock). As a result, insert a delay on failure, to
344 * let other cores have a turn.
350 boolean_t state
= ml_set_interrupts_enabled(FALSE
);
352 /* Indicate that we're in the process of writing a block of data to the console. */
353 (void)hw_atomic_add(&console_output
, 1);
355 simple_lock_try_lock_loop(&console_ring
.write_lock
);
357 /* try small chunk at a time, so we allow writes from other cpus into the buffer */
358 nchars_out
= MIN(console_ring
.used
, MAX_INT_DISABLED_FLUSH_SIZE
);
360 /* account for data to be read before wrap around */
361 size_before_wrap
= (int)((console_ring
.buffer
+ console_ring
.len
) - console_ring
.read_ptr
);
362 if (nchars_out
> size_before_wrap
)
363 nchars_out
= size_before_wrap
;
365 if (nchars_out
> 0) {
366 _cnputs(console_ring
.read_ptr
, nchars_out
);
367 console_ring
.read_ptr
=
368 console_ring
.buffer
+ ((console_ring
.read_ptr
- console_ring
.buffer
+ nchars_out
) % console_ring
.len
);
369 console_ring
.used
-= nchars_out
;
370 total_chars_out
+= nchars_out
;
373 simple_unlock(&console_ring
.write_lock
);
375 (void)hw_atomic_sub(&console_output
, 1);
377 simple_unlock(&console_ring
.read_lock
);
379 ml_set_interrupts_enabled(state
);
382 * In case we end up being the console drain thread
383 * for far too long, break out. Except in panic/suspend cases
384 * where we should clear out full buffer.
386 if (debug_mode
== 0 && !console_suspended
&& (total_chars_out
>= MAX_TOTAL_FLUSH_SIZE
))
389 } while (nchars_out
> 0);
396 console_suspended
= true;
397 console_ring_try_empty();
403 console_suspended
= false;
407 console_write(char * str
, int size
)
410 int chunk_size
= size
;
413 if (size
> console_ring
.len
)
414 chunk_size
= CPU_CONS_BUF_SIZE
;
417 boolean_t state
= ml_set_interrupts_enabled(FALSE
);
419 simple_lock_try_lock_loop(&console_ring
.write_lock
);
420 while (chunk_size
> console_ring_space()) {
421 simple_unlock(&console_ring
.write_lock
);
422 ml_set_interrupts_enabled(state
);
424 console_ring_try_empty();
426 state
= ml_set_interrupts_enabled(FALSE
);
427 simple_lock_try_lock_loop(&console_ring
.write_lock
);
430 for (i
= 0; i
< chunk_size
; i
++)
431 console_ring_put(str
[i
]);
435 simple_unlock(&console_ring
.write_lock
);
436 ml_set_interrupts_enabled(state
);
439 console_ring_try_empty();
446 cpu_data_t
* cpu_data_p
;
448 boolean_t needs_print
= TRUE
;
452 mp_disable_preemption();
453 cpu_data_p
= current_cpu_datap();
454 cbp
= (console_buf_t
*)cpu_data_p
->cpu_console_buf
;
455 if (console_suspended
|| cbp
== NULL
) {
456 mp_enable_preemption();
457 /* Put directly if console ring is not initialized or we're heading into suspend */
463 /* Is there a panic backtrace going on? */
464 if (cpu_data_p
->PAB_active
) {
465 /* If another processor was in the process of emptying the
466 * console ring buffer when it received the panic backtrace
467 * signal, that processor will be spinning in DebugXCall()
468 * waiting for the panicking processor to finish printing
469 * the backtrace. But panicking processor will never
470 * be able to obtain the ring buffer lock since it is
471 * owned by a processor that's spinning in DebugXCall().
472 * Blow away any locks that other processors may have on
473 * the console ring buffer so that the backtrace can
476 console_ring_lock_init();
478 #endif /* __x86_64__ */
480 state
= ml_set_interrupts_enabled(FALSE
);
484 * If the cpu buffer is full, we'll flush, then try
485 * another put. If it fails a second time... screw
488 if (needs_print
&& !cpu_buffer_put(cbp
, c
)) {
489 simple_lock_try_lock_loop(&console_ring
.write_lock
);
491 if (cpu_buffer_size(cbp
) > console_ring_space()) {
492 simple_unlock(&console_ring
.write_lock
);
493 ml_set_interrupts_enabled(state
);
494 mp_enable_preemption();
496 console_ring_try_empty();
500 for (cp
= cbp
->buf_base
; cp
< cbp
->buf_ptr
; cp
++)
501 console_ring_put(*cp
);
502 cbp
->buf_ptr
= cbp
->buf_base
;
503 simple_unlock(&console_ring
.write_lock
);
505 cpu_buffer_put(cbp
, c
);
511 ml_set_interrupts_enabled(state
);
512 mp_enable_preemption();
516 /* We printed a newline, time to flush the CPU buffer to the global buffer */
517 simple_lock_try_lock_loop(&console_ring
.write_lock
);
520 * Is there enough space in the shared ring buffer?
521 * Try to empty if not.
522 * Note, we want the entire local buffer to fit to
523 * avoid another cpu interjecting.
526 if (cpu_buffer_size(cbp
) > console_ring_space()) {
527 simple_unlock(&console_ring
.write_lock
);
528 ml_set_interrupts_enabled(state
);
529 mp_enable_preemption();
531 console_ring_try_empty();
536 for (cp
= cbp
->buf_base
; cp
< cbp
->buf_ptr
; cp
++)
537 console_ring_put(*cp
);
539 cbp
->buf_ptr
= cbp
->buf_base
;
540 simple_unlock(&console_ring
.write_lock
);
541 ml_set_interrupts_enabled(state
);
542 mp_enable_preemption();
544 console_ring_try_empty();
550 _serial_getc(__unused
int a
, __unused
int b
, boolean_t wait
, __unused boolean_t raw
)
555 } while (wait
&& c
< 0);
562 _serial_putc(__unused
int a
, __unused
int b
, int c
)
570 return cons_ops
[cons_ops_index
].getc(0, 0, TRUE
, FALSE
);
576 return cons_ops
[cons_ops_index
].getc(0, 0, FALSE
, FALSE
);
580 vcgetc(__unused
int l
, __unused
int u
, __unused boolean_t wait
, __unused boolean_t raw
)
584 if (0 == (*PE_poll_input
)(0, &c
))
590 /* So we can re-write the serial device functions at boot-time */
592 console_set_serial_ops(struct console_ops
* newops
)
594 cons_ops
[SERIAL_CONS_OPS
] = *newops
;