3

I am not understanding how it comes to know which kernel image to load? I have so many. Once I had created my own kernel and recompiled. How does it come to know that this is the one to load?

1

4 Answers 4

3

Here's what I've gleaned from info grub and this grub tutorial.

Short story is that, yes, if you change the /boot/grub/grub.cfg file, the grub2 bootloader will read those changes and act accordingly.

  • The caveat is that if you make a tiny typo, your system won't boot, (although grub2 itself will run and you can use the grub shell to boot, with three commands, if you know what you're doing). So instead of actually editing a boot entry within grub.cfg, duplicate it, and give a new name for the new menuentry.If the new one boots up correctly, you can either make it the new default (see below) or delete the old one.

  • The complication is that by default, whenever Ubuntu pushes a grub or kernel update it completely rewrites grub.cfg (via the shell script /usr/sbin/update-grub2). So if you change grub.cfg by hand to boot a custom kernel, those changes might get overwritten.

The way around this is, instead of messing with grub.cfg at all, add the custom kernel menu entry to the end of /etc/grub.d/40_custom, and run #sudo update-grub2

(That will ensure that your custom kernel will always be in grub's grub.cfg file even when there are grub or kernel updates pushed by by Ubuntu).

You still need to ensure that your kernel gets booted by default. Do so by editing the file /etc/default/grub

Change the line

GRUB-DEFAULT=0

to

GRUB-DEFAULT='My super duper kernel 3.11.xxx'

where the quoted string is exactly what is in quotes for the corresponding menuentry in grub.cfg

You may need to run update-grub2 again.

That's it, you're done.

Example:

I have the following kernel and initrd:

vmlinuz-3.11.0-18-generic

initrd.img-3.11.0-18-generic

and want to instead boot the following custom kernel by default

my_super_duper_kernel_3.11

initrd.img-my_super_duper_kernel_3.11

1) I look in /boot/grub/grub/cfg for the current entry. (Note, there seems to be a lot of unessential stuff in each menuentry -- see the end of this post for a bare-bones one).

menuentry 'Ubuntu' --class ubuntu --class gnu-linux --class gnu --class os
$menuentry_id_option 'gnulinux-simple-83af7d46-f6f8-4161-b7a4-47c44de0dd5e' {


... stuff deleted for brevity...

#this specifies first hard disk, first partition (i have a separate /boot partition)    
set root='hd0,msdos1'

linux   /vmlinuz-3.11.0-18-generic root=/dev/mapper/linuxlvm-lvubuntu ro   quiet splash $vt_handoff

initrd  /initrd.img-3.11.0-18-generic

}

2) I append the menuitem to /etc/grub.d/40_custom, substituting a new menuentry name, kernel image, and initrd:

#!/bin/sh
exec tail -n +3 $0
# This file provides an easy way to add custom menu entries.  Simply type the
# menu entries you want to add after this comment.  Be careful not to change
# the 'exec tail' line above.

#menu entry changed. It can be anything as long as it's unique
menuentry 'my_super_duper_kernel_3.11' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-83af7d46-f6f8-4161-b7a4-47c44de0dd5e' {


set root='hd0,msdos1'

#kernel image here must match the one in /boot
linux   /my_super_duper_kernel_3.11 root=/dev/mapper/linuxlvm-lvubuntu ro   quiet 

splash $vt_handoff

#initrd image, if you use one
initrd  /initrd-my_super_duper_kernel_3.11

#don't forget the closing bracket
}

3) run #sudo update-grub2

4) reboot. you should see the new kernel at the bottom of the bootloader list.

5) Make it default by editing the default line in /etc/default/grub. It must exactly match whatever you put in quotes in /etc/grub.d/40_custom right after menuentry=

GRUB-DEFAULT='My super duper kernel 3.11'

6) Not sure if necesary, but won't hurt to re-run `#sudo update-grub2

Background info:

