2
0
Fork 0

Add base-hw-pc

Build base-hw-pc with the Genode Labs build system
This commit is contained in:
Emery Hemingway 2020-02-18 20:14:29 +01:00
parent 64a34814dd
commit 7d5d2a3c5e
21 changed files with 525 additions and 16 deletions

View File

@ -21,6 +21,19 @@ rec {
program = "${drv}/bin/generate-manifest"; program = "${drv}/bin/generate-manifest";
}; };
hw-image = let
drv = import ./hw-image {
stdenv = packages.stdenv;
inherit nixpkgs dhallApps packages;
};
in {
type = "app";
program = "${drv}/bin/hw-image";
function = attrs: bootDesc:
nixpkgs.runCommand "image.elf" attrs
''XDG_CACHE_HOME=$TMPDIR ${drv}/bin/hw-image "${bootDesc}" > $out'';
};
nova-image = let nova-image = let
drv = import ./nova-image { drv = import ./nova-image {
stdenv = packages.stdenv; stdenv = packages.stdenv;
@ -34,6 +47,19 @@ rec {
''XDG_CACHE_HOME=$TMPDIR ${drv}/bin/nova-image "${bootDesc}" > $out''; ''XDG_CACHE_HOME=$TMPDIR ${drv}/bin/nova-image "${bootDesc}" > $out'';
}; };
hw-iso = let
drv = import ./hw-iso {
stdenv = packages.stdenv;
inherit nixpkgs packages hw-image;
};
in {
type = "app";
program = "${drv}/bin/hw-iso";
function = attrs: bootDesc:
nixpkgs.runCommand "hw.iso" attrs
''XDG_CACHE_HOME=$TMPDIR ${drv}/bin/hw-iso "${bootDesc}" > $out'';
};
nova-iso = let nova-iso = let
drv = import ./nova-iso { drv = import ./nova-iso {
stdenv = packages.stdenv; stdenv = packages.stdenv;

46
apps/hw-image/default.nix Normal file
View File

@ -0,0 +1,46 @@
# SPDX-License-Identifier: CC0-1.0
{ stdenv, nixpkgs, dhallApps, packages }:
let inherit (packages) base-hw-pc;
in nixpkgs.writeScriptBin "hw-image" (with nixpkgs.buildPackages;
let inherit (stdenv) cc;
in ''
#!${runtimeShell}
set -eu
CC="${cc}/bin/${cc.targetPrefix}cc"
LD="${buildPackages.binutils}/bin/${buildPackages.binutils.targetPrefix}ld"
TMPDIR="$(${coreutils}/bin/mktemp -d)"
trap "rm -rf $TMPDIR" err exit
export DHALL_PRELUDE=${packages.dhallPrelude}/package.dhall
export DHALL_GENODE=${packages.dhallGenode}/package.dhall
build_core() {
local lib="$1"
local modules="$2"
local link_address="$3"
${dhallApps.dhall.program} text <<< \
"(${../modules.as.dhall}).to64bitImage ($modules)" \
> "$TMPDIR/modules.as"
# compile the boot modules into one object file
$CC -c -x assembler -o "$TMPDIR/boot_modules.o" "$TMPDIR/modules.as"
# link final image
$LD \
--strip-all \
-T${base-hw-pc.src}/repos/base/src/ld/genode.ld \
-z max-page-size=0x1000 \
-Ttext=$link_address -gc-sections \
"$lib" "$TMPDIR/boot_modules.o"
cat a.out
}
set -v
${dhallApps.dhall.program} <<< "${../render-rom.dhall} ($@)" > "$TMPDIR/modules.dhall"
build_core "''${CORE_OBJ:-${base-hw-pc}/lib/core-hw-pc.o}" "$TMPDIR/modules.dhall" 0xffffffc000000000 > core.elf
build_core "''${BOOTSTRAP_OBJ:-${base-hw-pc}/lib/bootstrap-hw-pc.o}" "${../to-rom.dhall} \"core.elf\" \"./core.elf\"" 0x00200000
'')

43
apps/hw-iso/default.nix Normal file
View File

@ -0,0 +1,43 @@
# SPDX-License-Identifier: CC0-1.0
{ stdenv, nixpkgs, packages, hw-image }:
nixpkgs.writeScriptBin "hw-iso" (with nixpkgs.buildPackages;
let inherit (stdenv) cc;
in ''
#!${runtimeShell}
set -eu
SYSLINUX="${syslinux}/share/syslinux"
TMPDIR="$(${coreutils}/bin/mktemp -d)"
trap "rm -rf $TMPDIR" err exit
mkdir -p "$TMPDIR/boot/syslinux"
${hw-image.program} $@ > "$TMPDIR/boot/image.elf"
pushd "$TMPDIR" > /dev/null
out="hw.iso"
# build ISO layout
cp ${packages.NOVA}/hypervisor* boot/hypervisor
cp ${./isolinux.cfg} boot/syslinux/isolinux.cfg
cp \
$SYSLINUX/isolinux.bin \
$SYSLINUX/ldlinux.c32 \
$SYSLINUX/libcom32.c32 \
$SYSLINUX/mboot.c32 \
boot/syslinux
chmod +w boot/syslinux/isolinux.bin
# create ISO image
${cdrkit}/bin/mkisofs -o "$out" \
-b syslinux/isolinux.bin -c syslinux/boot.cat \
-no-emul-boot -boot-load-size 4 -boot-info-table \
-iso-level 2 \
boot
${syslinux}/bin/isohybrid "$out"
cat "$out"
'')

5
apps/hw-iso/isolinux.cfg Normal file
View File

@ -0,0 +1,5 @@
SERIAL
DEFAULT 0
LABEL 0
KERNEL mboot.c32
APPEND /image.elf

View File

@ -10,20 +10,12 @@ let compile =
λ ( addressType λ ( addressType
: Text : Text
) )
→ λ(boot : Genode.Boot.Type) → λ(rom : Prelude.Map.Type Text Genode.Boot.Rom)
→ let NaturalIndex = → let NaturalIndex =
{ index : Natural, value : Text } { index : Natural, value : Text }
let TextIndex = { index : Text, value : Text } let TextIndex = { index : Text, value : Text }
let rom =
[ { mapKey = "config"
, mapValue =
Genode.Boot.Rom.RomText (Genode.Init.render boot.config)
}
]
# boot.rom
let moduleKeys = Prelude.Map.keys Text Genode.Boot.Rom rom let moduleKeys = Prelude.Map.keys Text Genode.Boot.Rom rom
let moduleValues = let moduleValues =

View File

@ -19,14 +19,14 @@ in nixpkgs.writeScriptBin "nova-image" (with nixpkgs.buildPackages;
export DHALL_PRELUDE=${packages.dhallPrelude}/package.dhall export DHALL_PRELUDE=${packages.dhallPrelude}/package.dhall
export DHALL_GENODE=${packages.dhallGenode}/package.dhall export DHALL_GENODE=${packages.dhallGenode}/package.dhall
${dhallApps.dhall.program} text <<< \ ${dhallApps.dhall.program} text <<< \
"(${./nova-modules.as.dhall}).to64bitImage ($@)" \ "(${../modules.as.dhall}).to64bitImage (${../render-rom.dhall} ($@))" \
> "$TMPDIR/modules.as" > "$TMPDIR/modules.as"
# compile the boot modules into one object file # compile the boot modules into one object file
$CC -c -x assembler -o "$TMPDIR/boot_modules.o" "$TMPDIR/modules.as" $CC -c -x assembler -o "$TMPDIR/boot_modules.o" "$TMPDIR/modules.as"
# link final image # link final image
$LD -nostdlib \ $LD --strip-all \
-T${base-nova.src}/repos/base/src/ld/genode.ld \ -T${base-nova.src}/repos/base/src/ld/genode.ld \
-T${base-nova.src}/repos/base-nova/src/core/core-bss.ld \ -T${base-nova.src}/repos/base-nova/src/core/core-bss.ld \
-z max-page-size=0x1000 \ -z max-page-size=0x1000 \

17
apps/render-rom.dhall Normal file
View File

@ -0,0 +1,17 @@
-- SPDX-License-Identifier: CC0-1.0
let Genode = env:DHALL_GENODE
let render =
λ(boot : Genode.Boot.Type)
→ let rom =
[ { mapKey = "config"
, mapValue =
Genode.Boot.Rom.RomText (Genode.Init.render boot.config)
}
]
# boot.rom
in rom
in render

10
apps/to-rom.dhall Normal file
View File

@ -0,0 +1,10 @@
-- SPDX-License-Identifier: CC0-1.0
let Genode = env:DHALL_GENODE
let toRom =
λ(mapKey : Text)
→ λ(path : Text)
→ [ { mapKey = mapKey, mapValue = Genode.Boot.Rom.RomPath path } ]
in toRom

View File

@ -43,6 +43,7 @@
export BASE_MANIFEST="${packages.genode.base.manifest}" export BASE_MANIFEST="${packages.genode.base.manifest}"
export BASE_LINUX_MANIFEST="${packages.genode.base-linux.manifest}" export BASE_LINUX_MANIFEST="${packages.genode.base-linux.manifest}"
export BASE_NOVA_MANIFEST="${packages.genode.base-nova.manifest}" export BASE_NOVA_MANIFEST="${packages.genode.base-nova.manifest}"
export BASE_HW_MANIFEST="${packages.base-hw-pc.manifest}"
export OS_MANIFEST="${packages.genode.os.manifest}" export OS_MANIFEST="${packages.genode.os.manifest}"
''; '';
}; };

View File

@ -16,10 +16,29 @@ let
callPackage' = path: attrs: callPackage' = path: attrs:
addManifest (legacyPackages.callPackages path attrs); addManifest (legacyPackages.callPackages path attrs);
buildUpstream = import ./genodelabs {
nixpkgs = legacyPackages;
inherit apps;
};
in rec { in rec {
inherit (legacyPackages) stdenv; inherit (legacyPackages) stdenv;
base-hw-pc = buildUpstream {
name = "base-hw-pc";
arch = "x86_64";
kernel = "hw";
board = "pc";
targets = [ "bootstrap" "core" "timer" ];
libTargets = [ "ld-hw" ];
postInstall = ''
mkdir -p $out/lib
mv $out/bin/*.o $out/lib/
mv $out/bin/ld-hw.lib.so $out/lib/ld.lib.so
'';
};
bender = legacyPackages.buildPackages.callPackage ./bender { }; bender = legacyPackages.buildPackages.callPackage ./bender { };
dhallGenode = dhallPackages.genode; dhallGenode = dhallPackages.genode;

View File

@ -0,0 +1,65 @@
{ nixpkgs, apps }:
{ name, targets, libTargets ? [ ], arch ? "x86_64", kernel ? "linux"
, board ? "pc", ... }@extraAttrs:
let
sourceForgeToolchain =
nixpkgs.buildPackages.callPackage ./../genode/toolchain.nix { };
stdenvGcc = let
env = nixpkgs.stdenvAdapters.overrideCC nixpkgs.stdenv sourceForgeToolchain;
in assert env.cc.isGNU; env;
version = "19.11";
toolPrefix = if arch == "x86_64" then
"genode-x86-"
else
throw "unknown tool prefix for Genode arch ${arch}";
in stdenvGcc.mkDerivation ({
outputs = [ "out" "manifest" ];
pname = name;
inherit version targets libTargets;
src = nixpkgs.fetchFromGitHub {
owner = "genodelabs";
repo = "genode";
rev = version;
sha256 = "0j0wfwqmv8mivfkpra1pb02a8dy1nnsakr3v6l5y964dfkq3737i";
};
nativeBuildInputs = with nixpkgs.buildPackages; [ binutils tcl which ];
enableParallelBuilding = true;
configurePhase = ''
patchShebangs ./tool/check_abi
patchShebangs ./tool/create_builddir
substituteInPlace repos/base/etc/tools.conf \
--replace "/usr/local/genode/tool/19.05/bin/" ""
substituteInPlace tool/check_abi \
--replace "exec nm" "exec ${toolPrefix}nm"
./tool/create_builddir ${arch} BUILD_DIR=build
'';
makeFlags = [ "-C build" "KERNEL=${kernel}" "BOARD=${board}" ];
buildPhase = ''
runHook preBuild
local flagsArray=(
''${enableParallelBuilding:+-j''${NIX_BUILD_CORES} -l''${NIX_BUILD_CORES}}
SHELL=$SHELL
$makeFlags ''${makeFlagsArray+"''${makeFlagsArray[@]}"}
$buildFlags ''${buildFlagsArray+"''${buildFlagsArray[@]}"}
)
for LIB in $libTargets; do
make "''${flagsArray[@]}" LIB=$LIB
done
make "''${flagsArray[@]}" $targets
runHook postBuild
'';
installPhase = ''
runHook preInstall
find build/bin -execdir install -Dt $out/bin '{}' \;
runHook postInstall
${apps.generate-manifest.program} $out > $manifest
'';
} // extraAttrs)

View File

@ -28,6 +28,14 @@ let
inherit apps system testPkgs hostPkgs lib depot; inherit apps system testPkgs hostPkgs lib depot;
}).callTest; }).callTest;
hw = (call:
((tests call) // {
pci = call ./pci.nix { };
rtc = call ./rtc.nix { };
})) (import ./driver-hw.nix {
inherit apps system testPkgs hostPkgs lib depot;
}).callTest;
testsToList = tests: testsToList = tests:
map (test: { map (test: {
inherit (test) name; inherit (test) name;
@ -40,4 +48,4 @@ let
}) (testsToList nova); }) (testsToList nova);
in with builtins; in with builtins;
listToAttrs ((concatLists (map (testsToList) [ linux nova ])) ++ nova-sotest) listToAttrs ((concatLists (map (testsToList) [ linux nova hw ])) ++ nova-sotest)

View File

@ -0,0 +1,95 @@
-- SPDX-License-Identifier: CC0-1.0
let Genode = env:DHALL_GENODE
let Prelude = Genode.Prelude
let ChildEntry = Prelude.Map.Entry Text Genode.Init.Start.Type
let toChildEntry =
λ(init : Genode.Init.Type)
→ let childCount = Prelude.List.length ChildEntry init.children
let onlyChild = Prelude.Natural.lessThan childCount 2
let child =
if onlyChild
then Prelude.Optional.fold
ChildEntry
(Prelude.List.head ChildEntry init.children)
ChildEntry
(λ(child : ChildEntry) → child)
{ mapKey = ""
, mapValue = Genode.Init.Start::{ binary = "" }
}
else { mapKey = "init", mapValue = Genode.Init.toStart init }
in child
in λ(boot : Genode.Boot.Type)
→ let child = toChildEntry boot.config
in { config =
Genode.Init::{
, defaultRoutes =
Genode.Init.default.defaultRoutes
# [ Genode.ServiceRoute.parent "IO_MEM"
, Genode.ServiceRoute.parent "IO_PORT"
, Genode.ServiceRoute.parent "IRQ"
, Genode.ServiceRoute.child "Timer" "timer"
]
, children =
[ { mapKey = "timer"
, mapValue =
Genode.Init.Start::{
, binary = "hw_timer_drv"
, resources = { caps = 96, ram = Genode.units.MiB 1 }
, provides = [ "Timer" ]
}
}
, { mapKey = "harness"
, mapValue =
Genode.Init.Start::{
, binary = "sotest-harness"
, exitPropagate = True
, resources =
{ caps = child.mapValue.resources.caps + 128
, ram =
child.mapValue.resources.ram
+ Genode.units.MiB 1
}
, config =
Some
( Prelude.XML.element
{ name = "config"
, attributes = Prelude.XML.emptyAttributes
, content =
[ Genode.Init.Start.toXML
child.mapKey
child.mapValue
]
}
)
, routes =
[ Genode.ServiceRoute.parentLabel
"LOG"
(Some "SOTEST")
(Some "unlabeled")
]
}
}
]
}
, rom =
let manifest = env:MANIFEST
in Genode.Boot.toRomPaths
[ manifest.base-hw-pc.lib.ld
, manifest.base-hw-pc.bin.hw_timer_drv
, manifest.os.bin.init
, manifest.sotest-producer.bin.sotest-harness
]
# boot.rom
}

171
tests/driver-hw.nix Normal file
View File

@ -0,0 +1,171 @@
# SPDX-License-Identifier: CC0-1.0
{ system, apps, testPkgs, hostPkgs, lib, depot }:
let
testDriver = with hostPkgs;
stdenv.mkDerivation {
name = "hw-genode-test-driver";
preferLocalBuild = true;
buildInputs = [ makeWrapper expect ];
dontUnpack = true;
installPhase = ''
install -Dm555 ${./hw-test-driver.exp} $out/bin/genode-test-driver
wrapProgram $out/bin/genode-test-driver \
--prefix PATH : "${lib.makeBinPath [ expect coreutils ]}"
'';
};
runTests = driver:
hostPkgs.stdenv.mkDerivation {
name = "hw-" + driver.testName;
preferLocalBuild = true;
buildCommand = ''
mkdir -p $out/nix-support
${driver}/bin/genode-test-driver | tee $out/log
touch $out/nix-support
echo "report testlog $out log" >> $out/nix-support/hydra-build-products
'';
};
defaultScript = ''run_genode_until {child "init" exited with exit value 0} 60'';
mkTest = { name ? "unamed", testScript ? defaultScript, testConfig, testInputs ? [ ]
, env ? { }, qemuMem ? 32, ... # TODO: remove ...
}@t:
let
manifest = lib.mergeManifests (with testPkgs;
[ base-hw-pc genode.os sotest-producer ]
++ testInputs);
env' = {
DHALL_PRELUDE = "${testPkgs.dhallPrelude}/package.dhall";
DHALL_GENODE = "${testPkgs.dhallGenode}/package.dhall";
MANIFEST = manifest;
} // env;
image = apps.hw-image.function env'
"${./driver-hw-config.dhall} ${testConfig}";
baseSetup = ''
##
# Wait for a specific output of a already running spawned proce
#
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 -1 }
timeout { puts stderr "Error: Test execution timed out"; exit -1 }
}
set output $expect_out(buffer)
}
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
spawn ${hostPkgs.qemu_test}/bin/qemu-system-x86_64 \
-machine q35 -serial mon:stdio -nographic \
-m size=${toString qemuMem} \
-kernel "${testPkgs.bender}" \
-initrd "${image}"
wait_for_output $wait_for_re $timeout_value $spawn_id
}
# TODO: not in TCL
global env
set out $env(out)
'';
driver = with hostPkgs;
buildPackages.runCommand "genode-test-driver-${name}" {
buildInputs = [ makeWrapper expect ];
inherit baseSetup testConfig testScript;
preferLocalBuild = true;
testName = name;
} ''
mkdir -p $out/bin
echo "$testScript" > $out/test-script
echo "$baseSetup" > $out/base-setup
ln -s ${testDriver}/bin/genode-test-driver $out/bin/
wrapProgram $out/bin/genode-test-driver \
--run "export testScript=\"\$(cat $out/test-script)\"" \
--run "export baseSetup=\"\$(cat $out/base-setup)\"" \
'';
passMeta = drv:
drv
// lib.optionalAttrs (t ? meta) { meta = (drv.meta or { }) // t.meta; };
test = passMeta (runTests driver);
in test // {
inherit driver image test manifest;
config = hostPkgs.runCommand (name + ".dhall") env' ''
export XDG_CACHE_HOME=''${TMPDIR:-/tmp}
${apps.dhall.program} <<< \
"(${./driver-hw-config.dhall} ${testConfig})" > $out
'';
iso = apps.hw-iso.function env'
"(${./driver-hw-config.dhall} ${testConfig})";
xml = hostPkgs.runCommand (name + ".config") env' ''
export XDG_CACHE_HOME=''${TMPDIR:-/tmp}
${apps.render-init.program} \
"(${./driver-hw-config.dhall} ${testConfig}).config" > $out'';
sotest = hostPkgs.runCommand "hw-${name}-sotest" env' ''
cp "${testPkgs.bender}" bender
cp ${image} image.elf
mkdir -p $out/nix-support
${hostPkgs.zip}/bin/zip "$out/binaries.zip" \
bender image.elf
${apps.dhall-to-yaml.program} < ${
./sotest_hw_config.dhall
} > "$out/sotest_config.yaml"
echo file zip $out/binaries.zip >> "$out/nix-support/hydra-build-products"
echo file config $out/sotest_config.yaml >> "$out/nix-support/hydra-build-products"
'';
};
in {
callTest = path: args:
(import path ({
testEnv = {
inherit mkTest lib;
isLinux = false;
isNova = true;
};
pkgs = testPkgs;
inherit depot hostPkgs;
} // args));
}

View File

@ -28,7 +28,7 @@ in λ(args : Args)
} }
, rom = , rom =
let manifest = env:MANIFEST let manifest = env:MANIFEST
in Genode.Boot.toRomPaths in Genode.Boot.toRomPaths
[ manifest.base-linux.bin.ld [ manifest.base-linux.bin.ld
, manifest.base-linux.bin.linux_timer_drv , manifest.base-linux.bin.linux_timer_drv

View File

@ -42,7 +42,7 @@ let
DHALL_PRELUDE = "${testPkgs.dhallPrelude}/package.dhall"; DHALL_PRELUDE = "${testPkgs.dhallPrelude}/package.dhall";
DHALL_GENODE = "${testPkgs.dhallGenode}/package.dhall"; DHALL_GENODE = "${testPkgs.dhallGenode}/package.dhall";
MANIFEST = lib.mergeManifests (with testPkgs; MANIFEST = lib.mergeManifests (with testPkgs;
[ genode.base genode.base-linux genode.os ] ++ testInputs); [ genode.base-linux genode.os ] ++ testInputs);
} // env; } // env;
toExports = env: toExports = env:

View File

@ -84,7 +84,7 @@ in λ(boot : Genode.Boot.Type)
} }
, rom = , rom =
let manifest = env:MANIFEST let manifest = env:MANIFEST
in Genode.Boot.toRomPaths in Genode.Boot.toRomPaths
[ manifest.base-nova.lib.ld [ manifest.base-nova.lib.ld
, manifest.base-nova.bin.nova_timer_drv , manifest.base-nova.bin.nova_timer_drv

View File

@ -41,7 +41,7 @@ let
}@t: }@t:
let let
manifest = lib.mergeManifests (with testPkgs; manifest = lib.mergeManifests (with testPkgs;
[ genode.base genode.base-nova genode.os sotest-producer ] [ genode.base-nova genode.os sotest-producer ]
++ testInputs); ++ testInputs);
env' = { env' = {
DHALL_PRELUDE = "${testPkgs.dhallPrelude}/package.dhall"; DHALL_PRELUDE = "${testPkgs.dhallPrelude}/package.dhall";

5
tests/hw-test-driver.exp Normal file
View File

@ -0,0 +1,5 @@
#!/usr/bin/env expect
eval $env(baseSetup)
eval $env(testScript)

View File

@ -10,4 +10,6 @@ testEnv.mkTest rec {
testConfig = ./log.dhall; testConfig = ./log.dhall;
testScript = "run_genode_until {Test done.} 120"; testScript = "run_genode_until {Test done.} 120";
testInputs = [ pkgs.genode.base ];
} }

View File

@ -0,0 +1,4 @@
{ boot_items =
[ { exec = "bender", load = [ "image.elf" ], name = "Genode base-hw" } ]
, boot_panic_patterns = [ "Error: init", "PAGE-FAULT IN CORE" ]
}