Raspberry Piのリアルタイムカーネル

手作業で作るのはいやなのでClaudeにスクリプト書かせた。いろんなサイトで導入の説明はされてるけど、スクリプトでサクっとできるのはなかったと思う。

## 前提
- Mac
- Docker
- ParallelsにインストールしたUbuntu
- Raspberry Pi 4 か 5　(3はまだできてない)

## 作業フォルダ構成
こんな感じに、Mac上でどこかに適当なフォルダ（ここではPREEMPT_RT）を作って、pi4_64とpi5_64というフォルダを作る。その中のファイルはこの後順を追って作る。rpi_rt_outputは成果物が入るフォルダで勝手に作られる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107818/6f102e83-513c-4f16-8843-b994c1ed1640.png)

## Dockerfile
まずはRaspberry Pi 4用。
```Dockerfile
FROM ubuntu:22.04

# 非対話的インストールのため
ENV DEBIAN_FRONTEND=noninteractive

# 必要なパッケージをインストール
RUN apt-get update && apt-get install -y \
    git \
    bc \
    bison \
    flex \
    libssl-dev \
    make \
    libc6-dev \
    libncurses5-dev \
    crossbuild-essential-arm64 \
    gcc-aarch64-linux-gnu \
    wget \
    xz-utils \
    device-tree-compiler \
    python3 \
    rsync \
    kmod \
    && rm -rf /var/lib/apt/lists/*

# 作業ディレクトリを設定
WORKDIR /build

# クロスコンパイル用の環境変数（64bit ARM用）
ENV ARCH=arm64
ENV CROSS_COMPILE=aarch64-linux-gnu-
ENV KERNEL=kernel8

# Raspberry Pi カーネルソースをクローン（6.12系 - RPi4対応）
RUN git clone --depth=1 --branch rpi-6.12.y https://github.com/raspberrypi/linux

# カーネル設定（6.12系メインラインPREEMPT_RT - RPi4用）
RUN cd linux && \
    echo "Configuring PREEMPT_RT kernel for Raspberry Pi 4 (6.12+)" && \
    make bcm2711_defconfig && \
    echo "Enabling mainline PREEMPT_RT features..." && \
    # エキスパートモードを有効化
    scripts/config --enable CONFIG_EXPERT && \
    # プリエンプションモデルを確実に設定
    scripts/config --disable CONFIG_PREEMPT_NONE && \
    scripts/config --disable CONFIG_PREEMPT_VOLUNTARY && \
    scripts/config --disable CONFIG_PREEMPT && \
    scripts/config --enable CONFIG_PREEMPT_RT && \
    # 基本RT設定
    scripts/config --enable CONFIG_HIGH_RES_TIMERS && \
    scripts/config --set-val CONFIG_HZ 1000 && \
    scripts/config --enable CONFIG_IRQ_FORCED_THREADING && \
    # RPi4では安全なRCU設定も有効化可能
    scripts/config --enable CONFIG_RCU_BOOST && \
    scripts/config --enable CONFIG_NO_HZ_FULL && \
    # 設定を適用
    make olddefconfig && \
    echo "=== RPi4 PREEMPT_RT Configuration Check ===" && \
    if grep -q "CONFIG_PREEMPT_RT=y" .config && ! grep -q "CONFIG_PREEMPT=y" .config; then \
        echo "✓ SUCCESS: PREEMPT_RT is properly configured for RPi4!"; \
    else \
        echo "✗ FAILED: PREEMPT_RT configuration failed!"; \
        grep -E "CONFIG_PREEMPT.*=" .config; \
        exit 1; \
    fi

# ビルドスクリプトをコピー
COPY docker_build.sh /build/
RUN chmod +x /build/docker_build.sh

CMD ["/build/docker_build.sh"]
```

