Шукати в цьому блозі

вівторок, 17 лютого 2015 р.

DSDT + GRUB2

DSDT - Differentiated System Description Table.

Як правило з цім звіром, DSDT, у першу чергу стикаються ті хто намагається ставити хакінтоши з кловерами, тощо. Що таке ж це за звір - DSDT? Наведу цитату з інструкції по встановленню хакінтошу, можливо й трішечки застарілу, але за змістом взагалі вірну:
„…«дифференцированная таблица описания системы» содержит сведения обо всех ключевых устройствах, из которых состоит компьютер, а также о параметрах и режимах их функционирования“
Взагалі то сучасні Linux-и і без того непогано справляються з отриманням відомостей про пристрої комп'ютера на якому працюють, але якщо є бажання трішечки їм у цьому допомогти то тоді ця замітка для вас.

Є декілька шляхів для досягнення мети.
  1. initrd
  2. додання у ядро
  3. додання у завантажувач (grub2)
Відповідно нам знадобиться grub2. Ставиться він як і завжди, без якихось додаткових танців з бубном, тому зупинятись на цьому кроці особливо не буду.
Далі, додаємо скрипт /etc/grub.d/01_acpi з наступним вмістом:
#!/bin/sh
set -e

# Uncomment to load custom ACPI table
GRUB_CUSTOM_ACPI="/boot/dsdt.aml"


# DON'T MODIFY ANYTHING BELOW THIS LINE!


prefix=/usr
exec_prefix=${prefix}
libdir=${exec_prefix}/lib


#. /usr/share/grub/grub-mkconfig_lib
. /usr/lib/grub/grub-mkconfig_lib
#. ${libdir}/grub/grub-mkconfig_lib


# Load custom ACPI table
if [ x${GRUB_CUSTOM_ACPI} != x ] && [ -f ${GRUB_CUSTOM_ACPI} ] && is_path_readable_by_grub ${GRUB_CUSTOM_ACPI}; then
    echo "Found custom ACPI table: ${GRUB_CUSTOM_ACPI}" >&2
    prepare_grub_to_access_device `${grub_probe} --target=device ${GRUB_CUSTOM_ACPI}` | sed -e "s/^/  /"
    cat << EOF
  acpi (\$root)`make_system_path_relative_to_its_root ${GRUB_CUSTOM_ACPI}`
EOF
fi
Додаємо скрипту атрибут запуску:
chmod +x /etc/grub.d/01_acpi
Основний момент, скомпильована DSDT буде знаходитись у файлі /boot/dsdt.aml. Це логічно, так як саме розділ /boot читається grub-ом, але за бажанням можете спробувати змінити.

Як створити цей самий dsdt.aml? Для початку встановлюємо пакет iasl - Intel ASL compiler/decompiler.
# cd /tmp/
# cat /sys/firmware/acpi/tables/DSDT > dsdt.dat
# iasl -d dsdt.dat
На цьому кроці ми отримали dsdt.dsl. Це звичайний текстовий файл що містить дизасембльований з AML ASL код, який можна редагувати через звичний vim. Після цього можемо спробувати ASL код скомпілювати назад у AML:
# iasl dsdt.dsl
На виході отримаємо dsdt.aml який і перемістимо (чи скопіюємо) у /boot. У ідеальному випадку мета досягнута, але ідеал майже завжди далекий від життя, тому на етапі компіляції майже завжди з'являються помилки. Зазвичай причина полягає у тому що можна спостерігати або недбайливе ставлення виробників заліза до DSDT, або у тому, що більшість з них користується компілятором ASL від MicroSoft, який аж ніяк не гірше за Intel-овський, але в нього не такі жорсткі вимоги щодо використання специфікацій ASL. Тому іноді те, що MicroSoft компілятор спокійно "схаває", а, наприклад, віртуальні машини ACPI спокійно виконають, компілятор від Intel просто відмовиться зібрати. Тому запасаймось терпінням і готуймось приводити dsdt.dsl у відповідність до специфікацій.

