Под капотом загрузчика

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

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

d40e63425550414dd0eefd5a0179bb25.jpg

Что такое загрузчик (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» — мы перевели это как этап, а не уровень).

9b826c698cf6a56b151552a01e536b6b.png

На загрузочном устройстве записан 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. Данные в ней размещаются согласно картинке:

b533b38d68f501d1d92022cfe58763f1.jpg

Давайте посмотрим, как выглядит работа с 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.

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

© Habrahabr.ru