Dual Boot modern OSes in Legacy Mode

Most new Linux distributions come these days with out of the box support for EFI boot (UEFI). However, if you are stuck with an ancient pc where maybe you installed Windows years ago, it would probably be on legacy BIOS mode. Moreover, GRUB, the legacy BIOS mode of Linux, is now old and has given way to UEFI based newer entrants, like systemd-boot that are used in the latest distributions of Arch, Linux Mint etc. So when we install a latest Linux distro, chances are that its systemd-boot loader has overwritten grub, and if your Windows installation happened to be on another drive altogether, then it would definitely not recognize that.

So the situation we are going to fix is:

  1. Existing Windows installation on /dev/sdb1 in BIOS (Legacy) mode
  2. New Linux installation on /dev/sda1 using systemd-bootin BIOS (Legacy) mode
  3. Possibly other linux/ windows installations in /dev/sdb or a third, /dev/sdc (yes, power users do like to use the choices available to them).

I faced this situation with a brand new installation of System76’s Pop OS, which is based on Ubuntu but getting some good reviews these days. To resolve the issue, I had to update grub after probing for existing OS across my drives (all of which were recognized in GParted or Parted disk utilities).

Follow the below steps to restore Windows or other OS installations, if you are in a similar situation:

1. List your partitions


$ lsblk -l
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 167.7G 0 disk
sda1 8:1 0 9.5G 0 part
sda2 8:3 0 142.9G 0 part /
sda3 8:5 0 15.3G 0 part
sdb 8:16 0 931.5G 0 disk
sdb1 8:17 0 200G 0 part
sdb2 8:18 0 200G 0 part
sdb3 8:19 0 84G 0 part
sr0 11:0 1 1024M 0 rom
cryptswap 253:0 0 15.3G 0 crypt [SWAP]

2. Identify your windows partition and mount it:


$ mkdir -p /media/user/sdb1
$ sudo mount /dev/sdb1 /media/user/sdb1

$ mkdir -p /media/user/sdb2
$ sudo mount /dev/sdb2 /media/user/sdb2

Here, sdb1 and sdb2 contain the previously installed OSes, like Windows and Linux.

(Steps 1 and 2 can also be done by simply mounting the Windows partition from File explorer: Files > Other Locations > click on the required partition among the list)

3. Install and run a utility ‘os-prober’ – it may not come with the distro – as in the case for Pop OS.


$ sudo apt-get install os-prober
$ sudo os-prober

In the output, we can see that it has picked the other OS installations across mounted drives. If the drive is not mounted, it wont search for bootloaders there, so we need to mount secondary and tertiary drives first (steps 1, 2).

4. Update good old GRUB, which systemd-boot would actually use in case of BIOS (Legacy) mode – to confirm we can check under /boot, which will have /grub as a subdirectory instead of /efi


$ sudo update-grub

Thats it*. Now restart the system to load into Grub Menu, from where we can boot into other OSes. (Curiously, Pop OS shows up as Ubuntu; probably they did not think of this use case so did not fix).

EDIT:

*In case this is a dual/ triple boot scenario with a second Linux distribution, this may or may not work always. The above procedure basically “updates” GRUB from the newest OS installed, i.e. Pop in this case. Pop is still in charge of the system GRUB after this. The previous Linux distro (not Windows) in my system was Linux Mint, which was in charge of GRUB before this (i.e. GRUB was last updated from there).

Now, some distros like Manjaro do not like being not in charge of GRUB. One issue with Manjaro is that it loads a Intel microcode kernel before the actual Linux kernel in it, and when Pop updated grub, it searched only for the Linux kernel as the file pointer, but since Manjaro expects it to be Intel microcode instead, it threw Kernel Panic on selecting the option from Pop’s GRUB. More details can be found here.

The solution to this is to put Manjaro in charge of GRUB, i.e run the os-prober from Manjaro and then update GRUB. For this to work, we first need to boot into Manjaro. When I installed Pop OS 20.04, at that time Manjaro was the previously installed OS in charge of GRUB. But it was in second hard drive, i.e. sda, so I simply changed the boot priority in BIOS and it booted into Manjaro desktop. From there, I ran the above commands and it recognized the newly installed Pop and previously installed Windows, not to mention itself as well. GRUB was updated and I was able to boot into all 3 OSes.

