2015-01-08 21:08:48 +00:00
|
|
|
#!/usr/bin/expect
|
|
|
|
|
|
|
|
#
|
|
|
|
# \brief Framework for running automated tests
|
|
|
|
# \author Norman Feske
|
|
|
|
# \date 2010-03-16
|
|
|
|
#
|
|
|
|
# Usage: run --name <run_name> --include <run_script> ...
|
|
|
|
#
|
|
|
|
# The '--name' argument is used for as name for the boot-image and
|
|
|
|
# temporary directories. The files includes via the '--include'
|
|
|
|
# argument provide platform-specific additions/refinements to the
|
|
|
|
# test framework as well as the actual test steps.
|
|
|
|
#
|
|
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
# Remove leading and trailing whitespace from string
|
|
|
|
#
|
|
|
|
proc strip_whitespace {string} {
|
|
|
|
regsub -all {^\s+} $string "" string
|
|
|
|
regsub -all {\s+$} $string "" string
|
|
|
|
return $string
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
# Check if the specified spec requirement is satisfied
|
|
|
|
#
|
|
|
|
proc assert_spec {spec} {
|
|
|
|
global specs
|
|
|
|
if {[lsearch $specs $spec] == -1} {
|
|
|
|
puts stderr "Test requires '$spec'"
|
|
|
|
exit 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
# Build genode targets specified as space-separated strings
|
|
|
|
#
|
|
|
|
# If the build process fails, this procedure will exit the program with
|
|
|
|
# the error code -4.
|
|
|
|
#
|
|
|
|
proc build {targets} {
|
|
|
|
|
|
|
|
if {[get_cmd_switch --skip-build]} return
|
|
|
|
|
|
|
|
regsub -all {\s\s+} $targets " " targets
|
|
|
|
puts "building targets: $targets"
|
|
|
|
set timeout 10000
|
|
|
|
set pid [eval "spawn make $targets"]
|
|
|
|
expect { eof { } }
|
|
|
|
if {[lindex [wait $pid] end] != 0} {
|
|
|
|
puts "Error: Genode build failed"
|
|
|
|
exit -4
|
|
|
|
}
|
|
|
|
puts "genode build completed"
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
# Create a fresh boot directory
|
|
|
|
#
|
|
|
|
proc create_boot_directory { } {
|
|
|
|
exec rm -rf [run_dir]
|
|
|
|
exec mkdir -p [run_dir]
|
|
|
|
exec mkdir -p [run_dir]/genode
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
# Append string to variable only if 'condition' is satisfied
|
|
|
|
#
|
2017-03-09 10:54:05 +00:00
|
|
|
proc append_if {condition var args} {
|
2015-01-08 21:08:48 +00:00
|
|
|
upvar $var up_var
|
2017-03-09 10:54:05 +00:00
|
|
|
if {$condition} { append up_var [join $args ""] }
|
2015-01-08 21:08:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
# Append element to list only if 'condition' is satisfied
|
|
|
|
#
|
|
|
|
proc lappend_if {condition var string} {
|
|
|
|
upvar $var up_var
|
|
|
|
if {$condition} { lappend up_var $string }
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
# Check syntax of specified XML file using xmllint
|
|
|
|
#
|
|
|
|
proc check_xml_syntax {xml_file} {
|
|
|
|
|
|
|
|
if {![have_installed xmllint]} {
|
|
|
|
puts "Warning: Cannot validate config syntax (please install xmllint)"
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if {[catch {exec xmllint --noout $xml_file} result]} {
|
|
|
|
puts stderr $result
|
|
|
|
puts stderr "Error: Invalid XML syntax in $xml_file"
|
|
|
|
exit 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
##
|
2017-09-05 21:05:43 +00:00
|
|
|
# Validate file to match Genode's XML schema using xmllint
|
|
|
|
#
|
|
|
|
proc check_xml_with_schema {xml_file} {
|
|
|
|
|
|
|
|
if {![have_installed xmllint]} {
|
|
|
|
puts "Warning: Cannot validate config syntax (please install xmllint)"
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if {[catch {exec xmllint --noout -schema [genode_dir]/tool/run/genode.xsd $xml_file} result]} {
|
|
|
|
if {$result != "$xml_file validates"} {
|
|
|
|
puts stderr "$result"
|
|
|
|
puts stderr "Error: Invalid XML syntax in $xml_file"
|
|
|
|
exit 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
# Install content of specified variable as init config file
|
2015-01-08 21:08:48 +00:00
|
|
|
#
|
2017-07-05 14:36:27 +00:00
|
|
|
proc install_config { args } {
|
2015-01-08 21:08:48 +00:00
|
|
|
set fh [open "[run_dir]/genode/config" "WRONLY CREAT TRUNC"]
|
2017-07-05 14:36:27 +00:00
|
|
|
puts $fh [join $args {}]
|
2015-01-08 21:08:48 +00:00
|
|
|
close $fh
|
|
|
|
|
2017-09-05 21:05:43 +00:00
|
|
|
check_xml_with_schema [run_dir]/genode/config
|
2015-01-08 21:08:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
# Integrate specified binaries into boot image
|
|
|
|
#
|
|
|
|
# \param binaries space-separated list of file names located within the
|
|
|
|
# '<build-dir>/bin/' directory
|
|
|
|
#
|
|
|
|
proc build_boot_image {binaries} {
|
2017-03-29 14:04:07 +00:00
|
|
|
check_for_missing_depot_archives
|
2015-01-08 21:08:48 +00:00
|
|
|
run_boot_dir $binaries
|
|
|
|
}
|
|
|
|
|
2015-02-12 12:13:21 +00:00
|
|
|
# set expect match-buffer size
|
|
|
|
match_max -d 40000
|
2015-01-08 21:08:48 +00:00
|
|
|
|
|
|
|
##
|
|
|
|
# Execute Genode
|
|
|
|
#
|
|
|
|
# \param wait_for_re regular expression that matches the test completion
|
|
|
|
# \param timeout_value timeout in seconds
|
|
|
|
# \param spawn_id spawn_id of a already running and spawned process
|
|
|
|
# spawn_id may be a list of spawned processes if needed
|
|
|
|
# \global output contains the core output (modified)
|
|
|
|
#
|
|
|
|
# If the function is called without any argument, Genode is executed in
|
|
|
|
# interactive mode.
|
|
|
|
#
|
|
|
|
# If the test execution times out, this procedure will exit the program with
|
|
|
|
# the error code -2.
|
|
|
|
#
|
|
|
|
proc run_genode_until {{wait_for_re forever} {timeout_value 0} {running_spawn_id -1}} {
|
|
|
|
#
|
|
|
|
# If a running_spawn_id is specified, wait for the expected output
|
|
|
|
#
|
|
|
|
if {$running_spawn_id != -1} {
|
|
|
|
wait_for_output $wait_for_re $timeout_value $running_spawn_id
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
set retry 3
|
|
|
|
while { $retry != 0 } {
|
|
|
|
|
2017-08-07 14:30:38 +00:00
|
|
|
if {[expr [run_power_on] == false]} {
|
|
|
|
puts "Power on step failed, retry."
|
|
|
|
sleep 3
|
|
|
|
incr retry -1;
|
|
|
|
continue
|
|
|
|
}
|
2015-01-08 21:08:48 +00:00
|
|
|
|
|
|
|
if {![run_load]} {
|
|
|
|
puts "Load step failed, retry."
|
|
|
|
|
|
|
|
# kill the spawned load process if there is one
|
|
|
|
if {[load_spawn_id] != -1} {
|
|
|
|
set pid [exp_pid -i [load_spawn_id]]
|
|
|
|
exec kill -9 $pid
|
|
|
|
}
|
|
|
|
|
|
|
|
incr retry -1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if {![run_log $wait_for_re $timeout_value]} {
|
|
|
|
puts "Log step failed, retry."
|
|
|
|
incr retry -1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
puts stderr "Boot process failed 3 times in series. I give up!";
|
|
|
|
exit -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
# Remove color information from output
|
|
|
|
#
|
|
|
|
proc filter_out_color_escape_sequences { } {
|
|
|
|
global output
|
|
|
|
regsub -all {\e\[.*?m} $output "" output
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
# Remove superfluous empty lines and unify line endings from output
|
|
|
|
#
|
|
|
|
proc trim_lines { } {
|
|
|
|
global output
|
|
|
|
regsub -all {[\r\n]+} $output "\n" output
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
# Filter output based on the specified pattern
|
|
|
|
#
|
|
|
|
# Only those lines that match the pattern are preserved.
|
|
|
|
#
|
|
|
|
proc grep_output {pattern} {
|
|
|
|
global output
|
|
|
|
|
|
|
|
filter_out_color_escape_sequences
|
|
|
|
|
|
|
|
trim_lines
|
|
|
|
|
|
|
|
set output_list [split $output "\n"]
|
|
|
|
set filtered ""
|
|
|
|
foreach line $output_list {
|
|
|
|
if {[regexp $pattern $line]} {
|
|
|
|
append filtered "$line\n"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
set output $filtered
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
# Unify known variations that appear in the test output
|
|
|
|
#
|
|
|
|
# \global output test output (modified)
|
|
|
|
#
|
|
|
|
proc unify_output {pattern replacement} {
|
|
|
|
global output
|
|
|
|
regsub -all $pattern $output $replacement output
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
# Compare output against expected output line by line
|
|
|
|
#
|
|
|
|
# \param good expected test output
|
|
|
|
# \global output test output
|
|
|
|
#
|
|
|
|
# This procedure will exit the program with the error code -1 if the
|
|
|
|
# comparison fails.
|
|
|
|
#
|
|
|
|
proc compare_output_to { good } {
|
|
|
|
global output
|
|
|
|
set output_list [split [strip_whitespace $output] "\n"]
|
|
|
|
set good_list [split [strip_whitespace $good] "\n"]
|
|
|
|
|
|
|
|
set i 0
|
|
|
|
set mismatch_cnt 0
|
|
|
|
foreach good_line $good_list {
|
|
|
|
set output_line [strip_whitespace [lindex $output_list $i]]
|
|
|
|
set good_line [strip_whitespace $good_line]
|
|
|
|
|
|
|
|
if {$output_line != $good_line} {
|
|
|
|
puts ""
|
|
|
|
puts stderr "Line $i of output is unexpected"
|
|
|
|
puts stderr " expected: '$good_line'"
|
|
|
|
puts stderr " got: '$output_line'"
|
|
|
|
incr mismatch_cnt
|
|
|
|
}
|
|
|
|
incr i
|
|
|
|
}
|
|
|
|
|
|
|
|
#
|
|
|
|
# if $good is empty the foreach-loop isn't entered
|
|
|
|
# so we've to check for it separately
|
|
|
|
#
|
|
|
|
if {![llength $good_list] && [llength $output_list]} {
|
|
|
|
foreach output_line $output_list {
|
|
|
|
set output_line [strip_whitespace $output_line]
|
|
|
|
puts ""
|
|
|
|
puts stderr "Line $i of output is unexpected"
|
|
|
|
puts stderr " got: '$output_line'"
|
|
|
|
incr mismatch_cnt
|
|
|
|
incr i
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if {$mismatch_cnt > 0} {
|
|
|
|
puts "Error: Test failed, $mismatch_cnt unexpected lines of output"
|
|
|
|
exit -1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
# Return true if command-line switch was specified
|
|
|
|
#
|
|
|
|
proc get_cmd_switch { arg_name } {
|
|
|
|
global argv
|
|
|
|
return [expr [lsearch $argv $arg_name] >= 0]
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
# Return command-line argument value
|
|
|
|
#
|
|
|
|
# If a argument name is specified multiple times, a
|
|
|
|
# list of argument values is returned.
|
|
|
|
#
|
|
|
|
proc get_cmd_arg { arg_name default_value } {
|
|
|
|
global argv
|
|
|
|
|
|
|
|
# find argument name in argv list
|
|
|
|
set arg_idx_list [lsearch -all $argv $arg_name]
|
|
|
|
|
|
|
|
if {[llength $arg_idx_list] == 0} { return $default_value }
|
|
|
|
|
|
|
|
set result {}
|
|
|
|
foreach arg_idx $arg_idx_list {
|
|
|
|
set next_idx [expr $arg_idx + 1]
|
|
|
|
|
|
|
|
# stop if argv ends with the argument name
|
|
|
|
if {$next_idx >= [llength $argv]} continue
|
|
|
|
|
|
|
|
# return list element following the argument name
|
|
|
|
lappend result [lindex $argv $next_idx]
|
|
|
|
}
|
|
|
|
|
|
|
|
# if argument occurred only once, return its value
|
|
|
|
if {[llength $result] == 1} { return [lindex $result 0] }
|
|
|
|
|
|
|
|
# if argument occurred multiple times, contain list of arguments
|
|
|
|
return $result
|
|
|
|
}
|
|
|
|
|
|
|
|
##
|
|
|
|
# Return command-line argument value
|
|
|
|
#
|
|
|
|
# If a argument name is specified multiple times, return only the
|
|
|
|
# first match.
|
|
|
|
#
|
|
|
|
proc get_cmd_arg_first { arg_name default_value } {
|
|
|
|
global argv
|
|
|
|
|
|
|
|
set arg_idx [lsearch $argv $arg_name]
|
|
|
|
|
|
|
|
if {$arg_idx == -1} { return $default_value }
|
|
|
|
|
|
|
|
return [lindex $argv [expr $arg_idx + 1]]
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
# Read command-line arguments
|
|
|
|
#
|
|
|
|
|
|
|
|
set run_name [get_cmd_arg --name "noname"]
|
|
|
|
set genode_dir [get_cmd_arg --genode-dir ""]
|
|
|
|
set cross_dev_prefix [get_cmd_arg --cross-dev-prefix ""]
|
|
|
|
set specs [get_cmd_arg --specs ""]
|
|
|
|
set repositories [get_cmd_arg --repositories ""]
|
|
|
|
|
|
|
|
|
|
|
|
# accessor functions for command-line arguments
|
|
|
|
proc run_name { } { global run_name; return $run_name }
|
|
|
|
proc run_dir { } { global run_name; return var/run/$run_name }
|
|
|
|
proc genode_dir { } { global genode_dir; return $genode_dir }
|
|
|
|
proc cross_dev_prefix { } { global cross_dev_prefix; return $cross_dev_prefix }
|
|
|
|
|
|
|
|
##
|
|
|
|
# Return true if spec value is set for the build
|
|
|
|
#
|
|
|
|
proc have_spec {spec} { global specs; return [expr [lsearch $specs $spec] != -1] }
|
|
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
# Return true if specified program is installed
|
|
|
|
#
|
|
|
|
proc have_installed {program} {
|
|
|
|
if {[catch { exec which $program }]} { return false; }
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
# Return true if specified program is installed on the host platform
|
|
|
|
#
|
|
|
|
proc requires_installation_of {program} {
|
|
|
|
if {![have_installed $program]} {
|
|
|
|
puts "Run script aborted because $program is not installed"; exit
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
# Return first repository containing the given path
|
|
|
|
#
|
|
|
|
proc repository_contains {path} {
|
|
|
|
global repositories;
|
|
|
|
foreach i $repositories {
|
|
|
|
if {[file exists $i/$path]} { return $i }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
## Utilities for performing steps that are the same on several platforms
|
|
|
|
##
|
|
|
|
|
|
|
|
##
|
|
|
|
# Read kernel location from build-directory configuration
|
|
|
|
#
|
|
|
|
# If config file does not exist or if there is no 'KERNEL' declaration in the
|
|
|
|
# config file, the function returns 'default_location'. If the config file
|
|
|
|
# points to a non-existing kernel image, the function aborts with the exit
|
|
|
|
# value -6.
|
|
|
|
#
|
|
|
|
proc kernel_location_from_config_file { config_file default_location } {
|
|
|
|
global _kernel
|
|
|
|
|
|
|
|
if {![info exists _kernel]} {
|
|
|
|
if {[file exists $config_file]} {
|
|
|
|
set _kernel [exec sed -n "/^KERNEL/s/^.*=\\s*//p" $config_file]
|
|
|
|
|
|
|
|
# check if the regular expression matched
|
|
|
|
if {$_kernel != ""} {
|
|
|
|
if {[file exists $_kernel]} {
|
|
|
|
return $_kernel
|
|
|
|
} else {
|
|
|
|
puts stderr "Error: kernel specified in '$config_file' does not exist"
|
|
|
|
exit -6
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
# try to fall back to version hosted with the Genode build directory
|
|
|
|
set _kernel $default_location
|
|
|
|
}
|
|
|
|
return $_kernel
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-12-09 22:09:17 +00:00
|
|
|
##
|
|
|
|
# Return name of kernel-specific binary for a given generic name
|
|
|
|
#
|
|
|
|
# The boot_dir plugin may provide functions named 'binary_name_<binary>'
|
|
|
|
# where '<binary>' stands for a generic name like "timer" or "nic". The
|
|
|
|
# function returns the name of the binary to integrate into the boot
|
|
|
|
# directory under the name '<binary>'.
|
|
|
|
#
|
|
|
|
# If no such function exists, it returns the argument as is. This is the
|
|
|
|
# case for regular binaries that appear in the boot directory under their
|
|
|
|
# original name.
|
|
|
|
#
|
2017-05-17 10:57:14 +00:00
|
|
|
proc kernel_specific_binary { binary {silent ""} } {
|
2016-12-09 22:09:17 +00:00
|
|
|
|
|
|
|
regsub -all {\.} $binary "_" function_suffix
|
|
|
|
set function_name "binary_name_$function_suffix"
|
|
|
|
|
|
|
|
if {[info procs $function_name] == $function_name} {
|
|
|
|
set binary_name [$function_name]
|
2017-05-17 10:57:14 +00:00
|
|
|
if {$silent != "silent"} {
|
|
|
|
puts "using '$binary_name' as '$binary'"
|
|
|
|
}
|
2016-12-09 22:09:17 +00:00
|
|
|
return [$function_name]
|
|
|
|
}
|
|
|
|
|
|
|
|
return $binary
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-04-03 13:39:36 +00:00
|
|
|
proc copy_genode_binaries_to_run_dir { binaries } {
|
2015-01-08 21:08:48 +00:00
|
|
|
|
|
|
|
foreach binary $binaries {
|
2017-04-03 13:39:36 +00:00
|
|
|
file copy -force bin/[kernel_specific_binary $binary] [run_dir]/genode/$binary
|
2015-01-08 21:08:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
# Wait for a specific output of a already running spawned process
|
|
|
|
#
|
|
|
|
proc wait_for_output { wait_for_re timeout_value running_spawn_id } {
|
|
|
|
global output
|
|
|
|
|
|
|
|
if {$wait_for_re == "forever"} {
|
|
|
|
set timeout -1
|
|
|
|
interact {
|
|
|
|
\003 {
|
|
|
|
send_user "Expect: 'interact' received 'strg+c' and was cancelled\n";
|
|
|
|
exit
|
|
|
|
}
|
|
|
|
-i $running_spawn_id
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
set timeout $timeout_value
|
|
|
|
}
|
|
|
|
|
2015-10-26 14:02:14 +00:00
|
|
|
set platform_msg [run_boot_string]
|
|
|
|
if {$platform_msg eq ""} {
|
|
|
|
set platform_msg "undefined platform command startup string sequence"
|
|
|
|
}
|
|
|
|
|
2015-01-08 21:08:48 +00:00
|
|
|
expect {
|
2015-10-26 14:02:14 +00:00
|
|
|
-i $running_spawn_id $platform_msg { puts stderr "Error: platform rebooted unexpectedly"; exit -4 }
|
2015-01-08 21:08:48 +00:00
|
|
|
-i $running_spawn_id -re $wait_for_re { }
|
|
|
|
eof { puts stderr "Error: Spawned process died unexpectedly"; exit -3 }
|
|
|
|
timeout { puts stderr "Error: Test execution timed out"; exit -2 }
|
|
|
|
}
|
2015-03-24 10:02:56 +00:00
|
|
|
append output $expect_out(buffer)
|
2015-01-08 21:08:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
## Fall-back implementations of all run module procedures
|
|
|
|
##
|
|
|
|
|
2015-02-06 17:02:55 +00:00
|
|
|
##
|
|
|
|
# Dummy boot_string procedure
|
2017-04-03 13:39:36 +00:00
|
|
|
#
|
2015-02-06 17:02:55 +00:00
|
|
|
proc run_boot_string { } { return ""; }
|
|
|
|
|
2017-04-03 13:39:36 +00:00
|
|
|
|
2015-01-08 21:08:48 +00:00
|
|
|
##
|
2015-04-28 16:34:15 +00:00
|
|
|
# Fall-back boot_dir module
|
|
|
|
#
|
|
|
|
# If this function is called someone forgot to include an appropriate boot_dir
|
|
|
|
# module. So, we exit with an error.
|
2017-04-03 13:39:36 +00:00
|
|
|
#
|
2015-04-28 16:34:15 +00:00
|
|
|
proc run_boot_dir { binaries } {
|
|
|
|
puts stderr "Error: boot_dir module missing, e.g., '--include boot_dir/hw'"
|
|
|
|
exit 1
|
|
|
|
}
|
2015-01-08 21:08:48 +00:00
|
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
# Dummy image build module
|
|
|
|
#
|
|
|
|
proc run_image { {image "" } } { return true; }
|
|
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
# Dummy load module
|
|
|
|
#
|
|
|
|
proc run_load { } { return true; }
|
|
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
# Dummy output module
|
|
|
|
#
|
|
|
|
# XXX explain why exit 0 is appropiate
|
|
|
|
#
|
|
|
|
proc run_log { wait_for_re timeout_value } { exit 0 }
|
|
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
# Dummy power_on module
|
|
|
|
#
|
|
|
|
proc run_power_on { } { return true; }
|
|
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
# Dummy power_off module
|
|
|
|
#
|
|
|
|
proc run_power_off { } { return true; }
|
|
|
|
|
|
|
|
|
2016-09-15 14:08:33 +00:00
|
|
|
##
|
|
|
|
# Default core linker options
|
|
|
|
#
|
|
|
|
proc core_ld_opts { } {
|
|
|
|
set ret { -Wl,-T }
|
|
|
|
lappend ret "-Wl,[genode_dir]/repos/base/src/ld/genode.ld"
|
|
|
|
return $ret
|
|
|
|
}
|
|
|
|
|
|
|
|
##
|
|
|
|
# Default core link address
|
|
|
|
#
|
|
|
|
proc core_link_address { } { return "0x01000000" }
|
|
|
|
|
2015-01-08 21:08:48 +00:00
|
|
|
##
|
|
|
|
# Check if a specific file is included
|
|
|
|
#
|
|
|
|
proc have_include { name } {
|
|
|
|
global include_list
|
|
|
|
foreach element $include_list {
|
|
|
|
if {[string equal $element $name]} {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
# Override the exit procedure
|
|
|
|
#
|
|
|
|
# We have to override the exit procedure to make sure that a loaded
|
|
|
|
# run_power_off procedure is in any case execute when stopping the
|
|
|
|
# execution of the run tool.
|
|
|
|
#
|
|
|
|
rename exit real_exit
|
|
|
|
proc exit {{status 0}} {
|
|
|
|
run_power_off
|
|
|
|
|
|
|
|
real_exit $status
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
# Determine terminal program
|
|
|
|
#
|
|
|
|
proc terminal { } {
|
|
|
|
global env
|
|
|
|
if {[info exists env(COLORTERM)]} {
|
|
|
|
return $env(COLORTERM)
|
|
|
|
}
|
|
|
|
return $env(TERM)
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
# Determine GDB executable installed at the host
|
|
|
|
#
|
|
|
|
proc gdb { } {
|
|
|
|
if {[have_installed "[cross_dev_prefix]gdb"]} {
|
|
|
|
return "[cross_dev_prefix]gdb" }
|
|
|
|
|
|
|
|
if {[have_installed gdb]} {
|
|
|
|
return "gdb" }
|
|
|
|
|
|
|
|
requires_installation_of gdb
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
# Check if a shell command is installed
|
|
|
|
#
|
|
|
|
# \param command name of the command to search
|
|
|
|
#
|
|
|
|
# \return absolute path of command if found, or exists if not
|
|
|
|
#
|
|
|
|
proc check_installed {command} {
|
|
|
|
if { [catch {set path [exec which $command]}] == 0} {
|
|
|
|
return $path
|
|
|
|
}
|
|
|
|
|
|
|
|
set dir { /sbin /usr/sbin /usr/local/bin }
|
|
|
|
|
|
|
|
foreach location $dir {
|
|
|
|
append location / $command
|
|
|
|
|
|
|
|
if { [file exists $location] == 1} {
|
|
|
|
return $location
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
puts stderr "Error: '$command' command could be not found. Please make sure to install the"
|
|
|
|
puts stderr " packet containing '$command', or make it available in your PATH variable.\n"
|
|
|
|
|
|
|
|
exit 1
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-09-15 14:08:33 +00:00
|
|
|
##
|
|
|
|
# Generate assembly code aggregating boot-module data from specified files.
|
|
|
|
#
|
|
|
|
proc generate_boot_modules_asm {path modules} {
|
|
|
|
|
|
|
|
# architecture dependent definitions
|
|
|
|
if {[have_spec "64bit"]} { set address_type ".quad"
|
|
|
|
} else { set address_type ".long" }
|
|
|
|
|
|
|
|
# header
|
|
|
|
set asm_src {}
|
|
|
|
append asm_src ".set MIN_PAGE_SIZE_LOG2, 12\n"
|
|
|
|
append asm_src ".set DATA_ACCESS_ALIGNM_LOG2, 3\n"
|
|
|
|
append asm_src "\n"
|
|
|
|
append asm_src ".section .data\n"
|
|
|
|
append asm_src "\n"
|
|
|
|
append asm_src ".p2align DATA_ACCESS_ALIGNM_LOG2\n"
|
|
|
|
append asm_src ".global _boot_modules_headers_begin\n"
|
|
|
|
append asm_src "_boot_modules_headers_begin:\n"
|
|
|
|
append asm_src "\n"
|
|
|
|
|
|
|
|
# module list
|
|
|
|
set i 0
|
|
|
|
foreach module $modules {
|
|
|
|
incr i
|
|
|
|
append asm_src "${address_type} _boot_module_${i}_name\n"
|
|
|
|
append asm_src "${address_type} _boot_module_${i}_begin\n"
|
|
|
|
append asm_src "${address_type} _boot_module_${i}_end -"
|
|
|
|
append asm_src " _boot_module_${i}_begin\n"
|
|
|
|
append asm_src "\n"
|
|
|
|
}
|
|
|
|
append asm_src ".global _boot_modules_headers_end\n"
|
|
|
|
append asm_src "_boot_modules_headers_end:\n"
|
|
|
|
append asm_src "\n"
|
|
|
|
|
|
|
|
# module names
|
|
|
|
set i 0
|
|
|
|
foreach module $modules {
|
|
|
|
incr i
|
|
|
|
append asm_src ".p2align DATA_ACCESS_ALIGNM_LOG2\n"
|
|
|
|
append asm_src "_boot_module_${i}_name:\n"
|
|
|
|
append asm_src ".string \"${module}\"\n"
|
|
|
|
append asm_src ".byte 0\n"
|
|
|
|
append asm_src "\n"
|
|
|
|
}
|
|
|
|
|
|
|
|
# header end
|
|
|
|
append asm_src ".section .data.boot_modules_binaries\n"
|
|
|
|
append asm_src "\n"
|
|
|
|
append asm_src ".global _boot_modules_binaries_begin\n"
|
|
|
|
append asm_src "_boot_modules_binaries_begin:\n"
|
|
|
|
append asm_src "\n"
|
|
|
|
|
|
|
|
# module data
|
|
|
|
set i 0
|
|
|
|
foreach module $modules {
|
|
|
|
incr i
|
|
|
|
append asm_src ".p2align MIN_PAGE_SIZE_LOG2\n"
|
|
|
|
append asm_src "_boot_module_${i}_begin:\n"
|
|
|
|
append asm_src ".incbin \"${path}/${module}\"\n"
|
|
|
|
append asm_src "_boot_module_${i}_end:\n"
|
|
|
|
append asm_src "\n"
|
|
|
|
}
|
|
|
|
|
2017-09-22 12:15:26 +00:00
|
|
|
append asm_src ".p2align MIN_PAGE_SIZE_LOG2\n"
|
2016-09-15 14:08:33 +00:00
|
|
|
append asm_src ".global _boot_modules_binaries_end\n"
|
|
|
|
append asm_src "_boot_modules_binaries_end:\n"
|
|
|
|
|
|
|
|
return $asm_src
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
# Link core image containing given modules
|
|
|
|
#
|
2016-10-20 08:28:11 +00:00
|
|
|
proc build_core {lib modules target link_address} {
|
2016-09-15 14:08:33 +00:00
|
|
|
|
|
|
|
# generate assembly code aggregating the modules data
|
|
|
|
set asm_src [generate_boot_modules_asm [run_dir]/genode $modules]
|
|
|
|
|
|
|
|
# architecture dependent definitions
|
|
|
|
set arch {}
|
2017-06-20 13:25:04 +00:00
|
|
|
if {[have_spec "x86_64"]} { set arch { -m64 -mcmodel=large } }
|
2016-09-15 14:08:33 +00:00
|
|
|
if {[have_spec "x86_32"]} { set arch -m32 }
|
|
|
|
|
|
|
|
# determine the libgcc
|
|
|
|
set libgcc [exec [cross_dev_prefix]gcc -print-libgcc-file-name {*}$arch]
|
|
|
|
|
|
|
|
# compile the boot modules into one object file
|
|
|
|
exec [cross_dev_prefix]gcc {*}$arch -c -x assembler -o [run_dir].boot_modules.o - << $asm_src
|
|
|
|
|
|
|
|
# link final image
|
|
|
|
exec [cross_dev_prefix]g++ {*}$arch -nostdlib {*}[core_ld_opts] \
|
|
|
|
-Wl,-z -Wl,max-page-size=0x1000 \
|
2016-10-20 08:28:11 +00:00
|
|
|
-Wl,-Ttext=$link_address -Wl,-gc-sections \
|
2016-09-15 14:08:33 +00:00
|
|
|
-Wl,-nostdlib -Wl,--whole-archive -Wl,--start-group \
|
|
|
|
$lib [run_dir].boot_modules.o -Wl,--no-whole-archive \
|
|
|
|
-Wl,--end-group $libgcc -o $target
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-04-03 13:39:36 +00:00
|
|
|
##
|
|
|
|
# Return kernel-specific files to be excluded from the core image
|
|
|
|
#
|
|
|
|
proc kernel_files { } { return { } }
|
|
|
|
|
|
|
|
|
2016-09-15 14:08:33 +00:00
|
|
|
##
|
|
|
|
# Generate bootable core image containing all boot-modules
|
|
|
|
#
|
2017-04-03 13:39:36 +00:00
|
|
|
proc build_core_image { modules } {
|
2016-12-08 11:25:00 +00:00
|
|
|
|
2017-04-03 13:39:36 +00:00
|
|
|
set core_obj [kernel_specific_binary core.o]
|
2016-09-15 14:08:33 +00:00
|
|
|
|
2017-04-03 13:39:36 +00:00
|
|
|
# replace 'core' with actual core-object name in 'modules' list
|
|
|
|
if {[lsearch $modules "core"] != -1} {
|
|
|
|
set idx [lsearch $modules "core"]
|
|
|
|
set modules [lreplace $modules $idx $idx]
|
|
|
|
lappend modules $core_obj
|
|
|
|
}
|
2016-09-15 14:08:33 +00:00
|
|
|
|
2017-04-03 13:39:36 +00:00
|
|
|
copy_genode_binaries_to_run_dir $modules
|
Disambiguate kernel-specific file names
This patch removes possible ambiguities with respect to the naming of
kernel-dependent binaries and libraries. It also removes the use of
kernel-specific global side effects from the build system. The reach of
kernel-specific peculiarities has thereby become limited to the actual
users of the respective 'syscall-<kernel>' libraries.
Kernel-specific build artifacts are no longer generated at magic places
within the build directory (like okl4's includes, or the L4 build
directories of L4/Fiasco and Fiasco.OC, or the build directories of
various kernels). Instead, such artifacts have been largely moved to the
libcache. E.g., the former '<build-dir>/l4/' build directory for the L4
build system resides at '<build-dir>/var/libcache/syscall-foc/build/'.
This way, the location is unique to the kernel. Note that various tools
are still generated somewhat arbitrarily under '<build-dir>/tool/' as
there is no proper formalism for building host tools yet.
As the result of this work, it has become possible to use a joint Genode
build directory that is usable with all kernels of a given hardware
platform. E.g., on x86_32, one can now seamlessly switch between linux,
nova, sel4, okl4, fiasco, foc, and pistachio without rebuilding any
components except for core, the kernel, the dynamic linker, and the timer
driver. At the current stage, such a build directory must still be
created manually. A change of the 'create_builddir' tool will follow to
make this feature easily available.
This patch also simplifies various 'run/boot_dir' plugins by removing
the option for an externally hosted kernel. This option remained unused
for many years now.
Issue #2190
2016-12-10 00:30:38 +00:00
|
|
|
|
2016-09-15 14:08:33 +00:00
|
|
|
# create core binary without modules for debugging
|
2017-05-09 10:59:13 +00:00
|
|
|
build_core debug/$core_obj {} [run_dir].core [core_link_address]
|
2017-04-03 13:39:36 +00:00
|
|
|
|
|
|
|
# determine modules to be incorporated into the core image
|
|
|
|
set modules [glob -nocomplain -tails -directory [run_dir]/genode/ *]
|
|
|
|
set excluded_modules [kernel_files]
|
|
|
|
lappend excluded_modules $core_obj
|
|
|
|
foreach excluded $excluded_modules {
|
|
|
|
set modules [lsearch -inline -not -all $modules $excluded] }
|
|
|
|
|
|
|
|
# check syntax of all boot modules named *.config
|
|
|
|
foreach file [glob -nocomplain [run_dir]/genode/*.config] {
|
|
|
|
check_xml_syntax $file }
|
2016-09-15 14:08:33 +00:00
|
|
|
|
|
|
|
# create core binary containing the boot modules
|
2017-04-03 13:39:36 +00:00
|
|
|
build_core [run_dir]/genode/$core_obj $modules [run_dir]/image.elf [core_link_address]
|
2016-09-15 14:08:33 +00:00
|
|
|
exec [cross_dev_prefix]strip [run_dir]/image.elf
|
2016-12-08 11:25:00 +00:00
|
|
|
|
2017-02-09 13:04:04 +00:00
|
|
|
# Save config part of the image.elf for easy inspection
|
2017-04-03 13:39:36 +00:00
|
|
|
exec cp -f [run_dir]/genode/config [run_dir].config
|
2016-09-15 14:08:33 +00:00
|
|
|
}
|
|
|
|
|
2017-03-29 14:04:07 +00:00
|
|
|
source [genode_dir]/tool/run/depot.inc
|
|
|
|
|
2016-09-15 14:08:33 +00:00
|
|
|
|
2015-01-08 21:08:48 +00:00
|
|
|
##
|
|
|
|
## Execution of run scripts
|
|
|
|
##
|
|
|
|
|
|
|
|
|
|
|
|
set include_list { }
|
|
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
# Read and execute files specified as '--include' arguments
|
|
|
|
#
|
|
|
|
# Out of convenience run modules may be included by using a relative path.
|
|
|
|
#
|
|
|
|
foreach include_name [get_cmd_arg --include ""] {
|
|
|
|
# first check if the include name is absolute
|
|
|
|
if {[string first "/" $include_name] == 0} {
|
|
|
|
puts "including $include_name"
|
|
|
|
lappend include_list $include_name
|
|
|
|
source $include_name
|
|
|
|
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
# if it is relative, check run modules
|
|
|
|
set run_path [genode_dir]/tool/run
|
|
|
|
set dir { etc }
|
|
|
|
lappend dir $run_path
|
|
|
|
|
|
|
|
set found 0
|
|
|
|
foreach location $dir {
|
|
|
|
set include_file $location/$include_name
|
|
|
|
if {[file exists $include_file] == 1} {
|
|
|
|
puts "including $include_file"
|
|
|
|
lappend include_list $include_name
|
|
|
|
source $include_file
|
|
|
|
|
|
|
|
set found 1
|
|
|
|
break
|
|
|
|
} else {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if {!$found} {
|
|
|
|
puts stderr "Aborting, could not load '$include_file'"
|
|
|
|
exit -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
puts "\nRun script execution successful."
|
|
|
|
exit 0
|