Repository: OSInside/kiwi

Issue:
wrong grub binary path in ppc/bootinfo.txt for Fedora ppc64le images
The Fedora KDE Live ISOs are not bootable on a ppc64le KVM system. The SLOF firmware reports `failed to load CHRP boot loader` and `E3404: not a bootable device` when booting the ISOs in the KVM VM. I think it is because `ppc/bootinfo.txt` refers to `\boot\grub2\powerpc-ieee1275\grub.elf`, while in Fedora we have `\boot\grub2\powerpc-ieee1275\core.elf` instead.

Hints from issue comments:
@Conan-Kudo: For some extra details:

Test image: https://kojipkgs.fedoraproject.org//packages/Fedora-KDE-Desktop-Live/Rawhide/20250227.n.0/images/Fedora-KDE-Desktop-Live-Rawhide-20250227.n.0.ppc64le.iso

Build log: https://kojipkgs.fedoraproject.org//packages/Fedora-KDE-Desktop-Live/Rawhide/20250227.n.0/data/logs/image/ppc64le/image-root.ppc64le.log

### Build information

* KIWI version: 10.2.11-1.fc43
* Operating system host version: Fedora Linux 43
* Operating system target version: Fedora Linux 43
* Open Build Service version (N/A if not using OBS): N/A
* Koji version (N/A if not using Koji): 1.35.1@schaefi: Hrm, thanks for reporting 👍 

I take a look asap@Conan-Kudo: We probably need to add a fedora ppc64le live image test case to make sure we don't break this...@schaefi: > We probably need to add a fedora ppc64le live image test case to make sure we don't break this...

yes I add one

Solution patch:
diff --git a/helper/build_status.sh b/helper/build_status.sh
index 7ec6cb58..6680bc40 100755
--- a/helper/build_status.sh
+++ b/helper/build_status.sh
@@ -8,6 +8,7 @@ for project in \
     Virtualization:Appliances:SelfContained:universal \
     Virtualization:Appliances:Images:Testing_x86:tumbleweed \
     Virtualization:Appliances:Images:Testing_x86:rawhide \
+    Virtualization:Appliances:Images:Testing_ppc:rawhide \
     Virtualization:Appliances:Images:Testing_x86:leap \
     Virtualization:Appliances:Images:Testing_x86:centos \
     Virtualization:Appliances:Images:Testing_x86:fedora \
diff --git a/kiwi/bootloader/config/grub2.py b/kiwi/bootloader/config/grub2.py
index 621f665f..50de1687 100644
--- a/kiwi/bootloader/config/grub2.py
+++ b/kiwi/bootloader/config/grub2.py
@@ -975,12 +975,15 @@ class BootLoaderConfigGrub2(BootLoaderConfigBase):
             <chrp-boot>
             <description>{os_name}</description>
             <os-name>{os_name}</os-name>
