Bootloader? Не, не слышали... Загрузка через EFISTUB без костылей

Опрос

Пользуетесь ли вы UEFI загрузкой?
Да, это стильно-модно-молодежно
Пользовался бы, но нет железа с поддержкой
Нафик оно надо? У меня и так все хорошо
А?
*Предполагается, что ты знаком с основами UEFI и принципом загрузки ОС через него. Это не мануал, а кратко скомпонованные факты. Если не знаешь, как сделать GPT таблицу разделов или отформатировать EFI раздел - кури вики.
*В заметке не будет пространных размышлений о плюсах и минусах UEFI - думайте сами, решайте сами, иметь или не иметь (с).

Итак, приступим.
Что нам нужно, для того, чтобы загрузиться через UEFI (кроме совместимой материнки)?
  1. GPT таблица разделов.
  2. Отформатированный FAT32 (FAT12, FAT16, но это - старье) раздел со специальной сигнатурой C12A7328-F81F-11D2-BA4B-00A0C93EC93B (EFI System Partition - ESP).
  3. UEFI-совместимый бинарник, расположенный на этом разделе. Почему-то считается, что он должен лежать по пути \EFI\${VENDOR}\${LOADER}.efi. Как мы убедимся позже - необязательное условие. Бинарник должен быть правильной платформы: загрузить x86 на x86_64 процессоре не получится.
  4. Опционально: запись BootXXXX в параметрах UEFI, которая указывает на нужный бинарник. По умолчанию загружается \EFI\BOOT\boot[architecture name].efi.
В вики описаны 3 способа загрузки linux через UEFI:
  1. Внешний загрузчик (rEFInd, gummiboot, grub2, syslinux>=6.x, ...), расположенный на ESP разделе - не наш случай. Мы ведь не хотим загрузчик, правда? ;)
  2. Через UEFI Shell - специальный шелл, который может быть уже встроен в UEFI или устанавливаться отдельно на ESP раздел (http://sourceforge.net/apps/mediawiki/tianocore/index.php?title=Welcome). Для этого нам нужно выполнить команды:
    > fs0:
    > cd \EFI\arch
    > vmlinuz-arch.efi root=PARTUUID=3518bb68-d01e-45c9-b973-0b5d918aae96 ro rootfstype=ext4 add_efi_memmap initrd=EFI/arch/initramfs-arch.img
    Или создать специальный MS-DOS подобный скрипт archlinux.nsh в корне ESP:
    echo -on
    \EFI\arch\vmlinuz-arch.efi root=PARTUUID=3518bb68-d01e-45c9-b973-0b5d918aae96 rootfstype=ext4 add_efi_memmap initrd=EFI/arch/initramfs-arch.img
    Тогда можно будет делать так:
    fs0:
    archlinux
    Если назвать этот скрипт startup.nsh (о чем вики скромно умалчивает), то скрипт будет автоматически исполнен через 5 сек (ваш Кэп).
    Последовательность загрузки в этом случае: UEFI -> UEFI Shell -> скрипт -> ядро.
    Слишком много сущностей, тебе не кажется? Еще и ждать. А мы ведь любим целоваться... Вывод: в пень!
  3. Создать запись BootXXXX (XXXX - от 0x0000 до 0xFFFF) в EFI vars с помощью efibootmgr и напрямую передавать управление ядру.
Для того, чтобы пункты 2 и 3 работали, ядро должно быть собрано с особыми параметрами, т.е. прикидываться UEFI бинарником. Эти параметры были добавлены в Linux>=3.3. Они включены по умолчанию в ядро archlinux и некоторые другие ядра из AUR и сторонних реп (linux-ck, например). Тут вырисовывается очевидное ограничение: таким образом не загрузишь x86 систему на x86_64 процессоре (помнишь про это ограничение бинарника UEFI?).

Описывать я буду как раз 3 способ. Что нам советует вики для 2 и 3 случая? Только не спеши повторять!
  1. Создать ESP раздел.
  2. Смонтировать его на /boot/efi
  3. Создать директорию /boot/efi/EFI/arch/
  4. Скопировать ядро и initramfs на ESP раздел
    /boot/vmlinuz-linux -> /boot/efi/EFI/arch/vmlinuz-arch.efi
    /boot/initramfs-linux.img -> /boot/efi/EFI/arch/initramfs-arch.img
    /boot/initramfs-linux-fallback.img -> /boot/efi/EFI/arch/initramfs-arch-fallback.img
Теперь ESP раздел у нас подготовлен. Или нет? А что будет, если ядро обновиться? Опять руками копировать? У вики есть 3 способа для тебя, парень (и да простят меня милые девушки)!
  1. Systemd юнит и path-файл для его активации (следит за изменением файла), которые зачем-то предлагают сохранить в /usr/lib/systemd/system/, вместо предназначенного для пользовательских файлов /etc/systemd/system/ (святотатство-то какое!).
  2. lncron
  3. mkinitcpio hook
Вроде, теперь все хорошо. А в fstab кто за тебя ESP раздел прописывать будет?! Опять вики молчит, как партизанка.

Объединяет эти 3 способа только то, что они - костыли! Это не наш метод, бро! Ты ведь не следовали этим советам, правда? ;)
А что, если сгрузить ядро в корень ESP раздела и монтировать его как /boot, прописав его в BootXXXX запись не как \EFI\arch\vmlinuz-arch.efi, а \vmlinuz-linux? Тогда при обновлении ядра, оно автоматически сгрузиться на ESP раздел, без каких-либо танцев с бубном. А будет ли это работать? Спека по UEFI (12.3.1.3 Directory Structure) говорит, что бинарники должны располагаться в \EFI\${VENDOR}, иначе возможны коллизии имен. Но мы-то сами знаем, что и где у нас лежит на ESP разделе! Как-нибудь уж сами разберемся с коллизиями, чай не маленькие дети. Тест на 2 материнках от разных производителей (Asus P8Z77-I DELUXE и Gigabyte B75-N) показал, что способ вполне себе рабочий. В самом деле: нафик UEFI проверять путь на валидность? Если кто-то его прописал - значит попробуем загрузить!

