Привет, Хабр!

Мы, сервисные инженеры, сталкиваемся с GRUB2 ежедневно. А вот когда стало любопытно посмотреть на загрузчик комплексно, то в интернете и в учебнике Linux нашли лишь несколько команд: как заново проинсталлировать загрузчик и обновить текущую конфигурацию. «А почему так мало?», — была наша первая мысль.  Решили восполнить пробел — так появилась эта статья. А для иллюстрации попросили нейросетку изобразить, «как выглядят эпичные проблемы с GRUB» -- вот что вышло.

Что такое загрузчик (bootloader)?

Это самая первая запускающаяся программа. Ее цель — загрузить и передать управление ядру. Оно уже завершает инициализацию и запускает операционную систему (ОС).

Можно ли обойтись без загрузчика?

Совсем без него обойтись можно, но это потребует ряд подготовительных шагов:

  • убедиться, что есть UEFI;

  • пересобрать ядро с CONFIG_EFI_STUB, если этот параметр не включен;

  • проверить, чтобы ядро было выше версии 3.1;

  • ответить на вопрос: «Ради чего вы хотите потратить приличное количество времени на это?»

Если загрузчик в вашей системе «съедает» слишком много времени (разница с перечисленными выше операциями составляет 2-3 секунды), то вам придется отказаться от него и обратить внимание на другие статьи.

Какой загрузчик использовать?

В теории у нас достаточно большой выбор загрузочных программ, но на практике многие производители используют какую-то одну. Переход на другой загрузчик можно произвести позже. Если вам любопытно, то большая сравнительная таблица доступна здесь: https://en.wikipedia.org/wiki/Comparison_of_bootloaders. Но нам ближе всего GRUB/GRUB2 по ряду причин:

  • Он универсален и отрабатывает, по cути, все сценарии.

  • Он интерактивен.

  • Он «понимает» файловые системы.

  • Большинство инженеров умеют с ним работать.

  • Этот загрузчик используется по умолчанию для RHEL и подобных ему дистрибутивов. «Кровавый Enterprise» душит креатив, но что поделать.

Мы пишем GRUB/GRUB2, потому как обе версии продолжают существовать, и они немного отличаются. Когда появилась вторая версия этого загрузчика, пользователи были не очень довольны некоторыми изменениями. Так, в GRUB2 стало заметно сложнее что-то прописывать руками, например, в том же интерактивном режиме. Изменился подход производителя к созданию меню, ибо «нечего лазить в настройку руками» J А теперь сравним для примера секции, отвечающие за загрузку ОС.

GRUB:

title Red Hat Enterprise Linux 6 (2.6.32-573.el6.x86_64)
        root (hd0,0)
        kernel /vmlinuz-2.6.32-573.el6.x86_64 ro root=/dev/mapper/vg_rhel6-lv_root rd_NO_LUKS LANG=en_US.UTF-8 rd_NO_MD SYSFONT=latarcyrheb-sun16 rd_LVM_LV=vg_rhel6/lv_swap crashkernel=auto  KEYBOARDTYPE=pc KEYTABLE=us rd_LVM_LV=vg_rhel6/lv_root rd_NO_DM rhgb quiet
        initrd /initramfs-2.6.32-573.el6.x86_64.img

GRUB2:

menuentry 'CentOS Linux (3.10.0-1160.el7.x86_64) 7 (Core)' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-1160.el7.x86_64-advanced-53a77eb0-927d-45ab-a110-1f00713931db' {
        load_video
        set gfxpayload=keep
        insmod gzio
        insmod part_gpt
        insmod xfs
        set root='hd0,gpt2'
        if [ x$feature_platform_search_hint = xy ]; then
          search --no-floppy --fs-uuid --set=root --hint-bios=hd0,gpt2 --hint-efi=hd0,gpt2 --hint-baremetal=ahci0,gpt2  eabdf552-63da-4489-a0db-6a0cdde095b8
        else
          search --no-floppy --fs-uuid --set=root eabdf552-63da-4489-a0db-6a0cdde095b8
        fi
        linuxefi /vmlinuz-3.10.0-1160.el7.x86_64 root=/dev/mapper/centos-root ro crashkernel=auto rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet 
        initrdefi /initramfs-3.10.0-1160.el7.x86_64.img
}

