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
}
- 456
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
- 13,384
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.
- 29,597
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.
- 456