Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / system / blaze / main.cc
// ========== Copyright Header Begin ==========================================
//
// OpenSPARC T2 Processor File: main.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 ============================================
/*
* Copyright (C) 1996, 2001 Sun Microsystems, Inc.
* All rights reserved.
*/
#pragma ident "@(#)1.36 03/06/02 main.cc"
/*
* Copyright (c) 1989, Sun Microsystems, Inc. All Rights Reserved. Sun
* considers its source code as an unpublished, proprietary trade secret, and
* it is available only under strict license provisions. This copyright
* notice is placed here only to protect Sun in the event the source is
* deemed a published work. Disassembly, decompilation, or other means of
* reducing the object code to human readable form is prohibited by the
* license agreement under which this code is provided to the user or company
* in possession of this copy
*
* RESTRICTED RIGHTS LEGEND: Use, duplication, or disclosure by the
* Government is subject to restrictions as set forth in subparagraph
* (c) (1) (ii) of the Rights in Technical Data and Computer Software clause
* at DFARS 52.227-7013 and in similar clauses in the FAR and NASA FAR
* Supplement
*/
/* standard C includes */
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <strings.h>
#include <unistd.h>
#include <dirent.h>
#include <thread.h>
#include <stdlib.h>
#include <ctype.h>
#include <limits.h>
#include <netdb.h>
#include <libgen.h>
/* solaris includes */
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/wait.h>
#include <sys/regset.h>
#include <signal.h>
#include <siginfo.h>
#include <ucontext.h>
#include <dlfcn.h>
#include <list>
/* project includes */
#include "types.h"
#include "blaze_globals.h"
#include "sim_cmd_struct.h"
#include "fileutil.h"
#include "term.h"
#include "system.h"
#include "ui.h"
#include "dr.h"
typedef void* TM_OPAQUE_DATA;
#include "tracemod.h"
#include "ui_utils.h"
#include "ui_cmds.h"
#include "system_impl.h"
#include "vtracer.h"
#include "vtracer_async_queue.h"
// Flexconfig
#include "serial_mod.h"
// to access serial device
#include "property.h"
#include "mmi.h"
#include "remote.h"
#include "dev_registry.h"
#define DEFAULT_RC_FILE ".blazerc"
int scsi_ctrl_count = 0;
devRegistry * samDevs;
uint64_t property_list::fkprom_dtinbuf_pa = 0x50;
int property_list::fkprom_dtinbuf_offset = 0x0;
vtracer_async_queue * trace_async_queue = NULL;
///////////////////////////////////////////////
int blaze_debug = 0;
int blaze_option = 0;
///////////////////////////////////////////////
char version[] = BLAZEVERSION_STRING; // version.h
//configstate_t *config_arch = NULL;
/* */
volatile e_blaze_runstate_t blaze_run_state = e_BLAZE_INVALID;
volatile int blaze_stop_request = 0;
static int openasroot = 0; // open disk devs as root?
int obp_boot_option = 0; // default to fakeprom
/* Memory Object */
memT *mm1 = NULL;
// this is the master clock // not a clock, is total of all cpus !
volatile uint64_t global_tick = 0; // should be in system.cc, be static
/* For terminal output to a file */
typedef struct {
char *configfile;
std::list<char *> *execfiles;
char *progname;
char *logFileName;
char *console_display_name;
char *overlaydir;
char *restore_dir;
#define CMM_RESTORE 1
uint16_t cmdline_mode;
bool_t immediate_start;
bool_t no_startup;
bool_t start_python;
FILE *serial_output_file;
char *serial_output_fname;
FILE *scsi_conf_file;
char *scsi_conf_fname;
uint32_t tsync_port;
} Blaze_cmd_opt;
Blaze_cmd_opt *Popt = NULL;
const char * overlaydir = NULL;
archglobals_t volatile the_arch = { 0 };
archglobals_t the_arch_backup = { 0 };
volatile int64_t the_arch_cmips = 0; /* sw05b Hack */
volatile int the_arch_ccntx = 0;
extern "C" {
void sigcore_handler(int sig, siginfo_t *si, void *arg2);
void sigignore_handler(int sig);
void sigconfirm_handler(int sig);
void sigtermination_handler(int sig);
}
static void init_devices();
static void copy_configuration(const archglobals_t& arch_src,
archglobals_t *arch_dest);
static void verify_configuration(const archglobals_t& arch_src,
const archglobals_t& arch_dest);
static void init_config_arch ();
// FORWARD DECLARATIONS:
bool_t vcpu_save(DR_OPAQUE pdr);
bool_t vcpu_restore(DR_OPAQUE pdr);
/* Externals */
extern void start_filecmd_check (SimCmd* state);
int check_tick_cmpr;
extern VCPU_ExInterface g_cpu_ex_intf;
extern char cpu_lib_name[160];
/*
* Major Paine Threads
*/
void sim_thread_loop (SimCmd*);
#ifdef __cplusplus
extern "C" {
#endif
void * term_thread_wrapper(void *); // simulated system console
#ifdef __cplusplus
}
#endif
// The -- option (or first non option) stops the blaze commandline
// parsing and all remaining options are put into the app_argv
// vector. These remaining options are passed on to the
// python interpreter when it is loaded
static int app_argc = 0;
static char** app_argv = 0;
/*
* Handle Command Line Options
* For getopt() library routine
*/
extern char *optarg;
extern char ver[128];
extern char second_ver[128];
extern int optind;
extern void* asi_ptr[];
Blaze_cmd_opt* handle_args(int argc, char **argv);
static void print_banner();
const char* diskspecfile = "pcidisk.init";
static SimCmd command;
static int not_root_warning = 0;
char *pty_dev_a, *pty_dev_b;
char *pty_dev_c, *pty_dev_d;
char* console_display;
bool pop_window = false;
extern uint64_t get_page_mask(int);
////////////////////////////////////////////////////////////
uint32_t BLAZE_restore_from_checkpoint ()
{
return Popt->cmdline_mode & CMM_RESTORE;
}
void get_dump_version()
{
int v, sv, ssv = 0; FILE *fp; char rfile[PATH_MAX];
sprintf (rfile, SAM_VERSION_FILE, get_restore_dir());
fp = fopen(rfile, "r");
if (!fp) {
sprintf (rfile, BLAZE_VERSION_FILE, get_restore_dir());
fp = fopen(rfile, "r");
}
if (!fp) {
ui->warning("No SAM version is specified in the dump\n ");
ui->warning("there is no guarantee of successfull restoration!!\n ");
return;
} else {
if (fgets (ver, 120, fp) == NULL)
ui->warning("CHECKPOINT might be corrupted!!\n ");
else
ui->output("CHECKPOINT of SAM v %s\n ", ver);
fclose (fp);
}
sprintf (rfile, SECONDARY_VERSION_FILE, get_restore_dir());
fp = fopen(rfile, "r");
if (fp) {
if (fgets (second_ver, 120, fp) == NULL)
ui->warning("Secondary V4 dump info lost!\n ");
else
ui->output("Secondary V4 version: %s\n ", second_ver);
fclose (fp);
}
if (strcmp(DEFAULT_RC_FILE, Popt->configfile))
return; // specified by '-c' already
sscanf(ver, "%d.%d.%d", &v, &sv, &ssv);
if (v > 5 || v == 5 && sv >= 5) {
sprintf(rfile, "%s/%s", get_restore_dir(), RC_DUMP);
if (isFile((const char *)rfile))
Popt->configfile = (char*)strdup(rfile);
}
if (!isFile(Popt->configfile)) {
ui->error("No script file for restoring!\n");
exit(-1);
}
}
char *get_script_file()
{
return Popt->configfile;
}
char *get_restore_dir()
{
return Popt->restore_dir;
}
////////////////////////////////////////////////////////////
serialInterface * systemConsole; // system console pointer
int access_serial_cb
(
uint8_t *c, // character to read/write
int wr // 0 - read, 1 - write
)
{
if(systemConsole == 0){
ui->error("systemConsole pointer null. Possible configuration problem!!\n");
exit(0);
}
if (wr == 0) // read
{
LWord buf = 0;
/* Write the intent of READING the register 0x0 */
systemConsole->reg_access( (char *)&buf, PORT_A_CONTROL, 0x1);
/* Read the register that the SERIAL CONTROL REGISTER is pointing to */
systemConsole->reg_access( (char *)&buf, PORT_A_CONTROL, 0x0);
/* If data is available */
if (buf & RX_CHAR_AVAILABLE)
{
/* Read the port register */
systemConsole->reg_access((char *)&buf, PORT_A_DATA, 0x0);
}
else // no data available
{
buf = 0xff;
}
*c = uint8_t(buf); // char read
}
else // write
{
LWord buf = (LWord)*c;
systemConsole->reg_access((char *)&buf, PORT_A_DATA, 0x1);
}
return 0;
}
////////////////////////////////////////////////////////
int access_io_cb
(
int cpuid, // cpu id
int wr, // operation code
uint64_t paddr, // physical address
uint32_t size, // access size
uint64_t &data, // 64 bit value to read/write
uint64_t bitmask // access bit mask
)
{
return SYSTEM_physio_access ( cpuid, NULL, paddr, bool_t(wr), size, &data, uint8_t(bitmask) );
}
////////////////////////////////////////////////////////
int access_asi_cb
(
int sid, // cpu id
int operation, // operation code
uint32_t asi, // asi value
uint64_t vaddr, // virtual address
int32_t size, // access size
uint64_t &buf // 64 bit data value
)
{
int rc;
// loadable modules that implement external asi should be
// thread safe
if ((operation == VCPU_LOAD_OP)) {
rc = TM_execute_load_asi (asi, vaddr, &buf, size, sid);
}
else { // operation == store
rc = TM_execute_store_asi (asi, vaddr, &buf, size, sid);
}
return rc;
}
///////////////////////////////////
//
// CPU initialization
//
Vcpu * init_cpu ( char *path, int argc, char **argv)
{
int id = g_nvcpu;
VCPU_Config config_info; // cpu config params
// set defaullt values
set_default ( config_info );
// parse configuration parameters
if ( argc > 0 )
{
for ( int i=0; i<argc; i++)
{
if ( set_param ( argv[i], &config_info ) != 0)
{
ui->error("cannot set cpu param %s\n", argv[i]);
exit (1);
}
}
}
// system interface for the cpu module
VCPU_ImpIntf sys_intf;
sys_intf.access_io = access_io_cb;
sys_intf.access_serial = access_serial_cb;
sys_intf.access_asi = access_asi_cb;
sys_intf.vtrace = NULL; //instruction_cb;
sys_intf.mem = mm1; // sys mem
Vcpu* vcpu = create_cpu ( path, config_info, &sys_intf );
if (vcpu == NULL)
{
ui->error( "FATAL : unable to create CPU %d \n",
id);
exit (1);
}
// for compatibility with v4 dump/restore skip "blaze" cpu model
if ((id == 0) && ((vcpu->config.cpu_type & VCPU_IMPL_SIM_MASK) != VCPU_IMPL_SIM_BLAZE))
{
DR_register( (char*)"cpu", vcpu_save, vcpu_restore, vcpu );
}
if (trace_async_queue == NULL) {
trace_async_queue = new vtracer_async_queue;
}
return vcpu;
}
//////////////////////////////////////////////////
//
// save a vcpu (for dump/restore)
//
bool_t vcpu_save(DR_OPAQUE pdr)
{
char *dir = DR_get_dir();
return g_cpu_ex_intf.save(dir);
}
//////////////////////////////////////////////////
//
// restore a vcpu (for dump/restore)
//
bool_t vcpu_restore(DR_OPAQUE pdr)
{
char *dir = DR_get_rdir (pdr);
return g_cpu_ex_intf.restore(dir);
return FALSE;
}
//////////////////////////////////////////////////
//
// Creates TERMINAL/CONSOLE Thread
//
void init_threads ()
{
#ifdef V5_FAKEPROM
thread_t termThread; // special thread that handles terminal IO
thr_create(NULL, NULL, term_thread_wrapper, NULL,
THR_BOUND|THR_DAEMON, &termThread);
#endif
}
//////////////////////////////////////////////////
extern int term_console (char *pty_dev, char *display);
#ifdef BS_WRAPPER
#ifdef __cplusplus
extern "C" {
#endif
extern void init_simix();
#ifdef __cplusplus
}
#endif
#endif
/* ------------------------------------------------------------------------
* blaze signal handlers
*
* whats weird about unix/posix/solaris signal handlers is that they are
* process-wide, you cannot have a different handler for each thread,
* so we register all signal handlers here...
* (you can block/unblock signals on a per-thread basis, which we do,
* and which is done inside each thread separately as necessary).
*
*/
void init_signal_handlers ()
{
/***** core dump signals **************** SIGBUS, SIGSEGV, SIGILL ******/
struct sigaction sact;
sact.sa_handler = NULL;
sact.sa_sigaction = sigcore_handler;
sact.sa_flags = SA_SIGINFO | SA_RESETHAND;
sigaction(SIGBUS, &sact, NULL);
sigaction(SIGSEGV, &sact, NULL);
sigaction(SIGILL, &sact, NULL);
/***** must ignore signals ********************* SIGPIPE, SIGUSR1 ******/
// must ignore sigpipe or blaze will crash whenever switchsim does
signal (SIGPIPE, sigignore_handler);
// for unsticking blaze threads that are stuck in blocking IO
// for terminating workerthreads so we can reconfigure
signal (SIGUSR1, sigignore_handler); /* disconnect (and park) rcvr-thread */
signal (SIGINT, sigignore_handler); /* kill worker-thread */
/***** special case signals ********************* SIGINT, SIGQUIT ******/
/* signal handler for blaze-keyboard -> ask for user confirmation */
// be user friendly, don't let accidental ctrl-C kill blaze !!!
signal (SIGINT, sigconfirm_handler); /* BREAK */
signal (SIGQUIT, sigconfirm_handler); /* CTRL-C */
/*signal (SIGHUP, sigconfirm_handler); * HangUp */
// we're still not sure what this means or what to do when it happens...
// /* signal handler for blaze-nonmaskable-termination -> ? */
// // graceful shutdown before nonmaskable kill signal ???
signal (SIGTERM, sigtermination_handler);
} // -----------------------------------------------------------------------
// Search for $SAM/etc/<proc>_samrc and add it to the Popt->execfiles list
static void samrc_init() {
if (g_nvcpu != 0) {
Vcpu *vcpu = g_vcpu[0];
const char *cpu_name = vcpu->cpu_name(vcpu->config.cpu_type);
const char* exec_name = getexecname();
char* sam_dir = NULL;
if (exec_name == NULL ||
(sam_dir = strdup(exec_name)) == NULL ||
(sam_dir = dirname(sam_dir)) == NULL) {
ui->error("can't allocate memory while searching for "
"$SAM/bin/sam\n", cpu_name);
return;
}
// Here sam_dir should point to $SAM/bin; check to make sure.
int sam_dir_len = strlen(sam_dir);
if (strcmp(&sam_dir[sam_dir_len - 4], "/bin") != 0) {
ui->error("Non-standard sam installation; aborting "
"search for $SAM/etc/%s_samrc\n", cpu_name);
return;
}
sam_dir[sam_dir_len - 4] = '\0'; // Make sam-dir -> $SAM
// Allocate space for "$SAM/etc/<proc>_samrc" and use sprintf
// to assign it.
char *samrc_name =
(char *)malloc(sam_dir_len + sizeof("/etc/_samrc") +
strlen(cpu_name));
if (samrc_name == NULL) {
ui->error("can't allocate memory while searching for "
"$SAM/etc/%s_samrc\n", cpu_name);
return;
}
sprintf(samrc_name, "%s/etc/%s_samrc", sam_dir, cpu_name);
// If the <proc>_samrc file exists, prepend it to the list of files
// to execute at start up.
struct stat stat_buf;
if (stat(samrc_name, &stat_buf) != -1)
Popt->execfiles->push_front(samrc_name);
}
}
static bool sysconf_done = false;
bool SYSTEM_sysconf_done() { return sysconf_done; }
// called after last sysconf line in RC file has been parsed.
static void complete_initialization()
{
if (!sysconf_done) {
SYSTEM_init();
TM_module_init(); // report MMI_CONFIG_INIT_DONE
if (BLAZE_restore_from_checkpoint()) {
restore_devices_action(get_restore_dir());
ui->output("----- RESTORE COMPLETED -----\n");
}
samrc_init();
sysconf_done = true;
}
}
static void process_rc_file(const char * fn){
FILE * fp = fopen(fn,"r");
if( !fp ){
ui->error("Can not open SAM RC file %s\n",fn);
exit(1);
}
const int max_buf_size = 1024 * 10;
char buf[max_buf_size];
int buf_index = 0;
// find the line number of last uncommented sysconf in RC file
// this assumes that all conf's, loads are before last sysconf.
// XXX : to be removed if -f <filename> becomes the norm
int line = 0; int cntr = 0;
while(fgets(buf,max_buf_size,fp)){
cntr++;
buf_index = 0;
while(buf[buf_index] && isspace(buf[buf_index]))
buf_index++;
if(buf[buf_index] == '#')
continue; // skip comment line
if(!strncmp("sysconf",buf + buf_index,strlen("sysconf")) \
&& isspace( *(buf+buf_index + strlen("sysconf")) ))
line = cntr;
}
fseek(fp,0,SEEK_SET);
cntr = 0;
while(fgets(buf,max_buf_size,fp)){
UI_exec_cmd(buf);
cntr++;
if(cntr == line)
complete_initialization();
}
fclose(fp);
return;
}
// -f <filename> SAM command line option
static void process_command_file(const char * fn){
FILE * fp = fopen(fn,"r");
if( !fp ){
ui->error("Can not open SAM command file %s\n",fn);
exit(1);
}
const int max_buf_size = 1024 * 10;
char buf[max_buf_size];
char buf_index = 0;
// make sure that there are no sysconf's in the command file
// make sure that there are no conf's in the command file
int sysconf_line = -1; int conf_line = -1; int cntr = 0;
while(fgets(buf,max_buf_size,fp)){
cntr++;
buf_index = 0;
while(buf[buf_index] && isspace(buf[buf_index]))
buf_index++;
if(buf[buf_index] == '#')
continue; // comment line
if(!strncmp("sysconf",buf + buf_index,strlen("sysconf")) \
&& isspace( *(buf+buf_index + strlen("sysconf")) )){
sysconf_line = cntr;
break;
}
if(!strncmp("conf",buf + buf_index,strlen("conf")) \
&& isspace( *(buf+buf_index + strlen("conf")) )){
conf_line = cntr;
break;
}
}
if(sysconf_line != -1){
ui->error("command file %s has sysconf directive\n",fn);
exit(1);
}
fseek(fp,0,SEEK_SET);
while(fgets(buf,max_buf_size,fp)){
UI_exec_cmd(buf);
}
return;
}
extern void ui_readline();
int main (int argc, char **argv)
{
init_SYSTEM_open (); // sets up search path for "load" ui cmds
for (int i=0; i<MAX_MP; i++) cpu_enabled[i] = 1;
cpu_enable_changed = 1;
init_signal_handlers ();
//
// Rummage up some additional file descriptors
//
struct rlimit rl;
getrlimit(RLIMIT_NOFILE, &rl);
rl.rlim_cur = rl.rlim_max;
setrlimit(RLIMIT_NOFILE, &rl);
//
// get command line arguments
//
Popt = handle_args (argc,argv);
//
// to setup some necessary default values in THE_ARCH
//
init_config_arch();
print_banner();
char *rdt_name = term_redirect_get_file ();
if (rdt_name) {
ui->output("console input redirected from <%s> \n", rdt_name);
}
//
// logging/debugging initialization
//
if (Popt->logFileName)
{
FILE* logfile;
if ((logfile = fopen(Popt->logFileName, "w+")) == NULL) {
ui->error("Unable to open log file <%s>", Popt->logFileName);
exit(1);
}
ui->set_log_file(logfile);
}
// Get dump version for the requirement of some constructors of device modules.
if (BLAZE_restore_from_checkpoint())
get_dump_version();
// to prepare for UI command registering
preinit_ui ();
// init loadable module support
init_tm ();
//
// dump/restore initialization, before UI thread initiated.
//
init_dr ();
init_threads(); // includes all CPU related threads start
init_devices();
samDevs = new devRegistry();
// process the configeRC file before starting the UI thread
process_rc_file(Popt->configfile);
SYSTEM_unlock();
init_ui (Popt->configfile, TRUE);
// Load python if user specified -py
if(Popt->start_python) {
std::string cmd = "run-python-file";
if (app_argc) {
for (int i=0; i< app_argc; i++)
{
cmd += ' ';
cmd += app_argv[i];
}
} else {
// no python application specified, load dummy
cmd += " /dev/null";
}
cmd += '\n';
UI_exec_cmd((char*)cmd.c_str());
}
// check to see if there is -f <filename> option provided
// if yes, execute the UI commands in there
for (std::list<char*>::iterator iter = Popt->execfiles->begin();
iter != Popt->execfiles->end();
++iter) {
process_command_file(*iter);
}
// Jump into the readline enabled ui handler. We exit
// there on quit (or eof).
ui_readline();
// just wait for all child threads (CPU, I/O, net, UI) to complete
while (thr_join(0, NULL, NULL) == 0 ) {
;//sleep(1); ** no reason to sleep, thr_join will select a thrd **
}
ui->fatal("unexpected termination!!! \n");
return 0;
}
////////////////////////////////////////////////////////
void init_devices()
{
int serial_dev_no = 0;
int uid = getuid(); // me
int euid = geteuid(); // root
int status = seteuid(uid); // backdown from root
// do not do it again in pcidisk.cc
ui->verbose("For all disks : overlay directory is <%s> \n", Popt->overlaydir);
overlaydir = (char*)strdup(Popt->overlaydir);
} // init_devices()
//////////////////////////////////////////////////
static void init_config_arch () {
the_arch.nwins = 8;
#ifdef CHPLUS
the_arch.mmutype = (char*)strdup("cheetahplus");
#else
the_arch.mmutype = (char*)strdup("cheetah");
#endif
the_arch.tlbsize = 64;
the_arch.numcpus = 1;
the_arch.loopticks = 16;
the_arch.stickincr = 1;
the_arch.cpus_per_thread = -1;
the_arch.numthreads = -1;
the_arch.arch_flags = 0;
the_arch.skip_mp = 10;
the_arch.block_mp = 0;
the_arch.cpi = FALSE;
}
//
// make a copy of the original config.init values
//
static void
copy_configuration(const archglobals_t& arch_src,
archglobals_t *arch_dest)
{
// first do a bit-by-bit copy
memcpy((void *)arch_dest, (const void *)&arch_src, sizeof(archglobals_t));
// then do a real copy on string
arch_dest->mmutype = strdup(arch_src.mmutype);
}
//
// comapre the configuration values in config.init with the newly
// inputted values (from restore operation, e.g.)
//
static void
verify_configuration(const archglobals_t& /* arch_src */,
const archglobals_t& /* arch_dest */)
{
}
void usage () {
ui->output(
"sam [-options]\n\n\
Version %s\n\
-h - this screen,\n\
-c CFILE - use configuration file CFILE (eg: -c sam.rc)\n\
-R path - restore from dump directory specified in <path>\n\
-goodtrap <pc> - (SAM-only) exit on this pc_va; return 0\n\
-badtrap <pc> - (SAM-only) exit on this pc_va; return 1\n\
-v(ersion) - print version and exit\n\
-w - start xterm window for sim console\n\
-y ovdir - put disk overlays in OVDIR (do not use /tmp for big files)\n\
-f <filename> - execute SAM UI commands in <filename> after RC file is processed\n\
-- <arg0> ... - start Pyhton if py does not occur in RC file, execute\n\
arg0 (if present) as script file passing other args as args to script file.\n\
If py specified in rc file, pass all arguments w/o interpretation to Python\n\
-l LFILE - use log file LFILE\n\
-obp - boot CH/CH+ SAM with COBP\n\
-nomemreserve - allocate simulated memory on demand. Only supported on builds with flat memory model. \n\
",
BLAZEVERSION_STRING);
}
////////////////////////////////////////////////////
static int
StrEq(const char *s1, const char *s2) {
if ( (s1==NULL) || (s2==NULL)) {
return 0;
}
while(*s1 != 0) {
if (*s1++ != *s2++) {
return NULL;
}
}
return (*s2 == 0);
} // StrEq()
#define TSYNC_PORT 11000
//
// Handle Command Line options
//
Blaze_cmd_opt *
handle_args (int argc, char **argv)
{
char hostname[MAXHOSTNAMELEN];
char ovd[MAXHOSTNAMELEN + 64];
Blaze_cmd_opt *popt = (Blaze_cmd_opt*) calloc (1, sizeof(Blaze_cmd_opt));
popt->logFileName = NULL;
popt->configfile = (char*) strdup (DEFAULT_RC_FILE);
popt->progname = (char*) strdup ("blaze");
popt->restore_dir = NULL;
popt->cmdline_mode = 0;
popt->tsync_port = TSYNC_PORT;
popt->execfiles = new std::list<char *>();
popt->start_python = 0;
gethostname(hostname, MAXHOSTNAMELEN);
sprintf (ovd, "./overlayDir.%d.%s", getpid(), hostname);
popt->overlaydir = (char*)strdup (ovd);
SYSTEM_set_goodtrap_pc(0x0);
SYSTEM_set_badtrap_pc(0x0);
/* Figure out the name of this program. */
if (argc < 1) {
popt->progname = strdup("blaze");
} else if ( (popt->progname = strrchr(argv[0], '/')) ) {
++popt->progname;
} else {
popt->progname = argv[0];
}
int argndx = 1;
while(argndx < argc) {
const char *nextarg = argv[argndx++];
//
// Try(!) to keep these alphabetically ordered...
//
if (StrEq(nextarg, "-badtrap")) { // Bad trap
char * arg = argv[argndx++];
char * end; // dummy
if (argndx > argc) {
ui->error("no argument specified to -goodtrap\n");
exit(4);
}
SYSTEM_set_badtrap_pc(strtoull(arg, &end, 0));
} else if (StrEq(nextarg, "-c")) { // the RC file
if (argndx >= argc) {
ui->error("Missing arg for -c option\n ");
exit(1);
}
popt->configfile = strdup(argv[argndx++]);
if ( ! isFile(popt->configfile) ) {
ui->error("Unable to open config file (%s).\n",
popt->configfile);
exit(2);
}
} else if (StrEq(nextarg, "-f")){
if (argndx >= argc) {
ui->error("Missing filename for -f option\n ");
exit(1);
}
// get the filename
popt->execfiles->push_back(strdup(argv[argndx++]));
} else if (StrEq(nextarg, "-goodtrap")) { // Good trap
char * arg = argv[argndx++];
char * end; // dummy
if (argndx > argc) {
ui->error("no argument specified to -goodtrap\n");
exit(4);
}
SYSTEM_set_goodtrap_pc(strtoull(arg, &end, 0));
} else if (StrEq(nextarg, "-l")) { // log file
char * arg;
if (argndx >= argc) {
ui->error("Missing filename for -l option\n ");
exit(1);
}
popt->logFileName = strdup(argv[argndx++]);
} else if (StrEq(nextarg, "-h")) { // help
usage();
exit(1);
} else if (StrEq(nextarg, "-nomemreserve")) {
SYSTEM_set_memreserve (FALSE);
} else if (StrEq(nextarg, "-obp")) { // obp boot option
obp_boot_option = TRUE;
} else if (StrEq(nextarg, "-R")) { // Restore from dump
DIR *rdir;
if (argndx >= argc) {
ui->error("Wrong usage of -R option\n ");
exit(1);
}
rdir = opendir (argv[argndx]);
if (rdir == NULL) {
ui->error("<%s> restore directory is not found", argv[argndx]);
exit(1);
}
popt->restore_dir = (char*)strdup(argv[argndx++]);
popt->cmdline_mode |= CMM_RESTORE;
closedir(rdir);
} else if (StrEq(nextarg, "-v") || StrEq(nextarg,"-version")) { // Version
/* see also version_ui_cmd() */
ui->output("SAM VERSION %s\n", BLAZEVERSION_STRING);
ui->output("BUILT ON %s, AT %s, IN %s\n", __DATE__,__TIME__,__CWD__);
/*if (StrEq(nextarg,"-version"))*/
exit(0);
} else if (StrEq(nextarg, "-w")) { // pop-up window for console
//
// if there is a next argument and it does not start with a '-',
// it must be the display specification
char *arg;
popt->console_display_name = NULL;
if (argndx < argc) {
arg = argv[argndx++];
if ((arg[0] != 0) && (arg[0] != '-')) {
popt->console_display_name = strdup(arg);
}
else {
argndx--;
}
}
// try to get console display id from the $DISPLAY env var
arg = getenv("DISPLAY");
if (arg != NULL) {
popt->console_display_name = strdup(arg);
}
if (popt->console_display_name != NULL) {
console_display = strdup(popt->console_display_name);
pop_window = true;
}else{
ui->error("it seems that you forgot to set DISPLAY environment variable.\n");
}
} else if (StrEq(nextarg, "-y")) { // overlayDir
char *arg = argv[argndx++];
popt->overlaydir = (char*) strdup(arg);
} else if (StrEq(nextarg, "-py")) { // overlayDir
popt->start_python = 1;
} else if (StrEq(nextarg, "--") || (nextarg[0] != '-')) {
// Consume all remaining options on the commandline.
// These remaining options are passed on to the python
// interpreter when it is loaded
if (nextarg[0] != '-')
--argndx;
app_argv = (char**)calloc(argc - argndx,sizeof(char*));
for (; argndx < argc; argndx++)
app_argv[app_argc++] = argv[argndx];
popt->start_python = 1;
} else { // invalid option
ui->error("Invalid argument (%s). -h for help\n", nextarg);
exit(1);
}
}
return popt;
}//handle_args
////////////////////////////////////////////////////////////
static void print_banner()
{
#ifdef OLD_LL
ui->fatal("\nWELCOME TO SAM [old LL] : %s\n\n", version);
#else
ui->output("\nSAM Version %s, Copyright (c) 2001-2007 Sun Microsystems, Inc.\n\n", version);
#endif
}
//////////////////////////////////////////////
//
// Wrappers for functions passed to thr_create() .
// BLAZE being compiled with IO_THREAD - TRUE
// creates separate thread for every supported disk
// as well as for SERIAL device and NETWORK ADAPTER.
// (IO_THREAD applies to DISK only)
//
//
void *
term_thread_wrapper(void * arg)
{
term_thread(arg);
return (void *) 0x0;
}
/*
* ******* the signal() system-call's effect is NOT persistent *******
* the OS resets the signal's disposition to SIG_DFL before delivery,
* and the application MUST set it back.
*/
void
sigignore_handler (int sig)
{
signal (sig, sigignore_handler); /* !!! MUST !!! */
}
void
sigconfirm_handler (int sig)
{
char response [1000];
switch (sig) {
case SIGHUP: // wait-a-minute, user can't see anything after a hang-up.?.!!.
ui->output("HANGUP received, type \"yes\" to terminate SAM:");
gets (response);
if (strcmp (response, "yes") == 0)
exit (1);
break;
case SIGINT:
ui->output("BREAK received, type \"yes\" to terminate SAM:");
gets (response);
if (strcmp (response, "yes") == 0)
exit (1);
break;
case SIGQUIT:
ui->output("CTRL-C received, type \"yes\" to terminate SAM:");
gets (response);
if (strcmp (response, "yes") == 0)
exit (1);
break;
}
signal (sig, sigconfirm_handler); /* !!! MUST !!! */
}
/* since we don't resume from these signals we dont have to restore them */
void
sigtermination_handler (int /* sig */)
{
ui->output("main/sigterm_handler calling exit...\n");
exit(1); /* execute cleanup functions registered by atexit()*/
}
void
sigcore_handler(int sig, siginfo_t *si, void *arg2)
{
uint64_t pc, npc;
struct ucontext *up = (struct ucontext *) arg2;
ui->output("\n\n");
ui->output("**********************************************\n");
ui->output("***** SAM received fatal signal, exiting *****\n");
ui->output("**********************************************\n");
ui->output("\n");
ui->output("signal %d occurred. \n", sig);
ui->output("siginfo: signo 0x%x \n", si->si_signo);
ui->output("siginfo: errno 0x%x \n", si->si_errno);
ui->output("siginfo: code 0x%x \n", si->si_code);
// how's this supposed to help, in an M-P simulator ?!.
pc = (uint64_t) up->uc_mcontext.gregs[1];
npc = (uint64_t) up->uc_mcontext.gregs[2];
ui->output("signal occurred at pc ---> 0x%llx %lld \n", pc, pc);
ui->output("signal occurred at npc ---> 0x%llx %lld \n", npc, npc);
ui->output("\n\n");
exit(1);
}
// ============================================================================
//
// HOSTINFO_ stuff...
//
int HOSTINFO_numcpus()
{
static int numcpus = 0;
if (!numcpus) {
// @@@ there's got to be a better way...???...
// @@@ this is so inefficient that we can't be re-doing this each
// @@@ time we're called...
// @@@ but that's what system-worker-threads really need...
FILE * FL = popen ("/usr/sbin/psrinfo | /bin/grep on-line | /bin/wc", "r");
char buf[100];
fgets (buf, 100, FL);
if (sscanf (buf, "%i", &numcpus) == NULL) {
ui->error("***HINFO: can nott get numcpus\n");
}
}
return numcpus;
}
// ===============================================================================
//
// Clean up overlaydir during exit, register only once when overlaydir is created
//
// ===============================================================================
void
overlaydir_cleanup()
{
if (isDir(overlaydir)) {
char *rmrf = (char*) malloc (strlen(overlaydir) + 32);
sprintf (rmrf, "rm -rf %s ", overlaydir);
int status = system (rmrf);
if (status != 0) {
const char* perr = strerror(errno);
ui->output("overlay dir cleanup: rmdir(%s) => %d (%s)\n", overlaydir, status, perr);
}
free(rmrf);
}
}