#include <mach_kdb.h>
#include <platforms.h>
#include <serial_console_default.h>
#include <kern/spl.h>
#include <machine/machparam.h>
#include <types.h>
#include <console/video_console.h>
#include <console/serial_protos.h>
#include <kern/kalloc.h>
#include <kern/thread.h>
#include <ppc/misc_protos.h>
#include <ppc/serial_io.h>
#include <kern/cpu_number.h>
#include <ppc/Firmware.h>
#include <ppc/proc_reg.h>
#include <ppc/cpu_internal.h>
#include <ppc/exception.h>
#include <pexpert/pexpert.h>
const int console_unit = 0;
const uint32_t console_chan_default = CONSOLE_PORT;
#define console_chan (console_chan_default)
#define MP_SAFE_CONSOLE 1
#if MP_SAFE_CONSOLE
struct ppcbfr {
unsigned int pos;
unsigned int noprompt;
unsigned int echo;
char buffer[256];
};
typedef struct ppcbfr ppcbfr_t;
ppcbfr_t cbfr_boot_cpu;
volatile unsigned int cbfpend;
volatile unsigned int sconowner=-1;
#endif
#define OPS(putc, getc, nosplputc, nosplgetc) putc, getc
console_ops_t cons_ops[] = {
{OPS(scc_putc, scc_getc, no_spl_scputc, no_spl_scgetc)},
{OPS(vcputc, vcgetc, no_spl_vcputc, no_spl_vcgetc)},
};
uint32_t nconsops = (sizeof cons_ops / sizeof cons_ops[0]);
uint32_t cons_ops_index = VC_CONS_OPS;
unsigned int killprint = 0;
unsigned int debcnputc = 0;
extern unsigned int mappingdeb0;
extern int debugger_cpu;
void *console_per_proc_alloc(boolean_t boot_processor)
{
ppcbfr_t *cbfr_cpu;
if (boot_processor)
cbfr_cpu = &cbfr_boot_cpu;
else {
cbfr_cpu = (ppcbfr_t *)kalloc(sizeof(ppcbfr_t));
if (cbfr_cpu == (ppcbfr_t *)NULL)
return (void *)NULL;
}
bzero((char *)cbfr_cpu, sizeof(ppcbfr_t));
return (void *)cbfr_cpu;
}
void console_per_proc_free(void *per_proc_cbfr)
{
if (per_proc_cbfr == (void *)&cbfr_boot_cpu)
return;
else
kfree(per_proc_cbfr, sizeof(ppcbfr_t));
}
static void _cnputc(char c)
{
cons_ops[cons_ops_index].putc(console_unit, console_chan, c);
}
void cnputcusr(char c) {
struct per_proc_info *procinfo;
spl_t s;
s=splhigh();
procinfo = getPerProc();
hw_atomic_add(&(procinfo->debugger_holdoff), 1);
_cnputc( c);
if(c=='\n') _cnputc( '\r');
hw_atomic_sub(&(procinfo->debugger_holdoff), 1);
splx(s);
return;
}
void
cnputc(char c)
{
unsigned int oldpend, i, cpu, ourbit, sccpu;
struct per_proc_info *procinfo;
ppcbfr_t *cbfr, *cbfr_cpu;
spl_t s;
#if MP_SAFE_CONSOLE
if(killprint) {
return;
}
s=splhigh();
procinfo = getPerProc();
cpu = procinfo->cpu_number;
cbfr = procinfo->pp_cbfr;
hw_atomic_add(&(procinfo->debugger_holdoff), 1);
ourbit = 1 << cpu;
if(debugger_cpu != -1) {
while(sconowner != cpu) {
hw_compare_and_store(-1, cpu, (unsigned int *)&sconowner);
}
_cnputc( c);
if(c=='\n')
_cnputc( '\r');
sconowner=-1;
hw_atomic_sub(&(procinfo->debugger_holdoff), 1);
splx(s);
return;
}
while(ourbit&cbfpend);
isync();
if(c) {
cbfr->buffer[cbfr->pos]=c;
cbfr->pos++;
if(cbfr->pos > 253) {
cbfr->buffer[254]='\n';
cbfr->buffer[255]='\r';
cbfr->pos=256;
c='\r';
}
}
if(c == '\n') {
cbfr->buffer[cbfr->pos]='\r';
cbfr->pos++;
c='\r';
}
#if 1
if(cbfr->echo == 1) {
if(c == 'K') {
cbfr->echo = 2;
}
else cbfr->echo = 0;
}
else if(cbfr->echo == 0) {
cbfr->echo = 1;
}
#endif
if((c == 0x00) || (c == '\r') || (cbfr->echo == 2)) {
while(1) {
oldpend=cbfpend;
if(hw_compare_and_store(oldpend, oldpend|ourbit, (unsigned int *)&cbfpend))
break;
}
if(!hw_compare_and_store(-1, cpu, (unsigned int *)&sconowner)) {
procinfo->debugger_holdoff = 0;
splx(s);
return;
}
while(1) {
oldpend=cbfpend;
for(sccpu=0; sccpu<real_ncpus; sccpu++) {
if ((PerProcTable[sccpu].ppe_vaddr == 0)
|| (PerProcTable[sccpu].ppe_vaddr->pp_cbfr == 0))
continue;
cbfr_cpu = PerProcTable[sccpu].ppe_vaddr->pp_cbfr;
if(oldpend&(1<<sccpu)) {
#if 0
if(!cbfr_cpu->noprompt) {
_cnputc( '{');
_cnputc( '0'+sccpu);
_cnputc( '.');
_cnputc( '0'+cpu);
_cnputc( '}');
_cnputc( ' ');
}
#endif
for(i=0; i<cbfr_cpu->pos; i++) {
_cnputc(cbfr_cpu->buffer[i]);
}
if(cbfr_cpu->buffer[cbfr_cpu->pos-1]!='\r') {
cbfr_cpu->noprompt = 1;
}
else {
cbfr_cpu->noprompt = 0;
cbfr_cpu->echo = 0;
}
cbfr_cpu->pos=0;
while(!hw_compare_and_store(cbfpend, cbfpend&~(1<<sccpu), (unsigned int *)&cbfpend));
}
}
sconowner=-1;
sync();
if(hw_compare_and_store(0, 0, (unsigned int *)&cbfpend)) break;
if(!hw_compare_and_store(-1, cpu, (unsigned int *)&sconowner)) break;
}
}
hw_atomic_sub(&(procinfo->debugger_holdoff), 1);
splx(s);
#else
_cnputc( c);
if (c == '\n')
_cnputc('\r');
#endif
}
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);
}
int
vcgetc(__unused int l,
__unused int u,
__unused boolean_t wait,
__unused boolean_t raw)
{
char c;
if( 0 == (*PE_poll_input)( 0, &c))
return( c);
else
return( 0);
}