2

I have a PC running Windows and Linux. I want the Windows system to be the default system because this PC is mainly used for gaming.

I do, however, occasionally use it as my remote development box. I've enabled WOL for it, so it will boot as soon as I try to access it while on the road.

Is it somehow possible to tell GRUB2 to boot into Linux when the computer is booted via WOL and boot to Windows if not?

1 Answer 1

6

I recently found a solution to this problem that works for my use-case. Although this question is rather old, I'm going to post it here for reference:

The method requires (root) access to some device other than the target PC, which should be accessible from within the PC's network - e.g. a raspberry pi or a rooted android phone. It also requires booting with UEFI. The idea is to have that device wake the PC, and simultaneously act as a TFTP server (see here for a guide) which provides a configuration file telling GRUB what to boot by setting the default variable. Therefore, you need:

  • on the TFTP server, a script of the form

    #!/bin/bash
    # replace <boot-target> with the number of the option you want to choose
    echo 'default <boot-target>' > /srv/tftp/grub_conf
    wol <PC MAC>
    sleep 15     # wait for GRUB to boot
    echo > /srv/tftp/grub_conf
    

    (just sleeping for 15 seconds is, of course, somewhat hacky and might break if multiple instances of the script are started simultaneously, especially if it contains multiple options for boot targets. A slightly cleaner solution would be to only clear the file if it wasn't changed during the 15 seconds. The potentially best solution is to use the server hooktftp, which would allow for noticing when grub accesses the file and clearing it right after. However, I did not yet have the time to test this.)

    This will be the script that starts up the PC. It can easily be extended to allow for multiple choices of the boot option, which can then be chosen by command-line arguments.

  • configuring your UEFI BIOS to initialize the network stack during booting (note that this may take multiple different BIOS options to work reliably)

  • finding out how to tell GRUB how to talk to your server. This took some playing around with the GRUB command line for me, it might be easier for others. You want to start by running

    insmod net
    insmod efinet
    insmod tftp
    

    Then, if your UEFI is configured correctly, running net_ls_cards should give a network card (for me, it was called efinet0). This card then needs to be configured to be able to talk to your server. In theory, simply running net_bootp (which sends a DHCP-request and configures the network accordingly) should work. It didn't for me, though, so I worked around it by using net_add_addr efinet0:link efinet0 <localIP> to give the card some local IP address (probably 192.168.0/1.something). Apparently this works even if your router actually wants you to use DHCP (the PC isn't going to talk to the router anyway, so it doesn't matter), as long as the IP address you set is not occupied already. In my case I was able to just set a fixed local IP address for my PC, which solved the problem.

    If your server does not have a fixed IP address, you need to refer to it by its host name, so that you will also need to add a DNS server with net_add_dns. The GRUB documentation contains a list of all the commands. The descriptions are quite brief, however, so you might need to refer to the source code if you run into difficulties.

  • Then, you can test whether you're able to read files from your server from the GRUB command line by running cat (tftp,<server>)/grub_conf.

  • If you've figured out how to configure networking with grub, you can add this to the grub config in /etc/grub.d/40-custom.conf. In my case, it looked like this:

    insmod net
    insmod efinet
    insmod tftp
    net_add_addr efinet0:link efinet0 192.168.1.40
    source (tftp,192.168.1.41)/grub_conf
    

    (with my PC and server being bound to 192.168.1.40 and 192.168.1.41 respectively). Then use sudo update-grub to update your grub.cfg.

    Luckily, source doesn't do anything if the file access fails, so you don't need any error handling to check if your server is available.

The configuration ends here, these two files should be all that you need to have the server tell the PC when and what to boot. You might need some extra configuration to be able to wake the PC from anywhere - to provide some inspiration I am going to share my personal configuration:

  • My TFTP server is a raspberry pi, which is also configured as a web server and accessible via ssh, all via port 443 (using sslh). I use noip to give the server a universally accessible URL.
  • One page on the web server provides a web interface for waking the PC via http requests (that is, a PHP script on the web server listens for requests and starts the above bash script accordingly). T
  • I use the Android app Automate to get a home screen shortcut that sends the HTTP requests (that's the whole reason why I use HTTP - AFAIK Automate doesn't know ssh).
  • The end result are two shortcuts I have on my phone's home screen to start Linux and Windows respectively. If I want to shut the PC down remotely, I can ssh into my raspberry pi (e.g. using Termux and access the PC from there. With some configuration, you can also shut down a PC running Windows remotely)
1
  • Thank you so much for this response! I wanted to achieve the same thing and got it working flawlessly. Some tips for future reference: "configuring your UEFI BIOS to initialize the network stack during booting" was achieved in my ASRock motherboard with "Enable PXE booting"; the command to show network cards in the GRUB CLI is net_ls_cards - this response is missind a "d"; I only got this to work by changing echo 'default <boot-target>' > /srv/tftp/grub_conf to echo 'set default=<boot-target>' > /srv/tftp/grub_conf, and <boot-target> is an integer starting from 0
    – Thiago
    Mar 24 at 17:13

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .