VMM ( Диспетчер виртуальных машин)

1. Ядро операционных систем Windows версий Windows 386/3.x/95/98/Me, то есть всех версий Windows, не являющихся Windows NT.

В ранних версиях — «многозадачник» для MS-DOS, отправлявший вниз в таковую всю реальную работу (например, с файлами на диске).

Первоначально разработан для поддержки исполнения нескольких DOS-приложений под Windows, с настоящей (preemptive) многозадачностью между ними и основной Windows (при этом между Windows-приложениями многозадачность была cooperative), в том числе в окнах. Для исполнения в окне использовалось следующее: VMM-драйвер видеокарты VDD создавал в памяти ядра виртуализацию видеокарты и видеопамяти, прилагающаяся к нему 16-битная DLL обычных Windows — grabber DLL — умела выхватывать из него видеопамять в формате .bmp, а окно DOS — WINOLDAP.EXE — загружало grabber DLL и постоянно рисовало выхваченные растры обычными вызовами GDI в окне.

Постепенно проэволюционировал до самостоятельного ядра ОС, практически (за исключением таких пустяков в Windows 95, как работа с текущей датой и временем, см. книгу ШульманаЭндрю Шульман. Неофициальная Windows 95) не обращающийся вниз к DOS, и использующий DOS только в качестве загрузчика и командной строки аварийного режима.

Всегда имел структуру модульного ядра — хотя первоначально модули загружались только при старте VMM без возможности отгрузки. Кернел-модули для VMM назывались VxD, расширение файлов — .vxd или .386, формат файлов, хотя и 32битный бессегментный, отличался от WinPE формата (Win32-приложений, DLL, и .SYS кернел-модулей Windows NT), и требовал специального инструментария для построения.

