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@
30 #include <i386/cpu_data.h>
31 #include <i386/bit_routines.h>
32 #include <i386/machine_cpu.h>
33 #include <i386/machine_routines.h>
34 #include <i386/misc_protos.h>
35 #include <i386/serial_io.h>
36 #include <vm/vm_kern.h>
37 #include <console/video_console.h>
38 #include <console/serial_protos.h>
39 #include <kern/kalloc.h>
47 decl_simple_lock_data(,read_lock
);
48 decl_simple_lock_data(,write_lock
);
51 hw_lock_data_t cnputc_lock
;
52 static volatile long console_output
= 0;
54 typedef struct console_buf
{
58 #define CPU_BUFFER_LEN (256 - 3*(sizeof(char*)))
59 char buf
[CPU_BUFFER_LEN
];
62 static void _serial_putc(int, int, int);
64 struct console_ops cons_ops
[] = {
75 uint32_t nconsops
= (sizeof cons_ops
/ sizeof cons_ops
[0]);
77 uint32_t cons_ops_index
= VC_CONS_OPS
;
79 /* This macro polls for pending TLB flushes while spinning on a lock
81 #define SIMPLE_LOCK_NO_INTRS(l) \
83 boolean_t istate = ml_get_interrupts_enabled(); \
84 while (!simple_lock_try((l))) \
87 handle_pending_TLB_flushes(); \
97 console_ring
.len
= PAGE_SIZE
;
98 ret
= kmem_alloc(kernel_map
, (vm_offset_t
*) &console_ring
.buffer
,
99 console_ring
.len
, VM_KERN_MEMORY_OSFMK
);
100 if (ret
!= KERN_SUCCESS
)
101 panic("console_ring_init() "
102 "failed to allocate ring buffer, error %d\n", ret
);
103 console_ring
.used
= 0;
104 console_ring
.read_ptr
= console_ring
.buffer
;
105 console_ring
.write_ptr
= console_ring
.buffer
;
106 simple_lock_init(&console_ring
.read_lock
, 0);
107 simple_lock_init(&console_ring
.write_lock
, 0);
108 hw_lock_init(&cnputc_lock
);
112 console_cpu_alloc(__unused boolean_t boot_processor
)
117 ret
= kmem_alloc(kernel_map
, (vm_offset_t
*) &cbp
,
118 sizeof(console_buf_t
), VM_KERN_MEMORY_OSFMK
);
119 if (ret
!= KERN_SUCCESS
) {
120 printf("console_cpu_alloc() "
121 "failed to allocate cpu buffer, error=%d\n", ret
);
125 cbp
->buf_base
= (char *) &cbp
->buf
;
126 cbp
->buf_ptr
= cbp
->buf_base
;
127 cbp
->buf_end
= cbp
->buf_base
+ CPU_BUFFER_LEN
;
133 console_cpu_free(void *buf
)
136 kfree((void *) buf
, sizeof(console_buf_t
));
139 /* So we can re-write the serial device functions at boot-time */
141 console_set_serial_ops( struct console_ops
*newops
)
143 cons_ops
[SERIAL_CONS_OPS
] = *newops
;
147 console_ring_space(void)
149 return console_ring
.len
- console_ring
.used
;
153 console_ring_put(char ch
)
155 if (console_ring
.used
< console_ring
.len
) {
156 console_ring
.used
++;;
157 *console_ring
.write_ptr
++ = ch
;
158 if (console_ring
.write_ptr
- console_ring
.buffer
160 console_ring
.write_ptr
= console_ring
.buffer
;
168 console_ring_get(void)
172 if (console_ring
.used
> 0) {
174 ch
= *console_ring
.read_ptr
++;
175 if (console_ring
.read_ptr
- console_ring
.buffer
177 console_ring
.read_ptr
= console_ring
.buffer
;
183 cpu_buffer_put(console_buf_t
*cbp
, char ch
)
185 if (ch
!= '\0' && cbp
->buf_ptr
< cbp
->buf_end
)
186 *(cbp
->buf_ptr
++) = ch
;
192 /* The console device output routines are assumed to be
195 mp_disable_preemption();
196 /* Use the maximum available spinlock timeout. Some configurations
197 * exhibit non-deterministic stalls across console output.
199 if (!hw_lock_to(&cnputc_lock
, UINT32_MAX
)) {
200 /* If we timed out on the lock, and we're in the debugger,
204 /* Since hw_lock_to takes a pre-emption count...*/
205 mp_enable_preemption();
206 hw_lock_init(&cnputc_lock
);
207 hw_lock_lock(&cnputc_lock
);
210 panic("Lock acquire timeout in _cnputc()");
212 cons_ops
[cons_ops_index
].putc(0, 0, c
);
214 cons_ops
[cons_ops_index
].putc(0, 0, '\r');
215 hw_lock_unlock(&cnputc_lock
);
216 mp_enable_preemption();
219 void cnputc_unbuffered(char c
) {
226 /* Spin (with pre-emption enabled) waiting for console_ring_try_empty()
227 * to complete output. There is a small window here where we could
228 * end up with a stale value of console_output, but it's unlikely,
229 * and _cnputc(), which outputs to the console device, is internally
230 * synchronized. There's something of a conflict between the
231 * character-at-a-time (with pre-emption enabled) unbuffered
232 * output model here, and the buffered output from cnputc(),
233 * whose consumers include printf() ( which outputs a sequence
234 * with pre-emption disabled, and should be safe to call with
235 * interrupts off); we don't want to disable pre-emption indefinitely
236 * here, and spinlocks and mutexes are inappropriate.
238 while (console_output
!= 0);
244 console_ring_try_empty(void)
246 boolean_t state
= ml_get_interrupts_enabled();
248 * Try to get the read lock on the ring buffer to empty it.
249 * If this fails someone else is already emptying...
251 if (!simple_lock_try(&console_ring
.read_lock
))
253 /* Indicate that we're in the process of writing a block of data
256 atomic_incl(&console_output
, 1);
260 handle_pending_TLB_flushes();
261 ml_set_interrupts_enabled(FALSE
);
262 SIMPLE_LOCK_NO_INTRS(&console_ring
.write_lock
);
263 ch
= console_ring_get();
264 simple_unlock(&console_ring
.write_lock
);
265 ml_set_interrupts_enabled(state
);
270 atomic_decl(&console_output
, 1);
271 simple_unlock(&console_ring
.read_lock
);
278 mp_disable_preemption();
279 cbp
= (console_buf_t
*) current_cpu_datap()->cpu_console_buf
;
281 mp_enable_preemption();
282 /* Put directly if console ring is not initialized */
287 /* add to stack buf */
289 /* XXX - cpu_buffer_put() can fail silently if the buffer
290 * is exhausted, as can happen if there's a long sequence
291 * of data with no newlines. We should, instead, attempt
294 cpu_buffer_put(cbp
, c
);
299 /* Here at end of printf -- time to try to output */
301 /* copy this buffer into the shared ring buffer */
302 state
= ml_set_interrupts_enabled(FALSE
);
303 SIMPLE_LOCK_NO_INTRS(&console_ring
.write_lock
);
306 * Is there enough space in the shared ring buffer?
307 * Try to empty if not.
308 * Note, we want the entire local buffer to fit to
309 * avoid another cpu interjecting.
311 while (cbp
->buf_ptr
-cbp
->buf_base
+ 1 > console_ring_space()) {
312 simple_unlock(&console_ring
.write_lock
);
313 ml_set_interrupts_enabled(state
);
314 console_ring_try_empty();
315 state
= ml_set_interrupts_enabled(FALSE
);
316 SIMPLE_LOCK_NO_INTRS(&console_ring
.write_lock
);
318 for (cp
= cbp
->buf_base
; cp
< cbp
->buf_ptr
; cp
++)
319 console_ring_put(*cp
);
320 console_ring_put('\n');
321 cbp
->buf_ptr
= cbp
->buf_base
;
322 simple_unlock(&console_ring
.write_lock
);
323 ml_set_interrupts_enabled(state
);
325 console_ring_try_empty();
326 mp_enable_preemption();
329 int _serial_getc(__unused
int a
, __unused
int b
, boolean_t wait
, __unused boolean_t raw
)
334 } while (wait
&& c
< 0);
339 static void _serial_putc(__unused
int a
, __unused
int b
, int c
)
348 return cons_ops
[cons_ops_index
].getc(0, 0,
355 return cons_ops
[cons_ops_index
].getc(0, 0,
360 vcgetc(__unused
int l
,
362 __unused boolean_t wait
,
363 __unused boolean_t raw
)
367 if( 0 == (*PE_poll_input
)( 0, &c
))