Compare commits

..

3 Commits

Author SHA1 Message Date
MickLesk 71ecb99c62 Source core.func for shared messaging in iommu-setup
Replace locally duplicated color variables and msg_* helpers with
core.func + load_functions, matching the pattern used by update-apps
and pve-privilege-converter. Telemetry remains via api.func only.
2026-06-26 22:02:49 +02:00
MickLesk a9cc6234e8 Fix bare-metal detection in iommu-setup
systemd-detect-virt prints "none" on bare metal but exits non-zero, so the
`|| echo "none"` fallback appended a second "none" and the check wrongly
treated a physical Proxmox host as virtualized. Capture the command output
directly and only block when a real virtualization type is reported.
2026-06-26 21:50:48 +02:00
MickLesk 9a4c8325cc Add iommu-setup tool for PCI(e) passthrough preparation
New PVE host tool that enables IOMMU for PCI(e) passthrough:

- Detects the CPU vendor and applies the matching kernel parameters
  (intel_iommu=on / amd_iommu=on plus iommu=pt).
- Supports both boot configurations: GRUB (/etc/default/grub + update-grub)
  and proxmox-boot-tool managed systemd-boot (/etc/kernel/cmdline +
  proxmox-boot-tool refresh).
- Idempotent: only missing parameters are appended and a timestamped backup
  of the boot config is created before editing.
- Loads the vfio modules at boot (vfio_virqfd omitted, merged into the core
  since kernel 6.2).
- Guards for root, supported PVE 8.x/9.x and bare metal; reports current
  IOMMU state and prints verification commands.
