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