Что ж, со временем все привыкли :(

Звучит очень просто, но можно поподробнее о процессе загрузки?

Начнем с Basic Input Output System (BIOS). После включения питания сервера BIOS принимает управление инициализацией периферического оборудования, выполняет Power on Self Test (POST) и в конце концов переходит к чтению устройства, указанного как загрузочное. Мы не будем погружаться в прерывания BIOS, чтобы не усложнять понимание предмета, и начнем уже с Этапа # 1 (в оригинале «stage» - мы перевели это как этап, а не уровень).

На загрузочном устройстве записан Master Boot Record (MBR) — данные, необходимые для загрузки операционной системы. MBR занимают всего 512 байт. С учетом того, что последние 66 байт зарезервированы под таблицу размещения разделов (Partition Table), для загрузчика остается 446 байт (boot.img). В этот объем трудно поместить что-то сложное и самодостаточное, его задача — найти и запустить уже полноценный загрузчик. Давайте посмотрим, как Этап #1 выглядит на диске. Возьмем пустой диск.

[root@oel78 ~]# dd if=/dev/sde bs=512 count=1 | hexdump -C

[root@oel78 ~]# cat /tmp/header |hexdump -C
00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000200

Создадим там одну партицию:

Hidden text
[root@oel78 ~]# fdisk /dev/sde
Welcome to fdisk (util-linux 2.23.2).

Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

Device does not contain a recognized partition table
Building a new DOS disklabel with disk identifier 0x4abaf638.

Command (m for help): p

Disk /dev/sde: 27.9 GB, 27917287424 bytes, 54525952 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk label type: dos
Disk identifier: 0x4abaf638

   Device Boot      Start         End      Blocks   Id  System

Command (m for help): n
Partition type:
   p   primary (0 primary, 0 extended, 4 free)
   e   extended
Select (default p): p
Partition number (1-4, default 1): 1 
First sector (2048-54525951, default 2048): 
Using default value 2048
Last sector, +sectors or +size{K,M,G} (2048-54525951, default 54525951): +1G
Partition 1 of type Linux and of size 1 GiB is set

Command (m for help): p

Disk /dev/sde: 27.9 GB, 27917287424 bytes, 54525952 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk label type: dos
Disk identifier: 0x4abaf638

   Device Boot      Start         End      Blocks   Id  System
/dev/sde1            2048     2099199     1048576   83  Linux

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.
Syncing disks.

Устанавливаем загрузчик. Важно указать весь диск, а не партицию:

Hidden text
[root@oel78 ~]# grub2-install /dev/sde
Installing for i386-pc platform.
Installation finished. No error reported.

[root@oel78 ~]# file -s /dev/sde
/dev/sde: x86 boot sector; partition 1: ID=0x83, starthead 0, startsector 2048, 2097152 sectors, extended partition table (last)\011, code offset 0x63

[root@oel78 ~]# dd if=/dev/sde of=/tmp/header-mbr |hexdump -C
00000000  eb 63 90 00 00 00 00 00  00 00 00 00 00 00 00 00  |.c..............|
00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000050  00 00 00 00 00 00 00 00  00 00 00 80 01 00 00 00  |................|
00000060  00 00 00 00 ff fa 90 90  f6 c2 80 74 05 f6 c2 70  |...........t...p|
00000070  74 02 b2 80 ea 79 7c 00  00 31 c0 8e d8 8e d0 bc  |t....y|..1......|
00000080  00 20 fb a0 64 7c 3c ff  74 02 88 c2 52 be 05 7c  |. ..d|<.t...R..||
00000090  b4 41 bb aa 55 cd 13 5a  52 72 3d 81 fb 55 aa 75  |.A..U..ZRr=..U.u|
000000a0  37 83 e1 01 74 32 31 c0  89 44 04 40 88 44 ff 89  |7...t21..D.@.D..|
000000b0  44 02 c7 04 10 00 66 8b  1e 5c 7c 66 89 5c 08 66  |D.....f..\|f.\.f|
000000c0  8b 1e 60 7c 66 89 5c 0c  c7 44 06 00 70 b4 42 cd  |..`|f.\..D..p.B.|
000000d0  13 72 05 bb 00 70 eb 76  b4 08 cd 13 73 0d 5a 84  |.r...p.v....s.Z.|
000000e0  d2 0f 83 de 00 be 85 7d  e9 82 00 66 0f b6 c6 88  |.......}...f....|
000000f0  64 ff 40 66 89 44 04 0f  b6 d1 c1 e2 02 88 e8 88  |d.@f.D..........|
00000100  f4 40 89 44 08 0f b6 c2  c0 e8 02 66 89 04 66 a1  |.@.D.......f..f.|
00000110  60 7c 66 09 c0 75 4e 66  a1 5c 7c 66 31 d2 66 f7  |`|f..uNf.\|f1.f.|
00000120  34 88 d1 31 d2 66 f7 74  04 3b 44 08 7d 37 fe c1  |4..1.f.t.;D.}7..|
00000130  88 c5 30 c0 c1 e8 02 08  c1 88 d0 5a 88 c6 bb 00  |..0........Z....|
00000140  70 8e c3 31 db b8 01 02  cd 13 72 1e 8c c3 60 1e  |p..1......r...`.|
00000150  b9 00 01 8e db 31 f6 bf  00 80 8e c6 fc f3 a5 1f  |.....1..........|
00000160  61 ff 26 5a 7c be 80 7d  eb 03 be 8f 7d e8 34 00  |a.&Z|..}....}.4.|
00000170  be 94 7d e8 2e 00 cd 18  eb fe 47 52 55 42 20 00  |..}.......GRUB .|
00000180  47 65 6f 6d 00 48 61 72  64 20 44 69 73 6b 00 52  |Geom.Hard Disk.R|
00000190  65 61 64 00 20 45 72 72  6f 72 0d 0a 00 bb 01 00  |ead. Error......|
000001a0  b4 0e cd 10 ac 3c 00 75  f4 c3 00 00 00 00 00 00  |.....<.u........|
000001b0  00 00 00 00 00 00 00 00  38 f6 ba 4a 00 00 00 00  |........8..J....|
000001c0  01 01 83 3f 20 00 00 08  00 00 00 00 20 00 00 00  |...? ....... ...|
000001d0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000001f0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 55 aa  |..............U.|
00000200 

Как вы видите, “Этап #1” действительно очень маленький.

Этап 1.5 GRUB’а должен находиться в пространстве между MBR и первой партицией. Этот участок исторически оставался нетронутым по техническим причинам. Первая партиция на диске начинается с 63-го сектора. Если нулевой сектор занят MBR, то у нас остается 62 сектора по 512 байт, что в сумме дает нам 31 744 байта. Здесь хранится core.img, являющийся тем самым этапом 1.5 GRUB. Его задача — загрузить драйвер файловой системы для работы со вторым этапом, расположенным в /boot. Посмотреть на Этап #1,5 сложнее, так как там находится просто код драйверов.

Примечание:

Если вы заметили, при создании партиции первым был 2048 сектор, а не 63-й:

Partition number (1-4, default 1): 1 

First sector (2048-54525951, default 2048): 

Using default value 2048

Это избыточно и уходит корнями в работу fdisk и его неудержимое желание выравнивать границы по “трекам” (http://jdebp.info./FGA/disc-partition-alignment.html).

Что делать, если у нас не MBR, а GPT?

Хороший вопрос, но давайте добавим сюда еще и UEFI, чтобы «два раза не вставать». Схема GPT пришла на смену MBR и в основном используется совместно с EFI/UEFI (в свою очередь, заменил BIOS), но также возможно использование и с BIOS. Данные в ней размещаются согласно картинке:

Давайте посмотрим, как выглядит работа с GPT стандартными утилитами:

Hidden text
[root@oel78 ~]# gdisk /dev/sdf
GPT fdisk (gdisk) version 0.8.10

Partition table scan:
  MBR: not present
  BSD: not present
  APM: not present
  GPT: not present

Creating new GPT entries.

Command (? for help): p
Disk /dev/sdf: 2097152 sectors, 1024.0 MiB
Logical sector size: 512 bytes
Disk identifier (GUID): B4B6ADC2-581E-4AC7-BED9-A1FDBE8E0EB7
Partition table holds up to 128 entries
First usable sector is 34, last usable sector is 2097118
Partitions will be aligned on 2048-sector boundaries
Total free space is 2097085 sectors (1024.0 MiB)

Number  Start (sector)    End (sector)  Size       Code  Name

Command (? for help): n
Partition number (1-128, default 1): 
First sector (34-2097118, default = 2048) or {+-}size{KMGTP}: 
Last sector (2048-2097118, default = 2097118) or {+-}size{KMGTP}: +500M
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300):  
Changed type of partition to 'Linux filesystem'

Command (? for help): p
Disk /dev/sdf: 2097152 sectors, 1024.0 MiB
Logical sector size: 512 bytes
Disk identifier (GUID): B4B6ADC2-581E-4AC7-BED9-A1FDBE8E0EB7
Partition table holds up to 128 entries
First usable sector is 34, last usable sector is 2097118
Partitions will be aligned on 2048-sector boundaries
Total free space is 1073085 sectors (524.0 MiB)

Number  Start (sector)    End (sector)  Size       Code  Name
   1            2048         1026047   500.0 MiB   8300  Linux filesystem

Command (? for help): w

Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING
PARTITIONS!!

Do you want to proceed? (Y/N): Y
OK; writing new GUID partition table (GPT) to /dev/sdf.
The operation has completed successfully.

При повторном использовании gdisk у нас уже будут и Protective MBR, и GPT:

[root@oel78 ~]# gdisk /dev/sdf
GPT fdisk (gdisk) version 0.8.10

Partition table scan:
  MBR: protective
  BSD: not present
  APM: not present
  GPT: present

Found valid GPT with protective MBR; using GPT.

Command (? for help):

Давайте посмотрим на партиции:

Hidden text
Command (? for help): i
Using 1
Partition GUID code: 0FC63DAF-8483-4772-8E79-3D69D8477DE4 (Linux filesystem)
Partition unique GUID: 00952D54-85EB-464A-A288-1B81C5F55D5C
First sector: 2048 (at 1024.0 KiB)
Last sector: 1026047 (at 501.0 MiB)
Partition size: 1024000 sectors (500.0 MiB)
Attribute flags: 0000000000000000
Partition name: 'Linux filesystem'

Command (? for help):

[root@oel78 ~]# dd if=/dev/sdf of=/tmp/header-sdf bs=512 count=3

[root@oel78 ~]# cat /tmp/header-sdf | hexdump -C
00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000001c0  02 00 ee 05 e1 f3 01 00  00 00 ff ff 1f 00 00 00  |................|
000001d0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000001f0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 55 aa  |..............U.|
00000200  45 46 49 20 50 41 52 54  00 00 01 00 5c 00 00 00  |EFI PART....\...|
00000210  54 d3 27 b6 00 00 00 00  01 00 00 00 00 00 00 00  |T.'.............|
00000220  ff ff 1f 00 00 00 00 00  22 00 00 00 00 00 00 00  |........".......|
00000230  de ff 1f 00 00 00 00 00  c2 ad b6 b4 1e 58 c7 4a  |.............X.J|
00000240  be d9 a1 fd be 8e 0e b7  02 00 00 00 00 00 00 00  |................|
00000250  80 00 00 00 80 00 00 00  8d 24 88 fa 00 00 00 00  |.........$......|
00000260  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000400  af 3d c6 0f 83 84 72 47  8e 79 3d 69 d8 47 7d e4  |.=....rG.y=i.G}.|
00000410  54 2d 95 00 eb 85 4a 46  a2 88 1b 81 c5 f5 5d 5c  |T-....JF......]\|
00000420  00 08 00 00 00 00 00 00  ff a7 0f 00 00 00 00 00  |................|
00000430  00 00 00 00 00 00 00 00  4c 00 69 00 6e 00 75 00  |........L.i.n.u.|
00000440  78 00 20 00 66 00 69 00  6c 00 65 00 73 00 79 00  |x. .f.i.l.e.s.y.|
00000450  73 00 74 00 65 00 6d 00  00 00 00 00 00 00 00 00  |s.t.e.m.........|
00000460  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*


[root@oel78 ~]# grub2-install /dev/sdf
Installing for i386-pc platform.
grub2-install: warning: this GPT partition label contains no BIOS Boot Partition; embedding won't be possible.
grub2-install: error: embedding is not possible, but this is required for cross-disk install.



[root@oel78 ~]# gdisk /dev/sdf
GPT fdisk (gdisk) version 0.8.10

Partition table scan:
  MBR: protective
  BSD: not present
  APM: not present
  GPT: present

Found valid GPT with protective MBR; using GPT.

Command (? for help): ?
b       back up GPT data to a file
c       change a partition's name
d       delete a partition
i       show detailed information on a partition
l       list known partition types
n       add a new partition
o       create a new empty GUID partition table (GPT)
p       print the partition table
q       quit without saving changes
r       recovery and transformation options (experts only)
s       sort partitions
t       change a partition's type code
v       verify disk
w       write table to disk and exit
x       extra functionality (experts only)
?       print this menu

Command (? for help): n
Partition number (2-128, default 2): 
First sector (34-2097118, default = 1026048) or {+-}size{KMGTP}: 
Last sector (1026048-2097118, default = 2097118) or {+-}size{KMGTP}: +200M
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): 
Changed type of partition to 'Linux filesystem'

Command (? for help): 
Command (? for help): p
Disk /dev/sdf: 2097152 sectors, 1024.0 MiB
Logical sector size: 512 bytes
Disk identifier (GUID): B4B6ADC2-581E-4AC7-BED9-A1FDBE8E0EB7
Partition table holds up to 128 entries
First usable sector is 34, last usable sector is 2097118
Partitions will be aligned on 2048-sector boundaries
Total free space is 663485 sectors (324.0 MiB)

Number  Start (sector)    End (sector)  Size       Code  Name
   1            2048         1026047   500.0 MiB   8300  Linux filesystem
   2         1026048         1435647   200.0 MiB   8300  Linux filesystem

Command (? for help): 2
b       back up GPT data to a file
c       change a partition's name
d       delete a partition
i       show detailed information on a partition
l       list known partition types
n       add a new partition
o       create a new empty GUID partition table (GPT)
p       print the partition table
q       quit without saving changes
r       recovery and transformation options (experts only)
s       sort partitions
t       change a partition's type code
v       verify disk
w       write table to disk and exit
x       extra functionality (experts only)
?       print this menu

Command (? for help): t
Partition number (1-2): 2
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): ef02
Changed type of partition to 'BIOS boot partition'

Command (? for help): w

Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING
PARTITIONS!!

Do you want to proceed? (Y/N): Y
OK; writing new GUID partition table (GPT) to /dev/sdf.
The operation has completed successfully

Теперь у нас получается инсталлировать загрузчик:

Hidden text
[root@oel78 ~]# grub2-install /dev/sdf
Installing for i386-pc platform.
Installation finished. No error reported.


[root@oel78 ~]# cat /tmp/header-sdf-2 | hexdump -C
00000000  eb 63 90 00 00 00 00 00  00 00 00 00 00 00 00 00  |.c..............|
00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000050  00 00 00 00 00 00 00 00  00 00 00 80 00 a8 0f 00  |................|
00000060  00 00 00 00 ff fa 90 90  f6 c2 80 74 05 f6 c2 70  |...........t...p|
00000070  74 02 b2 80 ea 79 7c 00  00 31 c0 8e d8 8e d0 bc  |t....y|..1......|
00000080  00 20 fb a0 64 7c 3c ff  74 02 88 c2 52 be 05 7c  |. ..d|<.t...R..||
00000090  b4 41 bb aa 55 cd 13 5a  52 72 3d 81 fb 55 aa 75  |.A..U..ZRr=..U.u|
000000a0  37 83 e1 01 74 32 31 c0  89 44 04 40 88 44 ff 89  |7...t21..D.@.D..|
000000b0  44 02 c7 04 10 00 66 8b  1e 5c 7c 66 89 5c 08 66  |D.....f..\|f.\.f|
000000c0  8b 1e 60 7c 66 89 5c 0c  c7 44 06 00 70 b4 42 cd  |..`|f.\..D..p.B.|
000000d0  13 72 05 bb 00 70 eb 76  b4 08 cd 13 73 0d 5a 84  |.r...p.v....s.Z.|
000000e0  d2 0f 83 de 00 be 85 7d  e9 82 00 66 0f b6 c6 88  |.......}...f....|
000000f0  64 ff 40 66 89 44 04 0f  b6 d1 c1 e2 02 88 e8 88  |d.@f.D..........|
00000100  f4 40 89 44 08 0f b6 c2  c0 e8 02 66 89 04 66 a1  |.@.D.......f..f.|
00000110  60 7c 66 09 c0 75 4e 66  a1 5c 7c 66 31 d2 66 f7  |`|f..uNf.\|f1.f.|
00000120  34 88 d1 31 d2 66 f7 74  04 3b 44 08 7d 37 fe c1  |4..1.f.t.;D.}7..|
00000130  88 c5 30 c0 c1 e8 02 08  c1 88 d0 5a 88 c6 bb 00  |..0........Z....|
00000140  70 8e c3 31 db b8 01 02  cd 13 72 1e 8c c3 60 1e  |p..1......r...`.|
00000150  b9 00 01 8e db 31 f6 bf  00 80 8e c6 fc f3 a5 1f  |.....1..........|
00000160  61 ff 26 5a 7c be 80 7d  eb 03 be 8f 7d e8 34 00  |a.&Z|..}....}.4.|
00000170  be 94 7d e8 2e 00 cd 18  eb fe 47 52 55 42 20 00  |..}.......GRUB .|
00000180  47 65 6f 6d 00 48 61 72  64 20 44 69 73 6b 00 52  |Geom.Hard Disk.R|
00000190  65 61 64 00 20 45 72 72  6f 72 0d 0a 00 bb 01 00  |ead. Error......|
000001a0  b4 0e cd 10 ac 3c 00 75  f4 c3 00 00 00 00 00 00  |.....<.u........|
000001b0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000001c0  02 00 ee 05 e1 f3 01 00  00 00 ff ff 1f 00 00 00  |................|
000001d0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000001f0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 55 aa  |..............U.|
00000200  45 46 49 20 50 41 52 54  00 00 01 00 5c 00 00 00  |EFI PART....\...|
00000210  25 38 90 a1 00 00 00 00  01 00 00 00 00 00 00 00  |%8..............|
00000220  ff ff 1f 00 00 00 00 00  22 00 00 00 00 00 00 00  |........".......|
00000230  de ff 1f 00 00 00 00 00  c2 ad b6 b4 1e 58 c7 4a  |.............X.J|
00000240  be d9 a1 fd be 8e 0e b7  02 00 00 00 00 00 00 00  |................|
00000250  80 00 00 00 80 00 00 00  66 63 9c 9a 00 00 00 00  |........fc......|
00000260  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000400  af 3d c6 0f 83 84 72 47  8e 79 3d 69 d8 47 7d e4  |.=....rG.y=i.G}.|
00000410  54 2d 95 00 eb 85 4a 46  a2 88 1b 81 c5 f5 5d 5c  |T-....JF......]\|
00000420  00 08 00 00 00 00 00 00  ff a7 0f 00 00 00 00 00  |................|
00000430  00 00 00 00 00 00 00 00  4c 00 69 00 6e 00 75 00  |........L.i.n.u.|
00000440  78 00 20 00 66 00 69 00  6c 00 65 00 73 00 79 00  |x. .f.i.l.e.s.y.|
00000450  73 00 74 00 65 00 6d 00  00 00 00 00 00 00 00 00  |s.t.e.m.........|
00000460  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000480  48 61 68 21 49 64 6f 6e  74 4e 65 65 64 45 46 49  |Hah!IdontNeedEFI|
00000490  8a 24 28 d6 d9 01 20 49  8a 8e 48 2c d9 ab 9a bb  |.$(... I..H,....|
000004a0  00 a8 0f 00 00 00 00 00  ff e7 15 00 00 00 00 00  |................|
000004b0  00 00 00 00 00 00 00 00  42 00 49 00 4f 00 53 00  |........B.I.O.S.|
000004c0  20 00 62 00 6f 00 6f 00  74 00 20 00 70 00 61 00  | .b.o.o.t. .p.a.|
000004d0  72 00 74 00 69 00 74 00  69 00 6f 00 6e 00 00 00  |r.t.i.t.i.o.n...|
000004e0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000600

Немного конфигураций

 По сути, все возможные конфигурации можно описать следующим образом:

· BIOS и MBR.

· BIOS и GPT.

· EFI и MBR.

· EFI и GPT.

BIOS и MBR. Это самая привычная и традиционная конфигурация, описанная ранее.

BIOS и GPT. В этом варианте у нас также первый этап загрузки расположен в MBR (что для GPT известно как protective MBR — своеобразная «метка», призванная защитить диск от приложений, не умеющих работать с GPT). Дальше GRUB использует BIOS Boot Partition, имеющую GPT-метку 21686148-6449-6E6F-744E. Дополнительные файлы по-прежнему находятся в директории /boot/grub так же, как и в комбинации BIOS и MBR.

EFI и MBR. В этой конфигурации первый этап (GRUB EFI — бинарный файл) расположен в EFI System Partition (ESP; тип 0xEF на MBR диске). Данный файл может называться как угодно, но обычно используется grubx64.efi в поддиректории /boot/efi/EFI/redhat/.

EFI и GPT. Данная конфигурация, по сути, аналогична предыдущей, за исключением того, что у ESP тип кода выглядит так: C12A7328-F81F-11D2-BA4B-00A0C93EC93B. Сейчас это самое распространенное сочетание.

Как работать с GRUB2

GRUB2 самостоятельно определяет имеющиеся ядра, файлы initramfs в /boot/ и создает для них записи в меню загрузчика. Это происходит либо автоматически после установки новой версии ядра, либо выполняется вручную командой grub2-mkconfig.

Например, было:

Hidden text
# grep -A 10 "menuentry 'CentOS" grub.cfg

menuentry 'CentOS Linux (3.10.0-1160.el7.x86_64) 7 (Core)' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-1160.el7.x86_64-advanced-53a77eb0-927d-45ab-a110-1f00713931db' {
	load_video
	set gfxpayload=keep
	insmod gzio
	insmod part_gpt
	insmod xfs
	set root='hd0,gpt2'
	if [ x$feature_platform_search_hint = xy ]; then
	  search --no-floppy --fs-uuid --set=root --hint-bios=hd0,gpt2 --hint-efi=hd0,gpt2 --hint-baremetal=ahci0,gpt2  eabdf552-63da-4489-a0db-6a0cdde095b8
	else
	  search --no-floppy --fs-uuid --set=root eabdf552-63da-4489-a0db-6a0cdde095b8
--
menuentry 'CentOS Linux (0-rescue-f1e78ff605dd47a3bc0839d240d643c6) 7 (Core)' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-0-rescue-f1e78ff605dd47a3bc0839d240d643c6-advanced-53a77eb0-927d-45ab-a110-1f00713931db' {
	load_video
	insmod gzio
	insmod part_gpt
	insmod xfs
	set root='hd0,gpt2'
	if [ x$feature_platform_search_hint = xy ]; then
	  search --no-floppy --fs-uuid --set=root --hint-bios=hd0,gpt2 --hint-efi=hd0,gpt2 --hint-baremetal=ahci0,gpt2  eabdf552-63da-4489-a0db-6a0cdde095b8
	else
	  search --no-floppy --fs-uuid --set=root eabdf552-63da-4489-a0db-6a0cdde095b8
	fi

Устанавливаем новое ядро:

Hidden text
[root@server-centos centos]# yum update kernel
Loaded plugins: fastestmirror, langpacks, product-id, search-disabled-repos, subscription-manager, versionlock

This system is not registered with an entitlement server. You can use subscription-manager to register.

Loading mirror speeds from cached hostfile
 * base: mirror.yandex.ru
 * elrepo: lon.mirror.rackspace.com
 * elrepo-extras: lon.mirror.rackspace.com
 * elrepo-kernel: lon.mirror.rackspace.com
 * elrepo-testing: lon.mirror.rackspace.com
 * epel: mirror.cloudhosting.lv
 * extras: mirror.yandex.ru
 * updates: mirror.hyperdedic.ru
Resolving Dependencies
--> Running transaction check
---> Package kernel.x86_64 0:3.10.0-1160.114.2.el7 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

==================================================================================================================================================================================================================
 Package                                       Arch                                          Version                                                         Repository                                      Size
==================================================================================================================================================================================================================
Installing:
 kernel                                        x86_64                                        3.10.0-1160.114.2.el7                                           updates                                         52 M

Transaction Summary
==================================================================================================================================================================================================================
Install  1 Package

Total size: 52 M
Installed size: 66 M
Is this ok [y/d/N]: y
Downloading packages:
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  Installing : kernel-3.10.0-1160.114.2.el7.x86_64                                                                                                                                                            1/1 
  Verifying  : kernel-3.10.0-1160.114.2.el7.x86_64                                                                                                                                                            1/1 

Installed:
  kernel.x86_64 0:3.10.0-1160.114.2.el7                                                                                                                                                                           

Complete!

Получаем новую запись:

Hidden text
# grub2-mkconfig | grep -A 10 "menuentry 'CentOS"           

menuentry 'CentOS Linux (3.10.0-1160.114.2.el7.x86_64) 7 (Core)' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-1160.114.2.el7.x86_64-advanced-53a77eb0-927d-45ab-a110-1f00713931db' {
	load_video
	set gfxpayload=keep
	insmod gzio
	insmod part_gpt
	insmod xfs
	set root='hd0,gpt2'
	if [ x$feature_platform_search_hint = xy ]; then
	  search --no-floppy --fs-uuid --set=root --hint-bios=hd0,gpt2 --hint-efi=hd0,gpt2 --hint-baremetal=ahci0,gpt2  eabdf552-63da-4489-a0db-6a0cdde095b8
	else
	  search --no-floppy --fs-uuid --set=root eabdf552-63da-4489-a0db-6a0cdde095b8

menuentry 'CentOS Linux (3.10.0-1160.el7.x86_64) 7 (Core)' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-1160.el7.x86_64-advanced-53a77eb0-927d-45ab-a110-1f00713931db' {
	load_video
	set gfxpayload=keep
	insmod gzio
	insmod part_gpt
	insmod xfs
	set root='hd0,gpt2'
	if [ x$feature_platform_search_hint = xy ]; then
	  search --no-floppy --fs-uuid --set=root --hint-bios=hd0,gpt2 --hint-efi=hd0,gpt2 --hint-baremetal=ahci0,gpt2  eabdf552-63da-4489-a0db-6a0cdde095b8
	else
	  search --no-floppy --fs-uuid --set=root eabdf552-63da-4489-a0db-6a0cdde095b8

menuentry 'CentOS Linux (0-rescue-f1e78ff605dd47a3bc0839d240d643c6) 7 (Core)' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-0-rescue-f1e78ff605dd47a3bc0839d240d643c6-advanced-53a77eb0-927d-45ab-a110-1f00713931db' {
	load_video
	insmod gzio
	insmod part_gpt
	insmod xfs
	set root='hd0,gpt2'
	if [ x$feature_platform_search_hint = xy ]; then
	  search --no-floppy --fs-uuid --set=root --hint-bios=hd0,gpt2 --hint-efi=hd0,gpt2 --hint-baremetal=ahci0,gpt2  eabdf552-63da-4489-a0db-6a0cdde095b8
	else
	  search --no-floppy --fs-uuid --set=root eabdf552-63da-4489-a0db-6a0cdde095b8
	fi
done

На самом деле при выполнении grub2-mkconfig он генерирует конфигурационный файл так:

1)      Инспектирует содержимое /boot/.

