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