Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / devices / dummy_mods / dumbserial / dumbserial.cc
// ========== Copyright Header Begin ==========================================
//
// OpenSPARC T2 Processor File: dumbserial.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 ============================================
/* dumb serial device for NIOBP */
/* "Leveraged" from Legion dumbserial devices :) */
/*
* A dumb serial device - briefly modeled on the NS 16550 device
* ... i.e. register bit fields are similar, but that's about it.
*
* We support input and output character buffering.
* Eventually these sizes will be settable from the configfile
* Also eventually we will understand baud rates etc. and fake
* these appropriately.
* For the moment, we support only a simple status poll, byte
* get and byte put.
* Status simply returns, byte-available, underrun, and overrun
* for input info. Nothing for output (yet).
*/
/*
* Registers (8-bits only - 8byte addressing, upper bits read 0 write ignored)
* num RW Function:
* 0 R Input data register
* 0 W Output data register
* 1 RW Interrupt enable register
* 2 R Interrupt indentification register
* 2 W FIFO control register
* 3 RW Line control register
* 4 RW Modem control register
* 5 RW Line status register
* 6 RW Modem status register
* 7 RW Scratch register
* 8 RW Divisor lo
* 9 RW Divisor hi
*
* See 16550 data sheet p 14 - table M
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <assert.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/dkio.h>
#include <sys/dklabel.h>
#include <sys/vtoc.h>
#include <strings.h>
#include <pthread.h>
#include <errno.h>
#include <signal.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/un.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <pthread.h>
#include "mmi.h"
#include "ui.h"
// #include "createthr.h"
static int dumbserial_ld_operation (void *cd, uint64_t paddr, uint64_t *buf, int size, uint32_t v9cpuid);
static int dumbserial_st_operation (void *cd, uint64_t paddr, uint64_t *buf, int size, uint32_t v9cpuid);
#define MAXCPU 32
#define DBGX(s) do {} while (0)
#define MAXNAMELEN 256
typedef enum {
DS_Input = 0x0, /* RO */
DS_Output = 0x0, /* WO */
DS_IntEnable = 0x1,
DS_IntIdent = 0x2, /* RO */
DS_FIFOCtrl = 0x2, /* WO */
DS_LineCtrl = 0x3,
DS_ModemCtrl = 0x4,
DS_LineStatus = 0x5,
DS_ModemStatus = 0x6,
DS_Scratch = 0x7,
DS_DivLo = 0x8,
DS_DivHi = 0x9
} ds_reg_t;
typedef enum {
TE_Normal,
TE_SawCR,
TE_SawTilde
} ds_tildestate_t;
#define ptest(_s) if (fds.revents & _s) printf(","#_s)
typedef struct {
bool uses_term;
/* device registers .. */
uint8_t scratch; /* ! */
uint8_t line_status;
#define DS_LSTAT_DATA_READY 0x1
#define DS_LSTAT_OVERRUN 0x2
#define DS_LSTAT_PARTIY_ERR 0x4
#define DS_LSTAT_FRAMING_ERR 0x8
#define DS_LSTAT_BREAK 0x10
#define DS_LSTAT_TX_HOLD 0x20
#define DS_LSTAT_TX_EMPTY 0x40
#define DS_LSTAT_RCV_ERR 0x80
#define DEFAULT_RXFIFOSZ 1024
struct {
uint8_t *bufp;
int head;
int tail;
int count;
int size;
} in;
int reg_shift; /* register alignment 0 .. 3 (default = 0 = byte align) */
#define DS_REG_SHIFT_DEF 0
/* the following if uses_term is set */
#define DEFAULT_XTERM_STR "/usr/openwin/bin/xterm -T TTY -e /bin/telnet %s %d &"
char * term_strp;
int tty_skt; /* socket to send / receive to client on */
bool tty_attached;
pthread_t pthread_id;
pthread_mutex_t tty_lock;
pthread_cond_t tty_cv;
ds_tildestate_t tilde_state;
uint64_t startpa;
uint64_t endpa;
const char * type; // GUEST or HYPERVISOR
} ds_state_t;
/*
* Internal functions
*/
#define NUM_DEVICES 2 // hypervisor and guest consoles
#define HV_DEVICE 0
#define G_DEVICE 1
static ds_state_t *dumbserials[NUM_DEVICES];
int temp_ds_counter = 0;
#define HV_SERIAL 0 // calls xterm
#define G_SERIAL 1 // nothing
/*
#define HV_START 0x9f00000000
#define HV_END 0x9f0000004f
*/
#define HV_START 0xfff0c2c000
#define HV_END 0xfff0c2c04f
#define G_START 0x9f10002000
#define G_END 0x9f1000204f
static void create_term(ds_state_t * dsp);
extern "C" static void * ds_input_thr(void * ptr);
static void ds_insert_bytes(ds_state_t * dsp, uint8_t * bufp, int len);
static void dump_buf(char * strp, uint8_t * bufp, int len);
#if NDEBUG /* { */
/* hack for TLB debugging - to go away FIXME */
static void ds_dump_tlb(ds_state_t * dsp, bool is_itlb);
#endif /* } */
ds_state_t *get_ds_instance(uint64_t addr) {
assert(0); // should not be called
#if 0
if ( addr >= HV_START && addr < HV_END ) {
return dumbserials[HV_DEVICE];
} else if ( addr >= G_START && addr < G_END ) {
return dumbserials[G_DEVICE];
} else {
fprintf(stderr, "Unknown dumbconsole address range!\n");
exit(1);
}
#endif
return NULL;
}
extern "C" static int dumbserial_physio_access(uint32_t cpuid, void* obj, uint64_t paddr, mmi_bool_t wr, uint32_t size, uint64_t* buf, uint8_t bytemask)
{
if (wr) {
return dumbserial_st_operation(obj, paddr, buf, size, cpuid);
} else {
return dumbserial_ld_operation(obj, paddr, buf, size, cpuid);
}
}
int dumbserial_ld_operation (void *obj, uint64_t paddr, uint64_t *buf, int size, uint32_t v9cpuid)
{
// Load accessor ...
ds_reg_t reg;
uint64_t val;
ds_state_t *dsp = (ds_state_t *) obj;
DBGX (printf("CAUGHT LD to %016llx with size %d\n", paddr, size); );
if ((paddr & (((uint64_t)1<<dsp->reg_shift)-1))!=0) {
*buf = 0;
return false;
}
// use the offset of the address, not the entire address
reg = (ds_reg_t) ((paddr & 0xfff) >> dsp->reg_shift);
val = 0;
DBGX(printf("\treg: %d\n", reg); );
switch (reg) {
case DS_Input:
pthread_mutex_lock(&dsp->tty_lock);
if (dsp->in.count == 0) {
val = 0;
dsp->line_status &= ~DS_LSTAT_DATA_READY;
} else {
val = dsp->in.bufp[dsp->in.head];
dsp->in.head ++;
if (dsp->in.head >= dsp->in.size) dsp->in.head = 0;
dsp->in.count --;
if (dsp->in.count == 0) {
dsp->line_status &= ~DS_LSTAT_DATA_READY;
}
}
pthread_mutex_unlock(&dsp->tty_lock);
break;
case DS_IntEnable:
break;
case DS_IntIdent:
break;
case DS_LineCtrl:
break;
case DS_ModemCtrl:
break;
case DS_LineStatus:
/* FIXME - more to do here */
/* TX always empty for the moment */
pthread_mutex_lock(&dsp->tty_lock);
val = dsp->line_status;
pthread_mutex_unlock(&dsp->tty_lock);
break;
case DS_ModemStatus:
break;
case DS_Scratch:
dsp->scratch = val & 0xff;
break;
case DS_DivLo:
break;
case DS_DivHi:
break;
default:
return true;
}
if (1 == size)
val = (uint64_t)(int64_t)(int8_t)val;
DBGX(printf("\tLD from %016llx returning %016llx\n", paddr, val););
*buf = val;
return 0;
}
int dumbserial_st_operation (void *obj, uint64_t pa, uint64_t *buf, int size, uint32_t v9cpuid)
{
// Store accessor ...
ds_reg_t reg;
uint64_t val;
ds_state_t *dsp = (ds_state_t *) obj;
DBGX(printf("caught st to %016llx with data %c, size %d\n", pa, (char)*buf, size););
if ((pa & (((uint64_t)1<<dsp->reg_shift)-1))!=0) {
return false;
}
// use the offset of the address, not the entire address
reg = (ds_reg_t) ((pa & 0xfff) >> dsp->reg_shift);
val = *buf;
if (val>0xff) {
return false;
}
val &= 0xff;
switch (reg) {
case DS_Output:
if (dsp->uses_term) {
if (dsp->tty_attached) {
uint8_t buf[1];
buf[0] = val;
write(dsp->tty_skt, buf, 1);
}
} else {
putchar(val);
fflush(stdout);
}
break;
case DS_IntEnable:
break;
case DS_FIFOCtrl:
break;
case DS_LineCtrl:
break;
case DS_ModemCtrl:
break;
case DS_LineStatus:
/* FIXME - more to do here */
/* TX always empty for the moment */
pthread_mutex_lock(&dsp->tty_lock);
dsp->line_status = (val & 0xff) | DS_LSTAT_TX_EMPTY | DS_LSTAT_TX_HOLD;
pthread_mutex_unlock(&dsp->tty_lock);
break;
case DS_ModemStatus:
break;
case DS_Scratch:
dsp->scratch = val & 0xff;
break;
case DS_DivLo:
break;
case DS_DivHi:
break;
default:
return false;
}
return 0;
}
void ds_parse(void) {
ds_state_t *dsp = (ds_state_t *)calloc(1, sizeof(ds_state_t));
dsp->uses_term = false; /* default: output but no input */
dsp->in.size = DEFAULT_RXFIFOSZ;
dsp->reg_shift = DS_REG_SHIFT_DEF;
dsp->term_strp = (char *)malloc(256);
dsp->uses_term = true;
switch(temp_ds_counter) {
case HV_SERIAL:
strcpy(dsp->term_strp, "xterm -l -lf guest1.log -bg black -fg green -geometry 80x20+170+300 -T 'Hypervisor Console' -e ./netcons %s %d &");
dumbserials[HV_DEVICE] = dsp;
break;
case G_SERIAL:
strcpy(dsp->term_strp, "xterm -l -lf guest1.log -bg black -fg green -geometry 80x35+200+30 -T 'Guest Console' -e ./netcons %s %d &");
dumbserials[G_DEVICE] = dsp;
break;
default:
break;
}
}
void ds_init(ds_state_t * dsp) {
#if 1
dsp->line_status = DS_LSTAT_TX_EMPTY | DS_LSTAT_TX_HOLD;
#else
dsp->line_status = 0;
#endif
dsp->scratch = 0;
dsp->in.count = 0;
dsp->in.head = 0;
dsp->in.tail = 0;
dsp->in.bufp = (uint8_t *)calloc(1, dsp->in.size);
/* if TTY to be created then do so ... */
if (dsp->uses_term) create_term(dsp);
}
/*
* Create term ... during initialisation, create the thread to run the
* terminal.
*/
void create_term(ds_state_t * dsp)
{
dsp->tty_skt = -1;
dsp->tty_attached = false;
/* dsp->tilde_state = TE_Normal; */
dsp->tilde_state = TE_SawCR; /* shouldn't have to CR to use ~ as first input char */
pthread_mutex_init(&dsp->tty_lock, NULL);
pthread_cond_init(&dsp->tty_cv, NULL);
/*
* OK first we create the management thread for this console's input
* - then wait for it to tell us that it is happily up and running
* before we return to the simulator to continue initialisation.
*/
pthread_mutex_lock(&dsp->tty_lock);
pthread_create(&(dsp->pthread_id), NULL, ds_input_thr, (void *) dsp);
/* should probably timeout here incase child doesn't start */
while (!dsp->tty_attached) pthread_cond_wait(&dsp->tty_cv, &dsp->tty_lock);
pthread_mutex_unlock(&dsp->tty_lock);
}
/*
* Thread to manage external connections to this serial port.
*
* By default it creates an xterm with a telnet connection to
* the appropriate i/o port.
*/
void * ds_input_thr(void * ptr)
{
ds_state_t * dsp;
uint8_t buf[1024];
#define MAXHOSTNAME 256
char myhostname[MAXHOSTNAME];
int ds_sv_skt;
struct hostent * hp;
int on, length;
struct sockaddr_in ds_server, from;
char * froms;
dsp = (ds_state_t*)ptr;
/*
* Create our socket to listen to
*/
ds_sv_skt = socket(AF_INET, SOCK_STREAM, 0);
if (ds_sv_skt < 0) {
fprintf(stderr, "opening stream socket");
exit(1);
}
/* enable the reuse of this socket if this process dies */
if (setsockopt(ds_sv_skt, SOL_SOCKET, SO_REUSEADDR, (uint8_t*)&on, sizeof(on))<0) {
fprintf(stderr,"turning on REUSEADDR");
exit(1);
}
/* bind it */
retry:;
ds_server.sin_family = AF_INET;
ds_server.sin_addr.s_addr = INADDR_ANY;
ds_server.sin_port = htons(0); /* bind to an OS selected local port */
if (bind(ds_sv_skt, (struct sockaddr *)&ds_server, sizeof(ds_server)) < 0) {
switch (errno) {
case EAGAIN:
goto retry;
case EADDRINUSE:
fprintf(stderr, "Port is already in use\n");
exit(1);
default:
fprintf(stderr, "binding tcp stream socket");
exit(1);
}
}
length = sizeof(ds_server);
if (getsockname(ds_sv_skt, (struct sockaddr *) &ds_server, &length)==-1) {
fprintf(stderr, "getting socket name");
exit(1);
}
listen(ds_sv_skt, 1);
/*
* Create the client xterm etc
*/
gethostname(myhostname, MAXHOSTNAME);
sprintf((char*)buf, dsp->term_strp, myhostname, ntohs(ds_server.sin_port));
system((char*)buf);
/*
* OK main loop for processing connections and data traffic
*/
do {
if (!dsp->tty_attached) {
ui->output("\nWaiting for connection to : %s:%d\n", myhostname, ntohs(ds_server.sin_port));
length = sizeof(from);
dsp->tty_skt = accept(ds_sv_skt, (struct sockaddr *)&from, (int*)&length);
hp = gethostbyaddr((char *)&from.sin_addr, 4, AF_INET);
if (hp == (struct hostent *)0) {
froms = inet_ntoa(from.sin_addr);
fprintf(stderr,"cant resolve hostname for %s\n", froms);;
} else {
froms = hp->h_name;
}
ui->output("connection from %s:%d\n", froms, ntohs(from.sin_port));
pthread_mutex_lock(&dsp->tty_lock);
dsp->tty_attached = true;
pthread_mutex_unlock(&dsp->tty_lock);
pthread_cond_signal(&dsp->tty_cv);
} else {
int res;
struct pollfd fds;
#define POLL_TIMEOUT -1 /* wait forever ? FIXME ? */
fds.fd = dsp->tty_skt;
fds.events = POLLIN|POLLPRI;
#if HOST_OS_SOLARIS9 /* { */
fds.events |= POLLRDNORM|POLLRDBAND;
#endif /* } */
fds.revents = 0;
res = poll(&fds, 1, POLL_TIMEOUT);
DBGX( printf("tty: ");
ptest(POLLIN);
ptest(POLLOUT);
ptest(POLLERR);
ptest(POLLHUP);
ptest(POLLNVAL);
printf("\n");
fflush(stdout); );
#if HOST_OS_SOLARIS9 /* { */
DBGX( printf("\t");
ptest(POLLRDNORM);
ptest(POLLRDBAND);
ptest(POLLWRNORM);
ptest(POLLWRBAND);
printf("\n");
fflush(stdout); );
#endif /* } */
if (fds.revents & POLLIN) {
res = read(dsp->tty_skt, buf, sizeof (buf));
if (res == 0) {
/* a read of 0 bytes is an EOF */
pthread_mutex_lock(&dsp->tty_lock);
dsp->tty_attached = false;
pthread_mutex_unlock(&dsp->tty_lock);
pthread_cond_signal(&dsp->tty_cv);
close(dsp->tty_skt);
// assert(dsp->tty_skt = -1);
} else if (res<0) {
perror("read");
} else {
DBGX( dump_buf("input bytes:", buf, res); );
ds_insert_bytes(dsp, buf, res);
}
}
}
} while (1);
return (void*)0; /* compiler joy */
}
void dump_buf(char * strp, uint8_t * bufp, int len)
{
int i;
printf("%s read %d bytes: ", strp, len);
for(i=0; i<len; i++) printf("0x%02x [%c]",bufp[i],bufp[i]>=32 && bufp[i]<127 ? bufp[i] : '.');
printf("\n");
}
/* emits string and newline */
void
ds_output(ds_state_t *dsp, const char *str)
{
if (dsp->uses_term && dsp->tty_attached) {
(void) write(dsp->tty_skt, str, strlen(str));
(void) write(dsp->tty_skt, "\n", 1);
} else {
puts(str);
fflush(stdout);
}
}
/* FIXME: This compile option
* enables the console to force an external chip reset of any procs
* attached to the same domain.
* This is somewhat of a hack, and should be handled else where ...
* ... which is why it is not a device option in the config file
*/
#if CONSOLE_RESET /* { */
void
ds_domain_reset(ds_state_t * dsp)
{
// domain_t * dp;
int i;
/*
* FIXME: this is a hack ...
* walk the procs in my domain, and reset them all
*/
// dp = dsp->config_devp->domainp;
for (i=0; i<dp->procs.count; i++) {
config_proc_t * cp;
cp = LIST_ENTRY(dp->procs, i);
cp->proc_typep->ext_signal(cp, ES_Reset);
}
}
#endif /* } */
void
ds_insert_bytes(ds_state_t *dsp, uint8_t *bufp, int len)
{
int i;
pthread_mutex_lock(&dsp->tty_lock);
/*
* process all characters in buffer, don't check for overrun
* right away
*/
for (i = 0; i < len; i++) {
int c = bufp[i];
DBGX( printf("State %d : Char typed 0x%x [%c]\n", (int)dsp->tilde_state, c, c>=' ' && c<127 ? c : '.'); fflush(stdout); );
switch (dsp->tilde_state) {
case TE_Normal: /* waiting for CR */
if (c == '\n') {
dsp->tilde_state = TE_SawCR;
break;
}
case TE_SawCR: /* waiting for tilde */
if (c == '~') {
dsp->tilde_state = TE_SawTilde;
goto skip;
}
if (c != '\n') dsp->tilde_state = TE_Normal;
break;
case TE_SawTilde: /* tilde command */
dsp->tilde_state = TE_SawCR;
switch (c) {
case '~': /* emit single tilde */
dsp->tilde_state = TE_Normal;
break;
case '#': /* BREAK */
dsp->line_status |= DS_LSTAT_BREAK;
ds_output(dsp, "BREAK");
/* allow another ~ cmd without CR */
goto skip;
case '?': /* help */
ds_output(dsp, "dumb_serial tilde escapes:");
ds_output(dsp, "\t# BREAK");
ds_output(dsp, "\t~ generate tilde");
#if CONSOLE_RESET /* { */
ds_output(dsp, "\tx external reset for CPUs in same domain");
#endif /* } */
#if !NDEBUG /* { */
ds_output(dsp, "\ti dump I-TLB contents for CPUs in same domain");
ds_output(dsp, "\td dump D-TLB contents for CPUs in same domain");
ds_output(dsp, "\tb toggle the debug output enable bits");
#endif /* } */
ds_output(dsp, "\t? this message");
/* allow another ~ cmd without CR */
goto skip;
#if CONSOLE_RESET /* { */
case 'x': /* Hack to enable extern chip reset easily */
ds_output(dsp, "Resetting cpu(s) in domain");
ds_domain_reset(dsp);
goto skip; /* swallow 'x' character after sending reset */
#endif /* } */
#if !NDEBUG /* { */
case 'i':
// ds_dump_tlb(dsp, false);
goto skip;
case 'd':
// ds_dump_tlb(dsp, true);
goto skip;
case 'b':
// debug_bits ^= -1;
goto skip;
#endif /* } */
default: /* eat current char */
/*
* FIXME could emit ~ and current char
* but it's harder
*/
ds_output(dsp, "~? for tilde help");
goto skip;
}
break;
}
if (dsp->in.count < dsp->in.size) {
dsp->in.bufp[dsp->in.tail] = bufp[i];
dsp->in.tail++;
if (dsp->in.tail >= dsp->in.size)
dsp->in.tail = 0;
dsp->in.count++;
dsp->line_status |= DS_LSTAT_DATA_READY;
} else {
if (!(dsp->line_status & DS_LSTAT_OVERRUN))
fprintf(stderr, "dumbserial: buffer overrun");
dsp->line_status |= DS_LSTAT_OVERRUN;
}
skip:;
}
pthread_mutex_unlock(&dsp->tty_lock);
}
#if NDEBUG /* { */
/* hack for TLB debugging - to go away FIXME */
/* First find all the cpus, then dump their TLBs ... */
static void ds_dump_tlb(ds_state_t * dsp, bool is_dtlb)
{
extern void niagara_dump_tlbs(config_proc_t * cp, bool is_dtlb);
domain_t * dp;
int i;
/*
* FIXME: this is a hack ...
* walk the procs in my domain, and dump the tlb contents
*/
dp = dsp->config_devp->domainp;
for (i=0; i<dp->procs.count; i++) {
config_proc_t * cp;
cp = LIST_ENTRY(dp->procs, i);
niagara_dump_tlbs(cp, is_dtlb); /* FIXME */
}
}
#endif /* } */
extern "C" void dumbserial_create_instance (const char *modname, const char *instance_name)
{
ds_state_t * dsp = new ds_state_t;
dsp->uses_term = true;
dsp->in.size = DEFAULT_RXFIFOSZ;
dsp->reg_shift = DS_REG_SHIFT_DEF;
dsp->term_strp = (char *)malloc(256);
mmi_instance_t instance = mmi_register_instance(modname, instance_name, (void *) dsp, "dumbserial model");
// parse startpa, endpa, type values for this instance
// syntax: sysconf dumbserial <name> type=<type> startpa=<pa> endpa=<pa>
// where <type> is either HYPERVISOR or GUEST
// syntax example: sysconf dumbserial ds0 type=HYPERVISOR startpa=0xfff0c2c000 endpa=0xfff0c2cfff
int argc = mmi_argc(instance);
int i;
for (i=0; i<argc; i++) {
char * arg = strdup(mmi_argv(instance, i));
char * marker;
char * lv = strtok_r(arg, "=", &marker);
if (strcmp(lv, "startpa") == 0) {
errno = 0;
char * rv = strtok_r(NULL, "=", &marker);
dsp->startpa = strtoull(rv, NULL, 0);
if (errno) {
perror("dumbserial: error parsing startpa");
exit(1);
}
} else if (strcmp(lv, "endpa") == 0) {
errno = 0;
char * rv = strtok_r(NULL, "=", &marker);
dsp->endpa = strtoull(rv, NULL, 0);
if (errno) {
perror("dumbserial: error parsing startpa");
exit(1);
}
} else if (strcmp(lv, "type") == 0) {
char * rv = strtok_r(NULL, "=", &marker);
dsp->type = strdup(rv);
} // else - do nothing
free(arg);
}
if (strcmp(dsp->type, "HYPERVISOR") == 0) {
strcpy(dsp->term_strp, "xterm -l -lf hypervisor1.log -bg black -fg green -geometry 80x20+170+300 -T 'Hypervisor Console' -e ./netcons %s %d &");
// dumbserials[HV_DEVICE] = dsp;
} else if (strcmp(dsp->type, "GUEST") == 0) {
strcpy(dsp->term_strp, "xterm -l -lf guest1.log -bg black -fg green -geometry 80x35+200+30 -T 'Guest Console' -e ./netcons %s %d &");
} else {
fprintf(stderr, "DUMBSERIAL: invalid type in sysconf directive (%s) - must be HYPERVISOR or GUEST\n", dsp->type);
}
// Parses memory information
// ds_parse();
// loads file
ds_init(dsp);
// register IO operations
uint64_t sz = dsp->endpa - dsp->startpa + 1;
ui->output ("dumbserial (%s): register LD/ST access @PA=0x%llx size=0x%llx\n", instance_name, dsp->startpa, sz);
if (mmi_map_physio(dsp->startpa, sz, (void *) dsp, dumbserial_physio_access)) {
fprintf (stderr, "dumbserial (%s): unable to register IO interceptor @0x%llx size 0x%llx\n", instance_name, dsp->startpa, sz);
return;
}
}
extern "C" void _init () {
char buff[128];
int ncpu;
int argc;
char *blaze_ver_s;
float blaze_ver;
if (! mmi_register_instance_creator ("dumbserial", dumbserial_create_instance )) {
fprintf (stderr, "Cannot register instance creator for <%s> \n", "dumbserial");
return;
}
/* Assign interface */
}
/////////////////////////////////////////////////
extern "C" void _fini ()
{
}