Menu

Where does rEFInd store the default boot loader?

faginbagin
2015-07-21
2015-07-21
  • faginbagin

    faginbagin - 2015-07-21

    This is a question I first asked Rod via email because the sourceforge discussion fora were down this weekend. I am pasting that email exchange here in case others are interested in the topic.

    First, let me say that rEFInd has simplified booting into one of three installed OSs on my laptop (Gateway NE570 with Insyde UEFI firmware). It has also allowed me to boot from a USB stick, something I could not do, regardless of whether I had configured the firmware for secure boot or not, or for UEFI or BIOS boot mode. I suspect it's a firmware bug since both Windows and Linux can read/write the USB sticks I've tried on the laptop, but the manufacturer hasn't posted any BIOS updates since I bought the laptop in late 2013.

    The only thing I think I might miss about grub is the ability to change the default boot entry via the grub-set-default command. I have found this command very handy when doing maintenance on my computers. It allows me to boot into a different OS without having to be physically present when I initiate a "shutdown -r now".

    I have searched your web site for clues, as well as the hard drive in both the ESP and the filesystem of the OS I used to install refind (Ubuntu 15.04) for a file that might store the default boot loader, similar to /boot/grub/grubenv. But I've come up empty. Is there a file? Or perhaps the info is saved in the NVRAM? If so, are there any command line tools I could use to change it? In any event, I'd like to make a feature request for a command that would do what grub-set-default does for grub/grub2.

    Rod's reply:

    That information is stored in NVRAM. In Linux, you can read the information from the
    /sys/firmware/efi/efivars/PreviousBoot-36d08fa7-cf0b-42f5-8f14-68df73ed3741
    variable (using the new efivarfs system; using the old efivar system, it's files in the
    /sys/firmware/efi/vars/PreviousBoot-36d08fa7-cf0b-42f5-8f14-68df73ed3741
    directory).

    In theory, you should be able to write new data to that variable, too, but I just tried it, and it didn't work for me. I'll have to look into this further.

    There are also mechanisms in other OSes that enable reading and setting EFI variables, but I'm not familiar with the details. In principles, these tools could be used to adjust the default boot option from those OSes.

     

    Last edit: faginbagin 2015-07-21
  • faginbagin

    faginbagin - 2015-07-21

    Our next exchanges:

    Thanks for replying so quickly. I have captured the PreviousBoot values using "cat" after booting into the two flavors of *buntu installed on the machine in question. One is mythbuntu 14.04.2 and the other is ubuntu 15.04. I'm tempted to try catting the mythbuntu value when booted into ubuntu and then seeing if I get the mythbuntu value back. If so, seeing what happens when I reboot. But I'm a little scared I might brick the machine. But perhaps that's exactly what you've already tried and what didn't work.

    When I tried it, I got various error messages and nothing happened. You're unlikely to "brick" the computer by writing to rEFInd's PreviousBoot variable. If you were to successfully write to some OTHER variable, that could conceivably cause problems.

    I guess what I'm trying to say is that I'm curious, willing to poke around, do some unit testing, whatever. I've got 20+ years experience as a software developer, and I've worked with a variety of languages, development environments, protocols, APIs, etc. So, if there's some way I can help, please let me know.

    If you discover how to do this, please send me a summary so I can add the information to the rEFInd documentation.

    Works for me!

    As I mentioned before, I had saved two versions of /sys/firmware/efi/efivars/PreviousBoot-36d08fa7-cf0b-42f5-8f14-68df73ed3740.
    boot-mythbuntu was saved while booted into mythbuntu 14.04.2 (kernel 3.16.0-43-generic)
    boot-ubuntu was saved while booted into ubuntu 15.04 (kernel 3.19.0-22-generic)
    While running ubuntu, I executed the command:
    cat ~/boot-mythbuntu > /sys/firmware/efi/efivars/PreviousBoot-36d08fa7-cf0b-42f5-8f14-68df73ed3740
    No errors. I verified its contents had indeed changed. I then rebooted. Lo and behold, the highlighted entry displayed by rEFInd was for mythbuntu. I waited 20 seconds and rEFInd then booted mythbuntu.

    I repeated the process from mythbuntu and was able to reboot into ubuntu without touching the keyboard.

    Next, I made a note of the string displayed when Windows is selected for booting in rEFInd:
    Boot Microsoft EFI boot from ESP
    I used vi with utf-16 encoding to get close to the EFI byte code I'd need. I used dd to grab the bytes I needed from the beginning and end of boot-ubuntu and to strip the newline character added by vi. catted the bits together, made sure they looked like the other boot-* files and then wrote that file out to /sys/firmware/efi/efivars/PreviousBoot-36d08fa7-cf0b-42f5-8f14-68df73ed3740. Rebooted. Sure enough, the Windows boot option was selected and the machine booted into windows without me needing to touch the keyboard.

    Is this sufficient info for you to add to the rEFInd documentation? I see the sourceforge discussion fora are back up. Would you like me to post my results there, perhaps including some/all of our email exchanges?

    Feel free to do so.

    I can get more specific about the dd command and the count and skip options I used to cut & paste the bytes I needed to form a valid boot-windows file. It probably wouldn't be too hard to turn this into a little C program that takes as a argument the "Boot <operating system="" file=""> from <disk-id|label>" string and then writes it to the PreviousBoot key. If you'd like, I can probably whip something up in the next 24 hours.

    If you care to do that and submit it for inclusion with rEFInd, I'll be
    happy to distribute it with rEFInd; just be sure to include a suitable
    copyright notice and license in your source file. (I use GPLv3 for
    rEFInd, but just about any open source license should be OK if your
    program doesn't use code from some other source.)

    Some questions:

    How is what I did different from what you did? IOW, why did it work for me, and not for you?

    Thanks for looking into this. I'd been using "echo", and may not have
    been thorough enough in adjusting my samples for UTF-16. I tried again
    with "dd" and the exact contents of
    PreviousBoot-36d08fa7-cf0b-42f5-8f14-68df73ed3740 from boots on multiple
    distributions and it worked for me, too. My suspicion is that the kernel
    code includes checks to ensure you're writing a valid UTF-16 string, and
    it errors out when you don't.

    What would happen if the user put in a string that wasn't quite valid? Would they lose total control of the boot sequence? Or would rEFInd ignore the invalid value and choose something valid?

    rEFInd would ignore the invalid entry. Basically, the PreviousBoot
    variable is handled as if it were the leading entry in the
    default_selection line in refind.conf. You should be able to store any
    unique portion of an entry in PreviousBoot to switch rEFInd's boot
    default. rEFInd stores the whole string simply because that's easier
    than trying to verify that a substring it might select is unique.

     

    Last edit: faginbagin 2015-07-21
  • faginbagin

    faginbagin - 2015-07-21

    Just wanted to say that I probably will take more than 24 hours to put together a little C program that does what I've been able to do with cat, dd and vi with utf-16 encoding. I want to take some time and review some other EFI source code projects to see if there's something I can reuse.

     

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.