run: modularize run tool

This commit is contained in:
Josef Söntgen 2015-01-08 22:08:48 +01:00 committed by Christian Helmuth
parent febca1b827
commit c706b1c0a7
36 changed files with 2152 additions and 1969 deletions

View File

@ -1,201 +0,0 @@
#
# \brief Fiasco-specific test-environment supplements
# \author Norman Feske
# \author Christian Helmuth
# \date 2010-08-26
#
# This file is meant to be used as '--include' argument for 'tool/run'.
#
##
# Install files needed to boot via PXE
#
proc install_pxe_bootloader_to_run_dir { } {
exec cp [genode_dir]/tool/boot/pulsar [run_dir]/boot/pulsar
exec cp [genode_dir]/tool/boot/bender [run_dir]/boot/bender
}
##
# Read the location of the Fiasco user directory from 'etc/fiasco.conf'
#
proc l4_dir { } {
global _l4_dir
if {![info exists _l4_dir]} {
if {[file exists etc/fiasco.conf]} {
set _l4_dir [exec sed -n "/^L4_BUILD_DIR/s/^.*=\\s*//p" etc/fiasco.conf]
if {[file exists $_l4_dir]} { return $_l4_dir }
}
set _l4_dir "[pwd]/l4"
if {![file exists $_l4_dir]} {
puts -nonewline stderr "Error: Could neither find the L4 build directory "
puts -nonewline stderr "within '<genode-build-dir>/l4' nor at a location "
puts -nonewline stderr "specified via 'L4_BUILD_DIR = <l4v2-build-dir>' "
puts stderr "in <genode-build-dir>/etc/fiasco.conf'."
exit 1
}
}
return $_l4_dir
}
##
# Return whether the l4-buid-directory is provided from the outside
#
proc l4_dir_external { } {
if {[l4_dir] == "[pwd]/l4"} { return 0 }
return 1
}
##
# Return the location of the Fiasco kernel
#
proc fiasco { } {
return [kernel_location_from_config_file etc/fiasco.conf [pwd]/kernel/fiasco/fiasco]
}
##
# Return whether fiasco kernel is provided from the outside
#
proc fiasco_external { } {
if {[fiasco] == "[pwd]/kernel/fiasco/fiasco"} { return 0 }
return 1
}
##################################
## Test framework API functions ##
##################################
proc create_boot_directory { } {
exec rm -rf [run_dir]
exec mkdir -p [run_dir]/genode
exec mkdir -p [run_dir]/fiasco
}
proc bin_dir { } {
if {[have_spec x86_32]} { return "[l4_dir]/bin/x86_586" }
puts stderr "Error: Cannot determine bin directory"
exit 1
}
set fiasco_serial_esc_arg "-serial_esc "
proc build_boot_image {binaries} {
global fiasco_serial_esc_arg
#
# Collect contents of the ISO image
#
copy_and_strip_genode_binaries_to_run_dir $binaries
if {![fiasco_external]} { build { kernel } }
if {![l4_dir_external]} { build { bootstrap sigma0 } }
# assert existence of the L4 build directory
l4_dir
puts "using fiasco kernel [fiasco]"
exec cp [fiasco] [run_dir]/fiasco/fiasco
puts "using sigma0/bootstrap at [l4_dir]"
exec cp [bin_dir]/l4v2/sigma0 [run_dir]/fiasco
exec cp [bin_dir]/bootstrap [run_dir]/fiasco
install_iso_bootloader_to_run_dir
#
# Generate grub config file
#
# The core binary is part of the 'binaries' list but it must
# appear right after 'sigma0' as boot module. Hence the special case.
#
set fh [open "[run_dir]/boot/grub/menu.lst" "WRONLY CREAT TRUNC"]
puts $fh "timeout 0"
puts $fh "default 0"
puts $fh "\ntitle Genode on L4/Fiasco"
puts $fh " kernel /boot/bender"
puts $fh " module /fiasco/bootstrap -serial -modaddr=0x02000000"
puts $fh " module /fiasco/fiasco -serial -jdb_cmd=JH $fiasco_serial_esc_arg"
puts $fh " module /fiasco/sigma0"
puts $fh " module /genode/core"
puts $fh " module /genode/config"
foreach binary $binaries {
if {$binary != "core"} {
puts $fh " module /genode/$binary" } }
puts $fh " vbeset 0x117 506070"
close $fh
#
# Install PXE bootloader pulsar
#
install_pxe_bootloader_to_run_dir
create_iso_image_from_run_dir
create_disk_image_from_run_dir
#
# Generate pulsar config file
#
set fh [open "[run_dir]/config-52-54-00-12-34-56" "WRONLY CREAT TRUNC"]
puts $fh " exec /boot/bender"
puts $fh " load /fiasco/bootstrap -serial -modaddr=0x02000000"
puts $fh " load /fiasco/fiasco -serial -serial_esc -jdb_cmd=JH"
puts $fh " load /fiasco/sigma0"
puts $fh " load /genode/core"
puts $fh " load /genode/config"
foreach binary $binaries {
if {$binary != "core"} {
puts $fh " load /genode/$binary" } }
close $fh
#
# Generate pulsar config file pointing to the config file above.
#
if {[info exists ::env(PXE_TFTP_DIR_BASE)] && [info exists ::env(PXE_TFTP_DIR_OFFSET)]} {
exec ln -nfs "[pwd]" "$::env(PXE_TFTP_DIR_BASE)$::env(PXE_TFTP_DIR_OFFSET)"
set tftp_base ""
if {[get_cmd_switch --tftp-absolute]} {
set tftp_base $::env(PXE_TFTP_DIR_BASE)
}
set fh [open "$::env(PXE_TFTP_DIR_BASE)$::env(PXE_TFTP_DIR_OFFSET)/config-00-00-00-00-00-00" "WRONLY CREAT TRUNC"]
puts $fh " root $tftp_base$::env(PXE_TFTP_DIR_OFFSET)/[run_dir]"
puts $fh " config config-52-54-00-12-34-56"
close $fh
}
}
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
}
#
# Try to use one of the supported backends for running the scripts
#
if {[is_amt_available]} {
spawn_amt $wait_for_re $timeout_value
return
}
if {[is_qemu_available]} {
spawn_qemu $wait_for_re $timeout_value
return
}
global run_target
puts stderr "Error: Can't execute automatically on target '$run_target'"
exit -1
}

View File

@ -1,72 +0,0 @@
#
# \brief Environment for executing Genode on Linux
# \author Norman Feske
# \date 2010-08-16
#
# For the documentation of the implemented API functions,
# please refer to the comments in 'tool/run'.
#
proc create_boot_directory { } {
exec rm -rf [run_dir]
exec mkdir -p [run_dir]
}
proc install_config {config} {
set fh [open "[run_dir]/config" "WRONLY CREAT TRUNC"]
puts $fh $config
close $fh
check_xml_syntax [run_dir]/config
}
proc build_boot_image {binaries} {
foreach binary $binaries {
exec ln -sf ../../../bin/$binary [run_dir] }
}
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
}
global spawn_id
set orig_pwd [pwd]
cd [run_dir]
spawn ./core
wait_for_output $wait_for_re $timeout_value $spawn_id
cd $orig_pwd
}
##
# Umount a directory that was bind-mounted beforehand
#
# This function is used by chroot-related tests, e.g., 'os/run/chroot.run',
# 'os/run/chroot_loader.run'.
#
proc umount_and_rmdir { path } {
puts "umounting $path"
#
# Invoke umount until it returns an error. Apparently, the unmounting
# of bind-mounted mount points does not always take immediate effect
# (regardless of the -l option).
#
while {1} {
if {[catch { exec sudo umount -l $path }]} { break; }
sleep 0.25
}
catch { exec rmdir -p $path }
}

View File

@ -1,144 +0,0 @@
#
# \brief NOVA-specific test-environment supplements
# \author Norman Feske
# \date 2010-08-31
#
# This file is meant to be used as '--include' argument for 'tool/run'.
#
##
# Install files needed to boot via PXE
#
proc install_pxe_bootloader_to_run_dir { } {
exec cp [genode_dir]/tool/boot/pulsar [run_dir]/boot/pulsar
exec cp [genode_dir]/tool/boot/bender [run_dir]/boot/bender
}
##
# Read the location of the NOVA kernel directory from 'etc/nova.conf'
#
proc nova_kernel { } {
global _nova_kernel
if {![info exists _nova_kernel]} {
if {[file exists etc/nova.conf]} {
set _nova_kernel [exec sed -n "/^NOVA_KERNEL/s/^.*=\\s*//p" etc/nova.conf]
} else {
set _nova_kernel "[pwd]/kernel/hypervisor"
}
}
return $_nova_kernel
}
##
# Return whether nova is provided from the outside
#
proc nova_external { } {
if {[nova_kernel] == "[pwd]/kernel/hypervisor"} { return 0 }
return 1
}
##################################
## Test framework API functions ##
##################################
proc create_boot_directory { } {
exec rm -rf [run_dir]
exec mkdir -p [run_dir]/genode
}
proc build_boot_image {binaries} {
#
# Collect contents of the ISO image
#
copy_and_strip_genode_binaries_to_run_dir $binaries
if {![nova_external] && ![file exists [nova_kernel]]} { build { kernel } }
puts "using NOVA kernel at [nova_kernel]"
exec [cross_dev_prefix]objcopy -O elf32-i386 [nova_kernel] [run_dir]/hypervisor
install_iso_bootloader_to_run_dir
#
# The core binary is part of the 'binaries' list but it must
# appear right after 'sigma0' as boot module. Hence the special case.
#
# Generate grub config file
#
set fh [open "[run_dir]/boot/grub/menu.lst" "WRONLY CREAT TRUNC"]
puts $fh "timeout 0"
puts $fh "default 0"
puts $fh "\ntitle Genode on NOVA"
puts $fh " kernel /boot/bender"
puts $fh " module /hypervisor iommu serial novpid"
puts $fh " module /genode/core"
puts $fh " module /genode/config"
foreach binary $binaries {
if {$binary != "core"} {
puts $fh " module /genode/$binary" } }
close $fh
install_pxe_bootloader_to_run_dir
create_iso_image_from_run_dir
create_disk_image_from_run_dir
#
# Generate pulsar config file
#
set fh [open "[run_dir]/config-52-54-00-12-34-56" "WRONLY CREAT TRUNC"]
puts $fh " exec /boot/bender"
puts $fh " load /hypervisor iommu serial novpid"
puts $fh " load /genode/core"
puts $fh " load /genode/config"
foreach binary $binaries {
if {$binary != "core"} {
puts $fh " load /genode/$binary" } }
close $fh
#
# Generate pulsar config file pointing to the config file above.
#
if {[info exists ::env(PXE_TFTP_DIR_BASE)] && [info exists ::env(PXE_TFTP_DIR_OFFSET)]} {
exec ln -nfs "[pwd]" "$::env(PXE_TFTP_DIR_BASE)$::env(PXE_TFTP_DIR_OFFSET)"
set tftp_base ""
if {[get_cmd_switch --tftp-absolute]} {
set tftp_base $::env(PXE_TFTP_DIR_BASE)
}
set fh [open "$::env(PXE_TFTP_DIR_BASE)$::env(PXE_TFTP_DIR_OFFSET)/config-00-00-00-00-00-00" "WRONLY CREAT TRUNC"]
puts $fh " root $tftp_base$::env(PXE_TFTP_DIR_OFFSET)/[run_dir]"
puts $fh " config config-52-54-00-12-34-56"
close $fh
}
}
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
}
#
# Try to use one of the supported backends for running the scripts
#
if {[is_amt_available]} {
spawn_amt $wait_for_re $timeout_value
return
}
if {[is_serial_available]} {
spawn_serial $wait_for_re $timeout_value "NOVA Microhypervisor"
return
}
if {[is_qemu_available]} {
spawn_qemu $wait_for_re $timeout_value
return
}
}

View File

@ -1,179 +0,0 @@
#
# \brief Pistachio-specific test-environment supplements
# \author Norman Feske
# \date 2010-08-25
#
# This file is meant to be used as '--include' argument for 'tool/run'.
#
##
# Install files needed to boot via PXE
#
proc install_pxe_bootloader_to_run_dir { } {
exec cp [genode_dir]/tool/boot/pulsar [run_dir]/boot/pulsar
exec cp [genode_dir]/tool/boot/bender [run_dir]/boot/bender
}
##
# Read the location of the Pistachio user directory from 'etc/pistachio.conf'
#
proc pistachio_user_dir { } {
global _pistachio_user_dir
if {![info exists _pistachio_user_dir]} {
if {[file exists etc/pistachio.conf]} {
set _pistachio_user_dir [exec sed -n "/^PISTACHIO_USER_BUILD_DIR/s/^.*=\\s*//p" etc/pistachio.conf]
} else {
set _pistachio_user_dir "[pwd]/l4"
}
}
return $_pistachio_user_dir
}
##
# Read the location of the Pistachio kernel directory from 'etc/pistachio.conf'
# or return a good heuristic
#
proc pistachio_kernel { } {
global _pistachio_kernel
if {![info exists _pistachio_kernel]} {
if {[file exists etc/pistachio.conf]} {
set _pistachio_kernel [exec sed -n "/^PISTACHIO_KERNEL/s/^.*=\\s*//p" etc/pistachio.conf]
if {$_pistachio_kernel == ""} {
set _pistachio_kernel [file dirname [file dirname [pistachio_user_dir]]]/kernel/build/x86-kernel
}
} else {
set _pistachio_kernel "[pwd]/bin/kernel"
}
}
return $_pistachio_kernel
}
##
# Return whether the kernel is provided from the outside
#
proc kernel_external { } {
if {[pistachio_kernel] == "[pwd]/bin/kernel"} { return 0 }
return 1
}
##################################
## Test framework API functions ##
##################################
proc create_boot_directory { } {
exec rm -rf [run_dir]
exec mkdir -p [run_dir]/genode
exec mkdir -p [run_dir]/pistachio
}
proc build_boot_image {binaries} {
#
# Collect contents of the ISO image
#
copy_and_strip_genode_binaries_to_run_dir $binaries
if {![kernel_external] && ![file exists [pistachio_kernel]]} { build { kernel } }
exec cp [pistachio_kernel] [run_dir]/pistachio/kernel
exec cp [pistachio_user_dir]/serv/sigma0/sigma0 [run_dir]/pistachio
exec cp [pistachio_user_dir]/util/kickstart/kickstart [run_dir]/pistachio
install_iso_bootloader_to_run_dir
#
# Generate grub config file
#
# The core binary is part of the 'binaries' list but it must
# appear right after 'sigma0' as boot module. Hence the special case.
#
set fh [open "[run_dir]/boot/grub/menu.lst" "WRONLY CREAT TRUNC"]
puts $fh "timeout 0"
puts $fh "default 0"
puts $fh "\ntitle Genode on L4ka::Pistachio"
puts $fh " kernel /pistachio/kickstart"
puts $fh " module /pistachio/kernel"
puts $fh " module /pistachio/sigma0"
puts $fh " module /genode/core"
puts $fh " module /genode/config"
foreach binary $binaries {
if {$binary != "core"} {
puts $fh " module /genode/$binary" } }
close $fh
#
# Install PXE bootloader pulsar
#
install_pxe_bootloader_to_run_dir
create_iso_image_from_run_dir
create_disk_image_from_run_dir
#
# Generate pulsar config file
#
set fh [open "[run_dir]/config-52-54-00-12-34-56" "WRONLY CREAT TRUNC"]
puts $fh " exec /boot/bender"
puts $fh " load /pistachio/kickstart"
puts $fh " load /pistachio/kernel"
puts $fh " load /pistachio/sigma0"
puts $fh " load /genode/core"
puts $fh " load /genode/config"
puts $fh " load /genode/config"
foreach binary $binaries {
if {$binary != "core"} {
puts $fh " load /genode/$binary" } }
close $fh
#
# Generate pulsar config file pointing to the config file above.
#
if {[info exists ::env(PXE_TFTP_DIR_BASE)] && [info exists ::env(PXE_TFTP_DIR_OFFSET)]} {
exec ln -nfs "[pwd]" "$::env(PXE_TFTP_DIR_BASE)$::env(PXE_TFTP_DIR_OFFSET)"
set tftp_base ""
if {[get_cmd_switch --tftp-absolute]} {
set tftp_base $::env(PXE_TFTP_DIR_BASE)
}
set fh [open "$::env(PXE_TFTP_DIR_BASE)$::env(PXE_TFTP_DIR_OFFSET)/config-00-00-00-00-00-00" "WRONLY CREAT TRUNC"]
puts $fh " root $tftp_base$::env(PXE_TFTP_DIR_OFFSET)/[run_dir]"
puts $fh " config config-52-54-00-12-34-56"
close $fh
}
}
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
}
#
# Try to use one of the supported backends for running the scripts
#
if {[is_amt_available]} {
spawn_amt $wait_for_re $timeout_value
return
}
if {[is_qemu_available]} {
spawn_qemu $wait_for_re $timeout_value
return
}
global run_target
puts stderr "Error: Can't execute automatically on target '$run_target'"
exit -1
}

View File

@ -238,13 +238,14 @@ RUN_SCRIPT = $(call select_from_repositories,run/$*.run)
run/%: $(call select_from_repositories,run/%.run) $(RUN_ENV)
$(VERBOSE)test -f "$(RUN_SCRIPT)" || (echo "Error: No run script for $*"; exit -1)
$(VERBOSE)$(GENODE_DIR)/tool/run --genode-dir $(GENODE_DIR) \
$(VERBOSE)$(GENODE_DIR)/tool/run/run --genode-dir $(GENODE_DIR) \
--name $* \
--specs "$(SPECS)" \
--repositories "$(REPOSITORIES)" \
--cross-dev-prefix "$(CROSS_DEV_PREFIX)" \
--qemu-args "$(QEMU_OPT)" \
--include $(RUN_ENV) $(RUN_OPT) \
$(RUN_OPT) \
--include $(RUN_ENV) \
--include $(RUN_SCRIPT)
##

1011
tool/run

File diff suppressed because it is too large Load Diff

141
tool/run/README Normal file
View File

