Refresh local build and test scripts, add DRM and Intel GPU test scripts

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2026-04-18 17:59:15 +01:00
parent b029ab628f
commit 841773c3a7
14 changed files with 572 additions and 198 deletions
-86
View File
@@ -1,86 +0,0 @@
#!/usr/bin/env bash
# Build Red Bear OS with AMD GPU support (Phase P2)
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
CONFIG="${1:-my-amd-desktop}"
JOBS="${JOBS:-$(nproc)}"
APPLY_PATCHES="${APPLY_PATCHES:-1}"
echo "=== Red Bear OS AMD GPU Build ==="
echo "Config: $CONFIG"
echo "Jobs: $JOBS"
echo "Apply patches: $APPLY_PATCHES"
echo "Root: $PROJECT_ROOT"
echo ""
cd "$PROJECT_ROOT"
# Step 0: Apply local patches
if [ "$APPLY_PATCHES" = "1" ]; then
echo ">>> Applying local patches..."
apply_patch_dir() {
local patch_dir="$1"
local target_dir="$2"
local label="$3"
if [ ! -d "$patch_dir" ]; then
return 0
fi
for patch_file in $(ls "$patch_dir"/*.patch 2>/dev/null | sort); do
patch_name=$(basename "$patch_file")
if [ ! -d "$target_dir" ]; then
echo " SKIP $patch_name ($label source not fetched yet)"
continue
fi
if patch --dry-run -p1 -d "$target_dir" < "$patch_file" > /dev/null 2>&1; then
patch -p1 -d "$target_dir" < "$patch_file" > /dev/null 2>&1
echo " OK $patch_name"
else
echo " SKIP $patch_name (already applied or won't apply)"
fi
done
}
apply_patch_dir "$PROJECT_ROOT/local/patches/kernel" "$PROJECT_ROOT/recipes/core/kernel/source" "kernel"
apply_patch_dir "$PROJECT_ROOT/local/patches/base" "$PROJECT_ROOT/recipes/core/base/source" "base"
apply_patch_dir "$PROJECT_ROOT/local/patches/relibc" "$PROJECT_ROOT/recipes/core/relibc/source" "relibc"
apply_patch_dir "$PROJECT_ROOT/local/patches/bootloader" "$PROJECT_ROOT/recipes/core/bootloader/source" "bootloader"
apply_patch_dir "$PROJECT_ROOT/local/patches/installer" "$PROJECT_ROOT/recipes/core/installer/source" "installer"
echo ""
fi
# Step 1: Build cookbook binary if needed
if [ ! -f "target/release/repo" ]; then
echo ">>> Building cookbook binary..."
cargo build --release
fi
# Step 2: Fetch AMD firmware blobs if missing
FW_DIR="$PROJECT_ROOT/local/firmware/amdgpu"
if [ -z "$(ls -A "$FW_DIR" 2>/dev/null)" ]; then
echo ">>> AMD firmware blobs not found. Run local/scripts/fetch-firmware.sh first."
echo " Skipping firmware fetch. Driver will NOT function without firmware."
else
FW_COUNT=$(ls "$FW_DIR"/*.bin 2>/dev/null | wc -l)
echo ">>> Found $FW_COUNT AMD firmware blobs"
fi
# Step 3: Build
echo ">>> Building Red Bear OS with config: $CONFIG"
echo ">>> This may take 30-60 minutes on first build..."
CI=1 make all "CONFIG_NAME=$CONFIG" "JOBS=$JOBS"
echo ""
echo "=== Build Complete ==="
echo "Image: build/x86_64/harddrive.img"
echo ""
echo "To run in QEMU:"
echo " make qemu QEMUFLAGS=\"-m 4G\""
echo ""
echo "To test on bare metal:"
echo " dd if=build/x86_64/harddrive.img of=/dev/sdX bs=4M status=progress"
+73 -11
View File
@@ -2,14 +2,15 @@
# build-redbear.sh — Build Red Bear OS from upstream base + Red Bear overlay
#
# Usage:
# ./local/scripts/build-redbear.sh # Default: redbear-desktop
# ./local/scripts/build-redbear.sh redbear-minimal # Minimal validation baseline
# ./local/scripts/build-redbear.sh # Default: redbear-kde
# ./local/scripts/build-redbear.sh redbear-minimal # Minimal validation baseline
# ./local/scripts/build-redbear.sh redbear-bluetooth-experimental # First bounded Bluetooth slice
# ./local/scripts/build-redbear.sh redbear-full # Full Red Bear integration target
# ./local/scripts/build-redbear.sh redbear-wayland # Wayland runtime validation profile
# ./local/scripts/build-redbear.sh redbear-kde # KDE Plasma bring-up target
# ./local/scripts/build-redbear.sh redbear-live # Live ISO variant
# APPLY_PATCHES=0 ./local/scripts/build-redbear.sh # Skip patch application
# ./local/scripts/build-redbear.sh redbear-full # Full Red Bear integration target
# ./local/scripts/build-redbear.sh redbear-wayland # Bounded Wayland runtime validation profile
# ./local/scripts/build-redbear.sh redbear-kde # Tracked KWin Wayland desktop target
# ./local/scripts/build-redbear.sh redbear-live # Live ISO variant
# ./local/scripts/build-redbear.sh --upstream redbear-kde # Allow Redox/upstream recipe refresh
# APPLY_PATCHES=0 ./local/scripts/build-redbear.sh # Skip patch application
#
# This script assumes the Red Bear overlay model:
# - upstream-owned sources are refreshable working trees
@@ -20,9 +21,56 @@ set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
CONFIG="${1:-redbear-desktop}"
CONFIG="redbear-kde"
JOBS="${JOBS:-$(nproc)}"
APPLY_PATCHES="${APPLY_PATCHES:-1}"
ALLOW_UPSTREAM=0
usage() {
cat <<EOF
Usage: $(basename "$0") [OPTIONS] [CONFIG]
Build a tracked Red Bear OS profile.
Options:
--upstream Allow Redox/upstream recipe source refresh during build
-h, --help Show this help
Configs:
redbear-desktop, redbear-minimal, redbear-bluetooth-experimental,
redbear-full, redbear-wayland, redbear-kde, redbear-live
EOF
}
POSITIONAL=()
while [ $# -gt 0 ]; do
case "$1" in
--upstream)
ALLOW_UPSTREAM=1
;;
-h|--help)
usage
exit 0
;;
-*)
echo "Unknown option: $1" >&2
usage >&2
exit 1
;;
*)
POSITIONAL+=("$1")
;;
esac
shift
done
if [ ${#POSITIONAL[@]} -gt 1 ]; then
echo "ERROR: Too many positional arguments" >&2
usage >&2
exit 1
fi
[ ${#POSITIONAL[@]} -eq 1 ] && CONFIG="${POSITIONAL[0]}"
case "$CONFIG" in
redbear-desktop|redbear-minimal|redbear-bluetooth-experimental|redbear-full|redbear-wayland|redbear-kde|redbear-live)
@@ -40,6 +88,7 @@ echo "========================================"
echo "Config: $CONFIG"
echo "Jobs: $JOBS"
echo "Apply patches: $APPLY_PATCHES"
echo "Upstream: $ALLOW_UPSTREAM"
echo "Root: ${PROJECT_ROOT##*/}"
echo "========================================"
echo ""
@@ -112,7 +161,7 @@ if [ "$APPLY_PATCHES" = "1" ]; then
apply_patch_dir "$PROJECT_ROOT/local/patches/bootloader" "$PROJECT_ROOT/recipes/core/bootloader/source" "bootloader"
apply_patch_dir "$PROJECT_ROOT/local/patches/installer" "$PROJECT_ROOT/recipes/core/installer/source" "installer"
# repo cook refetches nested sources before building; keep relibc clean after patch application
# repo cook can refetch nested sources when --upstream is enabled; keep relibc clean after patch application
stash_nested_repo_if_dirty "$PROJECT_ROOT/recipes/core/relibc/source" "relibc"
echo ""
fi
@@ -140,7 +189,13 @@ fi
# Step 3: Build
echo ">>> Building Red Bear OS with config: $CONFIG"
echo ">>> This may take 30-60 minutes on first build..."
CI=1 make all "CONFIG_NAME=$CONFIG" "JOBS=$JOBS"
if [ "$ALLOW_UPSTREAM" -eq 1 ]; then
echo ">>> Upstream recipe refresh enabled"
REPO_OFFLINE=0 COOKBOOK_OFFLINE=false CI=1 make all "CONFIG_NAME=$CONFIG" "JOBS=$JOBS"
else
echo ">>> Upstream recipe refresh disabled (pass --upstream to enable)"
REPO_OFFLINE=1 COOKBOOK_OFFLINE=true CI=1 make all "CONFIG_NAME=$CONFIG" "JOBS=$JOBS"
fi
# Step 4: Report
ARCH="${ARCH:-$(uname -m)}"
@@ -160,8 +215,15 @@ if [ "$CONFIG" = "redbear-minimal" ] || [ "$CONFIG" = "redbear-desktop" ]; then
fi
if [ "$CONFIG" = "redbear-wayland" ]; then
echo ""
echo "To validate the Phase 4 Wayland runtime path:"
echo "To validate the bounded Phase 4 Wayland runtime harness:"
echo " ./local/scripts/test-phase4-wayland-qemu.sh"
echo " # in guest: redbear-drm-display-check --vendor amd|intel"
fi
if [ "$CONFIG" = "redbear-kde" ]; then
echo ""
echo "To validate the primary KWin Wayland desktop path:"
echo " ./local/scripts/test-phase6-kde-qemu.sh --check"
echo " # in guest: redbear-drm-display-check --vendor amd|intel"
fi
echo ""
echo "To build live ISO:"
+119 -21
View File
@@ -9,11 +9,12 @@ Usage:
Outputs TOML quirk entries to stdout that can be appended to files in
/etc/quirks.d/ or local/recipes/system/redbear-quirks/source/quirks.d/.
PCI mode: handler-name → flag mapping is heuristic (substring match). Output
requires manual review — the script may misinfer flags. USB table extraction is
direct and does not require review.
PCI mode only maps explicit, high-confidence handler body effects. Unsupported
handlers are omitted instead of guessed. USB table extraction is direct and does
not require review.
"""
from dataclasses import dataclass
import re
import sys
@@ -27,6 +28,10 @@ PCI_FLAG_MAP = {
"PCI_DEV_FLAGS_BROKEN_PM": "no_pm",
}
PCI_HELPER_CALL_MAP = {
"pci_d3cold_disable": "no_d3cold",
}
USB_FLAG_MAP = {
"USB_QUIRK_STRING_FETCH_255": "no_string_fetch",
"USB_QUIRK_RESET_RESUME": "need_reset",
@@ -56,6 +61,15 @@ PCI_FIXUP_RE = re.compile(
r'(\w+)\s*\)'
)
PCI_FIXUP_CLASS_RE = re.compile(
r'DECLARE_PCI_FIXUP_CLASS_(?:FINAL|HEADER|EARLY|ENABLE|RESUME|LATE)\s*\(\s*'
r'(?:0x([0-9a-fA-F]+)|PCI_ANY_ID)\s*,\s*'
r'(?:0x([0-9a-fA-F]+)|PCI_ANY_ID)\s*,\s*'
r'(?:0x([0-9a-fA-F]+)|PCI_ANY_ID)\s*,\s*'
r'(?:0x([0-9a-fA-F]+)|PCI_ANY_ID)\s*,\s*'
r'(\w+)\s*\)'
)
DMI_MATCH_RE = re.compile(
r'DMI_MATCH\s*\(\s*DMI_([A-Z_]+)\s*,\s*"([^"]+)"\s*\)'
)
@@ -66,6 +80,18 @@ USB_QUIRK_TABLE_RE = re.compile(
r'([^}]+)\}'
)
PCI_HANDLER_RE = re.compile(r'\b(?P<name>\w+)\s*\([^;{}]*?\)\s*\{', re.DOTALL)
PCI_DEV_FLAGS_ASSIGNMENT_RE = re.compile(r'\b\w+\s*->\s*dev_flags\s*(?:\|=|=)\s*[^;]+;')
@dataclass(frozen=True)
class PciFixup:
vendor: int
device: int
handler: str
klass: int | None = None
class_mask: int | None = None
def extract_pci_fixups(source):
entries = []
@@ -73,10 +99,86 @@ def extract_pci_fixups(source):
vendor = int(m.group(1), 16) if m.group(1) else 0xFFFF
device = int(m.group(2), 16) if m.group(2) else 0xFFFF
handler = m.group(3)
entries.append((vendor, device, handler))
entries.append(PciFixup(vendor=vendor, device=device, handler=handler))
for m in PCI_FIXUP_CLASS_RE.finditer(source):
vendor = int(m.group(1), 16) if m.group(1) else 0xFFFF
device = int(m.group(2), 16) if m.group(2) else 0xFFFF
klass = int(m.group(3), 16) if m.group(3) else 0xFFFF
class_mask = int(m.group(4), 16) if m.group(4) else 0xFFFF
handler = m.group(5)
entries.append(
PciFixup(
vendor=vendor,
device=device,
handler=handler,
klass=klass,
class_mask=class_mask,
)
)
return entries
def _extract_brace_block(source, brace_start):
depth = 0
for index in range(brace_start, len(source)):
char = source[index]
if char == "{":
depth += 1
elif char == "}":
depth -= 1
if depth == 0:
return source[brace_start + 1 : index]
return None
def index_handler_bodies(source, handler_names):
bodies = {}
wanted = set(handler_names)
if not wanted:
return bodies
for match in PCI_HANDLER_RE.finditer(source):
name = match.group("name")
if name not in wanted or name in bodies:
continue
brace_start = match.end() - 1
body = _extract_brace_block(source, brace_start)
if body is not None:
bodies[name] = body
return bodies
def extract_pci_flags_from_handler(body):
flags = []
seen = set()
for match in PCI_DEV_FLAGS_ASSIGNMENT_RE.finditer(body):
statement = match.group(0)
for flag_name, toml_name in PCI_FLAG_MAP.items():
pattern = re.escape(flag_name) + r'(?:\s|$|\||\)|;|,)'
if re.search(pattern, statement) and toml_name not in seen:
flags.append(toml_name)
seen.add(toml_name)
for helper_name, toml_name in PCI_HELPER_CALL_MAP.items():
pattern = rf'\b{re.escape(helper_name)}\s*\(\s*\w+\s*\)'
if re.search(pattern, body) and toml_name not in seen:
flags.append(toml_name)
seen.add(toml_name)
return flags
def map_pci_fixups_to_flags(source):
fixups = extract_pci_fixups(source)
handler_bodies = index_handler_bodies(source, [fixup.handler for fixup in fixups])
mapped = []
for fixup in fixups:
flags = extract_pci_flags_from_handler(handler_bodies.get(fixup.handler, ""))
mapped.append((fixup, flags))
return mapped
def extract_usb_quirks(source):
entries = []
for m in USB_QUIRK_TABLE_RE.finditer(source):
@@ -94,14 +196,18 @@ def extract_usb_quirks(source):
def format_pci_toml(entries):
lines = []
for vendor, device, flags in entries:
for fixup, flags in entries:
if not flags:
continue
lines.append("[[pci_quirk]]")
if vendor != 0xFFFF:
lines.append(f"vendor = 0x{vendor:04X}")
if device != 0xFFFF:
lines.append(f"device = 0x{device:04X}")
if fixup.vendor != 0xFFFF:
lines.append(f"vendor = 0x{fixup.vendor:04X}")
if fixup.device != 0xFFFF:
lines.append(f"device = 0x{fixup.device:04X}")
if fixup.klass is not None and fixup.klass != 0xFFFF:
lines.append(f"class = 0x{fixup.klass:06X}")
if fixup.class_mask is not None and fixup.class_mask != 0xFFFF:
lines.append(f"class_mask = 0x{fixup.class_mask:06X}")
lines.append(f'flags = [{", ".join(f"\"{f}\"" for f in flags)}]')
lines.append("")
return "\n".join(lines)
@@ -226,18 +332,10 @@ def main():
entries = extract_usb_quirks(source)
print(format_usb_toml(entries))
else:
entries = extract_pci_fixups(source)
flags_map = PCI_FLAG_MAP
mapped = []
for vendor, device, handler in entries:
flags = []
for flag_name, toml_name in flags_map.items():
if flag_name.lower() in handler.lower():
flags.append(toml_name)
mapped.append((vendor, device, flags))
print("# WARNING: PCI handler-name → flag mapping is heuristic.")
print("# WARNING: Output requires manual review before committing.")
print("# USB table extraction is direct and does not need review.")
mapped = map_pci_fixups_to_flags(source)
print("# WARNING: PCI output only includes explicit, high-confidence handler body mappings.")
print("# WARNING: Unsupported Linux PCI quirk handlers are intentionally omitted.")
print("# WARNING: Review generated PCI entries before committing.")
print(format_pci_toml(mapped))
+119 -18
View File
@@ -1,28 +1,39 @@
#!/usr/bin/env bash
# Fetch AMD GPU firmware blobs from linux-firmware repository
# These are required for amdgpu driver to function
# Fetch bounded GPU firmware blobs from linux-firmware repository.
# AMD remains the larger set; Intel support here is intentionally limited to
# display-critical DMC blobs for the current bounded startup manifest.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
FIRMWARE_DIR="$SCRIPT_DIR/../firmware/amdgpu"
LINUX_FIRMWARE_REPO="https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git"
TEMP_DIR=$(mktemp -d)
VENDOR="amd"
SUBSET="all"
usage() {
cat <<EOF
Usage: $(basename "$0") [--subset all|rdna]
Usage: $(basename "$0") [--vendor amd|intel] [--subset all|rdna|dmc]
Fetch AMD GPU firmware blobs from linux-firmware.
Fetch bounded GPU firmware blobs from linux-firmware.
Options:
--subset all Fetch the full amdgpu firmware set (default)
--subset rdna Fetch only RDNA2/RDNA3-oriented firmware blobs
--vendor amd Fetch AMD GPU firmware (default)
--vendor intel Fetch bounded Intel display-critical DMC firmware set
--subset all Fetch the full AMD amdgpu firmware set (default for AMD)
--subset rdna Fetch only RDNA2/RDNA3-oriented AMD firmware blobs
--subset dmc Fetch bounded Intel DMC display firmware set (default for Intel)
-h, --help Show this help text
EOF
}
set_firmware_dir() {
case "$VENDOR" in
amd) FIRMWARE_DIR="$SCRIPT_DIR/../firmware/amdgpu" ;;
intel) FIRMWARE_DIR="$SCRIPT_DIR/../firmware/i915" ;;
esac
}
cleanup() {
rm -rf "$TEMP_DIR"
}
@@ -40,6 +51,15 @@ while [ "$#" -gt 0 ]; do
SUBSET="$2"
shift 2
;;
--vendor)
if [ "$#" -lt 2 ]; then
echo "ERROR: --vendor requires a value"
usage
exit 1
fi
VENDOR="$2"
shift 2
;;
-h|--help)
usage
exit 0
@@ -52,17 +72,41 @@ while [ "$#" -gt 0 ]; do
esac
done
case "$SUBSET" in
all|rdna)
case "$VENDOR" in
amd)
case "$SUBSET" in
all|rdna) ;;
*)
echo "ERROR: Unsupported AMD subset: $SUBSET"
usage
exit 1
;;
esac
;;
intel)
if [ "$SUBSET" = "all" ]; then
SUBSET="dmc"
fi
case "$SUBSET" in
dmc) ;;
*)
echo "ERROR: Unsupported Intel subset: $SUBSET"
usage
exit 1
;;
esac
;;
*)
echo "ERROR: Unsupported subset: $SUBSET"
echo "ERROR: Unsupported vendor: $VENDOR"
usage
exit 1
;;
esac
echo "=== AMD GPU Firmware Fetcher ==="
set_firmware_dir
echo "=== GPU Firmware Fetcher ==="
echo "Vendor: $VENDOR"
echo "Target: $FIRMWARE_DIR"
echo "Subset: $SUBSET"
@@ -73,7 +117,7 @@ git clone --depth 1 "$LINUX_FIRMWARE_REPO" "$TEMP_DIR/linux-firmware"
# Create target directory
mkdir -p "$FIRMWARE_DIR"
# Copy AMD GPU firmware
copy_amd_firmware() {
echo "Copying AMD GPU firmware blobs..."
if [ -d "$TEMP_DIR/linux-firmware/amdgpu" ]; then
shopt -s nullglob
@@ -145,10 +189,63 @@ else
echo "ERROR: amdgpu firmware directory not found in linux-firmware"
exit 1
fi
}
# Also create a listing of which firmware blobs map to which ASICs
echo "=== Creating firmware manifest ==="
cat > "$FIRMWARE_DIR/MANIFEST.txt" << 'MANIFEST'
copy_intel_dmc_firmware() {
echo "Copying bounded Intel DMC firmware blobs..."
if [ ! -d "$TEMP_DIR/linux-firmware/i915" ]; then
echo "ERROR: i915 firmware directory not found in linux-firmware"
exit 1
fi
local selected_blobs=()
local candidates=(
adlp_dmc.bin
adlp_dmc_ver2_16.bin
tgl_dmc.bin
tgl_dmc_ver2_12.bin
dg2_dmc.bin
dg2_dmc_ver2_06.bin
mtl_dmc.bin
)
for blob in "${candidates[@]}"; do
if [ -f "$TEMP_DIR/linux-firmware/i915/$blob" ]; then
selected_blobs+=("$TEMP_DIR/linux-firmware/i915/$blob")
fi
done
if [ "${#selected_blobs[@]}" -eq 0 ]; then
echo "ERROR: No Intel DMC firmware blobs were found"
exit 1
fi
rm -f "$FIRMWARE_DIR"/*.bin
cp -v "${selected_blobs[@]}" "$FIRMWARE_DIR/"
cat > "$FIRMWARE_DIR/MANIFEST.txt" <<'MANIFEST'
# Intel GPU Firmware for Red Bear OS (bounded startup slice)
# Source: linux-firmware (https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git)
# Scope: display-critical DMC blobs only
#
# This subset is intentionally bounded to startup/display proof for current Intel DRM work.
# It does NOT include GuC/HuC/GSC runtime/render/media firmware.
#
# Current bounded candidates:
# - adlp_dmc.bin / adlp_dmc_ver2_16.bin
# - tgl_dmc.bin / tgl_dmc_ver2_12.bin
# - dg2_dmc.bin / dg2_dmc_ver2_06.bin
# - mtl_dmc.bin
MANIFEST
echo "Copied ${#selected_blobs[@]} Intel DMC firmware blobs"
}
case "$VENDOR" in
amd)
copy_amd_firmware
echo "=== Creating firmware manifest ==="
cat > "$FIRMWARE_DIR/MANIFEST.txt" << 'MANIFEST'
# AMD GPU Firmware for Red Bear OS
# Source: linux-firmware (https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git)
# License: Various — see linux-firmware WHENCE file for details
@@ -166,8 +263,12 @@ cat > "$FIRMWARE_DIR/MANIFEST.txt" << 'MANIFEST'
# Key files for RDNA3 (Navi 31/32/33, gfx11):
# psp_13_*_sos.bin, gc_11_0_*.bin, sdma_6_*.bin, dcn_3_1_*.bin
MANIFEST
echo "$FIRMWARE_DIR/MANIFEST.txt created"
echo "$FIRMWARE_DIR/MANIFEST.txt created"
;;
intel)
copy_intel_dmc_firmware
;;
esac
# Summary
echo ""
@@ -176,5 +277,5 @@ ls -la "$FIRMWARE_DIR/" | head -20
echo "..."
echo "Total: $(ls "$FIRMWARE_DIR/"*.bin 2>/dev/null | wc -l) blobs"
echo ""
echo "WARNING: These are proprietary firmware blobs from AMD."
echo "WARNING: These firmware blobs are third-party upstream firmware."
echo "They are NOT open source. Verify your license compliance."
+59 -7
View File
@@ -6,11 +6,12 @@
# sources so they're available in recipes/<category>/<pkg>/source/.
#
# Usage:
# ./local/scripts/fetch-sources.sh # All sources
# ./local/scripts/fetch-sources.sh core # Core packages only
# ./local/scripts/fetch-sources.sh libs tools # Multiple categories
# ./local/scripts/fetch-sources.sh --upstream # All sources
# ./local/scripts/fetch-sources.sh --upstream core # Core packages only
# ./local/scripts/fetch-sources.sh --upstream libs tools # Multiple categories
# ./local/scripts/fetch-sources.sh --list # Show available categories
# ./local/scripts/fetch-sources.sh --status # Show fetch progress
# ./local/scripts/fetch-sources.sh --help # Show help
#
# After fetching, sources live at:
# recipes/<category>/<pkg>/source/ (git repos, tar extractions)
@@ -23,6 +24,51 @@ REPO_BIN="$PROJECT_ROOT/target/release/repo"
cd "$PROJECT_ROOT"
ALLOW_UPSTREAM=0
MODE="fetch"
CATEGORIES=()
usage() {
cat <<EOF
Usage: $(basename "$0") [OPTIONS] [CATEGORY ...]
Fetch recipe sources for browsing and editing.
Options:
--upstream Allow Redox/upstream source fetch
--list Show available categories
--status Show fetch progress
-h, --help Show this help
EOF
}
while [ $# -gt 0 ]; do
case "$1" in
--upstream)
ALLOW_UPSTREAM=1
;;
--list)
MODE="list"
;;
--status)
MODE="status"
;;
-h|--help)
usage
exit 0
;;
-*)
echo "Unknown option: $1" >&2
usage >&2
exit 1
;;
*)
CATEGORIES+=("$1")
;;
esac
shift
done
if [ ! -f "$REPO_BIN" ]; then
echo ">>> Building cookbook binary..."
cargo build --release
@@ -52,16 +98,22 @@ show_status() {
echo "Sources fetched: $fetched / $total ($pct%)"
}
if [ "${1:-}" = "--list" ]; then
if [ "$MODE" = "list" ]; then
list_categories
exit 0
fi
if [ "${1:-}" = "--status" ]; then
if [ "$MODE" = "status" ]; then
show_status
exit 0
fi
if [ "$ALLOW_UPSTREAM" -ne 1 ]; then
echo "ERROR: Redox/upstream source fetch is disabled by default." >&2
echo "Re-run with --upstream to fetch sources." >&2
exit 1
fi
echo "========================================"
echo " Redox Source Fetcher"
echo "========================================"
@@ -110,14 +162,14 @@ fetch_category() {
[ "$ok" -eq 0 ] && [ "$skip" -eq 0 ] && [ "$fail" -gt 0 ] && echo "$cat: $fail failed"
}
if [ $# -eq 0 ]; then
if [ ${#CATEGORIES[@]} -eq 0 ]; then
echo ">>> Fetching ALL recipe sources..."
echo ""
for cat in $ALL_CATEGORIES; do
fetch_category "$cat"
done
else
for cat in "$@"; do
for cat in "${CATEGORIES[@]}"; do
if [ -d "recipes/$cat" ]; then
echo ">>> Fetching category: $cat"
fetch_category "$cat"
+8 -3
View File
@@ -24,18 +24,23 @@ UPSTREAM_BRANCH="${UPSTREAM_BRANCH:-master}"
DRY_RUN=0
NO_MERGE=0
usage() {
echo "Usage: $0 [--dry-run] [--no-merge]"
echo " --dry-run Show what would happen without making changes"
echo " --no-merge Only fetch and check patch conflicts"
}
for arg in "$@"; do
case "$arg" in
--dry-run) DRY_RUN=1 ;;
--no-merge) NO_MERGE=1 ;;
--help|-h)
echo "Usage: $0 [--dry-run] [--no-merge]"
echo " --dry-run Show what would happen without making changes"
echo " --no-merge Only fetch and check patch conflicts"
usage
exit 0
;;
*)
echo "Unknown argument: $arg"
usage >&2
exit 1
;;
esac
+2 -40
View File
@@ -1,43 +1,5 @@
#!/usr/bin/env bash
# Test AMD GPU driver on Red Bear OS
# Run this inside Red Bear OS (or via QEMU serial console)
set -euo pipefail
echo "=== AMD GPU Driver Test ==="
echo ""
# Check if scheme:drm exists
if [ -e "/scheme/drm" ]; then
echo "✅ scheme:drm registered"
else
echo "❌ scheme:drm NOT found — redox-drm daemon not running?"
exit 1
fi
# Check card0
if [ -e "/scheme/drm/card0" ]; then
echo "✅ /scheme/drm/card0 exists"
else
echo "❌ /scheme/drm/card0 NOT found — AMD GPU not detected?"
exit 1
fi
# Try to read connector info
echo ""
echo "=== Connector Info ==="
if command -v modetest &>/dev/null; then
modetest -M amd 2>&1 | head -50
else
echo "modetest not available — reading raw scheme"
# Read from scheme directly
cat /scheme/drm/card0 2>&1 | head -20 || true
fi
echo ""
echo "=== PCI Devices (GPU) ==="
ls /scheme/pci/ 2>/dev/null | while read -r entry; do
echo " $entry"
done
echo ""
echo "=== Test Complete ==="
script_dir="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
exec "${script_dir}/test-drm-display-runtime.sh" --vendor amd "$@"
+64
View File
@@ -0,0 +1,64 @@
#!/usr/bin/env bash
set -euo pipefail
vendor=""
card_path="/scheme/drm/card0"
modeset_spec=""
usage() {
cat <<'USAGE'
Usage: test-drm-display-runtime.sh --vendor amd|intel [--card /scheme/drm/card0] [--modeset CONNECTOR:MODE]
Bounded DRM/KMS display validation harness.
This proves only display-path evidence:
- scheme:drm registration
- DRM card reachability
- connector/mode enumeration
- optional bounded modeset proof when a specific CONNECTOR:MODE is supplied
This does NOT prove render command submission, fence semantics, or hardware rendering.
USAGE
}
while [[ $# -gt 0 ]]; do
case "$1" in
--vendor)
vendor="${2:-}"
shift 2
;;
--card)
card_path="${2:-}"
shift 2
;;
--modeset)
modeset_spec="${2:-}"
shift 2
;;
--help|-h)
usage
exit 0
;;
*)
echo "ERROR: unknown argument: $1" >&2
usage >&2
exit 1
;;
esac
done
if [[ "$vendor" != "amd" && "$vendor" != "intel" ]]; then
echo "ERROR: --vendor must be amd or intel" >&2
exit 1
fi
echo "=== Red Bear DRM Display Runtime Check ==="
echo "DRM_VENDOR=${vendor}"
echo "DRM_CARD=${card_path}"
command=(redbear-drm-display-check --vendor "$vendor" --card "$card_path")
if [[ -n "$modeset_spec" ]]; then
command+=(--modeset "$modeset_spec")
fi
exec "${command[@]}"
+5
View File
@@ -0,0 +1,5 @@
#!/usr/bin/env bash
set -euo pipefail
script_dir="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
exec "${script_dir}/test-drm-display-runtime.sh" --vendor intel "$@"
@@ -111,6 +111,9 @@ run_guest_checks() {
echo " FAIL /scheme/drm does not exist"
failures=$((failures + 1))
fi
if command -v redbear-drm-display-check >/dev/null 2>&1; then
echo " NOTE redbear-drm-display-check available (run manually for bounded display validation)"
fi
echo
echo "--- health check summary ---"
+7 -6
View File
@@ -1,6 +1,7 @@
#!/usr/bin/env bash
# Launch the Phase 4 Wayland path in QEMU using the repo's Wayland profile.
# Launch the Phase 4 Wayland validation path in QEMU using the repo's Wayland profile.
# This script validates the current bounded software-path Wayland runtime slice.
# It is a bounded validation harness, not the production desktop path.
# It does NOT currently prove a hardware-accelerated desktop path in QEMU.
set -euo pipefail
@@ -36,8 +37,8 @@ Examples:
./local/scripts/test-phase4-wayland-qemu.sh --check
./local/scripts/test-phase4-wayland-qemu.sh -m 4G
Expected runtime path:
orbital -> orbital-wayland -> smallvil -> wayland-session
Expected validation path:
display session -> validation launcher -> compositor -> wayland-session
Important:
the current harness uses '-vga std' and today still surfaces llvmpipe in-guest.
@@ -99,8 +100,9 @@ echo "Suggested in-guest checks:"
echo " redbear-info --json"
echo " netctl status"
echo " redbear-phase4-wayland-check"
echo " smallvil should be the primary compositor path"
echo " the validation compositor should own the bounded runtime path"
echo " qt6-wayland-smoke should leave a success marker via wayland-session"
echo " production desktop direction is redbear-kde -> kwin_wayland"
echo
if [[ "$check_mode" -eq 1 ]]; then
@@ -115,9 +117,8 @@ send "password\r"
expect "Type 'help' for available commands."
send "redbear-phase4-wayland-check\r"
expect "Red Bear OS Phase 4 Wayland Runtime Check"
expect "orbital-wayland"
expect "redbear-validation-session"
expect "wayland-session"
expect "smallvil"
expect "/home/root/.qt6-bootstrap-minimal.ok"
expect "/home/root/.qt6-plugin-minimal.ok"
expect "/home/root/.qt6-wayland-smoke-minimal.ok"
+2 -3
View File
@@ -18,9 +18,8 @@ require_command() {
fi
}
require_command orbital-wayland "orbital-wayland launcher is installed"
require_command redbear-validation-session "validation launcher is installed"
require_command wayland-session "wayland-session launcher is installed"
require_command smallvil "smallvil compositor is installed"
require_command qt6-wayland-smoke "qt6-wayland-smoke is installed"
require_command qt6-bootstrap-check "qt6-bootstrap-check is installed"
require_command qt6-plugin-check "qt6-plugin-check is installed"
@@ -54,7 +53,7 @@ fi
echo
echo "=== Phase 4 launch surface ==="
echo "orbital-wayland, smallvil, and the Qt6 Phase 4 smoke helpers are present on the wayland profile."
echo "The validation launcher and the Qt6 Phase 4 smoke helpers are present on the wayland profile."
echo "Run this script inside the guest, or use redbear-phase4-wayland-check as the canonical validator."
echo
echo "=== Test Complete ==="
+3 -3
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env bash
# Launch or validate the Phase 6 KDE runtime surface in QEMU.
# Launch or validate the Phase 6 primary KWin Wayland runtime surface in QEMU.
set -euo pipefail
@@ -27,7 +27,7 @@ usage() {
cat <<'USAGE'
Usage: test-phase6-kde-qemu.sh [--check] [extra qemu args...]
Boot or validate the Red Bear OS Phase 6 KDE session surface on redbear-kde.
Boot or validate the Red Bear OS primary KWin Wayland session surface on redbear-kde.
USAGE
}
@@ -112,7 +112,7 @@ send "password\r"
expect "Type 'help' for available commands."
send "redbear-phase6-kde-check\r"
expect "Red Bear OS Phase 6 KDE Runtime Check"
expect "orbital-kde"
expect "redbear-kde-session"
expect "kwin_wayland"
expect {
"PHASE6_UPOWER_ENUMERATE=ok" {}
+108
View File
@@ -0,0 +1,108 @@
#!/usr/bin/env python3
import importlib.util
import pathlib
import unittest
SCRIPT_PATH = pathlib.Path(__file__).with_name("extract-linux-quirks.py")
SPEC = importlib.util.spec_from_file_location("extract_linux_quirks", SCRIPT_PATH)
if SPEC is None or SPEC.loader is None:
raise RuntimeError(f"failed to load module spec for {SCRIPT_PATH}")
MODULE = importlib.util.module_from_spec(SPEC)
SPEC.loader.exec_module(MODULE)
class ExtractLinuxQuirksPciTests(unittest.TestCase):
def test_direct_flag_assignment_maps_to_redbear_flag(self):
source = """
static void quirk_no_d3(struct pci_dev *dev)
{
dev->dev_flags |= PCI_DEV_FLAGS_NO_D3;
}
DECLARE_PCI_FIXUP_FINAL(0x1002, 0x67DF, quirk_no_d3);
"""
mapped = MODULE.map_pci_fixups_to_flags(source)
self.assertEqual(mapped[0][1], ["no_d3cold"])
def test_multi_flag_assignment_maps_all_supported_flags(self):
source = """
static void quirk_multi(struct pci_dev *dev)
{
dev->dev_flags |= PCI_DEV_FLAGS_NO_MSI | PCI_DEV_FLAGS_NO_MSIX | PCI_DEV_FLAGS_NO_ASPM;
}
DECLARE_PCI_FIXUP_HEADER(0x8086, 0x1234, quirk_multi);
"""
mapped = MODULE.map_pci_fixups_to_flags(source)
self.assertEqual(mapped[0][1], ["no_aspm", "no_msi", "no_msix"])
def test_helper_call_maps_no_d3cold(self):
source = """
static void quirk_disable_d3cold(struct pci_dev *pdev)
{
pci_d3cold_disable(pdev);
}
DECLARE_PCI_FIXUP_ENABLE(0x1022, 0x1481, quirk_disable_d3cold);
"""
mapped = MODULE.map_pci_fixups_to_flags(source)
self.assertEqual(mapped[0][1], ["no_d3cold"])
def test_unsupported_handler_body_yields_no_flags(self):
source = """
static void quirk_vendor_workaround(struct pci_dev *dev)
{
pci_info(dev, "workaround only\n");
}
DECLARE_PCI_FIXUP_LATE(0x10DE, 0x1C82, quirk_vendor_workaround);
"""
mapped = MODULE.map_pci_fixups_to_flags(source)
self.assertEqual(mapped[0][1], [])
self.assertEqual(MODULE.format_pci_toml(mapped), "")
def test_handler_name_false_positive_regression_is_ignored(self):
source = """
static void quirk_pci_dev_flags_no_msi_name_only(struct pci_dev *dev)
{
pci_info(dev, "name should not drive extraction\n");
}
DECLARE_PCI_FIXUP_FINAL(0x1234, 0x5678, quirk_pci_dev_flags_no_msi_name_only);
"""
mapped = MODULE.map_pci_fixups_to_flags(source)
self.assertEqual(mapped[0][1], [])
def test_class_fixup_carries_class_fields_into_toml_output(self):
source = """
static void quirk_class_based(struct pci_dev *dev)
{
dev->dev_flags |= PCI_DEV_FLAGS_ASSIGN_BARS | PCI_DEV_FLAGS_BROKEN_PM;
}
DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_ANY_ID, PCI_ANY_ID, 0x030000, 0xFFFF00, quirk_class_based);
"""
mapped = MODULE.map_pci_fixups_to_flags(source)
toml_output = MODULE.format_pci_toml(mapped)
self.assertEqual(mapped[0][1], ["disable_bar_sizing", "no_pm"])
self.assertIn("[[pci_quirk]]", toml_output)
self.assertIn("class = 0x030000", toml_output)
self.assertIn("class_mask = 0xFFFF00", toml_output)
self.assertIn('flags = ["disable_bar_sizing", "no_pm"]', toml_output)
if __name__ == "__main__":
unittest.main()