|
|
1.1 root 1: /*
2: * Copyright (c) 2000 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 <ppc/POWERMAC/video_console_entries.h>
37: #include <ppc/misc_protos.h>
38: #include <ppc/POWERMAC/serial_io.h>
39: #include <ppc/POWERMAC/mp/mp.h>
40: #include <kern/cpu_number.h>
41: #include <ppc/Firmware.h>
42: #include <ppc/proc_reg.h>
43: #include <pexpert/pexpert.h>
44:
45: /*
46: * A machine MUST have a console. In our case
47: * things are a little complicated by the graphic
48: * display: people expect it to be their "console",
49: * but we'd like to be able to live without it.
50: * This is not to be confused with the "rconsole" thing:
51: * that just duplicates the console I/O to
52: * another place (for debugging/logging purposes).
53: */
54:
55: const int console_unit = 0;
56: const int console_chan_default = CONSOLE_PORT;
57: #define console_chan (console_chan_default) /* ^ cpu_number()) */
58:
59: #define OPS(putc, getc, nosplputc, nosplgetc) putc, getc
60:
61: const struct console_ops {
62: int (*putc)(int, int, int);
63: int (*getc)(int, int, boolean_t, boolean_t);
64: } cons_ops[] = {
65: #define SCC_CONS_OPS 0
66: {OPS(scc_putc, scc_getc, no_spl_scputc, no_spl_scgetc)},
67: #define VC_CONS_OPS 1
68: {OPS(vcputc, vcgetc, no_spl_vcputc, no_spl_vcgetc)},
69: };
70: #define NCONSOPS (sizeof cons_ops / sizeof cons_ops[0])
71:
72: #if SERIAL_CONSOLE_DEFAULT
73: #define CONS_OPS SCC_CONS_OPS
74: #define CONS_NAME "com"
75: #else
76: #define CONS_OPS VC_CONS_OPS
77: #define CONS_NAME "vc"
78: #endif
79:
80: #define MP_SAFE_CONSOLE 1 /* Set this to 1 to allow more than 1 processor to print at once */
81: #if MP_SAFE_CONSOLE
82:
83: struct ppcbfr { /* Controls multiple processor output */
84: unsigned int pos; /* Current position in buffer */
85: unsigned int noprompt; /* Set if we skip the prompt */
86: unsigned int echo; /* Control character echoing */
87: char buffer[256]; /* Fairly big buffer */
88: };
89: typedef struct ppcbfr ppcbfr;
90: ppcbfr cbfr[NCPUS]; /* Get one of these for each processor */
91: volatile unsigned int cbfpend; /* A buffer is pending output */
92: volatile unsigned int sconowner=-1; /* Mark who's actually writing */
93:
94: #endif
95:
96:
97: unsigned int cons_ops_index = CONS_OPS;
98: unsigned int killprint = 0;
99: unsigned int debcnputc = 0;
100: extern unsigned int mappingdeb0;
101: extern int debugger_holdoff[NCPUS];
102:
103: static void _cnputc(char c)
104: {
105: cons_ops[cons_ops_index].putc(console_unit, console_chan, c);
106: }
107:
108: void cnputcusr(char c) { /* Echo input character directly */
109:
110: unsigned int cpu;
111:
112: if (cpu_data[master_cpu].active_thread) cpu = cpu_number(); /* If we're started up, use the current CPU */
113: else cpu = master_cpu; /* Otherwise use the master_cpu */
114:
115: hw_atomic_add(&debugger_holdoff[cpu], 1); /* Don't allow debugger entry just now (this is a HACK) */
116:
117: _cnputc( c); /* Echo the character */
118: if(c=='\n') _cnputc( '\r'); /* Add a return if we had a new line */
119:
120: hw_atomic_sub(&debugger_holdoff[cpu], 1); /* Don't allow debugger entry just now (this is a HACK) */
121: return;
122: }
123:
124: void
125: cnputc(char c)
126: {
127:
128: unsigned int oldpend, i, cpu, ourbit, sccpu;
129: spl_t s;
130:
131: #if MP_SAFE_CONSOLE
132:
133: /*
134: * Handle multiple CPU console output.
135: * Note: this thing has gotten god-awful complicated. We need a better way.
136: */
137:
138:
139: if(killprint) {
140: return; /* If printing is disabled, bail... */
141: }
142:
143: if (cpu_data[master_cpu].active_thread) cpu = cpu_number(); /* If we're started up, use the current CPU */
144: else cpu = master_cpu; /* Otherwise use the master_cpu */
145:
146: hw_atomic_add(&debugger_holdoff[cpu], 1); /* Don't allow debugger entry just now (this is a HACK) */
147:
148: ourbit = 1 << cpu; /* Make a mask for just us */
149: if(debugger_cpu != -1) { /* Are we in the debugger with empty buffers? */
150:
151: while(sconowner != cpu) { /* Anyone but us? */
152: hw_compare_and_store(-1, cpu, (unsigned int *)&sconowner); /* Try to mark it for us if idle */
153: }
154:
155: _cnputc( c); /* Yeah, just write it */
156: if(c=='\n') /* Did we just write a new line? */
157: _cnputc( '\r'); /* Yeah, just add a return */
158:
159: sconowner=-1; /* Mark it idle */
160: hw_atomic_sub(&debugger_holdoff[cpu], 1); /* Don't allow debugger entry just now (this is a HACK) */
161:
162: return; /* Leave... */
163: }
164:
165: s=splhigh(); /* Don't bother me */
166:
167: while(ourbit&cbfpend); /* We aren't "double buffered," so we'll just wait until the buffers are written */
168: isync(); /* Just in case we had to wait */
169:
170: if(c) { /* If the character is not null */
171: cbfr[cpu].buffer[cbfr[cpu].pos]=c; /* Fill in the buffer for our CPU */
172: cbfr[cpu].pos++; /* Up the count */
173: if(cbfr[cpu].pos > 253) { /* Is the buffer full? */
174: cbfr[cpu].buffer[254]='\n'; /* Yeah, set the second to last as a LF */
175: cbfr[cpu].buffer[255]='\r'; /* And the last to a CR */
176: cbfr[cpu].pos=256; /* Push the buffer to the end */
177: c='\r'; /* Set character to a CR */
178: }
179: }
180:
181: if(c == '\n') { /* Are we finishing a line? */
182: cbfr[cpu].buffer[cbfr[cpu].pos]='\r'; /* And the last to a CR */
183: cbfr[cpu].pos++; /* Up the count */
184: c='\r'; /* Set character to a CR */
185: }
186:
187: #if 1
188: if(cbfr[cpu].echo == 1) { /* Did we hit an escape last time? */
189: if(c == 'K') { /* Is it a partial clear? */
190: cbfr[cpu].echo = 2; /* Yes, enter echo mode */
191: }
192: else cbfr[cpu].echo = 0; /* Otherwise reset escape */
193: }
194: else if(cbfr[cpu].echo == 0) { /* Not in escape sequence, see if we should enter */
195: cbfr[cpu].echo = 1; /* Set that we are in escape sequence */
196: }
197: #endif
198:
199: if((c == 0x00) || (c == '\r') || (cbfr[cpu].echo == 2)) { /* Try to push out all buffers if we see CR or null */
200:
201: while(1) { /* Loop until we see who's doing this */
202: oldpend=cbfpend; /* Get the currentest pending buffer flags */
203: if(hw_compare_and_store(oldpend, oldpend|ourbit, (unsigned int *)&cbfpend)) /* Swap ours on if no change */
204: break; /* Bail the loop if it worked */
205: }
206:
207: if(!hw_compare_and_store(-1, cpu, (unsigned int *)&sconowner)) { /* See if someone else has this, and take it if not */
208: debugger_holdoff[cpu] = 0; /* Allow debugger entry (this is a HACK) */
209: splx(s); /* Let's take some 'rupts now */
210: return; /* We leave here, 'cause another processor is already writing the buffers */
211: }
212:
213: while(1) { /* Loop to dump out all of the finished buffers */
214: oldpend=cbfpend; /* Get the most current finished buffers */
215: for(sccpu=0; sccpu<NCPUS; sccpu++) { /* Cycle through all CPUs buffers */
216:
217: if(oldpend&(1<<sccpu)) { /* Does this guy have a buffer to do? */
218:
219: #if 0
220: if(!cbfr[sccpu].noprompt) { /* Don't prompt if there was not CR before */
221: _cnputc( '{'); /* Mark CPU number */
222: _cnputc( '0'+sccpu); /* Mark CPU number */
223: _cnputc( '.'); /* (TEST/DEBUG) */
224: _cnputc( '0'+cpu); /* (TEST/DEBUG) */
225: _cnputc( '}'); /* Mark CPU number */
226: _cnputc( ' '); /* Mark CPU number */
227: }
228: #endif
229:
230: for(i=0; i<cbfr[sccpu].pos; i++) { /* Do the whole buffer */
231: _cnputc( cbfr[sccpu].buffer[i]); /* Write it */
232: }
233:
234: if(cbfr[sccpu].buffer[cbfr[sccpu].pos-1]!='\r') { /* Was the last character a return? */
235: cbfr[sccpu].noprompt = 1; /* Remember not to prompt */
236: }
237: else { /* Last was a return */
238: cbfr[sccpu].noprompt = 0; /* Otherwise remember to prompt */
239: cbfr[sccpu].echo = 0; /* And clear echo */
240: }
241:
242: cbfr[sccpu].pos=0; /* Reset the buffer pointer */
243:
244: while(!hw_compare_and_store(cbfpend, cbfpend&~(1<<sccpu), (unsigned int *)&cbfpend)); /* Swap it off */
245: }
246: }
247: sconowner=-1; /* Set the writer to idle */
248: sync(); /* Insure that everything's done */
249: if(hw_compare_and_store(0, 0, (unsigned int *)&cbfpend)) break; /* If there are no new buffers, we are done... */
250: if(!hw_compare_and_store(-1, cpu, (unsigned int *)&sconowner)) break; /* If this isn't idle anymore, we're done */
251:
252: }
253: }
254: hw_atomic_sub(&debugger_holdoff[cpu], 1); /* Don't allow debugger entry just now (this is a HACK) */
255: splx(s); /* Let's take some 'rupts now */
256:
257: #else /* MP_SAFE_CONSOLE */
258: _cnputc( c);
259: if (c == '\n')
260: _cnputc('\r');
261: #endif /* MP_SAFE_CONSOLE */
262:
263: }
264:
265: int
266: cngetc()
267: {
268: return cons_ops[cons_ops_index].getc(console_unit, console_chan,
269: TRUE, FALSE);
270: }
271:
272: int
273: cnmaygetc()
274: {
275: return cons_ops[cons_ops_index].getc(console_unit, console_chan,
276: FALSE, FALSE);
277: }
278:
279: boolean_t console_is_serial()
280: {
281: return cons_ops_index == SCC_CONS_OPS;
282: }
283:
284: int
285: switch_to_video_console()
286: {
287: int old_cons_ops = cons_ops_index;
288: cons_ops_index = VC_CONS_OPS;
289: return old_cons_ops;
290: }
291:
292: int
293: switch_to_serial_console()
294: {
295: int old_cons_ops = cons_ops_index;
296: cons_ops_index = SCC_CONS_OPS;
297: return old_cons_ops;
298: }
299:
300: /* The switch_to_{video,serial,kgdb}_console functions return a cookie that
301: can be used to restore the console to whatever it was before, in the
302: same way that splwhatever() and splx() work. */
303: void
304: switch_to_old_console(int old_console)
305: {
306: static boolean_t squawked;
307: unsigned int ops = old_console;
308:
309: if (ops >= NCONSOPS && !squawked) {
310: squawked = TRUE;
311: printf("switch_to_old_console: unknown ops %d\n", ops);
312: } else
313: cons_ops_index = ops;
314: }
315:
316:
317: int
318: vcgetc(int l, int u, boolean_t wait, boolean_t raw)
319: {
320: char c;
321:
322: if( 0 == (*PE_poll_input)( 0, &c))
323: return( c);
324: else
325: return( 0);
326: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.