bootimg-efi.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. # ex:ts=4:sw=4:sts=4:et
  2. # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
  3. #
  4. # Copyright (c) 2014, Intel Corporation.
  5. # All rights reserved.
  6. #
  7. # This program is free software; you can redistribute it and/or modify
  8. # it under the terms of the GNU General Public License version 2 as
  9. # published by the Free Software Foundation.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License along
  17. # with this program; if not, write to the Free Software Foundation, Inc.,
  18. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  19. #
  20. # DESCRIPTION
  21. # This implements the 'bootimg-efi' source plugin class for 'wic'
  22. #
  23. # AUTHORS
  24. # Tom Zanussi <tom.zanussi (at] linux.intel.com>
  25. #
  26. import logging
  27. import os
  28. import shutil
  29. from wic import WicError
  30. from wic.engine import get_custom_config
  31. from wic.pluginbase import SourcePlugin
  32. from wic.misc import (exec_cmd, exec_native_cmd,
  33. get_bitbake_var, BOOTDD_EXTRA_SPACE)
  34. logger = logging.getLogger('wic')
  35. class BootimgEFIPlugin(SourcePlugin):
  36. """
  37. Create EFI boot partition.
  38. This plugin supports GRUB 2 and systemd-boot bootloaders.
  39. """
  40. name = 'bootimg-efi'
  41. @classmethod
  42. def do_configure_grubefi(cls, hdddir, creator, cr_workdir, source_params):
  43. """
  44. Create loader-specific (grub-efi) config
  45. """
  46. configfile = creator.ks.bootloader.configfile
  47. custom_cfg = None
  48. if configfile:
  49. custom_cfg = get_custom_config(configfile)
  50. if custom_cfg:
  51. # Use a custom configuration for grub
  52. grubefi_conf = custom_cfg
  53. logger.debug("Using custom configuration file "
  54. "%s for grub.cfg", configfile)
  55. else:
  56. raise WicError("configfile is specified but failed to "
  57. "get it from %s." % configfile)
  58. initrd = source_params.get('initrd')
  59. if initrd:
  60. bootimg_dir = get_bitbake_var("DEPLOY_DIR_IMAGE")
  61. if not bootimg_dir:
  62. raise WicError("Couldn't find DEPLOY_DIR_IMAGE, exiting")
  63. cp_cmd = "cp %s/%s %s" % (bootimg_dir, initrd, hdddir)
  64. exec_cmd(cp_cmd, True)
  65. else:
  66. logger.debug("Ignoring missing initrd")
  67. if not custom_cfg:
  68. # Create grub configuration using parameters from wks file
  69. bootloader = creator.ks.bootloader
  70. grubefi_conf = ""
  71. grubefi_conf += "serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1\n"
  72. grubefi_conf += "default=boot\n"
  73. grubefi_conf += "timeout=%s\n" % bootloader.timeout
  74. grubefi_conf += "menuentry 'boot'{\n"
  75. kernel = "/bzImage"
  76. grubefi_conf += "linux %s root=%s rootwait %s\n" \
  77. % (kernel, creator.rootdev, bootloader.append)
  78. if initrd:
  79. grubefi_conf += "initrd /%s\n" % initrd
  80. grubefi_conf += "}\n"
  81. logger.debug("Writing grubefi config %s/hdd/boot/EFI/BOOT/grub.cfg",
  82. cr_workdir)
  83. cfg = open("%s/hdd/boot/EFI/BOOT/grub.cfg" % cr_workdir, "w")
  84. cfg.write(grubefi_conf)
  85. cfg.close()
  86. @classmethod
  87. def do_configure_systemdboot(cls, hdddir, creator, cr_workdir, source_params):
  88. """
  89. Create loader-specific systemd-boot/gummiboot config
  90. """
  91. install_cmd = "install -d %s/loader" % hdddir
  92. exec_cmd(install_cmd)
  93. install_cmd = "install -d %s/loader/entries" % hdddir
  94. exec_cmd(install_cmd)
  95. bootloader = creator.ks.bootloader
  96. loader_conf = ""
  97. loader_conf += "default boot\n"
  98. loader_conf += "timeout %d\n" % bootloader.timeout
  99. initrd = source_params.get('initrd')
  100. if initrd:
  101. # obviously we need to have a common common deploy var
  102. bootimg_dir = get_bitbake_var("DEPLOY_DIR_IMAGE")
  103. if not bootimg_dir:
  104. raise WicError("Couldn't find DEPLOY_DIR_IMAGE, exiting")
  105. cp_cmd = "cp %s/%s %s" % (bootimg_dir, initrd, hdddir)
  106. exec_cmd(cp_cmd, True)
  107. else:
  108. logger.debug("Ignoring missing initrd")
  109. logger.debug("Writing systemd-boot config "
  110. "%s/hdd/boot/loader/loader.conf", cr_workdir)
  111. cfg = open("%s/hdd/boot/loader/loader.conf" % cr_workdir, "w")
  112. cfg.write(loader_conf)
  113. cfg.close()
  114. configfile = creator.ks.bootloader.configfile
  115. custom_cfg = None
  116. if configfile:
  117. custom_cfg = get_custom_config(configfile)
  118. if custom_cfg:
  119. # Use a custom configuration for systemd-boot
  120. boot_conf = custom_cfg
  121. logger.debug("Using custom configuration file "
  122. "%s for systemd-boots's boot.conf", configfile)
  123. else:
  124. raise WicError("configfile is specified but failed to "
  125. "get it from %s.", configfile)
  126. if not custom_cfg:
  127. # Create systemd-boot configuration using parameters from wks file
  128. kernel = "/bzImage"
  129. boot_conf = ""
  130. boot_conf += "title boot\n"
  131. boot_conf += "linux %s\n" % kernel
  132. boot_conf += "options LABEL=Boot root=%s %s\n" % \
  133. (creator.rootdev, bootloader.append)
  134. if initrd:
  135. boot_conf += "initrd /%s\n" % initrd
  136. logger.debug("Writing systemd-boot config "
  137. "%s/hdd/boot/loader/entries/boot.conf", cr_workdir)
  138. cfg = open("%s/hdd/boot/loader/entries/boot.conf" % cr_workdir, "w")
  139. cfg.write(boot_conf)
  140. cfg.close()
  141. @classmethod
  142. def do_configure_partition(cls, part, source_params, creator, cr_workdir,
  143. oe_builddir, bootimg_dir, kernel_dir,
  144. native_sysroot):
  145. """
  146. Called before do_prepare_partition(), creates loader-specific config
  147. """
  148. hdddir = "%s/hdd/boot" % cr_workdir
  149. install_cmd = "install -d %s/EFI/BOOT" % hdddir
  150. exec_cmd(install_cmd)
  151. try:
  152. if source_params['loader'] == 'grub-efi':
  153. cls.do_configure_grubefi(hdddir, creator, cr_workdir, source_params)
  154. elif source_params['loader'] == 'systemd-boot':
  155. cls.do_configure_systemdboot(hdddir, creator, cr_workdir, source_params)
  156. else:
  157. raise WicError("unrecognized bootimg-efi loader: %s" % source_params['loader'])
  158. except KeyError:
  159. raise WicError("bootimg-efi requires a loader, none specified")
  160. @classmethod
  161. def do_prepare_partition(cls, part, source_params, creator, cr_workdir,
  162. oe_builddir, bootimg_dir, kernel_dir,
  163. rootfs_dir, native_sysroot):
  164. """
  165. Called to do the actual content population for a partition i.e. it
  166. 'prepares' the partition to be incorporated into the image.
  167. In this case, prepare content for an EFI (grub) boot partition.
  168. """
  169. if not kernel_dir:
  170. kernel_dir = get_bitbake_var("DEPLOY_DIR_IMAGE")
  171. if not kernel_dir:
  172. raise WicError("Couldn't find DEPLOY_DIR_IMAGE, exiting")
  173. staging_kernel_dir = kernel_dir
  174. hdddir = "%s/hdd/boot" % cr_workdir
  175. install_cmd = "install -m 0644 %s/bzImage %s/bzImage" % \
  176. (staging_kernel_dir, hdddir)
  177. exec_cmd(install_cmd)
  178. try:
  179. if source_params['loader'] == 'grub-efi':
  180. shutil.copyfile("%s/hdd/boot/EFI/BOOT/grub.cfg" % cr_workdir,
  181. "%s/grub.cfg" % cr_workdir)
  182. for mod in [x for x in os.listdir(kernel_dir) if x.startswith("grub-efi-")]:
  183. cp_cmd = "cp %s/%s %s/EFI/BOOT/%s" % (kernel_dir, mod, hdddir, mod[9:])
  184. exec_cmd(cp_cmd, True)
  185. shutil.move("%s/grub.cfg" % cr_workdir,
  186. "%s/hdd/boot/EFI/BOOT/grub.cfg" % cr_workdir)
  187. elif source_params['loader'] == 'systemd-boot':
  188. for mod in [x for x in os.listdir(kernel_dir) if x.startswith("systemd-")]:
  189. cp_cmd = "cp %s/%s %s/EFI/BOOT/%s" % (kernel_dir, mod, hdddir, mod[8:])
  190. exec_cmd(cp_cmd, True)
  191. else:
  192. raise WicError("unrecognized bootimg-efi loader: %s" %
  193. source_params['loader'])
  194. except KeyError:
  195. raise WicError("bootimg-efi requires a loader, none specified")
  196. startup = os.path.join(kernel_dir, "startup.nsh")
  197. if os.path.exists(startup):
  198. cp_cmd = "cp %s %s/" % (startup, hdddir)
  199. exec_cmd(cp_cmd, True)
  200. du_cmd = "du -bks %s" % hdddir
  201. out = exec_cmd(du_cmd)
  202. blocks = int(out.split()[0])
  203. extra_blocks = part.get_extra_block_count(blocks)
  204. if extra_blocks < BOOTDD_EXTRA_SPACE:
  205. extra_blocks = BOOTDD_EXTRA_SPACE
  206. blocks += extra_blocks
  207. logger.debug("Added %d extra blocks to %s to get to %d total blocks",
  208. extra_blocks, part.mountpoint, blocks)
  209. # dosfs image, created by mkdosfs
  210. bootimg = "%s/boot.img" % cr_workdir
  211. label = part.label if part.label else "ESP"
  212. dosfs_cmd = "mkdosfs -n %s -i %s -C %s %d" % \
  213. (label, part.fsuuid, bootimg, blocks)
  214. exec_native_cmd(dosfs_cmd, native_sysroot)
  215. mcopy_cmd = "mcopy -i %s -s %s/* ::/" % (bootimg, hdddir)
  216. exec_native_cmd(mcopy_cmd, native_sysroot)
  217. chmod_cmd = "chmod 644 %s" % bootimg
  218. exec_cmd(chmod_cmd)
  219. du_cmd = "du -Lbks %s" % bootimg
  220. out = exec_cmd(du_cmd)
  221. bootimg_size = out.split()[0]
  222. part.size = int(bootimg_size)
  223. part.source_file = bootimg