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