Add firmware packaging and validation scripts
Red Bear OS Team
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build redbear-wifictl for the Redox target using the repo-provided cross toolchain.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage: build-redbear-wifictl-redox.sh [cargo build args...]
|
||||
|
||||
This helper ensures the repository's Redox cross-linker directory is on PATH before invoking
|
||||
`cargo build --target x86_64-unknown-redox` for `redbear-wifictl`.
|
||||
|
||||
Examples:
|
||||
./local/scripts/build-redbear-wifictl-redox.sh
|
||||
./local/scripts/build-redbear-wifictl-redox.sh --release
|
||||
EOF
|
||||
}
|
||||
|
||||
if [[ "${1:-}" == "--help" || "${1:-}" == "-h" ]]; then
|
||||
usage
|
||||
exit 0
|
||||
fi
|
||||
|
||||
repo_root="$(cd "$(dirname "$0")/../.." && pwd)"
|
||||
toolchain_bin="$repo_root/prefix/x86_64-unknown-redox/sysroot/bin"
|
||||
crate_dir="$repo_root/local/recipes/system/redbear-wifictl/source"
|
||||
|
||||
if [[ ! -d "$toolchain_bin" ]]; then
|
||||
echo "ERROR: missing Redox toolchain bin dir: $toolchain_bin" >&2
|
||||
echo "Build the prefix/sysroot first before using this helper." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -x "$toolchain_bin/x86_64-unknown-redox-gcc" ]]; then
|
||||
echo "ERROR: missing executable linker: $toolchain_bin/x86_64-unknown-redox-gcc" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Using Redox toolchain from: $toolchain_bin"
|
||||
PATH="$toolchain_bin:$PATH" cargo build --target x86_64-unknown-redox "$@"
|
||||
+170
@@ -0,0 +1,170 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
script_dir="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
|
||||
root_dir="$(CDPATH= cd -- "${script_dir}/../.." && pwd)"
|
||||
|
||||
target="${TARGET:-x86_64-unknown-redox}"
|
||||
source_sysroot="${SOURCE_SYSROOT:-${root_dir}/prefix/${target}/sysroot}"
|
||||
dest_root="${1:-${root_dir}/build/toolchain-export/${target}}"
|
||||
dest_sysroot="${dest_root}/sysroot"
|
||||
dest_bin="${dest_root}/bin"
|
||||
partial_root="${dest_root}.partial"
|
||||
partial_sysroot="${partial_root}/sysroot"
|
||||
partial_bin="${partial_root}/bin"
|
||||
|
||||
if [ ! -d "${source_sysroot}" ]; then
|
||||
echo "error: missing source sysroot: ${source_sysroot}" >&2
|
||||
echo "hint: build the prefix first with 'make prefix TARGET=${target}' or 'make prefix'" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rm -rf "${partial_root}"
|
||||
mkdir -p "${partial_root}"
|
||||
|
||||
cp -a "${source_sysroot}" "${partial_sysroot}"
|
||||
mkdir -p "${partial_bin}"
|
||||
|
||||
for tool in gcc c++ ar ranlib ld strip objcopy objdump; do
|
||||
tool_name="${target}-${tool}"
|
||||
if [ -x "${partial_sysroot}/bin/${tool_name}" ]; then
|
||||
ln -s "../sysroot/bin/${tool_name}" "${partial_bin}/${tool_name}"
|
||||
fi
|
||||
done
|
||||
|
||||
cat > "${partial_bin}/${target}-pkg-config" <<EOF
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
script_dir="\$(CDPATH= cd -- "\$(dirname -- "\$0")" && pwd)"
|
||||
toolchain_root="\$(CDPATH= cd -- "\${script_dir}/.." && pwd)"
|
||||
sysroot="\${REDBEAR_REDOX_SYSROOT:-\${toolchain_root}/sysroot}"
|
||||
|
||||
export PKG_CONFIG_SYSROOT_DIR="\${PKG_CONFIG_SYSROOT_DIR:-\${sysroot}}"
|
||||
export PKG_CONFIG_LIBDIR="\${PKG_CONFIG_LIBDIR:-\${sysroot}/lib/pkgconfig}"
|
||||
export PKG_CONFIG_PATH="\${PKG_CONFIG_PATH:-\${sysroot}/share/pkgconfig}"
|
||||
|
||||
if [ -n "\${COOKBOOK_DYNAMIC:-}" ]; then
|
||||
exec pkg-config "\$@"
|
||||
else
|
||||
exec pkg-config --static "\$@"
|
||||
fi
|
||||
EOF
|
||||
|
||||
cat > "${partial_bin}/${target}-llvm-config" <<EOF
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
LLVM_CONFIG = "/bin/llvm-config"
|
||||
TARGET = "${target}"
|
||||
|
||||
ARCH_MAP = {
|
||||
"x86_64": ("X86", "x86", "X86"),
|
||||
"i586": ("X86", "x86", "X86"),
|
||||
"aarch64": ("AArch64", "aarch64", "AArch64"),
|
||||
"riscv64gc": ("RISCV", "riscv", "RISCV"),
|
||||
}
|
||||
|
||||
ALL_ARCH_COMPS = ["x86", "aarch64", "riscv"]
|
||||
ALL_ARCH_LIBS = ["X86", "AArch64", "RISCV"]
|
||||
|
||||
|
||||
def is_unwanted_arch(item, allowed_prefix, all_prefixes, is_lib=False):
|
||||
matched_arch = None
|
||||
for arch in all_prefixes:
|
||||
if is_lib and f"LLVM{arch}" in item:
|
||||
matched_arch = arch
|
||||
break
|
||||
if not is_lib and item.startswith(arch):
|
||||
matched_arch = arch
|
||||
break
|
||||
|
||||
return matched_arch is not None and matched_arch != allowed_prefix
|
||||
|
||||
|
||||
def main():
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
toolchain_root = os.path.dirname(script_dir)
|
||||
toolchain_path = os.environ.get("COOKBOOK_HOST_SYSROOT", os.path.join(toolchain_root, "sysroot"))
|
||||
sysroot_path = os.environ.get("COOKBOOK_SYSROOT", toolchain_path)
|
||||
target_triple = os.environ.get("TARGET", TARGET)
|
||||
|
||||
target_arch = target_triple.split("-")[0]
|
||||
mapped_archs = ARCH_MAP.get(target_arch)
|
||||
if mapped_archs is None:
|
||||
print(f"Error: unsupported target architecture in {target_triple}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
target_built_name, comp_prefix, lib_prefix = mapped_archs
|
||||
cmd = [toolchain_path + LLVM_CONFIG] + sys.argv[1:]
|
||||
|
||||
try:
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=sys.stderr,
|
||||
check=False,
|
||||
text=True,
|
||||
)
|
||||
except FileNotFoundError:
|
||||
print(f"Error: Could not find executable '{LLVM_CONFIG}' under {toolchain_path}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
if result.returncode != 0:
|
||||
sys.exit(result.returncode)
|
||||
|
||||
output = result.stdout.strip()
|
||||
args_set = set(sys.argv[1:])
|
||||
|
||||
if "--bindir" in args_set:
|
||||
output = toolchain_path + "/usr/bin"
|
||||
elif "--targets-built" in args_set:
|
||||
output = target_built_name
|
||||
elif "--components" in args_set:
|
||||
components = output.split()
|
||||
output = " ".join(
|
||||
c for c in components if not is_unwanted_arch(c, comp_prefix, ALL_ARCH_COMPS, is_lib=False)
|
||||
)
|
||||
elif "--libs" in args_set:
|
||||
libs = output.split()
|
||||
output = " ".join(
|
||||
l for l in libs if not is_unwanted_arch(l, lib_prefix, ALL_ARCH_LIBS, is_lib=True)
|
||||
)
|
||||
output = output.replace(toolchain_path.rstrip(os.sep), sysroot_path.rstrip(os.sep))
|
||||
else:
|
||||
output = output.replace(toolchain_path.rstrip(os.sep), sysroot_path.rstrip(os.sep))
|
||||
|
||||
print(output, end="\n")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
EOF
|
||||
|
||||
cat > "${partial_root}/activate.sh" <<EOF
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
toolchain_root="\$(CDPATH= cd -- "\$(dirname -- "\${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
export TARGET="${target}"
|
||||
export REDBEAR_REDOX_SYSROOT="\${REDBEAR_REDOX_SYSROOT:-\${toolchain_root}/sysroot}"
|
||||
export COOKBOOK_HOST_SYSROOT="\${COOKBOOK_HOST_SYSROOT:-\${REDBEAR_REDOX_SYSROOT}}"
|
||||
export COOKBOOK_SYSROOT="\${COOKBOOK_SYSROOT:-\${REDBEAR_REDOX_SYSROOT}}"
|
||||
export PATH="\${toolchain_root}/bin:\${REDBEAR_REDOX_SYSROOT}/bin:\${PATH}"
|
||||
|
||||
echo "Activated ${target} toolchain from \${toolchain_root}"
|
||||
EOF
|
||||
|
||||
chmod 0755 \
|
||||
"${partial_root}/activate.sh" \
|
||||
"${partial_bin}/${target}-pkg-config" \
|
||||
"${partial_bin}/${target}-llvm-config"
|
||||
|
||||
rm -rf "${dest_root}"
|
||||
mv "${partial_root}" "${dest_root}"
|
||||
|
||||
echo "exported ${target} toolchain to ${dest_root}"
|
||||
echo "source ${dest_root}/activate.sh"
|
||||
@@ -0,0 +1,50 @@
|
||||
#!/usr/bin/env bash
|
||||
# Summarize and package Wi-Fi validation artifacts after a real run.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage: finalize-wifi-validation-run.sh <capture.json> [artifact.tar.gz] [additional files...]
|
||||
|
||||
Runs the packaged Wi-Fi analyzer on the supplied capture JSON and then packages the provided
|
||||
artifacts into a tarball.
|
||||
|
||||
Defaults:
|
||||
artifact tarball: ./wifi-validation-artifacts.tar.gz
|
||||
EOF
|
||||
}
|
||||
|
||||
if [[ $# -lt 1 || "${1:-}" == "--help" || "${1:-}" == "-h" ]]; then
|
||||
usage
|
||||
[[ $# -ge 1 ]] && exit 0 || exit 1
|
||||
fi
|
||||
|
||||
capture="$1"
|
||||
shift
|
||||
archive="${1:-wifi-validation-artifacts.tar.gz}"
|
||||
if [[ $# -gt 0 ]]; then
|
||||
shift
|
||||
fi
|
||||
|
||||
if [[ ! -f "$capture" ]]; then
|
||||
echo "ERROR: missing capture file $capture" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "=== Wi-Fi Validation Analysis ==="
|
||||
if command -v redbear-phase5-wifi-analyze >/dev/null 2>&1; then
|
||||
redbear-phase5-wifi-analyze "$capture"
|
||||
else
|
||||
echo "WARN: redbear-phase5-wifi-analyze not installed; skipping analyzer"
|
||||
fi
|
||||
|
||||
echo "=== Packaging Artifacts ==="
|
||||
files=("$capture")
|
||||
if [[ $# -gt 0 ]]; then
|
||||
for path in "$@"; do
|
||||
files+=("$path")
|
||||
done
|
||||
fi
|
||||
./local/scripts/package-wifi-validation-artifacts.sh "$archive" "${files[@]}"
|
||||
echo "finalized_archive=$archive"
|
||||
@@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env bash
|
||||
# Package Wi-Fi validation artifacts into a single tarball.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage: package-wifi-validation-artifacts.sh [OUTPUT_TARBALL] [FILES...]
|
||||
|
||||
Default output tarball:
|
||||
./wifi-validation-artifacts.tar.gz
|
||||
|
||||
If no FILES are provided, this script packages the common host-side artifact names referenced by the
|
||||
Wi-Fi validation runbook when they exist in the current directory.
|
||||
|
||||
If a provided FILE argument is a directory, it is included recursively.
|
||||
EOF
|
||||
}
|
||||
|
||||
if [[ "${1:-}" == "--help" || "${1:-}" == "-h" ]]; then
|
||||
usage
|
||||
exit 0
|
||||
fi
|
||||
|
||||
output="${1:-wifi-validation-artifacts.tar.gz}"
|
||||
shift || true
|
||||
|
||||
inputs=()
|
||||
if [[ $# -gt 0 ]]; then
|
||||
for path in "$@"; do
|
||||
if [[ -e "$path" ]]; then
|
||||
inputs+=("$path")
|
||||
else
|
||||
echo "WARN: skipping missing artifact $path" >&2
|
||||
fi
|
||||
done
|
||||
else
|
||||
defaults=(
|
||||
"wifi-passthrough-capture.json"
|
||||
"wifi-passthrough-capture.json.meta.json"
|
||||
"wifi-baremetal-capture.json"
|
||||
"wifi-baremetal-serial.log"
|
||||
"wifi-baremetal-console.log"
|
||||
)
|
||||
for path in "${defaults[@]}"; do
|
||||
if [[ -e "$path" ]]; then
|
||||
inputs+=("$path")
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [[ ${#inputs[@]} -eq 0 ]]; then
|
||||
echo "ERROR: no Wi-Fi validation artifacts found to package" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
manifest_dir=$(mktemp -d)
|
||||
manifest_path="$manifest_dir/wifi-validation-artifacts.manifest.txt"
|
||||
{
|
||||
echo "output=$output"
|
||||
for path in "${inputs[@]}"; do
|
||||
if command -v sha256sum >/dev/null 2>&1 && [[ -f "$path" ]]; then
|
||||
checksum=$(sha256sum "$path" | awk '{print $1}')
|
||||
printf 'file=%s sha256=%s\n' "$path" "$checksum"
|
||||
else
|
||||
printf 'path=%s\n' "$path"
|
||||
fi
|
||||
done
|
||||
} > "$manifest_path"
|
||||
|
||||
tar -czf "$output" "${inputs[@]}" -C "$manifest_dir" "$(basename "$manifest_path")"
|
||||
rm -rf "$manifest_dir"
|
||||
|
||||
echo "packaged_artifacts=$output"
|
||||
printf 'included=%s\n' "${inputs[*]}"
|
||||
echo "manifest=wifi-validation-artifacts.manifest.txt"
|
||||
@@ -0,0 +1,136 @@
|
||||
#!/usr/bin/env bash
|
||||
# Bind or unbind an Intel Wi-Fi PCI function to vfio-pci for Red Bear validation.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage:
|
||||
prepare-wifi-vfio.sh bind <PCI_BDF>
|
||||
prepare-wifi-vfio.sh unbind <PCI_BDF> <HOST_DRIVER>
|
||||
|
||||
Examples:
|
||||
sudo ./local/scripts/prepare-wifi-vfio.sh bind 0000:00:14.3
|
||||
sudo ./local/scripts/prepare-wifi-vfio.sh unbind 0000:00:14.3 iwlwifi
|
||||
|
||||
Notes:
|
||||
- This helper only prepares host PCI binding for VFIO-backed validation.
|
||||
- It does NOT itself prove Wi-Fi works inside Red Bear OS.
|
||||
- Use with care on a machine where the selected device is safe to detach.
|
||||
EOF
|
||||
}
|
||||
|
||||
require_root() {
|
||||
if [[ ${EUID:-$(id -u)} -ne 0 ]]; then
|
||||
echo "ERROR: this script must run as root" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
require_sysfs_path() {
|
||||
local path="$1"
|
||||
if [[ ! -e "$path" ]]; then
|
||||
echo "ERROR: missing sysfs path $path" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
read_pci_id() {
|
||||
local bdf="$1"
|
||||
local vendor device
|
||||
vendor=$(<"/sys/bus/pci/devices/$bdf/vendor")
|
||||
device=$(<"/sys/bus/pci/devices/$bdf/device")
|
||||
printf '%s %s\n' "$vendor" "$device"
|
||||
}
|
||||
|
||||
current_driver() {
|
||||
local bdf="$1"
|
||||
local link="/sys/bus/pci/devices/$bdf/driver"
|
||||
if [[ -L "$link" ]]; then
|
||||
basename "$(readlink -f "$link")"
|
||||
else
|
||||
printf 'none\n'
|
||||
fi
|
||||
}
|
||||
|
||||
bind_vfio() {
|
||||
local bdf="$1"
|
||||
require_sysfs_path "/sys/bus/pci/devices/$bdf"
|
||||
|
||||
local driver vendor device
|
||||
driver=$(current_driver "$bdf")
|
||||
read -r vendor device < <(read_pci_id "$bdf")
|
||||
|
||||
echo "Preparing $bdf for vfio-pci"
|
||||
echo "vendor=$vendor device=$device current_driver=$driver"
|
||||
|
||||
modprobe vfio-pci
|
||||
|
||||
if [[ "$driver" != "none" && "$driver" != "vfio-pci" ]]; then
|
||||
echo "$bdf" > "/sys/bus/pci/devices/$bdf/driver/unbind"
|
||||
fi
|
||||
|
||||
printf '%s %s\n' "$vendor" "$device" > /sys/bus/pci/drivers/vfio-pci/new_id || true
|
||||
echo "$bdf" > /sys/bus/pci/drivers/vfio-pci/bind
|
||||
|
||||
echo "vfio_driver=$(current_driver "$bdf")"
|
||||
}
|
||||
|
||||
unbind_vfio() {
|
||||
local bdf="$1"
|
||||
local host_driver="$2"
|
||||
require_sysfs_path "/sys/bus/pci/devices/$bdf"
|
||||
require_sysfs_path "/sys/bus/pci/drivers/$host_driver"
|
||||
|
||||
local driver
|
||||
driver=$(current_driver "$bdf")
|
||||
echo "Restoring $bdf from $driver to $host_driver"
|
||||
|
||||
if [[ "$driver" == "vfio-pci" ]]; then
|
||||
echo "$bdf" > /sys/bus/pci/drivers/vfio-pci/unbind
|
||||
elif [[ "$driver" != "none" && "$driver" != "$host_driver" ]]; then
|
||||
echo "$bdf" > "/sys/bus/pci/devices/$bdf/driver/unbind"
|
||||
fi
|
||||
|
||||
echo "$bdf" > "/sys/bus/pci/drivers/$host_driver/bind"
|
||||
echo "restored_driver=$(current_driver "$bdf")"
|
||||
}
|
||||
|
||||
main() {
|
||||
if [[ $# -lt 1 ]]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case "$1" in
|
||||
--help|-h|help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
require_root
|
||||
|
||||
case "$1" in
|
||||
bind)
|
||||
if [[ $# -ne 2 ]]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
bind_vfio "$2"
|
||||
;;
|
||||
unbind)
|
||||
if [[ $# -ne 3 ]]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
unbind_vfio "$2" "$3"
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
main "$@"
|
||||
@@ -0,0 +1,140 @@
|
||||
#!/usr/bin/env bash
|
||||
# Prepare a host Intel Wi-Fi PCI function for VFIO, run the Red Bear Wi-Fi passthrough
|
||||
# validation harness, and restore the host driver afterwards.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage: run-wifi-passthrough-validation.sh --host-pci 0000:xx:yy.z --host-driver DRIVER [--artifact-dir DIR] [--capture-output PATH] [--metadata-output PATH] [-- extra qemu args...]
|
||||
|
||||
Examples:
|
||||
sudo ./local/scripts/run-wifi-passthrough-validation.sh \
|
||||
--host-pci 0000:00:14.3 \
|
||||
--host-driver iwlwifi \
|
||||
--capture-output ./wifi-passthrough-capture.json
|
||||
|
||||
This wrapper:
|
||||
1. binds the selected PCI function to vfio-pci,
|
||||
2. launches test-wifi-passthrough-qemu.sh --check,
|
||||
3. restores the selected host driver on exit.
|
||||
|
||||
It does NOT itself prove end-to-end Wi-Fi connectivity; it automates the strongest in-repo
|
||||
passthrough validation path.
|
||||
EOF
|
||||
}
|
||||
|
||||
host_pci=""
|
||||
host_driver=""
|
||||
capture_output=""
|
||||
artifact_dir=""
|
||||
extra_args=()
|
||||
run_started="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
metadata_output=""
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--host-pci)
|
||||
host_pci="$2"
|
||||
shift 2
|
||||
;;
|
||||
--host-driver)
|
||||
host_driver="$2"
|
||||
shift 2
|
||||
;;
|
||||
--capture-output)
|
||||
capture_output="$2"
|
||||
shift 2
|
||||
;;
|
||||
--artifact-dir)
|
||||
artifact_dir="$2"
|
||||
shift 2
|
||||
;;
|
||||
--metadata-output)
|
||||
metadata_output="$2"
|
||||
shift 2
|
||||
;;
|
||||
--help|-h)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
extra_args+=("$@")
|
||||
break
|
||||
;;
|
||||
*)
|
||||
extra_args+=("$1")
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "$host_pci" || -z "$host_driver" ]]; then
|
||||
echo "ERROR: --host-pci and --host-driver are required" >&2
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
script_root="$(dirname "$0")"
|
||||
prepare_script="$script_root/prepare-wifi-vfio.sh"
|
||||
passthrough_script="$script_root/test-wifi-passthrough-qemu.sh"
|
||||
|
||||
cleanup() {
|
||||
if [[ -n "$host_pci" && -n "$host_driver" ]]; then
|
||||
echo "=== Restoring host driver ==="
|
||||
"$prepare_script" unbind "$host_pci" "$host_driver" || true
|
||||
fi
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
echo "=== Binding Intel Wi-Fi function to vfio-pci ==="
|
||||
"$prepare_script" bind "$host_pci"
|
||||
|
||||
echo "=== Running Wi-Fi passthrough validation ==="
|
||||
if [[ -n "$artifact_dir" ]]; then
|
||||
mkdir -p "$artifact_dir"
|
||||
if [[ -z "$capture_output" ]]; then
|
||||
capture_output="$artifact_dir/wifi-passthrough-capture.json"
|
||||
fi
|
||||
if [[ -z "$metadata_output" ]]; then
|
||||
metadata_output="$artifact_dir/wifi-passthrough-capture.meta.json"
|
||||
fi
|
||||
fi
|
||||
if [[ -z "$capture_output" ]]; then
|
||||
capture_output="$(pwd)/wifi-passthrough-capture.json"
|
||||
fi
|
||||
cmd=("$passthrough_script" --host-pci "$host_pci" --check)
|
||||
cmd+=(--capture-output "$capture_output")
|
||||
cmd+=("${extra_args[@]}")
|
||||
"${cmd[@]}"
|
||||
run_finished="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
|
||||
if [[ -z "$metadata_output" ]]; then
|
||||
metadata_output="${capture_output}.meta.json"
|
||||
fi
|
||||
|
||||
if [[ -n "$metadata_output" ]]; then
|
||||
python - <<'PY' "$metadata_output" "$host_pci" "$host_driver" "$capture_output" "$run_started" "$run_finished"
|
||||
import json, sys
|
||||
path, host_pci, host_driver, capture_output, run_started, run_finished = sys.argv[1:7]
|
||||
payload = {
|
||||
"host_pci": host_pci,
|
||||
"host_driver": host_driver,
|
||||
"capture_output": capture_output or None,
|
||||
"run_started": run_started,
|
||||
"run_finished": run_finished,
|
||||
}
|
||||
with open(path, "w", encoding="utf-8") as f:
|
||||
json.dump(payload, f, indent=2, sort_keys=True)
|
||||
f.write("\n")
|
||||
PY
|
||||
fi
|
||||
|
||||
echo "=== Validation complete ==="
|
||||
if [[ -n "$capture_output" ]]; then
|
||||
echo "capture_output=$capture_output"
|
||||
fi
|
||||
if [[ -n "$metadata_output" ]]; then
|
||||
echo "metadata_output=$metadata_output"
|
||||
fi
|
||||
@@ -0,0 +1,96 @@
|
||||
#!/usr/bin/env bash
|
||||
# Summarize packaged Wi-Fi validation artifacts for quick review.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage: summarize-wifi-validation-artifacts.sh <capture.json|artifact.tar.gz>
|
||||
|
||||
Print a compact summary of the packaged Wi-Fi validation evidence so the next debugging loop can
|
||||
see the most important runtime signals quickly.
|
||||
EOF
|
||||
}
|
||||
|
||||
if [[ $# -ne 1 || "$1" == "--help" || "$1" == "-h" ]]; then
|
||||
usage
|
||||
[[ $# -eq 1 ]] && exit 0 || exit 1
|
||||
fi
|
||||
|
||||
input="$1"
|
||||
tmpdir=""
|
||||
cleanup() {
|
||||
if [[ -n "$tmpdir" && -d "$tmpdir" ]]; then
|
||||
rm -rf "$tmpdir"
|
||||
fi
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
json_path=""
|
||||
if [[ "$input" == *.tar.gz ]]; then
|
||||
tmpdir=$(mktemp -d)
|
||||
tar -xzf "$input" -C "$tmpdir"
|
||||
json_path=$(find "$tmpdir" -maxdepth 2 -type f \( -name '*wifi*capture*.json' -o -name 'redbear-phase5-wifi-capture.json' \) | head -n 1 || true)
|
||||
if [[ -z "$json_path" ]]; then
|
||||
echo "ERROR: no Wi-Fi capture JSON found inside $input" >&2
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
json_path="$input"
|
||||
fi
|
||||
|
||||
python - <<'PY' "$json_path"
|
||||
import json, sys
|
||||
path = sys.argv[1]
|
||||
with open(path, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
|
||||
def cmd_stdout(name):
|
||||
return str(data.get('commands', {}).get(name, {}).get('stdout', '')).strip()
|
||||
|
||||
def scheme_value(name):
|
||||
value = data.get('scheme', {}).get(name, {})
|
||||
if isinstance(value, dict):
|
||||
return value.get('value', '').strip()
|
||||
return ''
|
||||
|
||||
print("=== Red Bear Wi-Fi Validation Summary ===")
|
||||
print(f"capture={path}")
|
||||
print(f"captured_at_unix={data.get('captured_at_unix', 'unknown')}")
|
||||
print(f"profile={data.get('profile', 'unknown')}")
|
||||
print(f"interface={data.get('interface', 'unknown')}")
|
||||
|
||||
installed = data.get('installed', {})
|
||||
print(f"driver_installed={installed.get('driver')}")
|
||||
print(f"wifictl_installed={installed.get('wifictl')}")
|
||||
print(f"netctl_installed={installed.get('netctl')}")
|
||||
|
||||
for key in [
|
||||
'driver_probe',
|
||||
'driver_status',
|
||||
'wifictl_probe',
|
||||
'wifictl_status',
|
||||
'netctl_status',
|
||||
'phase5_network_check',
|
||||
'phase5_wifi_check',
|
||||
]:
|
||||
out = cmd_stdout(key)
|
||||
first = out.splitlines()[0] if out else ''
|
||||
print(f"{key}_first_line={first}")
|
||||
|
||||
for key in [
|
||||
'status',
|
||||
'link_state',
|
||||
'firmware_status',
|
||||
'transport_status',
|
||||
'transport_init_status',
|
||||
'activation_status',
|
||||
'connect_result',
|
||||
'disconnect_result',
|
||||
'last_error',
|
||||
]:
|
||||
print(f"scheme_{key}={scheme_value(key)}")
|
||||
|
||||
scan = scheme_value('scan_results')
|
||||
print(f"scheme_scan_results={scan}")
|
||||
PY
|
||||
Executable
+146
@@ -0,0 +1,146 @@
|
||||
#!/usr/bin/env bash
|
||||
# Launch or validate the bounded Bluetooth Battery Level slice in QEMU.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
find_uefi_firmware() {
|
||||
local candidates=(
|
||||
"/usr/share/ovmf/x64/OVMF.4m.fd"
|
||||
"/usr/share/OVMF/x64/OVMF.4m.fd"
|
||||
"/usr/share/ovmf/x64/OVMF_CODE.4m.fd"
|
||||
"/usr/share/OVMF/x64/OVMF_CODE.4m.fd"
|
||||
"/usr/share/ovmf/OVMF.fd"
|
||||
"/usr/share/OVMF/OVMF_CODE.fd"
|
||||
"/usr/share/qemu/edk2-x86_64-code.fd"
|
||||
)
|
||||
local path
|
||||
for path in "${candidates[@]}"; do
|
||||
if [[ -f "$path" ]]; then
|
||||
printf '%s\n' "$path"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat <<'USAGE'
|
||||
Usage: test-bluetooth-qemu.sh [--check] [extra qemu args...]
|
||||
|
||||
Boot or validate the Red Bear OS bounded Bluetooth Battery Level slice on
|
||||
redbear-bluetooth-experimental.
|
||||
USAGE
|
||||
}
|
||||
|
||||
check_mode=0
|
||||
filtered_args=()
|
||||
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--help|-h|help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
--check)
|
||||
check_mode=1
|
||||
;;
|
||||
*)
|
||||
filtered_args+=("$arg")
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
firmware="$(find_uefi_firmware)" || {
|
||||
echo "ERROR: no usable x86_64 UEFI firmware found" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
arch="${ARCH:-$(uname -m)}"
|
||||
image="build/$arch/redbear-bluetooth-experimental/harddrive.img"
|
||||
extra="build/$arch/redbear-bluetooth-experimental/extra.img"
|
||||
extra_qemu_args="${filtered_args[*]:-}"
|
||||
|
||||
if [[ -n "${QEMUFLAGS:-}" ]]; then
|
||||
combined_qemu_args="${QEMUFLAGS} ${extra_qemu_args}"
|
||||
else
|
||||
combined_qemu_args="${extra_qemu_args}"
|
||||
fi
|
||||
|
||||
if [[ ! -f "$image" ]]; then
|
||||
echo "ERROR: missing image $image" >&2
|
||||
echo "Build it first with: ./local/scripts/build-redbear.sh redbear-bluetooth-experimental" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "$extra" ]]; then
|
||||
truncate -s 1g "$extra"
|
||||
fi
|
||||
|
||||
pcap="build/$arch/redbear-bluetooth-experimental/network.pcap"
|
||||
|
||||
echo "=== Red Bear OS Bluetooth QEMU Launch ==="
|
||||
echo "Config: redbear-bluetooth-experimental"
|
||||
echo "Image: $image"
|
||||
echo "UEFI: $firmware"
|
||||
echo
|
||||
echo "Suggested in-guest checks:"
|
||||
echo " redbear-btusb --status"
|
||||
echo " redbear-btctl --status"
|
||||
echo " redbear-bluetooth-battery-check"
|
||||
echo " test-bluetooth-runtime.sh"
|
||||
echo
|
||||
|
||||
if [[ "$check_mode" -eq 1 ]]; then
|
||||
expect <<EOF
|
||||
log_user 1
|
||||
set timeout 300
|
||||
spawn qemu-system-x86_64 -name {Red Bear OS x86_64} -device qemu-xhci -smp 4 -m 2048 -bios $firmware -chardev stdio,id=debug,signal=off,mux=on -serial chardev:debug -mon chardev=debug -machine q35 -device ich9-intel-hda -device hda-output -device virtio-net,netdev=net0 -netdev user,id=net0 -object filter-dump,id=f1,netdev=net0,file=$pcap -nographic -vga none -drive file=$image,format=raw,if=none,id=drv0 -device nvme,drive=drv0,serial=NVME_SERIAL -drive file=$extra,format=raw,if=none,id=drv1 -device nvme,drive=drv1,serial=NVME_EXTRA -enable-kvm -cpu host $combined_qemu_args
|
||||
expect "login:"
|
||||
send "root\r"
|
||||
expect "assword:"
|
||||
send "password\r"
|
||||
expect "Type 'help' for available commands."
|
||||
send "redbear-bluetooth-battery-check\r"
|
||||
expect "Red Bear OS Bluetooth Battery Check"
|
||||
expect "BLUETOOTH_BATTERY_CHECK=pass"
|
||||
send "redbear-bluetooth-battery-check\r"
|
||||
expect "Red Bear OS Bluetooth Battery Check"
|
||||
expect "BLUETOOTH_BATTERY_CHECK=pass"
|
||||
send "shutdown\r"
|
||||
expect eof
|
||||
spawn qemu-system-x86_64 -name {Red Bear OS x86_64} -device qemu-xhci -smp 4 -m 2048 -bios $firmware -chardev stdio,id=debug,signal=off,mux=on -serial chardev:debug -mon chardev=debug -machine q35 -device ich9-intel-hda -device hda-output -device virtio-net,netdev=net0 -netdev user,id=net0 -object filter-dump,id=f1,netdev=net0,file=$pcap -nographic -vga none -drive file=$image,format=raw,if=none,id=drv0 -device nvme,drive=drv0,serial=NVME_SERIAL -drive file=$extra,format=raw,if=none,id=drv1 -device nvme,drive=drv1,serial=NVME_EXTRA -enable-kvm -cpu host $combined_qemu_args
|
||||
expect "login:"
|
||||
send "root\r"
|
||||
expect "assword:"
|
||||
send "password\r"
|
||||
expect "Type 'help' for available commands."
|
||||
send "redbear-bluetooth-battery-check\r"
|
||||
expect "Red Bear OS Bluetooth Battery Check"
|
||||
expect "BLUETOOTH_BATTERY_CHECK=pass"
|
||||
send "shutdown\r"
|
||||
expect eof
|
||||
EOF
|
||||
exit 0
|
||||
fi
|
||||
|
||||
exec qemu-system-x86_64 \
|
||||
-name "Red Bear OS x86_64" \
|
||||
-device qemu-xhci \
|
||||
-smp 4 \
|
||||
-m 2048 \
|
||||
-bios "$firmware" \
|
||||
-chardev stdio,id=debug,signal=off,mux=on \
|
||||
-serial chardev:debug \
|
||||
-mon chardev=debug \
|
||||
-machine q35 \
|
||||
-device ich9-intel-hda -device hda-output \
|
||||
-device virtio-net,netdev=net0 \
|
||||
-netdev user,id=net0 \
|
||||
-object filter-dump,id=f1,netdev=net0,file="$pcap" \
|
||||
-nographic -vga none \
|
||||
-drive file="$image",format=raw,if=none,id=drv0 \
|
||||
-device nvme,drive=drv0,serial=NVME_SERIAL \
|
||||
-drive file="$extra",format=raw,if=none,id=drv1 \
|
||||
-device nvme,drive=drv1,serial=NVME_EXTRA \
|
||||
-enable-kvm -cpu host \
|
||||
$combined_qemu_args
|
||||
Executable
+10
@@ -0,0 +1,10 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
if [ "$(uname -s)" != "Redox" ]; then
|
||||
echo "SKIP: Bluetooth runtime helper is guest-only and requires a Redox runtime"
|
||||
echo "Use the host checks for build/test verification, and run this script inside a Redox guest."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
exec redbear-bluetooth-battery-check
|
||||
Executable
+71
@@ -0,0 +1,71 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
echo "[iwlwifi-runtime] checking driver binary"
|
||||
if [ ! -x /usr/lib/drivers/redbear-iwlwifi ]; then
|
||||
echo "[iwlwifi-runtime] FAIL: /usr/lib/drivers/redbear-iwlwifi is missing"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[iwlwifi-runtime] checking PCI surface"
|
||||
if [ ! -d /scheme/pci ]; then
|
||||
echo "[iwlwifi-runtime] FAIL: /scheme/pci is missing"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[iwlwifi-runtime] running bounded probe"
|
||||
/usr/lib/drivers/redbear-iwlwifi --probe || {
|
||||
echo "[iwlwifi-runtime] FAIL: driver probe failed"
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo "[iwlwifi-runtime] running bounded status"
|
||||
/usr/lib/drivers/redbear-iwlwifi --status || {
|
||||
echo "[iwlwifi-runtime] FAIL: driver status failed"
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo "[iwlwifi-runtime] running bounded prepare"
|
||||
/usr/lib/drivers/redbear-iwlwifi --prepare || {
|
||||
echo "[iwlwifi-runtime] FAIL: driver prepare failed"
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo "[iwlwifi-runtime] running bounded transport init"
|
||||
/usr/lib/drivers/redbear-iwlwifi --init-transport || {
|
||||
echo "[iwlwifi-runtime] FAIL: driver init-transport failed"
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo "[iwlwifi-runtime] running bounded activate-nic"
|
||||
/usr/lib/drivers/redbear-iwlwifi --activate-nic || {
|
||||
echo "[iwlwifi-runtime] FAIL: driver activate-nic failed"
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo "[iwlwifi-runtime] running bounded scan"
|
||||
/usr/lib/drivers/redbear-iwlwifi --scan || {
|
||||
echo "[iwlwifi-runtime] FAIL: driver scan failed"
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo "[iwlwifi-runtime] running bounded connect"
|
||||
/usr/lib/drivers/redbear-iwlwifi --connect demo wpa2-psk secret || {
|
||||
echo "[iwlwifi-runtime] FAIL: driver connect failed"
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo "[iwlwifi-runtime] running bounded disconnect"
|
||||
/usr/lib/drivers/redbear-iwlwifi --disconnect || {
|
||||
echo "[iwlwifi-runtime] FAIL: driver disconnect failed"
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo "[iwlwifi-runtime] running bounded retry"
|
||||
/usr/lib/drivers/redbear-iwlwifi --retry || {
|
||||
echo "[iwlwifi-runtime] FAIL: driver retry failed"
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo "[iwlwifi-runtime] PASS: bounded Intel Wi-Fi driver-side action set executed"
|
||||
echo "[iwlwifi-runtime] NOTE: this still does not prove real scan, real association, or network connectivity"
|
||||
@@ -0,0 +1,147 @@
|
||||
#!/usr/bin/env bash
|
||||
# Validate the bounded Intel Wi-Fi runtime path on a real Red Bear OS target.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
PROFILE="${1:-wifi-open-bounded}"
|
||||
IFACE="${2:-wlan0}"
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage: test-wifi-baremetal-runtime.sh [PROFILE] [INTERFACE]
|
||||
|
||||
Run the strongest in-OS validation currently available for the bounded Intel Wi-Fi path.
|
||||
|
||||
Defaults:
|
||||
PROFILE wifi-open-bounded
|
||||
INTERFACE wlan0
|
||||
|
||||
This script validates runtime surfaces and bounded lifecycle behavior on a real Red Bear OS target.
|
||||
It does NOT prove real AP association, packet flow, or end-to-end Wi-Fi connectivity by itself.
|
||||
EOF
|
||||
}
|
||||
|
||||
if [[ "${1:-}" == "--help" || "${1:-}" == "-h" ]]; then
|
||||
usage
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "=== Red Bear OS Wi-Fi Bare-Metal Runtime Check ==="
|
||||
echo "profile=$PROFILE"
|
||||
echo "interface=$IFACE"
|
||||
|
||||
need_cmd() {
|
||||
if ! command -v "$1" >/dev/null 2>&1; then
|
||||
echo "FAIL: missing command $1"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
need_cmd redbear-iwlwifi
|
||||
need_cmd redbear-wifictl
|
||||
need_cmd redbear-netctl
|
||||
need_cmd redbear-info
|
||||
need_cmd redbear-phase5-wifi-capture
|
||||
need_cmd redbear-phase5-wifi-check
|
||||
need_cmd redbear-phase5-wifi-run
|
||||
|
||||
echo "--- packaged wifi check ---"
|
||||
redbear-phase5-wifi-run "$PROFILE" "$IFACE" "/tmp/redbear-phase5-wifi-capture.json"
|
||||
|
||||
echo "--- driver probe ---"
|
||||
driver_probe=$(redbear-iwlwifi --probe)
|
||||
printf '%s\n' "$driver_probe"
|
||||
case "$driver_probe" in
|
||||
*"candidates="*) ;;
|
||||
*)
|
||||
echo "FAIL: redbear-iwlwifi --probe did not report candidates"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "--- control probe ---"
|
||||
wifictl_probe=$(redbear-wifictl --probe)
|
||||
printf '%s\n' "$wifictl_probe"
|
||||
case "$wifictl_probe" in
|
||||
*"interfaces="*"$IFACE"*) ;;
|
||||
*)
|
||||
echo "FAIL: redbear-wifictl --probe did not report interface $IFACE"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "--- bounded connect ---"
|
||||
connect_output=$(redbear-wifictl --connect "$IFACE" demo open)
|
||||
printf '%s\n' "$connect_output"
|
||||
case "$connect_output" in
|
||||
*"status=connected"*|*"status=associated"*|*"status=associating"*) ;;
|
||||
*)
|
||||
echo "FAIL: bounded connect did not report bounded connect state"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
case "$connect_output" in
|
||||
*"connect_result="*) ;;
|
||||
*)
|
||||
echo "FAIL: bounded connect did not report connect_result"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "--- bounded disconnect ---"
|
||||
disconnect_output=$(redbear-wifictl --disconnect "$IFACE")
|
||||
printf '%s\n' "$disconnect_output"
|
||||
case "$disconnect_output" in
|
||||
*"status=device-detected"*|*"status=firmware-ready"*) ;;
|
||||
*)
|
||||
echo "FAIL: bounded disconnect did not return interface to post-disconnect state"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
case "$disconnect_output" in
|
||||
*"disconnect_result="*) ;;
|
||||
*)
|
||||
echo "FAIL: bounded disconnect did not report disconnect_result"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "--- profile manager start/stop ---"
|
||||
start_output=$(redbear-netctl start "$PROFILE")
|
||||
printf '%s\n' "$start_output"
|
||||
status_output=$(redbear-netctl status "$PROFILE")
|
||||
printf '%s\n' "$status_output"
|
||||
case "$status_output" in
|
||||
*"interface=$IFACE"*) ;;
|
||||
*)
|
||||
echo "FAIL: netctl status did not report interface $IFACE"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
case "$status_output" in
|
||||
*"connect_result="*) ;;
|
||||
*)
|
||||
echo "FAIL: netctl status did not report connect_result"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
stop_output=$(redbear-netctl stop "$PROFILE")
|
||||
printf '%s\n' "$stop_output"
|
||||
|
||||
echo "--- runtime report ---"
|
||||
info_output=$(redbear-info --json)
|
||||
printf '%s\n' "$info_output"
|
||||
case "$info_output" in
|
||||
*"wifi_control_state"*"wifi_connect_result"*"wifi_disconnect_result"*) ;;
|
||||
*)
|
||||
echo "FAIL: redbear-info --json did not include Wi-Fi lifecycle reporting fields"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
capture_path="/tmp/redbear-phase5-wifi-capture.json"
|
||||
|
||||
echo "PASS: bounded Intel Wi-Fi runtime path exercised on target"
|
||||
echo "CAPTURE: $capture_path"
|
||||
echo "NOTE: this still does not prove real AP scan/auth/association, packet flow, DHCP success over Wi-Fi, or validated end-to-end connectivity"
|
||||
Executable
+252
@@ -0,0 +1,252 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
echo "[wifi-runtime] checking wifictl scheme"
|
||||
if [ ! -d /scheme/wifictl ]; then
|
||||
echo "[wifi-runtime] FAIL: /scheme/wifictl is missing"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[wifi-runtime] checking bounded Intel driver package"
|
||||
if [ ! -x /usr/lib/drivers/redbear-iwlwifi ]; then
|
||||
echo "[wifi-runtime] FAIL: /usr/lib/drivers/redbear-iwlwifi is missing"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[wifi-runtime] probing Intel Wi-Fi candidates"
|
||||
driver_probe=$(/usr/lib/drivers/redbear-iwlwifi --probe 2>/dev/null)
|
||||
printf '%s\n' "$driver_probe"
|
||||
case "$driver_probe" in
|
||||
*"candidates="*)
|
||||
;;
|
||||
*)
|
||||
echo "[wifi-runtime] FAIL: redbear-iwlwifi --probe did not report candidates=..."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "[wifi-runtime] checking backend selection behavior"
|
||||
probe_output=$(redbear-wifictl --probe 2>/dev/null || true)
|
||||
printf '%s\n' "$probe_output"
|
||||
case "$driver_probe" in
|
||||
*"candidates=0"*)
|
||||
case "$probe_output" in
|
||||
*"backend=no-device"*)
|
||||
echo "[wifi-runtime] NOTE: no Intel Wi-Fi candidates detected; no-device backend fallback is expected"
|
||||
;;
|
||||
*)
|
||||
echo "[wifi-runtime] FAIL: expected no-device fallback when no Intel Wi-Fi candidates are detected"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*)
|
||||
case "$probe_output" in
|
||||
*"backend=intel"*)
|
||||
;;
|
||||
*)
|
||||
echo "[wifi-runtime] FAIL: redbear-wifictl --probe did not report backend=intel when Intel Wi-Fi candidates are present"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "[wifi-runtime] checking wifictl interface surface"
|
||||
if [ ! -d /scheme/wifictl/ifaces ]; then
|
||||
echo "[wifi-runtime] FAIL: /scheme/wifictl/ifaces is missing"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[wifi-runtime] checking firmware base path"
|
||||
if [ ! -d /lib/firmware ]; then
|
||||
echo "[wifi-runtime] FAIL: /lib/firmware is missing"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[wifi-runtime] listing interfaces"
|
||||
ls /scheme/wifictl/ifaces || true
|
||||
|
||||
first_iface=$(ls /scheme/wifictl/ifaces 2>/dev/null | head -n 1 || true)
|
||||
if [ -n "$first_iface" ]; then
|
||||
echo "[wifi-runtime] checking firmware-status for $first_iface"
|
||||
if [ ! -f "/scheme/wifictl/ifaces/$first_iface/firmware-status" ]; then
|
||||
echo "[wifi-runtime] FAIL: missing /scheme/wifictl/ifaces/$first_iface/firmware-status"
|
||||
exit 1
|
||||
fi
|
||||
cat "/scheme/wifictl/ifaces/$first_iface/firmware-status" || true
|
||||
|
||||
echo "[wifi-runtime] checking transport-status for $first_iface"
|
||||
if [ ! -f "/scheme/wifictl/ifaces/$first_iface/transport-status" ]; then
|
||||
echo "[wifi-runtime] FAIL: missing /scheme/wifictl/ifaces/$first_iface/transport-status"
|
||||
exit 1
|
||||
fi
|
||||
cat "/scheme/wifictl/ifaces/$first_iface/transport-status" || true
|
||||
|
||||
echo "[wifi-runtime] checking prepare control node for $first_iface"
|
||||
if [ ! -f "/scheme/wifictl/ifaces/$first_iface/prepare" ]; then
|
||||
echo "[wifi-runtime] FAIL: missing /scheme/wifictl/ifaces/$first_iface/prepare"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[wifi-runtime] checking scan control and scan-results for $first_iface"
|
||||
if [ ! -f "/scheme/wifictl/ifaces/$first_iface/scan" ]; then
|
||||
echo "[wifi-runtime] FAIL: missing /scheme/wifictl/ifaces/$first_iface/scan"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -f "/scheme/wifictl/ifaces/$first_iface/scan-results" ]; then
|
||||
echo "[wifi-runtime] FAIL: missing /scheme/wifictl/ifaces/$first_iface/scan-results"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[wifi-runtime] checking transport-probe control node for $first_iface"
|
||||
if [ ! -f "/scheme/wifictl/ifaces/$first_iface/transport-probe" ]; then
|
||||
echo "[wifi-runtime] FAIL: missing /scheme/wifictl/ifaces/$first_iface/transport-probe"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[wifi-runtime] checking transport-init nodes for $first_iface"
|
||||
if [ ! -f "/scheme/wifictl/ifaces/$first_iface/init-transport" ]; then
|
||||
echo "[wifi-runtime] FAIL: missing /scheme/wifictl/ifaces/$first_iface/init-transport"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -f "/scheme/wifictl/ifaces/$first_iface/transport-init-status" ]; then
|
||||
echo "[wifi-runtime] FAIL: missing /scheme/wifictl/ifaces/$first_iface/transport-init-status"
|
||||
exit 1
|
||||
fi
|
||||
cat "/scheme/wifictl/ifaces/$first_iface/transport-init-status" || true
|
||||
|
||||
echo "[wifi-runtime] checking activate-nic and activation-status for $first_iface"
|
||||
if [ ! -f "/scheme/wifictl/ifaces/$first_iface/activate-nic" ]; then
|
||||
echo "[wifi-runtime] FAIL: missing /scheme/wifictl/ifaces/$first_iface/activate-nic"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -f "/scheme/wifictl/ifaces/$first_iface/activation-status" ]; then
|
||||
echo "[wifi-runtime] FAIL: missing /scheme/wifictl/ifaces/$first_iface/activation-status"
|
||||
exit 1
|
||||
fi
|
||||
cat "/scheme/wifictl/ifaces/$first_iface/activation-status" || true
|
||||
|
||||
echo "[wifi-runtime] checking connect control and profile fields for $first_iface"
|
||||
if [ ! -f "/scheme/wifictl/ifaces/$first_iface/connect" ]; then
|
||||
echo "[wifi-runtime] FAIL: missing /scheme/wifictl/ifaces/$first_iface/connect"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -f "/scheme/wifictl/ifaces/$first_iface/ssid" ]; then
|
||||
echo "[wifi-runtime] FAIL: missing /scheme/wifictl/ifaces/$first_iface/ssid"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -f "/scheme/wifictl/ifaces/$first_iface/security" ]; then
|
||||
echo "[wifi-runtime] FAIL: missing /scheme/wifictl/ifaces/$first_iface/security"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -f "/scheme/wifictl/ifaces/$first_iface/key" ]; then
|
||||
echo "[wifi-runtime] FAIL: missing /scheme/wifictl/ifaces/$first_iface/key"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -f "/scheme/wifictl/ifaces/$first_iface/connect-result" ]; then
|
||||
echo "[wifi-runtime] FAIL: missing /scheme/wifictl/ifaces/$first_iface/connect-result"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -f "/scheme/wifictl/ifaces/$first_iface/disconnect-result" ]; then
|
||||
echo "[wifi-runtime] FAIL: missing /scheme/wifictl/ifaces/$first_iface/disconnect-result"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[wifi-runtime] exercising bounded connect for $first_iface"
|
||||
printf 'demo-open\n' > "/scheme/wifictl/ifaces/$first_iface/ssid"
|
||||
printf 'open\n' > "/scheme/wifictl/ifaces/$first_iface/security"
|
||||
printf '\n' > "/scheme/wifictl/ifaces/$first_iface/key"
|
||||
printf '1\n' > "/scheme/wifictl/ifaces/$first_iface/connect"
|
||||
|
||||
connect_status=$(cat "/scheme/wifictl/ifaces/$first_iface/status" 2>/dev/null || true)
|
||||
connect_result=$(cat "/scheme/wifictl/ifaces/$first_iface/connect-result" 2>/dev/null || true)
|
||||
printf '%s\n' "$connect_status"
|
||||
printf '%s\n' "$connect_result"
|
||||
case "$connect_status" in
|
||||
*"connected"*|*"associated"*)
|
||||
;;
|
||||
*)
|
||||
echo "[wifi-runtime] FAIL: bounded connect did not update status to a connected/associated state"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
case "$connect_result" in
|
||||
*"connect_result="*)
|
||||
;;
|
||||
*)
|
||||
echo "[wifi-runtime] FAIL: bounded connect did not produce connect-result output"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "[wifi-runtime] exercising bounded disconnect for $first_iface"
|
||||
if [ ! -f "/scheme/wifictl/ifaces/$first_iface/disconnect" ]; then
|
||||
echo "[wifi-runtime] FAIL: missing /scheme/wifictl/ifaces/$first_iface/disconnect"
|
||||
exit 1
|
||||
fi
|
||||
printf '1\n' > "/scheme/wifictl/ifaces/$first_iface/disconnect"
|
||||
|
||||
disconnect_status=$(cat "/scheme/wifictl/ifaces/$first_iface/status" 2>/dev/null || true)
|
||||
disconnect_result=$(cat "/scheme/wifictl/ifaces/$first_iface/disconnect-result" 2>/dev/null || true)
|
||||
printf '%s\n' "$disconnect_status"
|
||||
printf '%s\n' "$disconnect_result"
|
||||
case "$disconnect_status" in
|
||||
*"device-detected"*|*"firmware-ready"*)
|
||||
;;
|
||||
*)
|
||||
echo "[wifi-runtime] FAIL: bounded disconnect did not return the interface to a post-disconnect state"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
case "$disconnect_result" in
|
||||
*"disconnect"*)
|
||||
;;
|
||||
*)
|
||||
echo "[wifi-runtime] FAIL: bounded disconnect did not produce disconnect result output"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
else
|
||||
case "$driver_probe" in
|
||||
*"candidates=0"*)
|
||||
echo "[wifi-runtime] NOTE: no wifictl interfaces are expected when no Intel Wi-Fi candidates are present"
|
||||
;;
|
||||
*)
|
||||
echo "[wifi-runtime] FAIL: Intel Wi-Fi candidates were detected but /scheme/wifictl/ifaces is empty"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
echo "[wifi-runtime] checking netctl Wi-Fi examples"
|
||||
if [ ! -f /etc/netctl/examples/wifi-dhcp ]; then
|
||||
echo "[wifi-runtime] FAIL: missing /etc/netctl/examples/wifi-dhcp"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f /etc/netctl/examples/wifi-open-bounded ]; then
|
||||
echo "[wifi-runtime] FAIL: missing /etc/netctl/examples/wifi-open-bounded"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[wifi-runtime] exercising netctl profile stop for wifi-open-bounded"
|
||||
redbear-netctl stop wifi-open-bounded >/tmp/redbear-netctl-stop.out 2>/tmp/redbear-netctl-stop.err || {
|
||||
cat /tmp/redbear-netctl-stop.err || true
|
||||
echo "[wifi-runtime] FAIL: redbear-netctl stop wifi-open-bounded failed"
|
||||
exit 1
|
||||
}
|
||||
cat /tmp/redbear-netctl-stop.out || true
|
||||
|
||||
echo "[wifi-runtime] checking netcfg interface tree"
|
||||
if [ ! -d /scheme/netcfg/ifaces ]; then
|
||||
echo "[wifi-runtime] FAIL: /scheme/netcfg/ifaces is missing"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[wifi-runtime] netcfg interfaces:"
|
||||
cat /scheme/netcfg/ifaces || true
|
||||
|
||||
echo "[wifi-runtime] PASS: bounded Wi-Fi control-plane surfaces are present"
|
||||
echo "[wifi-runtime] PASS: experimental runtime selects the Intel backend only when Intel Wi-Fi candidates are actually present"
|
||||
echo "[wifi-runtime] NOTE: this does not prove real radio association or working Wi-Fi connectivity"
|
||||
@@ -0,0 +1,170 @@
|
||||
#!/usr/bin/env bash
|
||||
# Launch Red Bear OS with an Intel Wi-Fi PCI device passed through for runtime validation.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
find_uefi_firmware() {
|
||||
local candidates=(
|
||||
"/usr/share/ovmf/x64/OVMF.4m.fd"
|
||||
"/usr/share/OVMF/x64/OVMF.4m.fd"
|
||||
"/usr/share/ovmf/x64/OVMF_CODE.4m.fd"
|
||||
"/usr/share/OVMF/x64/OVMF_CODE.4m.fd"
|
||||
"/usr/share/ovmf/OVMF.fd"
|
||||
"/usr/share/OVMF/OVMF_CODE.fd"
|
||||
"/usr/share/qemu/edk2-x86_64-code.fd"
|
||||
)
|
||||
local path
|
||||
for path in "${candidates[@]}"; do
|
||||
if [[ -f "$path" ]]; then
|
||||
printf '%s\n' "$path"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
capture_output=""
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage: test-wifi-passthrough-qemu.sh --host-pci 0000:xx:yy.z [--check] [--capture-output PATH] [extra qemu args...]
|
||||
|
||||
Boot Red Bear OS with an Intel Wi-Fi PCI function passed through via VFIO and optionally run the
|
||||
bounded in-guest Wi-Fi runtime check.
|
||||
|
||||
Options:
|
||||
--host-pci BDF Host PCI address of the Intel Wi-Fi device to pass through (required)
|
||||
--check Auto-login and run redbear-phase5-network-check plus the bounded Wi-Fi runtime check
|
||||
--capture-output PATH Save the in-guest Wi-Fi capture bundle to a host-side file during --check
|
||||
-h, --help Show this help text
|
||||
|
||||
Notes:
|
||||
- The host device must already be detached from the host driver and bound to vfio-pci.
|
||||
- This script only provides the launch/check harness. Real success still depends on Red Bear OS
|
||||
runtime behavior on the passed-through hardware.
|
||||
EOF
|
||||
}
|
||||
|
||||
host_pci=""
|
||||
check_mode=0
|
||||
filtered_args=()
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--host-pci)
|
||||
if [[ $# -lt 2 ]]; then
|
||||
echo "ERROR: --host-pci requires a PCI BDF" >&2
|
||||
exit 1
|
||||
fi
|
||||
host_pci="$2"
|
||||
shift 2
|
||||
;;
|
||||
--check)
|
||||
check_mode=1
|
||||
shift
|
||||
;;
|
||||
--capture-output)
|
||||
if [[ $# -lt 2 ]]; then
|
||||
echo "ERROR: --capture-output requires a path" >&2
|
||||
exit 1
|
||||
fi
|
||||
capture_output="$2"
|
||||
shift 2
|
||||
;;
|
||||
--help|-h)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
filtered_args+=("$1")
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "$host_pci" ]]; then
|
||||
echo "ERROR: --host-pci is required" >&2
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
firmware="$(find_uefi_firmware)" || {
|
||||
echo "ERROR: no usable x86_64 UEFI firmware found" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
arch="${ARCH:-$(uname -m)}"
|
||||
image="build/$arch/redbear-full/harddrive.img"
|
||||
extra="build/$arch/redbear-full/extra.img"
|
||||
|
||||
if [[ ! -f "$image" ]]; then
|
||||
echo "ERROR: missing image $image" >&2
|
||||
echo "Build it first with: ./local/scripts/build-redbear.sh redbear-full" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "$extra" ]]; then
|
||||
truncate -s 1g "$extra"
|
||||
fi
|
||||
|
||||
vfio_arg="vfio-pci,host=${host_pci}"
|
||||
|
||||
if [[ "$check_mode" -eq 1 ]]; then
|
||||
capture_output="${capture_output:-$(pwd)/wifi-passthrough-capture.json}"
|
||||
expect <<EOF
|
||||
log_user 1
|
||||
set timeout 420
|
||||
spawn qemu-system-x86_64 -name {Red Bear OS Wi-Fi Passthrough} -device qemu-xhci -smp 4 -m 4096 -bios $firmware -chardev stdio,id=debug,signal=off,mux=on -serial chardev:debug -mon chardev=debug -machine q35 -device ich9-intel-hda -device hda-output -device vfio-pci,host=$host_pci -vga std -drive file=$image,format=raw,if=none,id=drv0 -device nvme,drive=drv0,serial=NVME_SERIAL -drive file=$extra,format=raw,if=none,id=drv1 -device nvme,drive=drv1,serial=NVME_EXTRA -enable-kvm -cpu host ${filtered_args[*]}
|
||||
expect "login:"
|
||||
send "root\r"
|
||||
expect "assword:"
|
||||
send "password\r"
|
||||
expect "Type 'help' for available commands."
|
||||
send "redbear-phase5-network-check\r"
|
||||
expect "Red Bear OS Phase 5 Networking Check"
|
||||
send "redbear-phase5-wifi-run wifi-open-bounded wlan0 /tmp/redbear-phase5-wifi-capture.json\r"
|
||||
expect "Red Bear OS Phase 5 Wi-Fi Check"
|
||||
expect "PASS: bounded Intel Wi-Fi runtime path exercised on target"
|
||||
expect "capture_output=/tmp/redbear-phase5-wifi-capture.json"
|
||||
expect "root@"
|
||||
send "wc -c /tmp/redbear-phase5-wifi-capture.json\r"
|
||||
expect "/tmp/redbear-phase5-wifi-capture.json"
|
||||
send "printf 'CAPTURE-BEGIN\\n'; cat /tmp/redbear-phase5-wifi-capture.json; printf '\\nCAPTURE-END\\n'\r"
|
||||
expect "CAPTURE-BEGIN"
|
||||
expect {
|
||||
-re {(\{.*\})\r?\nCAPTURE-END} {
|
||||
set capture $expect_out(1,string)
|
||||
set fh [open "$capture_output" "w"]
|
||||
puts $fh $capture
|
||||
close $fh
|
||||
}
|
||||
timeout {
|
||||
send_user "ERROR: timed out while capturing Wi-Fi bundle\n"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
send "shutdown\r"
|
||||
expect eof
|
||||
EOF
|
||||
echo "capture_output=$capture_output"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
exec qemu-system-x86_64 \
|
||||
-name "Red Bear OS Wi-Fi Passthrough" \
|
||||
-device qemu-xhci \
|
||||
-smp 4 \
|
||||
-m 4096 \
|
||||
-bios "$firmware" \
|
||||
-chardev stdio,id=debug,signal=off,mux=on \
|
||||
-serial chardev:debug \
|
||||
-mon chardev=debug \
|
||||
-machine q35 \
|
||||
-device ich9-intel-hda -device hda-output \
|
||||
-device "$vfio_arg" \
|
||||
-vga std \
|
||||
-drive file="$image",format=raw,if=none,id=drv0 \
|
||||
-device nvme,drive=drv0,serial=NVME_SERIAL \
|
||||
-drive file="$extra",format=raw,if=none,id=drv1 \
|
||||
-device nvme,drive=drv1,serial=NVME_EXTRA \
|
||||
-enable-kvm -cpu host \
|
||||
"${filtered_args[@]}"
|
||||
@@ -0,0 +1,175 @@
|
||||
#!/usr/bin/env bash
|
||||
# Validate host prerequisites for Intel Wi-Fi VFIO passthrough testing.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage: validate-wifi-vfio-host.sh --host-pci 0000:xx:yy.z [--expect-driver DRIVER]
|
||||
|
||||
Check whether the current host appears ready to run the Red Bear Intel Wi-Fi VFIO passthrough
|
||||
validation path.
|
||||
|
||||
Options:
|
||||
--host-pci BDF Host PCI address of the Intel Wi-Fi device to validate (required)
|
||||
--expect-driver NAME Host driver expected before VFIO rebind (optional)
|
||||
-h, --help Show this help text
|
||||
|
||||
This command does not modify the host. It only reports readiness signals and common blockers.
|
||||
EOF
|
||||
}
|
||||
|
||||
host_pci=""
|
||||
expect_driver=""
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--host-pci)
|
||||
host_pci="$2"
|
||||
shift 2
|
||||
;;
|
||||
--expect-driver)
|
||||
expect_driver="$2"
|
||||
shift 2
|
||||
;;
|
||||
--help|-h)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "ERROR: unknown argument $1" >&2
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "$host_pci" ]]; then
|
||||
echo "ERROR: --host-pci is required" >&2
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
script_root="$(dirname "$0")"
|
||||
repo_root="$(cd "$script_root/../.." && pwd)"
|
||||
arch="${ARCH:-$(uname -m)}"
|
||||
image="$repo_root/build/$arch/redbear-full/harddrive.img"
|
||||
|
||||
find_uefi_firmware() {
|
||||
local candidates=(
|
||||
"/usr/share/ovmf/x64/OVMF.4m.fd"
|
||||
"/usr/share/OVMF/x64/OVMF.4m.fd"
|
||||
"/usr/share/ovmf/x64/OVMF_CODE.4m.fd"
|
||||
"/usr/share/OVMF/x64/OVMF_CODE.4m.fd"
|
||||
"/usr/share/ovmf/OVMF.fd"
|
||||
"/usr/share/OVMF/OVMF_CODE.fd"
|
||||
"/usr/share/qemu/edk2-x86_64-code.fd"
|
||||
)
|
||||
local path
|
||||
for path in "${candidates[@]}"; do
|
||||
if [[ -f "$path" ]]; then
|
||||
printf '%s\n' "$path"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
current_driver() {
|
||||
local bdf="$1"
|
||||
local link="/sys/bus/pci/devices/$bdf/driver"
|
||||
if [[ -L "$link" ]]; then
|
||||
basename "$(readlink -f "$link")"
|
||||
else
|
||||
printf 'none\n'
|
||||
fi
|
||||
}
|
||||
|
||||
read_pci_id() {
|
||||
local bdf="$1"
|
||||
local vendor device
|
||||
vendor=$(<"/sys/bus/pci/devices/$bdf/vendor")
|
||||
device=$(<"/sys/bus/pci/devices/$bdf/device")
|
||||
printf '%s %s\n' "$vendor" "$device"
|
||||
}
|
||||
|
||||
status=0
|
||||
|
||||
echo "=== Red Bear Wi-Fi VFIO Host Validation ==="
|
||||
echo "host_pci=$host_pci"
|
||||
|
||||
if [[ ! -e "/sys/bus/pci/devices/$host_pci" ]]; then
|
||||
echo "FAIL: PCI device $host_pci not found in sysfs"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
read -r vendor device < <(read_pci_id "$host_pci")
|
||||
driver=$(current_driver "$host_pci")
|
||||
echo "vendor=$vendor"
|
||||
echo "device=$device"
|
||||
echo "current_driver=$driver"
|
||||
|
||||
if [[ -n "$expect_driver" && "$driver" != "$expect_driver" && "$driver" != "vfio-pci" ]]; then
|
||||
echo "WARN: expected host driver $expect_driver but found $driver"
|
||||
status=1
|
||||
fi
|
||||
|
||||
if ! find_uefi_firmware >/dev/null; then
|
||||
echo "FAIL: no supported x86_64 UEFI firmware found for QEMU"
|
||||
status=1
|
||||
else
|
||||
echo "uefi_firmware=present"
|
||||
fi
|
||||
|
||||
if [[ ! -f "$image" ]]; then
|
||||
echo "FAIL: missing image $image"
|
||||
status=1
|
||||
else
|
||||
echo "redbear_image=present"
|
||||
fi
|
||||
|
||||
if ! command -v qemu-system-x86_64 >/dev/null 2>&1; then
|
||||
echo "FAIL: missing qemu-system-x86_64"
|
||||
status=1
|
||||
else
|
||||
echo "qemu=present"
|
||||
fi
|
||||
|
||||
if ! command -v expect >/dev/null 2>&1; then
|
||||
echo "FAIL: missing expect"
|
||||
status=1
|
||||
else
|
||||
echo "expect=present"
|
||||
fi
|
||||
|
||||
if ! lsmod | grep -q '^vfio_pci'; then
|
||||
echo "WARN: vfio_pci module is not currently loaded"
|
||||
status=1
|
||||
else
|
||||
echo "vfio_pci=loaded"
|
||||
fi
|
||||
|
||||
if [[ -d /sys/kernel/iommu_groups && -n "$(find /sys/kernel/iommu_groups -mindepth 1 -maxdepth 1 -type d 2>/dev/null)" ]]; then
|
||||
echo "iommu_groups=present"
|
||||
else
|
||||
echo "WARN: IOMMU groups not visible under /sys/kernel/iommu_groups"
|
||||
status=1
|
||||
fi
|
||||
|
||||
if command -v lspci >/dev/null 2>&1; then
|
||||
echo "lspci_summary=$(lspci -nn -s "$host_pci" 2>/dev/null || true)"
|
||||
fi
|
||||
|
||||
if [[ "$driver" == "vfio-pci" ]]; then
|
||||
echo "vfio_binding=already-bound"
|
||||
else
|
||||
echo "vfio_binding=not-bound"
|
||||
fi
|
||||
|
||||
if [[ "$status" -eq 0 ]]; then
|
||||
echo "PASS: host appears ready for Wi-Fi VFIO validation"
|
||||
else
|
||||
echo "FAIL: host validation found one or more blockers/warnings"
|
||||
fi
|
||||
|
||||
exit "$status"
|
||||
Reference in New Issue
Block a user