[yocto] [PATCH] EFI support for IA

Josef Ahmad josef.ahmad at intel.com
Wed Nov 23 02:39:49 PST 2011


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.ahmad at 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.zanussi at 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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.yoctoproject.org/pipermail/yocto/attachments/20111123/c57eba34/attachment.html>


More information about the yocto mailing list