]> git.saurik.com Git - apple/xnu.git/blob - osfmk/console/ppc/serial_console.c
6ea518c61cd7cf08848ea18be53b064a646d8a3c
[apple/xnu.git] / osfmk / console / ppc / serial_console.c
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 <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
70 #define MP_SAFE_CONSOLE 1 /* Set this to 1 to allow more than 1 processor to print at once */
71 #if MP_SAFE_CONSOLE
72
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 */
78 };
79 typedef struct ppcbfr ppcbfr_t;
80
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 */
84
85 #endif
86
87 #define OPS(putc, getc, nosplputc, nosplgetc) putc, getc
88
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)},
92 };
93
94 uint32_t nconsops = (sizeof cons_ops / sizeof cons_ops[0]);
95
96 uint32_t cons_ops_index = VC_CONS_OPS;
97
98 unsigned int killprint = 0;
99 unsigned int debcnputc = 0;
100 extern unsigned int mappingdeb0;
101 extern int debugger_cpu;
102
103 void *console_per_proc_alloc(boolean_t boot_processor)
104 {
105 ppcbfr_t *cbfr_cpu;
106
107 if (boot_processor)
108 cbfr_cpu = &cbfr_boot_cpu;
109 else {
110 cbfr_cpu = (ppcbfr_t *)kalloc(sizeof(ppcbfr_t));
111 if (cbfr_cpu == (ppcbfr_t *)NULL)
112 return (void *)NULL;
113 }
114 bzero((char *)cbfr_cpu, sizeof(ppcbfr_t));
115 return (void *)cbfr_cpu;
116 }
117
118 void console_per_proc_free(void *per_proc_cbfr)
119 {
120 if (per_proc_cbfr == (void *)&cbfr_boot_cpu)
121 return;
122 else
123 kfree(per_proc_cbfr, sizeof(ppcbfr_t));
124 }
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 cnputcusr(char c) { /* Echo input character directly */
133 struct per_proc_info *procinfo;
134 spl_t s;
135
136 s=splhigh();
137 procinfo = getPerProc();
138
139 hw_atomic_add(&(procinfo->debugger_holdoff), 1); /* Don't allow debugger entry just now (this is a HACK) */
140
141 _cnputc( c); /* Echo the character */
142 if(c=='\n') _cnputc( '\r'); /* Add a return if we had a new line */
143
144 hw_atomic_sub(&(procinfo->debugger_holdoff), 1); /* Don't allow debugger entry just now (this is a HACK) */
145 splx(s);
146 return;
147 }
148
149 void
150 cnputc(char c)
151 {
152 unsigned int oldpend, i, cpu, ourbit, sccpu;
153 struct per_proc_info *procinfo;
154 ppcbfr_t *cbfr, *cbfr_cpu;
155 spl_t s;
156
157 #if MP_SAFE_CONSOLE
158
159 /*
160 * Handle multiple CPU console output.
161 * Note: this thing has gotten god-awful complicated. We need a better way.
162 */
163
164
165 if(killprint) {
166 return; /* If printing is disabled, bail... */
167 }
168
169 s=splhigh(); /* Don't bother me */
170 procinfo = getPerProc();
171 cpu = procinfo->cpu_number;
172 cbfr = procinfo->pp_cbfr;
173
174 hw_atomic_add(&(procinfo->debugger_holdoff), 1); /* Don't allow debugger entry just now (this is a HACK) */
175
176 ourbit = 1 << cpu; /* Make a mask for just us */
177 if(debugger_cpu != -1) { /* Are we in the debugger with empty buffers? */
178
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 */
181 }
182
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 */
186
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) */
189
190 splx(s);
191 return; /* Leave... */
192 }
193
194
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 */
197
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 */
206 }
207 }
208
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 */
213 }
214
215 #if 1
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 */
219 }
220 else cbfr->echo = 0; /* Otherwise reset escape */
221 }
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 */
224 }
225 #endif
226
227 if((c == 0x00) || (c == '\r') || (cbfr->echo == 2)) { /* Try to push out all buffers if we see CR or null */
228
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 */
233 }
234
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 */
239 }
240
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))
246 continue;
247
248 cbfr_cpu = PerProcTable[sccpu].ppe_vaddr->pp_cbfr;
249
250 if(oldpend&(1<<sccpu)) { /* Does this guy have a buffer to do? */
251
252 #if 0
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 */
260 }
261 #endif
262
263 for(i=0; i<cbfr_cpu->pos; i++) { /* Do the whole buffer */
264 _cnputc(cbfr_cpu->buffer[i]); /* Write it */
265 }
266
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 */
269 }
270 else { /* Last was a return */
271 cbfr_cpu->noprompt = 0; /* Otherwise remember to prompt */
272 cbfr_cpu->echo = 0; /* And clear echo */
273 }
274
275 cbfr_cpu->pos=0; /* Reset the buffer pointer */
276
277 while(!hw_compare_and_store(cbfpend, cbfpend&~(1<<sccpu), (unsigned int *)&cbfpend)); /* Swap it off */
278 }
279 }
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 */
284
285 }
286 }
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 */
289
290 #else /* MP_SAFE_CONSOLE */
291 _cnputc( c);
292 if (c == '\n')
293 _cnputc('\r');
294 #endif /* MP_SAFE_CONSOLE */
295
296 }
297
298 int
299 cngetc()
300 {
301 return cons_ops[cons_ops_index].getc(console_unit, console_chan,
302 TRUE, FALSE);
303 }
304
305 int
306 cnmaygetc()
307 {
308 return cons_ops[cons_ops_index].getc(console_unit, console_chan,
309 FALSE, FALSE);
310 }
311
312
313 int
314 vcgetc(__unused int l,
315 __unused int u,
316 __unused boolean_t wait,
317 __unused boolean_t raw)
318 {
319 char c;
320
321 if( 0 == (*PE_poll_input)( 0, &c))
322 return( c);
323 else
324 return( 0);
325 }