2026-06-26 21:43:56 +02:00
3 changed files with 158 additions and 122 deletions
-6
View File
@@ -1,6 +0,0 @@
_______ __ __ __ __
/ ____(_)________ _ ______ _________ / / / /___ ____/ /___ _/ /____
/ /_ / / ___/ __ `/ | /| / / __ `/ ___/ _ \ / / / / __ \/ __ / __ `/ __/ _ \
/ __/ / / / / /_/ /| |/ |/ / /_/ / / / __/ / /_/ / /_/ / /_/ / /_/ / /_/ __/
/_/ /_/_/ \__,_/ |__/|__/\__,_/_/ \___/ \____/ .___/\__,_/\__,_/\__/\___/
/_/
-116
View File
@@ -1,116 +0,0 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: MickLesk (CanbiZ)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/refs/heads/main/misc/core.func)
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) 2>/dev/null || true
load_functions
declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "firmware-update" "pve"
APP="Firmware-Update"
APP_TYPE="tools"
header_info "$APP"
# Must run as root
if [ "$(id -u)" -ne 0 ]; then
msg_error "This script must be run as root."
exit 1
fi
# Must run on Proxmox VE 8.x or 9.x
if ! command -v pveversion >/dev/null 2>&1; then
msg_error "No Proxmox VE detected!"
exit 1
fi
if ! pveversion | grep -Eq "pve-manager/(8\.[0-4]|9\.[0-9]+)(\.[0-9]+)*"; then
msg_error "This version of Proxmox Virtual Environment is not supported."
msg_error "Requires Proxmox Virtual Environment Version 8.0-8.4 or 9.x."
exit 1
fi
# Firmware updates only make sense on bare metal. systemd-detect-virt prints
# "none" but exits non-zero on bare metal, so a `|| echo none` fallback would
# duplicate the value; capture the output as-is instead.
virt=$(systemd-detect-virt 2>/dev/null)
if [ -n "$virt" ] && [ "$virt" != "none" ]; then
msg_error "Firmware updates can only be applied on bare metal. Detected: $virt"
exit 1
fi
# Only x86_64/arm64 with UEFI/LVFS support; fwupd itself handles capability checks
whiptail --backtitle "Proxmox VE Helper Scripts" --title "Firmware Update (fwupd / LVFS)" \
--yesno "This tool uses fwupd to check for and optionally install firmware updates (UEFI/BIOS and supported devices) from the Linux Vendor Firmware Service (LVFS).\n\nWARNING: Flashing firmware carries risk. Ensure stable power and do not interrupt the process. Some updates require a reboot to be applied.\n\nProceed?" 16 70 || exit 0
# Install fwupd if missing
if ! command -v fwupdmgr >/dev/null 2>&1; then
msg_info "Installing fwupd"
apt-get update &>/dev/null
if ! apt-get install -y fwupd &>/dev/null; then
msg_error "Failed to install fwupd"
exit 1
fi
msg_ok "Installed fwupd"
else
msg_ok "fwupd is already installed"
fi
# Refresh metadata from LVFS
msg_info "Refreshing firmware metadata from LVFS"
if fwupdmgr refresh --force &>/dev/null; then
msg_ok "Refreshed firmware metadata"
else
# A failed refresh is not fatal (cached metadata may still be usable)
msg_error "Could not refresh metadata (continuing with cached data)"
fi
# Show detected, updatable devices. --no-metadata-check / -y keep fwupd from
# prompting interactively (e.g. the "metadata is 30 days old, update now?"
# question) which would otherwise block and garble the output.
echo -e "\n${YW}Detected devices with firmware management support:${CL}\n"
fwupdmgr get-devices --no-unreported-check --no-metadata-check 2>/dev/null || true
echo
# Check for available updates (non-interactive)
msg_info "Checking for available firmware updates"
updates_output=$(fwupdmgr get-updates --no-unreported-check --no-metadata-check -y 2>&1)
updates_rc=$?
msg_ok "Checked for firmware updates"
# Many Proxmox hosts have no permanently mounted EFI System Partition (e.g.
# ZFS root managed by proxmox-boot-tool). Without it, fwupd cannot stage
# UEFI/BIOS capsule updates, so make that explicit instead of burying it.
if echo "$updates_output" | grep -qi "ESP partition not detected"; then
echo -e "${YW}Note:${CL} No mounted EFI System Partition (ESP) was detected."
echo -e " UEFI/BIOS capsule firmware updates cannot be staged on this host."
echo -e " Device firmware (e.g. NVMe/SSD) can still be updated if offered.\n"
fi
if [ "$updates_rc" -ne 0 ] || echo "$updates_output" | grep -qiE "No (updates|upgrades) available|Devices with no available firmware updates|No updatable devices"; then
whiptail --backtitle "Proxmox VE Helper Scripts" --title "No Firmware Updates" \
--msgbox "No applicable firmware updates were found for this system." 10 68
echo -e "${GN}Nothing to do.${CL}"
exit 0
fi
echo -e "\n${YW}Available firmware updates:${CL}\n"
echo "$updates_output"
echo
whiptail --backtitle "Proxmox VE Helper Scripts" --title "Apply Firmware Updates" \
--yesno "Firmware updates are available (see terminal output).\n\nDo you want to apply them now?\n\nNOTE: Some updates schedule a flash on the next reboot. Do NOT power off during the process." 14 70 || {
echo -e "${YW}Skipped applying updates.${CL}"
exit 0
}
msg_info "Applying firmware updates (this may take a while)"
echo
if fwupdmgr update -y; then
msg_ok "Firmware update process completed"
echo -e "\n${YW}A reboot may be required to finalize some firmware updates.${CL}\n"
else
msg_error "Firmware update reported an error. Review the output above."
exit 1
fi
+158
View File
@@ -0,0 +1,158 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: MickLesk (CanbiZ)
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/refs/heads/main/misc/core.func)
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) 2>/dev/null || true
load_functions
declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "iommu-setup" "pve"
function header_info {
clear
cat <<"EOF"
____ ____ __ _____ __ ____ _____ __
/ _/ / __ \/ |/ / |/ / / / / / ___/___ / /___ ______
/ / / / / / /|_/ / /|_/ / / / / \__ \/ _ \/ __/ / / / __ \
_/ / / /_/ / / / / / / / /_/ / ___/ / __/ /_/ /_/ / /_/ /
/___/ \____/_/ /_/_/ /_/\____/ /____/\___/\__/\__,_/ .___/
/_/
EOF
}
header_info
# Guards
if [ "$(id -u)" -ne 0 ]; then
msg_error "This script must be run as root."
exit 1
fi
if ! command -v pveversion >/dev/null 2>&1; then
msg_error "No Proxmox VE detected!"
exit 1
fi
if ! pveversion | grep -Eq "pve-manager/(8\.[0-4]|9\.[0-9]+)(\.[0-9]+)*"; then
msg_error "This version of Proxmox Virtual Environment is not supported."
msg_error "Requires Proxmox Virtual Environment Version 8.0-8.4 or 9.x."
exit 1
fi
# systemd-detect-virt prints "none" but exits non-zero on bare metal, so a
# `|| echo none` fallback would duplicate the value; capture output as-is.
virt=$(systemd-detect-virt 2>/dev/null)
if [ -n "$virt" ] && [ "$virt" != "none" ]; then
msg_error "IOMMU/PCI passthrough must be configured on bare metal. Detected: $virt"
exit 1
fi
# Whether a kernel parameter is already present in a cmdline string
has_token() {
case " $1 " in
*" $2 "*) return 0 ;;
*) return 1 ;;
esac
}
# Detect CPU vendor and the matching kernel parameters
cpu_vendor=$(lscpu | grep -oP 'Vendor ID:\s*\K\S+' | head -n 1)
case "$cpu_vendor" in
GenuineIntel) IOMMU_PARAMS=("intel_iommu=on" "iommu=pt") ;;
AuthenticAMD) IOMMU_PARAMS=("amd_iommu=on" "iommu=pt") ;;
*)
msg_error "Unsupported CPU vendor: ${cpu_vendor:-unknown}"
exit 1
;;
esac
# Report current IOMMU state
iommu_active="no"
if [ -d /sys/kernel/iommu_groups ] && [ -n "$(ls -A /sys/kernel/iommu_groups 2>/dev/null)" ]; then
iommu_active="yes"
fi
echo -e "${BL}CPU vendor:${CL} ${cpu_vendor}"
echo -e "${BL}IOMMU active:${CL} $([ "$iommu_active" = "yes" ] && echo -e "${GN}yes${CL}" || echo -e "${RD}no${CL}")"
echo -e "${BL}Kernel params:${CL} ${IOMMU_PARAMS[*]}"
echo
if [ "$iommu_active" = "yes" ]; then
whiptail --backtitle "Proxmox VE Helper Scripts" --title "IOMMU Already Active" \
--yesno "IOMMU already appears to be active on this host.\n\nDo you still want to (re)apply the kernel parameters and vfio modules?" 12 70 || {
echo -e "${GN}Nothing to do.${CL}"
exit 0
}
else
whiptail --backtitle "Proxmox VE Helper Scripts" --title "Enable IOMMU / PCI(e) Passthrough" \
--yesno "This will enable IOMMU for PCI(e) passthrough by:\n\n - adding '${IOMMU_PARAMS[*]}' to the kernel command line\n - loading the vfio kernel modules\n\nA reboot is required afterwards. A backup of the modified boot config is created.\n\nProceed?" 16 74 || exit 0
fi
# Determine the boot configuration in use
# proxmox-boot-tool managed systems (ZFS / UEFI) use /etc/kernel/cmdline,
# everything else uses GRUB via /etc/default/grub.
if command -v proxmox-boot-tool >/dev/null 2>&1 && [ -f /etc/kernel/cmdline ]; then
BOOT_MODE="systemd-boot"
else
BOOT_MODE="grub"
fi
apply_grub() {
local file="/etc/default/grub" current merged
cp -a "$file" "${file}.bak.$(date +%Y%m%d%H%M%S)"
if grep -q '^GRUB_CMDLINE_LINUX_DEFAULT=' "$file"; then
current=$(sed -n 's/^GRUB_CMDLINE_LINUX_DEFAULT=//p' "$file" | tail -1)
current="${current%\"}"
current="${current#\"}"
else
current=""
fi
merged="$current"
for tok in "${IOMMU_PARAMS[@]}"; do
has_token "$merged" "$tok" || merged="${merged:+$merged }$tok"
done
if grep -q '^GRUB_CMDLINE_LINUX_DEFAULT=' "$file"; then
sed -i "s|^GRUB_CMDLINE_LINUX_DEFAULT=.*|GRUB_CMDLINE_LINUX_DEFAULT=\"${merged}\"|" "$file"
else
echo "GRUB_CMDLINE_LINUX_DEFAULT=\"${merged}\"" >>"$file"
fi
update-grub &>/dev/null
}
apply_systemd_boot() {
local file="/etc/kernel/cmdline" current merged
cp -a "$file" "${file}.bak.$(date +%Y%m%d%H%M%S)"
current=$(tr -d '\n' <"$file")
merged="$current"
for tok in "${IOMMU_PARAMS[@]}"; do
has_token "$merged" "$tok" || merged="${merged:+$merged }$tok"
done
echo "$merged" >"$file"
proxmox-boot-tool refresh &>/dev/null
}
msg_info "Applying kernel parameters via ${BOOT_MODE}"
if [ "$BOOT_MODE" = "systemd-boot" ]; then
apply_systemd_boot
else
apply_grub
fi
msg_ok "Applied kernel parameters (${BOOT_MODE})"
# Load vfio modules at boot (vfio_virqfd was merged into the core in
# kernel 6.2+, so it is intentionally not added here)
msg_info "Configuring vfio modules"
for m in vfio vfio_iommu_type1 vfio_pci; do
grep -qxF "$m" /etc/modules 2>/dev/null || echo "$m" >>/etc/modules
done
msg_ok "Configured vfio modules"
echo -e "\n${GN}IOMMU configuration written.${CL}"
echo -e "${YW}A reboot is required to activate IOMMU.${CL}"
echo -e "After rebooting, verify with: ${BL}dmesg | grep -e DMAR -e IOMMU${CL}"
echo -e "and list groups with: ${BL}find /sys/kernel/iommu_groups/ -type l${CL}\n"