]>
git.saurik.com Git - apple/xnu.git/blob - osfmk/console/ppc/serial_console.c
6ea518c61cd7cf08848ea18be53b064a646d8a3c
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_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. 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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
32 * @APPLE_FREE_COPYRIGHT@
36 #include <platforms.h>
37 #include <serial_console_default.h>
40 #include <machine/machparam.h> /* spl definitions */
42 #include <console/video_console.h>
43 #include <console/serial_protos.h>
44 #include <kern/kalloc.h>
45 #include <kern/thread.h>
46 #include <ppc/misc_protos.h>
47 #include <ppc/serial_io.h>
48 #include <kern/cpu_number.h>
49 #include <ppc/Firmware.h>
50 #include <ppc/proc_reg.h>
51 #include <ppc/cpu_internal.h>
52 #include <ppc/exception.h>
53 #include <pexpert/pexpert.h>
56 * A machine MUST have a console. In our case
57 * things are a little complicated by the graphic
58 * display: people expect it to be their "console",
59 * but we'd like to be able to live without it.
60 * This is not to be confused with the "rconsole" thing:
61 * that just duplicates the console I/O to
62 * another place (for debugging/logging purposes).
65 const int console_unit
= 0;
66 const uint32_t console_chan_default
= CONSOLE_PORT
;
67 #define console_chan (console_chan_default) /* ^ cpu_number()) */
70 #define MP_SAFE_CONSOLE 1 /* Set this to 1 to allow more than 1 processor to print at once */
73 struct ppcbfr
{ /* Controls multiple processor output */
74 unsigned int pos
; /* Current position in buffer */
75 unsigned int noprompt
; /* Set if we skip the prompt */
76 unsigned int echo
; /* Control character echoing */
77 char buffer
[256]; /* Fairly big buffer */
79 typedef struct ppcbfr ppcbfr_t
;
81 ppcbfr_t cbfr_boot_cpu
; /* Get one for boot cpu */
82 volatile unsigned int cbfpend
; /* A buffer is pending output */
83 volatile unsigned int sconowner
=-1; /* Mark who's actually writing */
87 #define OPS(putc, getc, nosplputc, nosplgetc) putc, getc
89 console_ops_t cons_ops
[] = {
90 {OPS(scc_putc
, scc_getc
, no_spl_scputc
, no_spl_scgetc
)},
91 {OPS(vcputc
, vcgetc
, no_spl_vcputc
, no_spl_vcgetc
)},
94 uint32_t nconsops
= (sizeof cons_ops
/ sizeof cons_ops
[0]);
96 uint32_t cons_ops_index
= VC_CONS_OPS
;
98 unsigned int killprint
= 0;
99 unsigned int debcnputc
= 0;
100 extern unsigned int mappingdeb0
;
101 extern int debugger_cpu
;
103 void *console_per_proc_alloc(boolean_t boot_processor
)
108 cbfr_cpu
= &cbfr_boot_cpu
;
110 cbfr_cpu
= (ppcbfr_t
*)kalloc(sizeof(ppcbfr_t
));
111 if (cbfr_cpu
== (ppcbfr_t
*)NULL
)
114 bzero((char *)cbfr_cpu
, sizeof(ppcbfr_t
));
115 return (void *)cbfr_cpu
;
118 void console_per_proc_free(void *per_proc_cbfr
)
120 if (per_proc_cbfr
== (void *)&cbfr_boot_cpu
)
123 kfree(per_proc_cbfr
, sizeof(ppcbfr_t
));
127 static void _cnputc(char c
)
129 cons_ops
[cons_ops_index
].putc(console_unit
, console_chan
, c
);
132 void cnputcusr(char c
) { /* Echo input character directly */
133 struct per_proc_info
*procinfo
;
137 procinfo
= getPerProc();
139 hw_atomic_add(&(procinfo
->debugger_holdoff
), 1); /* Don't allow debugger entry just now (this is a HACK) */
141 _cnputc( c
); /* Echo the character */
142 if(c
=='\n') _cnputc( '\r'); /* Add a return if we had a new line */
144 hw_atomic_sub(&(procinfo
->debugger_holdoff
), 1); /* Don't allow debugger entry just now (this is a HACK) */
152 unsigned int oldpend
, i
, cpu
, ourbit
, sccpu
;
153 struct per_proc_info
*procinfo
;
154 ppcbfr_t
*cbfr
, *cbfr_cpu
;
160 * Handle multiple CPU console output.
161 * Note: this thing has gotten god-awful complicated. We need a better way.
166 return; /* If printing is disabled, bail... */
169 s
=splhigh(); /* Don't bother me */
170 procinfo
= getPerProc();
171 cpu
= procinfo
->cpu_number
;
172 cbfr
= procinfo
->pp_cbfr
;
174 hw_atomic_add(&(procinfo
->debugger_holdoff
), 1); /* Don't allow debugger entry just now (this is a HACK) */
176 ourbit
= 1 << cpu
; /* Make a mask for just us */
177 if(debugger_cpu
!= -1) { /* Are we in the debugger with empty buffers? */
179 while(sconowner
!= cpu
) { /* Anyone but us? */
180 hw_compare_and_store(-1, cpu
, (unsigned int *)&sconowner
); /* Try to mark it for us if idle */
183 _cnputc( c
); /* Yeah, just write it */
184 if(c
=='\n') /* Did we just write a new line? */
185 _cnputc( '\r'); /* Yeah, just add a return */
187 sconowner
=-1; /* Mark it idle */
188 hw_atomic_sub(&(procinfo
->debugger_holdoff
), 1); /* Don't allow debugger entry just now (this is a HACK) */
191 return; /* Leave... */
195 while(ourbit
&cbfpend
); /* We aren't "double buffered," so we'll just wait until the buffers are written */
196 isync(); /* Just in case we had to wait */
198 if(c
) { /* If the character is not null */
199 cbfr
->buffer
[cbfr
->pos
]=c
; /* Fill in the buffer for our CPU */
200 cbfr
->pos
++; /* Up the count */
201 if(cbfr
->pos
> 253) { /* Is the buffer full? */
202 cbfr
->buffer
[254]='\n'; /* Yeah, set the second to last as a LF */
203 cbfr
->buffer
[255]='\r'; /* And the last to a CR */
204 cbfr
->pos
=256; /* Push the buffer to the end */
205 c
='\r'; /* Set character to a CR */
209 if(c
== '\n') { /* Are we finishing a line? */
210 cbfr
->buffer
[cbfr
->pos
]='\r'; /* And the last to a CR */
211 cbfr
->pos
++; /* Up the count */
212 c
='\r'; /* Set character to a CR */
216 if(cbfr
->echo
== 1) { /* Did we hit an escape last time? */
217 if(c
== 'K') { /* Is it a partial clear? */
218 cbfr
->echo
= 2; /* Yes, enter echo mode */
220 else cbfr
->echo
= 0; /* Otherwise reset escape */
222 else if(cbfr
->echo
== 0) { /* Not in escape sequence, see if we should enter */
223 cbfr
->echo
= 1; /* Set that we are in escape sequence */
227 if((c
== 0x00) || (c
== '\r') || (cbfr
->echo
== 2)) { /* Try to push out all buffers if we see CR or null */
229 while(1) { /* Loop until we see who's doing this */
230 oldpend
=cbfpend
; /* Get the currentest pending buffer flags */
231 if(hw_compare_and_store(oldpend
, oldpend
|ourbit
, (unsigned int *)&cbfpend
)) /* Swap ours on if no change */
232 break; /* Bail the loop if it worked */
235 if(!hw_compare_and_store(-1, cpu
, (unsigned int *)&sconowner
)) { /* See if someone else has this, and take it if not */
236 procinfo
->debugger_holdoff
= 0; /* Allow debugger entry (this is a HACK) */
237 splx(s
); /* Let's take some 'rupts now */
238 return; /* We leave here, 'cause another processor is already writing the buffers */
241 while(1) { /* Loop to dump out all of the finished buffers */
242 oldpend
=cbfpend
; /* Get the most current finished buffers */
243 for(sccpu
=0; sccpu
<real_ncpus
; sccpu
++) { /* Cycle through all CPUs buffers */
244 if ((PerProcTable
[sccpu
].ppe_vaddr
== 0)
245 || (PerProcTable
[sccpu
].ppe_vaddr
->pp_cbfr
== 0))
248 cbfr_cpu
= PerProcTable
[sccpu
].ppe_vaddr
->pp_cbfr
;
250 if(oldpend
&(1<<sccpu
)) { /* Does this guy have a buffer to do? */
253 if(!cbfr_cpu
->noprompt
) { /* Don't prompt if there was not CR before */
254 _cnputc( '{'); /* Mark CPU number */
255 _cnputc( '0'+sccpu
); /* Mark CPU number */
256 _cnputc( '.'); /* (TEST/DEBUG) */
257 _cnputc( '0'+cpu
); /* (TEST/DEBUG) */
258 _cnputc( '}'); /* Mark CPU number */
259 _cnputc( ' '); /* Mark CPU number */
263 for(i
=0; i
<cbfr_cpu
->pos
; i
++) { /* Do the whole buffer */
264 _cnputc(cbfr_cpu
->buffer
[i
]); /* Write it */
267 if(cbfr_cpu
->buffer
[cbfr_cpu
->pos
-1]!='\r') { /* Was the last character a return? */
268 cbfr_cpu
->noprompt
= 1; /* Remember not to prompt */
270 else { /* Last was a return */
271 cbfr_cpu
->noprompt
= 0; /* Otherwise remember to prompt */
272 cbfr_cpu
->echo
= 0; /* And clear echo */
275 cbfr_cpu
->pos
=0; /* Reset the buffer pointer */
277 while(!hw_compare_and_store(cbfpend
, cbfpend
&~(1<<sccpu
), (unsigned int *)&cbfpend
)); /* Swap it off */
280 sconowner
=-1; /* Set the writer to idle */
281 sync(); /* Insure that everything's done */
282 if(hw_compare_and_store(0, 0, (unsigned int *)&cbfpend
)) break; /* If there are no new buffers, we are done... */
283 if(!hw_compare_and_store(-1, cpu
, (unsigned int *)&sconowner
)) break; /* If this isn't idle anymore, we're done */
287 hw_atomic_sub(&(procinfo
->debugger_holdoff
), 1); /* Don't allow debugger entry just now (this is a HACK) */
288 splx(s
); /* Let's take some 'rupts now */
290 #else /* MP_SAFE_CONSOLE */
294 #endif /* MP_SAFE_CONSOLE */
301 return cons_ops
[cons_ops_index
].getc(console_unit
, console_chan
,
308 return cons_ops
[cons_ops_index
].getc(console_unit
, console_chan
,
314 vcgetc(__unused
int l
,
316 __unused boolean_t wait
,
317 __unused boolean_t raw
)
321 if( 0 == (*PE_poll_input
)( 0, &c
))