Нюансы EFI-загрузки Slackware: “прямая” загрузка, ELILO, GRUB2 (в т.ч. поддержка загрузки Windows)

EFI-загрузка Slackware64 14.1 по умолчанию подразумевает установку загрузчика ELILO (EFI Linux boot loader), несмотря на то, что этот тип загрузки с инсталляционного компакт-диска происходит в EFI-совместимом загрузчике GRUB2.
ELILO нормально работает и довольно легко настраивается, однако использование этого загрузчика на Desktop PC может оказаться неудобным, т.к. он не поддерживает EFI-загрузку Windows. В случае совместного использования этих операционных систем на одном компьютере для выбора конкретной системы приходится использовать EFI Boot Manager материнской платы, либо перейти на GRUB2.
Ниже я расскажу о том, как скомпилировать ядро Linux с полной поддержкой EFI-загрузки, настроить ELILO, заменить ELILO на GRUB2 и обеспечить там возможность EFI-загрузки Microsoft Windows.

В этой статье я не буду останавливаться на вопросах формирования образа initrd (initramfs), подразумевая, что в состав собираемого ядра будет включена поддержка всех необходимых для загрузки устройств, файловых систем и т.д. Вопросы initrd рассматриваются по ссылкам, приведенным в конце статьи.
Еще один важный нюанс – при имеющихся плюсах загрузки загрузки ядра напрямую через EFI, имеются и существенные недостатки. В этом варианте загрузки невозможно передать параметры ядру: это возможно сделать лишь через команды оболочки EFI (консоли EFI Boot Manager). При определенных условиях (к примеру, при авариях) данное обстоятельство может сильно осложнить жизнь, следует учитывать эту информацию при выборе способа загрузки.

В приведенных командах предполагается, что в каталог /boot смонтирован раздел /dev/sda1 (EFI-раздел типа EF00), /root/dev/sda3 (за исключением абзаца о загрузке Microsoft Windows), и Slackware64 14.1 уже установлена в режиме EFI-загрузки посредством ELILO. Все приведенные идентификаторы разделов сняты с тестовых станций и не применимы к рабочей конфигурации других компьютеров.

В рассмотренную ранее процедуру сборки ядра необходимо внести следующие изменения.
#make menuconfig
Наряду со всеми требуемыми изменениями нужно включить следующие опции:
Processor type and features -> EFI runtime service support
Processor type and features -> EFI stub support
Processor type and features -> Built-in kernel command line (root=/dev/sda3)

Последняя опция – желаемые параметры загрузки ядра. При использовании таблиц партицирования GPT в качестве точки монтирования root рекомендуют указывать Partition Unique GUID. В этом случае указанный параметр конфигурации ядра приобретает вид root=PARTUUID=E7C44EB1-84B2-4BB7-A63D-8111D0FD57F3. Выяснить Partition Unique GUID можно с помощью команды i программы gdisk /dev/sda.
После внесения необходимых настроек ядро и модули можно компилировать:
#make all
Установить модули:
#make modules_install
Теперь необходимо поместить скомпилированные файлы в требуемый каталог EFI-раздела.
#cp arch/x86/boot/bzImage /boot/efi/EFI/Slackware/vmlinuz-efi
#rm /boot/System.map
#cp System.map /boot/System.map-efi
#ln -s /boot/System.map-efi /boot/System.map

В полученное ядро уже встроен загрузчик, следовательно, его можно загружать, минуя ELILO. Для “прямой” загрузки Slackware необходимо добавить новый пункт в EFI Boot Manager:
#modprobe efivars #модуль ядра, необходимый для работы efibootmgr
#efibootmgr -c -d /dev/sda -l '\EFI\Slackware\vmlinuz-efi' -L 'Slackware-EFI'

В этой команде: -d устройство, содержащее EFI-раздел, -l путь к загрузчику, -L строка меню загрузки.
После перезагрузки можно вызвать EFI Boot Manager, выбрать пункт Slackware-EFI и убедиться в EFI-загрузке Slackware “мимо” ELILO.

Можно также добавить возможность загрузки нескольких ядер из ELILO.
Для этого требуется скопировать файлы, отвечающие за отображение графического меню, в каталог загрузки:
#cp /usr/doc/elilo-3.14/examples/textmenu-chooser/*.msg /boot/efi/EFI/Slackware/
Отредактировать файл конфигурации ELILO, изменив нужным образом параметры, относящиеся к отображению меню, и добавив секцию, описывающую параметры загрузки нового ядра:
#vi /boot/efi/EFI/Slackware/elilo.conf
Файл должен принять примерно следующий вид:
chooser=textmenu
delay=1000
timeout=10
prompt
message=textmenu-message.msg
#
image=vmlinuz
 label=vmlinuz
 description="Original Kernel"
 read-only
 append="root=/dev/sda3 vga-normal ro"