In case we had Manjaro in same drive as Pop OS, we would have to do this using Manjaro live USB stick/ DVD. There is an option to chroot into existing installation, from where we can run the above commands.

Quick fstab reference

/etc/fstab

The /etc/fstab file is used to set permissions on disk drives when mounted at boot. Based on this, one is able to read/ write/ execute files on the disk. The /etc/fstab is general permissions file for disk partitions, so it works on any Linux distribution.

Below is the typical contents of /etc/fstab for a 2-disk setup (OS installed on primary, applications/ media on secondary, both internal), which enables the user to run executable files. [Note that UUID values are faked; actual fstab entries should have the right values].

The ntfs-3g package must be installed for support of NTFS partitions; usually it is bundled with the distribution, but in case it isn’t, we can install using the distribution’s package manager.

Example fstab file

# # /etc/fstab: static file system information. 
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to 
# name devices # that works even if disks are added and removed. 
# See fstab(5). 
# # 

# / was on /dev/sda5 during installation 
UUID= / ext4 errors=remount-ro 0 1 
# /home was on /dev/sda6 during installation 
UUID= /home ext4 defaults 0 2 
# swap was on /dev/sda8 during installation 
UUID= none swap sw 0 0 
# s33 on /dev/sdb5 (Secondary Drive) 
UUID=UUIDOFS33PARTITION  /media/jdoe/s33 ntfs-3g defaults 0 0 
# s34 on /dev/sdb6 (Secondary Drive) 
UUID=UUIDOFS34PARTITION /media/jdoe/s34 ntfs-3g uid=1000,gid=1000,fmask=0000,dmask=0000,exec 0 0 
# s35 on /dev/sdb7 (Secondary Drive) 
UUID=UUIDOFS35PARTITION /media/jdoe/s35 ntfs-3g uid=1000,gid=1000,defaults 0 0
# s36 on /dev/sdb8 (Secondary Drive) 
UUID=UUIDOFS36PARTITION /media/jdoe/s36 ext4 defaults 0 0

The last 4 entries are for 3 NTFS partitions (/dev/sdb5, /dev/sdb6, /dev/sdb7) and a ext4 partition (/dev/sdb8) on a secondary internal hard drive. These were added manually after the OS install on primary, which automatically added the first 3 entries (root, home, swap), which may or may not be added by the installation.

The options column above decides which permissions to be set for the drive. The value defaults contains the options rw, suid, dev, exec, auto, nouser, and async. This is a typical usage of a file system, where the user will be able to read, write, execute files. The contents specified by defaults can be checked in the manual for mount, towards the end:

$ man mount

Write Access

If the mounted partition does not have write access, manually “own” the mounted folder as logged in user:

$ sudo chown -R jdoe:jdoe /media/jdoe/s36

Setting explicit user id and group id in fstab permissions

Above has two examples of how to set the permissions, with the second line explicitly mentioning the user id and group id to which the user belongs. To check what the value of these should be, we can run

$ cat /etc/passwd | grep jdoe

which returns

jdoe:x:1000:1000:John Doe:/home/jdoe:/bin/zsh

The part 1000:1000 corresponds to uid:gid

For more restrictive permissions, we can individually set permissions via fmask (for files), dmask (for directories), and umask (for both) by providing the bitwise inverse of the actual chmod permission number we want to set, since these are bit masks. More details can be found in the community guide for fstab in Ubuntu here.

Getting UUID of partitions to be mounted

The UUID values for these drives/ partitions can be obtained by running

$ sudo blkid

as suggested in the fstab header above.

To use the new fstab content without rebooting, we can simply run

$ mount -a

Steam/ Proton support for NTFS

Proton, the wrapper of WINE to play Windows games on Linux, is finicky about NTFS drives. It may or may not work depending on the distribution, and Proton version. I have seen Proton work with any of the 3 options we have used in NTFS above, but none of them worked for Proton 5.x. So if you are in the same boat, downgrade the Proton version to 4.x with the above fstab options, and it should work.

While most suggestions on the internet are to use ext4 as the format type, it misses the point – Linux is always about choice, and if someone wants to install Steam games on a partition and also use the same to install apps/ games under Windows, so be it.