Приклад деяких помилок та їх виправлення:
  1. Invalid object type for reserved name (found BUFFER, requires Package)
    У специфікації йде мова про те, що будь-яка змінна (значення для повернення) повинна бути Package, але у ASL-файлі вона позначена як Buffer:
    Name (_PLD, Buffer (0x10)
    {
        /* 0000 */    0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
        /* 0008 */    0x30, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    })
    diff:
    @@ -1,4 +1,4 @@
    -Name (_PLD, Buffer (0x10)
    +Name (_PLD, Package (0x10)
     {
         /* 0000 */    0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
         /* 0008 */    0x30, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  2. Invalid object type for reserved name (found ZERO, requires Buffer)
    Метод повертає 0, хоча вказано, що до повернення очікується тип Buffer:
    Method (_CRS, 0, NotSerialized)
    {
        If (OSFL ())
        {
            Return (Zero)
        }
        Else
        {
            Return (LCRO (^^PCI0.IMAP.PR0E))
        }
    }
    diff:
    @@ -2,7 +2,7 @@
     {
         If (OSFL ())
         {
    -        Return (Zero) // Ошибка тут
    +        Return (Buffer () { Zero })
         }
         Else
         {
  3. Non-hex letters must be upper case
    Маленькі букви використовуються там де повинні б були бути великі.
    Device (WMI0)
    {
        Name (_HID, "pnp0c14")
        // …
    }
    diff:
    @@ -1,5 +1,5 @@
     Device (WMI0)
     {
    -    Name (_HID, "pnp0c14")
    +    Name (_HID, "PNP0C14")
         // …
     }
  4. Invalid combination of Length and Min/Max fixed flags
    У загальному випадку виникає при визначенні поля Length. У наведеному прикладі змінюємо Length 0x00000000 на 0x00000001, так як Length вираховується за формулою:
    Length = Range Maximum - Range Minimum + 1
    DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
        0x00000000,         // Granularity
        0x00000000,         // Range Minimum
        0x00000000,         // Range Maximum
        0x00000000,         // Translation Offset
        0x00000000,         // Length
    ,, _Y1C, AddressRangeMemory, TypeStatic)
    diff:
    @@ -3,6 +3,6 @@
         0x00000000,         // Range Minimum
         0x00000000,         // Range Maximum
         0x00000000,         // Translation Offset
    -    0x00000000,         // Length
    +    0x00000001,         // Length
     ,, _Y1C, AddressRangeMemory, TypeStatic)
Далі про основні типи попереджень. Майте на увазі, що попередження то не є помилка.
  1. Use of compiler reserved name (_T_0)
    Виправляється заміною _T_0 на T_0. Те саме й з _T_1, _T_2 тощо.
  2. Not all control paths return a value
    У методі присутні розгалуження але не всі з них закінчуються Return:
    Method (MP0P, 1, NotSerialized)
    {
        If (LEqual (Arg0, 0x00)) { Return (P0P0) }
        If (LEqual (Arg0, 0x01)) { Return (P0P1) }
        If (LEqual (Arg0, 0x02)) { Return (P0P2) }
        If (LEqual (Arg0, 0x03)) { Return (P0P3) }
        If (LEqual (Arg0, 0x04)) { Return (P0P4) }
    }
    diff:
    @@ -5,5 +5,6 @@
         If (LEqual (Arg0, 0x02)) { Return (P0P2) }
         If (LEqual (Arg0, 0x03)) { Return (P0P3) }
         If (LEqual (Arg0, 0x04)) { Return (P0P4) }
    +    Return (Zero)
     }
  3. Called method may not always return a value
    Майже те саме що й попередній пункт, але тут мова йде про те, що не завжди метод повертає значення.
  4. Possible operator timeout is ignored
    Використання мутексів зрозумілого мало що було знайдено:
    Acquire (MUTE, 0x03E8)
    тому або залишаємо як є, або, якщо попередження мулять очі, змінюємо на наступне:
    Acquire (MUTE, 0xFFFF)
Можуть бути й інші помилки. З часом, можливо, додам і про них інформацію, але у будь-якому разі Google у допомогу ;)

Немає коментарів: