Как инициализировать NT

Марк Русинович.

научный сотрудник Университета Карнеги-Меллон. Соавтор многих популярных утилит для Windows NT, в том числе NTFSDOD, Filemon, Regmon и Recover. С ним можно связаться по адресу mark@sysinternals.com или http://www.sysinternals.com.
В ноябрьском номере была опубликована первая часть этой статьи, посвященной процессу загрузки Windows NT. Я уже рассказал о том, как программа Setup в NT готовит жесткий диск для загрузки, размещая код NT в головной записи загрузки (MBR) и секторах загрузки. При загрузке системы код NT выполняет программу из загрузочного файла NTLDR. Этот файл отвечает за ту часть, которая предшествует загрузке NT Kernel. Кроме того, в обязанности NTLDR входит подготовка структур данных с информацией о системе и создание ключей Registry HKEY_LOCAL_MACHINEHARDWARE и HKEY_LOCAL_MACHINESYSTEM. Позже NTLDR передает эту информацию в Kernel вместе с данными для hal.dll и драйверов старта загрузки устройств.

Я решил продолжить описание процесса загрузки с того момента, когда NTLDR завершает выполнение своих обязанностей, вызывая ядро NT Kernel. Я расскажу об остальном процессе загрузки, в том числе о процедурах инициализации, которые выполняет каждая из подсистем Executive. Мы поговорим о том, как и когда инициализируются драйверы устройств каждой из категорий загрузки — Boot, System и Auto. Завершу я свое описание рассказом о том, как Kernel заканчивает процесс загрузки, запустив программу режима пользователя, которая выводит на экран диалоговое окно для регистрации и запускает подсистему Win32.

Более подробную информацию можно найти во врезке «Windows 2000 и загрузка», где рассказывается о том, как процесс загрузки NT изменится в Windows 2000.

Инициализация Kernel и подсистем Executive

NT Kernel в своем процессе загрузки проходит две фазы: фазу 0 и фазу 1. Фаза 0 инициализирует в Kernel и подсистемах Executive все необходимое для того, чтобы базовые сервисы, требуемые для завершения инициализации, были готовы к работе во время фазы 1. Во время фазы 0 NT отключает все прерывания и разрешает их только во время фазы 1. Большинство подсистем Executive реализует свой код инициализации за счет того, что конкретная функция использует параметр, указывающий, какая фаза в данный момент выполняется.

Функция, ответственная за организацию фазы 0 называется ExpInitializeExecutive. Она запускается при вызове функции уровня аппаратной абстракции (HAL), получившей название HalInitSystem. Функция HalInitSystem предоставляет собственные версии HAL, которые создают различные OEM-производители с тем, чтобы получить контроль над системой до того, как NT выполнит значительную часть инициализации. Одна из обязанностей HalInitSystem состоит в подготовке контроллера системных прерываний для обработки прерываний и конфигурации прерывания по такту системных часов. Когда HalInitSystem возвращает управление, ExpInitializeExecutive продолжает свою работу в соответствии с состоянием переключателя /BURNMEMORY BOOT.INI (если такой переключатель выбран пользователем в файле boot.ini, определяя, какая из версий будет загружаться) и освобождает объем памяти, указываемый переключателем. Затем ExpInitializeExecutive вызывает подпрограммы инициализации для Memory Manager, Object Manager, Security Reference Monitor и Process Manager. Memory Manager получает эстафету, создавая таблицы страниц и внутренние структуры данных, которые необходимы для предоставления базовых сервисов памяти. Memory Manager организует и резервирует область для кэша системных файлов и создает области памяти для страничных и нестраничных пулов. Другие подсистемы Executive, Kernel и драйверы устройств используют эти пулы памяти для резервирования места под свои структуры данных.

Экран 1: Просмотр значений Service GroupOrder.

После того, как Memory Manager завершает фазу 0, ExpInitializeExecutive на начальном голубом экране выводит текст «Microsoft (r) Windows(tm) Version 4.0 (Build 1381)», который вы видите во время загрузки. Build 1381 — это номер сборки для NT 4.0 без сервисных пакетов. Для NT 4.0, к которой применялись сервисные пакеты, после номера сборки на голубом экране появится примерно следующий текст «Service Pack 3». Система получает номер сервисного пакета из HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlWindowsCDSVersion, где это число представлено в виде шестнадцатеричного значения, которое может идентифицировать промежуточные сервисные пакеты (например, Service Pack 1a).