2)      Смотрит на скрипты в /etc/grub.d/:

# ls -la /etc/grub.d/
total 88
drwx------.   2 root root   182 Apr 10  2023 .
drwxr-xr-x. 158 root root 12288 Apr 14 23:16 ..
-rwxr-xr-x.   1 root root  8702 Dec 16  2022 00_header
-rwxr-xr-x.   1 root root  1043 Mar 22  2019 00_tuned
-rwxr-xr-x.   1 root root   232 Dec 16  2022 01_users
-rwxr-xr-x.   1 root root 10781 Dec 16  2022 10_linux
-rwxr-xr-x.   1 root root 10275 Dec 16  2022 20_linux_xen
-rwxr-xr-x.   1 root root  2559 Dec 16  2022 20_ppc_terminfo
-rwxr-xr-x.   1 root root 11169 Dec 16  2022 30_os-prober
-rwxr-xr-x.   1 root root   214 Dec 16  2022 40_custom
-rwxr-xr-x.   1 root root   216 Dec 16  2022 41_custom
-rw-r--r--.   1 root root   483 Dec 16  2022 README

3)      Использует значения из /etc/default/grub.

Только после этого мы получаем конфигурационный файл.

Типовые задачи и их решение

Q: Как сделать, чтобы GRUB2 использовал по умолчанию определенный пункт меню?

