VMM
VMM (англ. Virtual Machine Manager Диспетчер виртуальных машин) 1. диспетчер виртуальных машин (гипервизор) подсистемы Windows 95, обеспечивающий динамическое распределение памяти, планирование задач, функции сервера DPMI, динамическую загрузку, работу с виртуальными машинами MS-DOS (создание, запуск, контроль и прекращение работы, предоставляет услуг по управлению памяти, процессов, обработки прерываний, защиты). Гипервизор содержался в файле WIN386.EXE (до выхода Windows 95) и в VMM32.VXD (для операционных систем (Windows 9x) вместе с драйверами VxD, установленными в системе.[1] 2. Virtual Memory Manager — диспетчер виртуальной памяти позволяет ОС (например, Windows 2000) использовать память на жёстком диске как часть ОЗУ. Контролирует процесс подкачки страниц с диска в ОЗУ и обратно (см. также свопинг, виртуальная память).
История
Первоначально была произведена разработка диспетчера виртуальных машин MS-DOS (с использованием режима V86 процессоров от 386 и выше) в виртуальном режиме процессора X86.
Ранее, в Windows 2.1 появилась версия Windows/386, включавшая в себя менеджер виртуальных машин с целью поддержки многозадачного исполнения нескольких приложений MS-DOS и их исполнения.
Архитектура
Гипервизор VMM поддерживал вытесняющую многозадачность между процессами (виртуальными машинами, так как первоначально каждый процесс был экземпляром виртуальной машины DOS, кроме того, в одном из процессов VMM выполнялись все приложения Windows).
Внутри себя гипервизор VMM не использовал вытесняющую многозадачность (примерно так же, как ранние версии Linux и другие UNIX-системы, особенно ранние).
Гипервизор VMM реализован на ассемблере, который также предлагался и как язык разработки дополнительных модулей (так называемые VxD). Написание модулей VxD на языке C требовало многочисленных оберток.
Обеспечивал ряд функций для модулей VxD:
- богатый набор функций по работе со страничной памятью, в том числе возможность отобразить принадлежащий VxD блок памяти в адресное пространство виртуальной машины DOS (эмуляция видеопамяти и так далее).
- низкоуровневые примитивы синхронизации — ожидание/пробуждение, нечто вроде condvar
- установка перехватов на обращения к портам — при исполнении машинных команд IN/OUT в виртуальной машине управление передавалось в определенную процедуру одного из VxD.
- установка точек останова — при попадании исполнения в виртуальной машине на точку останова управление передавалось в определенную процедуру одного из VxD.
Многозадачность и 16-битные приложения
Сам модуль VMM поддерживал вытесняющую многозадачность, хотя и не внутри самого себя.
Тем не менее Win16 API имел с этим серьёзные проблемы, полагаясь на разделяемую между задачами память. Кроме того, подсистемы GDI (двумерная графика) и USER (пользовательский интерфейс, менеджер окон) не были thread-safe. Это связано с тем, что данные подсистемы были разработаны до VMM для процессоров старше Intel 386.
Проблемы были настолько серьёзны, что не были решены до перехода на Win32, который полностью thread-safe и не полагается внутри себя, по крайней мере вне режима ядра, на разделяемую память (хотя и поддерживает её для приложений, того желающих).
Таким образом, ни в одной версии Windows не было и нет вытесняющей многозадачности между приложениями Win16. Даже в Windows NT такие приложения все исполняются в одном общем процессе NTVDM.EXE.
Что же касается Windows, основанных на VMM, то в них навсегда остались 16-битные подсистемы USER и GDI, которые вдобавок не thread-safe. 32-битные приложения захватывали мьютекс Win16Lock в прологе любого вызова этих подсистем, а при исполнении шестнадцатибитных приложений этот объект был захвачен на все время их исполнения (до отдачи процессора 32-битному приложению, которое вдобавок останавливалось в ожидании на этом объекте до тех пор, пока шестнадцатибитное приложение не осуществляло явную передачу процессора).
Это приводило к слабости реализации многозадачности в основанных на VMM Windows — никакие обращения к менеджеру окон и графики не могли исполняться (с зависанием машины), если шестнадцатибитное приложение зациклилось или же находилось в ожидании в процессе чтения файла с сети, данных из сокета и так далее.
Настоящая вытесняющая многозадачность в VMM была только между виртуальными машинами MS-DOS, которые по очевидным причинам не знали о USER и GDI и никогда туда не обращались.
VxD и «настоящие» драйвера устройств
Обычно задачей драйвера режима ядра является полная реализация всех операций с устройством. Также обычно в ядро ОС включают модули, аналогичные драйверам, но реализующие то, что требует глобальных на всю машину данных и таблиц — TCP/IP стек, файловые системы. Также включают и те модули, которые работают в плотной связке со всем перечисленным выше (фильтры сетевых пакетов, общие полиморфные части некоторых архитектур, таких, как сокеты и т. д.).
VMM всегда разрабатывался как надстройка над MS-DOS. Что касается устройств, то приложения DOS обычно содержали в себе весь код для работы со «своими» устройствами, и VMM потому первоначально также не включал в себя драйверы устройств.
Задачей VxD первоначально было не обслуживание устройств как таковых, а сериализация представления устройства между несколькими виртуальными машинами MS-DOS. Задачей виртуального драйвера видеоадаптера (тоже VxD) также являлась полная эмуляция такового адаптера для виртуальных машин, на данный момент невидимых или изображаемых в окне.
В Windows 3.1 впервые появился модуль VxD, полностью реализующий работу с устройством — WDCTRL для PC/AT-контроллера жесткого диска (то, что впоследствии стало стандартным IDE контроллером). Возможность была показана в интерфейсе пользователя как «32-битный доступ к диску», и заключалась в полном исполнении прерываний int 13h внутри WDCTRL, который для этого сам обращался к аппаратуре, не используя BIOS и его обработчик int 13h.
Выигрыш от этого был в том, что обработчик в BIOS не более чем крутится в цикле опроса все то время, пока диск отрабатывает команду, делая почти невозможным занять процессор в это время исполнением чего-то ещё.
Использование WDCTRL позволяло исполнять какой-то код в то время, пока диск отрабатывает операции, а также вести работу с файлом подкачки страниц в фоновом режиме. Это сильно повышало производительность.
Начиная с WDCTRL, VxD начали приобретать функции настоящих драйверов устройств, а VMM (хотя и по-прежнему основанный на DOS) — функции настоящего ядра ОС.
Далее в Windows for Workgroups в виде VxD был реализован весь стек протокола SMB/CIFS (с транспортным уровнем — только NetBEUI), как клиент, так и сервер, кроме самого нижнего уровня — драйвера сетевой карты, последний использовался тот же, что в MS LAN Manager Client для DOS, и загружался вместе с ядром DOS путём указания в файле config.sys.
Так как SMB клиент логически является файловой системой, появился и VxD под названием IFSMGR, распределяющий системные вызовы MS-DOS по работе с файлами (int 21h) между другими VxD, а в крайнем случае — отправляющий их в ядро DOS (того DOS, из которого загружен VMM).
В Windows 3.11 в виде VxD была реализована уже файловая система FAT (32bit File Access, улучшала производительность из-за использования страниц виртуальной памяти, а не крошечных буферов ядра DOS, под кэш). Кроме того, в этой ОС появилась возможность исполнения драйверов сетевых карт в виде модулей VxD.
Windows 95 и позже
Технология Plug and Play в Windows 95 была полностью реализована в виде модулей VxD, важнейший из которых является CONFIGMG.VXD.
Все драйверы устройств, участвующие в ней, были обязаны либо сами быть типа VxD, либо же иметь второй драйвер — загрузчик, знающий о первом и являющийся VxD. Второе было использовано для сред совместимости NDIS и SCSIPORT, поддерживающих загрузку драйверов сетевых карт и контроллеров устройств массовой памяти от Windows NT без изменений (даже несмотря на то, что драйверы Windows NT имели иной формат файла — тот же, что и приложения Win32).
Также в виде VxD был реализован весь стек работы с CD/DVD приводом (в том числе файловая система CDFS/Joliet), как и TCP/IP стек.
Таким образом, использование диспетчера виртуальных машин в структуре Windows 95 позволило корпорации Microsoft сделать маркетинговое заявление о том, что «Windows 95 более не использует MS-DOS», что полностью не соответствовало истине. Во-первых, исследователи (Эндрю Шульман) быстро доказали, что VMM по-прежнему обращается к нижележащему DOS для операций вроде «получить текущее время». Во-вторых, в самой ОС была возможность сделать загрузочную дискету MS-DOS, при этом использовалось то же ядро DOS, что и для загрузки VMM основной ОС.
В Windows 98 была реализована идея одинаковых драйверов для Windows 9x и Windows NT нового поколения — Windows Driver Model(WDM). Для реализации идеи в модель драйверов Windows NT добавили поддержку PnP и управления питанием (реализовано на 2 года позже Windows 98, в Windows 2000), после чего полученную модель упростили, убрав из неё некие старые вызовы времен NT 3.x, и перенесли в среду VMM.
VxD под названием NTKERN являлся оберткой вокруг VMM, реализующей WDM, и умеющей загружать драйверы в формате Windows NT. Например, вызов Windows NT IoInvalidateDeviceRelations (появился только в WDM, часть поддержки PnP) реализовывался через CM_Reenumerate_Devnode в CONFIGMG, и так далее.
Это позволило легко реализовать поддержку шин USB и 1394 сразу в обеих версиях Windows — все эти драйверы были реализованы в WDM. Более того, эти .sys файлы из бета-версий Windows 2000 нормально работали в Windows 98.
В те времена были различные понятия «драйвер WDM» и «драйвер Windows NT», последний мог использовать немного более богатый набор вызовов, не реализованных в NTKERN. С «вымиранием» основанных на VMM Windows исчезла и это различие, ныне WDM есть не более чем API ядра Windows для разработки драйверов аппаратуры (в противовес фильтрам сетевых пакетов, файловым системам и т. д. — такие драйвера всегда отличались коренным образом в Windows 9.x и в Windows NT).
Сравнение с настоящими виртуальными машинами
«Настоящие» виртуальные машины, появившиеся ещё в IBM 360, а ныне реализованные в Xen, Virtual PC, VMWare Workstation, ESX Server, Hyper-V и других продуктах, отличаются от тех виртуальных машин DOS, что были реализованы в VMM.
Например, они позволяют загрузить с гостевой учетной записью почти любую ОС и почти любую её версию, а также полностью перезагрузить гостевой сеанс. Для этого там эмулируется вся аппаратура, а также базовая система ввода-вывода (BIOS).
Тем не менее, виртуальные машины VMM использовали поддержку от процессора — режим V86. Настоящие же виртуальные машины требуют для своей работы либо трюков вроде virtual TLB, что приводят к гигантскому количеству «проваливаний» в гипервизор по отказу страницы и работает медленно (некоторые гипервизоры просто переключаются в режим покомандной интерпретации кода «гостя» в некоторых случаях, особенно при работе с видеоадаптером), либо же поддержку многоуровневых таблиц страниц уже в самом процессоре (Vanderpool), которая появилась не ранее примерно 2003 года.
Адекватная производительность настоящих виртуальных машин была достигнута только в поколении Pentium III, виртуальные же машины VMM прекрасно работали и на i386.
Критика
Отсутствие многозадачности между 16-битными приложениями Windows, вместе с использованием 16-битной подсистемы графики и пользовательского интерфейса во всех основанных на VMM Windows, а также отсутствие защиты памяти между такими приложениями, приводило к низкой надежности всех этих версий Windows.
Это вряд ли упрек в адрес VMM, скорее в адрес Win16 API и упомянутых подсистем, но тем не менее это давало мощные основания противникам Microsoft (из мира UNIX) говорить об отсутствии настоящей многозадачности в Windows.
Такое мнение распространялось даже на Windows NT, где оно есть несомненный миф, поддерживаемый разве что крайне слабой реализацией вызова fork() в пакете Cygwin, позволяющем перенос ПО из UNIX под Windows NT. Реализация fork() в Cygwin копирует всё адресное пространство, в основном из-за поддержки основанных на VMM Windows — VMM никогда не имел fork(), в отличие от ядра Windows NT (NtCreateProcess при SectionHandle == NULL), последнее использовалось в POSIX подсистеме Windows и её потомках Interix и Services for UNIX.
Windows NT по ряду возможностей — хорошая для своего времени поддержка многопроцессорных машин и наличие вытесняющей многозадачности даже внутри ядра — превосходила многие UNIX, такие, как ранние Linux и FreeBSD, в вопросе многозадачности. Впрочем, в мире Linux есть серьёзное мнение, что вытесняющая многозадачность внутри ядра не нужна.
Литература
- Andrew Schulman.Unauthorized Windows 95 / Эндрю Шульман. Неофициальная Windows 95, Киев :Диалектика,1995, ISBN 1-56884-169-8, ISBN 5-7707-8336-2, ISBN 5-85225-043-0
Примечания
- Эндрю Шульман. Неофициальная Windows 95, С.79