
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.
Комментарии (42)
Kudja
09.06.2016 15:02+2А никто не подскажет:
— проблемы с курсорными клавишами решили или есть решение? Например в mc навигация
— для разработки могу ли я создавать/использовать симлинки, права доступа на ФС и т.д. при работе с проектами?
— каким образом правильно прописать во внешнем софте (например в phpStorm) чтобы он использовал не gitbash а стандартный git?MainNika
09.06.2016 15:471. Решили. Работает и в стандартном терминале, и в ConEmu.
2. Симлинки и права доступа поддерживаются в файловой системе lxss (которая тоже как бы ntfs, и все это выглядит как магия), в /mnt/c/ не работают.
3. Пока никак.Kudja
09.06.2016 16:041. Только что попробовал, не работает, что мне нужно сделать не подскажете?
2. А как использовать чтоб работало — это какая то надастройка или формат ФС? если форматирование выбираю, то винда не предлагает на выбор такой
3. Жаль, без этого толк есть, но не полноценноKudja
09.06.2016 16:09По поводу 1 я полагаю надо поставить Fast обновления судя по камменту ниже и развернуть обновление
MainNika
09.06.2016 16:121. Не знаю, я просто запустил и проверил что работает. Гифка http://i.imgur.com/0qRE3oA.gifv
2. Ничего, симлинки, права, регистрозависимость, все это работает «внутри lxss». Т.е. в точке монтирования /. Со стороны Windows эти файлы просто лежат в USER\AppData\Local\Lxss.
Shamov
09.06.2016 15:07А если я захочу, например, открыть специальный сокет в ядре для управления сетевыми интерфейсами по netlink-протоколу? Этот LXss-драйвер так же будет перехватывать мои вызовы для работы с сокетом, транслировать их в WinAPI, а затем подсовывать в мой сокет данные в том же виде, в котором они пришли бы от Linux-ядра? Что-то я в это не верю…
VolCh
16.06.2016 07:37LXss не транслирует вызовы в WinAPI, он транслирует их (судя по всему) в вызовы LXCore, которые транслирует их в вызовы ntkernel. Так же как вызовы WinAPI (например вызовы user.dll) транслируются в вызовы ntdll, а затем транслируются в вызовы ntkernel. То есть LXss и WinAPI работают параллельно, возможно даже LXCore и ntdll работают параллельно.
FlarGargoyl
09.06.2016 16:02+1Больше интересует, были ли сподвижки в сторону драйверов для «немножко других файловых систем»? будет ли поддержка ext, например?
Rast1234
09.06.2016 18:21+1Вряд ли были, вряд ли будут. Например, есть максимально нативная реализация драйвера btrfs (сырая, но все-таки), и там в readme автор написал, что драйверу приходится «прикидываться» что это NTFS, потому что:
the function MPR!MprGetConnection checks the filesystem type against an internal whitelist, and fails if it's not found, which prevents UAC from working. Thanks Microsoft!
То есть если windows где-то имеет захардкоженные списки «хороших» типов ФС, они явно не рассчитывают на расширяемость, даже сторонними драйверами.
atero_zl
09.06.2016 17:40Ни кто не в курсе, микрософты не обидят 32 бита вин 10?)
daggert
09.06.2016 18:28А зачем они вам?
Bokhan
10.06.2016 13:20Вы не меня спрашивали, но попробую ответить.
Тривиально: чтобы заводить lxss в вин10 на процессорах, которые не могут в 64 бита. Для «интернета вещей» и прочих мелкоконтроллерах
Мне почему-то кажется, что вин7х64 для своей работы требует больше ресурсов, чем вин7х86. Соответственно, если запускать её виртуально, разница в быстродействии будет более заметна. Возможно, у вин10 тоже есть (если действительно есть) такой недостаток
Я ничего не замерял и даже не гуглил по этой теме, чисто субъективное ощущение. Я даже не могу логически обосновать это, кроме как не совсем корректной обработкой системных вызовов в версии х64.atero_zl
10.06.2016 13:26ситуация в том что проц то умеет 64, а вот уэфи туды запихнули с ограничением 32
DrSavinkov
Я правильно понял, Linux в Windows интегрирован методом преобразования запросов Linux к запросам Windows?
youROCK
Насколько я знаю, никто не скрывал, что Linux On Windows — это как WINE наоборот :). Что буквально несколько вещей реализованы прямо совсем в ядре, вроде вызова fork(), а остальное просто транслируется в соответствующие вызовы NT API (что бы это не означало).
DrPass
Я более того скажу, в Windows NT от рождения был промежуточный уровень системного API, и над ним было несколько надстроек, в частности WinAPI, OS/2 и тот самый POSIX. Но если не ошибаюсь, к Windows 2000 альтернативные API оттуда убрали.
sormon
Разве? Мне казалось, как минимум, POSIX-слой в том или ином виде был во всех версиях, начиная с NT…
hdfan2
Правильно кажется. Есть там POSIX (хотя, возможно, и неполный).
Psihiatr
Убрали POSIX только к релизу ХР, но он там изначально был довольно урезанный и ограниченный.
Mingun
А что, можно придумать другой вариант?
VolCh
Можно. Например поставить ядро BSD и преобразовывать вызовы как Windows, так и Linux к нему :)
VolCh
Запросы Windows есть трёх основных видов: NT kernel (ntoskrnl.exe), NT Native API (ntdll.dll) и Windows API (все остальные). Обычно используется только последний, его вызовы преобразуется в вызовы Native API, которые в свою очередь преобразуются в вызовы NT kernel (естественно, не все вызовы вышележащих слоев преобразуются 1:1 — могут вообще не преобразовываться, могут преобразовываться только сигнатуры, могут преобразовываться в несколько вызовов со сложной логикой). Судя по доступной информации WSL реализует преобразование вызовов как минимум Linux Kernel API в вызовы NT kernel и, возможно, в вызовы NT Native API, никак не касаясь подсистемы Windows API, работая параллельно ей.