8

I have an application where I need to boot to Linux, execute automated scripts and then automatically boot to Windows. Can I use Kexec to run grub?

Another use case would be to boot a Linux kernel to update the processor microcode, and then kexec to GRUB or Syslinux to boot Windows -- because the microcode won't survive a full reboot.

I've heard of grub4dos (link (unavailable), archived version), but it seems to be discontinued, so is there a way to do it with GRUB2?

I would basically need a loadable image of GRUB for kexec. I tried to load the images found in this explanation, but they don't seem to work. Thanks for any hints.


Note: Found this post from back in 2014, which said that this was not yet implemented in kexec.

Pourko
  • 1,774
  • 6
  • 27
rudib
  • 1,532
  • 1
  • 13
  • 33
  • Alternatively, could I kexec directly to a Windows loader? – Pourko Nov 15 '20 at 04:47
  • @Pourko I'm not sure about windows loader, but windows itself seems to be possible. https://www.phoronix.com/scan.php?page=news_item&px=Google-Kexec-Windows-Linux However, they didn't seem to show how they did it and it might not work with the default `kexec`. – rudib Nov 15 '20 at 09:19
  • Why don't you set up grub to boot to linux by default. Then, on booting the linux machine, you can execute the required commands and reboot to Windows with: `grub-reboot`. More info: https://wiki.debian.org/GrubReboot – Jesús Ángel Nov 15 '20 at 13:25
  • @JesúsÁngel Yes, that was the solution I settled on back then. I was looking for a faster way to do it (without having to reboot). – rudib Nov 15 '20 at 15:29
  • "grub-reboot" is not the solution, as I am speciffically trying to avoid a full reboot. If for example the Linux kernel updates the processor microcode -- that microcode won't survive a fill reboot. – Pourko Nov 15 '20 at 15:48
  • I remember being able to kexec to grub4dos a long time ago, but when I tried to do that now, I couldn't make it work. (with the last known version of [grub4dos](https://sourceforge.net/projects/grub4dos/) circa 2009) – Pourko Nov 15 '20 at 16:01
  • Is starting a Windows-VM from Linux an alternative way for you? – Nils Nov 20 '20 at 17:31
  • @Pourko I missed that you already tried `grub4dos`. I managed to load it on first try (0.4.4 from sourceforge). See my updated answer. – rudib Nov 20 '20 at 18:28
  • @Nils technically it totally is a solution, but the question is basically about using linux as a boot/chainlader. But you're not wrong, especially if there are enough resources, a vm makes a lot of sense. – rudib Nov 20 '20 at 18:36

5 Answers5

3

It seems to be possible to kexec Windows, but it seems to be experimental at best (and not well tested).

GRUB

It's not possible to kexec the grub core.img by itself (as it doesn't seem to have a compatible binary format), also see this bug report on launchpad. The error mentioned is still reproducible:

kexec -l /boot/grub2/i386-pc/core.img

According to kexec --help, the following types are supported at the moment:

elf-x86_64
multiboot-x86
multiboot2-x86
elf-x86
bzImage64
bzImage
beoboot-x86
nbi-x86

If you want to load a different loader, it would need to be in one of these formats or the compatibility would have to be added. I'm not sure what format GRUB is using - a simple file command only produces this:

/boot/grub2/i386-pc/core.img: data

Creating a bootable GRUB Image

Currently there seem to be these possibilities:

lnxboot

lnxboot.img would be a Linux kernel x86 boot executeable bzImage. It seems to be intended to be loaded as a kernel:

You can then load grub2.bin from syslinux/isolinux/pxelinux/lilo or any other boot loader that supports linux kernel.

Kexec does load it, but crashes when executing:

kexec -l /usr/lib/grub/i386-pc/lnxboot.img --initrd=/boot/grub2/i386-pc/core.img --debug

There also seems to be an issue occuring while loading (first few lines of debug output):

Try gzip decompression.
Try LZMA decompression.
lzma_decompress_file: read on /usr/lib/grub/i386-pc/lnxboot.img of 65536 bytes failed
[...]

Grub4Dos

A quick look at Grub4Dos:

# file grub.exe
grub.exe: Linux kernel x86 boot executable bzImage, version \353kHdrS\003\002, RO-rootFS, Normal VGA

