diff options
author | Patrick Williams <iawillia@us.ibm.com> | 2011-11-21 15:44:52 -0600 |
---|---|---|
committer | A. Patrick Williams III <iawillia@us.ibm.com> | 2011-12-06 16:11:44 -0600 |
commit | 7799749ee2db86f4fb66c4a7a69fb9fb0b46334e (patch) | |
tree | f50027f990e1db0ea79fabb1b8a9afa1a172dfd1 /src | |
parent | c761a76534988071d0988daa77b8c51526e2d9f4 (diff) | |
download | talos-hostboot-7799749ee2db86f4fb66c4a7a69fb9fb0b46334e.tar.gz talos-hostboot-7799749ee2db86f4fb66c4a7a69fb9fb0b46334e.zip |
Interactive debug tool.
- Modify debug fw to support writing data.
- Modify debug fw to support clocking model forward.
- Add simics environment support for both.
- Kernel support to start a task when directed.
- Write debug tool to modify kernel structure for debug.
Change-Id: Ic001dfd45f91392aefbc9d5096c5344018d5190e
Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/518
Tested-by: Jenkins Server
Reviewed-by: Andrew J. Geissler <andrewg@us.ibm.com>
Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/build/debug/Hostboot/CallFunc.pm | 159 | ||||
-rwxr-xr-x | src/build/debug/Hostboot/_DebugFramework.pm | 149 | ||||
-rwxr-xr-x | src/build/debug/simics-debug-framework.pl | 37 | ||||
-rwxr-xr-x | src/build/debug/simics-debug-framework.py | 52 | ||||
-rwxr-xr-x | src/build/simics/hb-simdebug.py | 97 | ||||
-rw-r--r-- | src/include/kernel/cpumgr.H | 7 | ||||
-rw-r--r-- | src/include/kernel/idebug.H | 85 | ||||
-rw-r--r-- | src/include/kernel/taskmgr.H | 9 | ||||
-rw-r--r-- | src/kernel/cpumgr.C | 8 | ||||
-rw-r--r-- | src/kernel/exception.C | 4 | ||||
-rw-r--r-- | src/kernel/idebug.C | 89 | ||||
-rw-r--r-- | src/kernel/kernel.C | 2 | ||||
-rw-r--r-- | src/kernel/makefile | 2 | ||||
-rw-r--r-- | src/kernel/taskmgr.C | 12 | ||||
-rw-r--r-- | src/makefile | 2 |
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 \ |