@ -0,0 +1,141 @@
===================
The Genode run tool
===================
Introduction
############
The run tool is used to configure, build, and execute so-called run scripts.
These run scripts include a scenario or test-case of Genode components and
subsystems. Its core functionality is split into various modules to accommodate
a variety of different execution environments. These modules provide the
implementation of a given step in the sequence of execution of a run script.
These steps are:
* Building the corresponding components
* Wrapping the components in a format suitable for execution
* Preparing the target systems
* Executing the scenario
* Collecting any output
After the run script was executed successfully, the run tool will print the
string 'Run script execution successful.". This message can be used to check
for the successful completion of the run script when doing automated testing.
The categories of modules are formed by existing requirements such as automated
testing on a variety of different hardware platforms and are based
on the above-named steps:
:boot_dir:
These modules contain the functionality to populate the boot directory
and are specific to each kernel. It is mandatory to always include the
module corresponding to the used kernel.
:image modules:
These modules are used to wrap up all components used by the run script
in a specific format and thereby to prepare them for execution.
Depending on the used kernel, there are different formats. With these
modules, the creation of ISO and disk images is also handled.
:load modules:
These modules handle the way the components are transfered to the
target system. Depending on the used kernel there are various options
to pass on the components. Loading from TFTP or via JTAG is handled
by the modules of this category.
:log modules:
These modules handle how the output of a currently executed run script
is captured.
:power_on modules:
These modules are used for bringing the target system into an defined
state, e.g., by starting or rebooting the system.
:power_off modules:
These modules are used for turning the target system off after the
execution of a run script.
When executing a run script, only one module of each category must be used.
Usage
#####
To execute a run script a combination of modules may be used. The combination
is controlled via the RUN_OPT variable used by the build framework. Here are a
few common exemplary combinations:
Executing NOVA in Qemu:
!RUN_OPT = --include boot_dir/nova \
! --include exec/qemu --include log/qemu --include image/iso
Executing NOVA on a real x86 machine using AMT for resetting the target system
and for capturing the serial output while loading the files via TFTP:
!RUN_OPT = --include boot_dir/nova \
! --include power_on/amt --power-on-amt-host 10.23.42.13 \
! --power-on-amt-password 'foo!' \
! --include load/tftp --load-tftp-base-dir /var/lib/tftpboot \
! --load-tftp-offset-dir /x86 \
! --include log/amt --log-amt-host 10.23.42.13 \
! --log-amt-password 'foo!'
Executing fiasco.OC on a real x86 machine using AMT for resetting, USB serial
for output while loading the files via TFTP:
!RUN_OPT = --include boot_dir/foc \
! --include power_on/amt --amt-host 10.23.42.13 --amt-password 'foo!' \
! --include load/tftp --tftp-base-dir /var/lib/tftpboot \
! --tftp-offset-dir /x86 \
! --include log/serial --serial-cmd 'picocom -b 115200 /dev/ttyUSB0'
Executing hw on a rpi using powerplug to reset the hardware, JTAG to load the
image and USB serial to capture the output:
!RUN_OPT = --include boot_dir/hw \
! --include power_on/powerplug --power-on-powerplug-ip 10.23.42.5 \
! --power-on-powerplug-user admin \
! --power-on-powerplug-password secret \
! --power-on-powerplug-port 1
! --include power_off/powerplug --power-off-powerplug-ip 10.23.42.5 \
! --power-off-powerplug-user admin \
! --power-off-powerplug-password secret \
! --power-off-powerplug-port 1
! --include load/jtag \
! --load-jtag-debugger /usr/share/openocd/scripts/interface/flyswatter2.cfg \
! --load-jtag-board /usr/share/openocd/scripts/interface/raspberrypi.cfg \
! --include log/serial --log-serial-cmd 'picocom -b 115200 /dev/ttyUSB0'
Module overview
###############
A module consist of a expect/TCL source file located in one of the existing
directories of a category. It is named implicitly by its location and the
name of the source file, e.g. 'image/iso' is the name of the image module
that creates an ISO image.
The source file contains one mandatory procedure:
* run_<module> { <module-args> }
The procedure is called if the step at hand is executed by the
run tool. If its execution was successful, it returns true and
otherwise false. Certain modules may also call exit on failure.
A module may have arguments, which are by convention prefixed with the name
of the source file, e.g. 'power_on/amt' may have an argument called
'--power-on-amt-host'. If the argument passes on a value the value must be
made accessible by calling an equally named procedure, e.g.
'--power-on-amt-host' becomes 'proc amt_host { }'.
Thereby a run script or a run environment can access the value of the argument
in a defined way without the use of a global variable by using
'[power_on_amt_host]'. Also arguments without a value may be queried in this
way. '--image-uboot-gzip' becomes '[image_uboot_use_gzip]'.
In addition to these procedures, a module may have any number of public
procedures. They may be used after the presence of the particular module that
contains them is verified. For this reason the run tool provides a procedure
called 'have_include', that performs this check. For example the presence of
the 'load/tftp' module is checked by calling '[have_include "load/tftp"]'.

28
tool/run/amt.inc Normal file
View File

@ -0,0 +1,28 @@
##
# Check whether AMT support is available
#
proc is_amt_available { {host "" } {password "" } } {
if {![have_spec x86]} { return false }
#
# Exit execution if parameter are not set rather returning
# false because we cannot recover anyway.
#
if {[string compare $host ""] == 0} {
puts "Aborting, AMT host not specified."
exit -1
}
if {[string compare $password ""] == 0} {
puts "Aborting, AMT password not set."
exit -1
}
if {[have_installed amtterm] &&
[expr [have_installed amttool] || [have_installed wsman] ] } {
return true
}
puts "No support for Intel's AMT detected."
return false
}

View File

@ -1,10 +1,3 @@
#
# \brief Codezero-specific test-environment supplements
# \author Norman Feske
# \date 2011-08-05
#
# This file is meant to be used as '--include' argument for 'tool/run'.
#
##
@ -34,21 +27,10 @@ proc exec_sh { command } {
}
##################################
## Test framework API functions ##
##################################
proc create_boot_directory { } {
# create only intermediate directries hosting the run directory
exec mkdir -p [run_dir]
exec rm -rf [run_dir]
exec mkdir -p [run_dir]/genode
}
proc build_boot_image {binaries} {
##
# Populate boot directory with binaries on codezero
#
proc run_boot_dir {binaries} {
if {![file exists kernel]} { build kernel }
@ -81,26 +63,3 @@ proc build_boot_image {binaries} {
# copy result to [run_dir]/image.elf (to be picked up by spawn_qemu)
exec_sh "cp [kernel_dir]/build/final.elf [run_dir]/image.elf"
}
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
}
#
# Try to use one of the supported backends for running the scripts
#
if {[is_qemu_available]} {
spawn_qemu $wait_for_re $timeout_value
return
}
global run_target
puts stderr "Error: Can't execute automatically on target '$run_target'"
exit -1
}

142
tool/run/boot_dir/fiasco Normal file
View File

@ -0,0 +1,142 @@
##
# Read the location of the Fiasco user directory from 'etc/fiasco.conf'
#
proc l4_dir { } {
global _l4_dir
if {![info exists _l4_dir]} {
if {[file exists etc/fiasco.conf]} {
set _l4_dir [exec sed -n "/^L4_BUILD_DIR/s/^.*=\\s*//p" etc/fiasco.conf]
if {[file exists $_l4_dir]} { return $_l4_dir }
}
set _l4_dir "[pwd]/l4"
if {![file exists $_l4_dir]} {
puts -nonewline stderr "Error: Could neither find the L4 build directory "
puts -nonewline stderr "within '<genode-build-dir>/l4' nor at a location "
puts -nonewline stderr "specified via 'L4_BUILD_DIR = <l4v2-build-dir>' "
puts stderr "in <genode-build-dir>/etc/fiasco.conf'."
exit 1
}
}
return $_l4_dir
}
##
# Return whether the l4-buid-directory is provided from the outside
#
proc l4_dir_external { } {
if {[l4_dir] == "[pwd]/l4"} { return 0 }
return 1
}
##
# Return the location of the Fiasco kernel
#
proc fiasco { } {
return [kernel_location_from_config_file etc/fiasco.conf [pwd]/kernel/fiasco/fiasco]
}
##
# Return whether fiasco kernel is provided from the outside
#
proc fiasco_external { } {
if {[fiasco] == "[pwd]/kernel/fiasco/fiasco"} { return 0 }
return 1
}
proc bin_dir { } {
if {[have_spec x86_32]} { return "[l4_dir]/bin/x86_586" }
puts stderr "Error: Cannot determine bin directory"
exit 1
}
set fiasco_serial_esc_arg "-serial_esc "
##
# Populate boot directory with binaries on fiasco
#
proc run_boot_dir {binaries} {
global fiasco_serial_esc_arg
exec mkdir -p [run_dir]/fiasco
#
# Collect contents of the ISO image
#
copy_and_strip_genode_binaries_to_run_dir $binaries
if {![fiasco_external]} { build { kernel } }
if {![l4_dir_external]} { build { bootstrap sigma0 } }
# assert existence of the L4 build directory
l4_dir
puts "using fiasco kernel [fiasco]"
exec cp [fiasco] [run_dir]/fiasco/fiasco
puts "using sigma0/bootstrap at [l4_dir]"
exec cp [bin_dir]/l4v2/sigma0 [run_dir]/fiasco
exec cp [bin_dir]/bootstrap [run_dir]/fiasco
if {[have_include "image/iso"] || [have_include "image/disk"]} {
#
# Install isolinux/GRUB files and bender
#
install_iso_bootloader_to_run_dir
#
# Generate GRUB config file
#
# The core binary is part of the 'binaries' list but it must
# appear right after 'sigma0' as boot module. Hence the special case.
#
set fh [open "[run_dir]/boot/grub/menu.lst" "WRONLY CREAT TRUNC"]
puts $fh "timeout 0"
puts $fh "default 0"
puts $fh "\ntitle Genode on L4/Fiasco"
puts $fh " kernel /boot/bender"
puts $fh " module /fiasco/bootstrap -serial -modaddr=0x02000000"
puts $fh " module /fiasco/fiasco -serial -jdb_cmd=JH $fiasco_serial_esc_arg"
puts $fh " module /fiasco/sigma0"
puts $fh " module /genode/core"
puts $fh " module /genode/config"
foreach binary $binaries {
if {$binary != "core"} {
puts $fh " module /genode/$binary" } }
puts $fh " vbeset 0x117 506070"
close $fh
}
run_image
if {[have_include "load/tftp"]} {
#
# Install PXE bootloader pulsar
#
install_pxe_bootloader_to_run_dir
#
# Generate pulsar config file
#
set fh [open "[run_dir]/config-52-54-00-12-34-56" "WRONLY CREAT TRUNC"]
puts $fh " exec /boot/bender"
puts $fh " load /fiasco/bootstrap -serial -modaddr=0x02000000"
puts $fh " load /fiasco/fiasco -serial -serial_esc -jdb_cmd=JH"
puts $fh " load /fiasco/sigma0"
puts $fh " load /genode/core"
puts $fh " load /genode/config"
foreach binary $binaries {
if {$binary != "core"} {
puts $fh " load /genode/$binary" } }
close $fh
generate_tftp_config
}
}

