1#
2# This program is free software; you can redistribute it and/or modify
3# it under the terms of the GNU General Public License version 2 as
4# published by the Free Software Foundation.
5#
6# This program is distributed in the hope that it will be useful,
7# but WITHOUT ANY WARRANTY; without even the implied warranty of
8# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
9# GNU General Public License for more details.
10#
11# You should have received a copy of the GNU General Public License along
12# with this program; if not, write to the Free Software Foundation, Inc.,
13# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
14#
15# DESCRIPTION
16# This implements the 'bootimg-biosplusefi' source plugin class for 'wic'
17#
18# AUTHORS
19# William Bourque <wbourque [at) gmail.com>
20
21import types
22
23from wic.pluginbase import SourcePlugin
24from importlib.machinery import SourceFileLoader
25
26class BootimgBiosPlusEFIPlugin(SourcePlugin):
27    """
28    Create MBR + EFI boot partition
29
30    This plugin creates a boot partition that contains both
31    legacy BIOS and EFI content. It will be able to boot from both.
32    This is useful when managing PC fleet with some older machines
33    without EFI support.
34
35    Note it is possible to create an image that can boot from both
36    legacy BIOS and EFI by defining two partitions : one with arg
37    --source bootimg-efi  and another one with --source bootimg-pcbios.
38    However, this method has the obvious downside that it requires TWO
39    partitions to be created on the storage device.
40    Both partitions will also be marked as "bootable" which does not work on
41    most BIOS, has BIOS often uses the "bootable" flag to determine
42    what to boot. If you have such a BIOS, you need to manually remove the
43    "bootable" flag from the EFI partition for the drive to be bootable.
44    Having two partitions also seems to confuse wic : the content of
45    the first partition will be duplicated into the second, even though it
46    will not be used at all.
47
48    Also, unlike "isoimage-isohybrid" that also does BIOS and EFI, this plugin
49    allows you to have more than only a single rootfs partitions and does
50    not turn the rootfs into an initramfs RAM image.
51
52    This plugin is made to put everything into a single /boot partition so it
53    does not have the limitations listed above.
54
55    The plugin is made so it does tries not to reimplement what's already
56    been done in other plugins; as such it imports "bootimg-pcbios"
57    and "bootimg-efi".
58    Plugin "bootimg-pcbios" is used to generate legacy BIOS boot.
59    Plugin "bootimg-efi" is used to generate the UEFI boot. Note that it
60    requires a --sourceparams argument to know which loader to use; refer
61    to "bootimg-efi" code/documentation for the list of loader.
62
63    Imports are handled with "SourceFileLoader" from importlib as it is
64    otherwise very difficult to import module that has hyphen "-" in their
65    filename.
66    The SourcePlugin() methods used in the plugins (do_install_disk,
67    do_configure_partition, do_prepare_partition) are then called on both,
68    beginning by "bootimg-efi".
69
70    Plugin options, such as "--sourceparams" can still be passed to a
71    plugin, as long they does not cause issue in the other plugin.
72
73    Example wic configuration:
74    part /boot --source bootimg-biosplusefi --sourceparams="loader=grub-efi"\\
75               --ondisk sda --label os_boot --active --align 1024 --use-uuid
76    """
77
78    name = 'bootimg-biosplusefi'
79
80    __PCBIOS_MODULE_NAME = "bootimg-pcbios"
81    __EFI_MODULE_NAME = "bootimg-efi"
82
83    __imgEFIObj = None
84    __imgBiosObj = None
85
86    @classmethod
87    def __init__(cls):
88        """
89        Constructor (init)
90        """
91
92        # XXX
93        # For some reasons, __init__ constructor is never called.
94        # Something to do with how pluginbase works?
95        cls.__instanciateSubClasses()
96
97    @classmethod
98    def __instanciateSubClasses(cls):
99        """
100
101        """
102
103        # Import bootimg-pcbios (class name "BootimgPcbiosPlugin")
104        modulePath = os.path.join(os.path.dirname(os.path.realpath(__file__)),
105                                  cls.__PCBIOS_MODULE_NAME + ".py")
106        loader = SourceFileLoader(cls.__PCBIOS_MODULE_NAME, modulePath)
107        mod = types.ModuleType(loader.name)
108        loader.exec_module(mod)
109        cls.__imgBiosObj = mod.BootimgPcbiosPlugin()
110
111        # Import bootimg-efi (class name "BootimgEFIPlugin")
112        modulePath = os.path.join(os.path.dirname(os.path.realpath(__file__)),
113                                  cls.__EFI_MODULE_NAME + ".py")
114        loader = SourceFileLoader(cls.__EFI_MODULE_NAME, modulePath)
115        mod = types.ModuleType(loader.name)
116        loader.exec_module(mod)
117        cls.__imgEFIObj = mod.BootimgEFIPlugin()
118
119    @classmethod
120    def do_install_disk(cls, disk, disk_name, creator, workdir, oe_builddir,
121                        bootimg_dir, kernel_dir, native_sysroot):
122        """
123        Called after all partitions have been prepared and assembled into a
124        disk image.
125        """
126
127        if ( (not cls.__imgEFIObj) or (not cls.__imgBiosObj) ):
128            cls.__instanciateSubClasses()
129
130        cls.__imgEFIObj.do_install_disk(
131            disk,
132            disk_name,
133            creator,
134            workdir,
135            oe_builddir,
136            bootimg_dir,
137            kernel_dir,
138            native_sysroot)
139
140        cls.__imgBiosObj.do_install_disk(
141            disk,
142            disk_name,
143            creator,
144            workdir,
145            oe_builddir,
146            bootimg_dir,
147            kernel_dir,
148            native_sysroot)
149
150    @classmethod
151    def do_configure_partition(cls, part, source_params, creator, cr_workdir,
152                               oe_builddir, bootimg_dir, kernel_dir,
153                               native_sysroot):
154        """
155        Called before do_prepare_partition()
156        """
157
158        if ( (not cls.__imgEFIObj) or (not cls.__imgBiosObj) ):
159            cls.__instanciateSubClasses()
160
161        cls.__imgEFIObj.do_configure_partition(
162            part,
163            source_params,
164            creator,
165            cr_workdir,
166            oe_builddir,
167            bootimg_dir,
168            kernel_dir,
169            native_sysroot)
170
171        cls.__imgBiosObj.do_configure_partition(
172            part,
173            source_params,
174            creator,
175            cr_workdir,
176            oe_builddir,
177            bootimg_dir,
178            kernel_dir,
179            native_sysroot)
180
181    @classmethod
182    def do_prepare_partition(cls, part, source_params, creator, cr_workdir,
183                             oe_builddir, bootimg_dir, kernel_dir,
184                             rootfs_dir, native_sysroot):
185        """
186        Called to do the actual content population for a partition i.e. it
187        'prepares' the partition to be incorporated into the image.
188        """
189
190        if ( (not cls.__imgEFIObj) or (not cls.__imgBiosObj) ):
191            cls.__instanciateSubClasses()
192
193        cls.__imgEFIObj.do_prepare_partition(
194            part,
195            source_params,
196            creator,
197            cr_workdir,
198            oe_builddir,
199            bootimg_dir,
200            kernel_dir,
201            rootfs_dir,
202            native_sysroot)
203
204        cls.__imgBiosObj.do_prepare_partition(
205            part,
206            source_params,
207            creator,
208            cr_workdir,
209            oe_builddir,
210            bootimg_dir,
211            kernel_dir,
212            rootfs_dir,
213            native_sysroot)
214