Hi all I've been in contact with Darren Hart, who has opened an RFC re: including support for EFI into Yocto. Meanwhile, due to time constraints of my own project, I worked out a patch to enable EFI on IA-based BSPs.
The patch makes it possible to deploy a system image that adds EFI boot feature along with the legacy bios boot mode. Hence it does not replace the legacy booting, which is still available on the built image. This solution appears to me conservative enough test without breaking existing features, and makes the following introduction of an EFI/PCBIOS switch relatively straightforward. To check out the feature, it's sufficient to add the following lines to either your local.conf or layer.conf: # Ensure you build an hddimg IMAGE_FSTYPES += "live" # Enable EFI mode EFI = "1" MACHINE_ESSENTIAL_EXTRA_RDEPENDS += "grub-efi" # Target-specific boot options (e.g. headless mode) GRUB_OPTS = "serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1" GRUB_APPEND = "console=uart8250,io,0x3f8,115200n8 ro" GRUB_TIMEOUT = "10" This will produce a system image containing the EFI Grub bootloader + boot configuration file. Currently, the patch applies to the meta layer and therefore has global visibility. However, I see from yesterday's meeting minutes that meta-intel has been added as a layer itself. Which comes in handy, as we can narrow the scope of the patch to the Intel targets, which are the only supported machines at the moment. Feedbacks are keenly appreciated. I'm still in ramp-up phase with Yocto, so I might be doing incorrect assumptions, or not complying with common practices. - Josef ----------------------------------- >From d04ffad92107572f70c06e5692083f285d767c01 Mon Sep 17 00:00:00 2001 From: Josef Ahmad <josef.ah...@intel.com> Date: Thu, 17 Nov 2011 14:57:20 +0000 Subject: [PATCH] Add UEFI support to Edison Add UEFI GRUB support into bootimg.bbclass Add grub-efi recipe Added UEFI GRUB support for system image generation Add switch for EFI mode + automated boot conf generation Fix typo in grub.bbclass comment header x86_64-efi now supported --- meta/classes/bootimg.bbclass | 24 ++++++ meta/classes/grub.bbclass | 73 ++++++++++++++++++ .../grub-efi/grub-efi-1.99/40_custom | 9 ++ .../grub-efi/grub-efi-1.99/grub-install.in.patch | 20 +++++ meta/recipes-devtools/grub-efi/grub-efi.bb | 79 ++++++++++++++++++++ 5 files changed, 205 insertions(+), 0 deletions(-) create mode 100644 meta/classes/grub.bbclass create mode 100755 meta/recipes-devtools/grub-efi/grub-efi-1.99/40_custom create mode 100644 meta/recipes-devtools/grub-efi/grub-efi-1.99/grub-install.in.patch create mode 100644 meta/recipes-devtools/grub-efi/grub-efi.bb diff --git a/meta/classes/bootimg.bbclass b/meta/classes/bootimg.bbclass index 49ee85e..00c70d4 100644 --- a/meta/classes/bootimg.bbclass +++ b/meta/classes/bootimg.bbclass @@ -45,7 +45,20 @@ BOOTIMG_EXTRA_SPACE ?= "512" SYSLINUXCFG = "${HDDDIR}/syslinux.cfg" SYSLINUXMENU = "${HDDDIR}/menu" +GRUBCFG = "${HDDDIR}/grub.cfg" + inherit syslinux +inherit grub + +def get_grub_imgname(bb, d): + import re + host = bb.data.getVar('HOST_SYS', d, 1) + if re.match('i.86.*-linux', host): + return "bootia32.efi" + if re.match('x86.64.*-linux', host): + return "bootx64.efi" + +GRUB_IMGNAME = "${@get_grub_imgname(bb, d)}" build_boot_bin() { install -d ${HDDDIR} @@ -62,6 +75,12 @@ build_boot_bin() { install -m 444 ${STAGING_LIBDIR}/syslinux/ldlinux.sys ${HDDDIR}/ldlinux.sys + # TODO locate bootloader under /EFI/boot/ as soon as mkdosfs bug is fixed + + if [ -n "${EFI}" ]; then + install -m 444 ${STAGING_LIBDIR}/grub/${GRUB_IMGNAME} ${HDDDIR}/ + fi + # Do a little math, bash style #BLOCKS=`du -s ${HDDDIR} | cut -f 1` BLOCKS=`du -bks ${HDDDIR} | cut -f 1` @@ -118,6 +137,11 @@ build_boot_bin() { python do_bootimg() { bb.build.exec_func('build_syslinux_cfg', d) + + efi = bb.data.getVar('EFI', d, 1) + if efi: + bb.build.exec_func('build_grub_cfg', d) + bb.build.exec_func('build_boot_bin', d) } diff --git a/meta/classes/grub.bbclass b/meta/classes/grub.bbclass new file mode 100644 index 0000000..b461fc5 --- /dev/null +++ b/meta/classes/grub.bbclass @@ -0,0 +1,73 @@ +# grub.bbclass +# (based off syslinux.bbclass Copyright (C) 2004-2006, Advanced Micro Devices, Inc.) + +python build_grub_cfg () { + import sys + + workdir = bb.data.getVar('WORKDIR', d, 1) + if not workdir: + bb.error("WORKDIR not defined, unable to package") + return + + labels = bb.data.getVar('LABELS', d, 1) + if not labels: + bb.debug(1, "LABELS not defined, nothing to do") + return + + if labels == []: + bb.debug(1, "No labels, nothing to do") + return + + cfile = bb.data.getVar('GRUBCFG', d, 1) + if not cfile: + raise bb.build.FuncFailed('Unable to read GRUBCFG') + + bb.mkdirhier(os.path.dirname(cfile)) + + try: + cfgfile = file(cfile, 'w') + except OSError: + raise bb.build.funcFailed('Unable to open %s' % (cfile)) + + cfgfile.write('# Automatically created by OE\n') + + opts = bb.data.getVar('GRUB_OPTS', d, 1) + + if opts: + for opt in opts.split(';'): + cfgfile.write('%s\n' % opt) + + cfgfile.write('default=%s\n' % (labels.split()[0])) + + timeout = bb.data.getVar('GRUB_TIMEOUT', d, 1) + if timeout: + cfgfile.write('timeout=%s\n' % timeout) + else: + cfgfile.write('timeout=50\n') + + for label in labels.split(): + localdata = bb.data.createCopy(d) + + overrides = bb.data.getVar('OVERRIDES', localdata, True) + if not overrides: + raise bb.build.FuncFailed('OVERRIDES not defined') + + bb.data.setVar('OVERRIDES', label + ':' + overrides, localdata) + bb.data.update_data(localdata) + + cfgfile.write('\nmenuentry \'%s\'{\n' % (label)) + cfgfile.write('linux /vmlinuz ') + + append = bb.data.getVar('GRUB_APPEND', localdata, 1) + initrd = bb.data.getVar('INITRD', localdata, 1) + + if append: + cfgfile.write('%s' % (append)) + cfgfile.write('\n') + + if initrd: + cfgfile.write('initrd /initrd') + cfgfile.write('\n}\n') + + cfgfile.close() +} diff --git a/meta/recipes-devtools/grub-efi/grub-efi-1.99/40_custom b/meta/recipes-devtools/grub-efi/grub-efi-1.99/40_custom new file mode 100755 index 0000000..0d80854 --- /dev/null +++ b/meta/recipes-devtools/grub-efi/grub-efi-1.99/40_custom @@ -0,0 +1,9 @@ +#!/bin/sh +exec tail -n +3 $0 +# This file provides an easy way to add custom menu entries. Simply type the +# menu entries you want to add after this comment. Be careful not to change +# the 'exec tail' line above. +menuentry "Linux" { + set root=(hd0,1) + linux /boot/vmlinuz root=__ROOTFS__ rw __VIDEO_MODE__ __VGA_MODE__ quiet +} diff --git a/meta/recipes-devtools/grub-efi/grub-efi-1.99/grub-install.in.patch b/meta/recipes-devtools/grub-efi/grub-efi-1.99/grub-install.in.patch new file mode 100644 index 0000000..326951d --- /dev/null +++ b/meta/recipes-devtools/grub-efi/grub-efi-1.99/grub-install.in.patch @@ -0,0 +1,20 @@ +Upstream-Status: Inappropriate [embedded specific] + +Our use of grub-install doesn't require the -x option, so we should be +be able make use of grep versions that don't support it. + +Signed-off-by: Tom Zanussi <tom.zanu...@intel.com> + +Index: grub-1.99/util/grub-install.in +=================================================================== +--- grub-1.99.orig/util/grub-install.in 2011-09-09 22:37:20.093906679 -0500 ++++ grub-1.99/util/grub-install.in 2011-09-09 22:37:30.854737882 -0500 +@@ -510,7 +510,7 @@ + + if [ "x${devabstraction_module}" = "x" ] ; then + if [ x"${install_device}" != x ]; then +- if echo "${install_device}" | grep -qx "(.*)" ; then ++ if echo "${install_device}" | grep -q "(.*)" ; then + install_drive="${install_device}" + else + install_drive="`"$grub_probe" --device-map="${device_map}" --target=drive --device "${install_device}"`" || exit 1 diff --git a/meta/recipes-devtools/grub-efi/grub-efi.bbb/meta/recipes-devtools/grub-efi/ grub-efi.bb new file mode 100644 index 0000000..1310c75 --- /dev/null +++ b/meta/recipes-devtools/grub-efi/grub-efi.bb @@ -0,0 +1,79 @@ +SUMMARY = "GRUB2 is the next-generation GRand Unified Bootloader" + +DESCRIPTION = "GRUB2 is the next generaion of a GPLed bootloader \ +intended to unify bootloading across x86 operating systems. In \ +addition to loading the Linux kernel, it implements the Multiboot \ +standard, which allows for flexible loading of multiple boot images." + +HOMEPAGE = "http://www.gnu.org/software/grub/" +SECTION = "bootloaders" +PRIORITY = "optional" + +LICENSE = "GPLv3" +LIC_FILES_CHKSUM = "file://COPYING;md5=d32239bcb673463ab874e80d47fae504" + +RDEPENDS_${PN} = "diffutils freetype" +PR = "r1" +PN = "grub-efi" +PV = "1.99" + + +SRC_URI = "ftp://ftp.gnu.org/gnu/grub/grub-${PV}.tar.gz \ + file://grub-install.in.patch;apply=yes \ + file://40_custom" + +inherit autotools +inherit gettext + +def set_grub_imgfmt(bb, d): + import re + host = bb.data.getVar('HOST_SYS', d, 1) + if re.match('i.86.*-linux', host): + return "i386" + if re.match('x86.64.*-linux', host): + return "x86_64" + +GRUB_IMGFMT = "${@set_grub_imgfmt(bb, d)}" + +EXTRA_OECONF = "--target=${GRUB_IMGFMT} --with-platform=efi --enable-grub-mkfont=no \ + --disable-nls --enable-efiemu=no --program-prefix=""" + +do_update_unpack_loc () { + rm -rf grub-efi-1.99 + mv grub-1.99 grub-efi-1.99 +} + +do_unpack_append () { + bb.build.exec_func('do_update_unpack_loc', d) +} + +do_configure() { + oe_runconf +} + +python __anonymous () { + import re + host = bb.data.getVar('HOST_SYS', d, 1) + if not re.match('x86.64.*-linux', host) and not re.match('i.86.*-linux', host): + raise bb.parse.SkipPackage("incompatible with host %s" % host) +} + +do_install_append () { + install -m 0755 ${WORKDIR}/40_custom ${D}${sysconfdir}/grub.d/40_custom + + if [ "${GRUB_IMGFMT}" = "i386" ] + then GRUB_EFIARCH="ia32" + else GRUB_EFIARCH="x64" + fi + + ./grub-mkimage -p / -d ./grub-core/ -O ${GRUB_IMGFMT}-efi \ + -o ./boot${GRUB_EFIARCH}.efi \ + boot linux fat serial part_msdos normal + + install -d ${STAGING_LIBDIR}/grub/ + install -m 644 ${S}/boot${GRUB_EFIARCH}.efi ${STAGING_LIBDIR}/grub/ +} + +FILES_${PN}-doc = "${datadir}" +FILES_${PN} = "/usr /etc" + -- 1.7.2.5
_______________________________________________ yocto mailing list yocto@yoctoproject.org https://lists.yoctoproject.org/listinfo/yocto