diff --git a/flake.nix b/flake.nix index 95adcb6..5fbd6ca 100644 --- a/flake.nix +++ b/flake.nix @@ -131,10 +131,6 @@ packages = self.packages.${system}; }); - nixosModules = - # Modules for composing Genode and NixOS - import ./nixos-modules { inherit self; }; - checks = # Checks for continous testing let tests = import ./tests; diff --git a/nixos-modules/default.nix b/nixos-modules/default.nix deleted file mode 100644 index ec1158b..0000000 --- a/nixos-modules/default.nix +++ /dev/null @@ -1,284 +0,0 @@ -{ self }: { - genodeHost = { config, lib, pkgs, modulesPath, ... }: - let - apps' = self.apps.x86_64-linux-x86_64-genode; - config' = config; - lib' = self.lib.x86_64-linux-x86_64-genode; - pkgs' = self.packages.x86_64-linux-x86_64-genode; - legacyPackages' = self.legacyPackages.x86_64-linux-x86_64-genode; - - modulesPath' = "${self.inputs.nixpkgs}/nixos/modules"; - - genodeConfig = config.genode; - - console = lib'.runDhallCommand "vbox.dhall" { } '' - dhall > $out <<< '${ - ./dhall/console.dhall - } { bash = "${legacyPackages'.bash}", coreutils = "${legacyPackages'.coreutils}", path = "${ - lib.makeSearchPathOutput "bin" "bin" - (with legacyPackages'; [ bash coreutils ]) - }" }' - ''; - - guestChildren = lib'.runDhallCommand "vbox.dhall" { } ('' - dhall > $out << END - let Genode = env:DHALL_GENODE - in [ - '' + builtins.concatStringsSep "," (lib.mapAttrsToList (vmName: cfg: - let - inherit (cfg) config; - - boot = { - iso = rec { - filename = "nixos.iso"; - drv = pkgs.callPackage - "${modulesPath'}/../lib/make-iso9660-image.nix" - # call the ISO utility from our nixpkgs with the package set of the guest - { - isoName = filename; - inherit (config.isoImage) volumeID contents; - }; - format = "< ISO | VDI >.ISO"; - storeRoot = "${baseNameOf drv}/iso"; - uuid = "81763434-9a51-49e8-9444-528a5a28c4bc"; - }; - vdi = rec { - filename = "nixos.vdi"; - drv = import "${modulesPath'}/../lib/make-disk-image.nix" { - inherit config lib pkgs; - diskSize = config.virtualbox.baseImageSize; - partitionTableType = "legacy"; - name = "nixos-${pkgs.stdenv.hostPlatform.system}.vdi"; - format = "vdi"; - }; - format = "< ISO | VDI >.VDI"; - storeRoot = baseNameOf drv; - uuid = '' - $(${pkgs.virtualbox}/bin/VBoxManage showmediuminfo "${boot.drv}/${boot.filename}" | awk '/^UUID:/ {print $2}')''; - }; - }.${cfg.bootFormat}; - - in lib'.runDhallCommand "vbox.dhall" { } '' - bootUuid=${boot.uuid} - dhall > $out << END - { mapKey = "vbox-${vmName}" - , mapValue = - ${./dhall/vbox-guest.dhall} - { bootFilename = "${boot.filename}" - , bootFormat = ${boot.format} - , bootPkg = "${boot.storeRoot}" - , bootUuid = "$bootUuid" - , memorySize = ${toString cfg.memorySize} - , vmName = "${vmName}" - } - } - END - '') config.genode.guests) + '' - ] : Genode.Init.Children.Type - END - ''); - - initConfig = let - fbDriverConfig = { - intel = ./dhall/intel_fb_drv.dhall; - vesa = ./dhall/vesa_fb_drv.dhall; - }.${genodeConfig.fbDriver}; - in '' - ${ - ./dhall/root.dhall - } { fbDriver = ${fbDriverConfig}, guests = toMap { console = ${console} } # ${guestChildren}, inputFilterChargens = ${genodeConfig.inputFilter.extraChargen}, partitionType = ${ - ./dhall/partition-type - }, wm = ${./dhall/wm.dhall}, graphical-log = ${ - ./dhall/graphical-log.dhall - }, fs-log = ${ - ./dhall/fs-log.dhall - }, systemLabel = "${config.system.nixos.label}" }''; - - buildBootDescription = self.legacyPackages.x86_64-linux.callPackage - ./buildBootDescription.nix { lib = lib'; }; - - bootDescription = buildBootDescription { - inherit initConfig; - imageInputs = [ legacyPackages'.bash ] ++ map pkgs'.genodeSources.depot - ([ - "acpi_drv" - "ahci_drv" - "cached_fs_rom" - "chroot" - "decorator" - "event_filter" - "fs_log" - "gui_fb" - "init" - "ipxe_nic_drv" - "libc" - "libiconv" - "log_core" - "nic_router" - "nitpicker" - "part_block" - "platform_drv" - "posix" - "ps2_drv" - "report_rom" - "rom_to_file" - "rtc_drv" - "rump" - "stdcxx" - "terminal" - "terminal_log" - "usb_drv" - "vfs" - "vfs_audit" - "vfs_import" - "vfs_pipe" - "vfs_ttf" - "window_layouter" - "wm" - ] ++ lib.optional (genodeConfig.guests != { }) "vbox5" - ++ lib.optional (genodeConfig.fbDriver == "vesa") "vesa_drv" - ++ lib.optional (genodeConfig.fbDriver == "intel") "intel_fb_drv") - ++ (with pkgs'; [ base-nova block_router ]); - extraBinaries = [ - "ld.lib.so" - "libc.so" - "libm.so" - "libposix.so" - "librump.so" - "librump_fs.so" - "libstdcxx.so" - "libvfs.so" - "libvfs_audit.so" - "libvfs_import.so" - "libvfs_pipe.so" - "libvfs_rump.so" - "libvfs_ttf.so" - ] ++ lib.optionals (genodeConfig.guests != { }) [ - "libc_pipe.so" - "libiconv.so" - "libqemu-usb.so" - ]; - extraRoms = { - "Inconsolata.ttf" = - "${pkgs.inconsolata}/share/fonts/truetype/inconsolata/Inconsolata-Regular.ttf"; - "focus" = builtins.toFile "nitpicker-is-too-complicated.xml" '' - - ''; - }; - }; - - firmware = lib'.novaImage "stage0" { gzip = true; } bootDescription; - - in { - - options.genode = with lib; { - - fbDriver = mkOption { - default = "vesa"; - type = types.enum [ "intel" "vesa" ]; - description = '' - Set framebuffer driver. - ''; - }; - - guests = mkOption { - type = types.attrsOf (types.submodule - ({ config, options, name, ... }: { - options = { - - bootFormat = mkOption { - default = "vdi"; - type = types.enum [ "iso" "vdi" ]; - description = "Set boot media format."; - }; - memorySize = mkOption { - type = types.int; - default = 1536; - description = '' - The amount of RAM in MiB allocated to the VirtualBox guest. - ''; - }; - - config = mkOption { - description = '' - A specification of the desired configuration of this - guest VM, as a NixOS module. - ''; - type = mkOptionType { - name = "Toplevel NixOS config"; - merge = loc: defs: - (import "${modulesPath}/../lib/eval-config.nix" { - inherit (config'.nixpkgs) system; - modules = { - iso = [ - "${modulesPath}/installer/cd-dvd/iso-image.nix" - - ]; - vdi = [ - "${modulesPath}/virtualisation/virtualbox-image.nix" - { - virtualbox.memorySize = - genodeConfig.guests.${name}.memorySize; - } - ]; - }.${genodeConfig.guests.${name}.bootFormat} - ++ [{ system.nixos.tags = [ name ]; }] - ++ (map (x: x.value) defs); - prefix = [ "guests" name ]; - }).config; - }; - }; - - }; - })); - default = { }; - }; - - inputFilter = { - extraChargen = mkOption { - description = - "Dhall expression of the type List Prelude.XML.Type"; - type = types.str; - default = "${./dhall/qwerty.chargen.dhall}"; - }; - }; - - }; - - config = { - - system.build.genode = { - inherit firmware console; - config = lib'.runDhallCommand "config.dhall" { } - ''dhall > $out <<< "${initConfig}"''; - - xml = lib'.runDhallCommand "config.xml" { } - ''${apps'.render-init.program} <<< "${initConfig}" > $out''; - }; - - boot.loader.grub = { - extraEntries = '' - menuentry Genode on NOVA { - insmod multiboot2 - insmod gzio - multiboot2 /bender - module2 /hypervisor hypervisor iommu novpid serial logmem - module2 /image.elf.gz image.elf - } - ''; - - extraFiles = { - "bender" = "${pkgs'.genodeSources}/tool/boot/bender"; - "hypervisor" = "${pkgs'.NOVA}/hypervisor-x86_64"; - "image.elf.gz" = "${firmware}/image.elf.gz"; - }; - }; - - }; - - }; - - workman-layout.genode.inputFilter.extraChargen = - "${./dhall/workman.chargen.dhall}"; - -} diff --git a/nixos-modules/dhall/console.dhall b/nixos-modules/dhall/console.dhall deleted file mode 100644 index 160799d..0000000 --- a/nixos-modules/dhall/console.dhall +++ /dev/null @@ -1,201 +0,0 @@ -let Genode = env:DHALL_GENODE - -let Prelude = Genode.Prelude - -let XML = Prelude.XML - -let Init = Genode.Init - -let Child = Init.Child - -let Resources = Init.Resources - -let ServiceRoute = Init.ServiceRoute - -let Libc = Genode.Libc - -let VFS = Genode.VFS - -in λ(params : { bash : Text, coreutils : Text, path : Text }) → - let init = - Init::{ - , verbose = True - , routes = - Prelude.List.map - Text - Init.ServiceRoute.Type - Init.ServiceRoute.parent - [ "Gui", "Rtc", "Timer" ] - , children = toMap - { gui_fb = - Child.flat - Child.Attributes::{ - , binary = "gui_fb" - , config = Init.Config::{ - , attributes = toMap - { xpos = "10" - , ypos = "10" - , initial_width = "800" - , initial_height = "600" - } - } - , exitPropagate = True - , provides = [ "Framebuffer", "Input" ] - , resources = Resources::{ ram = Genode.units.MiB 8 } - } - , terminal = - Child.flat - Child.Attributes::{ - , binary = "terminal" - , config = Init.Config::{ - , content = - [ XML.element - { name = "vfs" - , attributes = XML.emptyAttributes - , content = - [ XML.element - { name = "dir" - , attributes = toMap { name = "fonts" } - , content = - [ XML.leaf - { name = "fs" - , attributes = toMap - { label = "fonts" } - } - ] - } - ] - } - ] - } - , provides = [ "Terminal" ] - , resources = Resources::{ - , caps = 256 - , ram = Genode.units.MiB 4 - } - , routes = - [ ServiceRoute.child "Framebuffer" "gui_fb" - , ServiceRoute.child "Input" "gui_fb" - , ServiceRoute.parent "File_system" - ] - } - , vfs = - Child.flat - Child.Attributes::{ - , binary = "vfs" - , config = Init.Config::{ - , content = - [ VFS.vfs - [ VFS.dir - "dev" - [ VFS.leaf "log" - , VFS.leaf "null" - , VFS.dir "pipe" [ VFS.leaf "pipe" ] - , VFS.leaf "rtc" - , VFS.leaf "terminal" - , VFS.leaf "zero" - ] - , VFS.dir - "usr" - [ VFS.dir - "bin" - [ VFS.symlink - "${params.coreutils}/bin/env" - "env" - ] - ] - , VFS.dir "tmp" [ VFS.leaf "ram" ] - , VFS.dir - "nix" - [ VFS.dir - "store" - [ VFS.fs VFS.FS::{ label = "nix-store" } ] - ] - ] - ] - , policies = - [ Init.Config.Policy::{ - , service = "File_system" - , attributes = toMap - { root = "/", writeable = "yes" } - } - ] - } - , provides = [ "File_system" ] - , resources = Resources::{ - , caps = 256 - , ram = Genode.units.MiB 8 - } - , routes = - [ Init.ServiceRoute.parent "File_system" - , Init.ServiceRoute.child "Terminal" "terminal" - ] - } - , store_rom = - Child.flat - Child.Attributes::{ - , binary = "cached_fs_rom" - , provides = [ "ROM" ] - , resources = Resources::{ - , caps = 256 - , ram = Genode.units.MiB 4 - } - , routes = [ Init.ServiceRoute.child "File_system" "vfs" ] - } - , shell = - Child.flat - Child.Attributes::{ - , binary = "bash" - , config = - Libc.toConfig - Libc::{ - , stdin = Some "/dev/terminal" - , stdout = Some "/dev/terminal" - , stderr = Some "/dev/terminal" - , pipe = Some "/dev/pipe" - , rtc = Some "/dev/rtc" - , vfs = [ VFS.leaf "fs" ] - , env = toMap - { TERM = "screen" - , PATH = "${params.path}" - , PS1 = "system:\$PWD" - } - , args = [ "bash" ] - } - , exitPropagate = True - , resources = Resources::{ - , caps = 256 - , ram = Genode.units.MiB 8 - } - , routes = - [ Init.ServiceRoute.child "File_system" "vfs" - , { service = - { name = "ROM" - , label = - Init.LabelSelector.Type.Partial - { prefix = Some "/nix/store/" - , suffix = None Text - } - } - , route = - Init.Route.Type.Child - { name = "store_rom" - , label = None Text - , diag = None Bool - } - } - ] - } - } - } - - in Init.toChild - init - Init.Attributes::{ - , routes = - [ ServiceRoute.parent "File_system" - , ServiceRoute.parent "Gui" - , ServiceRoute.parent "Rtc" - , ServiceRoute.parent "Timer" - ] - } diff --git a/nixos-modules/dhall/fs-log.dhall b/nixos-modules/dhall/fs-log.dhall deleted file mode 100644 index ee36389..0000000 --- a/nixos-modules/dhall/fs-log.dhall +++ /dev/null @@ -1,56 +0,0 @@ -let Genode = env:DHALL_GENODE - -let Init = Genode.Init - -let Child = Init.Child - -let ServiceRoute = Init.ServiceRoute - -let routeLogRom = - λ(label : Text) → ServiceRoute.parentLabel "ROM" (Some "log") (Some label) - -in Init::{ - , verbose = True - , children = toMap - { fs_log = - Child.flat - Child.Attributes::{ - , binary = "fs_log" - , config = Init.Config::{ - , defaultPolicy = Some Init.Config.DefaultPolicy::{ - , attributes = toMap { merge = "yes", truncate = "yes" } - } - } - , exitPropagate = True - , provides = [ "LOG" ] - , routes = [ ServiceRoute.parent "File_system" ] - } - , log_core = - Child.flat - Child.Attributes::{ - , binary = "log_core" - , routes = - [ routeLogRom "core_log" - , ServiceRoute.childLabel - "LOG" - "fs_log" - (Some "log") - (Some "core") - ] - } - , log_kernel = - Child.flat - Child.Attributes::{ - , binary = "log_core" - , routes = - [ routeLogRom "kernel_log" - , ServiceRoute.childLabel - "LOG" - "fs_log" - (Some "log") - (Some "kernel") - ] - } - } - , routes = [ ServiceRoute.parent "Timer" ] - } diff --git a/nixos-modules/dhall/graphical-log.dhall b/nixos-modules/dhall/graphical-log.dhall deleted file mode 100644 index d1e13ee..0000000 --- a/nixos-modules/dhall/graphical-log.dhall +++ /dev/null @@ -1,105 +0,0 @@ -let Genode = env:DHALL_GENODE - -let Prelude = Genode.Prelude - -let XML = Prelude.XML - -let Init = Genode.Init - -let Child = Init.Child - -let Resources = Init.Resources - -let ServiceRoute = Init.ServiceRoute - -let routeLogRom = - λ(label : Text) → ServiceRoute.parentLabel "ROM" (Some "log") (Some label) - -in Init::{ - , verbose = True - , routes = - Prelude.List.map - Text - Init.ServiceRoute.Type - Init.ServiceRoute.parent - [ "Gui", "Rtc", "Timer" ] - , children = toMap - { gui_fb = - Child.flat - Child.Attributes::{ - , binary = "gui_fb" - , config = Init.Config::{ - , attributes = toMap - { initial_width = "600", initial_height = "600" } - } - , exitPropagate = True - , provides = [ "Framebuffer", "Input" ] - , resources = Resources::{ ram = Genode.units.MiB 8 } - } - , terminal = - Child.flat - Child.Attributes::{ - , binary = "terminal" - , config = Init.Config::{ - , content = - [ XML.element - { name = "vfs" - , attributes = XML.emptyAttributes - , content = - [ XML.element - { name = "dir" - , attributes = toMap { name = "fonts" } - , content = - [ XML.leaf - { name = "fs" - , attributes = toMap { label = "fonts" } - } - ] - } - ] - } - ] - } - , provides = [ "Terminal" ] - , resources = Resources::{ caps = 256, ram = Genode.units.MiB 4 } - , routes = - [ ServiceRoute.child "Framebuffer" "gui_fb" - , ServiceRoute.child "Input" "gui_fb" - , ServiceRoute.parent "File_system" - ] - } - , terminal_log = - Child.flat - Child.Attributes::{ - , binary = "terminal_log" - , provides = [ "LOG" ] - , routes = [ ServiceRoute.child "Terminal" "terminal" ] - } - , log_core = - Child.flat - Child.Attributes::{ - , binary = "log_core" - , routes = - [ routeLogRom "core_log" - , ServiceRoute.childLabel - "LOG" - "terminal_log" - (Some "log") - (Some "core") - ] - } - , log_kernel = - Child.flat - Child.Attributes::{ - , binary = "log_core" - , routes = - [ routeLogRom "kernel_log" - , ServiceRoute.childLabel - "LOG" - "terminal_log" - (Some "log") - (Some "kernel") - ] - } - } - } diff --git a/nixos-modules/dhall/intel_fb_drv.dhall b/nixos-modules/dhall/intel_fb_drv.dhall deleted file mode 100644 index 2ecb1b9..0000000 --- a/nixos-modules/dhall/intel_fb_drv.dhall +++ /dev/null @@ -1,23 +0,0 @@ -let Genode = env:DHALL_GENODE - -let Init = Genode.Init - -let Child = Init.Child - -let ServiceRoute = Init.ServiceRoute - -in Child.flat - Child.Attributes::{ - , binary = "intel_fb_drv" - , provides = [ "Framebuffer" ] - , resources = Init.Resources::{ caps = 256, ram = Genode.units.MiB 48 } - , routes = - [ ServiceRoute.parent "IO_MEM" - , ServiceRoute.parent "IO_PORT" - , ServiceRoute.childLabel - "Platform" - "platform_drv" - (None Text) - (Some "intel_fb_drv") - ] - } diff --git a/nixos-modules/dhall/partition-type b/nixos-modules/dhall/partition-type deleted file mode 100644 index 2cca25d..0000000 --- a/nixos-modules/dhall/partition-type +++ /dev/null @@ -1 +0,0 @@ -"24b69406-18a1-428d-908e-d21a1437122c" diff --git a/nixos-modules/dhall/qwerty.chargen.dhall b/nixos-modules/dhall/qwerty.chargen.dhall deleted file mode 100644 index 860cf2c..0000000 --- a/nixos-modules/dhall/qwerty.chargen.dhall +++ /dev/null @@ -1,297 +0,0 @@ -let Genode = env:DHALL_GENODE - -let Prelude = Genode.Prelude - -let XML = Prelude.XML - -let Key = < Ascii : Natural | Char : Text | Code : Natural > : Type - -let Map = - { Type = - { keys : Prelude.Map.Type Text Key - , mod1 : Bool - , mod2 : Bool - , mod3 : Bool - , mod4 : Bool - } - , default = { mod1 = False, mod2 = False, mod3 = False, mod4 = False } - } - -let boolToAttr = λ(_ : Bool) → if _ then "yes" else "no" - -let keyToXML = - λ(x : Prelude.Map.Entry Text Key) → - XML.leaf - { name = "key" - , attributes = - [ merge - { Ascii = - λ(_ : Natural) → - { mapKey = "ascii", mapValue = Prelude.Natural.show _ } - , Char = λ(_ : Text) → { mapKey = "char", mapValue = _ } - , Code = - λ(_ : Natural) → - { mapKey = "code", mapValue = Prelude.Natural.show _ } - } - x.mapValue - , { mapKey = "name", mapValue = x.mapKey } - ] - } - -let mapToXML = - λ(map : Map.Type) → - XML.element - { name = "map" - , attributes = toMap - { mod1 = boolToAttr map.mod1 - , mod2 = boolToAttr map.mod2 - , mod3 = boolToAttr map.mod3 - , mod4 = boolToAttr map.mod4 - } - , content = - Prelude.List.map - (Prelude.Map.Entry Text Key) - XML.Type - keyToXML - map.keys - } - -let qwerty = - [ Map::{ - , mod1 = False - , mod2 = False - , mod3 = False - , mod4 = False - , keys = toMap - { KEY_1 = Key.Code 49 - , KEY_2 = Key.Code 50 - , KEY_3 = Key.Code 51 - , KEY_4 = Key.Code 52 - , KEY_5 = Key.Code 53 - , KEY_6 = Key.Code 54 - , KEY_7 = Key.Code 55 - , KEY_8 = Key.Code 56 - , KEY_9 = Key.Code 57 - , KEY_0 = Key.Code 48 - , KEY_MINUS = Key.Code 45 - , KEY_EQUAL = Key.Code 61 - , KEY_Q = Key.Code 113 - , KEY_W = Key.Code 119 - , KEY_E = Key.Code 101 - , KEY_R = Key.Code 114 - , KEY_T = Key.Code 116 - , KEY_Y = Key.Code 121 - , KEY_U = Key.Code 117 - , KEY_I = Key.Code 105 - , KEY_O = Key.Code 111 - , KEY_P = Key.Code 112 - , KEY_LEFTBRACE = Key.Code 91 - , KEY_RIGHTBRACE = Key.Code 93 - , KEY_A = Key.Code 97 - , KEY_S = Key.Code 115 - , KEY_D = Key.Code 100 - , KEY_F = Key.Code 102 - , KEY_G = Key.Code 103 - , KEY_H = Key.Code 104 - , KEY_J = Key.Code 106 - , KEY_K = Key.Code 107 - , KEY_L = Key.Code 108 - , KEY_SEMICOLON = Key.Code 59 - , KEY_APOSTROPHE = Key.Code 39 - , KEY_GRAVE = Key.Code 96 - , KEY_BACKSLASH = Key.Code 92 - , KEY_Z = Key.Code 122 - , KEY_X = Key.Code 120 - , KEY_C = Key.Code 99 - , KEY_V = Key.Code 118 - , KEY_B = Key.Code 98 - , KEY_N = Key.Code 110 - , KEY_M = Key.Code 109 - , KEY_COMMA = Key.Code 44 - , KEY_DOT = Key.Code 46 - , KEY_SLASH = Key.Code 47 - , KEY_KPASTERISK = Key.Code 42 - , KEY_SPACE = Key.Code 32 - , KEY_KP7 = Key.Code 55 - , KEY_KP8 = Key.Code 56 - , KEY_KP9 = Key.Code 57 - , KEY_KPMINUS = Key.Code 45 - , KEY_KP4 = Key.Code 52 - , KEY_KP5 = Key.Code 53 - , KEY_KP6 = Key.Code 54 - , KEY_KPPLUS = Key.Code 43 - , KEY_KP1 = Key.Code 49 - , KEY_KP2 = Key.Code 50 - , KEY_KP3 = Key.Code 51 - , KEY_KP0 = Key.Code 48 - , KEY_KPDOT = Key.Code 46 - , KEY_102ND = Key.Code 60 - , KEY_KPSLASH = Key.Code 47 - , KEY_ESC = Key.Ascii 27 - , KEY_BACKSPACE = Key.Ascii 8 - , KEY_TAB = Key.Ascii 9 - , KEY_ENTER = Key.Ascii 10 - , KEY_KPENTER = Key.Ascii 10 - , KEY_DELETE = Key.Ascii 127 - } - } - , Map::{ - , mod1 = True - , mod2 = False - , mod3 = False - , mod4 = False - , keys = toMap - { KEY_1 = Key.Code 33 - , KEY_2 = Key.Code 64 - , KEY_3 = Key.Code 35 - , KEY_4 = Key.Code 36 - , KEY_5 = Key.Code 37 - , KEY_6 = Key.Code 94 - , KEY_7 = Key.Code 38 - , KEY_8 = Key.Code 42 - , KEY_9 = Key.Code 40 - , KEY_0 = Key.Code 41 - , KEY_MINUS = Key.Code 95 - , KEY_EQUAL = Key.Code 43 - , KEY_Q = Key.Code 81 - , KEY_W = Key.Code 87 - , KEY_E = Key.Code 69 - , KEY_R = Key.Code 82 - , KEY_T = Key.Code 84 - , KEY_Y = Key.Code 89 - , KEY_U = Key.Code 85 - , KEY_I = Key.Code 73 - , KEY_O = Key.Code 79 - , KEY_P = Key.Code 80 - , KEY_LEFTBRACE = Key.Code 123 - , KEY_RIGHTBRACE = Key.Code 125 - , KEY_A = Key.Code 65 - , KEY_S = Key.Code 83 - , KEY_D = Key.Code 68 - , KEY_F = Key.Code 70 - , KEY_G = Key.Code 71 - , KEY_H = Key.Code 72 - , KEY_J = Key.Code 74 - , KEY_K = Key.Code 75 - , KEY_L = Key.Code 76 - , KEY_SEMICOLON = Key.Code 58 - , KEY_APOSTROPHE = Key.Code 34 - , KEY_GRAVE = Key.Code 126 - , KEY_BACKSLASH = Key.Code 124 - , KEY_Z = Key.Code 90 - , KEY_X = Key.Code 88 - , KEY_C = Key.Code 67 - , KEY_V = Key.Code 86 - , KEY_B = Key.Code 66 - , KEY_N = Key.Code 78 - , KEY_M = Key.Code 77 - , KEY_COMMA = Key.Code 60 - , KEY_DOT = Key.Code 62 - , KEY_SLASH = Key.Code 63 - , KEY_KPASTERISK = Key.Code 42 - , KEY_KPMINUS = Key.Code 45 - , KEY_KPPLUS = Key.Code 43 - , KEY_102ND = Key.Code 62 - , KEY_KPSLASH = Key.Code 47 - } - } - , Map::{ - , mod1 = False - , mod2 = False - , mod3 = True - , mod4 = False - , keys = toMap { KEY_5 = Key.Code 8364, KEY_102ND = Key.Code 124 } - } - , Map::{ - , mod1 = False - , mod2 = False - , mod3 = False - , mod4 = True - , keys = toMap - { KEY_Q = Key.Code 81 - , KEY_W = Key.Code 87 - , KEY_E = Key.Code 69 - , KEY_R = Key.Code 82 - , KEY_T = Key.Code 84 - , KEY_Y = Key.Code 89 - , KEY_U = Key.Code 85 - , KEY_I = Key.Code 73 - , KEY_O = Key.Code 79 - , KEY_P = Key.Code 80 - , KEY_A = Key.Code 65 - , KEY_S = Key.Code 83 - , KEY_D = Key.Code 68 - , KEY_F = Key.Code 70 - , KEY_G = Key.Code 71 - , KEY_H = Key.Code 72 - , KEY_J = Key.Code 74 - , KEY_K = Key.Code 75 - , KEY_L = Key.Code 76 - , KEY_Z = Key.Code 90 - , KEY_X = Key.Code 88 - , KEY_C = Key.Code 67 - , KEY_V = Key.Code 86 - , KEY_B = Key.Code 66 - , KEY_N = Key.Code 78 - , KEY_M = Key.Code 77 - } - } - , Map::{ - , mod1 = True - , mod2 = False - , mod3 = False - , mod4 = True - , keys = toMap - { KEY_1 = Key.Code 33 - , KEY_2 = Key.Code 64 - , KEY_3 = Key.Code 35 - , KEY_4 = Key.Code 36 - , KEY_5 = Key.Code 37 - , KEY_6 = Key.Code 94 - , KEY_7 = Key.Code 38 - , KEY_8 = Key.Code 42 - , KEY_9 = Key.Code 40 - , KEY_0 = Key.Code 41 - , KEY_MINUS = Key.Code 95 - , KEY_EQUAL = Key.Code 43 - , KEY_Q = Key.Code 113 - , KEY_W = Key.Code 119 - , KEY_E = Key.Code 101 - , KEY_R = Key.Code 114 - , KEY_T = Key.Code 116 - , KEY_Y = Key.Code 121 - , KEY_U = Key.Code 117 - , KEY_I = Key.Code 105 - , KEY_O = Key.Code 111 - , KEY_P = Key.Code 112 - , KEY_LEFTBRACE = Key.Code 123 - , KEY_RIGHTBRACE = Key.Code 125 - , KEY_A = Key.Code 97 - , KEY_S = Key.Code 115 - , KEY_D = Key.Code 100 - , KEY_F = Key.Code 102 - , KEY_G = Key.Code 103 - , KEY_H = Key.Code 104 - , KEY_J = Key.Code 106 - , KEY_K = Key.Code 107 - , KEY_L = Key.Code 108 - , KEY_SEMICOLON = Key.Code 58 - , KEY_APOSTROPHE = Key.Code 34 - , KEY_GRAVE = Key.Code 126 - , KEY_BACKSLASH = Key.Code 124 - , KEY_Z = Key.Code 122 - , KEY_X = Key.Code 120 - , KEY_C = Key.Code 99 - , KEY_V = Key.Code 118 - , KEY_B = Key.Code 98 - , KEY_N = Key.Code 110 - , KEY_M = Key.Code 109 - , KEY_COMMA = Key.Code 60 - , KEY_DOT = Key.Code 62 - , KEY_SLASH = Key.Code 63 - , KEY_102ND = Key.Code 62 - } - } - ] - -in Prelude.List.map Map.Type XML.Type mapToXML qwerty diff --git a/nixos-modules/dhall/root.dhall b/nixos-modules/dhall/root.dhall deleted file mode 100644 index 66e6bb3..0000000 --- a/nixos-modules/dhall/root.dhall +++ /dev/null @@ -1,745 +0,0 @@ -let Genode = env:DHALL_GENODE - -let Prelude = Genode.Prelude - -let XML = Prelude.XML - -let Init = Genode.Init - -let Child = Init.Child - -let Resources = Init.Resources - -let ServiceRoute = Init.ServiceRoute - -let Policy = Init.Config.Policy - -let DefaultPolicy = Init.Config.DefaultPolicy - -let LabelSelector = Init.LabelSelector - -let label = - λ(label : Text) → - { local = label, route = label } : Child.Attributes.Label - -let rootInit = - λ ( params - : { fbDriver : Init.Child.Type - , guests : Init.Children.Type - , inputFilterChargens : List XML.Type - , partitionType : Text - , wm : Init.Type - , graphical-log : Init.Type - , fs-log : Init.Type - , systemLabel : Text - } - ) → - Init::{ - , children = toMap - { timer = - Child.flat - Child.Attributes::{ - , binary = "timer_drv" - , provides = [ "Timer" ] - } - , rtc = - Child.flat - Child.Attributes::{ - , binary = "rtc_drv" - , provides = [ "Rtc" ] - , routes = - [ ServiceRoute.parent "IO_PORT" - , ServiceRoute.parent "IO_MEM" - ] - } - , acpi_drv = - Child.flat - Child.Attributes::{ - , binary = "acpi_drv" - , priority = 1 - , resources = Resources::{ - , caps = 350 - , ram = Genode.units.MiB 4 - } - , romReports = [ label "acpi", label "smbios_table" ] - , routes = [ ServiceRoute.parent "IO_MEM" ] - } - , platform_drv = - Child.flat - Child.Attributes::{ - , binary = "platform_drv" - , resources = Resources::{ - , caps = 400 - , ram = Genode.units.MiB 4 - , constrainPhys = True - } - , reportRoms = [ label "acpi" ] - , romReports = [ label "pci" ] - , provides = [ "Acpi", "Platform" ] - , routes = - [ ServiceRoute.parent "IRQ" - , ServiceRoute.parent "IO_MEM" - , ServiceRoute.parent "IO_PORT" - , ServiceRoute.parentLabel - "ROM" - (Some "system") - (Some "system") - ] - , config = Init.Config::{ - , attributes = toMap { system = "yes" } - , content = - let PciPolicy/Type = - { labelSuffix : Text, pciClass : Text } - - in [ XML.text - '' - - - - - - - - - - - - - - - '' - ] - # Prelude.List.map - PciPolicy/Type - XML.Type - ( λ(policy : PciPolicy/Type) → - XML.element - { name = "policy" - , attributes = toMap - { label_suffix = policy.labelSuffix } - , content = - [ XML.leaf - { name = "pci" - , attributes = toMap - { class = policy.pciClass } - } - ] - } - ) - [ { labelSuffix = "ahci_drv" - , pciClass = "AHCI" - } - , { labelSuffix = "nic_drv" - , pciClass = "ETHERNET" - } - , { labelSuffix = "usb_drv", pciClass = "USB" } - , { labelSuffix = "vesa_fb_drv" - , pciClass = "VGA" - } - ] - } - } - , framebuffer = params.fbDriver - , event_filter = - Child.flat - Child.Attributes::{ - , binary = "event_filter" - , config = - let key = - λ(name : Text) → - XML.leaf - { name = "key", attributes = toMap { name } } - - let remap = - λ(name : Text) → - λ(to : Text) → - XML.leaf - { name = "key" - , attributes = toMap { name, to } - } - - in Init.Config::{ - , content = - [ XML.leaf - { name = "input" - , attributes = toMap { label = "ps2" } - } - , XML.leaf - { name = "input" - , attributes = toMap { label = "usb" } - } - , XML.element - { name = "output" - , attributes = XML.emptyAttributes - , content = - [ XML.element - { name = "chargen" - , attributes = XML.emptyAttributes - , content = - [ XML.element - { name = "remap" - , attributes = - XML.emptyAttributes - , content = - [ remap - "KEY_LEFTMETA" - "KEY_SCREEN" - , XML.element - { name = "merge" - , attributes = - XML.emptyAttributes - , content = - [ XML.leaf - { name = "input" - , attributes = toMap - { name = "ps2" } - } - , XML.leaf - { name = "input" - , attributes = toMap - { name = "usb" } - } - ] - } - ] - } - , XML.element - { name = "mod1" - , attributes = - XML.emptyAttributes - , content = - [ key "KEY_LEFTSHIFT" - , key "KEY_RIGHTSHIFT" - ] - } - , XML.element - { name = "mod2" - , attributes = - XML.emptyAttributes - , content = - [ key "KEY_LEFTCTRL" - , key "KEY_RIGHTCTRL" - ] - } - , XML.element - { name = "mod3" - , attributes = - XML.emptyAttributes - , content = - [ key "KEY_RIGHTALT" ] - } - ] - # params.inputFilterChargens - } - ] - } - ] - } - , provides = [ "Input" ] - , routes = - [ ServiceRoute.parentLabel - "ROM" - (Some "config") - (Some "config -> event_filter.config") - , ServiceRoute.childLabel - "Input" - "ps2_drv" - (Some "ps2") - (None Text) - , ServiceRoute.childLabel - "Input" - "usb_drv" - (Some "usb") - (None Text) - , ServiceRoute.child "Capture" "nitpicker" - ] - } - , ps2_drv = - Child.flat - Child.Attributes::{ - , binary = "ps2_drv" - , provides = [ "Input" ] - , routes = - [ ServiceRoute.childLabel - "Platform" - "platform_drv" - (None Text) - (Some "ps2_drv") - ] - } - , usb_drv = - Child.flat - Child.Attributes::{ - , binary = "usb_drv" - , config = Init.Config::{ - , attributes = toMap - { uhci = "yes" - , ohci = "yes" - , ehci = "yes" - , xhci = "yes" - , bios_handoff = "yes" - } - , content = - [ XML.leaf - { name = "hid", attributes = XML.emptyAttributes } - ] - } - , provides = [ "Input" ] - , resources = Init.Resources::{ - , caps = 128 - , ram = Genode.units.MiB 12 - } - , routes = - [ ServiceRoute.childLabel - "Platform" - "platform_drv" - (None Text) - (Some "usb_drv") - ] - } - , wm = - Init.toChild - params.wm - Init.Attributes::{ - , provides = [ "Capture", "Event", "Gui", "Report", "ROM" ] - , romReports = [ label "clipboard", label "shape" ] - , routes = - [ ServiceRoute.child "Framebuffer" "framebuffer" - , ServiceRoute.child "Input" "event_filter" - ] - } - , fonts_fs = - Child.flat - Child.Attributes::{ - , binary = "vfs" - , config = Init.Config::{ - , content = - [ XML.element - { name = "vfs" - , attributes = XML.emptyAttributes - , content = - [ XML.leaf - { name = "rom" - , attributes = toMap - { name = "Inconsolata.ttf" } - } - , XML.element - { name = "dir" - , attributes = toMap { name = "fonts" } - , content = - [ XML.element - { name = "dir" - , attributes = toMap { name = "title" } - , content = - [ XML.leaf - { name = "ttf" - , attributes = toMap - { name = "regular" - , path = "/Inconsolata.ttf" - , size_px = "12" - } - } - ] - } - , XML.element - { name = "dir" - , attributes = toMap { name = "text" } - , content = - [ XML.leaf - { name = "ttf" - , attributes = toMap - { name = "regular" - , path = "/Inconsolata.ttf" - , size_px = "12" - } - } - ] - } - , XML.element - { name = "dir" - , attributes = toMap - { name = "annotation" } - , content = - [ XML.leaf - { name = "ttf" - , attributes = toMap - { name = "regular" - , path = "/Inconsolata.ttf" - , size_px = "12" - } - } - ] - } - , XML.element - { name = "dir" - , attributes = toMap - { name = "monospace" } - , content = - [ XML.leaf - { name = "ttf" - , attributes = toMap - { name = "regular" - , path = "/Inconsolata.ttf" - , size_px = "12" - } - } - ] - } - ] - } - ] - } - ] - , defaultPolicy = Some DefaultPolicy::{ - , attributes = toMap { root = "/fonts" } - } - } - , provides = [ "File_system" ] - , resources = Init.Resources::{ - , caps = 256 - , ram = Genode.units.MiB 12 - } - , routes = [ ServiceRoute.child "Block" "block_router" ] - } - , graphical-log = - Init.toChild - params.graphical-log - Init.Attributes::{ - , routes = - [ ServiceRoute.child "Gui" "wm" - , ServiceRoute.child "File_system" "fonts_fs" - ] - } - , fs-log = - Init.toChild - params.fs-log - Init.Attributes::{ - , routes = - [ ServiceRoute.childLabel - "File_system" - "chroot" - (None Text) - (Some "dump") - ] - } - , rom_to_file = - Child.flat - Child.Attributes::{ - , binary = "rom_to_file" - , config = Init.Config::{ - , attributes = toMap { rom = "init.config" } - } - , routes = - [ ServiceRoute.childLabel - "File_system" - "chroot" - (None Text) - (Some "dump") - , ServiceRoute.parentLabel - "ROM" - (Some "init.config") - (Some "config") - ] - } - , block = - Child.flat - Child.Attributes::{ - , binary = "ahci_drv" - , config = Init.Config::{ - , defaultPolicy = Some DefaultPolicy::{ - , attributes = toMap { device = "0", writeable = "yes" } - } - } - , provides = [ "Block" ] - , resources = Init.Resources::{ - , caps = 256 - , ram = Genode.units.MiB 10 - } - , routes = - [ ServiceRoute.childLabel - "Platform" - "platform_drv" - (None Text) - (Some "ahci_drv") - ] - } - , block_partitions = - Child.flat - Child.Attributes::{ - , binary = "part_block" - , config = Init.Config::{ - , content = - Prelude.List.map - Natural - XML.Type - ( λ(i : Natural) → - XML.leaf - { name = "policy" - , attributes = - let partition = - Prelude.Natural.show (i + 1) - - in toMap - { label_suffix = " ${partition}" - , partition - , writeable = "yes" - } - } - ) - (Prelude.Natural.enumerate 128) - # [ XML.leaf - { name = "report" - , attributes = toMap { partitions = "yes" } - } - ] - } - , resources = Resources::{ - , caps = 256 - , ram = Genode.units.MiB 8 - } - , provides = [ "Block" ] - , routes = - [ ServiceRoute.child "Block" "block" - , ServiceRoute.child "Report" "block_router" - ] - } - , block_router = - Child.flat - Child.Attributes::{ - , binary = "block_router" - , config = Init.Config::{ - , attributes = toMap { verbose = "yes" } - , content = - [ XML.element - { name = "default-policy" - , attributes = XML.emptyAttributes - , content = - [ XML.leaf - { name = "partition" - , attributes = toMap - { type = params.partitionType - , writeable = "yes" - } - } - ] - } - ] - } - , resources = Resources::{ - , caps = 256 - , ram = Genode.units.MiB 8 - } - , provides = [ "Block", "Report" ] - , routes = [ ServiceRoute.child "Block" "block_partitions" ] - } - , file_system = - Child.flat - Child.Attributes::{ - , binary = "vfs" - , config = Init.Config::{ - , content = - [ XML.element - { name = "vfs" - , attributes = XML.emptyAttributes - , content = - [ XML.element - { name = "dir" - , attributes = toMap { name = "ext2" } - , content = - [ XML.leaf - { name = "rump" - , attributes = toMap - { fs = "ext2fs" - , writeable = "yes" - , ram = "8M" - } - } - ] - } - ] - } - ] - , policies = - [ Policy::{ - , label = LabelSelector.suffix "nix/store" - , attributes = toMap - { root = "/ext2/nix/store", writeable = "no" } - } - , Policy::{ - , label = LabelSelector.prefix "chroot" - , attributes = toMap - { root = "/ext2", writeable = "yes", path = "/" } - } - , Policy::{ - , label = LabelSelector.prefix "init -> console" - , attributes = toMap { root = "/", writeable = "yes" } - } - ] - } - , provides = [ "File_system" ] - , resources = Init.Resources::{ - , caps = 256 - , ram = Genode.units.MiB 12 - } - , routes = [ ServiceRoute.child "Block" "block_router" ] - } - , chroot = - Child.flat - Child.Attributes::{ - , binary = "chroot" - , config = Init.Config::{ - , policies = - [ Policy::{ - , label = LabelSelector.label "dump" - , attributes = toMap - { path = params.systemLabel, writeable = "yes" } - } - ] - , defaultPolicy = Some DefaultPolicy::{ - , attributes = toMap { writeable = "yes" } - } - } - , provides = [ "File_system" ] - , routes = [ ServiceRoute.child "File_system" "file_system" ] - } - , nic_drv = - Child.flat - Child.Attributes::{ - , binary = "ipxe_nic_drv" - , provides = [ "Nic" ] - , resources = Init.Resources::{ - , caps = 128 - , ram = Genode.units.MiB 4 - } - , routes = - [ ServiceRoute.childLabel - "Platform" - "platform_drv" - (None Text) - (Some "nic_drv") - ] - } - , nic_router = - Child.flat - Child.Attributes::{ - , binary = "nic_router" - , config = Init.Config::{ - , content = - [ XML.leaf - { name = "uplink" - , attributes = toMap { domain = "uplink" } - } - , XML.element - { name = "domain" - , attributes = toMap { name = "uplink" } - , content = - [ XML.leaf - { name = "nat" - , attributes = toMap - { domain = "default" - , tcp-ports = "1024" - , udp-ports = "1024" - , icmp-ids = "1024" - } - } - ] - } - , XML.element - { name = "domain" - , attributes = toMap - { name = "default", interface = "10.0.1.1/24" } - , content = - [ XML.leaf - { name = "dhcp-server" - , attributes = toMap - { ip_first = "10.0.1.2" - , ip_last = "10.0.1.200" - , dns_server_from = "uplink" - } - } - ] - # Prelude.List.map - Text - XML.Type - ( λ(proto : Text) → - XML.element - { name = proto - , attributes = toMap - { dst = "0.0.0.0/0" - , domain = "uplink" - } - , content = - [ XML.leaf - { name = "permit-any" - , attributes = toMap - { domain = "uplink" } - } - ] - } - ) - [ "tcp", "udp", "icmp" ] - } - ] - , defaultPolicy = Some DefaultPolicy::{ - , attributes = toMap { domain = "default" } - } - } - , provides = [ "Nic" ] - , resources = Init.Resources::{ ram = Genode.units.MiB 8 } - , routes = [ ServiceRoute.child "Nic" "nic_drv" ] - } - , init = - Init.toChild - Init::{ children = params.guests } - Init.Attributes::{ - , routes = - [ ServiceRoute.parent "VM" - , ServiceRoute.child "Gui" "wm" - , { service = - { name = "File_system" - , label = LabelSelector.last "fonts" - } - , route = - Init.Route.Type.Child - { name = "fonts_fs" - , label = None Text - , diag = None Bool - } - } - , { service = - { name = "File_system" - , label = LabelSelector.suffix "nix/store" - } - , route = - Init.Route.Type.Child - { name = "file_system" - , label = Some "nix/store" - , diag = None Bool - } - } - , { service = - { name = "File_system" - , label = LabelSelector.prefix "console" - } - , route = - Init.Route.Type.Child - { name = "file_system" - , label = None Text - , diag = None Bool - } - } - , ServiceRoute.child "File_system" "chroot" - , ServiceRoute.child "Nic" "nic_router" - , ServiceRoute.child "Rtc" "rtc" - , ServiceRoute.parentLabel - "ROM" - (Some "platform_info") - (Some "platform_info") - , ServiceRoute.child "Report" "_report_rom" - ] - } - } - , routes = [ ServiceRoute.child "Timer" "timer" ] - } - -in rootInit diff --git a/nixos-modules/dhall/show_input.dhall b/nixos-modules/dhall/show_input.dhall deleted file mode 100644 index 687a11b..0000000 --- a/nixos-modules/dhall/show_input.dhall +++ /dev/null @@ -1,41 +0,0 @@ -let Genode = env:DHALL_GENODE - -let Prelude = Genode.Prelude - -let XML = Prelude.XML - -let Init = Genode.Init - -let Child = Init.Child - -let Resources = Init.Resources - -let ServiceRoute = Init.ServiceRoute - -in Child.flat - Child.Attributes::{ - , binary = "show_input" - , config = Init.Config::{ - , content = - [ XML.element - { name = "vfs" - , attributes = XML.emptyAttributes - , content = - [ XML.element - { name = "dir" - , attributes = toMap { name = "fonts" } - , content = - [ XML.leaf - { name = "fs" - , attributes = toMap { label = "fonts" } - } - ] - } - ] - } - ] - } - , resources = Resources::{ ram = Genode.units.MiB 32 } - , routes = - [ ServiceRoute.parent "File_system", ServiceRoute.parent "Gui" ] - } diff --git a/nixos-modules/dhall/vbox-guest.dhall b/nixos-modules/dhall/vbox-guest.dhall deleted file mode 100644 index 4e26bee..0000000 --- a/nixos-modules/dhall/vbox-guest.dhall +++ /dev/null @@ -1,219 +0,0 @@ -let Genode = env:DHALL_GENODE - -let Prelude = Genode.Prelude - -let XML = Prelude.XML - -let Init = Genode.Init - -let Child = Init.Child - -let Resources = Init.Resources - -let ServiceRoute = Init.ServiceRoute - -let Libc = Genode.Libc - -let VFS = Genode.VFS - -let BootFormat = < ISO | VDI > - -let Params - : Type - = { bootFilename : Text - , bootPkg : Text - , bootUuid : Text - , bootFormat : BootFormat - , memorySize : Natural - , vmName : Text - } - -let toVbox = - λ(params : Params) → - let vboxConfig = - let hardDisks = - merge - { ISO = XML.text "" - , VDI = - XML.leaf - { name = "HardDisk" - , attributes = toMap - { uuid = "{${params.bootUuid}}" - , location = "${params.bootFilename}" - , format = "VDI" - , type = "Normal" - } - } - } - params.bootFormat - - let dvdImages = - merge - { ISO = - XML.leaf - { name = "Image" - , attributes = toMap - { uuid = "{${params.bootUuid}}" - , location = "${params.bootFilename}" - } - } - , VDI = XML.text "" - } - params.bootFormat - - let attachedDevices = - XML.element - { name = "AttachedDevice" - , attributes = - merge - { ISO = toMap - { passthrough = "false" - , type = "DVD" - , port = "3" - , device = "0" - } - , VDI = toMap - { type = "HardDisk", port = "0", device = "0" } - } - params.bootFormat - , content = - [ XML.leaf - { name = "Image" - , attributes = toMap - { uuid = "{${params.bootUuid}}" } - } - ] - } - - in '' - - - - ${XML.render hardDisks} - ${XML.render dvdImages} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ${XML.render attachedDevices} - - - - - '' - - in Child.flat - Child.Attributes::{ - , binary = "virtualbox5" - , config = - ( Libc.toConfig - Libc::{ - , vfs = - let mutableVfs = - let fsNode = - [ XML.leaf - { name = "fs" - , attributes = toMap - { label = "nix/store" - , root = "${params.bootPkg}" - } - } - ] - - in merge - { ISO = - [ XML.leaf - { name = "fs" - , attributes = toMap - { writeable = "yes" } - } - , XML.element - { name = "import" - , attributes = toMap - { overwrite = "no" } - , content = fsNode - } - ] - , VDI = - [ XML.leaf - { name = "fs" - , attributes = toMap - { writeable = "yes" } - } - , XML.element - { name = "import" - , attributes = toMap - { overwrite = "no" } - , content = fsNode - } - ] - } - params.bootFormat - - in [ VFS.inline "machine.vbox" vboxConfig - , VFS.dir - "dev" - [ VFS.leaf "log" - , VFS.leaf "null" - , VFS.leaf "rtc" - ] - ] - # mutableVfs - } - ) - with attributes = toMap - { vbox_file = "machine.vbox", vm_name = params.vmName } - , resources = Resources::{ - , caps = 1024 - , ram = - Genode.units.MiB 128 + Genode.units.MiB params.memorySize - } - , routes = - [ ServiceRoute.parent "File_system" - , ServiceRoute.parent "Nic" - , ServiceRoute.parent "Gui" - , ServiceRoute.parent "Rtc" - , ServiceRoute.parent "Timer" - , ServiceRoute.parent "VM" - , ServiceRoute.parent "Report" - , ServiceRoute.parentLabel - "ROM" - (Some "platform_info") - (Some "platform_info") - ] - } - -in toVbox diff --git a/nixos-modules/dhall/vesa_fb_drv.dhall b/nixos-modules/dhall/vesa_fb_drv.dhall deleted file mode 100644 index 50c7daa..0000000 --- a/nixos-modules/dhall/vesa_fb_drv.dhall +++ /dev/null @@ -1,27 +0,0 @@ -let Genode = env:DHALL_GENODE - -let ServiceRoute = Genode.Init.ServiceRoute - -let Child = Genode.Init.Child - -in Child.flat - Child.Attributes::{ - , binary = "vesa_fb_drv" - , config = Genode.Init.Config::{ - , attributes = toMap { width = "1024", height = "768" } - } - , provides = [ "Framebuffer" ] - , resources = Genode.Init.Resources::{ - , caps = 256 - , ram = Genode.units.MiB 16 - } - , routes = - [ ServiceRoute.parent "IO_MEM" - , ServiceRoute.parent "IO_PORT" - , ServiceRoute.childLabel - "Platform" - "platform_drv" - (None Text) - (Some "vesa_fb_drv") - ] - } diff --git a/nixos-modules/dhall/wm.dhall b/nixos-modules/dhall/wm.dhall deleted file mode 100644 index 442e089..0000000 --- a/nixos-modules/dhall/wm.dhall +++ /dev/null @@ -1,237 +0,0 @@ -let Genode = env:DHALL_GENODE - -let Prelude = Genode.Prelude - -let XML = Prelude.XML - -let Init = Genode.Init - -let Child = Init.Child - -let Resources = Init.Resources - -let ServiceRoute = Init.ServiceRoute - -let Policy = Init.Config.Policy - -let DefaultPolicy = Init.Config.DefaultPolicy - -let LabelSelector = Init.LabelSelector - -let label = - λ(label : Text) → - { local = label, route = label } : Child.Attributes.Label - -in Init::{ - , children = toMap - { nitpicker = - Child.flat - Child.Attributes::{ - , binary = "nitpicker" - , config = Init.Config::{ - , attributes = toMap { focus = "rom" } - , content = - [ XML.text - '' - - - - - - - '' - ] - , policies = - [ Policy::{ - , label = LabelSelector.prefix "pointer" - , attributes = toMap { domain = "pointer" } - } - , Policy::{ - , label = LabelSelector.suffix "-> decorator" - , attributes = toMap { domain = "decorator" } - } - , Policy::{ - , label = LabelSelector.prefix "wm" - , attributes = toMap { domain = "desktop" } - } - , Policy::{ - , label = LabelSelector.label "backdrop" - , attributes = toMap { domain = "backdrop" } - } - ] - , defaultPolicy = Some DefaultPolicy::{ - , attributes = toMap { domain = "default" } - } - } - , provides = [ "Gui", "Capture", "Event" ] - , resources = Resources::{ caps = 256, ram = Genode.units.MiB 64 } - , routes = - [ ServiceRoute.parent "Framebuffer" - , ServiceRoute.parent "Input" - ] - } - , pointer = - Child.flat - Child.Attributes::{ - , binary = "pointer" - , routes = [ ServiceRoute.child "Gui" "nitpicker" ] - } - , wm = - Child.flat - Child.Attributes::{ - , binary = "wm" - , config = Init.Config::{ - , policies = - [ Policy::{ - , attributes = toMap { role = "decorator" } - , label = LabelSelector.prefix "decorator" - } - , Policy::{ - , attributes = toMap { role = "layouter" } - , label = LabelSelector.prefix "layouter" - } - ] - , defaultPolicy = Some DefaultPolicy::{=} - } - , provides = [ "Gui", "Report", "ROM" ] - , reportRoms = [ label "focus", label "resize_request" ] - , romReports = - [ label "focus_request" - , label "pointer" - , label "shape" - , label "window_list" - ] - , resources = Init.Resources::{ - , caps = 256 - , ram = Genode.units.MiB 8 - } - , routes = - [ ServiceRoute.childLabel - "Gui" - "nitpicker" - (Some "") - (Some "focus") - , ServiceRoute.child "Gui" "nitpicker" - , ServiceRoute.parentLabel - "Report" - (Some "clipboard") - (Some "clipboard") - , ServiceRoute.parentLabel - "Report" - (Some "shape") - (Some "shape") - ] - } - , layouter = - Child.flat - Child.Attributes::{ - , binary = "window_layouter" - , config = Init.Config::{ - , attributes = toMap { rules = "rom" } - , content = - [ XML.text - '' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - '' - ] - } - , provides = [ "Gui", "Report", "ROM" ] - , romReports = - [ label "focus" - , label "resize_request" - , label "rules" - , label "window_layout" - ] - , reportRoms = - [ label "decorator_margins" - , label "focus_request" - , label "hover" - , label "rules" - , label "shape" - , label "window_list" - ] - , resources = Init.Resources::{ - , caps = 256 - , ram = Genode.units.MiB 8 - } - , routes = [ ServiceRoute.child "Gui" "wm" ] - } - , decorator = - Child.flat - Child.Attributes::{ - , binary = "decorator" - , config = Init.Config::{ - , content = - [ XML.element - { name = "controls" - , attributes = XML.emptyAttributes - , content = - [ XML.leaf - { name = "maximizer" - , attributes = XML.emptyAttributes - } - , XML.leaf - { name = "title", attributes = XML.emptyAttributes } - ] - } - ] - , defaultPolicy = Some DefaultPolicy::{=} - } - , provides = [ "Gui", "Report", "ROM" ] - , reportRoms = [ label "window_layout", label "pointer" ] - , romReports = [ label "decorator_margins", label "hover" ] - , resources = Init.Resources::{ - , caps = 128 - , ram = Genode.units.MiB 12 - } - , routes = [ ServiceRoute.child "Gui" "wm" ] - } - } - , routes = [ ServiceRoute.parent "Timer" ] - , services = - [ ServiceRoute.child "Gui" "wm" - , ServiceRoute.child "Report" "wm" - , ServiceRoute.child "ROM" "wm" - , ServiceRoute.child "Event" "Nitpicker" - , ServiceRoute.child "Capture" "Nitpicker" - ] - } diff --git a/nixos-modules/dhall/workman.chargen.dhall b/nixos-modules/dhall/workman.chargen.dhall deleted file mode 100644 index 6988bf0..0000000 --- a/nixos-modules/dhall/workman.chargen.dhall +++ /dev/null @@ -1,245 +0,0 @@ -let Genode = env:DHALL_GENODE - -let Prelude = Genode.Prelude - -let XML = Prelude.XML - -let Key = < Ascii : Natural | Char : Text | Code : Natural > : Type - -let Map = - { Type = - { keys : Prelude.Map.Type Text Key - , mod1 : Bool - , mod2 : Bool - , mod3 : Bool - , mod4 : Bool - } - , default = { mod1 = False, mod2 = False, mod3 = False, mod4 = False } - } - -let boolToAttr = λ(_ : Bool) → if _ then "yes" else "no" - -let keyToXML = - λ(x : Prelude.Map.Entry Text Key) → - XML.leaf - { name = "key" - , attributes = - [ merge - { Ascii = - λ(_ : Natural) → - { mapKey = "ascii", mapValue = Prelude.Natural.show _ } - , Char = λ(_ : Text) → { mapKey = "char", mapValue = _ } - , Code = - λ(_ : Natural) → - { mapKey = "code", mapValue = Prelude.Natural.show _ } - } - x.mapValue - , { mapKey = "name", mapValue = x.mapKey } - ] - } - -let mapToXML = - λ(map : Map.Type) → - XML.element - { name = "map" - , attributes = toMap - { mod1 = boolToAttr map.mod1 - , mod2 = boolToAttr map.mod2 - , mod3 = boolToAttr map.mod3 - , mod4 = boolToAttr map.mod4 - } - , content = - Prelude.List.map - (Prelude.Map.Entry Text Key) - XML.Type - keyToXML - map.keys - } - -let workman = - [ Map::{ - , keys = toMap - { KEY_ESC = Key.Ascii 27 - , KEY_1 = Key.Char "1" - , KEY_2 = Key.Char "2" - , KEY_3 = Key.Char "3" - , KEY_4 = Key.Char "4" - , KEY_5 = Key.Char "5" - , KEY_6 = Key.Char "6" - , KEY_7 = Key.Char "7" - , KEY_8 = Key.Char "8" - , KEY_9 = Key.Char "9" - , KEY_0 = Key.Char "0" - , KEY_MINUS = Key.Char "-" - , KEY_EQUAL = Key.Char "=" - , KEY_BACKSPACE = Key.Ascii 8 - , KEY_TAB = Key.Ascii 9 - , KEY_Q = Key.Char "q" - , KEY_W = Key.Char "d" - , KEY_E = Key.Char "r" - , KEY_R = Key.Char "w" - , KEY_T = Key.Char "b" - , KEY_Y = Key.Char "j" - , KEY_U = Key.Char "f" - , KEY_I = Key.Char "u" - , KEY_O = Key.Char "p" - , KEY_P = Key.Char ";" - , KEY_LEFTBRACE = Key.Char "[" - , KEY_RIGHTBRACE = Key.Char "]" - , KEY_ENTER = Key.Ascii 10 - , KEY_A = Key.Char "a" - , KEY_S = Key.Char "s" - , KEY_D = Key.Char "h" - , KEY_F = Key.Char "t" - , KEY_G = Key.Char "g" - , KEY_H = Key.Char "y" - , KEY_J = Key.Char "n" - , KEY_K = Key.Char "e" - , KEY_L = Key.Char "o" - , KEY_SEMICOLON = Key.Char "i" - , KEY_APOSTROPHE = Key.Char "'" - , KEY_GRAVE = Key.Char "`" - , KEY_BACKSLASH = Key.Ascii 92 - , KEY_Z = Key.Char "z" - , KEY_X = Key.Char "x" - , KEY_C = Key.Char "m" - , KEY_V = Key.Char "c" - , KEY_B = Key.Char "v" - , KEY_N = Key.Char "k" - , KEY_M = Key.Char "l" - , KEY_COMMA = Key.Char "," - , KEY_DOT = Key.Char "." - , KEY_SLASH = Key.Char "/" - , KEY_SPACE = Key.Char " " - , KEY_KP7 = Key.Char "7" - , KEY_KP8 = Key.Char "8" - , KEY_KP9 = Key.Char "9" - , KEY_KPMINUS = Key.Char "-" - , KEY_KP4 = Key.Char "4" - , KEY_KP5 = Key.Char "5" - , KEY_KP6 = Key.Char "6" - , KEY_KPPLUS = Key.Char "+" - , KEY_KP1 = Key.Char "1" - , KEY_KP2 = Key.Char "2" - , KEY_KP3 = Key.Char "3" - , KEY_KP0 = Key.Char "0" - , KEY_KPDOT = Key.Char "." - , KEY_KPENTER = Key.Ascii 10 - , KEY_KPSLASH = Key.Char "/" - } - } - , Map::{ - , mod1 = True - , keys = toMap - { KEY_1 = Key.Char "!" - , KEY_2 = Key.Char "@" - , KEY_3 = Key.Char "#" - , KEY_4 = Key.Char "\$" - , KEY_5 = Key.Char "%" - , KEY_6 = Key.Char "^" - , KEY_7 = Key.Ascii 38 - , KEY_8 = Key.Char "*" - , KEY_9 = Key.Char "(" - , KEY_0 = Key.Char ")" - , KEY_MINUS = Key.Char "_" - , KEY_EQUAL = Key.Char "+" - , KEY_Q = Key.Char "Q" - , KEY_W = Key.Char "D" - , KEY_E = Key.Char "R" - , KEY_R = Key.Char "W" - , KEY_T = Key.Char "B" - , KEY_Y = Key.Char "J" - , KEY_U = Key.Char "F" - , KEY_I = Key.Char "U" - , KEY_O = Key.Char "P" - , KEY_P = Key.Char ":" - , KEY_LEFTBRACE = Key.Char "{" - , KEY_RIGHTBRACE = Key.Char "}" - , KEY_A = Key.Char "A" - , KEY_S = Key.Char "S" - , KEY_D = Key.Char "H" - , KEY_F = Key.Char "T" - , KEY_G = Key.Char "G" - , KEY_H = Key.Char "Y" - , KEY_J = Key.Char "N" - , KEY_K = Key.Char "E" - , KEY_L = Key.Char "O" - , KEY_SEMICOLON = Key.Char "I" - , KEY_APOSTROPHE = Key.Ascii 34 - , KEY_GRAVE = Key.Char "~" - , KEY_BACKSLASH = Key.Char "|" - , KEY_Z = Key.Char "Z" - , KEY_X = Key.Char "X" - , KEY_C = Key.Char "M" - , KEY_V = Key.Char "C" - , KEY_B = Key.Char "V" - , KEY_N = Key.Char "K" - , KEY_M = Key.Char "L" - , KEY_COMMA = Key.Ascii 60 - , KEY_DOT = Key.Ascii 62 - , KEY_SLASH = Key.Char "?" - } - } - , Map::{ - , mod2 = True - , keys = toMap - { KEY_A = Key.Ascii 1 - , KEY_B = Key.Ascii 22 - , KEY_C = Key.Ascii 13 - , KEY_D = Key.Ascii 8 - , KEY_E = Key.Ascii 18 - , KEY_F = Key.Ascii 20 - , KEY_G = Key.Ascii 7 - , KEY_H = Key.Ascii 25 - , KEY_I = Key.Ascii 21 - , KEY_J = Key.Ascii 14 - , KEY_K = Key.Ascii 5 - , KEY_L = Key.Ascii 15 - , KEY_M = Key.Ascii 12 - , KEY_N = Key.Ascii 11 - , KEY_O = Key.Ascii 16 - , KEY_P = Key.Ascii 9 - , KEY_Q = Key.Ascii 17 - , KEY_R = Key.Ascii 23 - , KEY_S = Key.Ascii 19 - , KEY_T = Key.Ascii 2 - , KEY_U = Key.Ascii 6 - , KEY_V = Key.Ascii 3 - , KEY_W = Key.Ascii 4 - , KEY_X = Key.Ascii 24 - , KEY_Y = Key.Ascii 10 - , KEY_Z = Key.Ascii 26 - } - } - , Map::{ - , mod3 = True - , keys = toMap - { KEY_4 = Key.Code 8364 - , KEY_A = Key.Code 228 - , KEY_S = Key.Code 223 - , KEY_I = Key.Code 252 - , KEY_DOT = Key.Code 8230 - , KEY_K = Key.Code 235 - , KEY_C = Key.Code 181 - , KEY_L = Key.Code 246 - } - } - , Map::{ - , mod1 = True - , mod3 = True - , keys = toMap - { KEY_0 = Key.Code 8320 - , KEY_1 = Key.Code 8321 - , KEY_2 = Key.Code 8322 - , KEY_3 = Key.Code 8323 - , KEY_4 = Key.Code 8324 - , KEY_5 = Key.Code 8325 - , KEY_6 = Key.Code 8326 - , KEY_7 = Key.Code 8327 - , KEY_8 = Key.Code 8328 - , KEY_9 = Key.Code 8329 - } - } - ] - -in Prelude.List.map Map.Type XML.Type mapToXML workman diff --git a/tests/test-driver/test-driver.py b/tests/test-driver/test-driver.py deleted file mode 100644 index 45137fc..0000000 --- a/tests/test-driver/test-driver.py +++ /dev/null @@ -1,912 +0,0 @@ -#! /somewhere/python3 -# Copyright (c) 2003-2020 Nixpkgs/NixOS contributors - -from contextlib import contextmanager, _GeneratorContextManager -from queue import Queue, Empty -from typing import Tuple, Any, Callable, Dict, Iterator, Optional, List -from xml.sax.saxutils import XMLGenerator -import _thread -import atexit -import base64 -import codecs -import os -import pathlib -import ptpython.repl -import pty -import re -import shlex -import shutil -import socket -import subprocess -import sys -import tempfile -import time -import unicodedata - -CHAR_TO_KEY = { - "A": "shift-a", - "N": "shift-n", - "-": "0x0C", - "_": "shift-0x0C", - "B": "shift-b", - "O": "shift-o", - "=": "0x0D", - "+": "shift-0x0D", - "C": "shift-c", - "P": "shift-p", - "[": "0x1A", - "{": "shift-0x1A", - "D": "shift-d", - "Q": "shift-q", - "]": "0x1B", - "}": "shift-0x1B", - "E": "shift-e", - "R": "shift-r", - ";": "0x27", - ":": "shift-0x27", - "F": "shift-f", - "S": "shift-s", - "'": "0x28", - '"': "shift-0x28", - "G": "shift-g", - "T": "shift-t", - "`": "0x29", - "~": "shift-0x29", - "H": "shift-h", - "U": "shift-u", - "\\": "0x2B", - "|": "shift-0x2B", - "I": "shift-i", - "V": "shift-v", - ",": "0x33", - "<": "shift-0x33", - "J": "shift-j", - "W": "shift-w", - ".": "0x34", - ">": "shift-0x34", - "K": "shift-k", - "X": "shift-x", - "/": "0x35", - "?": "shift-0x35", - "L": "shift-l", - "Y": "shift-y", - " ": "spc", - "M": "shift-m", - "Z": "shift-z", - "\n": "ret", - "!": "shift-0x02", - "@": "shift-0x03", - "#": "shift-0x04", - "$": "shift-0x05", - "%": "shift-0x06", - "^": "shift-0x07", - "&": "shift-0x08", - "*": "shift-0x09", - "(": "shift-0x0A", - ")": "shift-0x0B", -} - -# Forward references -log: "Logger" -machines: "List[Machine]" - - -def eprint(*args: object, **kwargs: Any) -> None: - print(*args, file=sys.stderr, **kwargs) - - -def make_command(args: list) -> str: - return " ".join(map(shlex.quote, (map(str, args)))) - - -def retry(fn: Callable) -> None: - """Call the given function repeatedly, with 1 second intervals, - until it returns True or a timeout is reached. - """ - - for _ in range(900): - if fn(False): - return - time.sleep(1) - - if not fn(True): - raise Exception("action timed out") - - -class Logger: - def __init__(self) -> None: - self.logfile = os.environ.get("LOGFILE", "/dev/null") - self.logfile_handle = codecs.open(self.logfile, "wb") - self.xml = XMLGenerator(self.logfile_handle, encoding="utf-8") - self.queue: "Queue[Dict[str, str]]" = Queue() - - self.xml.startDocument() - self.xml.startElement("logfile", attrs={}) - - def close(self) -> None: - self.xml.endElement("logfile") - self.xml.endDocument() - self.logfile_handle.close() - - def sanitise(self, message: str) -> str: - return "".join(ch for ch in message if unicodedata.category(ch)[0] != "C") - - def maybe_prefix(self, message: str, attributes: Dict[str, str]) -> str: - if "machine" in attributes: - return "{}: {}".format(attributes["machine"], message) - return message - - def log_line(self, message: str, attributes: Dict[str, str]) -> None: - self.xml.startElement("line", attributes) - self.xml.characters(message) - self.xml.endElement("line") - - def log(self, message: str, attributes: Dict[str, str] = {}) -> None: - eprint(self.maybe_prefix(message, attributes)) - self.drain_log_queue() - self.log_line(message, attributes) - - def enqueue(self, message: Dict[str, str]) -> None: - self.queue.put(message) - - def drain_log_queue(self) -> None: - try: - while True: - item = self.queue.get_nowait() - attributes = {"machine": item["machine"], "type": "serial"} - self.log_line(self.sanitise(item["msg"]), attributes) - except Empty: - pass - - @contextmanager - def nested(self, message: str, attributes: Dict[str, str] = {}) -> Iterator[None]: - eprint(self.maybe_prefix(message, attributes)) - - self.xml.startElement("nest", attrs={}) - self.xml.startElement("head", attributes) - self.xml.characters(message) - self.xml.endElement("head") - - tic = time.time() - self.drain_log_queue() - yield - self.drain_log_queue() - toc = time.time() - self.log("({:.2f} seconds)".format(toc - tic)) - - self.xml.endElement("nest") - - -class Machine: - def __init__(self, args: Dict[str, Any]) -> None: - if "name" in args: - self.name = args["name"] - else: - self.name = "machine" - cmd = args.get("startCommand", None) - if cmd: - match = re.search("bin/run-(.+)-vm$", cmd) - if match: - self.name = match.group(1) - - self.script = args.get("startCommand", self.create_startcommand(args)) - - tmp_dir = os.environ.get("TMPDIR", tempfile.gettempdir()) - - def create_dir(name: str) -> str: - path = os.path.join(tmp_dir, name) - os.makedirs(path, mode=0o700, exist_ok=True) - return path - - self.state_dir = create_dir("vm-state-{}".format(self.name)) - self.shared_dir = create_dir("shared-xchg") - - self.booted = False - self.connected = False - self.pid: Optional[int] = None - self.socket = None - self.monitor: Optional[socket.socket] = None - self.logger: Logger = args["log"] - self.serialQueue: "Queue[str]" = Queue() - - self.allow_reboot = args.get("allowReboot", False) - - @staticmethod - def create_startcommand(args: Dict[str, str]) -> str: - net_backend = "-netdev user,id=net0" - net_frontend = "-device virtio-net-pci,netdev=net0" - - start_command = "qemu-system-x86_64 -m 384 $QEMU_OPTS " - - if "hda" in args: - hda_path = os.path.abspath(args["hda"]) - if args.get("hdaInterface", "") == "scsi": - start_command += ( - "-drive id=hda,file=" - + hda_path - + ",werror=report,if=none " - + "-device scsi-hd,drive=hda " - ) - else: - start_command += ( - "-drive file=" - + hda_path - + ",if=" - + args["hdaInterface"] - + ",werror=report " - ) - - if "cdrom" in args: - start_command += "-cdrom " + args["cdrom"] + " " - - if "usb" in args: - start_command += ( - "-device piix3-usb-uhci -drive " - + "id=usbdisk,file=" - + args["usb"] - + ",if=none,readonly " - + "-device usb-storage,drive=usbdisk " - ) - if "bios" in args: - start_command += "-bios " + args["bios"] + " " - - start_command += args.get("qemuFlags", "") - - return start_command - - def is_up(self) -> bool: - return self.booted and self.connected - - def log(self, msg: str) -> None: - self.logger.log(msg, {"machine": self.name}) - - def nested(self, msg: str, attrs: Dict[str, str] = {}) -> _GeneratorContextManager: - my_attrs = {"machine": self.name} - my_attrs.update(attrs) - return self.logger.nested(msg, my_attrs) - - def wait_for_monitor_prompt(self) -> str: - assert self.monitor is not None - answer = "" - while True: - undecoded_answer = self.monitor.recv(1024) - if not undecoded_answer: - break - answer += undecoded_answer.decode() - if answer.endswith("(qemu) "): - break - return answer - - def send_monitor_command(self, command: str) -> str: - message = ("{}\n".format(command)).encode() - self.log("sending monitor command: {}".format(command)) - assert self.monitor is not None - self.monitor.send(message) - return self.wait_for_monitor_prompt() - - def wait_for_unit(self, unit: str, user: Optional[str] = None) -> None: - """Wait for a systemd unit to get into "active" state. - Throws exceptions on "failed" and "inactive" states as well as - after timing out. - """ - - def check_active(_: Any) -> bool: - info = self.get_unit_info(unit, user) - state = info["ActiveState"] - if state == "failed": - raise Exception('unit "{}" reached state "{}"'.format(unit, state)) - - if state == "inactive": - status, jobs = self.systemctl("list-jobs --full 2>&1", user) - if "No jobs" in jobs: - info = self.get_unit_info(unit, user) - if info["ActiveState"] == state: - raise Exception( - ( - 'unit "{}" is inactive and there ' "are no pending jobs" - ).format(unit) - ) - - return state == "active" - - retry(check_active) - - def get_unit_info(self, unit: str, user: Optional[str] = None) -> Dict[str, str]: - status, lines = self.systemctl('--no-pager show "{}"'.format(unit), user) - if status != 0: - raise Exception( - 'retrieving systemctl info for unit "{}" {} failed with exit code {}'.format( - unit, "" if user is None else 'under user "{}"'.format(user), status - ) - ) - - line_pattern = re.compile(r"^([^=]+)=(.*)$") - - def tuple_from_line(line: str) -> Tuple[str, str]: - match = line_pattern.match(line) - assert match is not None - return match[1], match[2] - - return dict( - tuple_from_line(line) - for line in lines.split("\n") - if line_pattern.match(line) - ) - - def systemctl(self, q: str, user: Optional[str] = None) -> Tuple[int, str]: - if user is not None: - q = q.replace("'", "\\'") - return self.execute( - ( - "su -l {} --shell /bin/sh -c " - "$'XDG_RUNTIME_DIR=/run/user/`id -u` " - "systemctl --user {}'" - ).format(user, q) - ) - return self.execute("systemctl {}".format(q)) - - def require_unit_state(self, unit: str, require_state: str = "active") -> None: - with self.nested( - "checking if unit ‘{}’ has reached state '{}'".format(unit, require_state) - ): - info = self.get_unit_info(unit) - state = info["ActiveState"] - if state != require_state: - raise Exception( - "Expected unit ‘{}’ to to be in state ".format(unit) - + "'{}' but it is in state ‘{}’".format(require_state, state) - ) - - def execute(self, command: str) -> Tuple[int, str]: - self.connect() - - out_command = "( {} ); echo '|!=EOF' $?\n".format(command) - self.shell.send(out_command.encode()) - - output = "" - status_code_pattern = re.compile(r"(.*)\|\!=EOF\s+(\d+)") - - while True: - chunk = self.shell.recv(4096).decode(errors="ignore") - match = status_code_pattern.match(chunk) - if match: - output += match[1] - status_code = int(match[2]) - return (status_code, output) - output += chunk - - def succeed(self, *commands: str) -> str: - """Execute each command and check that it succeeds.""" - output = "" - for command in commands: - with self.nested("must succeed: {}".format(command)): - (status, out) = self.execute(command) - if status != 0: - self.log("output: {}".format(out)) - raise Exception( - "command `{}` failed (exit code {})".format(command, status) - ) - output += out - return output - - def fail(self, *commands: str) -> None: - """Execute each command and check that it fails.""" - for command in commands: - with self.nested("must fail: {}".format(command)): - status, output = self.execute(command) - if status == 0: - raise Exception( - "command `{}` unexpectedly succeeded".format(command) - ) - - def wait_until_succeeds(self, command: str) -> str: - """Wait until a command returns success and return its output. - Throws an exception on timeout. - """ - output = "" - - def check_success(_: Any) -> bool: - nonlocal output - status, output = self.execute(command) - return status == 0 - - with self.nested("waiting for success: {}".format(command)): - retry(check_success) - return output - - def wait_until_fails(self, command: str) -> str: - """Wait until a command returns failure. - Throws an exception on timeout. - """ - output = "" - - def check_failure(_: Any) -> bool: - nonlocal output - status, output = self.execute(command) - return status != 0 - - with self.nested("waiting for failure: {}".format(command)): - retry(check_failure) - return output - - def wait_for_shutdown(self) -> None: - if not self.booted: - return - - with self.nested("waiting for the VM to power off"): - sys.stdout.flush() - self.process.wait() - - self.pid = None - self.booted = False - self.connected = False - - def get_tty_text(self, tty: str) -> str: - status, output = self.execute( - "fold -w$(stty -F /dev/tty{0} size | " - "awk '{{print $2}}') /dev/vcs{0}".format(tty) - ) - return output - - def wait_until_tty_matches(self, tty: str, regexp: str) -> None: - """Wait until the visible output on the chosen TTY matches regular - expression. Throws an exception on timeout. - """ - matcher = re.compile(regexp) - - def tty_matches(last: bool) -> bool: - text = self.get_tty_text(tty) - if last: - self.log( - f"Last chance to match /{regexp}/ on TTY{tty}, " - f"which currently contains: {text}" - ) - return len(matcher.findall(text)) > 0 - - with self.nested("waiting for {} to appear on tty {}".format(regexp, tty)): - retry(tty_matches) - - def wait_until_serial_output(self, regexp: str) -> None: - """Wait until the serial output matches regular expression. - Throws an exception on timeout. - """ - matcher = re.compile(regexp) - - def serial_matches(last: bool) -> bool: - while not self.serialQueue.empty(): - text = self.serialQueue.get() - if last: - self.log( - f"Last chance to match /{regexp}/ on serial, " - f"which currently contains: {text}" - ) - if len(matcher.findall(text)) > 0: - return True - return False - - with self.nested("waiting for {} to appear on serial output".format(regexp)): - retry(serial_matches) - - def send_chars(self, chars: List[str]) -> None: - with self.nested("sending keys ‘{}‘".format(chars)): - for char in chars: - self.send_key(char) - - def wait_for_file(self, filename: str) -> None: - """Waits until the file exists in machine's file system.""" - - def check_file(_: Any) -> bool: - status, _ = self.execute("test -e {}".format(filename)) - return status == 0 - - with self.nested("waiting for file ‘{}‘".format(filename)): - retry(check_file) - - def wait_for_open_port(self, port: int) -> None: - def port_is_open(_: Any) -> bool: - status, _ = self.execute("nc -z localhost {}".format(port)) - return status == 0 - - with self.nested("waiting for TCP port {}".format(port)): - retry(port_is_open) - - def wait_for_closed_port(self, port: int) -> None: - def port_is_closed(_: Any) -> bool: - status, _ = self.execute("nc -z localhost {}".format(port)) - return status != 0 - - retry(port_is_closed) - - def start_job(self, jobname: str, user: Optional[str] = None) -> Tuple[int, str]: - return self.systemctl("start {}".format(jobname), user) - - def stop_job(self, jobname: str, user: Optional[str] = None) -> Tuple[int, str]: - return self.systemctl("stop {}".format(jobname), user) - - def wait_for_job(self, jobname: str) -> None: - self.wait_for_unit(jobname) - - def connect(self) -> None: - if self.connected: - return - - with self.nested("waiting for the VM to finish booting"): - self.start() - - tic = time.time() - self.shell.recv(1024) - # TODO: Timeout - toc = time.time() - - self.log("connected to guest root shell") - self.log("(connecting took {:.2f} seconds)".format(toc - tic)) - self.connected = True - - def screenshot(self, filename: str) -> None: - out_dir = os.environ.get("out", os.getcwd()) - word_pattern = re.compile(r"^\w+$") - if word_pattern.match(filename): - filename = os.path.join(out_dir, "{}.png".format(filename)) - tmp = "{}.ppm".format(filename) - - with self.nested( - "making screenshot {}".format(filename), - {"image": os.path.basename(filename)}, - ): - self.send_monitor_command("screendump {}".format(tmp)) - ret = subprocess.run("pnmtopng {} > {}".format(tmp, filename), shell=True) - os.unlink(tmp) - if ret.returncode != 0: - raise Exception("Cannot convert screenshot") - - def copy_from_host_via_shell(self, source: str, target: str) -> None: - """Copy a file from the host into the guest by piping it over the - shell into the destination file. Works without host-guest shared folder. - Prefer copy_from_host for whenever possible. - """ - with open(source, "rb") as fh: - content_b64 = base64.b64encode(fh.read()).decode() - self.succeed( - f"mkdir -p $(dirname {target})", - f"echo -n {content_b64} | base64 -d > {target}", - ) - - def copy_from_host(self, source: str, target: str) -> None: - """Copy a file from the host into the guest via the `shared_dir` shared - among all the VMs (using a temporary directory). - """ - host_src = pathlib.Path(source) - vm_target = pathlib.Path(target) - with tempfile.TemporaryDirectory(dir=self.shared_dir) as shared_td: - shared_temp = pathlib.Path(shared_td) - host_intermediate = shared_temp / host_src.name - vm_shared_temp = pathlib.Path("/tmp/shared") / shared_temp.name - vm_intermediate = vm_shared_temp / host_src.name - - self.succeed(make_command(["mkdir", "-p", vm_shared_temp])) - if host_src.is_dir(): - shutil.copytree(host_src, host_intermediate) - else: - shutil.copy(host_src, host_intermediate) - self.succeed("sync") - self.succeed(make_command(["mkdir", "-p", vm_target.parent])) - self.succeed(make_command(["cp", "-r", vm_intermediate, vm_target])) - # Make sure the cleanup is synced into VM - self.succeed("sync") - - def copy_from_vm(self, source: str, target_dir: str = "") -> None: - """Copy a file from the VM (specified by an in-VM source path) to a path - relative to `$out`. The file is copied via the `shared_dir` shared among - all the VMs (using a temporary directory). - """ - # Compute the source, target, and intermediate shared file names - out_dir = pathlib.Path(os.environ.get("out", os.getcwd())) - vm_src = pathlib.Path(source) - with tempfile.TemporaryDirectory(dir=self.shared_dir) as shared_td: - shared_temp = pathlib.Path(shared_td) - vm_shared_temp = pathlib.Path("/tmp/shared") / shared_temp.name - vm_intermediate = vm_shared_temp / vm_src.name - intermediate = shared_temp / vm_src.name - # Copy the file to the shared directory inside VM - self.succeed(make_command(["mkdir", "-p", vm_shared_temp])) - self.succeed(make_command(["cp", "-r", vm_src, vm_intermediate])) - self.succeed("sync") - abs_target = out_dir / target_dir / vm_src.name - abs_target.parent.mkdir(exist_ok=True, parents=True) - # Copy the file from the shared directory outside VM - if intermediate.is_dir(): - shutil.copytree(intermediate, abs_target) - else: - shutil.copy(intermediate, abs_target) - # Make sure the cleanup is synced into VM - self.succeed("sync") - - def dump_tty_contents(self, tty: str) -> None: - """Debugging: Dump the contents of the TTY - """ - self.execute("fold -w 80 /dev/vcs{} | systemd-cat".format(tty)) - - def get_screen_text(self) -> str: - if shutil.which("tesseract") is None: - raise Exception("get_screen_text used but enableOCR is false") - - magick_args = ( - "-filter Catrom -density 72 -resample 300 " - + "-contrast -normalize -despeckle -type grayscale " - + "-sharpen 1 -posterize 3 -negate -gamma 100 " - + "-blur 1x65535" - ) - - tess_args = "-c debug_file=/dev/null --psm 11 --oem 2" - - with self.nested("performing optical character recognition"): - with tempfile.NamedTemporaryFile() as tmpin: - self.send_monitor_command("screendump {}".format(tmpin.name)) - - cmd = "convert {} {} tiff:- | tesseract - - {}".format( - magick_args, tmpin.name, tess_args - ) - ret = subprocess.run(cmd, shell=True, capture_output=True) - if ret.returncode != 0: - raise Exception( - "OCR failed with exit code {}".format(ret.returncode) - ) - - return ret.stdout.decode("utf-8") - - def wait_for_text(self, regex: str) -> None: - def screen_matches(last: bool) -> bool: - text = self.get_screen_text() - matches = re.search(regex, text) is not None - - if last and not matches: - self.log("Last OCR attempt failed. Text was: {}".format(text)) - - return matches - - with self.nested("waiting for {} to appear on screen".format(regex)): - retry(screen_matches) - - def send_key(self, key: str) -> None: - key = CHAR_TO_KEY.get(key, key) - self.send_monitor_command("sendkey {}".format(key)) - - def start(self) -> None: - if self.booted: - return - - self.log("starting vm") - - def create_socket(path: str) -> socket.socket: - if os.path.exists(path): - os.unlink(path) - s = socket.socket(family=socket.AF_UNIX, type=socket.SOCK_STREAM) - s.bind(path) - s.listen(1) - return s - - monitor_path = os.path.join(self.state_dir, "monitor") - self.monitor_socket = create_socket(monitor_path) - - shell_path = os.path.join(self.state_dir, "shell") - self.shell_socket = create_socket(shell_path) - - qemu_options = ( - " ".join( - [ - "" if self.allow_reboot else "-no-reboot", - "-monitor unix:{}".format(monitor_path), - "-chardev socket,id=shell,path={}".format(shell_path), - "-device virtio-serial", - "-device virtconsole,chardev=shell", - "-device virtio-rng-pci", - "-serial stdio" if "DISPLAY" in os.environ else "-nographic", - ] - ) - + " " - + os.environ.get("QEMU_OPTS", "") - ) - - environment = dict(os.environ) - environment.update( - { - "TMPDIR": self.state_dir, - "SHARED_DIR": self.shared_dir, - "USE_TMPDIR": "1", - "QEMU_OPTS": qemu_options, - } - ) - - self.process = subprocess.Popen( - self.script, - bufsize=1, - stdin=subprocess.DEVNULL, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - shell=True, - cwd=self.state_dir, - env=environment, - ) - self.monitor, _ = self.monitor_socket.accept() - self.shell, _ = self.shell_socket.accept() - - def process_serial_output() -> None: - assert self.process.stdout is not None - for _line in self.process.stdout: - # Ignore undecodable bytes that may occur in boot menus - line = _line.decode(errors="ignore").replace("\r", "").rstrip() - eprint("{} # {}".format(self.name, line)) - self.logger.enqueue({"msg": line, "machine": self.name}) - self.serialQueue.put(line) - - _thread.start_new_thread(process_serial_output, ()) - - self.wait_for_monitor_prompt() - - self.pid = self.process.pid - self.booted = True - - self.log("QEMU running (pid {})".format(self.pid)) - - def shutdown(self) -> None: - if not self.booted: - return - - self.shell.send("poweroff\n".encode()) - self.wait_for_shutdown() - - def crash(self) -> None: - if not self.booted: - return - - self.log("forced crash") - self.send_monitor_command("quit") - self.wait_for_shutdown() - - def wait_for_x(self) -> None: - """Wait until it is possible to connect to the X server. Note that - testing the existence of /tmp/.X11-unix/X0 is insufficient. - """ - - def check_x(_: Any) -> bool: - cmd = ( - "journalctl -b SYSLOG_IDENTIFIER=systemd | " - + 'grep "Reached target Current graphical"' - ) - status, _ = self.execute(cmd) - if status != 0: - return False - status, _ = self.execute("[ -e /tmp/.X11-unix/X0 ]") - return status == 0 - - with self.nested("waiting for the X11 server"): - retry(check_x) - - def get_window_names(self) -> List[str]: - return self.succeed( - r"xwininfo -root -tree | sed 's/.*0x[0-9a-f]* \"\([^\"]*\)\".*/\1/; t; d'" - ).splitlines() - - def wait_for_window(self, regexp: str) -> None: - pattern = re.compile(regexp) - - def window_is_visible(last_try: bool) -> bool: - names = self.get_window_names() - if last_try: - self.log( - "Last chance to match {} on the window list,".format(regexp) - + " which currently contains: " - + ", ".join(names) - ) - return any(pattern.search(name) for name in names) - - with self.nested("Waiting for a window to appear"): - retry(window_is_visible) - - def sleep(self, secs: int) -> None: - time.sleep(secs) - - def forward_port(self, host_port: int = 8080, guest_port: int = 80) -> None: - """Forward a TCP port on the host to a TCP port on the guest. - Useful during interactive testing. - """ - self.send_monitor_command( - "hostfwd_add tcp::{}-:{}".format(host_port, guest_port) - ) - - def block(self) -> None: - """Make the machine unreachable by shutting down eth1 (the multicast - interface used to talk to the other VMs). We keep eth0 up so that - the test driver can continue to talk to the machine. - """ - self.send_monitor_command("set_link virtio-net-pci.1 off") - - def unblock(self) -> None: - """Make the machine reachable. - """ - self.send_monitor_command("set_link virtio-net-pci.1 on") - - -def create_machine(args: Dict[str, Any]) -> Machine: - global log - args["log"] = log - args["redirectSerial"] = os.environ.get("USE_SERIAL", "0") == "1" - return Machine(args) - - -def start_all() -> None: - global machines - with log.nested("starting all VMs"): - for machine in machines: - machine.start() - - -def join_all() -> None: - global machines - with log.nested("waiting for all VMs to finish"): - for machine in machines: - machine.wait_for_shutdown() - - -def test_script() -> None: - exec(os.environ["testScript"]) - - -def run_tests() -> None: - global machines - tests = os.environ.get("tests", None) - if tests is not None: - with log.nested("running the VM test script"): - try: - exec(tests, globals()) - except Exception as e: - eprint("error: {}".format(str(e))) - sys.exit(1) - else: - ptpython.repl.embed(locals(), globals()) - - # TODO: Collect coverage data - - for machine in machines: - if machine.is_up(): - machine.execute("sync") - - -@contextmanager -def subtest(name: str) -> Iterator[None]: - with log.nested(name): - try: - yield - return True - except Exception as e: - log.log(f'Test "{name}" failed with error: "{e}"') - raise e - - return False - - -if __name__ == "__main__": - log = Logger() - - vm_scripts = sys.argv[1:] - machines = [create_machine({"startCommand": s}) for s in vm_scripts] - machine_eval = [ - "{0} = machines[{1}]".format(m.name, idx) for idx, m in enumerate(machines) - ] - exec("\n".join(machine_eval)) - - @atexit.register - def clean_up() -> None: - with log.nested("cleaning up"): - for machine in machines: - if machine.pid is None: - continue - log.log("killing {} (pid {})".format(machine.name, machine.pid)) - machine.process.kill() - - log.close() - - tic = time.time() - run_tests() - toc = time.time() - print("test script finished in {:.2f}s".format(toc - tic))