]> git.saurik.com Git - apple/xnu.git/blame - osfmk/console/i386/serial_console.c
xnu-792.12.6.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 *
8ad349bb 4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
1c79356b 5 *
8ad349bb
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
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@
1c79356b 29 */
1c79356b 30
55e303ae 31#include <i386/mp.h>
91447636
A
32#include <i386/cpu_data.h>
33#include <i386/machine_cpu.h>
55e303ae 34#include <i386/machine_routines.h>
91447636
A
35#include <i386/misc_protos.h>
36#include <vm/vm_kern.h>
37#include <console/video_console.h>
38#include <kern/kalloc.h>
39
40static 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
50typedef 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;
1c79356b 57
55e303ae 58void
91447636
A
59console_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);
8ad349bb 74
91447636
A
75}
76
77void *
78console_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
98void
99console_cpu_free(void *buf)
100{
101 if (buf != NULL)
102 kfree((void *) buf, sizeof(console_buf_t));
103}
104
105static boolean_t
106console_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
120static int
121console_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
135static inline void
136cpu_buffer_put(console_buf_t *cbp, char ch)
137{
8ad349bb 138 if (cbp->buf_ptr < cbp->buf_end)
91447636
A
139 *(cbp->buf_ptr++) = ch;
140}
141
142static inline void
143_cnputc(char c)
1c79356b 144{
8ad349bb 145 vcputc(0, 0, c);
55e303ae 146 if (c == '\n')
8ad349bb 147 vcputc(0, 0,'\r');
91447636
A
148}
149
150void
151cnputcusr(char c)
8ad349bb
A
152{
153 simple_lock(&console_ring.read_lock);
91447636
A
154 _cnputc(c);
155 simple_unlock(&console_ring.read_lock);
156}
157
158void
159cnputc(char c)
160{
161 console_buf_t *cbp;
8ad349bb
A
162
163 if (!(real_ncpus > 1)) {
c0fea474
A
164 _cnputc(c);
165 return;
166 }
167
8ad349bb 168 mp_disable_preemption();
c0fea474 169 /* add to stack buf */
8ad349bb 170 cbp = (console_buf_t *) current_cpu_datap()->cpu_console_buf;
91447636
A
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);
8ad349bb
A
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;
91447636
A
191
192 /*
8ad349bb
A
193 * Try to get the read lock on the ring buffer to empty it.
194 * If this fails someone else is already emptying...
91447636 195 */
8ad349bb
A
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);
91447636
A
208 }
209 }
210 mp_enable_preemption();
55e303ae 211}