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?
4 Answers
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
}
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
-
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?– akshayMar 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 thesudo update-grub2
each time after you recompile. It is not harmful command.– DanatelaMar 18, 2014 at 7:17
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.
-
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?– akshayMar 18, 2014 at 11:22 -
update-grub2
. Single quotes are best, double quotes will work unless your menu name has shell escape characters (*?!` etc).– hopeMar 18, 2014 at 11:28 -
Not working. I used single-quotes and double-quotes. Dint work in either case. After running
update-grub2
i checkeduname -r
, it was still the same. I even rebooted , nothing changed.– akshayMar 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.,– akshayMar 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.– hopeMar 18, 2014 at 11:36
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.
-
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?– akshayMar 18, 2014 at 9:24