diff --git a/modules/nixos/nix/default.nix b/modules/nixos/nix/default.nix index 8d2b5a2..6626885 100644 --- a/modules/nixos/nix/default.nix +++ b/modules/nixos/nix/default.nix @@ -10,12 +10,14 @@ extra-sandbox-paths = [ config.programs.ccache.cacheDir ]; substituters = [ "https://cache.mjallen.dev/nas-cache" + "https://nixos-apple-silicon.cachix.org" "https://nixos-raspberrypi.cachix.org" "https://nix-community.cachix.org" "https://cache.nixos.org/" ]; trusted-public-keys = [ "nas-cache:Y7PR+XTLr1bLIL85PKb9Tk9/BnE5HndTKvZYWVP1/48=" + "nixos-apple-silicon.cachix.org-1:8psDu5SA5dAD7qA0zMy5UT292TxeEPzIz8VVEr2Js20=" "nixos-raspberrypi.cachix.org-1:4iMO9LXa8BqhU+Rpg6LQKiGa2lsNh/j2oiYLNOQ5sPI=" "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" ]; diff --git a/modules/nixos/user/default.nix b/modules/nixos/user/default.nix index f0a90d0..25454e4 100644 --- a/modules/nixos/user/default.nix +++ b/modules/nixos/user/default.nix @@ -119,6 +119,7 @@ in "avahi" "podman" "libvirtd" + "fuse" ] ++ cfg.extraGroups; diff --git a/packages/omnissa/default.nix b/packages/omnissa/default.nix new file mode 100644 index 0000000..b7d99ec --- /dev/null +++ b/packages/omnissa/default.nix @@ -0,0 +1,227 @@ +{ + stdenv, + lib, + buildFHSEnv, + copyDesktopItems, + fetchurl, + gsettings-desktop-schemas, + makeDesktopItem, + makeWrapper, + opensc, + writeTextDir, + writeShellScript, + # New dependencies for aarch64 support + fex, + muvm, + configText ? "", + # Allow users to choose emulation method + useMusvm ? true, # Use muvm + FEX (better isolation) vs just FEX +}: +let + version = "2506"; + + isAarch64 = stdenv.hostPlatform.system == "aarch64-linux"; + isX86_64 = stdenv.hostPlatform.system == "x86_64-linux"; + + # Always extract x64 binaries (we'll emulate on aarch64) + sysArch = "x64"; + + # For USB support, ensure that /var/run/omnissa/ + # exists and is owned by you. Then run omnissa-usbarbitrator as root. + + mainProgram = "horizon-client"; + + # This forces the default GTK theme (Adwaita) because Horizon is prone to + # UI usability issues when using non-default themes, such as Adwaita-dark. + wrapBinCommands = path: name: '' + makeWrapper "$out/${path}/${name}" "$out/bin/${name}_wrapper" \ + --set GTK_THEME Adwaita \ + --suffix XDG_DATA_DIRS : "${gsettings-desktop-schemas}/share/gsettings-schemas/${gsettings-desktop-schemas.name}" \ + --suffix LD_LIBRARY_PATH : "$out/lib/omnissa/horizon/crtbora:$out/lib/omnissa" + ''; + + omnissaHorizonClientFiles = stdenv.mkDerivation { + pname = "omnissa-horizon-files"; + inherit version; + src = fetchurl { + url = "https://download3.omnissa.com/software/CART26FQ2_LIN_2506_TARBALL/Omnissa-Horizon-Client-Linux-2506-8.16.0-16536624989.tar.gz"; + sha256 = "5515e79188e2605ced5a95c3a3829865b567be5d7a8de00a57455f7b5b2ae392"; + }; + nativeBuildInputs = [ makeWrapper ]; + installPhase = '' + mkdir ext + find ${sysArch} -type f -print0 | xargs -0n1 tar -Cext --strip-components=1 -xf + + chmod -R u+w ext/usr/lib + mv ext/usr $out + cp -r ext/${sysArch}/include $out/ + cp -r ext/${sysArch}/lib $out/ + + # Horizon includes a copy of libstdc++ which is loaded via $LD_LIBRARY_PATH + # when it cannot detect a new enough version already present on the system. + # The checks are distribution-specific and do not function correctly on NixOS. + # Deleting the bundled library is the simplest way to force it to use our version. + rm "$out/lib/omnissa/gcc/libstdc++.so.6" + + # This opensc library is required to support smartcard authentication during the + # initial connection to Horizon. + mkdir $out/lib/omnissa/horizon/pkcs11 + ln -s ${opensc}/lib/pkcs11/opensc-pkcs11.so $out/lib/omnissa/horizon/pkcs11/libopenscpkcs11.so + + ${wrapBinCommands "bin" "horizon-client"} + ${wrapBinCommands "lib/omnissa/horizon/usb" "horizon-eucusbarbitrator"} + ''; + }; + + # x86_64 FHS environment for native or emulated execution + omnissaFHSUserEnv = + pname: + buildFHSEnv { + inherit pname version; + + # On aarch64, we need to invoke via FEX or muvm + runScript = "${omnissaHorizonClientFiles}/bin/${pname}_wrapper"; + + targetPkgs = + pkgs: with pkgs; [ + at-spi2-atk + atk + cairo + dbus + file + fontconfig + freetype + gdk-pixbuf + glib + gtk2 + gtk3-x11 + harfbuzz + liberation_ttf + libjpeg + libpng + libpulseaudio + libtiff + libudev0-shim + libuuid + libv4l + pango + pcsclite + pixman + udev + omnissaHorizonClientFiles + xorg.libX11 + xorg.libXau + xorg.libXcursor + xorg.libXext + xorg.libXi + xorg.libXinerama + xorg.libxkbfile + xorg.libXrandr + xorg.libXrender + xorg.libXScrnSaver + xorg.libXtst + zlib + libxml2_13 + + (writeTextDir "etc/omnissa/config" configText) + ]; + }; + + # Create wrapper scripts for aarch64 that use FEX or muvm + # Option 1: Direct FEX execution (simpler, less isolation) + fexWrapper = pname: writeShellScript "${pname}-fex-wrapper" '' + export FEXINTERPRETER="${fex}/bin/FEXInterpreter" + export FEX_ROOTFS="${fex}/share/fex-emu/RootFS" + + # Set up FEX environment + export FEX_TSOENABLED=1 + + exec ${fex}/bin/FEXBash -c '${omnissaFHSUserEnv pname}/bin/${pname} "$@"' -- "$@" + ''; + + # Option 2: muvm + FEX (better isolation, handles kernel differences) + muvmWrapper = pname: writeShellScript "${pname}-muvm-wrapper" '' + # muvm creates a lightweight VM with x86_64 emulation via FEX + # This provides better isolation and compatibility + + exec ${muvm}/bin/muvm \ + --fex \ + --share-display \ + --share-sound \ + -- ${omnissaFHSUserEnv pname}/bin/${pname} "$@" + ''; + + # Select the appropriate wrapper based on configuration + aarch64Wrapper = pname: + if useMusvm + then muvmWrapper pname + else fexWrapper pname; + + # Final wrapper that handles both architectures + universalWrapper = pname: + if isAarch64 + then aarch64Wrapper pname + else "${omnissaFHSUserEnv pname}/bin/${pname}"; + + desktopItem = makeDesktopItem { + name = "horizon-client"; + desktopName = "Omnissa Horizon Client"; + icon = "${omnissaHorizonClientFiles}/share/icons/horizon-client.png"; + exec = "${ + if isAarch64 + then aarch64Wrapper mainProgram + else "${omnissaFHSUserEnv mainProgram}/bin/${mainProgram}" + } %u"; + mimeTypes = [ + "x-scheme-handler/horizon-client" + "x-scheme-handler/vmware-view" + ]; + }; + +in +stdenv.mkDerivation { + pname = "omnissa-horizon-client"; + inherit version; + + dontUnpack = true; + + nativeBuildInputs = [ copyDesktopItems ]; + + desktopItems = [ desktopItem ]; + + installPhase = '' + runHook preInstall + mkdir -p $out/bin + + ${if isAarch64 then '' + # On aarch64, create wrapper scripts that use FEX/muvm + cp ${aarch64Wrapper "horizon-client"} $out/bin/horizon-client + chmod +x $out/bin/horizon-client + cp ${aarch64Wrapper "omnissa-usbarbitrator"} $out/bin/omnissa-usbarbitrator + chmod +x $out/bin/omnissa-usbarbitrator + '' else '' + # On x86_64, use native FHS environment directly + ln -s ${omnissaFHSUserEnv "horizon-client"}/bin/horizon-client $out/bin/ + ln -s ${omnissaFHSUserEnv "omnissa-usbarbitrator"}/bin/omnissa-usbarbitrator $out/bin/ + ''} + + runHook postInstall + ''; + + unwrapped = omnissaHorizonClientFiles; + + passthru = { + updateScript = ./update.sh; + # Expose FHS env for debugging + fhsEnv = omnissaFHSUserEnv mainProgram; + }; + + meta = with lib; { + inherit mainProgram; + description = "Allows you to connect to your Omnissa Horizon virtual desktop"; + homepage = "https://www.omnissa.com/products/horizon-8/"; + license = licenses.unfree; + platforms = [ "x86_64-linux" "aarch64-linux" ]; + maintainers = with maintainers; [ mhutter ]; + }; +} \ No newline at end of file diff --git a/systems/aarch64-linux/macbook-pro-nixos/default.nix b/systems/aarch64-linux/macbook-pro-nixos/default.nix index 197e92b..f9a06f2 100755 --- a/systems/aarch64-linux/macbook-pro-nixos/default.nix +++ b/systems/aarch64-linux/macbook-pro-nixos/default.nix @@ -10,6 +10,9 @@ ./services.nix ]; + nix.settings.extra-platforms = [ "x86_64-linux" ]; + boot.binfmt.emulatedSystems = [ "x86_64-linux" ]; + hardware.asahi = { enable = true; peripheralFirmwareDirectory = ./firmware; @@ -30,9 +33,6 @@ }; user = { name = "matt"; - extraGroups = [ - "ratbagd" - "input" "scanner" "lp" "video" @@ -91,6 +91,12 @@ nixpkgs.config.allowUnsupportedSystem = true; virtualisation = { + libvirtd.enable = true; + # efi = { + # OVMF = (pkgs.OVMF.override { + # secureBoot = true; + # }); + # }; waydroid.enable = false; # - CONFIG_ANDROID_BINDER_IPC is not enabled! # - CONFIG_ANDROID_BINDERFS is not enabled @@ -107,10 +113,22 @@ asahi-nvram asahi-wifisync cabextract + erofs-utils + fex + light micro + muvm + squashfuse + squashfsTools unzip vim # Do not forget to add an editor to edit configuration.nix! The Nano editor is also installed by default. + virt-manager wget + + + (pkgs.OVMF.override { + secureBoot = true; + }) ]; environment.sessionVariables = {