summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/build/debug/Hostboot/CallFunc.pm159
-rwxr-xr-xsrc/build/debug/Hostboot/_DebugFramework.pm149
-rwxr-xr-xsrc/build/debug/simics-debug-framework.pl37
-rwxr-xr-xsrc/build/debug/simics-debug-framework.py52
-rwxr-xr-xsrc/build/simics/hb-simdebug.py97
-rw-r--r--src/include/kernel/cpumgr.H7
-rw-r--r--src/include/kernel/idebug.H85
-rw-r--r--src/include/kernel/taskmgr.H9
-rw-r--r--src/kernel/cpumgr.C8
-rw-r--r--src/kernel/exception.C4
-rw-r--r--src/kernel/idebug.C89
-rw-r--r--src/kernel/kernel.C2
-rw-r--r--src/kernel/makefile2
-rw-r--r--src/kernel/taskmgr.C12
-rw-r--r--src/makefile2
15 files changed, 652 insertions, 62 deletions
diff --git a/src/build/debug/Hostboot/CallFunc.pm b/src/build/debug/Hostboot/CallFunc.pm
new file mode 100644
index 000000000..69cf0130b
--- /dev/null
+++ b/src/build/debug/Hostboot/CallFunc.pm
@@ -0,0 +1,159 @@
+use strict;
+
+package Hostboot::CallFunc;
+use Exporter;
+our @EXPORT_OK = ('main');
+
+use constant CALLFUNC_DEBUG_READY_OFFSET => 0;
+use constant CALLFUNC_DEBUG_RUNNING_OFFSET => CALLFUNC_DEBUG_READY_OFFSET + 1;
+use constant CALLFUNC_DEBUG_COMPLETE_OFFSET => CALLFUNC_DEBUG_READY_OFFSET + 2;
+use constant CALLFUNC_DEBUG_ENTRY_OFFSET => CALLFUNC_DEBUG_READY_OFFSET + 8;
+use constant CALLFUNC_DEBUG_RETVAL_OFFSET => CALLFUNC_DEBUG_ENTRY_OFFSET + 8;
+use constant CALLFUNC_DEBUG_PARMS_OFFSET => CALLFUNC_DEBUG_RETVAL_OFFSET + 8;
+use constant CALLFUNC_DEBUG_PARMS => 8;
+sub main
+{
+ my ($packName,$args) = @_;
+
+ # Parse 'debug' option.
+ my $debug = 0;
+ if (defined $args->{"debug"})
+ {
+ $debug = 1;
+ }
+
+ # Parse function name from options.
+ my $function = "";
+ if (defined $args->{"function"})
+ {
+ $function = $args->{"function"};
+ }
+ elsif (defined $args->{"func"})
+ {
+ $function = $args->{"func"};
+ }
+ else
+ {
+ ::userDisplay "Must give a function to execute.\n";
+ return;
+ }
+
+ # Parse function arguments from options.
+ my @parms = ();
+ my $parms_string = "";
+ if (defined $args->{"arguments"})
+ {
+ $parms_string = $args->{"arguments"}
+ }
+ elsif (defined $args->{"args"})
+ {
+ $parms_string = $args->{"args"};
+ }
+ elsif (defined $args->{"parameters"})
+ {
+ $parms_string = $args->{"parameters"};
+ }
+ elsif (defined $args->{"parms"})
+ {
+ $parms_string = $args->{"parms"};
+ }
+ @parms = map eval, split /,/, $parms_string;
+
+ # Parse 'force' argument.
+ my $force = 0;
+ if (defined $args->{"force"})
+ {
+ $force = 1;
+ }
+
+
+ # Ensure environment is in the proper state for running instructions.
+ if (!::readyForInstructions())
+ {
+ ::userDisplay "Cannot execute while unable to run instructions.\n";
+ return;
+ }
+
+ # Find symbol's TOC address.
+ my $toc = ::findSymbolTOCAddress($function);
+ if ($debug)
+ {
+ ::userDisplay("Symbol $function TOC at $toc.\n");
+ }
+
+ # Find interactive debug structure in the kernel.
+ my $address = (::findSymbolAddress("CpuManager::cv_interactive_debug"))[0];
+
+ if ((not defined $toc) || (not defined $address))
+ {
+ ::userDisplay "Cannot find symbol to execute $function.\n";
+ return;
+ }
+
+ # Verify kernel isn't busy with an outstanding request.
+ if ((0 != ::read16 ($address + CALLFUNC_DEBUG_READY_OFFSET)) &&
+ (0 == $force))
+ {
+ ::userDisplay "Another command is still pending.\n";
+ return;
+ }
+
+ # Write entry point (function TOC) and parameters into debug structure.
+ ::write64(($address + CALLFUNC_DEBUG_ENTRY_OFFSET), $toc);
+ while(($#parms + 1) != CALLFUNC_DEBUG_PARMS)
+ {
+ push @parms, 0x0;
+ }
+ my $i = 0;
+ while ($i != CALLFUNC_DEBUG_PARMS)
+ {
+ if ($debug)
+ {
+ ::userDisplay "Param $i = ".$parms[$i]."\n";
+ }
+ ::write64(($address + CALLFUNC_DEBUG_PARMS_OFFSET + 8*$i), $parms[$i]);
+ $i = $i + 1;
+ }
+
+ # Set ready state.
+ ::write32(($address + CALLFUNC_DEBUG_READY_OFFSET), 0x01000000);
+
+ # Clock forward until kernel marks 'complete' state.
+ my $i = 0;
+ while((0 != ::read16($address + CALLFUNC_DEBUG_READY_OFFSET)) &&
+ (0 == ::read8($address + CALLFUNC_DEBUG_COMPLETE_OFFSET)) &&
+ ($i < 50))
+ {
+ ::executeInstrCycles(100000);
+ $i = $i + 1;
+ if ($debug)
+ {
+ ::userDisplay("Loop $i.\n");
+ }
+ }
+
+ # Verify successful execution ('complete' state set).
+ if (0 == ::read8($address + CALLFUNC_DEBUG_COMPLETE_OFFSET))
+ {
+ ::userDisplay "Command failed to complete.\n";
+ return;
+ }
+
+ # Display return value.
+ ::userDisplay ::read64($address + CALLFUNC_DEBUG_RETVAL_OFFSET)."\n";
+}
+
+sub help
+{
+ ::userDisplay "Tool: CallFunc\n";
+ ::userDisplay "\tInteractively execute a function.\n";
+ ::userDisplay "\n Options:\n";
+ ::userDisplay "\tfunction='function name' - Function to execute.\n";
+ ::userDisplay "\targuments=arg0,arg1... - List of arguments to pass.\n";
+ ::userDisplay "\tforce - Run command even if state doesn't not appear ".
+ "correct.\n";
+ ::userDisplay "\n\tfunc can be used as a short-name for 'function'.\n";
+ ::userDisplay "\targs, parameters, or parms can be used as a short-name ";
+ ::userDisplay "for arguments.\n";
+}
+
diff --git a/src/build/debug/Hostboot/_DebugFramework.pm b/src/build/debug/Hostboot/_DebugFramework.pm
index a55794ebc..fd62127bf 100755
--- a/src/build/debug/Hostboot/_DebugFramework.pm
+++ b/src/build/debug/Hostboot/_DebugFramework.pm
@@ -44,13 +44,16 @@ use Exporter 'import';
our @EXPORT = ( 'callToolModule', 'callToolModuleHelp',
'parseToolOpts', 'determineImagePath',
- 'findSymbolAddress', 'findSymbolByAddress',
+ 'findSymbolAddress', 'findSymbolTOCAddress',
+ 'findSymbolByAddress',
'findModuleByAddress',
'littleendian',
- 'read64', 'read32', 'read16', 'read8', 'readStr'
+ 'read64', 'read32', 'read16', 'read8', 'readStr',
+ 'write64', 'write32', 'write16', 'write8'
);
-our ($parsedSymbolFile, %symbolAddress, %addressSymbol, %symbolSize);
+our ($parsedSymbolFile, %symbolAddress, %symbolTOC,
+ %addressSymbol, %symbolSize);
our ($parsedModuleFile, %moduleAddress);
our (%toolOpts);
@@ -58,6 +61,7 @@ BEGIN
{
$parsedSymbolFile = 0;
%symbolAddress = ();
+ %symbolTOC = ();
%addressSymbol = ();
%symbolSize = ();
@@ -109,18 +113,50 @@ sub callToolModuleHelp
#
# Parses a space deliminated string of options for use by the tool.
#
+# Allows an option to contain spaces itself by wrapping the value in a
+# single quote.
+#
# @param string - Tool option list.
#
-# Example: "foo bar=/abcd/efg" --> { "foo" => 1 , "bar" => "/abcd/efg" }
+# Example:
+# "foo bar=/abcd/efg" --> { "foo" => 1 , "bar" => "/abcd/efg" }
+# "foo='bar nil'" --> { "foo" => "bar nil" }
#
sub parseToolOpts
{
my $toolOptions = shift;
+ my $partial = "";
foreach my $opt (split / /, $toolOptions)
{
+ # Search for a single-quoted word in the option string.
+ if (($opt =~ m/'/) and (not ($opt =~ m/'.*'/)))
+ {
+ # If partial is not empty, this single-quote terminates the string.
+ if ($partial ne "")
+ {
+ $opt = $partial." ".$opt;
+ $partial = "";
+ }
+ # Otherwise, append it to the partial string.
+ else
+ {
+ $partial = $opt;
+ next;
+ }
+ }
+ # Append a word to a partially completed string in progress.
+ elsif ($partial ne "")
+ {
+ $partial = $partial." ".$opt;
+ next;
+ }
+
+ # At this point "opt" is either a free-standing argument set or a
+ # fully complete single-quote deliminated string.
if ($opt =~ m/=/)
{
my ($name,$value) = split /=/, $opt;
+ $value =~ s/^'([^']*)'$/$1/; # Trim out the 's.
$toolOpts{$name} = $value;
}
else
@@ -185,11 +221,26 @@ sub parseSymbolFile
my $addr = hex $2;
my $tocAddr = hex $3;
my $size = hex $4;
+ my $type = $1;
- $symbolAddress{$name} = $addr;
- $symbolSize{$name} = $size;
$addressSymbol{$addr} = $name;
$addressSymbol{$tocAddr} = $name;
+
+ # Use only the first definition of a symbol.
+ # This is useful for constructors where we only want to call the
+ # 'in-charge' version of the constructor.
+ if (defined $symbolAddress{$name})
+ {
+ next;
+ }
+
+ $symbolAddress{$name} = $addr;
+ if ($type eq "F")
+ {
+ $symbolTOC{$name} = $tocAddr;
+ }
+ $symbolSize{$name} = $size;
+
}
close(FILE);
@@ -212,6 +263,21 @@ sub findSymbolAddress
return ($symbolAddress{$name}, $symbolSize{$name} );
}
+# @sub findSymbolTOCAddress
+# Searches a syms file for the address of the TOC of a symbol.
+#
+# @param string - Symbol to search for.
+# @return TOC address or 'not-defined'.
+#
+sub findSymbolTOCAddress
+{
+ my $name = shift;
+
+ parseSymbolFile();
+
+ return $symbolTOC{$name};
+}
+
# @sub findSymbolByAddress
#
# Searchs a syms file for the symbol name at a particular address.
@@ -393,4 +459,75 @@ sub readStr
return $result;
}
+# @sub write64
+#
+# Write a 64-bit unsigned integer to an address.
+#
+# @param Address to write to.
+# @param Value to write
+#
+sub write64
+{
+ my $addr = shift;
+ my $value = shift;
+
+ $value = pack("Q", $value);
+ if (littleendian()) { $value = reverse($value); }
+
+ my $result = ::writeData($addr, 8, $value);
+}
+
+# @sub write32
+#
+# Write a 32-bit unsigned integer to an address.
+#
+# @param Address to write to.
+# @param Value to write
+#
+sub write32
+{
+ my $addr = shift;
+ my $value = shift;
+
+ $value = pack("L", $value);
+ if (littleendian()) { $value = reverse($value); }
+
+ my $result = ::writeData($addr, 4, $value);
+}
+
+# @sub write16
+#
+# Write a 16-bit unsigned integer to an address.
+#
+# @param Address to write to.
+# @param Value to write
+#
+sub write16
+{
+ my $addr = shift;
+ my $value = shift;
+
+ $value = pack("S", $value);
+ if (littleendian()) { $value = reverse($value); }
+
+ my $result = ::writeData($addr, 2, $value);
+}
+
+# @sub write8
+#
+# Write a 8-bit unsigned integer to an address.
+#
+# @param Address to write to.
+# @param Value to write
+#
+sub write8
+{
+ my $addr = shift;
+ my $value = shift;
+
+ $value = pack("C", $value);
+
+ my $result = ::writeData($addr, 1, $value);
+}
+
__END__
diff --git a/src/build/debug/simics-debug-framework.pl b/src/build/debug/simics-debug-framework.pl
index a255439a9..90a7822a9 100755
--- a/src/build/debug/simics-debug-framework.pl
+++ b/src/build/debug/simics-debug-framework.pl
@@ -106,6 +106,43 @@ sub readData
return "";
}
+# @sub writeData
+# @brief Send a 'write-data' type message to Python.
+sub writeData
+{
+ my $addr = shift;
+ my $size = shift;
+ my $value = shift;
+
+ my $value = unpack("H*", $value);
+ sendIPCMsg("write-data", "$addr,$size,$value");
+
+ return;
+}
+
+# @sub executeInstrCycles
+# @brief Send a 'execute-instrs' type message to Python.
+sub executeInstrCycles
+{
+ my $cycles = shift;
+ sendIPCMsg("execute-instrs", "$cycles");
+}
+
+# @sub readyForInstructions
+# @brief Send a 'ready-for-instr' type message to Python.
+# @returns 0 - Not ready or 1 - Ready
+sub readyForInstructions
+{
+ sendIPCMsg("ready-for-instr", "");
+
+ my ($type, $data) = recvIPCMsg();
+ if ("1" eq $data)
+ {
+ return 1;
+ }
+ return 0;
+}
+
# Image path global.
my $imgPath = "";
sub getImgPath
diff --git a/src/build/debug/simics-debug-framework.py b/src/build/debug/simics-debug-framework.py
index 9cbfe8090..dcd05cee1 100755
--- a/src/build/debug/simics-debug-framework.py
+++ b/src/build/debug/simics-debug-framework.py
@@ -86,17 +86,19 @@ class DebugFrameworkProcess:
process = ""; # subprocess object.
tool = ""; # string - tool module name.
toolOptions = ""; # string - tool options
- usage = None; # mode - Usage output instead of Execution.
+ outputToString = None; # mode - String output instead of STDOUT.
imgPath = "./"; # Image dir path override.
result = ""; # Result string for Usage-mode.
outputFile = None; # Output file for results in addition to STDOUT
def __init__(self, tool = "Printk", toolOptions = "",
- usage = None, imgPath = "./",outputFile = None):
+ outputToString = None, usage = None,
+ imgPath = "./",outputFile = None):
# Determine sub-process arguments.
process_args = ["./simics-debug-framework.pl"];
if (usage): # Pass --usage if Usage mode selected.
process_args = process_args + [ "--usage" ];
+ outputToString = True;
# Spawn sub-process
self.process = subprocess.Popen(process_args,
@@ -104,7 +106,7 @@ class DebugFrameworkProcess:
# Update instance variables.
self.tool = tool;
self.toolOptions = toolOptions;
- self.usage = usage;
+ self.outputToString = outputToString;
self.imgPath = imgPath;
self.outputFile = open(outputFile, 'w') if outputFile else None;
@@ -129,7 +131,7 @@ class DebugFrameworkProcess:
# Display string (or save to result in Usage mode).
def display(self,data):
- if (self.usage):
+ if (self.outputToString):
self.result += data
else:
print data,
@@ -137,10 +139,10 @@ class DebugFrameworkProcess:
print >>self.outputFile,data,
# Read data from memory.
- # This message has data of the format "0xADDRESS,0xSIZE".
+ # This message has data of the format "0dADDRESS,0dSIZE".
def read_data(self,data):
pattern = re.compile("([0-9]+),([0-9]+)")
- match = pattern.search(data);
+ match = pattern.search(data)
addr = int(match.group(1))
size = int(match.group(2))
@@ -148,6 +150,32 @@ class DebugFrameworkProcess:
data = "".join(map(chr, conf.phys_mem.memory[[addr , addr+size-1]]))
self.sendMsg("data-response", data)
+ # Write data to memory.
+ # This message has data of the format "0dADDR,0dSIZE,hDATA".
+ def write_data(self,data):
+ pattern = re.compile("([0-9]+),([0-9]+),([0-9A-Fa-f]+)")
+ match = pattern.search(data)
+
+ addr = int(match.group(1))
+ size = int(match.group(2))
+ data = map(ord, match.group(3).decode("hex"));
+
+ conf.phys_mem.memory[[addr, addr+size-1]] = data;
+
+ # Clock forward the model.
+ # This message had data of the format "0dCYCLES".
+ def execute_instrs(self,data):
+ pattern = re.compile("([0-9]+)")
+ match = pattern.search(data)
+
+ cycles = int(match.group(1))
+
+ if (not SIM_simics_is_running()):
+ SIM_continue(cycles)
+
+ def ready_for_instr(self,data):
+ self.sendMsg("data-response", "0" if SIM_simics_is_running() else "1")
+
# Get tool module name.
def get_tool(self,data):
self.sendMsg("data-response", self.tool)
@@ -168,15 +196,20 @@ class DebugFrameworkProcess:
# @param usage - Usage mode or Execute mode.
# @param imgPath - Image path override.
def run_hb_debug_framework(tool = "Printk", toolOpts = "",
- usage = None, imgPath = "./", outputFile = None):
+ outputToString = None, usage = None,
+ imgPath = "./", outputFile = None):
# Create debug sub-process.
- fp = DebugFrameworkProcess(tool,toolOpts,usage,imgPath,outputFile)
+ fp = DebugFrameworkProcess(tool,toolOpts,outputToString,
+ usage,imgPath,outputFile)
# Read / handle messages until there are no more.
msg = fp.recvMsg()
while msg[0] != "":
operations = { "display" : DebugFrameworkProcess.display,
"read-data" : DebugFrameworkProcess.read_data,
+ "write-data" : DebugFrameworkProcess.write_data,
+ "execute-instrs" : DebugFrameworkProcess.execute_instrs,
+ "ready-for-instr" : DebugFrameworkProcess.ready_for_instr,
"get-tool" : DebugFrameworkProcess.get_tool,
"get-tool-options" : DebugFrameworkProcess.get_tool_options,
"get-img-path" : DebugFrameworkProcess.get_img_path,
@@ -186,10 +219,11 @@ def run_hb_debug_framework(tool = "Printk", toolOpts = "",
msg = fp.recvMsg()
# If in Usage mode, return result string.
- if (usage):
+ if (usage or outputToString):
return fp.result
return None
+
# @fn register_hb_debug_framework_tools
# @brief Create a simics command wrapper for each debug tool module.
def register_hb_debug_framework_tools():
diff --git a/src/build/simics/hb-simdebug.py b/src/build/simics/hb-simdebug.py
index 0119eb531..4a5e690bc 100755
--- a/src/build/simics/hb-simdebug.py
+++ b/src/build/simics/hb-simdebug.py
@@ -72,18 +72,18 @@ def print_istep_list( inList ):
print "-----------------------------------------------------------"
print " Supported ISteps: "
print " IStep\tSubStep\tStepName "
- print "-----------------------------------------------------------"
+ print "-----------------------------------------------------------"
## print len(inList)
for i in range(0,len(inList)) :
##print len(inList[i])
for j in range( 0, len(inList[i])) :
print "%d\t%d\t%s"%( i, j, inList[i][j] )
-
+
return None
-# normally this would be a loop to watch for the runningbit.
+# normally this would be a loop to watch for the runningbit.
# currently simics dumps all sorts of error lines every time a SCOM is
# read, so HostBoot only updates every 1 sec. at that rate we only
# need to sleep for 2 sec and we are sure to get it.
@@ -91,17 +91,17 @@ def print_istep_list( inList ):
def getStatusReg():
##StatusStr = "salerno_chip.regdump SCOM 0x13012685"
## -f <file> dumps the output to <file>_SCOM_0X13012685
- ## StatusStr = "salerno_chip.regdump SCOM 0x13012685 -f ./scom.out"
- StatusStr = "cpu0_0_0_2->scratch"
-
+ ## StatusStr = "salerno_chip.regdump SCOM 0x13012685 -f ./scom.out"
+ StatusStr = "cpu0_0_0_2->scratch"
+
## get response
# (result, statusOutput) = quiet_run_command( StatusStr, output_modes.regular )
result = conf.cpu0_0_0_2.scratch
- print "0x%x"%(result)
+ print "0x%x"%(result)
hiword = ( ( result & 0xffffffff00000000) >> 32 )
loword = ( result & 0x00000000ffffffff )
-
+
return (hiword, loword)
@@ -131,23 +131,23 @@ def runIStep( istep, substep, inList ):
# result = run_command( "stop" )
(hiword, loword) = getStatusReg()
-
+
runningbit = ( ( hiword & 0x80000000 ) >> 31 )
- readybit = ( ( hiword & 0x40000000 ) >> 30 )
+ readybit = ( ( hiword & 0x40000000 ) >> 30 )
stsIStep = ( ( hiword & 0x3fff0000 ) >> 16 )
stsSubstep = ( ( hiword & 0x0000ffff ) )
-
+
taskStatus = ( ( loword & 0xffff0000 ) >> 16 )
- istepStatus = ( ( loword & 0x0000ffff ) )
- print
+ istepStatus = ( ( loword & 0x0000ffff ) )
+ print
print "%s : returned Status 0x%8.8x_%8.8x : "%( inList[istep][substep], hiword, loword )
print "runningbit = 0x%x, readybit=0x%x"%(runningbit, readybit)
print "Istep 0x%x / Substep 0x%x Status: 0x%x 0x%x"%( stsIStep, stsSubstep, taskStatus, istepStatus )
- print "-----------------------------------------------------------------"
-
+ print "-----------------------------------------------------------------"
+
# result = run_command( "run" )
-
-## run command = "sN"
+
+## run command = "sN"
def sCommand( inList, scommand ) :
i = int(scommand)
j = 0
@@ -192,12 +192,12 @@ def istepHB( str_arg1, inList):
(result, out) = quiet_run_command(IStepModeStr, output_modes.regular )
# print result
return
-
+
if ( str_arg1 == "normalmode" ): ## set Normal Mode in SCOM reg
print "Set Normal Mode"
(result, out) = quiet_run_command(NormalModeStr, output_modes.regular )
# print result
- return
+ return
## check to see if we have an 's' command (string starts with 's')
if ( str_arg1.startswith('s') ):
@@ -214,7 +214,7 @@ def istepHB( str_arg1, inList):
for x in range( (int(M,16)), (int(N,16)+1) ) :
sCommand( inList, x )
return
- else:
+ else:
## substep name
## (ss_nameM, ss_nameN) = str_arg1.split("..")
namelist = str_arg1.split("..")
@@ -224,12 +224,12 @@ def istepHB( str_arg1, inList):
print "Invalid substep %s"%( namelist[0] )
return
runIStep( istepM, substepM, inList )
- else:
- ## substep name .. substep name
+ else:
+ ## substep name .. substep name
(istepM, substepM, foundit) = find_in_inList( inList, namelist[0] )
if ( not foundit ) :
print "Invalid substep %s"%( namelist[0] )
- return
+ return
(istepN, substepN, foundit) = find_in_inList( inList, namelist[1] )
if ( not foundit ) :
print( "Invalid substep %s"%( namelist[1]) )
@@ -237,7 +237,7 @@ def istepHB( str_arg1, inList):
for x in range( istepM, istepN+1 ) :
for y in range( substepM, substepN+1) :
runIStep( x, y, inList )
- return
+ return
#===============================================================================
@@ -334,19 +334,19 @@ def hb_istep(str_arg1):
[ "na" ], ## istep 2
[ "na" ], ## istep 3
[ "init_target_states", ## istep 4
- "init_fsi",
- "apply_fsi_info",
- "apply_dd_presence",
+ "init_fsi",
+ "apply_fsi_info",
+ "apply_dd_presence",
"apply_pr_keyword_data",
"apply_partial_bad",
"apply_gard",
"testHWP"
],
- ]
-
- ## print flag_t
-
- if str_arg1 == None:
+ ]
+
+ ## print flag_t
+
+ if str_arg1 == None:
print_istep_list( inList )
else:
print "args=%s" % str(str_arg1)
@@ -420,3 +420,36 @@ new_command("hb-singlethread",
alias = "hb-st",
type = ["hostboot-commands"],
short = "Disable all threads except cpu0_0_0_0.")
+
+
+#------------------------------------------------
+#------------------------------------------------
+new_command("hb-callfunc",
+ (lambda function, args:
+ eval(run_hb_debug_framework("CallFunc",
+ ("function='"+function+"' arguments="+
+ (",".join(map(str, args)))),
+ outputToString = 1))),
+ [
+ arg(str_t, "function"),
+ arg(list_t, "args", "?", [])
+ ],
+ type = ["hostboot-commands"],
+ see_also = ["hb-debug-CallFunc"],
+ short = "Interactively call a hostboot function.",
+ doc = """
+Parameters: \n
+ function = Function to execute.\n
+ args = List of arguments.\n
+
+Defaults: \n
+ args = [0]\n
+
+Examples: \n
+ hb-callfunc "malloc" [8]\n
+ hb-callfunc "free" [0x1234]\n
+
+Note:
+ This function may only be called with simics stopped.
+ """)
+
diff --git a/src/include/kernel/cpumgr.H b/src/include/kernel/cpumgr.H
index 78ade4ae3..1499fba98 100644
--- a/src/include/kernel/cpumgr.H
+++ b/src/include/kernel/cpumgr.H
@@ -26,12 +26,13 @@
#include <kernel/types.h>
#include <kernel/cpu.H>
#include <kernel/barrier.H>
+#include <kernel/idebug.H>
class CpuManager
{
public:
- enum
- {
+ enum
+ {
MAXCPUS = KERNEL_MAX_SUPPORTED_CPUS,
CPU_PERIODIC_CHECK_MEMORY = 64,
CPU_PERIODIC_FLUSH_PAGETABLE = 512, //TODO 1024 not currently hit
@@ -105,6 +106,8 @@ class CpuManager
// The status code that needs to be posted during shutdown
static uint64_t cv_shutdown_status;
+
+ static InteractiveDebug cv_interactive_debug;
};
#endif
diff --git a/src/include/kernel/idebug.H b/src/include/kernel/idebug.H
new file mode 100644
index 000000000..584dacf80
--- /dev/null
+++ b/src/include/kernel/idebug.H
@@ -0,0 +1,85 @@
+// IBM_PROLOG_BEGIN_TAG
+// This is an automatically generated prolog.
+//
+// $Source: src/include/kernel/idebug.H $
+//
+// IBM CONFIDENTIAL
+//
+// COPYRIGHT International Business Machines Corp. 2011
+//
+// p1
+//
+// Object Code Only (OCO) source materials
+// Licensed Internal Code Source Materials
+// IBM HostBoot Licensed Internal Code
+//
+// The source code for this program is not published or other-
+// wise divested of its trade secrets, irrespective of what has
+// been deposited with the U.S. Copyright Office.
+//
+// Origin: 30
+//
+// IBM_PROLOG_END
+#ifndef __KERNEL_IDEBUG_H
+#define __KERNEL_IDEBUG_H
+
+/** @file idebug.H
+ * @brief Structure for interactive debug support.
+ */
+
+#include <kernel/types.h>
+#include <kernel/taskmgr.H>
+
+/** @class InteractiveDebug
+ * @brief Structure that defines data needed for an interactive-debug call.
+ */
+class InteractiveDebug
+{
+ public:
+ /** Union to contain the state information between the kernel and
+ * the debug tool.
+ */
+ union
+ {
+ struct
+ {
+ /** Boolean for 'ready' state. */
+ uint8_t ready;
+ /** Boolean to mark kernel running request. */
+ uint8_t running;
+ /** Boolean to mark execution is complete. */
+ uint8_t complete;
+ uint8_t __reserved[5];
+ };
+ /** Word so that state can be atomically updated. */
+ uint64_t state_value;
+ };
+
+ /** Address of the desired function's TOC. */
+ uint64_t entry_point_toc;
+ /** Return value from function. */
+ uint64_t return_value;
+
+ /** Desired function parameters. */
+ uint64_t parms[8];
+
+ /** @brief Returns the 'ready' state from the union. */
+ bool isReady() { return ready != 0; };
+
+ /** @brief Creates a userspace task to execute debug call.
+ *
+ * @pre 'ready' state set and entry_point/parms are initialized by
+ * the debug tool.
+ *
+ * @post A detached task is created to execute the function.
+ */
+ void startDebugTask();
+
+ private:
+ /** @brief Entry point for 'task_create' of debug task.
+ * @param[in] idebug - Pointer to this interactive-debug structure.
+ */
+ static void debugEntryPoint(void* idebug);
+};
+
+#endif
diff --git a/src/include/kernel/taskmgr.H b/src/include/kernel/taskmgr.H
index 8f1deb264..63aa76484 100644
--- a/src/include/kernel/taskmgr.H
+++ b/src/include/kernel/taskmgr.H
@@ -21,7 +21,7 @@
//
// IBM_PROLOG_END
#ifndef __KERNEL_TASKMGR_H
-#define __KENREL_TASKMGR_H
+#define __KERNEL_TASKMGR_H
#include <kernel/types.h>
#include <util/lockfree/counter.H>
@@ -114,8 +114,11 @@ class TaskManager
*
* @param[in] t - The entry point to start the task at.
* @param[in] p - An argument pointer to pass to the task.
+ * @param[in] kernelParent - Should the kernel be assigned the parent
+ * of the new task.
*/
- static task_t* createTask(task_fn_t t, void* p);
+ static task_t* createTask(task_fn_t t, void* p,
+ bool kernelParent = false);
/** @brief End / destroy a task object.
*
@@ -156,7 +159,7 @@ class TaskManager
// Internal implementations of non-static / non-_ functions.
task_t* _createIdleTask();
- task_t* _createTask(task_fn_t, void*, bool);
+ task_t* _createTask(task_fn_t, void*, bool, bool);
void _endTask(task_t*, void*, int);
void _waitTask(task_t*, int64_t, int*, void**);
diff --git a/src/kernel/cpumgr.C b/src/kernel/cpumgr.C
index 6ec3b9f6d..626ad7f84 100644
--- a/src/kernel/cpumgr.C
+++ b/src/kernel/cpumgr.C
@@ -42,11 +42,14 @@ uint64_t CpuManager::cv_shutdown_status = 0;
Barrier CpuManager::cv_barrier;
bool CpuManager::cv_defrag = false;
size_t CpuManager::cv_cpuCount = 0;
+InteractiveDebug CpuManager::cv_interactive_debug;
CpuManager::CpuManager()
{
for (int i = 0; i < MAXCPUS; i++)
cv_cpus[i] = NULL;
+
+ memset(&cv_interactive_debug, '\0', sizeof(cv_interactive_debug));
}
cpu_t* CpuManager::getCurrentCPU()
@@ -178,6 +181,11 @@ void CpuManager::executePeriodics(cpu_t * i_cpu)
{
if(i_cpu->master)
{
+ if (cv_interactive_debug.isReady())
+ {
+ cv_interactive_debug.startDebugTask();
+ }
+
++(i_cpu->periodic_count);
if(0 == (i_cpu->periodic_count % CPU_PERIODIC_CHECK_MEMORY))
{
diff --git a/src/kernel/exception.C b/src/kernel/exception.C
index cbe97b220..863743f06 100644
--- a/src/kernel/exception.C
+++ b/src/kernel/exception.C
@@ -75,8 +75,8 @@ void kernel_execute_data_storage()
}
if (!handled)
{
- printk("Data Storage exception on %d: %lx, %lx\n",
- t->tid, getDAR(), getDSISR());
+ printk("Data Storage exception on %d: %lx, %lx @ %p\n",
+ t->tid, getDAR(), getDSISR(), t->context.nip);
TaskManager::endTask(t, NULL, TASK_STATUS_CRASHED);
}
}
diff --git a/src/kernel/idebug.C b/src/kernel/idebug.C
new file mode 100644
index 000000000..673ecb149
--- /dev/null
+++ b/src/kernel/idebug.C
@@ -0,0 +1,89 @@
+// IBM_PROLOG_BEGIN_TAG
+// This is an automatically generated prolog.
+//
+// $Source: src/kernel/idebug.C $
+//
+// IBM CONFIDENTIAL
+//
+// COPYRIGHT International Business Machines Corp. 2011
+//
+// p1
+//
+// Object Code Only (OCO) source materials
+// Licensed Internal Code Source Materials
+// IBM HostBoot Licensed Internal Code
+//
+// The source code for this program is not published or other-
+// wise divested of its trade secrets, irrespective of what has
+// been deposited with the U.S. Copyright Office.
+//
+// Origin: 30
+//
+// IBM_PROLOG_END
+#include <kernel/idebug.H>
+#include <kernel/console.H>
+#include <kernel/cpumgr.H>
+#include <kernel/scheduler.H>
+#include <sys/task.h>
+
+ // Set Ready = 0, Running = 1, Complete = 0.
+static const uint64_t IDEBUG_RUNNING_STATE = 0x0001000000000000ull;
+ // Set Ready = 0, Running = 0, Complete = 1.
+static const uint64_t IDEBUG_COMPLETE_STATE = 0x0000010000000000ull;
+
+void InteractiveDebug::startDebugTask()
+{
+ // Atomically set state to 'running'.
+ // Set Ready = 0, Running = 1, Complete = 0.
+ __sync_lock_test_and_set(&state_value, IDEBUG_RUNNING_STATE);
+
+ // Create userspace task to execute function.
+ task_t* t = TaskManager::createTask(&debugEntryPoint, this, true);
+ CpuManager::getCurrentCPU()->scheduler->addTask(t);
+
+ return;
+}
+
+void InteractiveDebug::debugEntryPoint(void* i_idObject)
+{
+ // Detach task so it is cleaned up properly once it exits.
+ task_detach();
+
+ // Get interactive debug structure from cast of input paramater.
+ InteractiveDebug* interactiveDebug =
+ static_cast<InteractiveDebug*>(i_idObject);
+
+ // Get function pointer from 'entry_point_toc'.
+ typedef uint64_t(*func)(uint64_t,uint64_t,uint64_t,uint64_t,
+ uint64_t,uint64_t,uint64_t,uint64_t);
+ func entry_point =
+ reinterpret_cast<func>(interactiveDebug->entry_point_toc);
+
+ // Call function with parameters.
+ // Due to the PowerABI, parameters get passed in r3-r10 and any
+ // unused parameters are ignored by the called function. You can
+ // therefore treat every function as if it has 8 parameters, even
+ // if it has fewer, and the calling conventions are the same from
+ // an assembly perspective.
+ interactiveDebug->return_value =
+ entry_point(interactiveDebug->parms[0],
+ interactiveDebug->parms[1],
+ interactiveDebug->parms[2],
+ interactiveDebug->parms[3],
+ interactiveDebug->parms[4],
+ interactiveDebug->parms[5],
+ interactiveDebug->parms[6],
+ interactiveDebug->parms[7]);
+
+ // Atomically set state to 'complete'.
+ // This must be proceeded by a sync to ensure all memory operations
+ // and instructions have fully completed prior to setting the complete
+ // state (due to weak consistency).
+ // Set Ready = 0, Running = 0, Complete = 1.
+ __sync_synchronize();
+ __sync_lock_test_and_set(&interactiveDebug->state_value,
+ IDEBUG_COMPLETE_STATE);
+
+ task_end();
+}
+
diff --git a/src/kernel/kernel.C b/src/kernel/kernel.C
index 557a1c81c..cbac9a20f 100644
--- a/src/kernel/kernel.C
+++ b/src/kernel/kernel.C
@@ -117,7 +117,7 @@ void Kernel::cpuBootstrap()
void Kernel::inittaskBootstrap()
{
- task_t * t = TaskManager::createTask(&init_main, NULL);
+ task_t * t = TaskManager::createTask(&init_main, NULL, true);
t->cpu = CpuManager::getCurrentCPU();
TaskManager::setCurrentTask(t);
}
diff --git a/src/kernel/makefile b/src/kernel/makefile
index 2ec3db0d9..05c15115a 100644
--- a/src/kernel/makefile
+++ b/src/kernel/makefile
@@ -26,7 +26,7 @@ OBJS = start.o kernel.o console.o pagemgr.o heapmgr.o taskmgr.o cpumgr.o
OBJS += syscall.o scheduler.o spinlock.o exception.o vmmmgr.o timemgr.o
OBJS += futexmgr.o ptmgr.o segmentmgr.o devicesegment.o basesegment.o
OBJS += block.o cpuid.o misc.o msghandler.o blockmsghdlr.o stacksegment.o
-OBJS += softpatch_p7.o barrier.o
+OBJS += softpatch_p7.o barrier.o idebug.o
include ${ROOTPATH}/config.mk
diff --git a/src/kernel/taskmgr.C b/src/kernel/taskmgr.C
index ad2aa3af5..b71bd2f25 100644
--- a/src/kernel/taskmgr.C
+++ b/src/kernel/taskmgr.C
@@ -68,9 +68,11 @@ task_t* TaskManager::createIdleTask()
return Singleton<TaskManager>::instance()._createIdleTask();
}
-task_t* TaskManager::createTask(TaskManager::task_fn_t t, void* p)
+task_t* TaskManager::createTask(TaskManager::task_fn_t t, void* p,
+ bool kernelParent)
{
- return Singleton<TaskManager>::instance()._createTask(t, p, true);
+ return Singleton<TaskManager>::instance()._createTask(t, p, true,
+ kernelParent);
}
void TaskManager::endTask(task_t* t, void* retval, int status)
@@ -85,11 +87,11 @@ void TaskManager::waitTask(task_t* t, int64_t tid, int* status, void** retval)
task_t* TaskManager::_createIdleTask()
{
- return this->_createTask(&TaskManager::idleTaskLoop, NULL, false);
+ return this->_createTask(&TaskManager::idleTaskLoop, NULL, false, true);
}
task_t* TaskManager::_createTask(TaskManager::task_fn_t t,
- void* p, bool withStack)
+ void* p, bool withStack, bool kernelParent)
{
task_t* task = new task_t;
memset(task, '\0', sizeof(task_t));
@@ -144,7 +146,7 @@ task_t* TaskManager::_createTask(TaskManager::task_fn_t t,
// Assign parent for tracker instance, add to task tree.
iv_spinlock.lock();
- task_t* parent = getCurrentTask();
+ task_t* parent = kernelParent ? NULL : getCurrentTask();
if (NULL == parent)
{
tracker->parent = NULL;
diff --git a/src/makefile b/src/makefile
index 28e426357..74c324f5f 100644
--- a/src/makefile
+++ b/src/makefile
@@ -29,7 +29,7 @@ EXTRA_LIDS = dslid
BASE_OBJECTS = console.o spinlock.o string.o string_ext.o stdlib.o ctype.o \
assert.o stdio.o builtins.o vfs_init.o heapmgr.o pagemgr.o \
- math.o barrier.o
+ math.o barrier.o idebug.o
DIRECT_BOOT_OBJECTS = start.o kernel.o taskmgr.o cpumgr.o syscall.o \
scheduler.o exception.o vmmmgr.o timemgr.o \
OpenPOWER on IntegriCloud