Поиск таймера обратного отсчета в исходном коде Grub 2.02

Измените тайм-аут Grub на интервалы 1/10 или 1/100 секунды

Использование Grub 2.02 в системе UEFI с архитектурой AMD64. Я хотел бы изменить счетчик тайм-аута grub с интервалов в 1 секунду на интервалы в 1/10 или 1/100 секунды. Причина в том, чтобы сделать gfxmenu круговой обратный отсчет хода менее прерывистым. Загрузочный GIF ниже показывает 5-секундный обратный отсчет круговыми 1-секундными фрагментами:

Загрузка Grub

После успешного изменения исходного кода и перекомпиляции /etc/default/grub будет изменен следующим образом:

  • Если интервал 1/10 секунды, обратный отсчет 2,5 секунды будет GRUB_TIMEOUT=25.
  • если интервал 1/100 секунды, обратный отсчет 2,5 секунды будет GRUB_TIMEOUT=250.

Grub 2.02 Источник - 1/2 миллиона строк

Я загрузил исходный код, как описано здесь: как собрать загрузчик grub2 из исходного кода и протестировать его с помощью эмулятора qemu и потратить время на просмотр исходных файлов. Однако есть 477k строк для поиска:

~/src/grub-2.02$ wc -l **/*

      20 asm-tests/arm.S
      18 asm-tests/i386-pc.S
       4 asm-tests/i386.S
      11 asm-tests/mips.S
       8 asm-tests/powerpc.S
            (... SNIP ...)
     115 util/spkmodem-recv.c
  477316 total

Я реализовал много проектов bash в Ask Ubuntu, но это будет мой первый проект C / Assembler Linux. Как новичок, я думаю:

  • Какой файл содержит исходный код таймера обратного отсчета?
  • Как изменить интервал на 1/10 или 1/100 секунды?
  • Было ли размещение исходного кода в моем домашнем каталоге обычным методом?
  • Любые советы по компиляции и тестированию в Virtualbox были бы полезны.

Обратите внимание, актуален только первый вопрос. Остальные вопросы предназначены для ответов, где автор предпочитает быть более подробными.


person WinEunuuchs2Unix    schedule 14.07.2018    source источник
comment
Хорошее начало - поиск GRUB_TIMEOUT в исходном коде с помощью grep. Это позволяет вам найти, где обрабатывается переменная. Затем прочтите код, который его обрабатывает, и продолжайте оттуда.   -  person fuz    schedule 14.07.2018
comment
Если вы все же внесете это изменение, я бы предложил либо исключить значение с плавающей запятой, либо изменить имя значения конфигурации, чтобы ваши изменения действительно могли быть включены обратно в Grub. Например GRUB_TIMEOUT=2.5 или GRUB_TIMEOUT_MS=2500.   -  person Ross Ridge    schedule 14.07.2018
comment
Я не вижу URL-адреса ваших изменений. Если вы сделаете свое репо где-то доступным, это потенциально может быть полезно для следующего человека, который захочет этого изменения.   -  person Peter Cordes    schedule 16.07.2018
comment
@PeterCordes Осталось изменить только одну строку. Я не уверен, как gitclone все grub и разветвления для синхронизации будущих обновлений grub. Могу я добавить дополнительные инструкции выше?   -  person WinEunuuchs2Unix    schedule 16.07.2018
comment
Ну тогда nvm; Я лишь случайно просмотрел эти вопросы и ответы, не осознавая, что в итоге это было изменение в одну строку, которое вы уже описали в вопросе. (Кстати, публиковать ответы как ответы, а не редактировать вопрос.) Тогда первая строка вашего ответа может быть строкой, которую необходимо изменить (желательно с некоторым контекстом diff)   -  person Peter Cordes    schedule 16.07.2018
comment
@PeterCordes Я поработаю над правильным ответом для загрузки X86 EFI. Пока что решение - это только i386-pc, который я использовал в виртуальной машине. Мне нужна помощь в компиляции grub для разных целей ...   -  person WinEunuuchs2Unix    schedule 16.07.2018


Ответы (2)


Переменная GRUB_TIMEOUT оценивается в util/grub.d/00_header.in.

if [ "x$GRUB_BUTTON_CMOS_ADDRESS" != "x" ]; then
    cat <<EOF
if cmostest $GRUB_BUTTON_CMOS_ADDRESS ; then
EOF
make_timeout "${GRUB_HIDDEN_TIMEOUT_BUTTON}" "${GRUB_TIMEOUT_BUTTON}" "${GRUB_TIMEOUT_STYLE_BUTTON}"
echo else
make_timeout "${GRUB_HIDDEN_TIMEOUT}" "${GRUB_TIMEOUT}" "${GRUB_TIMEOUT_STYLE}"
echo fi
else
make_timeout "${GRUB_HIDDEN_TIMEOUT}" "${GRUB_TIMEOUT}" "${GRUB_TIMEOUT_STYLE}"
fi

Обратите внимание, что это сценарий, который генерирует сценарий, поэтому он выглядит довольно странно. make_timeout выглядит так (там же):

make_timeout ()
{
    if [ "x${3}" != "x" ] ; then
        timeout="${2}"
        style="${3}"
    elif [ "x${1}" != "x" ] && [ "x${1}" != "x0" ] ; then
        # Handle the deprecated GRUB_HIDDEN_TIMEOUT scheme.
        timeout="${1}"
        if [ "x${2}" != "x0" ] ; then
            grub_warn "$(gettext "Setting GRUB_TIMEOUT to a non-zero value when GRUB_HIDDEN_TIMEOUT is set is no longer supported.")"
        fi
        if [ "x${GRUB_HIDDEN_TIMEOUT_QUIET}" = "xtrue" ] ; then
            style="hidden"
            verbose=
        else
            style="countdown"
            verbose=" --verbose"
        fi
    else
        # No hidden timeout, so treat as GRUB_TIMEOUT_STYLE=menu
        timeout="${2}"
        style="menu"
    fi
    cat << EOF
if [ x\$feature_timeout_style = xy ] ; then
  set timeout_style=${style}
  set timeout=${timeout}
EOF
    if [ "x${style}" = "xmenu" ] ; then
        cat << EOF
# Fallback normal timeout code in case the timeout_style feature is
# unavailable.
else
  set timeout=${timeout}
EOF
    else
        cat << EOF
# Fallback hidden-timeout code in case the timeout_style feature is
# unavailable.
elif sleep${verbose} --interruptible ${timeout} ; then
  set timeout=0
EOF
    fi
    cat << EOF
fi
EOF
}

Как видите, он просто вызывает sleep с некоторыми параметрами в конце. Эта команда определена в grub-core/commands/sleep.c. В то время как команда sleep может спать только с шагом в целые секунды, основная функция grub_millisleep может работать лучше.

Эту функцию должно быть легко исправить, изменив все вызовы grub_millisleep(1000) на grub_millisleep(100), но имейте в виду, что это нарушает все способы использования sleep. Более чистый вариант - добавить новую опцию в sleep, чтобы поведение можно было выбирать в каждом конкретном случае.

person fuz    schedule 14.07.2018
comment
Фантастика! Но добавить новую опцию в sleep звучит сложно. Возможно, в модуле gfxmenu я мог бы ввести #def SLEEP_IN_MS (микросекунды), а затем в sleep.c я мог бы вставить #ifdef SLEEP_IN_MS. Где я бы тогда назвал засыпание: grub_interruptible_millisleep (10) и парой строк ниже: grub_millisleep (10). Я предполагаю, что буду компилировать только /grub-core/gfxmenu/gfxmenu.c в /boot/grub/x86_64-efi/gfxmenu.mod, что, надеюсь, означает, что это не повлияет на остальную часть загрузчика grub. - person WinEunuuchs2Unix; 14.07.2018
comment
@ WinEunuuchs2Unix Если вы сделаете это таким образом, все вызовы sleep будут изменены. Добавить вариант не так уж сложно. В самом деле, я считаю это хорошим упражнением. - person fuz; 14.07.2018
comment
Звучит как отличное упражнение для начинающих. То, на что опытному ветерану жратвы потребовалось бы 15 минут, может занять у меня 15+ часов (еще нужно выучить cc + link), но я считаю это хорошей инвестицией в образование. Это как-то поэтично? запуск первого проекта C в grub, который является первой программой, запускаемой после BIOS POST. - person WinEunuuchs2Unix; 14.07.2018
comment
@ WinEunuuchs2Unix Это определенно вам поможет! Добавление новой опции включает изменение массива options. Прочтите код в include/grub/lib/arg.h и grub-core/lib/arg.c, чтобы понять, как это работает. - person fuz; 14.07.2018
comment
@ WinEunuuchs2Unix осторожно, путайте милли и микро :) - person Jester; 14.07.2018
comment
Что ж, на этих выходных проект завершен. Я много узнал о C и grub. Теперь я думаю, что вернусь на время к программированию на bash :) Я обновил свой вопрос решением, но принимаю ваш ответ, потому что вы направили меня в правильном направлении :) - person WinEunuuchs2Unix; 16.07.2018

Благодаря принятому ответу мне удалось достичь цели другим методом. После успешного изменения исходного кода Grub 2.02 и перекомпиляции /etc/default/grub был изменен на 3,5-секундный обратный отсчет с GRUB_TIMEOUT=35.

Обратите внимание, как круговой прогресс теперь плавный, без фрагментов:

Новая загрузка Grub


Код для изменения:

/grub-2.02/grub-core/normal/menu.c

Строка 546:

/* Check whether a second has elapsed since the last tick.  If so, adjust
   the timer and return 1; otherwise, return 0.  */