View File

@ -6,14 +6,6 @@
# This file is meant to be used as '--include' argument for 'tool/run'.
#
##
# Install files needed to boot via PXE
#
proc install_pxe_bootloader_to_run_dir { } {
exec cp [genode_dir]/tool/boot/pulsar [run_dir]/boot/pulsar
exec cp [genode_dir]/tool/boot/bender [run_dir]/boot/bender
}
##
# Return the location of the Fiasco.OC user directory
#
@ -83,20 +75,6 @@ proc reset_target { {spawn_id_arg -1} } {
send -i $spawn_id_arg "\033^^"
}
##################################
## Test framework API functions ##
##################################
proc create_boot_directory { } {
exec rm -rf [run_dir]
exec mkdir -p [run_dir]/genode
if {[have_spec x86]} {
exec mkdir -p [run_dir]/fiasco
exec mkdir -p [run_dir]/boot/grub
}
}
proc copy_and_strip_binaries {binaries} {
@ -108,10 +86,6 @@ proc copy_and_strip_binaries {binaries} {
catch {
exec [cross_dev_prefix]strip [run_dir]/genode/$binary }
}
#
# Generate config file for bootstrap
#
}
@ -126,10 +100,12 @@ proc bin_dir { } {
set fiasco_serial_esc_arg "-serial_esc "
proc build_boot_image_x86 {binaries} {
proc run_boot_dir_x86 {binaries} {
global fiasco_serial_esc_arg
exec mkdir -p [run_dir]/fiasco
copy_and_strip_binaries $binaries
set foc_targets { }
@ -149,6 +125,10 @@ proc build_boot_image_x86 {binaries} {
exec cp [bin_dir]/l4f/sigma0 [run_dir]/fiasco
exec cp [bin_dir]/bootstrap [run_dir]/fiasco
if {[have_include "image/iso"] || [have_include "image/disk"]} {
#
# Install isolinux/GRUB files and bender
#
install_iso_bootloader_to_run_dir
#
@ -172,10 +152,18 @@ proc build_boot_image_x86 {binaries} {
puts $fh " module /genode/$binary" } }
puts $fh " vbeset 0x117 506070"
close $fh
}
#
# Build image
#
run_image
if {[have_include "load/tftp"]} {
#
# Install PXE bootloader pulsar
#
install_pxe_bootloader_to_run_dir
create_iso_image_from_run_dir
create_disk_image_from_run_dir
#
# Generate pulsar config file
@ -192,26 +180,12 @@ proc build_boot_image_x86 {binaries} {
puts $fh " load /genode/$binary" } }
close $fh
#
# Generate pulsar config file pointing to the config file above.
#
if {[info exists ::env(PXE_TFTP_DIR_BASE)] && [info exists ::env(PXE_TFTP_DIR_OFFSET)]} {
exec ln -nfs "[pwd]" "$::env(PXE_TFTP_DIR_BASE)$::env(PXE_TFTP_DIR_OFFSET)"
set tftp_base ""
if {[get_cmd_switch --tftp-absolute]} {
set tftp_base $::env(PXE_TFTP_DIR_BASE)
}
set fh [open "$::env(PXE_TFTP_DIR_BASE)$::env(PXE_TFTP_DIR_OFFSET)/config-00-00-00-00-00-00" "WRONLY CREAT TRUNC"]
puts $fh " root $tftp_base$::env(PXE_TFTP_DIR_OFFSET)/[run_dir]"
puts $fh " config config-52-54-00-12-34-56"
close $fh
generate_tftp_config
}
}
proc build_boot_image_arm {binaries} {
proc run_boot_dir_arm {binaries} {
global run_target
global fiasco_serial_esc_arg
@ -249,53 +223,27 @@ proc build_boot_image_arm {binaries} {
}
exec cp [bin_dir]/bootstrap.elf [run_dir]/image.elf
build_uboot_image [run_dir]/image.elf
run_image [run_dir]/image.elf
puts "\nboot image: [run_dir]/image.elf\n"
# set symbolic link to image.elf file in TFTP directory for PXE boot
if {[info exists ::env(PXE_TFTP_DIR_BASE)] &&
[info exists ::env(PXE_TFTP_DIR_OFFSET)]} {
exec ln -sf "[pwd]/[run_dir]/image.elf" "$::env(PXE_TFTP_DIR_BASE)$::env(PXE_TFTP_DIR_OFFSET)"
if {[regexp "uboot" $run_target]} {
exec ln -sf "[pwd]/[run_dir]/uImage" "$::env(PXE_TFTP_DIR_BASE)$::env(PXE_TFTP_DIR_OFFSET)/uImage"
if {[have_include "load/tftp"]} {
set tftp_base_dir [load_tftp_base_dir]
set tftp_offset_dir [load_tftp_offset_dir]
exec ln -sf [pwd]/[run_dir]/image.elf $tftp_base_dir$tftp_offset_dir
if {[have_include "image/uboot"]} {
exec ln -sf [pwd]/[run_dir]/uImage $tftp_base_dir$tftp_offset_dir/uImage
}
}
}
proc build_boot_image {binaries} {
if {[have_spec x86]} { return [build_boot_image_x86 $binaries] }
if {[have_spec arm]} { return [build_boot_image_arm $binaries] }
}
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
}
#
# Try to use one of the supported backends for running the scripts
#
if {[is_amt_available]} {
spawn_amt $wait_for_re $timeout_value
return
}
if {[is_qemu_available]} {
spawn_qemu $wait_for_re $timeout_value
return
}
if {[is_serial_available]} {
spawn_serial $wait_for_re $timeout_value "L4 Bootstrapper"
return
}
global run_target
puts stderr "Error: Can't execute automatically on target '$run_target'"
exit -1
##
# Populate boot directory with binaries on fiasco.OC
#
proc run_boot_dir {binaries} {
if {[have_spec x86]} { return [run_boot_dir_x86 $binaries] }
if {[have_spec arm]} { return [run_boot_dir_arm $binaries] }
}

View File

@ -1,58 +1,19 @@
#!/usr/bin/expect
#
# \brief Implementation of the 'tool/run' interface
# \author Martin Stein
# \date 2011-12-16
#
###############
## Utilities ##
###############
#
##
# Ensure that the next Genode build includes no target specific boot modules
#
proc clean_boot_modules { } {
exec rm -rf boot_modules.s var/libcache/boot_modules/boot_modules.o }
##########################
## 'tool/run' interface ##
##########################
proc build {targets} {
# skip targets that shall not be build
if {[get_cmd_switch --skip-build]} return
# handle false remnants of previous builds
proc run_boot_dir_hook { } {
clean_boot_modules
#
# Build all remaining targets.
# Core is build with a dummy boot-modules file first.
#
regsub -all {\s\s+} $targets " " targets
set timeout 10000
set pid [eval "spawn make $targets"]
expect { eof { } }
if {[lindex [wait $pid] end] != 0} {
puts stderr "Error: Genode build failed"
exit -1
}
}
proc create_boot_directory { } {
exec rm -rf [run_dir]
exec mkdir -p [run_dir]/genode
}
proc build_boot_image {binaries {core_type core}} {
##
# Populate boot directory with binaries on hw
#
proc run_boot_dir {binaries {core_type core}} {
if {$core_type == "test"} {
set core_bin "test-[run_name]"
set core_target "test/[run_name]"
@ -90,7 +51,7 @@ proc build_boot_image {binaries {core_type core}} {
exec echo -e \
"/**" \
"\n * This file was automatically generated by the procedure" \
"\n * 'build_boot_image' in 'base-hw/run/env'." \
"\n * 'run_boot_dir' in 'base-hw/run/env'." \
"\n */" \
"\n" \
"\n /* core includes */" \
@ -176,15 +137,14 @@ proc build_boot_image {binaries {core_type core}} {
exec cp -L bin/$core_bin $elf_img
exec [cross_dev_prefix]strip $elf_img
build_uboot_image $elf_img
run_image $elf_img
# set symbolic link to image.elf file in TFTP directory for PXE boot
if {[info exists ::env(PXE_TFTP_DIR_BASE)] &&
[info exists ::env(PXE_TFTP_DIR_OFFSET)]} {
exec ln -sf "[pwd]/$elf_img" "$::env(PXE_TFTP_DIR_BASE)$::env(PXE_TFTP_DIR_OFFSET)"
if {[have_include "load/tftp"]} {
exec ln -sf [pwd]/$elf_img [load_tftp_base_dir][load_tftp_offset_dir]
if {[regexp "uboot" $run_target]} {
exec ln -sf "[pwd]/[run_dir]/uImage" "$::env(PXE_TFTP_DIR_BASE)$::env(PXE_TFTP_DIR_OFFSET)"
if {[have_include "image/uboot"]} {
exec ln -sf [pwd]/[run_dir]/uImage [load_tftp_base_dir][load_tftp_offset_dir]
}
}
@ -192,31 +152,3 @@ proc build_boot_image {binaries {core_type core}} {
exec cp $core_target/$core_bin.standalone bin/$core_bin
exec rm $core_target/$core_bin.standalone
}
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
}
#
# Try to use one of the supported backends for running the scripts
#
if {[is_qemu_available]} {
spawn_qemu $wait_for_re $timeout_value
return
}
if {[is_serial_available]} {
spawn_serial $wait_for_re $timeout_value "kernel initialized"
return
}
global run_target
puts stderr "Error: Can't execute automatically on target '$run_target'"
exit -1
}

7
tool/run/boot_dir/linux Normal file
View File

@ -0,0 +1,7 @@
##
# Populate boot directory with binaries on Linux
#
proc run_boot_dir {binaries} {
foreach binary $binaries {
exec ln -sf ../../../../bin/$binary [run_dir]/genode }
}

90
tool/run/boot_dir/nova Normal file
View File

@ -0,0 +1,90 @@
##
# Read the location of the NOVA kernel directory from 'etc/nova.conf'
#
proc nova_kernel { } {
global _nova_kernel
if {![info exists _nova_kernel]} {
if {[file exists etc/nova.conf]} {
set _nova_kernel [exec sed -n "/^NOVA_KERNEL/s/^.*=\\s*//p" etc/nova.conf]
} else {
set _nova_kernel "[pwd]/kernel/hypervisor"
}
}
return $_nova_kernel
}
##
# Return whether nova is provided from the outside
#
proc nova_external { } {
if {[nova_kernel] == "[pwd]/kernel/hypervisor"} { return 0 }
return 1
}
##
# Populate directory with binaries on NOVA
#
proc run_boot_dir {binaries} {
#
# Collect contents of the ISO image
#
copy_and_strip_genode_binaries_to_run_dir $binaries
if {![nova_external] && ![file exists [nova_kernel]]} { build { kernel } }
puts "using NOVA kernel at [nova_kernel]"
exec [cross_dev_prefix]objcopy -O elf32-i386 [nova_kernel] [run_dir]/hypervisor
if {[have_include "image/iso"] || [have_include "image/disk"]} {
#
# Install isolinux/GRUB files and bender
#
install_iso_bootloader_to_run_dir
#
# Generate GRUB config file
#
set fh [open "[run_dir]/boot/grub/menu.lst" "WRONLY CREAT TRUNC"]
puts $fh "timeout 0"
puts $fh "default 0"
puts $fh "\ntitle Genode on NOVA"
puts $fh " kernel /boot/bender"
puts $fh " module /hypervisor iommu serial novpid"
puts $fh " module /genode/core"
puts $fh " module /genode/config"
foreach binary $binaries {
if {$binary != "core"} {
puts $fh " module /genode/$binary" } }
close $fh
}
#
# Build image
#
run_image
if {[have_include "load/tftp"]} {
#
# Install PXE bootloader pulsar
#
install_pxe_bootloader_to_run_dir
#
# Generate pulsar config file
#
set fh [open "[run_dir]/config-52-54-00-12-34-56" "WRONLY CREAT TRUNC"]
puts $fh " exec /boot/bender"
puts $fh " load /hypervisor iommu serial novpid"
puts $fh " load /genode/core"
puts $fh " load /genode/config"
foreach binary $binaries {
if {$binary != "core"} {
puts $fh " load /genode/$binary" } }
close $fh
generate_tftp_config
}
}

View File

@ -1,24 +1,9 @@
#
# \brief OKL4-specific test-environment supplements
# \author Norman Feske
# \date 2010-08-16
#
# This file is meant to be used as '--include' argument for 'tool/run'.
#
##
# Install files needed to boot via PXE
#
proc install_pxe_bootloader_to_run_dir { } {
exec cp [genode_dir]/tool/boot/pulsar [run_dir]/boot/pulsar
exec cp [genode_dir]/tool/boot/bender [run_dir]/boot/bender
}
##
# Get the base-okl4 repository
#
proc base_okl4_dir {} { return [repository_contains mk/spec-okl4.mk] }
##
# Read the location of the OKL4 directory from 'etc/okl4.conf'
#
@ -37,6 +22,7 @@ proc okl4_dir { } {
return $_okl4_dir
}
##
# Return the location of the OKL4 kernel
#
@ -45,6 +31,7 @@ proc okl4 { } {
return bin/kernel
}
##
# Return whether okl4 kernel is provided from the outside
#
@ -53,15 +40,6 @@ proc okl4_external { } {
return 1
}
##################################
## Test framework API functions ##
##################################
proc create_boot_directory { } {
exec rm -rf [run_dir]
exec mkdir -p [run_dir]/genode
}
set weaver_xml_template {
<machine>
@ -122,7 +100,11 @@ set weaver_xml_template {
<rootprogram file="core" virtpool="virtual" physpool="physical" />
}
proc build_boot_image {binaries} {
##
# Populate directory with binaries on OKL4
#
proc run_boot_dir {binaries} {
global weaver_xml_template
#
@ -179,16 +161,12 @@ proc build_boot_image {binaries} {
#
exec rm -r [run_dir]/genode
if {[have_include "image/iso"] || [have_include "image/disk"]} {
#
# Install GRUB
#
install_iso_bootloader_to_run_dir
#
# Install PXE bootloader pulsar
#
install_pxe_bootloader_to_run_dir
#
# Generate grub config file
#
@ -204,9 +182,18 @@ proc build_boot_image {binaries} {
puts $fh " module /image.elf"
puts $fh " vbeset 0x117"
close $fh
}
create_iso_image_from_run_dir
create_disk_image_from_run_dir
#
# Build image
#
run_image
if {[have_include "load/tftp"]} {
#
# Install PXE bootloader pulsar
#
install_pxe_bootloader_to_run_dir
#
# Generate pulsar config file
@ -218,47 +205,6 @@ proc build_boot_image {binaries} {
puts $fh " load /image.elf"
close $fh
#
# Generate pulsar config file pointing to the config file above.
#
if {[info exists ::env(PXE_TFTP_DIR_BASE)] && [info exists ::env(PXE_TFTP_DIR_OFFSET)]} {
exec ln -nfs "[pwd]" "$::env(PXE_TFTP_DIR_BASE)$::env(PXE_TFTP_DIR_OFFSET)"
set tftp_base ""
if {[get_cmd_switch --tftp-absolute]} {
set tftp_base $::env(PXE_TFTP_DIR_BASE)
}
set fh [open "$::env(PXE_TFTP_DIR_BASE)$::env(PXE_TFTP_DIR_OFFSET)/config-00-00-00-00-00-00" "WRONLY CREAT TRUNC"]
puts $fh " root $tftp_base$::env(PXE_TFTP_DIR_OFFSET)/[run_dir]"
puts $fh " config config-52-54-00-12-34-56"
close $fh
generate_tftp_config
}
}
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
}
#
# Try to use one of the supported backends for running the scripts
#
if {[is_amt_available]} {
spawn_amt $wait_for_re $timeout_value
return
}
if {[is_qemu_available]} {
spawn_qemu $wait_for_re $timeout_value
return
}
global run_target
puts stderr "Error: Can't execute automatically on target '$run_target'"
exit -1
}

140
tool/run/boot_dir/pistachio Normal file
View File

@ -0,0 +1,140 @@
#
# \brief Pistachio-specific test-environment supplements
# \author Norman Feske
# \date 2010-08-25
#
# This file is meant to be used as '--include' argument for 'tool/run'.
#
##
# Install files needed to boot via PXE
#
proc install_pxe_bootloader_to_run_dir { } {
exec cp [genode_dir]/tool/boot/pulsar [run_dir]/boot/pulsar
exec cp [genode_dir]/tool/boot/bender [run_dir]/boot/bender
}
##
# Read the location of the Pistachio user directory from 'etc/pistachio.conf'
#
proc pistachio_user_dir { } {
global _pistachio_user_dir
if {![info exists _pistachio_user_dir]} {
if {[file exists etc/pistachio.conf]} {
set _pistachio_user_dir [exec sed -n "/^PISTACHIO_USER_BUILD_DIR/s/^.*=\\s*//p" etc/pistachio.conf]
} else {
set _pistachio_user_dir "[pwd]/l4"
}
}
return $_pistachio_user_dir
}
##
# Read the location of the Pistachio kernel directory from 'etc/pistachio.conf'
# or return a good heuristic
#
proc pistachio_kernel { } {
global _pistachio_kernel
if {![info exists _pistachio_kernel]} {
if {[file exists etc/pistachio.conf]} {
set _pistachio_kernel [exec sed -n "/^PISTACHIO_KERNEL/s/^.*=\\s*//p" etc/pistachio.conf]
if {$_pistachio_kernel == ""} {
set _pistachio_kernel [file dirname [file dirname [pistachio_user_dir]]]/kernel/build/x86-kernel
}
} else {
set _pistachio_kernel "[pwd]/bin/kernel"
}
}
return $_pistachio_kernel
}
##
# Return whether the kernel is provided from the outside
#
proc kernel_external { } {
if {[pistachio_kernel] == "[pwd]/bin/kernel"} { return 0 }
return 1
}
##
# Populdate boot directory with binaries on pistachio
#
proc run_boot_dir {binaries} {
exec mkdir -p [run_dir]/pistachio
#
# Collect contents of the ISO image
#
copy_and_strip_genode_binaries_to_run_dir $binaries
if {![kernel_external] && ![file exists [pistachio_kernel]]} { build { kernel } }
exec cp [pistachio_kernel] [run_dir]/pistachio/kernel
exec cp [pistachio_user_dir]/serv/sigma0/sigma0 [run_dir]/pistachio
exec cp [pistachio_user_dir]/util/kickstart/kickstart [run_dir]/pistachio
if {[have_include "image/iso"] || [have_include "image/disk"]} {
#
# Install isolinux/GRUB files and bender
#
install_iso_bootloader_to_run_dir
#
# Generate grub config file
#
# The core binary is part of the 'binaries' list but it must
# appear right after 'sigma0' as boot module. Hence the special case.
#
set fh [open "[run_dir]/boot/grub/menu.lst" "WRONLY CREAT TRUNC"]
puts $fh "timeout 0"
puts $fh "default 0"
puts $fh "\ntitle Genode on L4ka::Pistachio"
puts $fh " kernel /pistachio/kickstart"
puts $fh " module /pistachio/kernel"
puts $fh " module /pistachio/sigma0"
puts $fh " module /genode/core"
puts $fh " module /genode/config"
foreach binary $binaries {
if {$binary != "core"} {
puts $fh " module /genode/$binary" } }
close $fh
}
#
# Build image
#
run_image
if {[have_include "load/tftp"]} {
#
# Install PXE bootloader pulsar
#
install_pxe_bootloader_to_run_dir
#
# Generate pulsar config file
#
set fh [open "[run_dir]/config-52-54-00-12-34-56" "WRONLY CREAT TRUNC"]
puts $fh " exec /boot/bender"
puts $fh " load /pistachio/kickstart"
puts $fh " load /pistachio/kernel"
puts $fh " load /pistachio/sigma0"
puts $fh " load /genode/core"
puts $fh " load /genode/config"
puts $fh " load /genode/config"
foreach binary $binaries {
if {$binary != "core"} {
puts $fh " load /genode/$binary" } }
close $fh
generate_tftp_config
}
}

49
tool/run/image/disk Normal file
View File

@ -0,0 +1,49 @@
##
# Create disk image with contents of the run directory
#
# \param --image-disk-size disk size in MiB
#
source [genode_dir]/tool/run/iso.inc
proc image_disk_size { } { return [get_cmd_arg --image-disk-size 0] }
##
# Create disk image with the content of the run directory
#
proc run_image { {unused ""} } {
requires_installation_of parted
requires_installation_of resize2fs
requires_installation_of fallocate
set grub_img "[genode_dir]/tool/grub2-head.img"
set disk_img "[run_dir].img"
set part1_img "[run_dir]-part1.img"
set run_size [expr [regsub {\s.*} [exec du -sm [run_dir]] {}] + 4]
if {[image_disk_size] > 0} {
set disk_size [image_disk_size]
} else {
set disk_size $run_size
}
set part1_size [expr $disk_size - 1]MiB
# extract and resize partition image
exec dd if=$grub_img of=$part1_img bs=1M skip=1 2>/dev/null
exec fallocate -l $part1_size $part1_img
exec resize2fs $part1_img 2>/dev/null
# populate partition with binaries
exec [genode_dir]/tool/rump -F ext2fs -p [run_dir] $part1_img
# merge final image from GRUB2 head and partition
exec dd if=$grub_img of=$disk_img status=noxfer bs=1M count=1 2>/dev/null
exec dd if=$part1_img of=$disk_img status=noxfer bs=1M seek=1 2>/dev/null
exec parted -s $disk_img -- rm 1 mkpart primary 2048s -1s set 1 boot on
exec rm -f $part1_img
puts "Created image file $disk_img ($disk_size MiB)"
}

20
tool/run/image/iso Normal file
View File

@ -0,0 +1,20 @@
source [genode_dir]/tool/run/iso.inc
##
# Create ISO image with the content of the run directory
#
proc run_image { {unused ""} } {
puts "creating ISO image..."
exec rm -f "[run_dir].iso"
#
# The 'create_iso' writes diagnostics to stderr, which are interpreted as
# execution failure by expect unless '-ignorestderr' is set on 'exec'.
#
if {[catch {exec -ignorestderr [genode_dir]/tool/create_iso iso ISO=[run_dir]} ]} {
puts stderr "Error: ISO image creation failed"
exit -5
}
}

47
tool/run/image/uboot Normal file
View File

@ -0,0 +1,47 @@
##
# Build U-boot bootloader specific uImage
#
# \param --image-uboot-no-gzip do not gzip the uImage
#
##
# Check if the uImage should be gzipped
#
proc image_uboot_use_no_gzip { } { return [get_cmd_switch --image-uboot-no-gzip] }
##
# Build U-boot bootloader specific uImage
#
# \param elf_img ELF binary to build uImage from
#
proc run_image {elf_img} {
# parse ELF entrypoint and load address
set entrypoint [exec [cross_dev_prefix]readelf -h $elf_img | \
grep "Entry point address: " | \
sed -e "s/.*Entry point address: *//"]
set load_addr [exec [cross_dev_prefix]readelf -l $elf_img | \
grep -m 1 "LOAD"]
set load_addr [lindex [regexp -inline -all -- {\S+} $load_addr] 3]
set bin_img "[run_dir]/image.bin"
exec [cross_dev_prefix]objcopy -O binary $elf_img $bin_img
set use_gzip [expr ![image_uboot_use_no_gzip]]
set compress_type none
set bin_ext ""
# compress ELF
if $use_gzip {
exec gzip --best --force $bin_img
set bin_ext .gz
set compress_type gzip
}
# create uImage
set uboot_img [run_dir]/uImage
exec mkimage -A arm -O linux -T kernel -C $compress_type -a $load_addr \
-e $entrypoint -d $bin_img$bin_ext $uboot_img
exec rm -rf $bin_img$bin_ext
}

20
tool/run/iso.inc Normal file
View File

@ -0,0 +1,20 @@
##
# Install files needed to create a bootable ISO image
#
# The ISO boot concept uses isolinux to load GRUB, which in turn loads Genode.
# This way we can make use of isolinux' support for booting ISO images from a
# USB stick.
#
proc install_iso_bootloader_to_run_dir { } {
puts "install bootloader"
exec mkdir -p [run_dir]/boot/isolinux
exec cp [genode_dir]/tool/boot/chain.c32 [run_dir]/boot/isolinux
exec cp [genode_dir]/tool/boot/isolinux.bin [run_dir]/boot/isolinux
exec cp [genode_dir]/tool/boot/isolinux.cfg [run_dir]/boot/isolinux
exec mkdir -p [run_dir]/boot/grub
exec cp [genode_dir]/tool/boot/stage2_eltorito [run_dir]/boot/grub
exec cp [genode_dir]/tool/boot/bender [run_dir]/boot/bender
}

7
tool/run/load.inc Normal file
View File

@ -0,0 +1,7 @@
##
# Get the spawn_id of the load process
#
proc load_spawn_id { } {
global load_spawn_id
return $load_spawn_id
}

52
tool/run/load/jtag Normal file
View File

@ -0,0 +1,52 @@
##
# Load image to target hardware via JTAG
#
# \param --load-jtag-debugger Debugger used
# \param --load-jtag-board Set the used board
#
source [genode_dir]/tool/run/load.inc
proc load_jtag_debugger { } { return [get_cmd_arg --load-jtag-debugger 1] }
proc load_jtag_board { } { return [get_cmd_arg --load-jtag-board 1] }
proc run_load { } {
global load_spawn_id
if {![have_spec arm] || ![have_installed openocd]} {
puts "No support for JTAG detected."
exit -1
}
set debugger [load_jtag_debugger]
set board [load_jtag_board]
set elf_img "[run_dir]/image.elf"
# sleep a bit, board might need some time to come up
sleep 8
# parse ELF entrypoint
set entrypoint [exec [cross_dev_prefix]readelf -h $elf_img | \
grep "Entry point address: " | \
sed -e "s/.*Entry point address: *//"]
eval spawn openocd -f $debugger -f $board -c init -c halt \
-c \"load_image $elf_img\" -c \"resume $entrypoint\"
set load_spawn_id $spawn_id
set timeout 360
expect {
"downloaded" { return true; }
eof {
puts stderr "openocd command process died unexpectedly";
return false;
}
timeout {
puts stderr "Loading timed out";
return false;
}
}
}

64
tool/run/load/tftp Normal file
View File

@ -0,0 +1,64 @@
##
# Load files needed by the scenario via TFTP
#
# \param --load-tftp-base-dir base directory of TFTP
# \param --load-tftp-offset-dir offset directory within TFTP
# \param --load-tftp-absolute path is absolute, i.e. /base_dir/offset_dir
# instead of only /offset_dir is used
#
source [genode_dir]/tool/run/load.inc
##
# The files are loaded implicitly via TFTP to the target machine
#
proc run_load { } {
global load_spawn_id
set load_spawn_id -1
return true
}
proc load_tftp_base_dir { } { return [get_cmd_arg --load-tftp-base-dir ""] }
proc load_tftp_offset_dir { } { return [get_cmd_arg --load-tftp-offset-dir ""] }
proc load_tftp_use_absolute { } { return [get_cmd_switch --load-tftp-absolute] }
##
# Install files needed to boot via PXE
#
proc install_pxe_bootloader_to_run_dir { } {
exec mkdir -p [run_dir]/boot
exec cp [genode_dir]/tool/boot/pulsar [run_dir]/boot/pulsar
exec cp [genode_dir]/tool/boot/bender [run_dir]/boot/bender
}
##
# Generate pulsar config file used for loading files from TFTP
#
proc generate_tftp_config { } {
set tftp_base_dir [load_tftp_base_dir]
set tftp_offset_dir [load_tftp_offset_dir]
if {[string length $tftp_base_dir] > 0 && [string length $tftp_offset_dir] > 0} {
exec ln -nfs "[pwd]" "$tftp_base_dir$tftp_offset_dir"
set tftp_base ""
if {[load_tftp_use_absolute]} {
set tftp_base $tftp_base_dir
}
set fh [open "$tftp_base_dir$tftp_offset_dir/config-00-00-00-00-00-00" "WRONLY CREAT TRUNC"]
puts $fh " root $tftp_base$tftp_offset_dir/[run_dir]"
puts $fh " config config-52-54-00-12-34-56"
close $fh
} else {
puts "Warning, TFTP base directory or TFTP offset directory not set."
}
}

7
tool/run/log.inc Normal file
View File

@ -0,0 +1,7 @@
##
# Get the spawn_id of the output process
#
proc output_spawn_id { } {
global output_spawn_id
return $output_spawn_id
}

70
tool/run/log/amt Normal file
View File

@ -0,0 +1,70 @@
##
# Get output of the target machine via Intel AMT's SoL feature
#
# \param --amt-host IP address of target machine
# \param --amt-password AMT password for target machine
#
source [genode_dir]/tool/run/log.inc
source [genode_dir]/tool/run/amt.inc
proc log_amt_host { } {
return [get_cmd_arg_first --log-amt-host ""]
}
proc log_amt_password { } {
return [get_cmd_arg_first --log-amt-password ""]
}
##
# Log output of the test machine using Intel's AMT
#
proc run_log { wait_for_re timeout_value } {
global output_spawn_id
if {![is_amt_available [log_amt_host] [log_amt_password]]} {
set exit_result 1
return false
}
#
# grab output
#
set amtterm "amtterm -u admin -p [log_amt_password] -v [log_amt_host]"
if {$wait_for_re == "forever"} {
set timeout -1
} else {
set timeout [expr $timeout_value + 30]
}
set exit_result 1
while { $exit_result != 0 } {
set time_start [ clock seconds ]
eval spawn $amtterm
set output_spawn_id $spawn_id
expect {
-i $output_spawn_id -re $wait_for_re { break }
eof { continue }
timeout { puts "Error: Test execution timed out"; exit -2 }
}
catch wait result
set time_end [ clock seconds ]
if {[expr $time_end - $time_start] <= 1} {
incr timeout -1
} else {
incr timeout [expr -1 * ($time_end - $time_start)]
}
if {$timeout < 0} {
set timeout 0
}
set exit_result [lindex $result 3]
}
global output
set output $expect_out(buffer)
return true
}

11
tool/run/log/linux Normal file
View File

@ -0,0 +1,11 @@
source [genode_dir]/tool/run/log.inc
proc run_log { wait_for_re timeout_value } {
global linux_spawn_id
global output_spawn_id
set output_spawn_id $linux_spawn_id
wait_for_output $wait_for_re $timeout_value $linux_spawn_id
return true
}

17
tool/run/log/qemu Normal file
View File

@ -0,0 +1,17 @@
##
# Capture the output of a scenario executed via Qemu
#
source [genode_dir]/tool/run/log.inc
source [genode_dir]/tool/run/qemu.inc
proc run_log { wait_for_re timeout_value } {
global qemu_spawn_id
global output_spawn_id
set output_spawn_id $qemu_spawn_id
wait_for_output $wait_for_re $timeout_value $qemu_spawn_id
return true;
}

42
tool/run/log/serial Normal file
View File

@ -0,0 +1,42 @@
##
# Get the output of the target machine via serial connection
#
# \param --log-serial-cmd Cmd that is executed to capture the output
#
source [genode_dir]/tool/run/log.inc
set default_serial_cmd "picocom -b 115200 /dev/ttyUSB0"
proc log_serial_cmd { } {
global default_serial_cmd
return [get_cmd_arg --log-serial-cmd $default_serial_cmd]
}
##
# Log output of the test machine via serial device
#
proc run_log { wait_for_re timeout_value } {
global output_spawn_id
set timeout 210
while {true} {
eval spawn [log_serial_cmd]
set output_spawn_id $spawn_id
expect {
"Genode \[0-9]\[0-9]\.\[0-9]\[0-9]" {
wait_for_output $wait_for_re $timeout_value $output_spawn_id;
return true;
}
eof { continue; }
timeout {
puts stderr "Boot process timed out";
close;
return false;
}
}
}
}

View File

@ -0,0 +1,45 @@
##
# Reset the target machine via powerplug
#
# \param --power-off-powerplug-ip IP address of powerplug device
# \param --power-off-powerplug-user user for powerplug device
# \param --power-off-powerplug-password password for powerplug device
# \param --power-off-powerplug-port target port of powerplug device
#
source [genode_dir]/tool/run/powerplug.inc
proc power_off_powerplug_ip { } {
return [get_cmd_arg_first --power-off-powerplug-ip 1]
}
proc power_off_powerplug_user { } {
return [get_cmd_arg_first --power-off-powerplug-user 1]
}
proc power_off_powerplug_password { } {
return [get_cmd_arg_first --power-off-powerplug-password 1]
}
proc power_off_powerplug_port { } {
return [get_cmd_arg_first --power-off-powerplug-port 1]
}
proc run_power_off { } {
set server_ip [power_off_powerplug_ip]
set user_name [power_off_powerplug_user]
set password [power_off_powerplug_password]
set power_port [power_off_powerplug_port]
set connection_id [power_plug_connect $server_ip $user_name $password]
puts "switch port $power_port off"
send -i $connection_id "port $power_port 0\n"
expect -i $connection_id "250 OK"
}

131
tool/run/power_on/amt Normal file
View File

@ -0,0 +1,131 @@
##
# Reset the target machine via Intel AMT
#
# \param --power-on-amt-host IP address of target machine
# \param --power-on-amt-password AMT password for target machine
#
source [genode_dir]/tool/run/amt.inc
proc power_on_amt_host { } {
return [get_cmd_arg_first --power-on-amt-host ""]
}
proc power_on_amt_password { } {
return [get_cmd_arg_first --power-on-amt-password ""]
}
##
# Reset via Intel AMT (works up to version smaller Intel AMT 9)
#
proc amt_reset_soap_eoi { } {
set timeout 20
set exit_result 1
#
# amttool expects in the environment variable AMT_PASSWORD the password
#
set ::env(AMT_PASSWORD) [power_on_amt_password]
while { $exit_result != 0 } {
set try_again 0
set time_start [ clock seconds ]
spawn amttool [power_on_amt_host] reset
expect {
"host" { send "y\r"; }
eof { puts "Error: amttool died unexpectedly"; exit -4 }
timeout { puts "Error: amttool timed out"; exit -5 }
}
expect {
"result: pt_status: success" { break }
eof { set try_again 1 }
timeout { puts "Error: amttool timed out"; exit -6 }
}
catch wait result
set time_end [ clock seconds ]
if {[expr $time_end - $time_start] <= 1} {
incr timeout -1
} else {
incr timeout [expr -1 * ($time_end - $time_start)]
}
if {$timeout < 0} {
set timeout 0
}
if {$try_again != 0 } {
continue
}
set exit_result [lindex $result 3]
}
}
##
# Reset via Intel AMT wsman protocol
#
proc amt_reset_wsman { } {
set xml_request "amt-reset-wsman.xml"
set fh [open $xml_request "WRONLY CREAT TRUNC"]
puts $fh {
<!-- poweron - 2, poweroff - 8, reset - 5 -->
<p:RequestPowerStateChange_INPUT xmlns:p="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_PowerManagementService">
<p:PowerState>5</p:PowerState>
<p:ManagedElement xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
xmlns:wsman="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd">
<wsa:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:Address>
<wsa:ReferenceParameters>
<wsman:ResourceURI>http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ComputerSystem</wsman:ResourceURI>
<wsman:SelectorSet>
<wsman:Selector Name="CreationClassName">CIM_ComputerSystem</wsman:Selector>
<wsman:Selector Name="Name">ManagedSystem</wsman:Selector>
</wsman:SelectorSet>
</wsa:ReferenceParameters>
</p:ManagedElement>
</p:RequestPowerStateChange_INPUT>
}
close $fh
exec wsman invoke -a RequestPowerStateChange -J $xml_request \
"http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_PowerManagementService?SystemCreationClassName=\"CIM_ComputerSystem\",SystemName=\"Intel(r) AMT\",CreationClassName=\"CIM_PowerManagementService\",Name=\"Intel(r) AMT Power Management Service\"" \
--port 16992 -h [power_on_amt_host] --username admin -p [power_on_amt_password] -V -v
}
##
# Reset the test machine using Intel's AMT
#
proc run_power_on { } {
if {![is_amt_available [power_on_amt_host] [power_on_amt_password]]} {
return false
}
#
# amttool and wsman are supported for reset
#
set amt_tool [get_cmd_arg --amt-tool "default"]
#
# reset the box
#
if {[have_installed wsman] &&
( $amt_tool == "wsman" || $amt_tool == "default") } {
amt_reset_wsman
} else {
if {[have_installed amttool] &&
($amt_tool == "amttool" || $amt_tool == "default") } {
amt_reset_soap_eoi
} else {
puts stderr "specified tool \"$amt_tool\" for using Intel AMT is unknown or is not installed"
exit -1
}
}
sleep 5
return true
}

37
tool/run/power_on/linux Normal file
View File

@ -0,0 +1,37 @@
##
# Execute scenario on Linux
#
proc run_power_on { } {
global linux_spawn_id
global linux_orig_pwd
set linux_orig_pwd [pwd]
cd [run_dir]/genode
eval spawn ./core
set linux_spawn_id $spawn_id
cd $linux_orig_pwd
}
##
# Umount a directory that was bind-mounted beforehand
#
# This function is used by chroot-related tests, e.g., 'os/run/chroot.run',
# 'os/run/chroot_loader.run'.
#
proc umount_and_rmdir { path } {
puts "umounting $path"
#
# Invoke umount until it returns an error. Apparently, the unmounting
# of bind-mounted mount points does not always take immediate effect
# (regardless of the -l option).
#
while {1} {
if {[catch { exec sudo umount -l $path }]} { break; }
sleep 0.25
}
catch { exec rmdir -p $path }
}

View File

@ -0,0 +1,54 @@
##
# Reset the target machine via powerplug
#
# \param --power-on-powerplug-ip IP address of powerplug device
# \param --power-on-powerplug-user user for powerplug device
# \param --power-on-powerplug-password password for powerplug device
# \param --power-on-powerplug-port target port of powerplug device
#
source [genode_dir]/tool/run/powerplug.inc
proc power_on_powerplug_ip { } {
return [get_cmd_arg_first --power-on-powerplug-ip 1]
}
proc power_on_powerplug_user { } {
return [get_cmd_arg_first --power-on-powerplug-user 1]
}
proc power_on_powerplug_password { } {
return [get_cmd_arg_first --power-on-powerplug-password 1]
}
proc power_on_powerplug_port { } {
return [get_cmd_arg_first --power-on-powerplug-port 1]
}
proc run_power_on { } {
set server_ip [power_on_powerplug_ip]
set user_name [power_on_powerplug_user]
set password [power_on_powerplug_password]
set power_port [power_on_powerplug_port]
set connection_id [power_plug_connect $server_ip $user_name $password]
send -i $connection_id "port $power_port\n"
expect -i $connection_id -re {250 [0-9]+.*\n}
regexp -all {[0-9]+} $expect_out(0,string) power_status
if {!$power_status} {
puts "port $power_port is off - switching it on"
send -i $connection_id "port $power_port 1\n"
expect -i $connection_id "250 OK"
} else {
puts "port $power_port is on - reset port"
send -i $connection_id "port $power_port int\n"
expect -i $connection_id "250 OK"
}
}

78
tool/run/power_on/qemu Normal file
View File

@ -0,0 +1,78 @@
##
# Reset the target machine or rather run the scenario with Qemu
#
source [genode_dir]/tool/run/qemu.inc
##
# Execute scenario using Qemu
#
proc run_power_on { } {
global qemu_args
global qemu
global qemu_spawn_id
#
# Back out on platforms w/o Qemu support
#
if {![is_qemu_available]} { return 0 }
if {[have_spec x86_32]} { set qemu "qemu-system-i386" }
if {[have_spec x86_64]} { set qemu "qemu-system-x86_64" }
if {[have_spec arm]} { set qemu "qemu-system-arm" }
#
# Only the x86_64 variant of Qemu provides the emulation of hardware
# virtualization features used by NOVA. So let's always stick to this
# variant of Qemu when working with NOVA even when operating in 32bit.
#
if {[have_spec nova]} { set qemu "qemu-system-x86_64" }
#
# Redirect serial output to stdio, but only in graphics mode and no
# explicit configuration of serial interfaces is specified in the run
# script. The 'mon' prefix enables the access to the qemu console.
#
if {![regexp -- {-nographic} $qemu_args dummy] &&
![regexp -- {-serial} $qemu_args dummy]} {
append qemu_args " -serial mon:stdio " }
# tweak emulated platform for specific platforms
if {[have_spec platform_pbxa9]} {
#
# For PBXA9 qemu adjusts provided RAM chips to the -m arg. Thus we
# filter user values and force value that enables all chips that Genode
# expects to be available. Not doing so leads to inexplicable errors.
#
regsub -all {\-m ([0-9])+} $qemu_args "" qemu_args
append qemu_args " -m 768"
append qemu_args " -M realview-pbx-a9"
}
if {[have_spec platform_vpb926]} { append qemu_args " -M versatilepb -m 128 " }
if {[have_spec platform_vea9x4]} { append qemu_args " -M vexpress-a9 -cpu cortex-a9 -m 256 " }
# on x86, we support booting via pxe or iso/disk image
if {[have_spec x86]} {
if {[have_include "load/tftp"]} {
append qemu_args " -boot n -tftp [run_dir] -bootp boot/pulsar -no-reboot -no-shutdown "
} else {
if {[have_include "image/iso"]} {
append qemu_args " -cdrom [run_dir].iso "
} else {
if {[have_include "image/disk"]} {
append qemu_args " -hda [run_dir].img "
} else {
puts "Aborting, cannot execute Qemu without a ISO or disk image"
exit -4
}
}
}
}
# on ARM, we supply the boot image as kernel
if {[have_spec arm]} { append qemu_args " -kernel [run_dir]/image.elf " }
eval spawn $qemu $qemu_args
set qemu_spawn_id $spawn_id
}

9
tool/run/powerplug.inc Normal file
View File

@ -0,0 +1,9 @@
proc power_plug_connect { server_ip user_name password } {
spawn telnet $server_ip 1234
set connection_id $spawn_id
expect -i $connection_id "KSHELL V1.*"
send -i $connection_id "login $user_name $password\n"
expect -i $connection_id "250 OK"
return $connection_id
}

33
tool/run/qemu.inc Normal file
View File

@ -0,0 +1,33 @@
set qemu_spawn_id ""
set qemu_args [get_cmd_arg --qemu-args ""]
#
# Enable run scripts to extend 'qemu_arg' via 'append' without bothering
# about the required whitespace in front of the custom arguments.
#
append qemu_args " "
proc qemu_args { } {
global qemu_args
return $qemu_args
}
##
# Check whether Qemu support is available
#
# XXX should by removed in favor of [have_include "exec/qemu"]
#
proc is_qemu_available { } {
if {[have_spec linux]} { return false }
if {[have_spec platform_panda]
|| [have_spec platform_arndale]
|| [have_spec platform_rpi]} {
puts stderr "skipping execution because platform is not supported by qemu"
return false
}
return true
}

663
tool/run/run Executable file
View File

@ -0,0 +1,663 @@
#!/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
if {[info exists run_boot_dir_hook]} {
run_boot_dir_hook
}
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
#
proc append_if {condition var string} {
upvar $var up_var
if {$condition} { append up_var $string }
}
##
# 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
}
}
##
# Install content of specfied variable as init config file
#
proc install_config {config} {
set fh [open "[run_dir]/genode/config" "WRONLY CREAT TRUNC"]
puts $fh $config
close $fh
check_xml_syntax [run_dir]/genode/config
}
##
# 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} {
run_boot_dir $binaries
}
##
# 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 } {
run_power_on
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 }
# set expect match-buffer size
match_max -d 20000
##
# 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
}
##
# Copy the specified binaries from the 'bin/' directory to the run
# directory and try to strip executables.
#
proc copy_and_strip_genode_binaries_to_run_dir { binaries } {
foreach binary $binaries {
exec cp bin/$binary [run_dir]/genode
catch {
exec [cross_dev_prefix]strip [run_dir]/genode/$binary || true }
}
}
##
# 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
}
expect {
-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 }
}
set output $expect_out(buffer)
}
##
## Fall-back implementations of all run module procedures
##
##
# Dummy boot_dir maodule
proc run_boot_dir { } { return true; }
##
# 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; }
##
# 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
}
##
## 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