こっちがRaspberry Pi 5用。
```Dockerfile
FROM ubuntu:22.04

# 非対話的インストールのため
ENV DEBIAN_FRONTEND=noninteractive

# 必要なパッケージをインストール
RUN apt-get update && apt-get install -y \
    git \
    bc \
    bison \
    flex \
    libssl-dev \
    make \
    libc6-dev \
    libncurses5-dev \
    crossbuild-essential-arm64 \
    gcc-aarch64-linux-gnu \
    wget \
    xz-utils \
    device-tree-compiler \
    python3 \
    rsync \
    kmod \
    && rm -rf /var/lib/apt/lists/*

# 作業ディレクトリを設定
WORKDIR /build

# クロスコンパイル用の環境変数（64bit ARM用）
ENV ARCH=arm64
ENV CROSS_COMPILE=aarch64-linux-gnu-
ENV KERNEL=kernel_2712

# Raspberry Pi カーネルソースをクローン（6.12系 - RPi5対応）
RUN git clone --depth=1 --branch rpi-6.12.y https://github.com/raspberrypi/linux

# カーネル設定（6.12系メインラインPREEMPT_RT - RPi5用）
RUN cd linux && \
    echo "Configuring PREEMPT_RT kernel for Raspberry Pi 5 (6.12+)" && \
    make bcm2712_defconfig && \
    echo "Enabling mainline PREEMPT_RT features for RPi5..." && \
    # エキスパートモードを有効化
    scripts/config --enable CONFIG_EXPERT && \
    # プリエンプションモデルを確実に設定
    scripts/config --disable CONFIG_PREEMPT_NONE && \
    scripts/config --disable CONFIG_PREEMPT_VOLUNTARY && \
    scripts/config --disable CONFIG_PREEMPT && \
    scripts/config --enable CONFIG_PREEMPT_RT && \
    # 基本RT設定
    scripts/config --enable CONFIG_HIGH_RES_TIMERS && \
    scripts/config --set-val CONFIG_HZ 1000 && \
    scripts/config --enable CONFIG_IRQ_FORCED_THREADING && \
    # RPi5特有の設定
    scripts/config --enable CONFIG_RCU_BOOST && \
    scripts/config --enable CONFIG_NO_HZ_FULL && \
    # 16Kページサイズ対応
    scripts/config --set-val CONFIG_ARM64_PAGE_SHIFT 14 && \
    scripts/config --enable CONFIG_ARM64_16K_PAGES && \
    scripts/config --disable CONFIG_ARM64_4K_PAGES && \
    scripts/config --disable CONFIG_ARM64_64K_PAGES && \
    # 設定を適用
    make olddefconfig && \
    echo "=== RPi5 PREEMPT_RT Configuration Check ===" && \
    if grep -q "CONFIG_PREEMPT_RT=y" .config && ! grep -q "CONFIG_PREEMPT=y" .config; then \
        echo "✓ SUCCESS: PREEMPT_RT is properly configured for RPi5!"; \
        if grep -q "CONFIG_ARM64_16K_PAGES=y" .config; then \
            echo "✓ SUCCESS: 16K pages configured for RPi5!"; \
        else \
            echo "⚠ WARNING: 16K pages not configured!"; \
        fi; \
    else \
        echo "✗ FAILED: PREEMPT_RT configuration failed!"; \
        grep -E "CONFIG_PREEMPT.*=" .config; \
        exit 1; \
    fi

# ビルドスクリプトをコピー
COPY docker_build.sh /build/
RUN chmod +x /build/docker_build.sh

CMD ["/build/docker_build.sh"]
```

## ビルドスクリプト

pi4_64かpi5_64それぞれの作業フォルダの中でこれを```./build_rt_kernel.sh```って実行すればビルドできる。実機でやるより圧倒的に速い。

Raspberry Pi 4用。
```build_rt_kernel.sh
#!/bin/bash

# Raspberry Pi 4 64-bit PREEMPT_RT Kernel Build Script for Docker
# 6.12+ Mainline PREEMPT_RT Version (Raspberry Pi 4 optimized)
# Usage: ./build_rt_kernel.sh

set -e

# 色付きの出力用
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

echo -e "${GREEN}Raspberry Pi 4 64-bit PREEMPT_RT Kernel Builder${NC}"
echo "6.12+ Mainline PREEMPT_RT (RPi4 optimized!)"
echo "============================================="

# 出力ディレクトリを作成
OUTPUT_DIR="$(pwd)/rpi_rt_output"
echo -e "${YELLOW}Cleaning previous build...${NC}"
rm -rf "$OUTPUT_DIR"
mkdir -p "$OUTPUT_DIR"

echo -e "${YELLOW}Output directory: $OUTPUT_DIR${NC}"

# 必要なファイルの確認
if [ ! -f "Dockerfile" ]; then
    echo -e "${RED}Error: Dockerfile not found in current directory${NC}"
    exit 1
fi

if [ ! -f "docker_build.sh" ]; then
    echo -e "${RED}Error: docker_build.sh not found in current directory${NC}"
    exit 1
fi

# Dockerイメージをビルド
echo -e "${YELLOW}Building Docker image for RPi4 6.12+ kernel...${NC}"
docker build -t rpi4-rt-builder-6.12 .

if [ $? -ne 0 ]; then
    echo -e "${RED}Docker image build failed!${NC}"
    exit 1
fi

echo -e "${GREEN}Docker image built successfully!${NC}"

# カーネルをビルド
echo -e "${YELLOW}Starting RPi4 PREEMPT_RT kernel build process...${NC}"
echo "This may take 30-60 minutes..."

docker run --rm \
    -v "$OUTPUT_DIR:/output" \
    rpi4-rt-builder-6.12

if [ $? -ne 0 ]; then
    echo -e "${RED}Kernel build failed!${NC}"
    exit 1
fi

echo -e "${GREEN}RPi4 PREEMPT_RT kernel build completed successfully!${NC}"
echo ""
echo -e "${YELLOW}Installation Instructions for Raspberry Pi 4:${NC}"
echo "1. Mount your RPi4 SD card"
echo "2. Backup current kernel:"
echo "   sudo cp /Volumes/bootfs/kernel8.img /Volumes/bootfs/kernel8.img.backup"
echo "   sudo cp /Volumes/bootfs/config.txt /Volumes/bootfs/config.txt.backup"
echo ""
echo "3. Copy the new files:"
echo "   sudo cp $OUTPUT_DIR/boot/kernel8.img /Volumes/bootfs/"
echo "   sudo cp $OUTPUT_DIR/boot/*.dtb /Volumes/bootfs/"
echo "   sudo cp $OUTPUT_DIR/boot/overlays/*.dtb* /Volumes/bootfs/overlays/"
echo ""
echo "4. Install kernel modules:"
echo "   sudo cp -r $OUTPUT_DIR/modules/lib/modules/* /Volumes/rootfs/lib/modules/"
echo ""
echo "5. Update /boot/config.txt by adding:"
echo "   cat $OUTPUT_DIR/boot/config_snippet.txt"
echo ""
echo "6. Update cmdline.txt with RT optimizations:"
echo "   # Replace PARTUUID with your actual partition UUID"
echo "   sudo cp $OUTPUT_DIR/boot/cmdline_rt.txt /Volumes/bootfs/cmdline.txt"
echo ""
echo "7. Reboot your Raspberry Pi 4"
echo ""
echo -e "${YELLOW}Verification commands (after reboot):${NC}"
echo "   uname -r                    # Should show RT version"
echo "   uname -m                    # Should show 'aarch64'"
echo "   cat /sys/kernel/realtime    # Should show '1'"
echo "   sudo cyclictest -t1 -p 80 -i 1000 -l 10000 -h 100 -m"
echo ""
echo -e "${GREEN}This kernel uses mainline PREEMPT_RT (6.12+)${NC}"
echo -e "${GREEN}Optimized for Raspberry Pi 4 - No RCU issues!${NC}"
echo ""
echo -e "${GREEN}Files are ready in: $OUTPUT_DIR${NC}"
```

