From mboxrd@z Thu Jan 1 00:00:00 1970 From: Ian Campbell Subject: [PATCH OSSTEST v3 21/22] Debian: Arrange to be able to chainload a xen.efi from grub2 Date: Wed, 24 Jun 2015 16:32:40 +0100 Message-ID: <1435159961-22292-21-git-send-email-ian.campbell@citrix.com> References: <1435159944.28264.295.camel@citrix.com> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Return-path: In-Reply-To: <1435159944.28264.295.camel@citrix.com> List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Sender: xen-devel-bounces@lists.xen.org Errors-To: xen-devel-bounces@lists.xen.org To: ian.jackson@eu.citrix.com Cc: Ian Campbell , xen-devel@lists.xen.org List-Id: xen-devel@lists.xenproject.org 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 --- v3: Rewrap and reindent to avoid long lines --- Osstest/Debian.pm | 77 +++++++++++++++++++++++++++++++++++++++-- overlay/etc/grub.d/20_linux_xen | 21 +++++++++++ 2 files changed, 96 insertions(+), 2 deletions(-) diff --git a/Osstest/Debian.pm b/Osstest/Debian.pm index d7f8e9c..669cd36 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 = <{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, + <{Initrd}?<{Xenpolicy}?<{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..30bdfc8 100755 --- a/overlay/etc/grub.d/20_linux_xen +++ b/overlay/etc/grub.d/20_linux_xen @@ -142,6 +142,27 @@ 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 <