]> git.saurik.com Git - apple/xnu.git/blame - osfmk/console/ppc/serial_console.c
xnu-517.3.15.tar.gz
[apple/xnu.git] / osfmk / console / ppc / serial_console.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
43866e37 6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
1c79356b 7 *
43866e37
A
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
1c79356b
A
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
43866e37
A
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
1c79356b
A
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25/*
26 * @OSF_COPYRIGHT@
27 */
28/*
29 * @APPLE_FREE_COPYRIGHT@
30 */
31
32#include <mach_kdb.h>
33#include <platforms.h>
34#include <serial_console_default.h>
35
36#include <kern/spl.h>
37#include <machine/machparam.h> /* spl definitions */
38#include <types.h>
55e303ae 39#include <console/video_console.h>
1c79356b 40#include <ppc/misc_protos.h>
55e303ae 41#include <ppc/serial_io.h>
1c79356b
A
42#include <kern/cpu_number.h>
43#include <ppc/Firmware.h>
44#include <ppc/proc_reg.h>
45#include <pexpert/pexpert.h>
46
47/*
48 * A machine MUST have a console. In our case
49 * things are a little complicated by the graphic
50 * display: people expect it to be their "console",
51 * but we'd like to be able to live without it.
52 * This is not to be confused with the "rconsole" thing:
53 * that just duplicates the console I/O to
54 * another place (for debugging/logging purposes).
55 */
56
57const int console_unit = 0;
58const int console_chan_default = CONSOLE_PORT;
59#define console_chan (console_chan_default) /* ^ cpu_number()) */
60
61#define OPS(putc, getc, nosplputc, nosplgetc) putc, getc
62
63const struct console_ops {
64 int (*putc)(int, int, int);
65 int (*getc)(int, int, boolean_t, boolean_t);
66} cons_ops[] = {
67#define SCC_CONS_OPS 0
68 {OPS(scc_putc, scc_getc, no_spl_scputc, no_spl_scgetc)},
69#define VC_CONS_OPS 1
70 {OPS(vcputc, vcgetc, no_spl_vcputc, no_spl_vcgetc)},
71};
72#define NCONSOPS (sizeof cons_ops / sizeof cons_ops[0])
73
74#if SERIAL_CONSOLE_DEFAULT
75#define CONS_OPS SCC_CONS_OPS
76#define CONS_NAME "com"
77#else
78#define CONS_OPS VC_CONS_OPS
79#define CONS_NAME "vc"
80#endif
81
82#define MP_SAFE_CONSOLE 1 /* Set this to 1 to allow more than 1 processor to print at once */
83#if MP_SAFE_CONSOLE
84
85struct ppcbfr { /* Controls multiple processor output */
86 unsigned int pos; /* Current position in buffer */
87 unsigned int noprompt; /* Set if we skip the prompt */
88 unsigned int echo; /* Control character echoing */
89 char buffer[256]; /* Fairly big buffer */
90};
91typedef struct ppcbfr ppcbfr;
92ppcbfr cbfr[NCPUS]; /* Get one of these for each processor */
93volatile unsigned int cbfpend; /* A buffer is pending output */
94volatile unsigned int sconowner=-1; /* Mark who's actually writing */
95
96#endif
97
98
99unsigned int cons_ops_index = CONS_OPS;
100unsigned int killprint = 0;
101unsigned int debcnputc = 0;
102extern unsigned int mappingdeb0;
103extern int debugger_holdoff[NCPUS];
55e303ae 104extern int debugger_cpu;
1c79356b
A
105
106static void _cnputc(char c)
107{
108 cons_ops[cons_ops_index].putc(console_unit, console_chan, c);
109}
110
111void cnputcusr(char c) { /* Echo input character directly */
112
113 unsigned int cpu;
114
9bccf70c 115 cpu = cpu_number();
1c79356b
A
116
117 hw_atomic_add(&debugger_holdoff[cpu], 1); /* Don't allow debugger entry just now (this is a HACK) */
118
119 _cnputc( c); /* Echo the character */
120 if(c=='\n') _cnputc( '\r'); /* Add a return if we had a new line */
121
122 hw_atomic_sub(&debugger_holdoff[cpu], 1); /* Don't allow debugger entry just now (this is a HACK) */
123 return;
124}
125
126void
127cnputc(char c)
128{
129
130 unsigned int oldpend, i, cpu, ourbit, sccpu;
131 spl_t s;
132
133#if MP_SAFE_CONSOLE
134
135/*
136 * Handle multiple CPU console output.
137 * Note: this thing has gotten god-awful complicated. We need a better way.
138 */
139
140
141 if(killprint) {
142 return; /* If printing is disabled, bail... */
143 }
144
9bccf70c 145 cpu = cpu_number();
1c79356b
A
146
147 hw_atomic_add(&debugger_holdoff[cpu], 1); /* Don't allow debugger entry just now (this is a HACK) */
148
149 ourbit = 1 << cpu; /* Make a mask for just us */
150 if(debugger_cpu != -1) { /* Are we in the debugger with empty buffers? */
151
152 while(sconowner != cpu) { /* Anyone but us? */
153 hw_compare_and_store(-1, cpu, (unsigned int *)&sconowner); /* Try to mark it for us if idle */
154 }
155
156 _cnputc( c); /* Yeah, just write it */
157 if(c=='\n') /* Did we just write a new line? */
158 _cnputc( '\r'); /* Yeah, just add a return */
159
160 sconowner=-1; /* Mark it idle */
161 hw_atomic_sub(&debugger_holdoff[cpu], 1); /* Don't allow debugger entry just now (this is a HACK) */
162
163 return; /* Leave... */
164 }
165
166 s=splhigh(); /* Don't bother me */
167
168 while(ourbit&cbfpend); /* We aren't "double buffered," so we'll just wait until the buffers are written */
169 isync(); /* Just in case we had to wait */
170
171 if(c) { /* If the character is not null */
172 cbfr[cpu].buffer[cbfr[cpu].pos]=c; /* Fill in the buffer for our CPU */
173 cbfr[cpu].pos++; /* Up the count */
174 if(cbfr[cpu].pos > 253) { /* Is the buffer full? */
175 cbfr[cpu].buffer[254]='\n'; /* Yeah, set the second to last as a LF */
176 cbfr[cpu].buffer[255]='\r'; /* And the last to a CR */
177 cbfr[cpu].pos=256; /* Push the buffer to the end */
178 c='\r'; /* Set character to a CR */
179 }
180 }
181
182 if(c == '\n') { /* Are we finishing a line? */
183 cbfr[cpu].buffer[cbfr[cpu].pos]='\r'; /* And the last to a CR */
184 cbfr[cpu].pos++; /* Up the count */
185 c='\r'; /* Set character to a CR */
186 }
187
188#if 1
189 if(cbfr[cpu].echo == 1) { /* Did we hit an escape last time? */
190 if(c == 'K') { /* Is it a partial clear? */
191 cbfr[cpu].echo = 2; /* Yes, enter echo mode */
192 }
193 else cbfr[cpu].echo = 0; /* Otherwise reset escape */
194 }
195 else if(cbfr[cpu].echo == 0) { /* Not in escape sequence, see if we should enter */
196 cbfr[cpu].echo = 1; /* Set that we are in escape sequence */
197 }
198#endif
199
200 if((c == 0x00) || (c == '\r') || (cbfr[cpu].echo == 2)) { /* Try to push out all buffers if we see CR or null */
201
202 while(1) { /* Loop until we see who's doing this */
203 oldpend=cbfpend; /* Get the currentest pending buffer flags */
204 if(hw_compare_and_store(oldpend, oldpend|ourbit, (unsigned int *)&cbfpend)) /* Swap ours on if no change */
205 break; /* Bail the loop if it worked */
206 }
207
208 if(!hw_compare_and_store(-1, cpu, (unsigned int *)&sconowner)) { /* See if someone else has this, and take it if not */
209 debugger_holdoff[cpu] = 0; /* Allow debugger entry (this is a HACK) */
210 splx(s); /* Let's take some 'rupts now */
211 return; /* We leave here, 'cause another processor is already writing the buffers */
212 }
213
214 while(1) { /* Loop to dump out all of the finished buffers */
215 oldpend=cbfpend; /* Get the most current finished buffers */
216 for(sccpu=0; sccpu<NCPUS; sccpu++) { /* Cycle through all CPUs buffers */
217
218 if(oldpend&(1<<sccpu)) { /* Does this guy have a buffer to do? */
219
220#if 0
221 if(!cbfr[sccpu].noprompt) { /* Don't prompt if there was not CR before */
222 _cnputc( '{'); /* Mark CPU number */
223 _cnputc( '0'+sccpu); /* Mark CPU number */
224 _cnputc( '.'); /* (TEST/DEBUG) */
225 _cnputc( '0'+cpu); /* (TEST/DEBUG) */
226 _cnputc( '}'); /* Mark CPU number */
227 _cnputc( ' '); /* Mark CPU number */
228 }
229#endif
230
231 for(i=0; i<cbfr[sccpu].pos; i++) { /* Do the whole buffer */
232 _cnputc( cbfr[sccpu].buffer[i]); /* Write it */
233 }
234
235 if(cbfr[sccpu].buffer[cbfr[sccpu].pos-1]!='\r') { /* Was the last character a return? */
236 cbfr[sccpu].noprompt = 1; /* Remember not to prompt */
237 }
238 else { /* Last was a return */
239 cbfr[sccpu].noprompt = 0; /* Otherwise remember to prompt */
240 cbfr[sccpu].echo = 0; /* And clear echo */
241 }
242
243 cbfr[sccpu].pos=0; /* Reset the buffer pointer */
244
245 while(!hw_compare_and_store(cbfpend, cbfpend&~(1<<sccpu), (unsigned int *)&cbfpend)); /* Swap it off */
246 }
247 }
248 sconowner=-1; /* Set the writer to idle */
249 sync(); /* Insure that everything's done */
250 if(hw_compare_and_store(0, 0, (unsigned int *)&cbfpend)) break; /* If there are no new buffers, we are done... */
251 if(!hw_compare_and_store(-1, cpu, (unsigned int *)&sconowner)) break; /* If this isn't idle anymore, we're done */
252
253 }
254 }
255 hw_atomic_sub(&debugger_holdoff[cpu], 1); /* Don't allow debugger entry just now (this is a HACK) */
256 splx(s); /* Let's take some 'rupts now */
257
258#else /* MP_SAFE_CONSOLE */
259 _cnputc( c);
260 if (c == '\n')
261 _cnputc('\r');
262#endif /* MP_SAFE_CONSOLE */
263
264}
265
266int
267cngetc()
268{
269 return cons_ops[cons_ops_index].getc(console_unit, console_chan,
270 TRUE, FALSE);
271}
272
273int
274cnmaygetc()
275{
276 return cons_ops[cons_ops_index].getc(console_unit, console_chan,
277 FALSE, FALSE);
278}
279
280boolean_t console_is_serial()
281{
282 return cons_ops_index == SCC_CONS_OPS;
283}
284
285int
286switch_to_video_console()
287{
288 int old_cons_ops = cons_ops_index;
289 cons_ops_index = VC_CONS_OPS;
290 return old_cons_ops;
291}
292
293int
294switch_to_serial_console()
295{
296 int old_cons_ops = cons_ops_index;
297 cons_ops_index = SCC_CONS_OPS;
298 return old_cons_ops;
299}
300
301/* The switch_to_{video,serial,kgdb}_console functions return a cookie that
302 can be used to restore the console to whatever it was before, in the
303 same way that splwhatever() and splx() work. */
304void
305switch_to_old_console(int old_console)
306{
307 static boolean_t squawked;
308 unsigned int ops = old_console;
309
310 if (ops >= NCONSOPS && !squawked) {
311 squawked = TRUE;
312 printf("switch_to_old_console: unknown ops %d\n", ops);
313 } else
314 cons_ops_index = ops;
315}
316
317
318int
319vcgetc(int l, int u, boolean_t wait, boolean_t raw)
320{
321 char c;
322
323 if( 0 == (*PE_poll_input)( 0, &c))
324 return( c);
325 else
326 return( 0);
327}