#
image=vmlinuz-efi
 label=vmlinuz-efi
 description="Alternate Kernel"
 read-only
 append="root=/dev/sda3 vga-normal ro"

Теперь при запуске загрузчика ELILO появляется меню выбора загрузки разных ядер. Манипулируя значением параметра append, нетрудно добавить прочие варианты загрузки, в т.ч. в single user mode.

Но я возвращаюсь к основной теме – установке GRUB2 в качестве замены ELILO.
Установить GRUB2:
#grub-install --efi-directory=/boot/efi --bootloader-id=GRUB2
Эта команда скопирует firmware-файл загрузчика в /boot/efi/EFI/GRUB2 (путь определяется совокупностью параметров запуска), создаст необходимые файлы в /boot/grub и добавит новую опцию загрузки в EFI Boot Manager (см. результат выполнения efibootmgr).
Сгенерировать файл конфигурации GRUB2:
#grub-mkconfig -o /boot/grub/grub.cfg
Этот сценарий попытается обнаружить все варианты загрузки. В приведенных условиях он обнаружит ядра huge и generic (в том числе варианты их загрузки в single user mode) в /boot, ядро vmlinuz в каталоге загрузчика ELILO /boot/efi/EFI/Slackware (и варианты загрузки этого ядра, за исключением загрузки посредством самого ELILO).
Существует вероятность того, что grub-mkconfig не обнаружит необходимые варианты загрузки, обнаружив вместо этого неактуальные варианты (старые ядра).
Добавить нужные варианты можно, например, в файле /etc/grub.d/40_custom:
menuentry 'My Slackware' {
root='hd0,gpt1'
linux /EFI/Slackware/slackware-efi root=/dev/sda3 ro
}
menuentry 'My Slackware-EFI' {
root='hd0,gpt1'
chainloader /EFI/Slackware/slackware-efi
}

Не забыть обновить конфигурацию GRUB2:
#grub-mkconfig -o /boot/grub/grub.cfg
После перезагрузки в меню GRUB2 появятся два дополнительных пункта.
В первом пункте новое ядро загружается средствами GRUB2; интегрированный на этапе его сборки EFI-сегмент игнорируется. Этот вариант, в частности, позволяет передать ядру параметры загрузки, перечисленные после команды linux. Путь к ядру указывается относительно пути, объявленного в efi-directory при установке GRUB2.
Во втором пункте GRUB2 передает управление загрузчику, встроенному в ядро; для этого используется команда chainloader. Команду chainloader можно использовать и для передачи управления загрузчику Windows, это будет рассмотрено ниже.
Параметр root=’hd0,gpt1′ относится к разделу, в котором располагается ядро; при этом физические диски hd считаются с нуля, а разделы gpt – с единицы, таким образом /dev/sda1 соответствует ‘hd0,gpt1’, а /dev/sdb3‘hd1,gpt3’.
Важное замечание: в нумерацию дисков, к сожалению, могут вмешиваться установленные устройства CardReader (даже в отсутствие вставленных карт памяти): устройство /dev/sda1 может оказаться, к примеру, ‘hd5,gpt1’, а не ‘hd0,gpt1’. Для того, чтобы понять, какое значение должен принять параметр root, можно в консоли (интерактивном режиме) GRUB2 воспользоваться командой ls, которая выдаст все диски и разделы в нужном формате, и попытаться сориентироваться по ним. Однако есть более эффективное решение – использование уникального GRUB-uuid.
Сначала необходимо выяснить этот uuid:
#grub-probe --target=fs_uuid /boot/efi
Команда вернет нужный uuid, например, такой:
3AB1-15D6 (не следует путать его с uuid, возвращаемым другими программами, в т.ч. gdisk)
Теперь в файле /etc/grub.d/40_custom параметр root= можно заменить на конструкцию search –fs-uuid –set=root 3AB1-15D6. В результате описание пункта меню примет следующий вид:
menuentry 'My Slackware' {
search --fs-uuid --set=root 3AB1-15D6
linux /EFI/Slackware/slackware-efi root=/dev/sda3 ro
}

Проблема определения значения параметра root решена.