Во время фазы 0 при инициализации Object Manager NT определяет объекты, которые необходимы для создания пространства имен Object Manager так, что другие подсистемы могут добавлять в это пространство свои объекты. NT также создает таблицу обработки, которая позволяет начать определение местонахождения ресурсов. Security Reference Monitor инициализирует объект типа токен и затем использует этот объект для создания и подготовки первого токена, который присваивается начальному процессу. Последняя подсистема Executive, которая инициализируется во время фазы 0 — это Process Manager. Эта подсистема выполняет большую часть своей инициализации именно во время фазы 0, определяя процесс и типы объектов-нитей и создает списки для контроля активных процессов и нитей. Process Manager также создает объект процесса для начального процесса и называет его Idle. На последнем шаге Process Manager создает процесс System и запускает нить для этого процесса, которая будет определять инициализацию во время фазы 1 в функции Kernel — Phase 1 Initialization.

Когда к нему возвращается управление, ExpInitializeExecutive становится нитью в процессе Idle и превращается в свободную нить системы. ExpInitializeExecutive устанавливает свой приоритет в 0 (самый низкий из возможных) и начинает выполнять цикл, который будет реализоваться только в том случае, если никакая другая нить в системе не может выполняться.

Фаза 1 начинается, когда Phase 1 Initialization вызывает HAL для того, чтобы подготовить систему к восприятию прерываний, инициируемых устройствами, и разрешить прерывания. Phase1Initialization отмечает время и сохраняет его как время загрузки системы. До этого момента активным может быть только один процессор. В системах с симметричной многопроцессорной обработкой (SMP), процесс загрузки оставляет отключенными другие процессоры. Теперь с помощью HAL Phase 1 Initialization включает остальные процессоры. После того, как все процессоры проинициализированы, NT выводит на голубой экран текст, примерно следующего содержания: «2 System Processors [128 MB Memory] Multiprocessor Kernel».

Таблица 1: Инициализация подсистемы Executive во время фазы 1

Подсистема Executive Функция инициализации
Obect Manager Создает корневой каталог пространства имен Object Manager — каталог ObjectTypes, каталог ?? и DosDevices связывает с каталогом ??.
Executive Создает типы объектов Executive, в том числе семафоры, взаимные исключения, события и таймер
Kernel Инициализирует структуры данных планировщика (диспетчера) и таблицу System Services
Security Reference Monitor Создает каталог Security в пространстве имен Object Manager и инициализирует проверочные структуры данных, если включена опция проверки.
Memory Manager Создает тип объекта раздела, начинает изменять нить модуля записи страниц и нить Balance Set Manager.
Cahe Manager Инициализирует структуры данных кэширования для системных файлов.
Configuration Manager Создает объект ключа Registry в пространстве имен Object Manager и получает данные, переданные модулем O/S Loader в HKEY_LOCAL_MACHINESYSTEMHARDWARE.
Local Procedure Call SubsystemИнициализирует объект типа порт.
I/O Manager Инициализирует журнал регистрации ошибок, создает типы объектов драйвера и устройства. Инициализирует драйверы SERVICE_BOOT_START, а также загружает и инициализирует драйверы SERVICE_SYSTEM_START.
Process Manager Загружает библиотеку ntdll.dll в адресное пространство систем ных процессов.

Phase1Initialization продолжается за счет вызова каждой подсистемы Executive в порядке, указанном в Таблице 1 так, что они могут выполнять инициализацию фазы 1. Порядок, в котором Phase1Initialization вызывает подсистемы важен в силу определенных взаимозависимостей между системами. Например, Executive должна определить тип таких объектов, как взаимные исключения, семафоры, события и таймеры, поскольку другие подсистемы эти объекты используют.

Инициализация драйверов

Инициализация I/O Manager представляет особый интерес, поскольку во время инициализации фазы 1 наконец начинается загрузка драйверов, которая описана в NTLDR. Когда вы или NT устанавливаете драйвер устройства, сценарий Setup драйвера или программа могут передать указание NT в дополнение к значению Start определить три значения Registry в ключе Registry для драйвера. Эти значения — Group, Tag и DependOnGroup. Первые два значения служат для более детального описания, когда I/O Manager должен инициализировать драйвер и I/O Manager использует третье значение для того, чтобы решить, нужно ли запускать конкретный драйвер.

Прежде, чем I/O Manager инициализирует драйверы загрузки, он сортирует их в соответствии со значениями их параметра Group, а драйверы, для которых этот параметр не определен, помещает в конец списка. Значение Registry HKEY_LOCAL_ MACHINESYSTEMCurrentControlSetControlServiceGroupOrder определяет приоритет группы в процессе сортировки. На Экране 1 показаны значения ServiceGroupOrder. Группы в начале списка имеют более высокий приоритет, чем группы в конце списка.

