[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH OSSTEST v4 21/21] Debian: Arrange to be able to chainload a xen.efi from grub2



Xen cannot (currently) be booted directly via the usual multiboot
path on EFI systems of any arch. Instead it is necessary to either
launch xen.efi direct from the UEFI shell or to chainload it from
grub. In both cases the Xen command line as well as what would
normally be the multiboot modules (kernel+command line, XSM policy,
initrd) must be configured in a Xen configuration file.

Here we add a new overlay/etc/grub.d/15_osstest_uefi grub script which
arranges that if a xen.efi is found in the EFI System Partition (as
arrange by a previous patch) a suitable entry is created in grub.cfg
as well.

When parsing the grub.cfg look for such an entry into addition to the
regular/multiboot one and when necessary write the configuration file
based on the regular entry and return the chainload one such that it
gets booted.

This is currently enabled only for Jessie ARM64 systems.

Signed-off-by: Ian Campbell <ian.campbell@xxxxxxxxxx>
---
v4: Use a separate grub script snippet, there's nothing we need in
    20_linux_xen
v3: Rewrap and reindent to avoid long lines

Split out boot script
---
 Osstest/Debian.pm                  | 77 +++++++++++++++++++++++++++++++++++++-
 overlay/etc/grub.d/15_osstest_uefi | 49 ++++++++++++++++++++++++
 2 files changed, 124 insertions(+), 2 deletions(-)
 create mode 100755 overlay/etc/grub.d/15_osstest_uefi