Теперь можно перейти к совместному использованию Linux и Windows на одном компьютере.
Необходимо понимать, что при установке двух (и более) операционных систем раздел EFI является общим, вне зависимости от того, устанавливают ОС на различные жесткие диски или на один диск. В качестве примера можно рассмотреть любую произвольную конфигурацию.
Далее предполагается, что на чистый жесткий диск в режиме EFI-загрузки установлена Microsoft Windows 8.1 Pro. Во время ее установки на диске был создан новый раздел NTFS для использования в качестве основного раздела Windows; одновременно операционная система самостоятельно создала EFI-раздел в 100 Мб и раздел MSR для собственных нужд. На EFI-разделе (впоследствии он окажется каталогом /boot/ в Linux) системой создана структура каталогов, в один из которых помещен загрузчик Windows (/boot/efi/EFI/Microsoft/Boot/bootmgfw.efi).
Вслед за Microsoft Windows 8.1 Pro на этот жесткий диск произведена установка Slackware64 14.1: на EFI-раздел при этом были записаны файлы загрузчика ELILO, образы ядер и сопутствующие файлы.
Для обеспечения загрузки обеих операционных систем с помощью GRUB2 сначала необходимо установить этот загрузчик способом, рассмотренным выше.
Теперь необходимо добавить пункт меню, описывающий загрузку Windows, в файл /etc/grub.d/40_custom:
menuentry 'My Windows' {
search --fs-uuid --set=root 3AB1-15D6
chainloader /EFI/Microsoft/Boot/bootmgfw.efi
}

После применения настроек GRUB2 с помощью grub-mkconfig возможность загрузки Windows будет доступна из меню GRUB2.

По окончанию проверки всех нужных вариантов загрузки следует навести порядок на EFI-разделе.
Удалить файлы ненужных ядер и загрузчиков Linux:
– неактуальные ядра generic и huge в /boot, а также соответствующие им файлы System.map- и config-;
– файл загрузчика и конфигурации ELILO – /boot/efi/EFI/Slackware/elilo* и /boot/elilo*.
Если в /etc/grub.d/40_custom были описаны все требуемые варианты загрузки, можно добавить в /etc/default/grub опцию отключения сценария os-prober (автоматическое обнаружение альтернативных вариантов загрузки):
#echo GRUB_DISABLE_OS_PROBER=true >> /etc/default/grub
Нужно помнить, что после любых модификаций преконфигурационных файлов GRUB2 требуется обновить саму конфигурацию GRUB2.
Также необходимо удалить опцию загрузчика ELILO из EFI Boot Manager и установить загрузку GRUB2 по умолчанию:
#modprobe efivars
#efibootmgr
BootCurrent: 0008
Timeout: 0 seconds
BootOrder: 0008,0009,0000,0001,0002,0003,0004,0005,0006,0007
Boot0000* Windows Boot Manager
Boot0001* USB Floppy/CD
Boot0002* USB Hard Drive
Boot0003* ATAPI CD-ROM DRIVE
Boot0004* CD/DVD Drive
Boot0005* USB Floppy/CD
Boot0006* Hard Drive
Boot0007* Realtek PXE B03 D00
Boot0008* GRUB2
Boot0009* Slackware
#efibootmgr --delete-bootnum --bootnum 0009 #Удаление опции загрузки ELILO "Slackware"
#efibootmgr --bootorder 0008,0000 #Определение порядка загрузки, начиная с 0008 - GRUB2.

Further reading:
Замечательная книга Rod Smith “Managing EFI Boot Loaders for Linux”
Компиляция ядра с поддержкой EFI-загрузки на Gentoo
Установка GRUB2 с EFI-загрузкой на Slackware
Файл /boot/initrd.README – мини HOWTO по initrd от Patrick Volkerding
Создание образа initrd с пакетом dmraid

Обновление ядра Slackware64-14.1 до 3.13.1 с одновременным внедрением поддержки ASUS Xonar DG

К сожалению, нынешнее ядро Linux имеет ограниченную поддержку аудиокарты ASUS Xonar DG на чипе C-Media CMI8786. В частности, отсутствует поддержка Front Panel.

В конце 2013 года Роман Волков написал патч к ядру, который сейчас находится в стадии рассмотрения сообществом разработчиков и, вероятно, будет реализован в одной из будущих версий ядра.

Тем временем, я привожу краткий мануал по установке этого патча, а заодно и обновления ядра Slackware64-14.1 до версии 3.13.1. Приводящаяся ниже информация актуальна только для LILO; особенности UEFI-совместимых загрузчиков ELILO/GRUB2 будут рассмотрены позднее.