Raspberry Pi 5用。
```build_rt_kernel.sh
#!/bin/bash

# Raspberry Pi 5 64-bit PREEMPT_RT Kernel Build Script for Docker
# 6.12+ Mainline PREEMPT_RT Version (Raspberry Pi 5 optimized)
# Usage: ./build_rt_kernel.sh

set -e

# 色付きの出力用
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

echo -e "${GREEN}Raspberry Pi 5 64-bit PREEMPT_RT Kernel Builder${NC}"
echo "6.12+ Mainline PREEMPT_RT (RPi5 optimized with 16K pages!)"
echo "=========================================================="

# 出力ディレクトリを作成
OUTPUT_DIR="$(pwd)/rpi5_rt_output"
echo -e "${YELLOW}Cleaning previous build...${NC}"
rm -rf "$OUTPUT_DIR"
mkdir -p "$OUTPUT_DIR"

echo -e "${YELLOW}Output directory: $OUTPUT_DIR${NC}"

# 必要なファイルの確認
if [ ! -f "Dockerfile" ]; then
    echo -e "${RED}Error: Dockerfile not found in current directory${NC}"
    exit 1
fi

if [ ! -f "docker_build.sh" ]; then
    echo -e "${RED}Error: docker_build.sh not found in current directory${NC}"
    exit 1
fi

# Dockerイメージをビルド
echo -e "${YELLOW}Building Docker image for RPi5 6.12+ kernel...${NC}"
docker build -t rpi5-rt-builder-6.12 .

if [ $? -ne 0 ]; then
    echo -e "${RED}Docker image build failed!${NC}"
    exit 1
fi

echo -e "${GREEN}Docker image built successfully!${NC}"

# カーネルをビルド
echo -e "${YELLOW}Starting RPi5 PREEMPT_RT kernel build process...${NC}"
echo "This may take 30-60 minutes..."

docker run --rm \
    -v "$OUTPUT_DIR:/output" \
    rpi5-rt-builder-6.12

if [ $? -ne 0 ]; then
    echo -e "${RED}Kernel build failed!${NC}"
    exit 1
fi

echo -e "${GREEN}RPi5 PREEMPT_RT kernel build completed successfully!${NC}"
echo ""
echo -e "${YELLOW}Installation Instructions for Raspberry Pi 5:${NC}"
echo "1. Mount your RPi5 SD card"
echo "2. Backup current kernel:"
echo "   sudo cp /Volumes/bootfs/kernel_2712.img /Volumes/bootfs/kernel_2712.img.backup"
echo "   sudo cp /Volumes/bootfs/config.txt /Volumes/bootfs/config.txt.backup"
echo ""
echo "3. Copy the new files:"
echo "   sudo cp $OUTPUT_DIR/boot/kernel_2712.img /Volumes/bootfs/"
echo "   sudo cp $OUTPUT_DIR/boot/*.dtb /Volumes/bootfs/"
echo "   sudo cp $OUTPUT_DIR/boot/overlays/*.dtb* /Volumes/bootfs/overlays/"
echo ""
echo "4. Install kernel modules:"
echo "   sudo cp -r $OUTPUT_DIR/modules/lib/modules/* /Volumes/rootfs/lib/modules/"
echo ""
echo "5. Update /boot/config.txt by adding:"
echo "   cat $OUTPUT_DIR/boot/config_snippet.txt"
echo ""
echo "6. Update cmdline.txt with RT optimizations:"
echo "   # Replace PARTUUID with your actual partition UUID"
echo "   sudo cp $OUTPUT_DIR/boot/cmdline_rt.txt /Volumes/bootfs/cmdline.txt"
echo ""
echo "7. Reboot your Raspberry Pi 5"
echo ""
echo -e "${YELLOW}Verification commands (after reboot):${NC}"
echo "   uname -r                    # Should show RT version"
echo "   uname -m                    # Should show 'aarch64'"
echo "   cat /proc/version           # Should show 'PREEMPT_RT'"
echo "   sudo cyclictest -t1 -p 80 -i 1000 -l 10000 -h 100 -m"
echo ""
echo -e "${GREEN}This kernel uses mainline PREEMPT_RT (6.12+)${NC}"
echo -e "${GREEN}Optimized for Raspberry Pi 5 with 16K pages!${NC}"
echo ""
echo -e "${GREEN}Files are ready in: $OUTPUT_DIR${NC}"
```

