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?

akshay
  • 279
  • 6
  • 15

4 Answers4

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
}
hope
  • 456
  • 3
  • 6
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
Danatela
  • 13,243
  • 11
  • 45
  • 72
  • 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 '14 at 07: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 '14 at 07:17
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.

LiveWireBT
  • 28,763
  • 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 '14 at 09:24
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.

hope
  • 456
  • 3
  • 6
  • 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 '14 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 '14 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 '14 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 '14 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 '14 at 11:36
  • 1.40_custom is empty. I haven't changed it. 2.This is the result of ls /boot : initrd.img-3.8.0-37-generic initrd.img-3.8.13.14-qd initrd.img-2.6.30.10 initrd.img-3.8.0-29-generic initrd.img-3.8.0-35-generic initrd.img-3.8.0-36-generic – akshay Mar 18 '14 at 11:38
  • ok, then post the ls /boot and the first few lines of /etc/default/grub (include the DEFAULT line, and the 3 following). Thx. – hope Mar 18 '14 at 11:40
  • default is initrd.img-3.8.13.14-qd i want initrd.img-2.6.30.10 – akshay Mar 18 '14 at 11:42
  • and the /etc/grub/default is

    GRUB_DEFAULT='Ubuntu, with Linux 2.6.30.10' GRUB_HIDDEN_TIMEOUT=0 GRUB_HIDDEN_TIMEOUT_QUIET=true

    – akshay Mar 18 '14 at 11:43
  • comment out the GRUB_HIDDEN_TIMEOUT line (put a # in front of it). That will show the grub prompt on bootup, which is a good thing while you are testing. Your /boot directory doesn't seem to have a vmlinuz-something file (which is wierd). Run cd /boot; sudo file $(ls). Hopefully something in there comes up as "Linux kernel x86 boot executable", which is your kernel image. If not, your kernel image is somewhere else, and I'm not sure what's going on. (kernels are not usually named initrd. They are vmlinuz or vmlinux). – hope Mar 18 '14 at 11:56
  • I'm sorry. I've just added the img files and not the vmlinuz files. Similar vmlinuz files are there as the img files. – akshay Mar 18 '14 at 11:58
  • and i'm using VMWare to run linux. – akshay Mar 18 '14 at 11:59
  • Workaround: boot, holding the shit-key down. That should show you a list of kernels that update-grub2 found. If you want the second entry to boot by default, put GRUB_DEFAULT=1 in /etc/grub/default. If you want the third one, GRUB_DEFAULT=2. etc. Other than that, I can't help you. – hope Mar 18 '14 at 12:07