Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / system / blaze / dr.cc
// ========== Copyright Header Begin ==========================================
//
// OpenSPARC T2 Processor File: dr.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) 1991, 2001, 2005 Sun Microsystems, Inc.
* All rights reserved.
*/
#pragma ident "@(#)1.4 02/05/2002 dr.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
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <synch.h>
#include "types.h"
#include "dr.h"
#include "system.h"
#include "workerthread.h"
#include "blaze_globals.h"
#include "ui.h"
///////////////////////////////////////////////////
//
// This module is an implementation of
// BLAZE DUMP/RESTORE facility
//
///////////////////////////////////////////////////
#include "dr_impl.h"
static DR_unitNode *dr_head = NULL, *dr_tail = NULL;
static char help_string [] = "dump <directory name> - directory shouldn't exist";
static char *dr_dir = NULL;
int dump_cmd_action (void*, int argc, char **argv);
bool_t dump_blaze (DR_unit*);
bool_t restore_blaze (DR_unit*);
char ver[128] = BLAZEVERSION_STRING;
char second_ver[128] = "\0";
///////////////////////////////////////////////////
int dump_version()
{int ver_no, sub_ver_no; char blaze_ver[8];
strncpy(blaze_ver, ver ,4);
sscanf(blaze_ver, "%d.%d", &ver_no, &sub_ver_no);
return ver_no;
}
// This must be called in company with restore_v4_dump()!!
int v4_sub_version()
{int ver_no, sub_ver_no; char blaze_ver[8];
assert(restore_v4_dump());
if (handle_pseud_v4_dump())
strncpy(blaze_ver, second_ver, 4);
else
strncpy(blaze_ver, ver, 4);
sscanf(blaze_ver, "%d.%d", &ver_no, &sub_ver_no);
return sub_ver_no;
}
int sub_version()
{int ver_no, sub_ver_no; char blaze_ver[8];
strncpy(blaze_ver, ver, 4);
sscanf(blaze_ver, "%d.%d", &ver_no, &sub_ver_no);
return sub_ver_no;
}
int sub_sub_version()
{int ver_no, sub_ver_no, sub_sub_ver_no; char blaze_ver[8];
strncpy(blaze_ver, ver, 7);
sscanf(blaze_ver, "%d.%d.%d", &ver_no, &sub_ver_no, &sub_sub_ver_no);
return sub_sub_ver_no;
}
// For handling a primary V5 dump created from a restored V4 dump
bool_t handle_pseud_v4_dump()
{
if (second_ver[0] == '4')
return TRUE;
else
return FALSE;
}
bool_t restore_pure_v4_dump()
{
if (BLAZE_restore_from_checkpoint() && dump_version() == 4)
return TRUE;
else
return FALSE;
}
bool_t restore_v4_dump()
{
if (BLAZE_restore_from_checkpoint() && (dump_version() == 4 || handle_pseud_v4_dump()))
return TRUE;
else
return FALSE;
}
bool_t restore_v5_dump()
{
if (BLAZE_restore_from_checkpoint() && dump_version() >= 5)
return TRUE;
else
return FALSE;
}
// ----------------------------------------------------------------------------
//
void init_dr ()
{
//@@@ this is grotesque,
//@@@ why not call DR_register(&dump_blaze,&restore_blaze)
DR_unit *pdr;
dr_head = DR_unitNode::CreateInstance ("DR list");
dr_tail = dr_head;
if (dr_head == NULL) {
ui->error("Unable to allocate memory for DR");
return;
}
pdr = dr_head->GetData ();
pdr->dump_fn = dump_blaze; /* local ftn, calls SYSTEM_dump */
pdr->restore_fn = restore_blaze; /* local ftn, calls SYSTEM_restore */
pdr->name = (char*)strdup(BLAZE_SYSTEM);
UI_register_cmd_2 ((char*)"dump", help_string, dump_cmd_action, NULL);
}
// ----------------------------------------------------------------------------
//
// the "dump" UI command
int dump_cmd_action (void*, int argc, char **argv)
{
DR_unit *pdr;
DR_unitNode *pnode;
if (dump_version() < 5) {
ui->warning("restored from old-format (V4) dump; the new dump will be V5 format\n");
}
//** pre-dump criteria *****
if (!SYSTEM_is_stopped ()) {
ui->error("SAM must be STOPPED for dump");
return 1;
}
if (argc != 2) {
ui->error("Illegal UI command format ");
return 1;
}
if (mkdir(argv[1], S_IRWXU | S_IRWXG | S_IRWXO) == -1) {
ui->perror (argv[1]);
return 1;
}
ui->output("dump directory <%s> is created\n", argv[1]);
//** pre-dump actions *****
WorkerThread::doEventqueUnloads ();
//** now call every registered dump function *****
pdr = dr_head->GetData ();
pdr->dir = (char*)strdup(argv[1]);
dr_dir = (char*)strdup(argv[1]);
for (pnode = dr_head; pnode; pnode = pnode->Next()) {
pdr = pnode->GetData ();
if (pdr->dump_fn) {
ui->output("Dumping <%s> ...\n", pdr->name);
bool tmp = pdr->dump_fn(pdr); //*** <--- here's the action
ui->output(" %s\n",(tmp ? "done" : "failed"));
}
else {
ui->output("no dump action found for <%s> \n", pdr->name);
}
}
//** post-dump return *****
return 0;
}
// ----------------------------------------------------------------------------
//
// gets called indirectly by the above (dump_cmd_action) function
//
bool_t dump_blaze (DR_unit* pdr)
{
char cmd_line[1024];
char *dumpfile = (char*) malloc (strlen(pdr->dir) + 64);
if (dumpfile == NULL) {
ui->error("memory problems");
return FALSE;
}
sprintf(cmd_line, "cp %s %s/%s", get_script_file(), pdr->dir, RC_DUMP);
if (system(cmd_line)) {
ui->error("Script copy failed. %s!", strerror(errno));
return FALSE;
}
sprintf (dumpfile, SAM_VERSION_FILE, pdr->dir);
pdr->fp = fopen(dumpfile, "w");
if (pdr->fp == NULL) {
ui->perror (dumpfile);
return FALSE;
}
fputs (SYSTEM_get_version(), pdr->fp);
fclose (pdr->fp);
/* dump_version() < 5 means the restored V4 dump is being dumped as a V5 dump.
handle_pseud_v4_dump() means the V4 mixed V5 dump is being dumped again. */
if (dump_version() < 5 || handle_pseud_v4_dump()) {
sprintf (dumpfile, SECONDARY_VERSION_FILE, pdr->dir);
pdr->fp = fopen(dumpfile, "w");
if (pdr->fp == NULL) {
ui->perror (dumpfile);
return FALSE;
}
if (dump_version() < 5)
fputs(ver, pdr->fp);
else
fputs(second_ver, pdr->fp);
fclose (pdr->fp);
}
sprintf (dumpfile, "%s/%s.dmp", pdr->dir, pdr->name);
pdr->fp = fopen(dumpfile, "w");
if (pdr->fp == NULL) {
ui->perror (dumpfile);
return FALSE;
}
pdr->filename = (char*)strdup(dumpfile);
SYSTEM_dump (pdr->fp); //*** <--- here's the action, but this is
// only for "dump/blaze_system.dmp" !!!
fclose (pdr->fp);
return TRUE;
}
// ---------------------------------------------------------------------------
//
// gets called indirectly by ui_cmds.cc before first "run" command:
// (@@@@@ but not for "stepi", "stepc" commands ?????)
//
// -> complete_initialization
// -> restore_devices_action
// -> DR_restore_object
//
bool_t restore_blaze (DR_unit* pdr)
{
FILE *fp;
bool_t ret;
char *rfile = (char*) malloc (strlen(pdr->restore_dir) + strlen(pdr->name) + 16);
if (rfile == NULL) {
ui->error("memory problems");
return FALSE;
}
sprintf (rfile, "%s/%s.dmp", pdr->restore_dir, pdr->name);
fp = fopen(rfile, "r");
if (fp == NULL) {
ui->perror (rfile);
return FALSE;
}
ret = SYSTEM_restore (fp); //*** <--- here's the action, but this is
// only for "dump/blaze_system.dmp" !!!
fclose (fp);
return ret;
}
///////////////////////////////////////////////////
void DR_register (const char *name, dump_action dump_fn, restore_action restore_fn, void * client_data)
{
DR_unitNode *pnode = DR_unitNode::CreateInstance ("DR list");
DR_unit *pdr;
if (pnode == NULL) {
ui->error("unable to allocate memory for <%s>", name);
}
else {
pdr = pnode->GetData();
pdr->name = (char*) strdup (name);
pdr->dump_fn = dump_fn;
pdr->restore_fn = restore_fn;
pdr->client_data = client_data;
DR_unitNode::AddTail (&dr_head, &dr_tail, pnode);
}
return;
}
///////////////////////////////////////////////////
void DR_unregister (void *client_data)
{
DR_unitNode *pnode = dr_head;
DR_unitNode *prev = NULL;
while (pnode) {
DR_unit *pdr = pnode->GetData();
if (pdr->client_data == client_data) {
DR_unitNode::DeleteNode(&dr_head, prev);
prev = NULL;
pnode = dr_head;
}
else {
prev = pnode;
pnode = pnode->Next();
}
}
}
///////////////////////////////////////////////////
char * DR_get_name (DR_OPAQUE pdr)
{
return pdr->name;
}
char * DR_get_dir ()
{
return dr_dir;
}
char * DR_get_rdir (DR_OPAQUE pdr)
{
return pdr->restore_dir;
}
///////////////////////////////////////////////////
void* DR_get_client_data (DR_OPAQUE pdr)
{
return pdr->client_data;
}
///////////////////////////////////////////////////
bool_t
DR_restore_object (char * dir, char * name)
{
DR_unitNode *pnode = dr_head;
DR_unit *pdr;
bool_t ret;
ui->output("Restoring <%s> ...", name);
for (;pnode; pnode = pnode->Next()) {
pdr = pnode->GetData();
if (strcmp(pdr->name, name) == NULL) {
pdr->restore_dir = (char*)strdup(dir);
dr_dir = (char*)strdup(dir);
if (pdr->restore_fn) {
ret = pdr->restore_fn (pdr); //***
}
else {
ret = FALSE;
ui->output(" .. NO HANDLER .. ");
}
ui->output(" %s \n", ret ? "done" : "failed");
return ret;
}
}
ui->error("failed\n");
return FALSE;
}
//** if restoring, is called from UI before first "run" command
//
void restore_devices_action(char *dir)
{
DR_unit *pdr;
DR_unitNode *pnode;
for (pnode = dr_head; pnode; pnode = pnode->Next()) {
pdr = pnode->GetData ();
if (!DR_restore_object(dir, pdr->name)) //***
exit(1);
}
}