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