Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / devices / serial_4v / serial.cc
// ========== Copyright Header Begin ==========================================
//
// OpenSPARC T2 Processor File: serial.cc
// Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
//
// The above named program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License version 2 as published by the Free Software Foundation.
//
// The above named program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with this work; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
//
// ========== Copyright Header End ============================================
#include "serial_4v.h"
static const char *serial_4v_help = "\
tip based SAM N2 console module (for Legion's virtual console device)\n\
Sysconf format is :\n\
sysconf serial_4v <instance_name> base=<start_addr> size=<map size> [log[=<filename>]] [pop] [fg=<color>] [bg=<color>] [font=<font>] [dnkxoe] [raw] [-a] [T=<title>] [e=<command>]\n\
'base' is the start address of memory mapped address, of the device CSRs\n\
'size' is the size of the CSR space\n\
'log' enables logging of console o/p to a file. The default log file is <instance_name>.log\n\
'raw' - optional boolean parameter, if specified enables unbuffered logging of console o/p, if logging is enabled\n\
The log file is opened in append mode if -a is not specified\n\
'pop' is boolean arg which if present will open an xterm window for console o/p\n\
'e, e, command\' is optional argument to set command instead of /bin/tip\n\
'T, T, title\' is optional argument to set xterm title instead of instance name\n\
'fg, bg, font, T' are optional arguments to set foreground, background and font of the xterm window\n\
'dnkxoe' - do not kill xterm on exit, default - window killed\n\
For UI help type <instance name>\n\
For module specific info type \"modinfo <instance name>\"";
Module *Module::create(const char *_modname, const char *_instance_name){
return new serial4v(_modname, _instance_name);
}
const char * serial4v::get_help(){
return Module::get_help_string();
}
const char *
Module::get_help_string(){
return serial_4v_help;
}
serial4v::serial4v(const char * modname,const char * instance_name)
:
Module(modname,instance_name),
title(0)
{
log = false;
start_pa = -1;
end_pa = 0;
size = 0;
logfile = 0;
pop = false;
portConName = 0;
portCon = -1;
pthread_mutex_init(&mutty,0);
scratch = 0;
line_status = DS_LSTAT_TX_EMPTY | DS_LSTAT_TX_HOLD;
in.count = in.head = in.tail = 0;
in.size = MaxBuf;
font = strdup("-dec-terminal-medium-r-normal-*-14-140-*-75-c-80-iso8859-1");
bg = strdup("grey90");
fg = strdup("black");
exec = strdup("/bin/tip");
kill_xterm_on_exit = true;
raw =false;
append = true;
mmi_register_instance_cmd(getInstance(),serial_4v_help,serial_4v_ui_cmd);
}
bool serial4v::parse_arg(const char * arg){
if(!strcmp("pop",arg)){
pop = true;
return true;
}else if(!strcmp("dnkxoe",arg)){
kill_xterm_on_exit = false;
return true;
}else if(!strcmp("raw",arg)){
raw = true;
return true;
}else if(!strcmp("-a",arg)){
append = false;
return true;
}else if(!strncmp("log",arg,3)){
log = true;
if(arg[3] == '='){
logfile = strdup(arg+4);
debug_more("%s: console log enabled. Log file %s",getName(),logfile);
}else
debug_more("%s: console log enabled. Log file %s.log",getName(),getName());
return true;
}else if(argval("base",arg,&start_pa)){
debug_more("%s: base_pa %llx\n",getName(), start_pa);
return true;
}else if(argval("size",arg,&size)){
debug_more("%s: size %llx, end_pa %llx\n",getName(), size, start_pa + size - 1);
return true;
}else if(argval("bg",arg,&bg)){
debug_more("%s: bg - %s\n",getName(), bg);
return true;
}else if(argval("fg",arg,&fg)){
debug_more("%s: fg - %s\n",getName(), fg);
return true;
}else if(argval("font",arg,&font)){
debug_more("%s: font - %s\n",getName(), font);
return true;
}else if(argval("T",arg,&title)){
debug_more("%s: T - %s\n",getName(), title);
return true;
}else if(argval("e",arg,&exec)){
debug_more("%s: e - %s\n",getName(), exec);
return true;
}else
return false;
}
bool serial4v::check_args(){
if(start_pa == -1){
debug_err("%s:must specify start address\n",getName());
return false;
}else if(size == 0){
debug_err("%s:must specify size of address mapping\n",getName());
return false;
}else
return true;
}
void serial4v::init_done(){
if (!title)
{
title = (const char*)malloc(strlen(getName() + 1));
strcpy((char*)title,getName());
}
Console = new console();
if(fg) Console->setFg(fg);
if(bg) Console->setBg(bg);
if(font) Console->setFont(font);
if(exec) Console->setExec(exec);
if(title) Console->setTitle(title);
portCon = Console->getTerminal((char*)title,10000,getConsoleIp, this, &portConName, pop);
fprintf(stderr,"%s : to connect to console: tip %s\n",getName(),portConName);
Console->setId(getName());
if(log){
if(!logfile){
char * logname = (char*)malloc( strlen( getName() ) + strlen(".log") + 1 );
strcpy(logname,getName());
strcat(logname,".log");
logfile = strdup(logname);
free(logname);
}
Console->log(portCon,true,logfile,raw,append);
}
if(mmi_map_physio(start_pa, size, (void *) this, serial4v_physio_access) != 0) {
debug_err("%s fatal error: unaable to map IO space\n");
exit(1);
}
}
void serial4v::getConsoleIp(void *data,unsigned char *ip, int port){
serial4v * self = (serial4v *)data;
pthread_mutex_lock(&self->mutty);
if(self->in.count < self->in.size){
self->in.bufp[self->in.tail] = *ip;
self->in.tail++;
if(self->in.tail >= self->in.size)
self->in.tail = 0;
self->in.count++;
self->line_status |= DS_LSTAT_DATA_READY;
}else{
if(!(self->line_status & DS_LSTAT_OVERRUN))
self->debug_err("%s: buffer overrun",self->getName());
self->line_status |= DS_LSTAT_OVERRUN;
}
pthread_mutex_unlock(&self->mutty);
}
void serial4v::serial4v_ld (uint64_t paddr, uint64_t *buf, int size){
ds_reg_t reg;
uint64_t val;
reg = (ds_reg_t) (paddr & 0xfff) ;
val = 0;
switch (reg) {
case DS_Input:
pthread_mutex_lock(&mutty);
if (in.count == 0) {
val = 0;
line_status &= ~DS_LSTAT_DATA_READY;
}else{
val = in.bufp[in.head];
in.head ++;
if (in.head >= in.size)
in.head = 0;
in.count --;
if (in.count == 0)
line_status &= ~DS_LSTAT_DATA_READY;
}
pthread_mutex_unlock(&mutty);
break;
case DS_IntEnable:
break;
case DS_IntIdent:
break;
case DS_LineCtrl:
break;
case DS_ModemCtrl:
break;
case DS_LineStatus:
pthread_mutex_lock(&mutty);
val = line_status;
pthread_mutex_unlock(&mutty);
break;
case DS_ModemStatus:
break;
case DS_Scratch:
scratch = val & 0xff;
break;
case DS_DivLo:
break;
case DS_DivHi:
break;
default:
debug_err("%s: rd access to unimplemented register 0x%x\n",getName());
val = 0;
break;
}
*buf = val;
return;
}
void serial4v::serial4v_st(uint64_t pa, uint64_t *buf, int sz){
ds_reg_t reg;
uint64_t val;
reg = (ds_reg_t) (pa & 0xfff);
val = *buf;
assert(sz == 1);
if (val > 0xff)
debug_err("%s:writing 0x%llx to console. Truncate to 8 bits\n",getName());
val &= 0xff;
switch (reg) {
case DS_Output:
{
uint8_t chr = *buf;
Console->writeTerminal(portCon, &chr, 1);
break;
}
case DS_IntEnable:
break;
case DS_FIFOCtrl:
break;
case DS_LineCtrl:
break;
case DS_ModemCtrl:
break;
case DS_LineStatus:
pthread_mutex_lock(&mutty);
line_status = (val & 0xff) | DS_LSTAT_TX_EMPTY | DS_LSTAT_TX_HOLD;
pthread_mutex_unlock(&mutty);
break;
case DS_ModemStatus:
break;
case DS_Scratch:
scratch = val & 0xff;
break;
case DS_DivLo:
break;
case DS_DivHi:
break;
default:
debug_err("%s: wr access to unimplemented register 0x%x\n",getName());
break;
}
return;
}
int serial4v::serial4v_physio_access(uint32_t cpuid, void* obj, uint64_t paddr,
mmi_bool_t wr, uint32_t size, uint64_t* buf, uint8_t bytemask){
serial4v* s = (serial4v*) obj;
if(wr)
s->serial4v_st(paddr,buf,size);
else
s->serial4v_ld(paddr,buf,size);
return 0;
}
int serial_4v_ui_cmd(void * obj, int argc, char * argv[]){
serial4v * i = (serial4v *)obj;
i->handle_ui(argc, argv);
return 0;
}
void serial4v::handle_ui(int argc, char * argv[]){
if(argc == 1){
ui_cmd_usage();
return;
}else if(!strcmp(argv[1],"send")){
if(argv[2]){
const int bufSize = 1024 * 10;
char buf[bufSize];
buf[0] = '\0';
// no error checking for command string to be longer than 10KB
for(int i = 2; i < argc; i++){
strcat(buf,argv[i]);
strcat(buf," ");
}
buf[strlen(buf) - 1] = '\n';
for(int i = 0; i < strlen(buf); i++)
getConsoleIp((void*)this,(uint8_t *)(buf + i),-1);
}else{
char buf[2];
buf[0] = '\n';
buf[1] = '\0';
for(int i = 0; i < strlen(buf); i++)
getConsoleIp((void*)this,(uint8_t *)(buf + i),-1);
}
}else if(!strcmp(argv[1],"sendfile")){
FILE * fp;
if(argv[2]){
fp = fopen(argv[2],"r");
if(fp){
uint8_t chr;
while(fread(&chr,1,1,fp))
getConsoleIp((void*)this,&chr,-1);
}
else
fprintf(stderr,"%s restore: error opening file <%s>\n",getName(),argv[2]);
}else
fprintf(stderr,"%s sendfile: no filename specified\n",getName());
}else if(!strcmp(argv[1],"dump")){
FILE * fp = stderr;
if(argv[2]){
fp = fopen(argv[2],"w");
if(!fp){
fprintf(stderr,"%s dump: error opening file <%s>\n",getName(),argv[2]);
fp = stderr;
}
}
dump(fp);
if(fp != stderr)
fclose(fp);
}else if(!strcmp(argv[1],"restore")){
FILE * fp;
if(argv[2]){
fp = fopen(argv[2],"r");
if(fp){
restore(fp);
fclose(fp);
}else
fprintf(stderr,"%s restore: error opening file <%s>\n",getName(),argv[2]);
}else
fprintf(stderr,"%s restore: no restore filename specified\n",getName());
}else if(!strcmp(argv[1],"debug")){
if(argv[2]){
debug_level = atoi(argv[2]);
fprintf(stderr,"%s: set debug level to %d\n",getName(),debug_level);
}else
fprintf(stderr,"%s: current debug level %d\n",getName(),debug_level);
}else if(!strcmp(argv[1],"pop")){
Console->pop_term(portCon);
}else if(!strcmp(argv[1],"kill")){
Console->kill_term(portCon);
}else if(!strcmp(argv[1],"fg")){
if(fg) free((void*)fg);
if(argv[2]){
fg = strdup(argv[2]);
Console->setFg(fg);
}else
fprintf(stderr," fg : %s\n", fg);
}else if(!strcmp(argv[1],"bg")){
if(bg) free((void*)bg);
if(argv[2]){
bg = strdup(argv[2]);
Console->setBg(bg);
}else
fprintf(stderr," bg : %s\n", bg);
}else if(!strcmp(argv[1],"font")){
if(font) free((void*)font);
if(argv[2]){
font = strdup(argv[2]);
Console->setFont(font);
}else
fprintf(stderr," font : %s\n", font);
}else if(!strcmp(argv[1],"T")){
if(title) free((void*)title);
if(argv[2]){
title = strdup(argv[2]);
Console->setTitle(title);
}else
fprintf(stderr," title : %s\n", title);
}else if(!strcmp(argv[1],"e")){
if(exec) free((void*)exec);
if(argv[2]){
exec = strdup(argv[2]);
Console->setExec(exec);
}else
fprintf(stderr," exec : %s\n", exec);
}else
debug_err("%s: unsupported UI command <%s>\n",getName(),argv[1]);
return;
}