diff --git a/.github/workflows/generate-ionstack-config.yml b/.github/workflows/generate-ionstack-config.yml deleted file mode 100644 index 50e6e40..0000000 --- a/.github/workflows/generate-ionstack-config.yml +++ /dev/null @@ -1,318 +0,0 @@ -name: Generate IonStack Config - -on: - workflow_dispatch: - inputs: - rom_url: - description: 'Firmware/ROM download URL (.zip / .tar.gz / payload.bin / boot.img)' - required: true - base_address: - description: 'kimage_text_base (ARM64 kernel base address)' - required: false - default: '0xFFFFFFC008000000' - boot_partition: - description: 'Partition name in payload.bin (boot / init_boot)' - required: false - default: 'boot' - magisk_url: - description: 'Magisk APK URL (empty = latest debug)' - required: false - default: 'https://github.com/topjohnwu/Magisk/releases/latest/download/app-debug.apk' - -jobs: - generate-config: - runs-on: ubuntu-latest - timeout-minutes: 30 - - steps: - # ============================================================ - # Checkout the repo (for gen_ionstack_config.py) - # ============================================================ - - name: Checkout repository - uses: actions/checkout@v4 - - # ============================================================ - # Setup Python - # ============================================================ - - name: Setup Python - uses: actions/setup-python@v5 - with: - python-version: '3.11' - - - name: Install Python dependencies - run: pip install vmlinux-to-elf pyelftools - - - name: Install system tools - run: | - sudo apt-get update -qq - sudo apt-get install -y -qq p7zip-full xxd 2>/dev/null || true - - # ============================================================ - # Get magiskboot (statically linked x86_64, runs natively) - # ============================================================ - - name: Download Magisk and extract magiskboot - run: | - MAGISK_URL="${{ inputs.magisk_url }}" - if [ -z "$MAGISK_URL" ]; then - MAGISK_URL="https://github.com/topjohnwu/Magisk/releases/latest/download/app-debug.apk" - fi - echo "[*] Downloading Magisk from: $MAGISK_URL" - wget -nv -O magisk.apk "$MAGISK_URL" - - echo "[*] Extracting libmagiskboot.so (x86_64)..." - unzip -o -j magisk.apk 'lib/x86_64/libmagiskboot.so' -d . - chmod +x libmagiskboot.so - - # Verify it runs - echo "[*] magiskboot version:" - ./libmagiskboot.so 2>&1 | head -3 - - # Free disk space - rm -f magisk.apk - - # ============================================================ - # Download the ROM / firmware - # ============================================================ - - name: Download ROM - run: | - ROM_URL="${{ inputs.rom_url }}" - echo "[*] Downloading: $ROM_URL" - - wget -nv -O "rom.ext" "$ROM_URL" - ls -lh "rom.ext" - file="./rom.ext" - if [ ! -f "$file" ]; then echo "File not found"; exit 1; fi - - # 2a. 用魔数判断 zip/gzip(file 会把带 META-INF/ 的 OTA zip 误判成 JAR) - MAGIC=$(xxd -l 4 -p "$file") - case "$MAGIC" in - 504b0304) - new_name="${file%.*}.zip" - echo "Detected ZIP, renaming to $new_name" - mv -n "$file" "$new_name" - echo "RENAMED_FILE=$new_name" >> $GITHUB_ENV - exit 0 - ;; - 1f8b*) - new_name="${file%.*}.tar.gz" - echo "Detected GZIP, renaming to $new_name" - mv -n "$file" "$new_name" - echo "RENAMED_FILE=$new_name" >> $GITHUB_ENV - exit 0 - ;; - esac - - # 2b. 不是压缩包,尝试用 magiskboot 检测 payload - if ./libmagiskboot.so extract "$file" >/dev/null 2>&1; then - echo "Valid payload.bin" - mv "$file" payload.bin - echo "RENAMED_FILE=payload.bin" >> $GITHUB_ENV - else - # 用魔数判断是否为直接下载的 boot.img - MAGIC=$(xxd -l 8 -p "$file") - if [ "$MAGIC" = "414e44524f494421" ]; then - echo "Valid boot.img (ANDROID! magic)" - mv "$file" boot.img - echo "RENAMED_FILE=boot.img" >> $GITHUB_ENV - else - echo "[!] Invalid file: not zip/gzip, payload.bin, or boot.img" - exit 1 - fi - fi - - - # ============================================================ - # Extract ROM - # ============================================================ - - name: Extract ROM - run: | - mkdir -p rom_out - - ROM_FILE="${RENAMED_FILE:-$(ls rom.* 2>/dev/null | head -1)}" - if [ -z "$ROM_FILE" ]; then - echo "[!] No ROM file found" - exit 1 - fi - - echo "[*] Extracting: $ROM_FILE ($(du -h "$ROM_FILE" | cut -f1))" - - case "$ROM_FILE" in - *.zip) - echo "[*] Using unzip..." - unzip -o -q "$ROM_FILE" -d rom_out || { - echo "[*] unzip failed, trying 7z..." - 7z x "$ROM_FILE" -orom_out -y || 7zz x "$ROM_FILE" -orom_out -y - } - ;; - *.tar.gz|*.tgz) - tar xzf "$ROM_FILE" -C rom_out - ;; - *) - echo "[*] Not an archive, copying directly..." - cp "$ROM_FILE" rom_out/ - ;; - esac - - echo "[*] ROM contents (first 40 files):" - find rom_out -type f | head -40 - - # Free disk space: delete the original archive - rm -f "$ROM_FILE" - echo "[*] Removed original archive to free space" - - # ============================================================ - # Locate and extract boot.img - # ============================================================ - - name: Extract boot.img - id: bootimg - run: | - BOOT_PART="${{ inputs.boot_partition }}" - - # --- Strategy 1: payload.bin (OTA package) --- - PAYLOAD=$(find rom_out -name 'payload.bin' -type f 2>/dev/null | head -1) - if [ -n "$PAYLOAD" ]; then - echo "[*] Found payload.bin: $PAYLOAD ($(du -h "$PAYLOAD" | cut -f1))" - echo "[*] Extracting '$BOOT_PART' partition with magiskboot..." - ./libmagiskboot.so extract "$PAYLOAD" "$BOOT_PART" boot.img - if [ -f boot.img ] && [ -s boot.img ]; then - echo "[+] boot.img extracted ($(du -h boot.img | cut -f1))" - echo "source=payload.bin" >> "$GITHUB_OUTPUT" - # Free disk: remove payload + rom dir - rm -rf rom_out - exit 0 - fi - echo "[!] magiskboot extract failed for '$BOOT_PART', trying other partitions..." - fi - - # --- Strategy 2: boot.img directly in ROM --- - BOOT_IMG=$(find rom_out -name 'boot.img' -type f 2>/dev/null | head -1) - if [ -n "$BOOT_IMG" ]; then - echo "[*] Found boot.img: $BOOT_IMG ($(du -h "$BOOT_IMG" | cut -f1))" - cp "$BOOT_IMG" boot.img - echo "source=direct" >> "$GITHUB_OUTPUT" - rm -rf rom_out - exit 0 - fi - - # --- Strategy 3: init_boot.img (Android 13+ GKI) --- - BOOT_IMG=$(find rom_out -name 'init_boot.img' -type f 2>/dev/null | head -1) - if [ -n "$BOOT_IMG" ]; then - echo "[*] Found init_boot.img: $BOOT_IMG" - cp "$BOOT_IMG" boot.img - echo "source=init_boot" >> "$GITHUB_OUTPUT" - rm -rf rom_out - exit 0 - fi - - # --- Strategy 4: Downloaded file IS a boot image --- - for f in $(find rom_out -type f 2>/dev/null); do - MAGIC=$(xxd -l 8 -p "$f") - if [ "$MAGIC" = "414e44524f494421" ]; then - echo "[*] Downloaded file IS a boot image (ANDROID! magic)" - cp "$f" boot.img - echo "source=standalone" >> "$GITHUB_OUTPUT" - exit 0 - fi - done - - echo "[!] ERROR: Cannot find payload.bin, boot.img, or init_boot.img" - echo "[!] All files found:" - find . -type f - exit 1 - - # ============================================================ - # Unpack boot.img → extract kernel with magiskboot - # ============================================================ - - name: Unpack boot.img and extract kernel - run: | - mkdir -p boot_unpack - cd boot_unpack - - echo "[*] Unpacking boot.img ($(du -h ../boot.img | cut -f1)) with magiskboot..." - - # magiskboot unpacks and auto-decompresses kernel - ../libmagiskboot.so unpack ../boot.img - - echo "[*] Unpacked contents:" - ls -la - - # magiskboot produces a decompressed 'kernel' file - if [ -f kernel ]; then - echo "[+] Found decompressed kernel ($(du -h kernel | cut -f1))" - file kernel - cp kernel ../kernel.Image - else - # If kernel is not decompressed for some reason - for k in kernel.gz kernel.lz4 kernel.lzma kernel.xz kernel.bz2 kernel.zst; do - if [ -f "$k" ]; then - echo "[*] Decompressing $k..." - ../libmagiskboot.so decompress "$k" ../kernel.Image - break - fi - done - fi - - if [ ! -f ../kernel.Image ]; then - echo "[!] ERROR: Could not extract kernel" - ls -la - exit 1 - fi - - echo "[*] kernel.Image ready:" - ls -lh ../kernel.Image - file ../kernel.Image - - # ============================================================ - # Convert raw kernel Image → ELF with symbols - # ============================================================ - - name: Convert kernel to ELF (vmlinux-to-elf) - run: | - echo "[*] Running vmlinux-to-elf with base ${{ inputs.base_address }}..." - vmlinux-to-elf \ - --base-address "${{ inputs.base_address }}" \ - kernel.Image kernel.elf - - echo "[*] kernel.elf generated:" - ls -lh kernel.elf - - # Sanity check - python3 -c " - from elftools.elf.elffile import ELFFile - with open('kernel.elf', 'rb') as f: - elf = ELFFile(f) - symtab = elf.get_section_by_name('.symtab') - if symtab: - n = symtab.num_symbols() - print(f'[+] ELF OK: {n} symbols') - if n < 1000: - print('[!] WARNING: very few symbols — kernel may be stripped') - else: - print('[!] WARNING: No .symtab in output ELF') - " - - # ============================================================ - # Generate ionstack.conf - # ============================================================ - - name: Generate IonStack config - id: generate - run: | - python3 gen_ionstack_config.py kernel.elf ionstack.conf - echo '==================== Generated Config ====================' - cat ionstack.conf - echo '==========================================================' - - # ============================================================ - # Upload artifacts - # ============================================================ - - name: Upload ionstack.conf - uses: actions/upload-artifact@v4 - with: - name: ionstack-config - path: ionstack.conf - - - name: Upload kernel ELF (debug, 3-day retention) - uses: actions/upload-artifact@v4 - with: - name: kernel-elf-debug - path: kernel.elf - retention-days: 3