Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / devices / common / module.cc
// ========== Copyright Header Begin ==========================================
//
// OpenSPARC T2 Processor File: module.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 2004 by Sun Microsystems, Inc.
* All rights reserved.
*
* W% 06/01/25
*/
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <sys/types.h>
#include "types.h"
#include "dr.h"
#include "mmi.h"
#include "module.h"
#include "arg.h"
#include <dlfcn.h>
#include <link.h>
#define NON_V4_MOD_NUM 6
#define V4_DISTINCT 3
//extern devRegistry * samDevs;
//////////////////////////////////////////////////
// VIRTUAL FUNCTION STUBS //
// these should be implemented in each subclass //
//////////////////////////////////////////////////
// return help string
const char *
Module::get_help()
{
return MODNAME;
}
// return version string
const char *
Module::get_version()
{
return "1.00";
}
// parse an arg
bool
Module::parse_arg(const char *)
{
return false;
}
// check args for sanity
bool
Module::check_args()
{
return true;
}
// called once after blaze has initialized devices and cpu data structs
void
Module::init_done()
{
}
// called each time a new module instance has been created
void
Module::module_added(mmi_instance_t, const char*)
{
}
// called each time a new module instance has been unloaded
void
Module::module_deleted(mmi_instance_t, const char*)
{
}
// print interesting info about this module
void
Module::modinfo()
{
printf("module name <%s>, instance name <%s>\n", MODNAME, getName());
}
// return pointer to interface
void *
Module::get_interface(const char*)
{
return NULL;
}
// dump/restore
bool
Module::dump(FILE *)
{
return true;
}
bool
Module::restore(FILE *)
{
return true;
}
// stop/restart
void
Module::stop()
{
}
void
Module::restart()
{
}
// called during sysconf
void
Module::get_dev_props()
{
}
//////////////////////
// END STUB SECTION //
//////////////////////
// debug printf
void
Module::debug_err(const char *fmt, ...)
{
if (debug_level >= 0) {
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
}
}
void
Module::debug_info(const char *fmt, ...)
{
if (debug_level >= 1) {
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
}
}
void
Module::debug_more(const char *fmt, ...)
{
if (debug_level >= 2) {
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
}
}
// generate "module:file(Lnn)" for debug output
const char *
Module::_here(const char *f, int n)
{
const char *p = strrchr(f, '/');
snprintf(herebuf, sizeof herebuf, "%s:%s(L%d)", getName(), p?(p+1):f, n);
return herebuf;
}
// dump/restore
static mmi_bool_t module_dump_restore(Module * module, const char * file_name, bool isDump)
{
FILE *fp;
bool rc = false;
char *non_v4_mod[NON_V4_MOD_NUM] = {"excalibur", "pci_bus", "bi", "rtc", "scsi", "fc"};
char fn[PATH_MAX], *ptr, *v4_distinct_name[V4_DISTINCT] = {"schizo", "serial", "ll"};
fn[0] = '\0';
// comment out when testing hh/parrot v5 modules with v4 blaze
if (restore_pure_v4_dump() && !isDump) {
for (int i = 0; i < NON_V4_MOD_NUM; i ++)
if (!strcmp(module->get_mod_name(), non_v4_mod[i]))
return mmi_true;
for (int i = 0; i < V4_DISTINCT; i ++)
if (!strcmp(module->get_mod_name(), v4_distinct_name[i])) {
strcpy(fn, file_name);
ptr = (char *)strrchr(fn, '/') + 1;
*ptr = '\0';
strcat((char *)fn, v4_distinct_name[i]);
strcat((char *)fn, ".dmp");
fp = fopen(fn, "r");
break;
}
}
if (!fn[0])
fp = fopen (file_name, isDump ? "w" : "r");
if (fp) {
rc = isDump ? module->dump(fp) : module->restore(fp);
fclose (fp);
}
if (!rc) {
if (fn[0])
perror(fn);
else
perror(file_name);
}
return (mmi_bool_t)rc;
}
static mmi_bool_t module_dump(void * mydata, const char * file_name)
{
return module_dump_restore((Module *)mydata, file_name, true);
}
static mmi_bool_t module_restore(void * mydata, const char * file_name)
{
return module_dump_restore((Module *)mydata, file_name, false);
}
// stop/restart
extern "C" static void module_stop(void *ptr)
{
Module *module = (Module *) ptr;
module->stop();
}
extern "C" static void module_restart(void *ptr)
{
Module *module = (Module *) ptr;
module->restart();
}
// parse sysconf args
static void module_parse_args(Module *module, mmi_instance_t instance, bool allargs)
{
int argc = mmi_argc(instance);
for (int i = 0; i < argc; i++) {
char *arg = mmi_argv(instance, i);
if (!strncmp("-d", arg, 2)) { // debug_level: -d#
module->debug_level = (int) strtol(&arg[2], NULL, 0);
} else if (allargs && !module->parse_arg(arg))
module->debug_err("%s: WARNING: Ignoring arg '%s'\n", module->HERE, arg);
}
}
// config callback
extern "C" static void module_reconfig(void *cb_data, mmi_instance_t target, const char *target_name, mmi_config_t ev)
{
Module *module = (Module*)cb_data;
if (target == module->getInstance()) {
if (ev == MMI_CONFIG_DELETE_MODULE)
delete module;
else if (ev == MMI_CONFIG_INIT_DONE)
module->init_done();
} else if (ev == MMI_CONFIG_NEW_MODULE) {
module->module_added(target, target_name);
} else if (ev == MMI_CONFIG_DELETE_MODULE) {
module->module_deleted(target, target_name);
}
}
// callback to retrieve module information
extern "C" static void module_get_modinfo (mmi_instance_t instance)
{
Module *module = (Module *) instance;
module->modinfo();
}
// interface callback
extern "C" static void *module_get_interface(void *cb_data, const char *name)
{
Module *module = (Module *)cb_data;
if (!strcmp(name, MODULE_INTERFACE))
return module;
return module->get_interface(name);
}
// constructor
Module::Module(const char *_modname, const char *_instance_name)
: debug_level(0)
{
instance_name = makestr(_instance_name, instance_name);
modname = makestr(_modname, modname);
instance = mmi_get_instance(instance_name);
memset(herebuf, 0, sizeof herebuf);
module_parse_args(this, instance, false);
debug_more("%s: constructor\n", HERE);
mmi_register_start_stop (module_restart, module_stop, (void*)this);
mmi_register_dump_restore(getName(), module_dump, module_restore, (void*)this);
plist = new property_list();
if(mySamDevPtr = (devRegistry**)dlsym(RTLD_DEFAULT,"samDevs")){
samId = (*mySamDevPtr)->registerDev(this);
}else{
samId = -1;
}
}
// destructor
Module::~Module()
{
debug_more("%s: destructor\n", getName());
if (instance_name) {
free((void*)instance_name);
}
if (modname) {
free((void*)modname);
}
}
// called during ldm and sysconf, after _init
extern "C" static void module_create_instance(const char *modname, const char *instance_name)
{
Module *module = Module::create(modname, instance_name);
if (!module) {
fprintf(stderr, "%s: Could not create <%s>\n", MODNAME, instance_name);
} else {
mmi_instance_t instance = mmi_register_instance(modname, instance_name, (void*)module, Module::get_help_string());
if (!instance) {
fprintf(stderr, "%s: Could not register <%s>\n", MODNAME,instance_name);
} else {
#if 0
fprintf(stderr, "mmi_register_instance %s 0x%llx, data 0x%llx \n", instance_name, instance, (void*)module);
#endif
module_parse_args(module, instance, true);
module->debug_more("%s: modname <%s> instance_name <%s>\n", MODNAME, modname, instance_name);
module->debug_info("%s: Version <%s>\n",MODNAME,module->get_version());
if (!module->check_args()) {
fprintf (stderr, "%s: Could not create object for <%s>\n", MODNAME,instance_name);
} else {
mmi_register_modinfo_cb(instance, module_get_modinfo);
mmi_register_interface_cb(instance, module_get_interface);
mmi_register_config_cb(instance, module_reconfig);
}
}
}
}
// The _init() and _fini() routines are only needed when we compile
// a module into a .so. In case a module is linked statically to
// another module (.so) we get multiple defined _init() and _inif()
// routines. Currently modules for cosim are all linked statically.
// MODULE_STATIC_LINKAGE excludes _init() and _fini() when defined.
#ifndef MODULE_STATIC_LINKAGE
// module init, called during dlopen
extern "C" void _init()
{
if (! mmi_register_instance_creator (MODNAME, module_create_instance )) {
fprintf (stderr, "%s: Failed to load\n", MODNAME);
}
}
// called by dlclose during uldm and exit
extern "C" void _fini()
{
}
#endif