static int
has_second_elapsed (grub_uint64_t *saved_time)
{
  grub_uint64_t current_time;

  current_time = grub_get_time_ms ();
  /* July 14, 2018 Use deciseconds - change 1000 to 100 */
  if (current_time - *saved_time >= 100)
    {
      *saved_time = current_time;
      return 1;
    }
  else
    return 0;
}

Измените строку:

if (current_time - *saved_time >= 1000)

to:

if (current_time - *saved_time >= 100)

Вуаля! нужно изменить одну строку кода. Плюс две строки комментариев добавлены для удобства.

Как скомпилировать grub 2.02

Прежде чем следовать инструкциям на веб-сайте Grub :

sudo apt install bison
sudo apt install flex

Затем следуйте инструкциям на сайте grub:

cd grub-2.02
./configure

Выполните следующую команду на сайте Grub:

make install

Файлы создаются в /usr/local/bin (сюрприз !!!) вместе с .../grub-2.02 директорией, чего и следовало ожидать.


Разные проблемы при компиляции grub

В итоге я скопировал исходный код в виртуальную машину (Lubuntu 16.04) и перекомпилировал там. Использование недавно скомпилированного grub-install все испортило, и мне пришлось использовать sudo apt install grub2, чтобы получить новую установку. Затем вручную скопируйте вновь скомпилированные файлы в /boot/grub/i386-pc

