]> git.saurik.com Git - apple/xnu.git/blob - osfmk/console/ppc/serial_console.c
xnu-1456.1.26.tar.gz
[apple/xnu.git] / osfmk / console / ppc / serial_console.c
1 /*
2 * Copyright (c) 2000-2006 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 <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>
54
55 /*
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).
63 */
64
65 const int console_unit = 0;
66 const uint32_t console_chan_default = CONSOLE_PORT;
67 #define console_chan (console_chan_default) /* ^ cpu_number()) */
68
69 #define MP_SAFE_CONSOLE 1 /* Set this to 1 to allow more than 1 processor to print at once */
70 #if MP_SAFE_CONSOLE
71 struct ppcbfr { /* Controls multiple processor output */
72 unsigned int pos; /* Current position in buffer */
73 unsigned int noprompt; /* Set if we skip the prompt */
74 unsigned int echo; /* Control character echoing */
75 char buffer[256]; /* Fairly big buffer */
76 };
77 typedef struct ppcbfr ppcbfr_t;
78
79 ppcbfr_t cbfr_boot_cpu; /* Get one for boot cpu */
80 volatile unsigned int cbfpend; /* A buffer is pending output */
81 volatile unsigned int sconowner=-1; /* Mark who's actually writing */
82 #endif /* MP_SAFE_CONSOLE */
83
84 struct console_ops cons_ops[] = {
85 {
86 .putc = scc_putc,
87 .getc = scc_getc,
88 },
89 {
90 .putc = vcputc,
91 .getc = vcgetc,
92 },
93 };
94
95 uint32_t nconsops = (sizeof cons_ops / sizeof cons_ops[0]);
96
97 uint32_t cons_ops_index = VC_CONS_OPS;
98
99 unsigned int killprint = 0;
100 unsigned int debcnputc = 0;
101 extern unsigned int mappingdeb0;
102 extern int debugger_cpu;
103
104 void *console_per_proc_alloc(boolean_t boot_processor)
105 {
106 ppcbfr_t *cbfr_cpu;
107
108 if (boot_processor)
109 cbfr_cpu = &cbfr_boot_cpu;
110 else {
111 cbfr_cpu = (ppcbfr_t *)kalloc(sizeof(ppcbfr_t));
112 if (cbfr_cpu == (ppcbfr_t *)NULL)
113 return (void *)NULL;
114 }
115 bzero((char *)cbfr_cpu, sizeof(ppcbfr_t));
116 return (void *)cbfr_cpu;
117 }
118
119 void console_per_proc_free(void *per_proc_cbfr)
120 {
121 if (per_proc_cbfr == (void *)&cbfr_boot_cpu)
122 return;
123 else
124 kfree(per_proc_cbfr, sizeof(ppcbfr_t));
125 }
126
127 static void _cnputc(char c)
128 {
129 cons_ops[cons_ops_index].putc(console_unit, console_chan, c);
130 }
131
132 void cnputc_unbuffered(char c) {
133 _cnputc(c);
134 }
135
136 void cnputcusr(char c) { /* Echo input character directly */
137 struct per_proc_info *procinfo;
138 spl_t s;
139
140 s=splhigh();
141 procinfo = getPerProc();
142
143 (void)hw_atomic_add(&(procinfo->debugger_holdoff), 1); /* Don't allow debugger entry just now (this is a HACK) */
144
145 _cnputc( c); /* Echo the character */
146 if(c=='\n') _cnputc( '\r'); /* Add a return if we had a new line */
147
148 (void)hw_atomic_sub(&(procinfo->debugger_holdoff), 1); /* Don't allow debugger entry just now (this is a HACK) */
149 splx(s);
150 return;
151 }
152
153 void
154 cnputc(char c)
155 {
156 unsigned int oldpend, i, cpu, ourbit, sccpu;
157 struct per_proc_info *procinfo;
158 ppcbfr_t *cbfr, *cbfr_cpu;
159 spl_t s;
160
161 #if MP_SAFE_CONSOLE
162
163 /*
164 * Handle multiple CPU console output.
165 * Note: this thing has gotten god-awful complicated. We need a better way.
166 */
167
168
169 if(killprint) {
170 return; /* If printing is disabled, bail... */
171 }
172
173 s=splhigh(); /* Don't bother me */
174 procinfo = getPerProc();
175 cpu = procinfo->cpu_number;
176 cbfr = procinfo->pp_cbfr;
177
178 (void)hw_atomic_add(&(procinfo->debugger_holdoff), 1); /* Don't allow debugger entry just now (this is a HACK) */
179
180 ourbit = 1 << cpu; /* Make a mask for just us */
181 if(debugger_cpu != -1) { /* Are we in the debugger with empty buffers? */
182
183 while(sconowner != cpu) { /* Anyone but us? */
184 hw_compare_and_store(-1, cpu, &sconowner); /* Try to mark it for us if idle */
185 }
186
187 _cnputc( c); /* Yeah, just write it */
188 if(c=='\n') /* Did we just write a new line? */
189 _cnputc( '\r'); /* Yeah, just add a return */
190
191 sconowner=-1; /* Mark it idle */
192 (void)hw_atomic_sub(&(procinfo->debugger_holdoff), 1); /* Don't allow debugger entry just now (this is a HACK) */
193
194 splx(s);
195 return; /* Leave... */
196 }
197
198
199 while(ourbit&cbfpend); /* We aren't "double buffered," so we'll just wait until the buffers are written */
200 isync(); /* Just in case we had to wait */
201
202 if(c) { /* If the character is not null */
203 cbfr->buffer[cbfr->pos]=c; /* Fill in the buffer for our CPU */
204 cbfr->pos++; /* Up the count */
205 if(cbfr->pos > 253) { /* Is the buffer full? */
206 cbfr->buffer[254]='\n'; /* Yeah, set the second to last as a LF */
207 cbfr->buffer[255]='\r'; /* And the last to a CR */
208 cbfr->pos=256; /* Push the buffer to the end */
209 c='\r'; /* Set character to a CR */
210 }
211 }
212
213 if(c == '\n') { /* Are we finishing a line? */
214 cbfr->buffer[cbfr->pos]='\r'; /* And the last to a CR */
215 cbfr->pos++; /* Up the count */
216 c='\r'; /* Set character to a CR */
217 }
218
219 #if 1
220 if(cbfr->echo == 1) { /* Did we hit an escape last time? */
221 if(c == 'K') { /* Is it a partial clear? */
222 cbfr->echo = 2; /* Yes, enter echo mode */
223 }
224 else cbfr->echo = 0; /* Otherwise reset escape */
225 }
226 else if(cbfr->echo == 0) { /* Not in escape sequence, see if we should enter */
227 cbfr->echo = 1; /* Set that we are in escape sequence */
228 }
229 #endif
230
231 if((c == 0x00) || (c == '\r') || (cbfr->echo == 2)) { /* Try to push out all buffers if we see CR or null */
232
233 while(1) { /* Loop until we see who's doing this */
234 oldpend=cbfpend; /* Get the currentest pending buffer flags */
235 if(hw_compare_and_store(oldpend, oldpend|ourbit, &cbfpend)) /* Swap ours on if no change */
236 break; /* Bail the loop if it worked */
237 }
238
239 if(!hw_compare_and_store(-1, cpu, &sconowner)) { /* See if someone else has this, and take it if not */
240 procinfo->debugger_holdoff = 0; /* Allow debugger entry (this is a HACK) */
241 splx(s); /* Let's take some 'rupts now */
242 return; /* We leave here, 'cause another processor is already writing the buffers */
243 }
244
245 while(1) { /* Loop to dump out all of the finished buffers */
246 oldpend=cbfpend; /* Get the most current finished buffers */
247 for(sccpu=0; sccpu<real_ncpus; sccpu++) { /* Cycle through all CPUs buffers */
248 if ((PerProcTable[sccpu].ppe_vaddr == 0)
249 || (PerProcTable[sccpu].ppe_vaddr->pp_cbfr == 0))
250 continue;
251
252 cbfr_cpu = PerProcTable[sccpu].ppe_vaddr->pp_cbfr;
253
254 if(oldpend&(1<<sccpu)) { /* Does this guy have a buffer to do? */
255
256 #if 0
257 if(!cbfr_cpu->noprompt) { /* Don't prompt if there was not CR before */
258 _cnputc( '{'); /* Mark CPU number */
259 _cnputc( '0'+sccpu); /* Mark CPU number */
260 _cnputc( '.'); /* (TEST/DEBUG) */
261 _cnputc( '0'+cpu); /* (TEST/DEBUG) */
262 _cnputc( '}'); /* Mark CPU number */
263 _cnputc( ' '); /* Mark CPU number */
264 }
265 #endif
266
267 for(i=0; i<cbfr_cpu->pos; i++) { /* Do the whole buffer */
268 _cnputc(cbfr_cpu->buffer[i]); /* Write it */
269 }
270
271 if(cbfr_cpu->buffer[cbfr_cpu->pos-1]!='\r') { /* Was the last character a return? */
272 cbfr_cpu->noprompt = 1; /* Remember not to prompt */
273 }
274 else { /* Last was a return */
275 cbfr_cpu->noprompt = 0; /* Otherwise remember to prompt */
276 cbfr_cpu->echo = 0; /* And clear echo */
277 }
278
279 cbfr_cpu->pos=0; /* Reset the buffer pointer */
280
281 while(!hw_compare_and_store(cbfpend, cbfpend&~(1<<sccpu), &cbfpend)); /* Swap it off */
282 }
283 }
284 sconowner=-1; /* Set the writer to idle */
285 sync(); /* Insure that everything's done */
286 if(hw_compare_and_store(0, 0, &cbfpend)) break; /* If there are no new buffers, we are done... */
287 if(!hw_compare_and_store(-1, cpu, &sconowner)) break; /* If this isn't idle anymore, we're done */
288
289 }
290 }
291 (void)hw_atomic_sub(&(procinfo->debugger_holdoff), 1); /* Don't allow debugger entry just now (this is a HACK) */
292 splx(s); /* Let's take some 'rupts now */
293
294 #else /* MP_SAFE_CONSOLE */
295 _cnputc( c);
296 if (c == '\n')
297 _cnputc('\r');
298 #endif /* MP_SAFE_CONSOLE */
299
300 }
301
302 int
303 cngetc(void)
304 {
305 return cons_ops[cons_ops_index].getc(console_unit, console_chan,
306 TRUE, FALSE);
307 }
308
309 int
310 cnmaygetc(void)
311 {
312 return cons_ops[cons_ops_index].getc(console_unit, console_chan,
313 FALSE, FALSE);
314 }
315
316
317 int
318 vcgetc(__unused int l,
319 __unused int u,
320 __unused boolean_t wait,
321 __unused boolean_t raw)
322 {
323 char c;
324
325 if( 0 == (*PE_poll_input)( 0, &c))
326 return( c);
327 else
328 return( 0);
329 }