После того, как I/O Manager сортирует драйверы по группам, он сортирует драйверы внутри каждой группы в соответствии со значениями Tag, определенными в ключах Registry соответствующих драйверов. Драйверы без этого параметра помещаются в конец списка в рамках своей группы. Можно было бы предположить, что I/O Manager инициализирует драйверы с тегами, имеющими меньшее числовое значение, до драйверов с большими значениями этого параметра, но это вовсе не обязательно. Ключ Registry HKEY_ LOCAL_MACHINESYSTEMCurrent ControlSetControlServiceGroupOrderList определяет приоритеты тегов в группе; с помощью этого ключа разработчики Microsoft и драйверов устройств могут по своему желанию переопределить условия сортировки целых чисел.

После того, как I/O Manager заканчивает сортировку драйверов, он просматривает созданные им списки и инициализирует драйверы в соответствии с занимаемыми ими в списке местом. Однако, если драйвер имеет параметр DependOnGroup, I/O Manager не будет загружать этот драйвер до тех пор, пока не будет загружен хотя бы один драйвер, принадлежащий к этой конкретной группе. Параметр DependOnGroup позволяет упростить определение драйвера, который не должен загружаться, если его работа требует применения другого драйвера, который отсутствует в системе.

По мере инициализации каждого драйвера I/O Manager проверяет, какой статус возвращает функция инициализации драйвера. Если драйвер сообщает об ошибке, действия, которые предпринимает I/O Manager, зависят от значения ErrorControl ключа Registry данного драйвера. В Таблице 2 приводятся возможные значения ErrorControl и действия, которые I/O Manager предпринимает, когда драйвер с конкретным значением параметра сообщает об ошибке. В некоторых случаях ошибка вызывает перезагрузку NT и при этой перезагрузке будет использовано предыдущее значение подключа Control в Registry для того, чтобы успешно завершить этот процесс. Сразу же после инициализации драйверов загрузки I/O Manager загружает и инициализирует все драйверы, промаркированные как SERVICE_SYSTEM_START (старт системы). I/O Manager обрабатывает порядок инициализации драйвера старта системы и зависимостей таким же образом, как и при обработке драйверов старта загрузки. Единственное отличие между драйверами старта загрузки и старта системы состоит в том, что NTLDR предварительно загружает драйверы старта загрузки и NT инициализирует их первыми. Когда драйверы старта загрузки (особенно драйверы файловой системы и диска, отвечающие за системный раздел) активны, I/O Manager может использовать их для загрузки драйверов старта системы.

По мере того, как драйверы устройств инициализируются во время загрузки, они работают в ограниченной среде: NTLDR и Configuration Manager определяют только HKEY_LOCAL_MACHINESYSTEM и HKEY_LOCAL_MACHINEHARDWAREDESCRIPTION части Registry и драйверы загрузки не могут получить доступ к файлам на диске. После того, как I/O Manager инициализирует драйверы старта системы, он вызывает HAL для того, чтобы определить соответствие дисков и их названий (букв), которое определяет связь названий дисков с разделами, на которые эти названия ссылаются. Например, диск C: может быть связан с разделом harddiskpartition1. HAL поддерживает любые присваивания названий, определенных пользователем с помощью Disk Administrator и считывает эту информацию из HKEY_LOCAL_MACHINE SYSTEMDisk.

К моменту завершения выполнения функции Phase1Initialization ядро NT Kernel и подсистемы Executive способны выполнять все свои обязанности. Последнее, что делает функция — это запускает Session Manager Subsystem (SMSS, которая располагается в winntsystem32smss.exe) процесса режима пользователя. SMSS отвечает за создание среды режима пользователя, которая предоставляет визуальный интерфейс для NT. SMSS, CSRSS и Winlogon

SMSS аналогична всем остальным процессам режима пользователя за исключением двух моментов. Во-первых, NT рассматривает SMSS как доверенную часть операционной системы, а во-вторых, SMSS — это встроенное приложение. Поскольку она является доверенным компонентом ОС, SMSS может выполнять действия, которые мало кто из других процессов способен осуществлять, такие как создание токенов защиты. Поскольку она является встроенным приложением, SMSS не использует прикладные программные интерфейсы Win32 API. Она использует только базовые интерфейсы Executive API, все вместе называемые Native API для NT. SMSS не использует Win32 API, потому что подсистема Win32 не работает, когда запускается SMSS. Фактически, одна из задач SMSS как раз и состоит в том, чтобы запустить подсистему Win32.

