]>
git.saurik.com Git - apple/xnu.git/blob - osfmk/console/ppc/serial_console.c
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
27 * @APPLE_FREE_COPYRIGHT@
31 #include <platforms.h>
32 #include <serial_console_default.h>
35 #include <machine/machparam.h> /* spl definitions */
37 #include <console/video_console.h>
38 #include <kern/kalloc.h>
39 #include <kern/thread.h>
40 #include <ppc/misc_protos.h>
41 #include <ppc/serial_io.h>
42 #include <kern/cpu_number.h>
43 #include <ppc/Firmware.h>
44 #include <ppc/proc_reg.h>
45 #include <ppc/cpu_internal.h>
46 #include <ppc/exception.h>
47 #include <pexpert/pexpert.h>
50 * A machine MUST have a console. In our case
51 * things are a little complicated by the graphic
52 * display: people expect it to be their "console",
53 * but we'd like to be able to live without it.
54 * This is not to be confused with the "rconsole" thing:
55 * that just duplicates the console I/O to
56 * another place (for debugging/logging purposes).
59 const int console_unit
= 0;
60 const int console_chan_default
= CONSOLE_PORT
;
61 #define console_chan (console_chan_default) /* ^ cpu_number()) */
63 #define OPS(putc, getc, nosplputc, nosplgetc) putc, getc
65 const struct console_ops
{
66 int (*putc
)(int, int, int);
67 int (*getc
)(int, int, boolean_t
, boolean_t
);
69 #define SCC_CONS_OPS 0
70 {OPS(scc_putc
, scc_getc
, no_spl_scputc
, no_spl_scgetc
)},
72 {OPS(vcputc
, vcgetc
, no_spl_vcputc
, no_spl_vcgetc
)},
74 #define NCONSOPS (sizeof cons_ops / sizeof cons_ops[0])
76 #if SERIAL_CONSOLE_DEFAULT
77 #define CONS_OPS SCC_CONS_OPS
78 #define CONS_NAME "com"
80 #define CONS_OPS VC_CONS_OPS
81 #define CONS_NAME "vc"
84 #define MP_SAFE_CONSOLE 1 /* Set this to 1 to allow more than 1 processor to print at once */
87 struct ppcbfr
{ /* Controls multiple processor output */
88 unsigned int pos
; /* Current position in buffer */
89 unsigned int noprompt
; /* Set if we skip the prompt */
90 unsigned int echo
; /* Control character echoing */
91 char buffer
[256]; /* Fairly big buffer */
93 typedef struct ppcbfr ppcbfr_t
;
95 ppcbfr_t cbfr_boot_cpu
; /* Get one for boot cpu */
96 volatile unsigned int cbfpend
; /* A buffer is pending output */
97 volatile unsigned int sconowner
=-1; /* Mark who's actually writing */
102 unsigned int cons_ops_index
= CONS_OPS
;
103 unsigned int killprint
= 0;
104 unsigned int debcnputc
= 0;
105 extern unsigned int mappingdeb0
;
106 extern int debugger_cpu
;
108 void *console_per_proc_alloc(boolean_t boot_processor
)
113 cbfr_cpu
= &cbfr_boot_cpu
;
115 cbfr_cpu
= (ppcbfr_t
*)kalloc(sizeof(ppcbfr_t
));
116 if (cbfr_cpu
== (ppcbfr_t
*)NULL
)
119 bzero((char *)cbfr_cpu
, sizeof(ppcbfr_t
));
120 return (void *)cbfr_cpu
;
123 void console_per_proc_free(void *per_proc_cbfr
)
125 if (per_proc_cbfr
== (void *)&cbfr_boot_cpu
)
128 kfree(per_proc_cbfr
, sizeof(ppcbfr_t
));
132 static void _cnputc(char c
)
134 cons_ops
[cons_ops_index
].putc(console_unit
, console_chan
, c
);
137 void cnputcusr(char c
) { /* Echo input character directly */
138 struct per_proc_info
*procinfo
;
142 procinfo
= getPerProc();
144 hw_atomic_add(&(procinfo
->debugger_holdoff
), 1); /* Don't allow debugger entry just now (this is a HACK) */
146 _cnputc( c
); /* Echo the character */
147 if(c
=='\n') _cnputc( '\r'); /* Add a return if we had a new line */
149 hw_atomic_sub(&(procinfo
->debugger_holdoff
), 1); /* Don't allow debugger entry just now (this is a HACK) */
157 unsigned int oldpend
, i
, cpu
, ourbit
, sccpu
;
158 struct per_proc_info
*procinfo
;
159 ppcbfr_t
*cbfr
, *cbfr_cpu
;
165 * Handle multiple CPU console output.
166 * Note: this thing has gotten god-awful complicated. We need a better way.
171 return; /* If printing is disabled, bail... */
174 s
=splhigh(); /* Don't bother me */
175 procinfo
= getPerProc();
176 cpu
= procinfo
->cpu_number
;
177 cbfr
= procinfo
->pp_cbfr
;
179 hw_atomic_add(&(procinfo
->debugger_holdoff
), 1); /* Don't allow debugger entry just now (this is a HACK) */
181 ourbit
= 1 << cpu
; /* Make a mask for just us */
182 if(debugger_cpu
!= -1) { /* Are we in the debugger with empty buffers? */
184 while(sconowner
!= cpu
) { /* Anyone but us? */
185 hw_compare_and_store(-1, cpu
, (unsigned int *)&sconowner
); /* Try to mark it for us if idle */
188 _cnputc( c
); /* Yeah, just write it */
189 if(c
=='\n') /* Did we just write a new line? */
190 _cnputc( '\r'); /* Yeah, just add a return */
192 sconowner
=-1; /* Mark it idle */
193 hw_atomic_sub(&(procinfo
->debugger_holdoff
), 1); /* Don't allow debugger entry just now (this is a HACK) */
196 return; /* Leave... */
200 while(ourbit
&cbfpend
); /* We aren't "double buffered," so we'll just wait until the buffers are written */
201 isync(); /* Just in case we had to wait */
203 if(c
) { /* If the character is not null */
204 cbfr
->buffer
[cbfr
->pos
]=c
; /* Fill in the buffer for our CPU */
205 cbfr
->pos
++; /* Up the count */
206 if(cbfr
->pos
> 253) { /* Is the buffer full? */
207 cbfr
->buffer
[254]='\n'; /* Yeah, set the second to last as a LF */
208 cbfr
->buffer
[255]='\r'; /* And the last to a CR */
209 cbfr
->pos
=256; /* Push the buffer to the end */
210 c
='\r'; /* Set character to a CR */
214 if(c
== '\n') { /* Are we finishing a line? */
215 cbfr
->buffer
[cbfr
->pos
]='\r'; /* And the last to a CR */
216 cbfr
->pos
++; /* Up the count */
217 c
='\r'; /* Set character to a CR */
221 if(cbfr
->echo
== 1) { /* Did we hit an escape last time? */
222 if(c
== 'K') { /* Is it a partial clear? */
223 cbfr
->echo
= 2; /* Yes, enter echo mode */
225 else cbfr
->echo
= 0; /* Otherwise reset escape */
227 else if(cbfr
->echo
== 0) { /* Not in escape sequence, see if we should enter */
228 cbfr
->echo
= 1; /* Set that we are in escape sequence */
232 if((c
== 0x00) || (c
== '\r') || (cbfr
->echo
== 2)) { /* Try to push out all buffers if we see CR or null */
234 while(1) { /* Loop until we see who's doing this */
235 oldpend
=cbfpend
; /* Get the currentest pending buffer flags */
236 if(hw_compare_and_store(oldpend
, oldpend
|ourbit
, (unsigned int *)&cbfpend
)) /* Swap ours on if no change */
237 break; /* Bail the loop if it worked */
240 if(!hw_compare_and_store(-1, cpu
, (unsigned int *)&sconowner
)) { /* See if someone else has this, and take it if not */
241 procinfo
->debugger_holdoff
= 0; /* Allow debugger entry (this is a HACK) */
242 splx(s
); /* Let's take some 'rupts now */
243 return; /* We leave here, 'cause another processor is already writing the buffers */
246 while(1) { /* Loop to dump out all of the finished buffers */
247 oldpend
=cbfpend
; /* Get the most current finished buffers */
248 for(sccpu
=0; sccpu
<real_ncpus
; sccpu
++) { /* Cycle through all CPUs buffers */
249 if ((PerProcTable
[sccpu
].ppe_vaddr
== 0)
250 || (PerProcTable
[sccpu
].ppe_vaddr
->pp_cbfr
== 0))
253 cbfr_cpu
= PerProcTable
[sccpu
].ppe_vaddr
->pp_cbfr
;
255 if(oldpend
&(1<<sccpu
)) { /* Does this guy have a buffer to do? */
258 if(!cbfr_cpu
->noprompt
) { /* Don't prompt if there was not CR before */
259 _cnputc( '{'); /* Mark CPU number */
260 _cnputc( '0'+sccpu
); /* Mark CPU number */
261 _cnputc( '.'); /* (TEST/DEBUG) */
262 _cnputc( '0'+cpu
); /* (TEST/DEBUG) */
263 _cnputc( '}'); /* Mark CPU number */
264 _cnputc( ' '); /* Mark CPU number */
268 for(i
=0; i
<cbfr_cpu
->pos
; i
++) { /* Do the whole buffer */
269 _cnputc(cbfr_cpu
->buffer
[i
]); /* Write it */
272 if(cbfr_cpu
->buffer
[cbfr_cpu
->pos
-1]!='\r') { /* Was the last character a return? */
273 cbfr_cpu
->noprompt
= 1; /* Remember not to prompt */
275 else { /* Last was a return */
276 cbfr_cpu
->noprompt
= 0; /* Otherwise remember to prompt */
277 cbfr_cpu
->echo
= 0; /* And clear echo */
280 cbfr_cpu
->pos
=0; /* Reset the buffer pointer */
282 while(!hw_compare_and_store(cbfpend
, cbfpend
&~(1<<sccpu
), (unsigned int *)&cbfpend
)); /* Swap it off */
285 sconowner
=-1; /* Set the writer to idle */
286 sync(); /* Insure that everything's done */
287 if(hw_compare_and_store(0, 0, (unsigned int *)&cbfpend
)) break; /* If there are no new buffers, we are done... */
288 if(!hw_compare_and_store(-1, cpu
, (unsigned int *)&sconowner
)) break; /* If this isn't idle anymore, we're done */
292 hw_atomic_sub(&(procinfo
->debugger_holdoff
), 1); /* Don't allow debugger entry just now (this is a HACK) */
293 splx(s
); /* Let's take some 'rupts now */
295 #else /* MP_SAFE_CONSOLE */
299 #endif /* MP_SAFE_CONSOLE */
306 return cons_ops
[cons_ops_index
].getc(console_unit
, console_chan
,
313 return cons_ops
[cons_ops_index
].getc(console_unit
, console_chan
,
317 boolean_t
console_is_serial()
319 return cons_ops_index
== SCC_CONS_OPS
;
323 switch_to_video_console()
325 int old_cons_ops
= cons_ops_index
;
326 cons_ops_index
= VC_CONS_OPS
;
331 switch_to_serial_console()
333 int old_cons_ops
= cons_ops_index
;
334 cons_ops_index
= SCC_CONS_OPS
;
338 /* The switch_to_{video,serial,kgdb}_console functions return a cookie that
339 can be used to restore the console to whatever it was before, in the
340 same way that splwhatever() and splx() work. */
342 switch_to_old_console(int old_console
)
344 static boolean_t squawked
;
345 unsigned int ops
= old_console
;
347 if (ops
>= NCONSOPS
&& !squawked
) {
349 printf("switch_to_old_console: unknown ops %d\n", ops
);
351 cons_ops_index
= ops
;
356 vcgetc(__unused
int l
,
358 __unused boolean_t wait
,
359 __unused boolean_t raw
)
363 if( 0 == (*PE_poll_input
)( 0, &c
))