A: Нужно воспользоваться утилитой grubby:

# grubby --info=ALL
index=0
kernel=/boot/vmlinuz-3.10.0-1160.114.2.el7.x86_64
args="ro crashkernel=auto rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet LANG=en_US.UTF-8"
root=/dev/mapper/centos-root
initrd=/boot/initramfs-3.10.0-1160.114.2.el7.x86_64.img
title=CentOS Linux (3.10.0-1160.114.2.el7.x86_64) 7 (Core)
index=1
kernel=/boot/vmlinuz-3.10.0-1160.el7.x86_64
args="ro crashkernel=auto rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet LANG=en_US.UTF-8"
root=/dev/mapper/centos-root
initrd=/boot/initramfs-3.10.0-1160.el7.x86_64.img
title=CentOS Linux (3.10.0-1160.el7.x86_64) 7 (Core)
index=2
kernel=/boot/vmlinuz-0-rescue-f1e78ff605dd47a3bc0839d240d643c6
args="ro crashkernel=auto rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet"
root=/dev/mapper/centos-root
initrd=/boot/initramfs-0-rescue-f1e78ff605dd47a3bc0839d240d643c6.img
title=CentOS Linux (0-rescue-f1e78ff605dd47a3bc0839d240d643c6) 7 (Core)
index=3
non linux entry