#cd /usr/src
Скачать архив исходников версии ядра:
#wget https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.13.1.tar.xz
Распаковать архив:
#tar xvf linux-3.13.1.tar.xz
#cd linux-3.13.1

Скачать файлы патча поддержки аудиокарты Xonar DG (копия файлов с сайта Романа Волкова, ссылка в конце статьи):
#wget 'http://bzimage.ru/files/xonardg/0001-xonar-dg-extended-support.patch'
#wget 'http://bzimage.ru/files/xonardg/0002-xonar-dg-extended-support.patch'
#wget 'http://bzimage.ru/files/xonardg/0003-xonar-dg-extended-support.patch'
#wget 'http://bzimage.ru/files/xonardg/0004-xonar-dg-extended-support.patch'

Применить файлы патча:
#patch -p1 <0001-xonar-dg-extended-support.patch
#patch -p1 <0002-xonar-dg-extended-support.patch
#patch -p1 <0003-xonar-dg-extended-support.patch
#patch -p1 <0004-xonar-dg-extended-support.patch

Удалить символическую ссылку на старый каталог исходников ядра:
#rm /usr/src/linux
Создать символическую ссылку на новый каталог исходников ядра:
#ln -s /usr/src/linux-3.13.1 /usr/src/linux
#cd /usr/src/linux

Скопировать действующий конфигурационный файл для сборки исходников.
Примечание: этот файл не поддерживает новые features свежего ядра, поэтому если к моменту установки Patrick Volkerding или кто-либо еще выпустит конфигурационный файл для новой версии, лучше использовать его.
#zcat /proc/config.gz > /usr/src/linux/.config
Применить конфигурацию. Для всех не определенных в конфигурационном файле значений будет задан дополнительный вопрос. Можно нажимать Enter для применения значений по умолчанию, если нет других идей.
#make oldconfig
Примечание: поправить конфигурацию для тех, кто знает, что делает, можно с помощью make menuconfig. Хорошей идеей является присвоение строке релиза ядра, возвращаемой командой uname -a, дополнительной уникальной последовательности символов, к примеру, -mykernel. Для этого существует опция make menuconfig “General setup” -> “Local version – append to kernel release”. Продолжительность компиляции напрямую зависит от количества включаемых в ядро драйверов и др. пакетов. Хорошей практикой считается включение в ядро только необходимых пакетов (действительно использующихся устройств, файловых систем и т.д.), для этого придется детально изучить каждый параметр конфигурации ядра.
Не забыть сохранить изменения конфигурации.
Собрать ядро:
#make bzImage
Собрать модули ядра:
#make modules
Установить модули ядра:
#make modules_install
Скопировать свежесобранное ядро в /boot:
#cp arch/x86/boot/bzImage /boot/vmlinuz-mykernel
Скопировать файл System.map в /boot и поправить символические ссылки. Буква S – прописная, обратите внимание.
#mv System.map /boot/System.map-mykernel
#rm /boot/System.map
#ln -s /boot/System.map-mykernel /boot/System.map

Добавить секцию загрузки нового ядра в /etc/lilo.conf:
#vi /etc/lilo.conf
image = /boot/vmlinuz-mykernel
root = /dev/sda1 #указать свой partition
label = Linux-myfirstkernel
read-only
#lilo

После перезагрузки в менеджере lilo выбрать загрузку с новым ядром и проверить uname -a.
Если все ок, можно исправить ядро по умолчанию в /etc/lilo.conf:
#vi /etc/lilo.conf
default = Linux-myfirstkernel
#lilo

Further reading:
Раздел Slackbook, посвященный компиляции ядра
Руководство по обновлению ядра от Eric Hameleers (alien)
Страница на сайте Романа Волкова, посвященная патчу ядра для поддержки Xonar DG

Исходные данные

Во всех последующих примерах предполагается, что все действия производятся с «чистой» установкой Slackware64-14.1.
Дистрибутив установлен в следующей комплектации:

a base установлено полностью
ap applications установлено полностью
d development установлено полностью
e GNU Emacs установлено полностью
f FAQ/Documentation установлено полностью
k kernel source установлено полностью
kde KDE установлено частично
kdei KDE internationalization установлен пакет l10n для KDE
l libraries установлено полностью
n networking установлено полностью
t TeX не установлено
tcl Tcl/Tk and related установлено полностью
x X Window System установлено полностью
xap X applications установлено частично
xfce Xfce desktop не установлено
y BSD games не установлено

Необходимые tagfiles для автоматической установки доступны здесь.

Further reading:
Раздел Slackbook о составе установки Slackware
Раздел Slackbook, посвященный редактированию tagfiles