Итак, план действий:
  1. Копируем vmlinuz-linux, initramfs-linux.img и initramfs-linux-fallback.img (по желанию) в /tmp:
    cp /boot/{vmlinuz-linux,initramfs-linux.img,initramfs-linux-fallback.img} /tmp/
  2. Монтируем ESP раздел на /boot:
    mount <UEFI Partition> /boot
  3. Перемещаем из /tmp на ESP:
    mv /tmp/{vmlinuz-linux,initramfs-linux.img,initramfs-linux-fallback.img} /boot/
  4. Добавляем запись в /etc/fstab:
    UUID=be445405-0426-4e59-8614-c9873d685419 /boot     	vfat      	rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro	0 2
    где be445405-0426-4e59-8614-c9873d685419 - UUID раздела (узнать можно ls -l /dev/disk/by-uuid/).
  5. Добавляем BootXXXX запись с помощью efibootmgr:
    # modprobe efivars
    # efibootmgr -c -d /dev/sdX -p Y -l /vmlinuz-linux -L "Arch Linux" -u "initrd=/initramfs-linux.img root=PARTUUID=087e1626-ccc5-468a-ab8d-ca02f8f04d14 ro add_efi_memmap"
    где sdX - диск с ESP, Y - номер ESP раздела, 087e1626-ccc5-468a-ab8d-ca02f8f04d14 - PARTUUID (≠UUID) root-раздела (ls -l /dev/disk/by-partuuid). Для fallback, если нужно, аналогично.
    Кстати, тут в вики очередной фейл: они указывают "$(cat /proc/cmdline)", в качестве командной строки ядра. При загрузки в не-UEFI режиме или с флешки установщика - там будет не то, что нам нужно!
    АХТУНГ: До версии ядра 3.8 нужно использовать обратные слэши (\) в пути к initramfs. Т.е. путь долже выглядеть так: initrd=\\initramfs-linux.img
  6. Опционально: при успешной загрузке сносим ставшие ненужными файлы с корня:
    umount /boot
    rm /boot/{vmlinuz-linux,initramfs-linux.img,initramfs-linux-fallback.img}
    mount /boot
  7. Выпиваем пару литров божественного компота из хмеля и солода (или морковного сока, по желанию)