# grubby --set-default-index=1
# grubby --default-kernel
/boot/vmlinuz-3.10.0-1160.el7.x86_64

Q: Что делать, если загрузчик поврежден?

A: Мы можем проинсталлировать его заново командой grub2-install, загрузив операционную систему с установочного диска. Главное — помнить, что в качестве аргумента нужно использовать весь диск, а не просто раздел boot (в случае BIOS и MBR). Вы же помните, где находится первый этап загрузки?

Для UEFI можно переинсталлировать пакеты:

# yum reinstall grub2-efi shim

# reboot

Q: Как пересобрать конфигурацию GRUB2?

A: Просто командой grub2-mkconfig > /boot/grub2/grub.cfg.

Мы постарались собрать все аспекты работы загрузчика. По нашему опыту, при проблемах недостаточно знать только одну команду — решение требует комплексного знания предмета. Ну и нам было просто интересно. Ведь хороший сервисный инженер – это любопытный сервисный инженер.

Комментарии (18)


  1. radioxoma
    10.06.2024 17:45
    +2

    GRUB2 переусложнён и... не нужен? На десктопе достаточно refind (удобно иметь efi shell, gdisk, красивости, менять параметры ядра не загружая ОС) или голого efistub (обманчивая простота арча).
    Штатный mkinitcpio может сразу упаковать всё (ядро, рамдиск, cmdline, splash image) в один efi executable и в esp положить. Перешёл на efistub, чтобы работал SecureBoot и недоверенные ОС вроде Windows не могли загружаться.


    1. redfox0
      10.06.2024 17:45

      systemd-boot ещё.


      1. radioxoma
        10.06.2024 17:45

        Когда смотрел, не понял чем он может быть удобен. Ну, кроме претензий на дефолтность из-за systemd в названии.
        Refind был любовью с первого взгляда. До сих пор в esp валяется ради легкого доступа к shell и gdisk, хоть и везде уже UEFI грузит efistub напрямую.


  1. hogstaberg
    10.06.2024 17:45
    +2

    • убедиться, что есть UEFI;

    • пересобрать ядро с CONFIG_EFI_STUB, если этот параметр не включен;

    • проверить, чтобы ядро было выше версии 3.1;

    • ответить на вопрос: «Ради чего вы хотите потратить приличное количество времени на это?»

    Последний пункт - сильное заявление, учитывая, что в современном мире прям нечасто встретишь кейс когда система не проходит по первым трём пунктам из коробки. В 99% случаев grub - пятое колесо у телеги и даром не сдался. Но все почему-то упорно продолжают жрать этот кактус.

    А уж всё безумие утилит и мест, которые нужно крутить и править в современном rhel с uefi загрузкой - это вообще мрак и тлен.


    1. radioxoma
      10.06.2024 17:45

      Стаья давно плесенью покрылась. Ещё бы LILO вспомнили.
      MBR в 2024 году? Я все машины (Arch + Win7) >5 лет назад на GPT перевёл без переустановки.


      1. hogstaberg
        10.06.2024 17:45

        Вы таки не поверите что используют до сих пор во всяких энтерпрайзных rhel-like дистрибутивах. И нет, mbr там тоже не пахнет, но вот grub пихают с упорством, достойным лучшего применения.


    1. JetHabr Автор
      10.06.2024 17:45
      +2

      У ряда дистрибутивов "кактус" входит в заводскую комплектацию и тратить силы на его выкорчевывание совсем не хочется.


  1. vvzvlad
    10.06.2024 17:45

    А зачем груб, если в UEFI есть примерно такое же меню?