-            <boot-script>boot &device;:1,\\boot\\grub2\\powerpc-ieee1275\\grub.elf</boot-script>
+            <boot-script>boot &device;:1,\\boot\\grub2\\powerpc-ieee1275\\{chrp_loader}</boot-script>
             </chrp-boot>
         ''').strip() + os.linesep
         with open(chrp_bootinfo_file, 'w') as chrp_bootinfo:
             chrp_bootinfo.write(
-                chrp_config.format(os_name=self.get_menu_entry_install_title())
+                chrp_config.format(
+                    os_name=self.get_menu_entry_install_title(),
+                    chrp_loader=Defaults.get_grub_chrp_loader(self.boot_dir)
+                )
             )
 
     def _setup_platform_image(self, mbrid, lookup_path=None):
diff --git a/kiwi/defaults.py b/kiwi/defaults.py
index 71562257..5497a3fe 100644
--- a/kiwi/defaults.py
+++ b/kiwi/defaults.py
@@ -975,6 +975,29 @@ class Defaults:
                 return unsigned_grub_file
         return None
 
+    @staticmethod
+    def get_grub_chrp_loader(boot_path: str) -> str:
+        """
+        Lookup CHRP boot loader (ppc)
+
+        :param string boot_path: boot path
+
+        :return: file base name
+
+        :rtype: str
+        """
+        for chrp_loader in ['grub.elf', 'core.elf']:
+            for grub_chrp in glob.iglob(
+                os.sep.join(
+                    [boot_path, 'boot/grub*/powerpc-ieee1275', chrp_loader]
+                )
+            ):
+                log.info(f'Found CHRP loader at: {grub_chrp}')
+                return os.path.basename(grub_chrp)
+        raise KiwiBootLoaderGrubDataError(
+            f'CHRP loader not found in {boot_path}'
+        )
+
     @staticmethod
     def get_grub_platform_core_loader(root_path):
         """


Test patch:
diff --git a/test/unit/bootloader/config/grub2_test.py b/test/unit/bootloader/config/grub2_test.py
index f605f359..fb65c3f6 100644
--- a/test/unit/bootloader/config/grub2_test.py
+++ b/test/unit/bootloader/config/grub2_test.py
@@ -1749,6 +1749,7 @@ class TestBootLoaderConfigGrub2:
     @patch('kiwi.bootloader.config.base.BootLoaderConfigBase.get_boot_path')
     @patch('kiwi.bootloader.config.grub2.Defaults.get_unsigned_grub_loader')
     @patch('kiwi.bootloader.config.grub2.Defaults.get_grub_platform_core_loader')
+    @patch('kiwi.bootloader.config.grub2.Defaults.get_grub_chrp_loader')
     @patch('kiwi.bootloader.config.grub2.Command.run')
     @patch('kiwi.bootloader.config.grub2.Path.which')
     @patch('kiwi.bootloader.config.grub2.Path.create')
@@ -1758,10 +1759,11 @@ class TestBootLoaderConfigGrub2:
     def test_setup_install_boot_images_ppc(
         self, mock_shutil_copy2, mock_exists, mock_sync,
         mock_Path_create, mock_Path_which, mock_command,
-        mock_get_grub_platform_core_loader, mock_get_unsigned_grub_loader,
-        mock_get_boot_path
+        mock_get_grub_chrp_loader, mock_get_grub_platform_core_loader,
+        mock_get_unsigned_grub_loader, mock_get_boot_path
     ):
         Defaults.set_platform_name('ppc64le')
+        mock_get_grub_chrp_loader.return_value = 'grub.elf'
         mock_get_grub_platform_core_loader.return_value = None
         mock_Path_which.return_value = '/path/to/grub2-mkimage'
         mock_get_boot_path.return_value = '/boot'
diff --git a/test/unit/defaults_test.py b/test/unit/defaults_test.py
index cc21ac1a..3411d5bc 100644
--- a/test/unit/defaults_test.py
+++ b/test/unit/defaults_test.py
@@ -3,7 +3,9 @@ from unittest.mock import patch
 
 import sys
 from unittest.mock import MagicMock
-from pytest import fixture
+from pytest import (
+    fixture, raises
+)
 
 from .test_helper import argv_kiwi_tests
 
@@ -11,6 +13,8 @@ from kiwi.defaults import Defaults
 from kiwi.defaults import grub_loader_type
 from kiwi.defaults import shim_loader_type
 
+from kiwi.exceptions import KiwiBootLoaderGrubDataError
+
 
 class TestDefaults:
     @fixture(autouse=True)
@@ -222,3 +226,18 @@ class TestDefaults:
         assert Defaults.get_min_volume_mbytes('btrfs') == 120
         assert Defaults.get_min_volume_mbytes('xfs') == 300
         assert Defaults.get_min_volume_mbytes('some') == 30
+
+    @patch('glob.iglob')
+    def test_get_grub_chrp_loader(self, mock_glob_iglob):
+        mock_glob_iglob.return_value = []
+        with raises(KiwiBootLoaderGrubDataError):
+            Defaults.get_grub_chrp_loader('some-boot')
+
+        mock_glob_iglob.reset_mock()
+        mock_glob_iglob.return_value = [
+            '/some-boot/boot/grub2/powerpc-ieee1275/grub.elf'
+        ]
+        assert Defaults.get_grub_chrp_loader('some-boot') == 'grub.elf'
+        mock_glob_iglob.assert_called_once_with(
+            'some-boot/boot/grub*/powerpc-ieee1275/grub.elf'
+        )