## SDカードにインストール

ビルドできたら、Raspberry Piの実機に入ってるSDカードをMacに挿してParallels上で動いているUbuntuにマウントする。作業フォルダ（pi4_64またはpi5_64）に移動して、```sudo install_rt_kernel.sh```だけ。sudo必要なので注意。

インストール用のスクリプト Raspberry Pi 4用。
```install_rt_kernel.sh
#!/bin/bash

# Raspberry Pi 4 PREEMPT_RT Kernel Installation Script
# For 6.12+ Mainline PREEMPT_RT Kernels
# Usage: ./install_rt_kernel.sh

set -e

# 色付きの出力用
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# スクリプトの場所を取得
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

echo -e "${GREEN}Raspberry Pi 4 PREEMPT_RT Kernel Installer${NC}"
echo -e "${BLUE}6.12+ Mainline PREEMPT_RT Version${NC}"
echo "============================================"

# RTカーネルの出力ディレクトリを確認
RT_OUTPUT_DIR="$SCRIPT_DIR/rpi_rt_output"
if [ ! -d "$RT_OUTPUT_DIR" ]; then
    echo -e "${RED}Error: $RT_OUTPUT_DIR not found!${NC}"
    echo "Please run the build script first: ./build_rt_kernel.sh"
    exit 1
fi

# 必要なファイルの存在確認
echo -e "${YELLOW}Checking RT kernel files...${NC}"
REQUIRED_FILES=(
    "boot/kernel8.img"
    "boot/config_snippet.txt"
    "boot/cmdline_rt.txt"
)

MISSING_FILES=()
for file in "${REQUIRED_FILES[@]}"; do
    if [ ! -f "$RT_OUTPUT_DIR/$file" ]; then
        MISSING_FILES+=("$file")
    fi
done

if [ ${#MISSING_FILES[@]} -gt 0 ]; then
    echo -e "${RED}Error: Missing required files:${NC}"
    for file in "${MISSING_FILES[@]}"; do
        echo "  - $file"
    done
    echo "Please rebuild the kernel with: ./build_rt_kernel.sh"
    exit 1
fi

if [ ! -d "$RT_OUTPUT_DIR/modules/lib/modules" ]; then
    echo -e "${RED}Error: kernel modules not found!${NC}"
    exit 1
fi

echo -e "${GREEN}RT kernel files found!${NC}"

# カーネル情報を表示
KERNEL_SIZE=$(stat -c%s "$RT_OUTPUT_DIR/boot/kernel8.img" 2>/dev/null || echo "0")
MODULE_COUNT=$(find "$RT_OUTPUT_DIR/modules/lib/modules" -name "*.ko" 2>/dev/null | wc -l)
KERNEL_VERSION=$(ls "$RT_OUTPUT_DIR/modules/lib/modules/" | head -1)

echo "Kernel size: $(( KERNEL_SIZE / 1024 / 1024 ))MB"
echo "Kernel version: $KERNEL_VERSION"
echo "Module count: $MODULE_COUNT"

# SDカードの自動検出（Parallels/Mac環境対応）
echo ""
echo -e "${YELLOW}Detecting SD card...${NC}"
BOOT_MOUNT=""
ROOT_MOUNT=""

# 環境変数で指定されている場合はそれを使用
if [ -n "$BOOT_MOUNT" ] && [ -n "$ROOT_MOUNT" ]; then
    echo "Using environment variables:"
    echo "  BOOT_MOUNT=$BOOT_MOUNT"
    echo "  ROOT_MOUNT=$ROOT_MOUNT"
elif [ -d "/media/parallels/bootfs" ] && [ -d "/media/parallels/rootfs" ]; then
    # Parallels環境の場合
    BOOT_MOUNT="/media/parallels/bootfs"
    ROOT_MOUNT="/media/parallels/rootfs"
    echo "Parallels environment detected"
else
    # その他の環境での検出
    MOUNT_PATTERNS=("/Volumes/bootfs" "/Volumes/boot" "/media/*/bootfs" "/media/*/boot")
    for pattern in "${MOUNT_PATTERNS[@]}"; do
        for mount_point in $pattern; do
            if [ -d "$mount_point" ]; then
                # bootfsらしいディレクトリの確認
                if [ -f "$mount_point/config.txt" ] || [ -f "$mount_point/kernel8.img" ]; then
                    BOOT_MOUNT="$mount_point"
                    break 2
                fi
            fi
        done
    done

    ROOT_PATTERNS=("/Volumes/rootfs" "/Volumes/root" "/media/*/rootfs" "/media/*/root")
    for pattern in "${ROOT_PATTERNS[@]}"; do
        for mount_point in $pattern; do
            if [ -d "$mount_point" ]; then
                # rootfsらしいディレクトリの確認
                if [ -d "$mount_point/lib/modules" ] || [ -d "$mount_point/home" ]; then
                    ROOT_MOUNT="$mount_point"
                    break 2
                fi
            fi
        done
    done
fi

if [ -z "$BOOT_MOUNT" ] || [ -z "$ROOT_MOUNT" ]; then
    echo -e "${RED}Error: SD card not detected or not mounted!${NC}"
    echo ""
    echo "Please ensure your Raspberry Pi 4 SD card is connected and mounted."
    echo "Current mount points detected:"
    echo "Available mounts:"
    df -h | grep -E "(bootfs|rootfs|boot|root)"
    echo ""
    echo "Expected mount points:"
    echo "  - Boot partition: /media/parallels/bootfs or /Volumes/bootfs"
    echo "  - Root partition: /media/parallels/rootfs or /Volumes/rootfs"
    echo ""
    echo "You can run with manual specification:"
    echo "  BOOT_MOUNT=/your/boot/path ROOT_MOUNT=/your/root/path $0"
    exit 1
fi

echo -e "${GREEN}SD card detected:${NC}"
echo "  Boot partition: $BOOT_MOUNT"
echo "  Root partition: $ROOT_MOUNT"

# Raspberry Pi OS の確認
if [ ! -f "$BOOT_MOUNT/config.txt" ]; then
    echo -e "${RED}Error: This doesn't appear to be a Raspberry Pi OS SD card${NC}"
    echo "Missing config.txt file"
    exit 1
fi

# アーキテクチャの確認（64-bit推奨）
if grep -q "arm_64bit=1" "$BOOT_MOUNT/config.txt" 2>/dev/null || [ -f "$BOOT_MOUNT/kernel8.img" ]; then
    echo -e "${GREEN}64-bit Raspberry Pi OS detected${NC}"
else
    echo -e "${YELLOW}Warning: May not be 64-bit Raspberry Pi OS${NC}"
    echo "This RT kernel is optimized for 64-bit RPi4"
fi

# 確認プロンプト
echo ""
echo -e "${YELLOW}This script will install PREEMPT_RT kernel for Raspberry Pi 4:${NC}"
echo "1. Backup current kernel and configuration files"
echo "2. Install RT kernel (kernel8.img)"
echo "3. Copy device tree files and kernel modules"
echo "4. Update config.txt for RT kernel with optimizations"
echo "5. Create RT-optimized cmdline.txt template"
echo ""
echo -e "${RED}Warning: This will replace your current kernel!${NC}"
echo "Make sure you have backups and can access the SD card if issues occur."
echo ""
read -p "Continue with installation? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
    echo "Installation cancelled."
    exit 1
fi

# バックアップの作成
echo ""
echo -e "${YELLOW}Creating backups...${NC}"
BACKUP_DIR="$BOOT_MOUNT/backup_rt_$(date +%Y%m%d_%H%M%S)"
mkdir -p "$BACKUP_DIR"

# 元のカーネルファイルをバックアップ
if [ -f "$BOOT_MOUNT/kernel8.img" ]; then
    cp "$BOOT_MOUNT/kernel8.img" "$BACKUP_DIR/"
    echo "Backed up kernel8.img"
fi

if [ -f "$BOOT_MOUNT/config.txt" ]; then
    cp "$BOOT_MOUNT/config.txt" "$BACKUP_DIR/"
    echo "Backed up config.txt"
fi

if [ -f "$BOOT_MOUNT/cmdline.txt" ]; then
    cp "$BOOT_MOUNT/cmdline.txt" "$BACKUP_DIR/"
    echo "Backed up cmdline.txt"
fi

echo -e "${GREEN}Backups created in: $BACKUP_DIR${NC}"

# RTカーネルのインストール
echo ""
echo -e "${YELLOW}Installing RT kernel...${NC}"
cp "$RT_OUTPUT_DIR/boot/kernel8.img" "$BOOT_MOUNT/"
echo "RT kernel installed ($(ls -lh "$BOOT_MOUNT/kernel8.img" | awk '{print $5}'))"

# デバイスツリーファイルのコピー
echo -e "${YELLOW}Installing device tree files...${NC}"
cp "$RT_OUTPUT_DIR/boot/"*.dtb "$BOOT_MOUNT/" 2>/dev/null || echo "No DTB files to copy"
cp "$RT_OUTPUT_DIR/boot/overlays/"*.dtb* "$BOOT_MOUNT/overlays/" 2>/dev/null || echo "No overlay files to copy"
echo "Device tree files installed"

# カーネルモジュールのインストール
echo -e "${YELLOW}Installing kernel modules...${NC}"
cp -r "$RT_OUTPUT_DIR/modules/lib/modules/"* "$ROOT_MOUNT/lib/modules/"
echo "Kernel modules installed"

# config.txtの更新
echo -e "${YELLOW}Updating config.txt...${NC}"
cat "$RT_OUTPUT_DIR/boot/config_snippet.txt" >> "$BOOT_MOUNT/config.txt"
echo "config.txt updated for RT kernel"

# cmdline.txtテンプレートの作成
echo -e "${YELLOW}Creating RT cmdline.txt template...${NC}"
# 元のPARTUUIDを保持
ORIGINAL_PARTUUID=$(grep -o 'root=PARTUUID=[^ ]*' "$BACKUP_DIR/cmdline.txt" 2>/dev/null || echo 'root=PARTUUID=YOUR_PARTUUID')

sed "s/root=PARTUUID=PLACEHOLDER/$ORIGINAL_PARTUUID/" "$RT_OUTPUT_DIR/boot/cmdline_rt.txt" > "$BOOT_MOUNT/cmdline_rt_template.txt"
echo "RT cmdline template created: cmdline_rt_template.txt"
echo "Review and replace cmdline.txt if you want RT optimizations"

# 同期と完了メッセージ
echo -e "${YELLOW}Syncing files...${NC}"
sync

echo ""
echo -e "${GREEN}Installation completed successfully for Raspberry Pi 4!${NC}"
echo ""
echo -e "${BLUE}Installation Summary:${NC}"
echo "- RT kernel: $(ls -lh "$BOOT_MOUNT/kernel8.img" | awk '{print $5}')"
echo "- Modules: $(ls "$ROOT_MOUNT/lib/modules/" | grep -E '^6\.' | tail -1)"
echo "- Backup: $BACKUP_DIR"
echo ""
echo -e "${YELLOW}Next steps:${NC}"
echo "1. Safely eject the SD card"
echo "2. Insert into Raspberry Pi 4 and boot"
echo "3. After boot, verify RT kernel with:"
echo "   uname -r"
echo "   cat /sys/kernel/realtime"
echo "   sudo cyclictest -t1 -p 80 -i 1000 -l 1000"
echo ""
echo -e "${YELLOW}Optional RT optimizations:${NC}"
echo "Replace /boot/cmdline.txt with /boot/cmdline_rt_template.txt for:"
echo "- CPU isolation (cores 1,2,3 for RT tasks)"
echo "- IRQ affinity (core 0 for interrupts)"
echo "- Tickless operation on isolated cores"
echo ""
echo -e "${YELLOW}If boot fails, restore from backup:${NC}"
echo "   cp $BACKUP_DIR/kernel8.img $BOOT_MOUNT/"
echo "   cp $BACKUP_DIR/config.txt $BOOT_MOUNT/"
echo ""
echo -e "${GREEN}Happy real-time computing on Raspberry Pi 4!${NC}"
```

