]> git.saurik.com Git - apple/xnu.git/blame - osfmk/console/i386/serial_console.c
xnu-792.17.14.tar.gz
[apple/xnu.git] / osfmk / console / i386 / serial_console.c
CommitLineData
1c79356b 1/*
55e303ae 2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
1c79356b 3 *
8f6c56a5 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
8f6c56a5
A
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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
8ad349bb 24 * limitations under the License.
8f6c56a5
A
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b 27 */
1c79356b 28
55e303ae 29#include <i386/mp.h>
91447636
A
30#include <i386/cpu_data.h>
31#include <i386/machine_cpu.h>
55e303ae 32#include <i386/machine_routines.h>
91447636
A
33#include <i386/misc_protos.h>
34#include <vm/vm_kern.h>
35#include <console/video_console.h>
36#include <kern/kalloc.h>
37
38static struct {
39 char *buffer;
40 int len;
41 int used;
42 char *write_ptr;
43 char *read_ptr;
44 decl_simple_lock_data(,read_lock);
45 decl_simple_lock_data(,write_lock);
46} console_ring;
47
48typedef struct console_buf {
49 char *buf_base;
50 char *buf_end;
51 char *buf_ptr;
52#define CPU_BUFFER_LEN (256 - 3*(sizeof(char*)))
53 char buf[CPU_BUFFER_LEN];
54} console_buf_t;
1c79356b 55
55e303ae 56void
91447636
A
57console_init(void)
58{
59 int ret;
60
61 console_ring.len = PAGE_SIZE;
62 ret = kmem_alloc(kernel_map, (vm_offset_t *) &console_ring.buffer,
63 console_ring.len);
64 if (ret != KERN_SUCCESS)
65 panic("console_ring_init() "
66 "failed to allocate ring buffer, error %d\n", ret);
67 console_ring.used = 0;
68 console_ring.read_ptr = console_ring.buffer;
69 console_ring.write_ptr = console_ring.buffer;
70 simple_lock_init(&console_ring.read_lock, 0);
71 simple_lock_init(&console_ring.write_lock, 0);
8f6c56a5 72
91447636
A
73}
74
75void *
76console_cpu_alloc(__unused boolean_t boot_processor)
77{
78 int ret;
79 console_buf_t *cbp;
80
81 ret = kmem_alloc(kernel_map, (vm_offset_t *) &cbp,
82 sizeof(console_buf_t));
83 if (ret != KERN_SUCCESS) {
84 printf("console_cpu_alloc() "
85 "failed to allocate cpu buffer, error=%d\n", ret);
86 return NULL;
87 }
88
89 cbp->buf_base = (char *) &cbp->buf;
90 cbp->buf_ptr = cbp->buf_base;
91 cbp->buf_end = cbp->buf_base + CPU_BUFFER_LEN;
92
93 return (void *) cbp;
94}
95
96void
97console_cpu_free(void *buf)
98{
99 if (buf != NULL)
100 kfree((void *) buf, sizeof(console_buf_t));
101}
102
103static boolean_t
104console_ring_put(char ch)
105{
106 if (console_ring.used < console_ring.len) {
107 console_ring.used++;;
108 *console_ring.write_ptr++ = ch;
109 if (console_ring.write_ptr - console_ring.buffer
110 == console_ring.len)
111 console_ring.write_ptr = console_ring.buffer;
112 return TRUE;
113 } else {
114 return FALSE;
115 }
116}
117
118static int
119console_ring_get(void)
120{
121 char ch = 0;
122
123 if (console_ring.used > 0) {
124 console_ring.used--;
125 ch = *console_ring.read_ptr++;
126 if (console_ring.read_ptr - console_ring.buffer
127 == console_ring.len)
128 console_ring.read_ptr = console_ring.buffer;
129 }
130 return (int) ch;
131}
132
133static inline void
134cpu_buffer_put(console_buf_t *cbp, char ch)
135{
8f6c56a5 136 if (cbp->buf_ptr < cbp->buf_end)
91447636
A
137 *(cbp->buf_ptr++) = ch;
138}
139
140static inline void
141_cnputc(char c)
1c79356b 142{
8f6c56a5 143 vcputc(0, 0, c);
55e303ae 144 if (c == '\n')
8f6c56a5 145 vcputc(0, 0,'\r');
91447636
A
146}
147
148void
149cnputcusr(char c)
8f6c56a5
A
150{
151 simple_lock(&console_ring.read_lock);
91447636
A
152 _cnputc(c);
153 simple_unlock(&console_ring.read_lock);
154}
155
156void
157cnputc(char c)
158{
159 console_buf_t *cbp;
8f6c56a5
A
160
161 if (!(real_ncpus > 1)) {
5d5c5d0d
A
162 _cnputc(c);
163 return;
164 }
165
8f6c56a5 166 mp_disable_preemption();
5d5c5d0d 167 /* add to stack buf */
8f6c56a5 168 cbp = (console_buf_t *) current_cpu_datap()->cpu_console_buf;
91447636
A
169 if (c != '\n') {
170 cpu_buffer_put(cbp, c);
171 } else {
172 boolean_t state;
173 char *cp;
174
175 /* Here at end of printf -- time to try to output */
176
177 /* copy this buffer into the shared ring buffer */
178 state = ml_set_interrupts_enabled(FALSE);
8f6c56a5
A
179 simple_lock(&console_ring.write_lock);
180 for (cp = cbp->buf_base; cp < cbp->buf_ptr; cp++) {
181 while (!console_ring_put(*cp))
182 /* spin if share buffer full */
183 cpu_pause();
184 }
185 (void) console_ring_put('\n');
186 simple_unlock(&console_ring.write_lock);
187 ml_set_interrupts_enabled(state);
188 cbp->buf_ptr = cbp->buf_base;
91447636
A
189
190 /*
8f6c56a5
A
191 * Try to get the read lock on the ring buffer to empty it.
192 * If this fails someone else is already emptying...
91447636 193 */
8f6c56a5
A
194 if (simple_lock_try(&console_ring.read_lock)) {
195 for (;;) {
196 char ch;
197
198 simple_lock(&console_ring.write_lock);
199 ch = console_ring_get();
200 simple_unlock(&console_ring.write_lock);
201 if (ch == 0)
202 break;
203 _cnputc(ch);
204 }
205 simple_unlock(&console_ring.read_lock);
91447636
A
206 }
207 }
208 mp_enable_preemption();
55e303ae 209}