Все.

UPD: На хабре вышла довольно подробная статья про загрузку через EFI Boot Stub.

UPD2: Кстати, для тех, кому религия не позволяет хранить ядро и initram в корне UEFI раздела, а делать костыли с systemd, cron'ом или хуком mkinitcpio для синхронизации ядра при его обновлении не хочется, есть еще один способ.
Можно хранить ядро в ESP\EFI\arch, как описано в вики и спецификации UEFI, и монтировать этот путь на /boot через mount --bind.
Забавные приключения.
Укрощать UEFI загрузчик, наверное, довольно увлекательно, хотя я предпочитаю обычный груб в обычном MBR. Это правда работает быстрее?

И да, у вас явно деструктивная рекомендация в конце – если вы удалите каталог /boot , смонтировать в него раздел явно не получится.
P.S.
Ага, вижу, что исправили :)
Спасибо, но... "нет железа" :)
Зачем всё это, зачееееем? (песня какая-то такая была)

Призываю всех переходить сразу к пункту 7.
такие дела.
cucullus
Зачем всё это, зачееееем? (песня какая-то такая была)

Призываю всех переходить сразу к пункту 7.

Я уже :) Кто со мной?
Natrio
Это правда работает быстрее?
Если выключена обратная совместимость с BIOS - то да. У меня -3 секунды к загрузке. Но вообще это зависит от материнки и конкретной реализации UEFI. Ускорение достигается как раз за счет быстрой инициализации устройств.
Natrio
И да, у вас явно деструктивная рекомендация в конце – если вы удалите каталог /boot , смонтировать в него раздел явно не получится.
Это от недосыпа было... Когда перечитывал, понял, какую фигню написал :)
cucullus
Зачем всё это, зачееееем? (песня какая-то такая была)
А незачем. Просто новый комп настраивал и решил поковырять. Чуть быстрее загружаться стал. Минус один пакет в системе (syslinux).
cucullus
Я уже :) Кто со мной?
Вижу, ни у одного меня свободный график ;) Присоединился бы, но предпочитаю это дело real2real xD
Постепенно домашние макбуки-айр мид-2011 мигрируют на Arch. Если на мид-2011 можно вовобще игнорировать имевшийся там раздел ефи, то и так все работате - разве что раздражает белый экран загрузчика Мака - висит, гад, 15с и это исправить не удается.

А вот с Мид-2013 все сложнее. Для начала туда ничего не поставилось, кроме Дебиана (Arch в планах на эти сб-вс) - потому, что броадкомовы дрова вай-фай нужны версии 6.30, каковые были у меня лишь под Деб (или алиеном в rpm). Накурил сам, что можно просто модуль wl подсунуть в lib/... и вай-фай заработает - проверено на Мид-2011.

Загрузчик на Мид-2013 точно какой-то маковский, при сносе efi-раздела (что работало на Мид-2011) система не запускается. На рабочей машине с Деб стоит refit, Efi точно монтируется в boot, причем так - /boot/efi/(EFI + refit + tools), в EFI есть дир. APPLE и деб. ( в самом В чем вопрос? - прошлые попытки что-то изменитьв работе загрузчика кончались тем, что пришлось в режиме восстановления поднимать мак-ось и ставить все по новой, включая полный подъем из бэкапа /home.

Т.о. вопрос - унифиицированы ли системы UEFI разных производителей, не сталкивался ли кто с Маком?

На хабре вышла довольно подробная статья про загрузку через EFI Boot Stub.
Чтобы воспользоваться помощью efibootmgr, надо сначала загрузиться из EFI.
У меня провакационная гипотеза - наше ядро представляет собой комплект из трех файлов, vmlinuz-linux,initramfs-linux.img,initramfs-linux-fallback.img. Предполагается, что vmlinuz-linux уже является файлом, который этот самый efi может воспринять как исполняемый. Сути гипотезы - если vmlinuz-linux переименовать в прописанный уже ефи-загрузчику grubx64.efi и подсунуть системе вместо этого самого исходного в /boot/efi/EFI/disrt/grubx64.efi - пойдет?
 
Зарегистрироваться или войдите чтобы оставить сообщение.