Raspberry Pi 5用。
```install_rt_kernel.sh
#!/bin/bash

# Raspberry Pi 5 PREEMPT_RT Kernel Installation Script
# For 6.12+ Mainline PREEMPT_RT Kernels
# Usage: ./install_rt_kernel.sh

set -e

# 色付きの出力用
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# スクリプトの場所を取得
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

echo -e "${GREEN}Raspberry Pi 5 PREEMPT_RT Kernel Installer${NC}"
echo -e "${BLUE}6.12+ Mainline PREEMPT_RT Version${NC}"
echo "============================================"

# RTカーネルの出力ディレクトリを確認
RT_OUTPUT_DIR="$SCRIPT_DIR/rpi5_rt_output"
if [ ! -d "$RT_OUTPUT_DIR" ]; then
    echo -e "${RED}Error: $RT_OUTPUT_DIR not found!${NC}"
    echo "Please run the build script first: ./build_rt_kernel.sh"
    exit 1
fi

# 必要なファイルの存在確認
echo -e "${YELLOW}Checking RT kernel files...${NC}"
REQUIRED_FILES=(
    "boot/kernel_2712.img"
    "boot/config_snippet.txt"
    "boot/cmdline_rt.txt"
)

MISSING_FILES=()
for file in "${REQUIRED_FILES[@]}"; do
    if [ ! -f "$RT_OUTPUT_DIR/$file" ]; then
        MISSING_FILES+=("$file")
    fi
done

if [ ${#MISSING_FILES[@]} -gt 0 ]; then
    echo -e "${RED}Error: Missing required files:${NC}"
    for file in "${MISSING_FILES[@]}"; do
        echo "  - $file"
    done
    echo "Please rebuild the kernel with: ./build_rt_kernel.sh"
    exit 1
fi

if [ ! -d "$RT_OUTPUT_DIR/modules/lib/modules" ]; then
    echo -e "${RED}Error: kernel modules not found!${NC}"
    exit 1
fi

echo -e "${GREEN}RT kernel files found!${NC}"

# カーネル情報を表示
KERNEL_SIZE=$(stat -c%s "$RT_OUTPUT_DIR/boot/kernel_2712.img" 2>/dev/null || echo "0")
MODULE_COUNT=$(find "$RT_OUTPUT_DIR/modules/lib/modules" -name "*.ko" 2>/dev/null | wc -l)
KERNEL_VERSION=$(ls "$RT_OUTPUT_DIR/modules/lib/modules/" | head -1)

echo "Kernel size: $(( KERNEL_SIZE / 1024 / 1024 ))MB"
echo "Kernel version: $KERNEL_VERSION"
echo "Module count: $MODULE_COUNT"

# SDカードの自動検出（Parallels/Mac環境対応）
echo ""
echo -e "${YELLOW}Detecting SD card...${NC}"
BOOT_MOUNT=""
ROOT_MOUNT=""

# 環境変数で指定されている場合はそれを使用
if [ -n "$BOOT_MOUNT" ] && [ -n "$ROOT_MOUNT" ]; then
    echo "Using environment variables:"
    echo "  BOOT_MOUNT=$BOOT_MOUNT"
    echo "  ROOT_MOUNT=$ROOT_MOUNT"
elif [ -d "/media/parallels/bootfs" ] && [ -d "/media/parallels/rootfs" ]; then
    # Parallels環境の場合
    BOOT_MOUNT="/media/parallels/bootfs"
    ROOT_MOUNT="/media/parallels/rootfs"
    echo "Parallels environment detected"
else
    # その他の環境での検出
    MOUNT_PATTERNS=("/Volumes/bootfs" "/Volumes/boot" "/media/*/bootfs" "/media/*/boot")
    for pattern in "${MOUNT_PATTERNS[@]}"; do
        for mount_point in $pattern; do
            if [ -d "$mount_point" ]; then
                # bootfsらしいディレクトリの確認
                if [ -f "$mount_point/config.txt" ] || [ -f "$mount_point/kernel_2712.img" ]; then
                    BOOT_MOUNT="$mount_point"
                    break 2
                fi
            fi
        done
    done

    ROOT_PATTERNS=("/Volumes/rootfs" "/Volumes/root" "/media/*/rootfs" "/media/*/root")
    for pattern in "${ROOT_PATTERNS[@]}"; do
        for mount_point in $pattern; do
            if [ -d "$mount_point" ]; then
                # rootfsらしいディレクトリの確認
                if [ -d "$mount_point/lib/modules" ] || [ -d "$mount_point/home" ]; then
                    ROOT_MOUNT="$mount_point"
                    break 2
                fi
            fi
        done
    done
fi

if [ -z "$BOOT_MOUNT" ] || [ -z "$ROOT_MOUNT" ]; then
    echo -e "${RED}Error: SD card not detected or not mounted!${NC}"
    echo ""
    echo "Please ensure your Raspberry Pi 5 SD card is connected and mounted."
    echo "Current mount points detected:"
    echo "Available mounts:"
    df -h | grep -E "(bootfs|rootfs|boot|root)"
    echo ""
    echo "Expected mount points:"
    echo "  - Boot partition: /media/parallels/bootfs or /Volumes/bootfs"
    echo "  - Root partition: /media/parallels/rootfs or /Volumes/rootfs"
    echo ""
    echo "You can run with manual specification:"
    echo "  BOOT_MOUNT=/your/boot/path ROOT_MOUNT=/your/root/path $0"
    exit 1
fi

echo -e "${GREEN}SD card detected:${NC}"
echo "  Boot partition: $BOOT_MOUNT"
echo "  Root partition: $ROOT_MOUNT"

# Raspberry Pi OS の確認
if [ ! -f "$BOOT_MOUNT/config.txt" ]; then
    echo -e "${RED}Error: This doesn't appear to be a Raspberry Pi OS SD card${NC}"
    echo "Missing config.txt file"
    exit 1
fi

# アーキテクチャの確認（64-bit推奨）
if grep -q "arm_64bit=1" "$BOOT_MOUNT/config.txt" 2>/dev/null || [ -f "$BOOT_MOUNT/kernel_2712.img" ]; then
    echo -e "${GREEN}64-bit Raspberry Pi OS detected${NC}"
else
    echo -e "${YELLOW}Warning: May not be 64-bit Raspberry Pi OS${NC}"
    echo "This RT kernel is optimized for 64-bit RPi5"
fi

# 確認プロンプト
echo ""
echo -e "${YELLOW}This script will install PREEMPT_RT kernel for Raspberry Pi 5:${NC}"
echo "1. Backup current kernel and configuration files"
echo "2. Install RT kernel (kernel_2712.img)"
echo "3. Copy device tree files and kernel modules"
echo "4. Update config.txt for RT kernel with optimizations"
echo "5. Create RT-optimized cmdline.txt template"
echo ""
echo -e "${RED}Warning: This will replace your current kernel!${NC}"
echo "Make sure you have backups and can access the SD card if issues occur."
echo ""
read -p "Continue with installation? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
    echo "Installation cancelled."
    exit 1
fi

# バックアップの作成
echo ""
echo -e "${YELLOW}Creating backups...${NC}"
BACKUP_DIR="$BOOT_MOUNT/backup_rt_$(date +%Y%m%d_%H%M%S)"
mkdir -p "$BACKUP_DIR"

# 元のカーネルファイルをバックアップ
if [ -f "$BOOT_MOUNT/kernel_2712.img" ]; then
    cp "$BOOT_MOUNT/kernel_2712.img" "$BACKUP_DIR/"
    echo "Backed up kernel_2712.img"
fi

if [ -f "$BOOT_MOUNT/config.txt" ]; then
    cp "$BOOT_MOUNT/config.txt" "$BACKUP_DIR/"
    echo "Backed up config.txt"
fi

if [ -f "$BOOT_MOUNT/cmdline.txt" ]; then
    cp "$BOOT_MOUNT/cmdline.txt" "$BACKUP_DIR/"
    echo "Backed up cmdline.txt"
fi

echo -e "${GREEN}Backups created in: $BACKUP_DIR${NC}"

# RTカーネルのインストール
echo ""
echo -e "${YELLOW}Installing RT kernel...${NC}"
cp "$RT_OUTPUT_DIR/boot/kernel_2712.img" "$BOOT_MOUNT/"
echo "RT kernel installed ($(ls -lh "$BOOT_MOUNT/kernel_2712.img" | awk '{print $5}'))"

# デバイスツリーファイルのコピー
echo -e "${YELLOW}Installing device tree files...${NC}"
cp "$RT_OUTPUT_DIR/boot/"*.dtb "$BOOT_MOUNT/" 2>/dev/null || echo "No DTB files to copy"
if [ -d "$RT_OUTPUT_DIR/boot/overlays" ] && [ -d "$BOOT_MOUNT/overlays" ]; then
    cp "$RT_OUTPUT_DIR/boot/overlays/"*.dtb* "$BOOT_MOUNT/overlays/" 2>/dev/null || echo "No overlay files to copy"
fi
echo "Device tree files installed"

# カーネルモジュールのインストール
echo -e "${YELLOW}Installing kernel modules...${NC}"
cp -r "$RT_OUTPUT_DIR/modules/lib/modules/"* "$ROOT_MOUNT/lib/modules/"
echo "Kernel modules installed"

# config.txtの更新
echo -e "${YELLOW}Updating config.txt...${NC}"
cat "$RT_OUTPUT_DIR/boot/config_snippet.txt" >> "$BOOT_MOUNT/config.txt"
echo "config.txt updated for RT kernel"

# cmdline.txtテンプレートの作成
echo -e "${YELLOW}Creating RT cmdline.txt template...${NC}"
# 元のPARTUUIDを保持
ORIGINAL_PARTUUID=$(grep -o 'root=PARTUUID=[^ ]*' "$BACKUP_DIR/cmdline.txt" 2>/dev/null || echo 'root=PARTUUID=YOUR_PARTUUID')

sed "s/root=PARTUUID=PLACEHOLDER/$ORIGINAL_PARTUUID/" "$RT_OUTPUT_DIR/boot/cmdline_rt.txt" > "$BOOT_MOUNT/cmdline_rt_template.txt"
echo "RT cmdline template created: cmdline_rt_template.txt"
echo "Review and replace cmdline.txt if you want RT optimizations"

# 同期と完了メッセージ
echo -e "${YELLOW}Syncing files...${NC}"
sync

echo ""
echo -e "${GREEN}Installation completed successfully for Raspberry Pi 5!${NC}"
echo ""
echo -e "${BLUE}Installation Summary:${NC}"
echo "- RT kernel: $(ls -lh "$BOOT_MOUNT/kernel_2712.img" | awk '{print $5}')"
echo "- Modules: $(ls "$ROOT_MOUNT/lib/modules/" | grep -E '^6\.' | tail -1)"
echo "- Backup: $BACKUP_DIR"
echo ""
echo -e "${YELLOW}Next steps:${NC}"
echo "1. Safely eject the SD card"
echo "2. Insert into Raspberry Pi 5 and boot"
echo "3. After boot, verify RT kernel with:"
echo "   uname -r"
echo "   cat /sys/kernel/realtime"
echo "   sudo cyclictest -t1 -p 80 -i 1000 -l 1000"
echo ""
echo -e "${YELLOW}Optional RT optimizations:${NC}"
echo "Replace /boot/cmdline.txt with /boot/cmdline_rt_template.txt for:"
echo "- CPU isolation (cores 1,2,3 for RT tasks)"
echo "- IRQ affinity (core 0 for interrupts)"
echo "- Tickless operation on isolated cores"
echo ""
echo -e "${YELLOW}If boot fails, restore from backup:${NC}"
echo "   cp $BACKUP_DIR/kernel_2712.img $BOOT_MOUNT/"
echo "   cp $BACKUP_DIR/config.txt $BOOT_MOUNT/"
echo ""
echo -e "${GREEN}Happy real-time computing on Raspberry Pi 5!${NC}"
```

```shell
sudo ./install_rt_kernel.sh
```
たったのこれだけ。ヤバくない？途中で実行していいか聞かれるのでyを押して、しばらく待つとインストールが終わる。バックアップも作ってくれるのでもし動かなかったらファイルを戻せばok。

## 確認
SDカードをMacから抜いてRaspberry Piに挿して起動して、```uname -a```で確認。PREEMPT_RTの表記があれば成功。
```
uname -a
Linux ifw01 6.12.30-v8-16k+ #1 SMP PREEMPT_RT Wed Jun 11 00:26:35 UTC 2025 aarch64 GNU/Linux
```