unix
Today

История одного патча II: приключения в FreeBSD

Еще одна поучительная история из жизни открытого ПО, на этот раз про «заимствование» чужих исходников.

Понимаю, что для большинства читателей актуальна только голая баба на фоне, но тем не менее.

Помните, рассказывал об одном досадном баге в ядре Linux, выедавшем мне мозг последние несколько лет?

Внезапно этот же баг проявился в совершенно другой операционной системе, по идее не имеющей к линуксу никакого отношения — FreeBSD.

С чего я знатно прих#ел впал в недоумение, поскольку интернет испокон веков и поныне заполнен срачами интеллектуальными дискуссиями на тему «Linux vs FreeBSD» — их радикальных отличий в самих идеях и концепциях, позиционировании и половой ориентации авторов.

Для тех кто не ходит по ссылкам, напомню суть бага:

Ноутбук засыпает, ноутбук просыпается и батарея «зависает» — перестает отдавать свой статус и уровень заряда.

Ноутбук старый, ноутбук редкий, из тех сказочных времен, в которые подсистема ACPI считалась чем-то новым и еще не до конца проработанным.

Поэтому производители компьютерного оборудования позволяли себе вольности по части поддержки ACPI в своих девайсах. И разумеется описываемый ноутбук (Asus F3Ke) оказался одним из таких.

Не буду повторять тут всю историю поиска решения, занявшего несколько лет — она описана в оригинальной статье и достаточно интересна для чтения.

Расскажу в этот раз про другое:

как бл#ть, каким таким сказочным образом баг в драйвере (!) одной открытой ОС перекочевал в другую открытую ОС.

Напоминаю на всякий случай, что термин «драйвер» — из мира Windows и для Linux/BSD не совсем корректен, поскольку прямого аналога драйверов оборудования в этих ОС нет.

Короче, сказочная х#ня о которой идет речь называется:

ACPICA kernel-resident subsystem

И живет оно внутри ядра, без возможности выгрузки.

Симбиоз

Конечно это не тайное знание и не «секрет полишинеля», что разработчики открытых систем постоянно обмениваются идеями и копируют друг у друга какие-то наработки — это разумно, поскольку в некоторых случаях нет ни смысла ни ресурсов изобретать собственный велосипед.

У проекта FreeBSD долгая история заимствований из Linux, для примера именно таким путем (прямого заимствования) в FreeBSD появился DBus, появился Bluez (поддержка Bluetooth) и много чего еще.

Процесс зашел настолько далеко, что появился и активно развивается отдельный слой эмуляции Linux на уровне ядра, позволяющий запускать практически любые Linux-приложения.

Но к заимствованию из Linux исходного кода целых подсистем, еще и прямо в ядро — к такому я был не готов.

Еще я не был готов к нынешним реалиям — история с ACPICA оказалась несколько глубже и интереснее, чем просто заимствование.

Мы пришли с миром

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

Каталогов contrib несколько, первый находится прямо в корне и содержит внешний исходный код утилит и библиотек, используемых в базовой системе:

Второй contrib находится в каталоге sys и содержит заимствованный код, используемый непосредственно в ядре FreeBSD:

Именно тут находится виновник нашего торжества, в каталоге:

/usr/src/sys/contrib/dev/acpica

Место правки - файл components/events/evregion.c, как видите сохранен даже оригинальный комментарий.

Сама правка и ее причины описаны в первой части:

/*
     * These address spaces do not need a call to _REG, since the ACPI
     * specification defines them as: "must always be accessible". Since
     * they never change state (never become unavailable), no need to ever
     * call _REG on them. Also, a DataTable is not a "real" address space,
     * so do not call _REG. September 2018.
*/
if (
        //(SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY) ||
        (SpaceId == ACPI_ADR_SPACE_SYSTEM_IO) ||
        (SpaceId == ACPI_ADR_SPACE_DATA_TABLE))
 {
        return_VOID;
 }

Единственное заметное отличие — использование другой нотации в именовании переменных.

После правки ядро необходимо пересобрать и установить:

make buildkernel KERNCONF=ALEXS
make installkernel

Напоминаю, что правка находится в подсистеме ACPICA, которая не отделяема и не выгружаема — т. е. монолитная часть ядра FreeBSD.

ACPICA

Мне стало интересно, что же это за неведомая хня, написанная на чистом Си и вот так просто кочующая из одной операционной системы в другую.

Недолгое гугление вывело на сайт проекта и репозиторий на Github:

The ACPI Component Architecture (ACPICA) project provides an open-source operating system-independent implementation of the Advanced Configuration and Power Interface specification (ACPI).

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

А теперь самое интересное, вот так выглядит оригинальный код с проблемным местом, которое я исправлял:

Как видите никаких отличий нет и даже сам комментарий с пояснением как оказалось был перенесен в ядро Linux именно отсюда.

А затем этот же код от Intel был внесен и в кодовую базу FreeBSD.

Прекрасный новый мир, короче.