Содержался (вместе со стандартным комплектом модулей VxD) в файле WIN386.EXE (до выхода Windows 95) и в VMM32.VXD (для операционных систем (Windows 9x) вместе со стандартным комплектом модулей VxDЭндрю Шульман. Неофициальная Windows 95, С.79

2. Virtual Memory Manager — диспетчер виртуальной памяти позволяет ОС (например, Windows 2000) использовать память на жёстком диске как часть ОЗУ. Контролирует процесс подкачки страниц с диска в ОЗУ и обратно (см. также свопинг, виртуальная память).

История Первоначально была произведена разработка диспетчера виртуальных машин MS-DOS (с использованием режима V86 процессоров от 386 и выше) в виртуальном режиме процессора X86.

Ранее, в Windows 2.1 появилась версия Windows/386, включавшая в себя менеджер виртуальных машин с целью поддержки многозадачного исполнения нескольких приложений MS-DOS и их исполнения.

В Windows 3.1 появился VxD WDCTRL, который представлял собой полный драйвер режима ядра для Standard AT/IDE/ATA жесткого диска на портах 0x1f0 и 0x170. Этот драйвер поддерживал многозадачную работу с диском (процессор исполняет код, пока в диске шевелятся головки), и заменял int 13h API в BIOSе, на который полагалась MS-DOS, и который не имел никакой многозадачности (глухой цикл ожидания прерывания все время, пока диск исполняет операцию). Это называлось — 32bit disk access.

В Windows for Workgroups 3.1 в виде VxD были реализованы: SMB сервер, редиректор и протокол NetBEUI, хотя пока еще с DOSовскими драйверами сетевых карт. Поскольку редиректор является файловой системой с кэшированием, к нему в помощь был разработан vcache.386

В Windows for Workgroups 3.11 в виде VxD были реализованы: файловая система FAT (это называлось — 32bit file access), общий фасад файловых систем (FAT и редиректора) ifsmgr.386, поддержка драйверов сетевых карт в виде VxD, а также — в дополнительных компонентах — TCP/IP и Winsock. Это сделало VMM полноценным ядром ОС, практически не обращающимся к нижележащему DOSу. Шульман в своей книге удивлялся, что «субминорная» смена цифры версии с .1 на .11 означала куда бОльшие изменения в ядре Windows, нежели переход на новую схему нумерации версий в Windows 95.

Примерно тогда же (около 1993 года) появился Win32S, главнейшая часть которого была реализована как VxD, и который добавлял поддержку Win32-приложений (с урезанным API) в Windows 3.x. В частности, Win32S поддерживал файлы, отображаемые в память. Главное отличие Win32S от будущей Windows 95 — это отсутствие потоков (threads), ибо потоки требовали переделки самого VMM, что было сделано лишь в Windows 95.

Win32S позволил разработчикам сравнительно легко перенести под Windows приложения из других, 32битных, ОС — например, тогдашней MacOS (Adobe APhotoshop). Невзирая на то, что тогда уже существовала Windows NT, из-за огромных по тем временам требований последней к размеру памяти (минимум 16МБ, что тогда означало — самый дорогой сегмент PC-совместимых компьютеров, почти workstation) — нетребовательный к памяти Win32S сыграл огромную роль на ИТ-рынке, позволив вырасти экосистеме Win32-приложений еще до выхода Windows 95 (и до массового перехода на Windows NT в конце 90ых, в связи с удешевлением памяти).

В Windows 95 в сам VMM была добавлена поддержка потоков. Кроме того, к нему добавились:

CONFIGMG — реализация реестра и подсистема Plug and Play PELDR — загрузчик .sys файлов в формате Windows NT, с серьезными ограничениями на используемые API. На тот момент поддерживались только NT-драйверы сетевых карт и дисковых/SCSI контроллеров. поддержка шины PCI переработанная архитектура работы с дисками с добавлением scsiport.pdr — эмулятора SCSI-подсистемы из Windows NT, позволившего использовать NT-драйверы дисковых контроллеров.

В Windows 98 были добавлены:

NTKERN — реализация WDM — почти всего API ядра Windows NT, причем даже не NT4, а будущей Windows 2000 с поддержкой Plug and Play. Разработан на основе PELDR. При этом многие вызовы NT4, такие, например, как большинство системных вызовов ZwXxx и устарелые, предшествующие Plug and Play, вызовы для работы с аппаратурой типа HalAssignSlotResources — в WDM не вошли. Являлся оберткой над VxD API ядра VMM — например, WDM вызов IoInvalidateDeviceRelations (извещение PnP подсистемы о том, что список устройств, дочерних для данного, изменился) — был простейшей оберткой над CM_Reenumerate_DevNode в модуле CONFIGMG. основанные на WDM стеки шин USD и 1394 (в то время существовали большие ожидания успеха последней). Эти стеки никогда не реализовывались как VxD. Исполняемые файлы от Windows 98 подходили к Windows 2000 (тогда в бетах), и наоборот. основанная на WDM подсистема Ks — часть «медиаплеерной» подсистемы DirectShow, что находится с режиме ядра (драйвера аппаратных DVD-декодеров, подключаемых по 1394 видеокамер и др).

К концу своей эпохи VMM стал полноценным и развитым ядром ОС, будучи не очень намного хуже, чем ядро Windows NT, и почти полностью совместимым с последним и по приложениям (Win32), и по кернел-модулям (WDM).

Основные недостатки VMM:

отсутствие многозадачности внутри самого ядра (в Windows NT она такая же, как в Linux 2.x с CONFIG_PREEMPT, основана на спинлоках и DPC/bottom half) отсутствие поддержки многопроцессорных машин отсутствие «взрослых» файловых систем (наиболее умной была FAT32) отсутствие overlapped IO (в Windows NT есть не только API для такового, но и все драйвера написаны как overlapped с использованием структуры IRP, что избавляет от необходимости, известной по node.js, в создании пула рабочих нитей ввода-вывода в user mode платформе). отсутствие поддержки Unicode (и тем более utf-8), например, в именах файлов — использовались 1байтные (а для иероглифических языков 1-2байтные) ANSI-кодировки, при этом 2байтные иероглифические кодировки могли иметь второй байт, совпадающий с ASCII символом, чего нет в utf-8 и что требует переделки кода лексеров и парсеров). проприетарный формат VxD файлов, отличный от WinPE, требовал специальных инструментов, первое время — обязательного программирования на ассемблере (обертки для Си++ появились значительно позже), и имевший весьма убогую поддержку DLL/shared library exports/imports.

Недостатки «маленьких» VMM-based Windows (которые не Windows NT) в основном не были недостатками VMM, а были связаны с тем, что эти ОС использовали 16битный графический движок GDI (и драйвера видеокарт и принтеров) и менеджер окон USER. Что касается gdi32.dll и user32.dll, то в этих версиях они были набором переходников (thunks) из плоского 32битного кода в сегментный 16битный. 16битный код GDI и USER не был thread-safe, что требовало взятия Win16Lock в обертках. Более того — при передаче управления любому 16битному приложению (все они жили в VM 0) тоже брался Win16Lock, и удерживался до передачи управления в приложение Win32 или DOS.

Это приводило к тому, например, что повисшее 16битное приложение полностью блокировало всю ОС.

Архитектура Гипервизор VMM поддерживал вытесняющую многозадачность между процессами (виртуальными машинами, так как первоначально каждый процесс был экземпляром виртуальной машины DOS, кроме того, в одном из процессов VMM выполнялись все приложения Windows). С появлением Win32 (сначала в Win32S, потом в Windows 95) каждый Win32-процесс тоже стал отдельной виртуальной машиной VMM. Фактически слова «виртуальная машина» стали означать «процесс».

Внутри себя гипервизор VMM не использовал вытесняющую многозадачность — примерно так же, как Linux без CONFIG_PREEMPT, и другие UNIX-системы, особенно ранние. То есть — переключение задач делается либо явным ожиданием, либо при возврате из ядра в user mode.

Гипервизор 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 и никогда туда не обращались.