diff --git a/modules/common/services/desktop.nix b/modules/common/services/desktop.nix index 9fb54338d..117813921 100644 --- a/modules/common/services/desktop.nix +++ b/modules/common/services/desktop.nix @@ -167,6 +167,13 @@ in icon = "${pkgs.icon-pack}/system-file-manager.svg"; } + { + name = "Network Settings"; + description = "Manage Network & Wi-Fi Settings"; + path = "${pkgs.nm-launcher.override { inherit (config.ghaf.users.accounts) uid; }}/bin/nm-launcher"; + icon = "${pkgs.icon-pack}/preferences-system-network.svg"; + } + { name = "Bluetooth Settings"; description = "Manage Bluetooth Devices & Settings"; diff --git a/modules/common/systemd/hardened-configs/common/microvm@.nix b/modules/common/systemd/hardened-configs/common/microvm@.nix index 47715ae7f..46e91956d 100644 --- a/modules/common/systemd/hardened-configs/common/microvm@.nix +++ b/modules/common/systemd/hardened-configs/common/microvm@.nix @@ -25,7 +25,7 @@ ProtectSystem = "full"; ProtectProc = "noaccess"; # ReadWritePaths=[ "/etc"]; - PrivateTmp = true; + PrivateTmp = false; # Not applicable for the service runs as root # PrivateMounts=true; diff --git a/modules/common/users/accounts.nix b/modules/common/users/accounts.nix index a474cd408..01b24aa20 100644 --- a/modules/common/users/accounts.nix +++ b/modules/common/users/accounts.nix @@ -23,6 +23,13 @@ in A default user to create in the system. ''; }; + uid = mkOption { + default = 1000; + type = with types; int; + description = '' + A default user id for the user. + ''; + }; password = mkOption { default = "ghaf"; type = with types; str; @@ -38,6 +45,7 @@ in users."${cfg.user}" = { isNormalUser = true; inherit (cfg) password; + inherit (cfg) uid; #TODO add "docker" use "lib.optionals" extraGroups = [ "wheel" diff --git a/modules/desktop/graphics/waybar.config.nix b/modules/desktop/graphics/waybar.config.nix index 765ebe758..7890de81a 100644 --- a/modules/desktop/graphics/waybar.config.nix +++ b/modules/desktop/graphics/waybar.config.nix @@ -107,7 +107,9 @@ in }, "custom/admin": { "format": " ", - "on-click": "${pkgs.nm-launcher}/bin/nm-launcher", + "on-click": "${ + pkgs.nm-launcher.override { inherit (config.ghaf.users.accounts) uid; } + }/bin/nm-launcher", "tooltip": false }, "pulseaudio": { diff --git a/modules/hardware/common/default.nix b/modules/hardware/common/default.nix index 4ba3c653b..fb13c09f5 100644 --- a/modules/hardware/common/default.nix +++ b/modules/hardware/common/default.nix @@ -8,5 +8,6 @@ ./devices.nix ./kernel.nix ./qemu.nix + ./shared-mem.nix ]; } diff --git a/modules/hardware/common/shared-mem.nix b/modules/hardware/common/shared-mem.nix new file mode 100644 index 000000000..3e524717b --- /dev/null +++ b/modules/hardware/common/shared-mem.nix @@ -0,0 +1,229 @@ +# Copyright 2022-2024 TII (SSRC) and the Ghaf contributors +# SPDX-License-Identifier: Apache-2.0 +# +# Module for Shared Memory Definitions +# +{ + config, + lib, + pkgs, + ... +}: +with lib; +{ + options.ghaf.shm = { + enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = mdDoc '' + Enables using shared memory between VMs. + ''; + }; + memSize = mkOption { + type = types.int; + default = 16; + description = mdDoc '' + Defines shared memory size in MBytes + ''; + }; + hostSocketPath = mkOption { + type = types.path; + default = "/tmp/ivshmem_socket"; # The value is hardcoded in the application + description = mdDoc '' + Defines location of the shared memory socket. It's used by qemu + instances for memory sharing and sending interrupts. + ''; + }; + flataddr = mkOption { + type = types.str; + default = "0x920000000"; + description = mdDoc '' + If set to a non-zero value, it maps the shared memory + into this physical address. The value is arbitrary chosen, platform + specific, in order not to conflict with other memory areas (e.g. PCI). + ''; + }; + vms_enabled = mkOption { + type = types.listOf types.str; + default = [ ]; + description = mdDoc '' + If set to a non-zero value, it maps the shared memory + into this physical address. The value is arbitrary chosen, platform + specific, in order not to conflict with other memory areas (e.g. PCI). + ''; + }; + enable_host = lib.mkOption { + type = lib.types.bool; + default = false; + description = mdDoc '' + Enables memsocket on host. + ''; + apply = + enable: + if enable && !config.ghaf.shm.enable then + builtins.throw "Enable shared memory in order to use shm on host" + else + enable; + }; + instancesCount = mkOption { + type = types.int; + default = + if config.ghaf.shm.enable_host then + (builtins.length config.ghaf.shm.vms_enabled) + 1 + else + builtins.length config.ghaf.shm.vms_enabled; + }; + serverSocketPath = mkOption { + type = types.path; + default = "/run/user/${builtins.toString config.ghaf.users.accounts.uid}/memsocket-server.sock"; + description = mdDoc '' + Defines location of the listening socket. + It's used by waypipe as an output socket when running in server mode + ''; + }; + clientSocketPath = mkOption { + type = types.path; + default = "/run/user/${builtins.toString config.ghaf.users.accounts.uid}/memsocket-client.sock"; + description = mdDoc '' + Defines location of the output socket. It's fed + with data coming from AppVMs. + It's used by waypipe as an input socket when running in client mode + ''; + }; + display = mkOption { + type = types.bool; + default = false; + description = "Display VMs using shared memory"; + apply = + enable: + if enable && !config.ghaf.shm.enable then + builtins.throw "Enable shared memory in order to use shm display" + else + enable; + }; + }; + + config.boot.kernelParams = + let + hugepagesz = "2M"; # valid values: "2M" and "1G", as kernel supports these huge pages' size + hugepages = + if hugepagesz == "2M" then config.ghaf.shm.memSize / 2 else config.ghaf.shm.memSize / 1024; + in + optionals config.ghaf.shm.enable [ + "hugepagesz=${hugepagesz}" + "hugepages=${toString hugepages}" + ]; + config.environment.systemPackages = optionals config.ghaf.shm.enable_host [ + (pkgs.callPackage ../../../packages/memsocket { vms = config.ghaf.shm.instancesCount; }) + ]; + + config.systemd.services.ivshmemsrv = + let + pidFilePath = "/tmp/ivshmem-server.pid"; + ivShMemSrv = + let + vectors = toString (2 * config.ghaf.shm.instancesCount); + in + pkgs.writeShellScriptBin "ivshmemsrv" '' + chown microvm /dev/hugepages + chgrp kvm /dev/hugepages + if [ -S ${config.ghaf.shm.hostSocketPath} ]; then + echo Erasing ${config.ghaf.shm.hostSocketPath} ${pidFilePath} + rm -f ${config.ghaf.shm.hostSocketPath} + fi + ${pkgs.sudo}/sbin/sudo -u microvm -g kvm ${pkgs.qemu_kvm}/bin/ivshmem-server -p ${pidFilePath} -n ${vectors} -m /dev/hugepages/ -l ${ + (toString config.ghaf.shm.memSize) + "M" + } + ''; + in + lib.mkIf config.ghaf.shm.enable { + enable = true; + description = "Start qemu ivshmem memory server"; + path = [ ivShMemSrv ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + StandardOutput = "journal"; + StandardError = "journal"; + ExecStart = "${ivShMemSrv}/bin/ivshmemsrv"; + }; + }; + config.microvm.vms = + let + memsocket = pkgs.callPackage ../../../packages/memsocket { vms = config.ghaf.shm.instancesCount; }; + vectors = toString (2 * config.ghaf.shm.instancesCount); + makeAssignment = vmName: { + ${vmName} = { + config = { + config = { + microvm = { + qemu = { + extraArgs = [ + "-device" + "ivshmem-doorbell,vectors=${vectors},chardev=ivs_socket,flataddr=${config.ghaf.shm.flataddr}" + "-chardev" + "socket,path=${config.ghaf.shm.hostSocketPath},id=ivs_socket" + ]; + }; + kernelParams = [ "kvm_ivshmem.flataddr=${config.ghaf.shm.flataddr}" ]; + }; + boot.extraModulePackages = [ + (pkgs.linuxPackages.callPackage ../../../packages/memsocket/module.nix { + inherit (config.microvm.vms.${vmName}.config.config.boot.kernelPackages) kernel; + vmCount = config.ghaf.shm.instancesCount; + }) + ]; + services = { + udev = { + extraRules = '' + SUBSYSTEM=="misc",KERNEL=="ivshmem",GROUP="kvm",MODE="0666" + ''; + }; + }; + environment.systemPackages = optionals config.ghaf.shm.enable [ + memsocket + ]; + systemd.user.services.memsocket = + if vmName == "gui-vm" then + lib.mkIf config.ghaf.shm.enable { + enable = true; + description = "memsocket"; + after = [ "labwc.service" ]; + serviceConfig = { + Type = "simple"; + ExecStart = "${memsocket}/bin/memsocket -c ${config.ghaf.shm.clientSocketPath}"; + Restart = "always"; + RestartSec = "1"; + }; + wantedBy = [ "ghaf-session.target" ]; + } + else + # machines connecting to gui-vm + let + vmIndex = lib.lists.findFirstIndex (vm: vm == vmName) null config.ghaf.shm.vms_enabled; + in + lib.mkIf config.ghaf.shm.enable { + enable = true; + description = "memsocket"; + serviceConfig = { + Type = "simple"; + ExecStart = "${memsocket}/bin/memsocket -s ${config.ghaf.shm.serverSocketPath} ${builtins.toString vmIndex}"; + Restart = "always"; + RestartSec = "1"; + }; + wantedBy = [ "default.target" ]; + }; + }; + }; + }; + }; + in + mkIf config.ghaf.shm.enable ( + foldl' lib.attrsets.recursiveUpdate { } (map makeAssignment config.ghaf.shm.vms_enabled) + ); + + config.ghaf.hardware.definition.gpu.kernelConfig.kernelParams = optionals config.ghaf.shm.enable [ + "kvm_ivshmem.flataddr=${config.ghaf.shm.flataddr}" + ]; +} diff --git a/modules/microvm/flake-module.nix b/modules/microvm/flake-module.nix index 9d0f4ff70..f9954d2c4 100644 --- a/modules/microvm/flake-module.nix +++ b/modules/microvm/flake-module.nix @@ -16,6 +16,7 @@ ./virtualization/microvm/modules.nix ./networking.nix ./power-control.nix + ../hardware/common/shared-mem.nix ]; }; } diff --git a/modules/microvm/virtualization/microvm/appvm.nix b/modules/microvm/virtualization/microvm/appvm.nix index 917dc2d9d..aff5fdd11 100644 --- a/modules/microvm/virtualization/microvm/appvm.nix +++ b/modules/microvm/virtualization/microvm/appvm.nix @@ -53,10 +53,17 @@ let }: let waypipeBorder = if vm.borderColor != null then "--border \"${vm.borderColor}\"" else ""; - runWaypipe = pkgs.writeScriptBin "run-waypipe" '' - #!${pkgs.runtimeShell} -e - ${pkgs.waypipe}/bin/waypipe --vsock -s ${toString configHost.ghaf.virtualization.microvm.guivm.waypipePort} ${waypipeBorder} server "$@" - ''; + runWaypipe = + if configHost.ghaf.shm.display then + pkgs.writeScriptBin "run-waypipe" '' + #!${pkgs.runtimeShell} -e + ${pkgs.waypipe}/bin/waypipe -s ${configHost.ghaf.shm.serverSocketPath} ${waypipeBorder} server "$@" + '' + else + pkgs.writeScriptBin "run-waypipe" '' + #!${pkgs.runtimeShell} -e + ${pkgs.waypipe}/bin/waypipe --vsock -s ${toString configHost.ghaf.virtualization.microvm.guivm.waypipePort} ${waypipeBorder} server "$@" + ''; in { ghaf = { diff --git a/modules/microvm/virtualization/microvm/guivm.nix b/modules/microvm/virtualization/microvm/guivm.nix index e7d0ee55a..6e28e148a 100644 --- a/modules/microvm/virtualization/microvm/guivm.nix +++ b/modules/microvm/virtualization/microvm/guivm.nix @@ -122,7 +122,7 @@ let pkgs.sticky-notes ]) ++ [ - pkgs.nm-launcher + (pkgs.nm-launcher.override { inherit (config.ghaf.users.accounts) uid; }) pkgs.bt-launcher pkgs.pamixer pkgs.eww @@ -206,7 +206,11 @@ let description = "waypipe"; serviceConfig = { Type = "simple"; - ExecStart = "${pkgs.waypipe}/bin/waypipe --vsock -s ${toString cfg.waypipePort} client"; + ExecStart = + if config.ghaf.shm.display then + "${pkgs.waypipe}/bin/waypipe -s ${config.ghaf.shm.clientSocketPath} client" + else + "${pkgs.waypipe}/bin/waypipe --vsock -s ${toString cfg.waypipePort} client"; Restart = "always"; RestartSec = "1"; }; @@ -277,6 +281,7 @@ in }; config = lib.mkIf cfg.enable { + ghaf.shm.vms_enabled = [ vmName ]; # Allow access to VMs shared memory microvm.vms."${vmName}" = { autostart = true; config = guivmBaseConfiguration // { diff --git a/modules/reference/appvms/default.nix b/modules/reference/appvms/default.nix index 224660ec8..468f160b1 100644 --- a/modules/reference/appvms/default.nix +++ b/modules/reference/appvms/default.nix @@ -41,5 +41,9 @@ in ++ (lib.optionals cfg.comms-vm [ (import ./comms.nix { inherit pkgs lib config; }) ]) ++ (lib.optionals cfg.business-vm [ (import ./business.nix { inherit pkgs lib config; }) ]); }; + ghaf.shm.vms_enabled = [ + "chromium-vm" + "element-vm" + ]; # Allow access to VMs shared memory }; } diff --git a/overlays/custom-packages/default.nix b/overlays/custom-packages/default.nix index 1868b1941..cc41f899d 100644 --- a/overlays/custom-packages/default.nix +++ b/overlays/custom-packages/default.nix @@ -11,7 +11,7 @@ element-web = final.callPackage ../../packages/element-web { }; waypipe = import ./waypipe { inherit final prev; }; qemu_kvm = import ./qemu { inherit final prev; }; - nm-launcher = final.callPackage ../../packages/nm-launcher { }; + nm-launcher = final.callPackage ../../packages/nm-launcher { uid = null; }; bt-launcher = final.callPackage ../../packages/bt-launcher { }; icon-pack = final.callPackage ../../packages/icon-pack { }; labwc = import ./labwc { inherit prev; }; diff --git a/overlays/custom-packages/qemu/0001-ivshmem-flat-memory-support.patch b/overlays/custom-packages/qemu/0001-ivshmem-flat-memory-support.patch new file mode 100644 index 000000000..690f15352 --- /dev/null +++ b/overlays/custom-packages/qemu/0001-ivshmem-flat-memory-support.patch @@ -0,0 +1,258 @@ +From 13229d9e11eaf15eb6679be036364b9d0256f1c1 Mon Sep 17 00:00:00 2001 +From: Jaroslaw Kurowski +Date: Wed, 10 Jul 2024 15:21:07 +0400 +Subject: ivshmem flat memory support + +--- + contrib/ivshmem-server/ivshmem-server.c | 6 +- + hw/i386/pc_q35.c | 2 + + hw/misc/ivshmem.c | 74 ++++++++++++++++++++++--- + include/hw/misc/ivshmem.h | 1 + + 4 files changed, 71 insertions(+), 12 deletions(-) + +diff --git a/contrib/ivshmem-server/ivshmem-server.c b/contrib/ivshmem-server/ivshmem-server.c +index 2f3c732..906c5d0 100644 +--- a/contrib/ivshmem-server/ivshmem-server.c ++++ b/contrib/ivshmem-server/ivshmem-server.c +@@ -11,6 +11,7 @@ + + #include + #include ++#include + + #include "ivshmem-server.h" + +@@ -297,11 +298,10 @@ ivshmem_server_start(IvshmemServer *server) + server->shm_path); + shm_fd = shm_open(server->shm_path, O_CREAT | O_RDWR, S_IRWXU); + } else { +- gchar *filename = g_strdup_printf("%s/ivshmem.XXXXXX", server->shm_path); ++ gchar *filename = g_strdup_printf("%s/ivshmem", server->shm_path); + IVSHMEM_SERVER_DEBUG(server, "Using file-backed shared memory: %s\n", + server->shm_path); +- shm_fd = mkstemp(filename); +- unlink(filename); ++ shm_fd = open(filename, O_RDWR | O_CREAT, 0666); + g_free(filename); + } + +diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c +index c7bc8a2..d76939e 100644 +--- a/hw/i386/pc_q35.c ++++ b/hw/i386/pc_q35.c +@@ -28,6 +28,7 @@ + * THE SOFTWARE. + */ + ++#include "hw/misc/ivshmem.h" + #include "qemu/osdep.h" + #include "qemu/units.h" + #include "hw/acpi/acpi.h" +@@ -361,6 +362,7 @@ static void pc_q35_machine_options(MachineClass *m) + machine_class_allow_dynamic_sysbus_dev(m, TYPE_INTEL_IOMMU_DEVICE); + machine_class_allow_dynamic_sysbus_dev(m, TYPE_RAMFB_DEVICE); + machine_class_allow_dynamic_sysbus_dev(m, TYPE_VMBUS_BRIDGE); ++ machine_class_allow_dynamic_sysbus_dev(m, TYPE_IVSHMEM_FLAT); + compat_props_add(m->compat_props, + pc_q35_compat_defaults, pc_q35_compat_defaults_len); + } +diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c +index de49d1b..b1761b3 100644 +--- a/hw/misc/ivshmem.c ++++ b/hw/misc/ivshmem.c +@@ -36,6 +36,7 @@ + #include "chardev/char-fe.h" + #include "sysemu/hostmem.h" + #include "qapi/visitor.h" ++#include "hw/sysbus.h" + + #include "hw/misc/ivshmem.h" + #include "qom/object.h" +@@ -59,6 +60,7 @@ + + #define TYPE_IVSHMEM_COMMON "ivshmem-common" + typedef struct IVShmemState IVShmemState; ++typedef struct IvshmemFTState IvshmemFTState; + DECLARE_INSTANCE_CHECKER(IVShmemState, IVSHMEM_COMMON, + TYPE_IVSHMEM_COMMON) + +@@ -74,6 +76,9 @@ DECLARE_INSTANCE_CHECKER(IVShmemState, IVSHMEM_DOORBELL, + DECLARE_INSTANCE_CHECKER(IVShmemState, IVSHMEM, + TYPE_IVSHMEM) + ++#define TYPE_IVSHMEM_FLAT "ivshmem-flat" ++DECLARE_INSTANCE_CHECKER(IvshmemFTState, IVSHMEM_FLAT, TYPE_IVSHMEM_FLAT) ++ + typedef struct Peer { + int nb_eventfds; + EventNotifier *eventfds; +@@ -117,6 +122,15 @@ struct IVShmemState { + /* migration stuff */ + OnOffAuto master; + Error *migration_blocker; ++ ++ /* flat memory stuff */ ++ uint64_t flataddr; ++ DeviceState *flat_dev; ++ MemoryRegion flat_mem; ++}; ++ ++struct IvshmemFTState { ++ SysBusDevice parent_obj; + }; + + /* registers for the Inter-VM shared memory device */ +@@ -476,8 +490,11 @@ static void setup_interrupt(IVShmemState *s, int vector, Error **errp) + + static void process_msg_shmem(IVShmemState *s, int fd, Error **errp) + { ++ Error *local_err = NULL; + struct stat buf; + size_t size; ++ void *ptr; ++ SysBusDevice *sbd; + + if (s->ivshmem_bar2) { + error_setg(errp, "server sent unexpected shared memory message"); +@@ -494,13 +511,26 @@ static void process_msg_shmem(IVShmemState *s, int fd, Error **errp) + + size = buf.st_size; + ++ if (s->flataddr) { ++ ++ ptr = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_HUGETLB|MAP_LOCKED, ++ fd, 0); ++ s->flat_dev = sysbus_create_simple(TYPE_IVSHMEM_FLAT, -1, 0); ++ ++ memory_region_init_ram_ptr(&s->flat_mem, OBJECT(IVSHMEM_FLAT(s->flat_dev)), ++ "ivshmem.flat", size, ptr); ++ sbd = SYS_BUS_DEVICE(s->flat_dev); ++ sysbus_init_mmio(sbd, &s->flat_mem); ++ sysbus_mmio_map(sbd, 0, s->flataddr); ++ } ++ + /* mmap the region and map into the BAR2 */ +- if (!memory_region_init_ram_from_fd(&s->server_bar2, OBJECT(s), +- "ivshmem.bar2", size, RAM_SHARED, +- fd, 0, errp)) { ++ memory_region_init_ram_from_fd(&s->server_bar2, OBJECT(s), "ivshmem.bar2", ++ size, RAM_SHARED, fd, 0, &local_err); ++ if (local_err) { ++ error_propagate(errp, local_err); + return; + } +- + s->ivshmem_bar2 = &s->server_bar2; + } + +@@ -832,7 +862,6 @@ static void ivshmem_write_config(PCIDevice *pdev, uint32_t address, + + static void ivshmem_common_realize(PCIDevice *dev, Error **errp) + { +- ERRP_GUARD(); + IVShmemState *s = IVSHMEM_COMMON(dev); + Error *err = NULL; + uint8_t *pci_conf; +@@ -902,7 +931,8 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp) + if (!ivshmem_is_master(s)) { + error_setg(&s->migration_blocker, + "Migration is disabled when using feature 'peer mode' in device 'ivshmem'"); +- if (migrate_add_blocker(&s->migration_blocker, errp) < 0) { ++ if (migrate_add_blocker(s->migration_blocker, errp) < 0) { ++ error_free(s->migration_blocker); + return; + } + } +@@ -920,7 +950,10 @@ static void ivshmem_exit(PCIDevice *dev) + IVShmemState *s = IVSHMEM_COMMON(dev); + int i; + +- migrate_del_blocker(&s->migration_blocker); ++ if (s->migration_blocker) { ++ migrate_del_blocker(s->migration_blocker); ++ error_free(s->migration_blocker); ++ } + + if (memory_region_is_mapped(s->ivshmem_bar2)) { + if (!s->hostmem) { +@@ -1014,7 +1047,7 @@ static const VMStateDescription ivshmem_plain_vmsd = { + .minimum_version_id = 0, + .pre_load = ivshmem_pre_load, + .post_load = ivshmem_post_load, +- .fields = (const VMStateField[]) { ++ .fields = (VMStateField[]) { + VMSTATE_PCI_DEVICE(parent_obj, IVShmemState), + VMSTATE_UINT32(intrstatus, IVShmemState), + VMSTATE_UINT32(intrmask, IVShmemState), +@@ -1068,7 +1101,7 @@ static const VMStateDescription ivshmem_doorbell_vmsd = { + .minimum_version_id = 0, + .pre_load = ivshmem_pre_load, + .post_load = ivshmem_post_load, +- .fields = (const VMStateField[]) { ++ .fields = (VMStateField[]) { + VMSTATE_PCI_DEVICE(parent_obj, IVShmemState), + VMSTATE_MSIX(parent_obj, IVShmemState), + VMSTATE_UINT32(intrstatus, IVShmemState), +@@ -1083,6 +1116,7 @@ static Property ivshmem_doorbell_properties[] = { + DEFINE_PROP_BIT("ioeventfd", IVShmemState, features, IVSHMEM_IOEVENTFD, + true), + DEFINE_PROP_ON_OFF_AUTO("master", IVShmemState, master, ON_OFF_AUTO_OFF), ++ DEFINE_PROP_UINT64("flataddr", IVShmemState, flataddr, 0), + DEFINE_PROP_END_OF_LIST(), + }; + +@@ -1115,6 +1149,20 @@ static void ivshmem_doorbell_class_init(ObjectClass *klass, void *data) + dc->vmsd = &ivshmem_doorbell_vmsd; + } + ++static Property ivshmem_flat_props[] = { ++ DEFINE_PROP_END_OF_LIST(), ++}; ++ ++static void ivshmem_flat_class_init(ObjectClass *klass, void *data) ++{ ++ DeviceClass *dc = DEVICE_CLASS(klass); ++ ++ dc->hotpluggable = true; ++ set_bit(DEVICE_CATEGORY_MISC, dc->categories); ++ device_class_set_props(dc, ivshmem_flat_props); ++ dc->user_creatable = false; ++} ++ + static const TypeInfo ivshmem_doorbell_info = { + .name = TYPE_IVSHMEM_DOORBELL, + .parent = TYPE_IVSHMEM_COMMON, +@@ -1123,11 +1171,19 @@ static const TypeInfo ivshmem_doorbell_info = { + .class_init = ivshmem_doorbell_class_init, + }; + ++static const TypeInfo ivshmem_flat_info = { ++ .name = TYPE_IVSHMEM_FLAT, ++ .parent = TYPE_SYS_BUS_DEVICE, ++ .instance_size = sizeof(IvshmemFTState), ++ .class_init = ivshmem_flat_class_init, ++}; ++ + static void ivshmem_register_types(void) + { + type_register_static(&ivshmem_common_info); + type_register_static(&ivshmem_plain_info); + type_register_static(&ivshmem_doorbell_info); ++ type_register_static(&ivshmem_flat_info); + } + + type_init(ivshmem_register_types) +diff --git a/include/hw/misc/ivshmem.h b/include/hw/misc/ivshmem.h +index 433ef53..43aeab7 100644 +--- a/include/hw/misc/ivshmem.h ++++ b/include/hw/misc/ivshmem.h +@@ -21,5 +21,6 @@ + #define IVSHMEM_H + + #define IVSHMEM_PROTOCOL_VERSION 0 ++#define TYPE_IVSHMEM_FLAT "ivshmem-flat" + + #endif /* IVSHMEM_H */ +-- +2.45.2 + diff --git a/overlays/custom-packages/qemu/default.nix b/overlays/custom-packages/qemu/default.nix index ec0008eda..1d68bcb82 100644 --- a/overlays/custom-packages/qemu/default.nix +++ b/overlays/custom-packages/qemu/default.nix @@ -12,6 +12,16 @@ prev.qemu_kvm.overrideAttrs ( patches = prev.patches ++ [ ./acpi-devices-passthrough-qemu-8.0.patch ]; }) // (final.lib.optionalAttrs (final.lib.versionAtLeast qemu_version "8.1") { - patches = prev.patches ++ [ ./acpi-devices-passthrough-qemu-8.1.patch ]; + patches = prev.patches ++ [ + ./acpi-devices-passthrough-qemu-8.1.patch + ./0001-ivshmem-flat-memory-support.patch + ]; }) + // { + postInstall = + (prev.postInstall or "") + + '' + cp contrib/ivshmem-server/ivshmem-server $out/bin + ''; + } ) diff --git a/packages/memsocket/default.nix b/packages/memsocket/default.nix new file mode 100644 index 000000000..a575d4848 --- /dev/null +++ b/packages/memsocket/default.nix @@ -0,0 +1,36 @@ +# Copyright 2022-2023 TII (SSRC) and the Ghaf contributors +# SPDX-License-Identifier: Apache-2.0 +{ + stdenv, + lib, + debug ? false, + vms, + fetchFromGitHub, + ... +}: +stdenv.mkDerivation { + name = "memsocket"; + + src = fetchFromGitHub { + owner = "tiiuae"; + repo = "shmsockproxy"; + rev = "fd6b8ac051f1c68edc2b3222146d5d9053c81cc6"; + sha256 = "sha256-4FiRZy/HxwANgIAHxUfQo2tl4Dcgpz74SqvuRjqIw8M="; + }; + + CFLAGS = "-O2 -DVM_COUNT=" + (toString vms) + (if debug then " -DDEBUG_ON" else ""); + sourceRoot = "source/app"; + + installPhase = '' + mkdir -p $out/bin + install ./memsocket $out/bin/memsocket + ''; + + meta = with lib; { + description = "memsocket"; + platforms = [ + "x86_64-linux" + "aarch64-linux" + ]; + }; +} diff --git a/packages/memsocket/module.nix b/packages/memsocket/module.nix new file mode 100644 index 000000000..d7589ab82 --- /dev/null +++ b/packages/memsocket/module.nix @@ -0,0 +1,42 @@ +# Copyright 2022-2024 TII (SSRC) and the Ghaf contributors +# SPDX-License-Identifier: Apache-2.0 +{ + stdenv, + lib, + kernel, + fetchFromGitHub, + vmCount, + ... +}: +stdenv.mkDerivation { + inherit vmCount; + name = "ivshmem-driver-${kernel.version}"; + + src = fetchFromGitHub { + owner = "tiiuae"; + repo = "shmsockproxy"; + rev = "851ca1f2d23db764dd817b15aa783d82ab17560f"; + sha256 = "sha256-8jyciVZccptGaj4u3bDj5YOCfZSsf69FH4yfqcUoB5k="; + }; + + sourceRoot = "source/module"; + hardeningDisable = [ + "pic" + "format" + ]; + nativeBuildInputs = kernel.moduleBuildDependencies; + + makeFlags = [ + "KDIR=${kernel.dev}/lib/modules/${kernel.modDirVersion}/build" + "MODULEDIR=$(out)/lib/modules/${kernel.modDirVersion}/kernel/drivers/char" + "CFLAGS_kvm_ivshmem.o=\"-DCONFIG_KVM_IVSHMEM_VM_COUNT=${builtins.toString vmCount}\"" + ]; + + meta = with lib; { + description = "Shared memory Linux kernel module"; + platforms = [ + "x86_64-linux" + "aarch64-linux" + ]; + }; +} diff --git a/packages/nm-launcher/default.nix b/packages/nm-launcher/default.nix index 5bdb38439..dae01c0e2 100644 --- a/packages/nm-launcher/default.nix +++ b/packages/nm-launcher/default.nix @@ -9,6 +9,7 @@ openssh, writeShellApplication, lib, + uid, ... }: writeShellApplication { @@ -25,7 +26,7 @@ writeShellApplication { -o UserKnownHostsFile=/dev/null \ -o StreamLocalBindUnlink=yes \ -o ExitOnForwardFailure=yes \ - -L /tmp/ssh_session_dbus.sock:/run/user/1000/bus \ + -L /tmp/ssh_session_dbus.sock:/run/user/${builtins.toString uid}/bus \ -L /tmp/ssh_system_dbus.sock:/run/dbus/system_bus_socket ${networkmanagerapplet}/bin/nm-applet --indicator # Use the control socket to close the ssh tunnel.