SMSS сначала обрабатывает команды в области Registry HKEY_ LOCAL_MACHINESYSTEMCurrentControlSetSession ManagerBoot Execute. Обычно эта область содержит одну команду для работы приложения проверки состояния диска CHKDSK. Во время исполнения CHKDSK выводит на экран информацию о состоянии каждого раздела, который он проверяет. SMSS создает файлы страничного обмена после работы CHKDSK так, что более крупные приложения могут начать свою работу. Затем SMSS вызывает Configuration Manager — подсистему Executive для того, чтобы закончить инициализацию Registry, присваивая значения всем ключам Registry. Для этого Configuration Manager загружает группу файлов, составляющих Registry, для ключей HKEY_LOCAL_ MACHINESAM, HKEY_LOCAL_ MACHINESAMSECURITY и HKEY_ LOCAL_MACHINESOFTWARE. Configuration Manager просматривает ключ HKEY_LOCAL_MACHINE SYSTEMCurrentControlSetHivelist для того, чтобы найти, где на диске располагаются файлы, составляющие Registry.

Затем SMSS загружает драйвер устройства win32k.sys, который реализует часть режима ядра подсистемы Win32. SMSS определяет расположение win32k.sys и других компонентов, которые он загружает, найдя пути к ним в HKEY_LOCAL_MACHINESYSTEMCurrentControlSet Session Manager. Наконец, SMSS запускает csrss.exe и winlogon.exe. CSRSS — это часть режима пользователя подсистемы Win32, а Winlogon — диспетчер регистрации. Вскоре после запуска win32k.sys, он переключает экран в графический режим. Чуть позже Winlogon запускает подсистему Services (winntsystem32services.exe), которая загружает все сервисы и драйверы устройств, промаркированные как Service Control Manager (SCM). Сервисы и драйверы Auto Start могут определять зависимость от конкретного сервиса за счет включения значения DependOnService в свои ключи Registry аналогично тому, как драйверы загрузки используют значение DependOnService. SCM сортирует и затем инициализирует сервисы и драйверы Auto Start в соответствии с их группами и значениями тегов также, как I/O Manager сортирует драйверы старта загрузки и старта системы.

Таблица 2: Значения ErrorControl

Значение Число Описание
IGNORE (0) I/O Manager игнорирует ошибки, которые возвращает драйвер. Никакие замечания в журнал ошибок не заносятся и не отображаются на экране.
NORMAL (1) Если драйвер сообщает об ошибке, отображается предупреждение.
SEVERE (2) Если драйвер возвращает ошибку и пользователь не выбрал опцию LastKnownGood, происходит перезагрузка с данными Last Known Good. В противном случае процесс загрузки продолжается.
CRITICAL (3) Если драйвер возвращает ошибку и пользователь не выбрал LastKnownGood, происходит перезагрузка с данными Last Known Good. В противном случае загрузка прерывается, о чем свидетельствует голубой экран дисплея.

После того, как SCM инициализирует сервисы и драйверы Auto Start, он считает, что загрузка успешно завершена. Подключ Registry HKEY_ TEMCurrentControlSet становится набором элементов управления Last Known Good, поскольку до этого момента загрузка системы проходила успешно. В начале загрузки NT сделала копию своего подключа и назвала эту копию HKEY_LOCAL_MACHINESYSTEMCLONE. Любые изменения драйверов, внесенные в существующий набор элементов управления во время загрузки, не отражаются в копии подключа CLONE. SCM копирует подключ CLONE в другой подключ элементов управления (например, HKEY_LOCAL_MACHINESYSTEMCurrentControlSet001) и SCM маркирует этот подключ элементов управления как Last Known Good. SCM маркирует подключ, устанавливая значение HKEY_LOCAL_MACHINESYSTEMSelectLastKnownGood так, чтобы указать трехзначный идентификатор в конце имени подключа набора элементов управления (например, 001). Если пользователь выбирает загрузку в меню Last Known Good во время первых шагов загрузки, или, если драйвер возвращает ошибки SEVERE или CRITICAL, система использует подключ Last Known Good в качестве HKEY_LOCAL_ MACHINESYSTEMCurrentControlSet. Такое решение увеличивает вероятность того, что загрузка системы завершится успешно, поскольку по крайней мере одна из предыдущих загрузок, использующая профайл Last Known Good, закончилась успешно. Приблизительно в тот момент, когда подсистема Services инициирует работу сетевых сервисов, Winlogon представляет пользователям первое диалоговое окно регистрации. Это действие и завершает процесс загрузки.

