]> git.saurik.com Git - apple/xnu.git/blob - osfmk/console/ppc/serial_console.c
xnu-792.10.96.tar.gz
[apple/xnu.git] / osfmk / console / ppc / serial_console.c
1 /*
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 * @OSF_COPYRIGHT@
24 */
25 /*
26 * @APPLE_FREE_COPYRIGHT@
27 */
28
29 #include <mach_kdb.h>
30 #include <platforms.h>
31 #include <serial_console_default.h>
32
33 #include <kern/spl.h>
34 #include <machine/machparam.h> /* spl definitions */
35 #include <types.h>
36 #include <console/video_console.h>
37 #include <console/serial_protos.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>
48
49 /*
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).
57 */
58
59 const int console_unit = 0;
60 const uint32_t console_chan_default = CONSOLE_PORT;
61 #define console_chan (console_chan_default) /* ^ cpu_number()) */
62
63
64 #define MP_SAFE_CONSOLE 1 /* Set this to 1 to allow more than 1 processor to print at once */
65 #if MP_SAFE_CONSOLE
66
67 struct ppcbfr { /* Controls multiple processor output */
68 unsigned int pos; /* Current position in buffer */
69 unsigned int noprompt; /* Set if we skip the prompt */
70 unsigned int echo; /* Control character echoing */
71 char buffer[256]; /* Fairly big buffer */
72 };
73 typedef struct ppcbfr ppcbfr_t;
74
75 ppcbfr_t cbfr_boot_cpu; /* Get one for boot cpu */
76 volatile unsigned int cbfpend; /* A buffer is pending output */
77 volatile unsigned int sconowner=-1; /* Mark who's actually writing */
78
79 #endif
80
81 #define OPS(putc, getc, nosplputc, nosplgetc) putc, getc
82
83 console_ops_t cons_ops[] = {
84 {OPS(scc_putc, scc_getc, no_spl_scputc, no_spl_scgetc)},
85 {OPS(vcputc, vcgetc, no_spl_vcputc, no_spl_vcgetc)},
86 };
87
88 uint32_t nconsops = (sizeof cons_ops / sizeof cons_ops[0]);
89
90 uint32_t cons_ops_index = VC_CONS_OPS;
91
92 unsigned int killprint = 0;
93 unsigned int debcnputc = 0;
94 extern unsigned int mappingdeb0;
95 extern int debugger_cpu;
96
97 void *console_per_proc_alloc(boolean_t boot_processor)
98 {
99 ppcbfr_t *cbfr_cpu;
100
101 if (boot_processor)
102 cbfr_cpu = &cbfr_boot_cpu;
103 else {
104 cbfr_cpu = (ppcbfr_t *)kalloc(sizeof(ppcbfr_t));
105 if (cbfr_cpu == (ppcbfr_t *)NULL)
106 return (void *)NULL;
107 }
108 bzero((char *)cbfr_cpu, sizeof(ppcbfr_t));
109 return (void *)cbfr_cpu;
110 }
111
112 void console_per_proc_free(void *per_proc_cbfr)
113 {
114 if (per_proc_cbfr == (void *)&cbfr_boot_cpu)
115 return;
116 else
117 kfree(per_proc_cbfr, sizeof(ppcbfr_t));
118 }
119
120
121 static void _cnputc(char c)
122 {
123 cons_ops[cons_ops_index].putc(console_unit, console_chan, c);
124 }
125
126 void cnputcusr(char c) { /* Echo input character directly */
127 struct per_proc_info *procinfo;
128 spl_t s;
129
130 s=splhigh();
131 procinfo = getPerProc();
132
133 hw_atomic_add(&(procinfo->debugger_holdoff), 1); /* Don't allow debugger entry just now (this is a HACK) */
134
135 _cnputc( c); /* Echo the character */
136 if(c=='\n') _cnputc( '\r'); /* Add a return if we had a new line */
137
138 hw_atomic_sub(&(procinfo->debugger_holdoff), 1); /* Don't allow debugger entry just now (this is a HACK) */
139 splx(s);
140 return;
141 }
142
143 void
144 cnputc(char c)
145 {
146 unsigned int oldpend, i, cpu, ourbit, sccpu;
147 struct per_proc_info *procinfo;
148 ppcbfr_t *cbfr, *cbfr_cpu;
149 spl_t s;
150
151 #if MP_SAFE_CONSOLE
152
153 /*
154 * Handle multiple CPU console output.
155 * Note: this thing has gotten god-awful complicated. We need a better way.
156 */
157
158
159 if(killprint) {
160 return; /* If printing is disabled, bail... */
161 }
162
163 s=splhigh(); /* Don't bother me */
164 procinfo = getPerProc();
165 cpu = procinfo->cpu_number;
166 cbfr = procinfo->pp_cbfr;
167
168 hw_atomic_add(&(procinfo->debugger_holdoff), 1); /* Don't allow debugger entry just now (this is a HACK) */
169
170 ourbit = 1 << cpu; /* Make a mask for just us */
171 if(debugger_cpu != -1) { /* Are we in the debugger with empty buffers? */
172
173 while(sconowner != cpu) { /* Anyone but us? */
174 hw_compare_and_store(-1, cpu, (unsigned int *)&sconowner); /* Try to mark it for us if idle */
175 }
176
177 _cnputc( c); /* Yeah, just write it */
178 if(c=='\n') /* Did we just write a new line? */
179 _cnputc( '\r'); /* Yeah, just add a return */
180
181 sconowner=-1; /* Mark it idle */
182 hw_atomic_sub(&(procinfo->debugger_holdoff), 1); /* Don't allow debugger entry just now (this is a HACK) */
183
184 splx(s);
185 return; /* Leave... */
186 }
187
188
189 while(ourbit&cbfpend); /* We aren't "double buffered," so we'll just wait until the buffers are written */
190 isync(); /* Just in case we had to wait */
191
192 if(c) { /* If the character is not null */
193 cbfr->buffer[cbfr->pos]=c; /* Fill in the buffer for our CPU */
194 cbfr->pos++; /* Up the count */
195 if(cbfr->pos > 253) { /* Is the buffer full? */
196 cbfr->buffer[254]='\n'; /* Yeah, set the second to last as a LF */
197 cbfr->buffer[255]='\r'; /* And the last to a CR */
198 cbfr->pos=256; /* Push the buffer to the end */
199 c='\r'; /* Set character to a CR */
200 }
201 }
202
203 if(c == '\n') { /* Are we finishing a line? */
204 cbfr->buffer[cbfr->pos]='\r'; /* And the last to a CR */
205 cbfr->pos++; /* Up the count */
206 c='\r'; /* Set character to a CR */
207 }
208
209 #if 1
210 if(cbfr->echo == 1) { /* Did we hit an escape last time? */
211 if(c == 'K') { /* Is it a partial clear? */
212 cbfr->echo = 2; /* Yes, enter echo mode */
213 }
214 else cbfr->echo = 0; /* Otherwise reset escape */
215 }
216 else if(cbfr->echo == 0) { /* Not in escape sequence, see if we should enter */
217 cbfr->echo = 1; /* Set that we are in escape sequence */
218 }
219 #endif
220
221 if((c == 0x00) || (c == '\r') || (cbfr->echo == 2)) { /* Try to push out all buffers if we see CR or null */
222
223 while(1) { /* Loop until we see who's doing this */
224 oldpend=cbfpend; /* Get the currentest pending buffer flags */
225 if(hw_compare_and_store(oldpend, oldpend|ourbit, (unsigned int *)&cbfpend)) /* Swap ours on if no change */
226 break; /* Bail the loop if it worked */
227 }
228
229 if(!hw_compare_and_store(-1, cpu, (unsigned int *)&sconowner)) { /* See if someone else has this, and take it if not */
230 procinfo->debugger_holdoff = 0; /* Allow debugger entry (this is a HACK) */
231 splx(s); /* Let's take some 'rupts now */
232 return; /* We leave here, 'cause another processor is already writing the buffers */
233 }
234
235 while(1) { /* Loop to dump out all of the finished buffers */
236 oldpend=cbfpend; /* Get the most current finished buffers */
237 for(sccpu=0; sccpu<real_ncpus; sccpu++) { /* Cycle through all CPUs buffers */
238 if ((PerProcTable[sccpu].ppe_vaddr == 0)
239 || (PerProcTable[sccpu].ppe_vaddr->pp_cbfr == 0))
240 continue;
241
242 cbfr_cpu = PerProcTable[sccpu].ppe_vaddr->pp_cbfr;
243
244 if(oldpend&(1<<sccpu)) { /* Does this guy have a buffer to do? */
245
246 #if 0
247 if(!cbfr_cpu->noprompt) { /* Don't prompt if there was not CR before */
248 _cnputc( '{'); /* Mark CPU number */
249 _cnputc( '0'+sccpu); /* Mark CPU number */
250 _cnputc( '.'); /* (TEST/DEBUG) */
251 _cnputc( '0'+cpu); /* (TEST/DEBUG) */
252 _cnputc( '}'); /* Mark CPU number */
253 _cnputc( ' '); /* Mark CPU number */
254 }
255 #endif
256
257 for(i=0; i<cbfr_cpu->pos; i++) { /* Do the whole buffer */
258 _cnputc(cbfr_cpu->buffer[i]); /* Write it */
259 }
260
261 if(cbfr_cpu->buffer[cbfr_cpu->pos-1]!='\r') { /* Was the last character a return? */
262 cbfr_cpu->noprompt = 1; /* Remember not to prompt */
263 }
264 else { /* Last was a return */
265 cbfr_cpu->noprompt = 0; /* Otherwise remember to prompt */
266 cbfr_cpu->echo = 0; /* And clear echo */
267 }
268
269 cbfr_cpu->pos=0; /* Reset the buffer pointer */
270
271 while(!hw_compare_and_store(cbfpend, cbfpend&~(1<<sccpu), (unsigned int *)&cbfpend)); /* Swap it off */
272 }
273 }
274 sconowner=-1; /* Set the writer to idle */
275 sync(); /* Insure that everything's done */
276 if(hw_compare_and_store(0, 0, (unsigned int *)&cbfpend)) break; /* If there are no new buffers, we are done... */
277 if(!hw_compare_and_store(-1, cpu, (unsigned int *)&sconowner)) break; /* If this isn't idle anymore, we're done */
278
279 }
280 }
281 hw_atomic_sub(&(procinfo->debugger_holdoff), 1); /* Don't allow debugger entry just now (this is a HACK) */
282 splx(s); /* Let's take some 'rupts now */
283
284 #else /* MP_SAFE_CONSOLE */
285 _cnputc( c);
286 if (c == '\n')
287 _cnputc('\r');
288 #endif /* MP_SAFE_CONSOLE */
289
290 }
291
292 int
293 cngetc()
294 {
295 return cons_ops[cons_ops_index].getc(console_unit, console_chan,
296 TRUE, FALSE);
297 }
298
299 int
300 cnmaygetc()
301 {
302 return cons_ops[cons_ops_index].getc(console_unit, console_chan,
303 FALSE, FALSE);
304 }
305
306
307 int
308 vcgetc(__unused int l,
309 __unused int u,
310 __unused boolean_t wait,
311 __unused boolean_t raw)
312 {
313 char c;
314
315 if( 0 == (*PE_poll_input)( 0, &c))
316 return( c);
317 else
318 return( 0);
319 }