Microsoft раскрыла технические аспекты реализации подсистемы Linux в Windows 10
В наших предыдущих постах мы рассказывали о намерении Microsoft включить подсистему Ubuntu Linux в Windows 10. Исполняемые файлы подсистемы появились в ОС начиная с Windows 10 Insider Preview Build 14251, для использования она стала доступна в Insider Preview Build 14316, а для всех пользователей Windows 10 она станет доступна с обещанным Microsoft большим июньским обновлением, т. е. уже в этом месяце. Для использования подсистемы, ее нужно будет включить специальной настройкой, т. к. по умолчанию она выключена. Процесс включения мы описывали в этом посте.
Microsoft называет подсистему Linux для Windows как Windows Subsystem for Linux (WSL). Сегодня компания опубликовала новые технические детали реализации WSL. Ранее мы уже писали про модель подсистем в Windows 10 (NT) и то, как WSL реализуется на уровне ядра Windows за счет драйверов LXss.sys и LXCore.sys. Так как оригинальная модель ядра Windows позволяет верхнему уровню компонентов (напр. ntdll.dll — Win32) использовать свою семантику системных вызовов за счет расширенного интерфейса ядра, у WSL нет проблем со своей реализацией в окружении Windows.
Рис. Пример реализации сервиса получения списка файлов в директории. Драйвер LXss.sys в режиме ядра реализует семантику команды ls за счет использования расширенного интерфейса ядра ntoskrnl! NtQueryDirectoryFile, который позволяет ей это делать. Ту же операцию для подсистемы Windows выполняет компонент ntdll.dll, обращаясь к ntoskrnl! NtQueryDirectoryFile напрямую (справа).
Интересной является особенность реализации системных вызовов Linux в новой подсистеме, так как данная функция является наиважнейшей операцией при работе программ Linux. Системный сервис представляет из себя вызов функции ядра для выполнения базового действия в ОС с передачей ему аргументов. К таким действиям относятся операции с файлами, процессами, сетью и т. д. Для вызова сервиса используется инструкция микропроцессора под названием syscall, которая передает управление в режим ядра и вызовет диспетчер управления сервисами.
Microsoft называет правила вызова системного сервиса как Application Binary Interface (ABI). Особенность ABI для WSL заключается в том, что он не полностью совпадает с тем, который используется в Windows. Ниже представлены различия в передаче аргументов системному сервису в случае идентичных операций — сервиса getdents64 на Linux и NtQueryDirectoryFile в Windows. Описание аргументов сервиса Linux находится здесь.
Рис. Различия в ABI между Linux и Windows.
Отличие заключается как в используемых Windows и Linux регистрах, так и в номерах системных сервисов, которые должны быть переданы в регистре rax. Выше в таблице указано это отличие, при этом прочие шаги ABI являются идентичными, аргументы обоих сервисов размещаются в регистрах и выполняется вызов syscall. Другое отличие заключается и в возвращаемых сервисами Linux и Windows статусах. В то время как Windows использует специальные отрицательные константы NTSTATUS, Linux использует иную систему нумерации статусов выполненных операций. После вызова системного сервиса WLS, управление передается диспетчеру системных сервисов Windows, который в неизменном виде отправлет запрос LXss.sys, реализующему соответствующую семантику.
Драйвер LXss.sys может просто вызывать системный сервис Windows без обеспечения для него дополнительной семантики. Это касается тех сервисов, семантика реализации которых одинакова для обоих ОС. Например, функция Linux sched_yield соответствует сервису Windows под названием ZwYieldExecution, который имеет ту же семантику. Эта функция инструктирует ядро передать микропроцессор в использование другому потоку. WLS не будет предпринимать каких-либо дополнительных действий, а просто вызовет ZwYieldExecution. В других случаях, например, при реализации функций работы с каналами (pipe) и ветвлении процессов fork, LXss.sys реализует соответствующую семантику опираясь на основные функции и примитивы синхронизации ядра Windows.