Выключение

В отличие от процесса загрузки, выключение системы выполняется очень просто. Во-первых, подсистема Win32 информирует все приложения Windows о том, что система готовится к выключению. Большинство приложений заканчивают работу «по своей воле», а Winlogon останавливает работу всех «несогласных». Winlogon руководит окончанием процесса выключения, вызывая функцию NtShutdownSystem подсистемы Executive. Эта функция вызывает I/O Manager, Configuration Manager, Memory Manager, а затем опять I/O Manager и информирует их о то, что они должны подготовится к выключению.

Когда NtShutdownSystem в первый раз вызывает I/O Manager, последний рассылает пакеты ввода/вывода, информирующие всех драйверов устройств, которые запрашивают такое уведомление, о выключении системы. Эта операция позволяет драйверам устройств выполнить любую специальную обработку, которое может потребоваться данному устройству перед окончанием работы NT. Configuration Manager копирует все измененные данные Registry на диск, а Memory Manager записывает все измененные страницы, содержащие данные о файлах в соответствующие файлы. Если включена опция очистки файла страничного обмена в момент выключения системы, то Memory Manager в этот момент очищает файл страничного обмена. Когда NtShutdownSystem вызывает I/O Manager во второй раз, I/O Manager информирует драйверы файловой системы о том, что система выключается. Наконец, если системный пользователь указывает опцию перезагрузки после выключения, система вызывает HAL для перезагрузки компьютера.

Разговором об отключении системы я завершаю свою серию из двух статей, посвященную процессу загрузки системы, которая по сути представляет собой описание операций, которые происходят скрыто от пользователя во время загрузки системы. В Таблице 3 представлено описание компонентов процесса загрузки с режимами исполнения и обязанностями. Понимание тонкостей процесса загрузки поможет вам диагностировать ошибки, которые могут возникать во время загрузки и позволит понять, как NT сама исправляет ошибки, возникающие в процессе загрузки.

Таблица 3: Компоненты процесса загрузки, режимы исполнения и обязанности

Компонент Режим исполнения процессора Обязанности
Код Master Boot 16-разрядный реальный режим Читает и загружает сектора Record (MBR) загрузки разделов.
Boot Sector 16-разрядный реальный режим FAT/NTFS для того, чтобы загрузить NTLDR. Читает корневой каталог
NTLDR 32-разрядный защищенный режим; включает поддержку страницЧитает boot.ini, представляет меню загрузки и загружает ntoskrnl.exe, hal.dll и драйве- ры старта загрузки устройств.
NTOSKRNL 32-разрядный защищенный режим с поддержкой страниц Инициализирует подсистемы Executive и загружает драйверы устройств старта системы, готовит систему для работы встроенных приложений и за- гружает SMSS.
SMSS 32-разрядный встроенное приложение NTЗагружает подсистему Win32, в том числе win32k.sys и csrss.exe. Запускает процесс Winlogon.
Winlogon 32-разрядное встроенное приложение NTПредоставляет интерфейс для регистрации. Запускает Service Control Manager (подсистему Services).
Services 32-разрядное встроенное приложение Загружает и инициализирует NT драйверы устройства Auto Start и сервисы Win32.

Windows 2000 и загрузка

Инициализация системы в Windows 2000 немногим отличается от аналогичного процесса в Windows NT 4.0. В Windows 2000 введены две подсистемы Executive: Plug and Play Manager и Power Manager. Первая интегрирована с I/O Manager и содержит функции инициализации. Однако драйверы инициализируются таким образом, чтобы адаптироваться к режиму Plug and Play. В Power Manager функция инициализации есть. Она называется PolnitSystem. Ее вызывает ExplnitializeExecutive для выполнения фазы 0 и фазы 1 инициализации перед вызовом функции инициализации Process Manager. PolnitSystem подготавливает Power Manager к реализации предусмотренной в системе политики управления питанием, уведомляет драйверы устройств о том, что состояние энергетической подсистемы меняется и обащается к уровню HAL.

Наиболее заметное изменение в процессе загрузки состоит в том, что меню загрузки системы включает опцию для загрузки в режиме safe mode. В последнем случае загружается усеченная конфигурация Windows 2000. Вместо привычного графического пользовательского интерфейса, режим safe mode предлагает окно с интерфейсом командной строки. Загружаются и инициализируются только драйверы и сервисы, специальным образом помеченные как относящиеся к данному режиму. Использование данного режима увеличивает вероятность того, что загрузка пройдет успешно, поскольку загружается только то, что действительно необходимо.