|
|
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.