diff --git a/Osstest/Debian.pm b/Osstest/Debian.pm
index c76d63a..718a7e2 100644
--- a/Osstest/Debian.pm
+++ b/Osstest/Debian.pm
@@ -400,12 +400,18 @@ sub setupboot_grub2 ($$$$) {
 
     my $rmenu= '/boot/grub/grub.cfg';
     my $kernkey= (defined $xenhopt ? 'KernDom0' : 'KernOnly');
- 
+
+    # Grub2 on Jessie/arm* doesn't do multiboot, so we must chainload.
+    my $need_uefi_chainload =
+        get_host_property($ho, "firmware") eq "uefi" &&
+        $ho->{Suite} =~ m/jessie/ && $r{arch} =~ m/^arm/;
+
     my $parsemenu= sub {
         my $f= bl_getmenu_open($ho, $rmenu, "$stash/$ho->{Name}--grub.cfg.1");
     
         my @offsets = (0);
         my $entry;
+        my $chainentry;
         my $submenu;
         while (<$f>) {
             next if m/^\s*\#/ || !m/\S/;
@@ -424,7 +430,13 @@ sub setupboot_grub2 ($$$$) {
                        (defined $xenhopt
                         ? qw(Title Hv KernDom0 KernVer)
                         : qw(Title Hv KernOnly KernVer));
-               if (@missing) {
+               if ($need_uefi_chainload && $entry->{Chainload}) {
+                   # Needs to be before check of @missing, since a
+                   # chained entry doesn't have anything useful in it
+                   logm("Found chainload entry at $entry->{StartLine}..$.");
+                   die "already got one" if $chainentry;
+                   $chainentry = $entry;
+               } elsif (@missing) {
                    logm("(skipping entry at $entry->{StartLine}..$.;".
                         " no @missing)");
                } elsif ($entry->{Hv} =~ m/xen-syms/) {
@@ -456,9 +468,15 @@ sub setupboot_grub2 ($$$$) {
                 $submenu={ StartLine =>$., MenuEntryPath => join ">", @offsets 
};
                 push @offsets,(0);
             }
+            if (m/^\s*chainloader\s*\/EFI\/osstest\/xen.efi/) {
+                die unless $entry;
+                $entry->{Hv}= $1;
+                $entry->{Chainload} = 1;
+            }
             if (m/^\s*multiboot\s*(?:\/boot)?\/(xen\S+)/) {
                 die unless $entry;
                 $entry->{Hv}= $1;
+                $entry->{Chainload} = 0;
             }
             if (m/^\s*multiboot\s*(?:\/boot)?\/(vmlinu[xz]-(\S+))\s+(.*)/) {
                 die unless $entry;
@@ -490,13 +508,68 @@ sub setupboot_grub2 ($$$$) {
            die unless $entry->{Hv};
        }
 
+       if ($need_uefi_chainload) {
+           die 'chainload entry not found' unless $chainentry;
+
+            # Propagate relevant fields of the main entry over to the
+            # chain entry for use of subsequent code.
+            foreach (qw(KernVer KernDom0 KernOnly KernOpts
+                        Initrd Xenpolicy)) {
+               next unless $entry->{$_};
+               die if $chainentry->{$_};
+               $chainentry->{$_} = $entry->{$_};
+            }
+
+            $entry = $chainentry;
+       }
+
         return $entry;
     };
 
 
     $bl->{UpdateConfig}= sub {
        my ( $ho ) = @_;
+
+        target_editfile_root($ho, '/etc/default/grub', sub {
+            while (<::EI>) {
+                next if m/^export GRUB_ENABLE_XEN_UEFI_CHAINLOAD\=/;
+                print ::EO;
+            }
+           print ::EO "export GRUB_ENABLE_XEN_UEFI_CHAINLOAD=\"osstest\"\n"
+               if $need_uefi_chainload;
+       });
+
        target_cmd_root($ho, "update-grub");
+
+       if ($need_uefi_chainload) {
+           my $entry= $parsemenu->();
+           my $xencfg = <<END;
+[global]
+default=osstest
+
+[osstest]
+options=$xenhopt
+kernel=vmlinuz $entry->{KernOpts}
+END
+            $xencfg .= "ramdisk=initrd.gz\n" if $entry->{Initrd};
+            $xencfg .= "xsm=xenpolicy\n" if $entry->{Xenpolicy};
+
+            target_putfilecontents_root_stash($ho,30,$xencfg,
+                               "/boot/efi/EFI/osstest/xen.cfg");
+
+            # /boot/efi should be a mounted EFI system partition, and
+            # /boot/efi/EFI/osstest/xen.efi should already exist. Hence no 
mkdir
+            # here.
+            target_cmd_root($ho,
+               
<<END.($entry->{Initrd}?<<END:"").($entry->{Xenpolicy}?<<END:""));
+set -ex
+cp -vL /boot/$entry->{KernDom0} /boot/efi/EFI/osstest/vmlinuz #/
+END
+cp -vL /boot/$entry->{Initrd} /boot/efi/EFI/osstest/initrd.gz #/
+END
+cp -vL /boot/$entry->{Xenpolicy} /boot/efi/EFI/osstest/xenpolicy #/
+END
+       }
     };
 
     $bl->{GetBootKern}= sub { return $parsemenu->()->{$kernkey}; };
diff --git a/overlay/etc/grub.d/15_osstest_uefi 
b/overlay/etc/grub.d/15_osstest_uefi
new file mode 100755
index 0000000..94fbcee
--- /dev/null
+++ b/overlay/etc/grub.d/15_osstest_uefi
@@ -0,0 +1,49 @@
+#! /bin/sh
+
+set -e
+
+# grub-mkconfig helper script.
+# Copyright (C) 2006,2007,2008,2009,2010  Free Software Foundation, Inc.
+#
+# GRUB is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# GRUB is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+
+prefix="/usr"
+exec_prefix="${prefix}"
+datarootdir="${prefix}/share"
+
+. "${datarootdir}/grub/grub-mkconfig_lib"
+
+CLASS="--class gnu-linux --class gnu --class os --class xen"
+
+chain_xen_entry () {
+    vendor="$1"
+    if [ ! -f /boot/efi/EFI/$vendor/xen.efi ] ; then
+       return
+    fi
+    title=$(gettext_quoted "Chainload $vendor Xen")
+    xmessage="$(gettext_printf "Chainloading $vendor Xen ...")"
+    printf "menuentry '${title}' ${CLASS} {\n"
+    prepare_grub_to_access_device \
+       `${grub_probe} --target=device /boot/efi/EFI/$vendor/xen.efi` \
+       | grub_add_tab
+    cat <<EOF
+       echo    '$xmessage'
+       chainloader     /EFI/$vendor/xen.efi
+}
+EOF
+}
+
+for i in ${GRUB_ENABLE_XEN_UEFI_CHAINLOAD} ; do
+    chain_xen_entry $i
+done
-- 
2.1.4


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.