Terminology: `The bootloader is called grub2, but colloquially ppl still call it 'grub'. So if you google for help on the subject, make sure to search specifically for grub2. Googling just 'grub' will bring up some outdated info on the old grub loader (which is still in use, but renamed 'grub-legacy').

How it knows: Grub2 consists of a tiny piece of software (boot.img) that is installed (usually on the MBR of your disk) and has hardcoded into it the locations on your disk of the grub.cfg file and more software (core.img and various *.mod files) which actually boot the linux kernel. So boot.img knows to find core.img, which in turn will read grub.cfg

grub.cfg is generated by the shell script /usr/sbin/update-grub2. It executes all the executable scripts in /etc/grub.d/ (in alphabetical order, so 10_linux gets executed before 40_custom, etc) and sends their outputs to grub.cfg

Barebones file Unless you are using non-standard filesystems or hardware you should only need a few lines to boot a linux kernel on a standard PC with grub. The other stuff is for graphical splash screens and I don't know what else (the following was tested with an ext4 /boot partition and / in lvm-ext4 ):

menuentry 'foo' {
set root='hd0,msdos1' #depends on your partitioning scheme 

linux   /kernel_image root=/dev/mapper/linuxlvm-lvubuntu ro  
#root= should be set to whatever /etc/fstab (or the mount command) says for the device that / is mounted on.

#initrd image, if you use one
initrd  /initrd-my_super_duper_kernel_3.11
}
1

It doesn't know. It only looks for certain files (initrd*, vmlinuz*) inside /boot directory and writes a config file (/boot/grub/grub.cfg). You can update that file using

sudo update-grub2

or

sudo grub2-mkconfig -o /boot/grub/grub.cfg

Then, on the boot stage GRUB looks into the file and uses information it placed there. It's simple.

Example output:

$ sudo update-grub2
Generating grub.cfg ...
Found linux image: /boot/vmlinuz-3.11.0-18-generic
Found initrd image: /boot/initrd.img-3.11.0-18-generic
Found memtest86+ image: /memtest86+.bin
  No volume groups found
done
2
  • I'm sorry, I'm very naive in this. When I opened the grub.cfg file, the first menuentry was the one which is loaded and that menuentry was the one which I had recompiled and loaded. So if I change it to some other image, would it work? I mean would it load the new image?
    – akshay
    Mar 18, 2014 at 7:11
  • You should look into terminal when you compile your kernels. If it shows output like found initrd image... then your new kernel probably will be in the config. But to be sure, just run the sudo update-grub2 each time after you recompile. It is not harmful command.
    – Danatela
    Mar 18, 2014 at 7:17
0

To answer your final question:

You can put the new menuentry anywhere in /etc/grub.d/40_custom.

Then edit /etc/default/grub, and change the DEFAULT to the name of the menuentry that you added to 40_custom. (Using the name rather than a 0-indexed number is best because it allows for the possibility of more kernel images being added or deleted later: see grub2 infopage).

Then make sure to run sudo update-grub2 (or your changes won't be written to grub.cfg).

Reasoning: 40_custom gets added to grub menu underneath any kernel images that grub-update2 finds, so the order within 40_custom won't overide the kernels found by 10_linux.

13
  • Is it grub-update2 or update-grub2 ? and when the value of DEFAULT is changed, do i have to include single-quote or double-quote?
    – akshay
    Mar 18, 2014 at 11:22
  • update-grub2. Single quotes are best, double quotes will work unless your menu name has shell escape characters (*?!` etc).
    – hope
    Mar 18, 2014 at 11:28
  • Not working. I used single-quotes and double-quotes. Dint work in either case. After running update-grub2 i checked uname -r , it was still the same. I even rebooted , nothing changed.
    – akshay
    Mar 18, 2014 at 11:31
  • The grub.cfg file contains set default = the new one which i ve added. But the menuentry is still the same old one.,
    – akshay
    Mar 18, 2014 at 11:34
  • Please post your 40_custom, the results of ls /boot, and the kernel that's booting by default now, and the kernel that you want to be booted. Also you do get a grub menu with a list of kernels right? If not, press and hold shift after the bios prompt.
    – hope
    Mar 18, 2014 at 11:36
0

To elaborate on Danatela's answer, there exist grub-mkconfig helper scripts in /etc/grub.d/ that define where GRUB should look for kernels (10_linux) and if other operating systems that are installed should be included (30_os-prober can be turned off by adding GRUB_DISABLE_OS_PROBER=true to /etc/default/grub).

You could either look at the code in 10_linux to get a glimpse of how GRUB "finds" the kernels and tries to include them, or add your own code to 40_custom, which could be a bit difficult as the 10_linux code looks rather complex and not easy to customize.

1
  • Got it. Anyways i wanted to go back to my previous kernel. I mean i want my grub to load an older kernel instead of the one which it is using. So should i put the previous version's code in 40_custom above than the one there is already? Or how do i make the grub load the previous?
    – akshay
    Mar 18, 2014 at 9:24

You must log in to answer this question.

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