Моя клеммная коробка перекошена, поэтому мне придется создать новое фоновое изображение grub. На изображении ниже я изменил GRUB_TIMEOUT=35 на обратный отсчет 3,5 секунды.


Обновление от 16 июля 2018 г.

Разобрался с одним параметром, который нужно использовать для получения поддержки X86, EFI:

./configure –with-platform=efi

*******************************************************
GRUB2 will be compiled with following components:
Platform: x86_64-efi
With devmapper support: No (need libdevmapper header)
With memory debugging: No
With disk cache statistics: No
With boot time statistics: No
efiemu runtime: No (not available on efi)
grub-mkfont: No (need freetype2 library)
grub-mount: No (need FUSE library)
starfield theme: No (No build-time grub-mkfont)
With libzfs support: No (need zfs library)
Build-time grub-mkfont: No (need freetype2 library)
Without unifont (no build-time grub-mkfont)
Without liblzma (no support for XZ-compressed mips images) (need lzma library)
*******************************************************

Однако после make install возникает ошибка:

Making install in grub-core
make[2]: Entering directory '/home/rick/src/grub-2.02/grub-core'
gcc -E -DHAVE_CONFIG_H  -Wall -W  -DGRUB_MACHINE_EFI=1 -DGRUB_MACHINE=X86_64_EFI -m64 -nostdinc -isystem /usr/lib/gcc/x86_64-linux-gnu/5/include -I../include -I../include -DGRUB_FILE=\"symlist.h\" -I. -I. -I.. -I.. -I../include -I../include -I../grub-core/lib/libgcrypt-grub/src/   -DGRUB_KERNEL=1 -D_FILE_OFFSET_BITS=64 -DGRUB_SYMBOL_GENERATOR=1 symlist.h > symlist.p || (rm -f symlist.p; exit 1)
symlist.h:25:44: fatal error: ../include/grub/machine/kernel.h: No such file or directory
compilation terminated.
Makefile:42544: recipe for target 'symlist.c' failed
make[2]: *** [symlist.c] Error 1
make[2]: Leaving directory '/home/rick/src/grub-2.02/grub-core'
Makefile:10904: recipe for target 'install-recursive' failed
make[1]: *** [install-recursive] Error 1
make[1]: Leaving directory '/home/rick/src/grub-2.02'
Makefile:11927: recipe for target 'install' failed
make: *** [install] Error 2

Я отправил отчет об ошибке людям из Grub (июль 2018 г.), но ничего не получил в ответ. Следующим шагом для системы EFI является загрузка исходного кода при новой установке с использованием репозиториев Ubuntu вместо инструкций веб-сайта Grub.


person WinEunuuchs2Unix    schedule 02.09.2018