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

[Xen-devel] [PATCH OSSTEST v2 19/19] 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.

By patching overlay/etc/grub.d/20_linux_xen that if a suitable 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.

Note that the 20_linux_xen change here is a bit specific to us and not
really generic enough to go upstream IMHO, hence I haven't.

Signed-off-by: Ian Campbell <ian.campbell@xxxxxxxxxx>
---
 Osstest/Debian.pm               | 75 +++++++++++++++++++++++++++++++++++++++--
 overlay/etc/grub.d/20_linux_xen | 19 +++++++++++
 2 files changed, 92 insertions(+), 2 deletions(-)

diff --git a/Osstest/Debian.pm b/Osstest/Debian.pm
index d342103..c89a362 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,66 @@ 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/20_linux_xen b/overlay/etc/grub.d/20_linux_xen
index aaead1b..7bee1a3 100755
--- a/overlay/etc/grub.d/20_linux_xen
+++ b/overlay/etc/grub.d/20_linux_xen
@@ -142,6 +142,25 @@ EOF
 }
 EOF
 }
+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
 
 linux_list=`for i in /boot/vmlinu[xz]-* /vmlinu[xz]-* /boot/kernel-*; do
     if grub_file_is_not_garbage "$i"; then
-- 
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®.