This should mean that it is compatible. It wasn't an option for me as it's legacy software.

However, I managed to load grub4dos by downloading 0.4.4 from sourceforge and then running:

kexec -l grub.exe
kexec -e

Unconfigured, it falls back to the grub shell after some time. If you want to use gru4dos, you should only need to tweak the cmdline to fit your needs. This thread should still apply.

Windows

Kexec'ing Windows doesn't seem to be a one-liner, but it has been done before.

Most of the work in this direction seems to be associated with the LinuxBoot project. Github

I found these slides as well as this github repo. This seems to be the project mentioned in the article that was making it work.

It seems to be possible, but a lot of work (and no "production-ready" solution available - At least I haven't found it yet). Unfortunately there doesn't seem to be a lot of documentation for LinuxBoot, so you may have to ask the developers. There may already be a more straightforward way to do this.

rudib
  • 1,532
  • 1
  • 13
  • 33
  • When you say it like "It's not possible to kexec grub, because non-elf multiboot images aren't supported yet" -- like it's an authoritative answer -- that is just somebody said something in some post from 2014. And contrary to that statement, kexec-ing to grub4dos used to be possible at that time. – Pourko Nov 15 '20 at 16:44
  • @Pourko it's not an authorative answer, but it's all the info I found on it. And I tried it when asking that question in 2017. It will give you an error and say that the image isn't compatible. (It might be fixed by now). I believe that `grub4dos` had a different format (`elf`? non multiboot?) and that's why it worked (so that wouldn't necessarily contradict anything). – rudib Nov 15 '20 at 16:59
  • 1
    That's why I am not limiting my search to grub2. I would be happy if I find a way to kexec to ANY bootloader, like Syslinux, or Clover, or something. – Pourko Nov 15 '20 at 17:19
  • @Pourko well - for now, the only option i know of with which this may work is `grub4dos` (if you're ok with **ANY** bootloader). There may be others, you'd have to check the image formats with `file`. – rudib Nov 15 '20 at 19:09
  • I would accept your answer, if it was not for that section about grub, where you make it sound like you know what you're talking about, while you're actually basing it all on somebody's very old post you googled. – Pourko Nov 15 '20 at 19:45
  • @Pourko you don't need to accept it at all. Someone might have a better answer. In fact, I don't really consider it an answer myself - I just wanted to provide an update on this topic, since it's been a while (until a better solution comes up). You don't seem to be reading my posts carefully though. I've tried it myself in 2017 and now I've tried it again. It literally does not work. Try it yourself. – rudib Nov 15 '20 at 19:54
  • We both don't know the answer, which is why we posted here in the first place, to attract the attention of somebody who might know. – Pourko Nov 15 '20 at 20:16
  • @Pourko well `core.img` definately dosen't run. However, there is a chance that I and the ones before me made a mistake. Perhaps `core.img` isn't supposed to run by itself because of the way GRUB is built. https://www.gnu.org/software/grub/manual/grub/html_node/Images.html Perhaps `kernel.img` **inside** `core.img` is actually what we want. – rudib Nov 15 '20 at 20:28
  • Found [this thread](http://web.archive.org/web/20180701010336/http://reboot.pro/topic/7223-how-to-boot-directly-into-windows-from-kexecgrub4dos/) from 2009 that might help or at least give some pointers to a solution. – Paranoid Nov 18 '20 at 22:18
  • @Paranoid Yes, I found that too (linked in the question) ;) – rudib Nov 18 '20 at 22:28
2

The reason why kexec-ing into Windows is so difficult and complicated is because the internal design mechanism of kexec has an imperfection that, it assumes all OS boot loaders loads OS kernel image in a similar way, which is clearly not the case. For example, some OS kernel image must be loaded starting from some special memory address offset, some OS may require loading additional files (that containing driver info) alongside OS kernel image, etc. Since we have no control over how an operating system loads its kernel image, or will load its kernel image in a future release, the current way of kexec-ing into another OS/kernel is not going to work very well in the long run.

The more universal/compatible way (as I propose) of kexec-ing into another OS is to load the real-mode boot-sector boot code, quit the protected mode, and then jump directly into the real-mode boot code entry point. This is the most universal way because any operating system's real-mode boot-sector boot code can always be loaded starting at any memory address, that is how BIOS (different computer manufacturers make different BIOS) boots into an operating system (unless an OS does not want other BIOS to install or boot it, e.g., Apple, they can impose proprietary restrictions on how to load boot-sector boot codes). In this way, we can always boot into any operating system regardless of how its boot code loads its OS kernel image simply because we are running its own boot-sector boot code directly. Moreover, this mode does not introduce any slow-down because boot-sector boot code is small and thus fast to load, and the difference in loading a large kernel image file in real mode vs in protected mode is not very big.

However, to achieve this is very challenging because:

  1. For all modern OS, once they enter protected mode from real mode, the real-mode memory is over-written by some descriptor tables or page tables entries. Thus, there is no backup. However, real mode boot codes use BIOS interrupts to access hardware IO, so without restoring the original real-mode memory map, they won't be able to load kernel image file from hard-disk. This problem is tricky but solvable. We can install some special Linux boot loader that takes a memory snapshot before entering protected mode and it only needs to be done once for all on one machine.

  2. Not all processors well support going back to real mode from protected mode. Modern processors are designed for booting into an OS (entering protected mode from real mode), rather than un-booting out of an OS (returning to real mode from protected mode), for production cost and efficiency reasons. Thus, the behavior of returning to real mode from protected mode is not well tested and thus very much undefined. Since this behavior varies in each model, there is no control thus no guarantee of on which brand/models processors will it work correctly.

  3. Only Intel X86 processors have real mode and protected mode (because it went through a very early stage legacy technology). Thus, the mechanism of rebooting from boot sector will be different for different processor architectures, not necessarily involving returning to real mode from protected mode, but may involve some other switches in processor operating states.

Nevertheless, it should work in principle if everything is correctly taken care of. In the future, Linux should have the capability of kexec-ing into any mounted boot-able partition (but not necessarily marked as boot-able because each hard-disk can only have one partition that is marked as boot-able, or BIOS will report an error and refuse to boot) from any hard-disk directly without a full hardware reboot which is much slower. This shed more light and hope to Linux ^_^

xuancong84
  • 141
  • 2
  • Welcome to the site, and thank you for your contribution. Unfortunately, while you describe how the desired function could be implemented in the future, your answer doesn't really describe what the OP could do _now_ to solve the problem. You may want to consider posting your proposition on the [kexec mailing list](https://lists.infradead.org/mailman/listinfo/kexec) or a different developer's forum instead. – AdminBee Nov 12 '21 at 07:45
  • On x86 PCs, your proposal would run into EFI hand-off issues: boot loaders are expected to cooperate with EFI during system boot, but that can only happen once. Also, point 2 was only ever an issue with the 286, current processors support returning to real mode just fine. In any case, EFI systems wouldn’t return to real mode — EFI boot programs run in protected mode. – Stephen Kitt Nov 12 '21 at 16:53
  • @StephenKitt FYI, EFI starts in real mode (https://github.com/tianocore/edk2/blob/master/UefiCpuPkg/ResetVector/Vtf0/Ia16/ResetVectorVtf0.asm#L52 ) and switches to protected mode (https://github.com/tianocore/edk2/blob/master/IntelFsp2Pkg/FspSecCore/SecMain.c#L52 ). In particular, different OS provide their own EFI firmware image (e.g., bootmgr.efi for Windows, grubx64.efi for Linux). So ideally, kexec should provide the option of either kexec-ing from before *.efi is loaded or after *.efi is loaded. – xuancong84 Nov 13 '21 at 10:36
  • Of course EFI starts in real mode, that’s the mode x86 CPUs start in. But it switches to protected mode before loading the boot manager. So even if you want `kexec` to re-execute the boot manager, there’s no need to return to real mode if the system was booted by EFI. – Stephen Kitt Nov 13 '21 at 12:19
  • `bootmgr.efi`, `grubx64.efi` etc. aren’t firmware images. – Stephen Kitt Nov 13 '21 at 12:20
  • In that case, `kexec` should have the option of `kexec-legacy` (which starts from real mode and loads selected boot sector) or `kexec-uefi` (which starts from protected mode and loads the selected .efi boot manager). If `kexec-legacy` is not provided, `kexec` will not be able to boot legacy-installed OS (theoretically can, but we need to know how the legacy OS loads its kernel, and different OS loads its kernel in slightly different ways). – xuancong84 Nov 14 '21 at 03:14
  • Feel free to [edit] your post to address all that then ;-). – Stephen Kitt Nov 17 '21 at 09:48
1

You need to have grub installed and the Linux system as the default boot.

On the linux system create a crontab entry like this:

@reboot /do/some/stuff

Where /do/some/stuff is a script to perform whatever tasks you need to do. At the end of the script add the following:

#!/bin/bash
#
# Do something here

sudo grub2-once "Windows"
sudo reboot

It should then reboot into windows provided the grub menu item for windows is "Windows".

At the next reboot it will go back into linux and do the same thing.

Paranoid
  • 305
  • 1
  • 3
  • 1
    Sorry, but this is not what we're looking for. Were trying to **not** reboot here. (but it's what I did to get similar behaviour though - but it's not what the question is about). – rudib Nov 18 '20 at 21:05
  • @Paranoid great answer. I was looking into conditional boot with a file being used as a flag. But this is both simpler and cleaner. – Eduardo Trápani Nov 18 '20 at 21:29
  • @rubid, out of curiosity, why don't you want to reboot? – Eduardo Trápani Nov 18 '20 at 21:30
  • @EduardoTrápani Originally it was just to save time. Now also out of curiosity. Also, Pourko wants to use it to update microcode (which would be lost on reboot). – rudib Nov 18 '20 at 22:26
0

kexec might work if you combine these two grub images: lnxboot.img and core.img, like...

cat lnxboot.img core.img > your-kexec-able.img

Worth trying that.

EDIT:

Now that I looked inside the images, lnxboot.image looks more like an "ELF" than lnxboot.img, so try that one too.

EDIT:

Aparently, the /boot/grub2/i386-pc/xxx.img images are not to the liking of kexec. Then why not try using grub-mkimage to genrate some different formats, and see what works? From the man page, -O, --format=FORMAT supports a whole bunch of other formats. Maybe try the x86_64-xen format.

  • Looks promising. `lnxboot.img` is valid, but doesn't boot. I'll try the `.image` too. – rudib Nov 15 '20 at 21:09
  • Yes, both can be loaded, but unfortunately it crashes when executing. – rudib Nov 15 '20 at 21:23
  • Splendid idea! I can't quite make it work though. Kexec actually loads the combined image, `kexec -l -t bzImage lnx-core.img`, but then when I execute `kexec -e` it just displays the message "kexec-core: Starting new kernel!", and all freezes right there. – Pourko Nov 15 '20 at 21:45
0

Not exactly what has been asked for, but starting a Windows-VM using Linux is a solution feasible, if you have got enough power on that machine.

I can recommend VirtualBox for this. There you can configure VMs to autostart during bootup, to.

By modifying the runlevel relationships you can time when to start that windows-VM. With shared folders you can even use a signalling mechanism between Linux and the Windows VM.

Nils
  • 18,202
  • 11
  • 46
  • 82
  • Yes, that is not what has been asked for, and is completely unrelated. Suppose I have a machine that's strictly Windows. I know how to boot it through Grub, but I'd love to find a way to boot it through Linux. (for example, if I want to use the Linux kernel to update the processor microcode before I boot Windows -- hense my desire to be able to jump from Linux back to Grub) – Pourko Nov 22 '20 at 02:06
  • @Pourko I asked wether this would be a solution. And the CPU-microcode-update will be there, too. In the VM you could map the windows-partitions to virtual storage for that VM, too. – Nils Nov 25 '20 at 16:56
  • No, a virtual box has no real access to the hardware of the host, let alone messing with the microcode of the CPU. – Pourko Nov 25 '20 at 17:36
  • @Pourko the virtual CPUs will inherit the mircrocode from the hardware CPU. Which is installed during ealry boot in root-space, whereas the VM resides in user space. – Nils Nov 25 '20 at 20:57
  • I have no use of virtual machines "inheriting" anything. Virtual machines have nothing to do with the problem at hand. – Pourko Nov 25 '20 at 21:04