(o)Драйвер, который не требуется для загрузки системы и распознает устройство, не перечисляемое драйвером системной шины, указывает в Start значение, равное 1 (запуск системой). Пример – драйвер последовательного порта, информирующий диспетчер PnP о присутствии стандартных последовательных портов, которые были обнаружены программой Setup и зарегистрированы в реестре.
    (o)Драйвер, не поддерживающий Plug and Play, или драйвер файловой системы, не обязательный для загрузки системы, устанавливает значение Start равным 2 (автозапуск). Пример – драйвер многосетевого UNC-npoвайдера (Multiple UNC Provider, MUP), поддерживающий UNC-имена удаленных ресурсов (вроде \\REMOTECOMPUTERNAME\SHARE).
    (o)PnP-драйверы, не нужные для загрузки системы (например, драйверы сетевых адаптеров), указывают значение Start равным 3 (запуск по требованию). Единственное предназначение параметра Start для PnP-драйверов и драйверов перечисляемых устройств – загрузка драйвера с помощью загрузчика операционной системы, если такой драйвер обязателен для успешного запуска системы.
 
Перечисление устройств
   Диспетчер PnP начинает перечисление устройств с виртуального драйвера шины с именем Root, который представляет всю систему и выступает в роли драйвера шины для драйверов, не поддерживающих Plug and Play, и для HAL.
   HAL работает как драйвер шины, перечисляющий устройства, напрямую подключенные к материнской плате, и такие системные компоненты, как аккумуляторы. Определяя основную шину (обычно это PCI-шина) и устройства типа аккумуляторов и вентиляторов, HAL на самом деле полагается на описание оборудования, зафиксированное программой Setup в реестре еще при установке операционной системы.
   Драйвер основной шины перечисляет устройства на этой шине, при этом он может найти другие шины, драйверы которых инициализируются диспетчером PnP Эти драйверы в свою очередь могут обнаруживать другие устройства, включая вспомогательные шины. Такой рекурсивный процесс – перечисление, загрузка драйвера (если он еще не загружен), дальнейшее перечисление – продолжается до тех пор, пока не будут обнаружены и сконфигурированы все устройства в системе.
   По мере поступления сообщений от драйверов шин об обнаруженных устройствах, диспетчер PnP формирует внутреннее дерево, называемое деревом устройств(device tree) и отражающее взаимосвязи между устройствами. Узлы этого дерева называются узлами устройств(device nodes, devnodes). Узел устройств содержит информацию об объектах «устройство», представляющих устройства, и другую PnP-информацию, которая записывается в узел диспетчером PnP Упрощенный пример дерева устройств показан на рис. 9-25. Эта система ACPI-совместима, и поэтому перечислителем основной шины является ACPI-совместимый HAL. K основной шине PCI в данной системе подключены шины USB, ISA и SCSI.
   Диспетчер устройств, доступный из оснастки Computer Management (Управление компьютером) и с вкладки Hardware (Оборудование) окна свойств системы, отображает простой список устройств в системе, сконфигурированной по умолчанию. Для просмотра устройств в виде иерархического дерева можно выбрать в меню View (Вид) диспетчера устройств команду Devices By Connection устройства по подключению). Рис. 9-26 иллюстрирует, как выглядит окно диспетчера устройств при выборе этой команды.
   C учетом перечисления устройств загрузка и инициализация драйверов происходит в следующем порядке.
   1. Диспетчер ввода-вывода вызывает входную процедуру каждого драйвера, запускаемого при загрузке системы. Если у такого драйвера имеются дочерние устройства, диспетчер ввода-вывода перечисляет эти устройства, сообщая о них диспетчеру PnP Дочерние устройства конфигурируются и запускаются, если их драйверы являются запускаемыми при загрузке системы. Если у устройства есть драйвер, не запускаемый при загрузке системы, диспетчер PnP создает для этого устройства узел, но не запускает устройство и не загружает его драйвер.
   2. После инициализации драйверов, запускаемых при загрузке системы, диспетчер PnP проходит по дереву устройств, загружая драйверы для узлов устройств, не загруженных на первом этапе, и запускает их устройства. Запуская каждое устройство, диспетчер PnP перечисляет его дочерние устройства (если таковые есть). Для этого он запускает соответствующие драйверы и при необходимости перечисляет их дочерние устройства. Ha данном этапе диспетчер PnP загружает драйверы для обнаруженных устройств независимо om значений параметров Start этих драйве ров(кроме тех драйверов, параметр Start которых содержит значение «отключен»). B конце этого этапа драйверы всех PnP-устройств загружены и запущены, кроме драйверов не перечисляемых устройств и их дочерних устройств.
   3. Диспетчер PnP загружает любые еще не загруженные драйверы, запускаемые системой. Эти драйверы определяют свои устройства, не перечисляемые обычным образом, и сообщают о них. После этого диспетчер PnP загружает драйверы для этих устройств.
   4. Наконец, диспетчер управления сервисами (SCM) загружает автоматически запускаемые драйверы.
   Дерево устройств используется диспетчерами PnP и электропитания в то время, когда они выдают устройствам IRP-пакеты, связанные с Plug and Play и управлением электропитанием. Как правило, поток IRP распространяется от верхней части узла устройств вниз, и иногда какой-либо драйвер в одном из узлов устройств создает новые IRP для передачи другим узлам (всегда в направлении корня). O потоках IRP-пакетов, связанных с Plug and Play и управлением электропитанием, мы поговорим позже.
 
    ЭКСПЕРИМЕНТ: получаем дамп дерева устройств
   Команда !devnodeотладчика ядра позволяет более подробно изучить дерево устройств. Задав Oи 1в качестве параметров, вы получите дамп внутренних структур узлов этого дерева. При этом элементы структур выводятся с отступами, отражающими позиции элементов в общей иерархии.
   Информация, показываемая для каждого узла устройств, включает InstancePath (имя подраздела для перечисленного устройства в HKLM\ SYSTEM\CurrentControlSet\Enum) и ServiceName (имя подраздела для драйвера устройства в HKLM\SYSTEM\CurrentControlSet\Services). Чтобы просмотреть такие ресурсы, как прерывания, порты и диапазоны памяти, назначенные каждому узлу устройств, используйте команду !devnode 0 3.
   Все устройства, обнаруженные после установки системы, регистрируются в подразделах раздела реестра HKLM\SYSTEM\CurrentControlSet\Enum. Этим подразделам присваиваются имена в виде ‹Перечислителъ›\‹ID_устройства›\‹ID_экземпляра›,где перечислитель- драйвер шины, ID_ycmpouства- уникальный идентификатор устройств данного типа, а ID_ экземпляра- уникальный идентификатор данного экземпляра этого устройства.
 
Узлы устройств
   Узел устройств, который включает минимум два объекта «устройство», показан на рис. 9-27.
    (o) Объект «физическое устройство» (physical device object, PDO)Создается драйвером шины по заданию диспетчера PnP, когда драйвер шины, перечисляя устройства на своей шине, сообщает о наличии какого-либо устройства. PDO представляет физический интерфейс устройства.
    (o) Необязательные группы объектов-фильтров (filter device objects, FiDO)Одна группа таких объектов размещается между PDO и FDO (создается драйверами фильтров шин), вторая – между FDO и первой группой FiDO (создается низкоуровневыми драйверами фильтров), третья – над FDO (создается высокоуровневыми драйверами фильтров).
    (o) Объект «функциональное устройство» (functional device object, FDO)Создается функциональным драйвером, который загружается диспетчером PnP для управления обнаруженным устройством. FDO представляет логический интерфейс устройства. Функциональный драйвер может выступать и в роли драйвера шины, если к устройству, представленному FDO, подключены другие устройства. Этот драйвер часто создает интерфейс к PDO, соответствующему данному FDO, что позволяет приложениям и другим драйверам открывать устройство и взаимодействовать с ним. Иногда функциональные драйверы подразделяются на драйвер класса, порт-драйвер и минипорт-драйвер, совместно управляющие вводом-выводом для FDO.
   Узлы устройств полагаются на функциональность диспетчера ввода-вывода; поток IRP идет по узлу устройств сверху вниз. Решение об окончании обработки IRP может быть принято на любом уровне узла устройств. Например, функциональный драйвер может обработать запрос на чтение, не пересылая IRP драйверу шины. IRP проходит весь путь сверху вниз и далее к узлу устройств, содержащему драйвер шины, только если функциональному драйверу нужна помощь драйвера шины.
 
Загрузка драйверов для узла устройств
   До сих пор мы так и не ответили на два важных вопроса: как диспетчер PnP определяет, какой функциональный драйвер нужно загрузить для данного устройства и как драйверы фильтров регистрируют свое присутствие, чтобы их можно было загружать при создании узла устройств?
   Ответ на оба вопроса надо искать в реестре. Перечисляя устройства, драйвер шины сообщает диспетчеру PnP идентификаторы обнаруженных устройств. Эти идентификаторы специфичны для конкретной шины. Например, для шины USB такой идентификатор состоит из идентификатора изготовителя (vendor ID, VID) и идентификатора продукта (product ID, PID), назначенного устройству изготовителем (подробнее о форматах идентификаторов устройств см. в DDK). B совокупности эти идентификаторы образуют то, что в терминологии спецификации Plug and Play называется идентификатором устройства(device ID). Диспетчер PnP также запрашивает у драйвера шины идентификатор экземпляра(instance ID), который позволяет различать отдельные экземпляры одного и того же устройства. Идентификатор экземпляра может определять устройство относительно шины (например, USB-порт) или представлять глобально уникальный дескриптор (скажем, серийный номер устройства). Идентификаторы устройства и экземпляра дают идентификатор экземпляра устройства(device instance ID, DIID), используемый диспетчером PnP для поиска раздела устройства в ветви реестра HKLM\SYSTEM\CurrentControlSet\Enum. Пример такого раздела для клавиатуры показан на рис. 9-28. B эти разделы помещаются данные, характеризующие устройство, и получаемые из INF-файла параметры Service и ClassGUID, с помощью которых диспетчер PnP находит драйверы, нужные для данного устройства.
 
    ЭКСПЕРИМЕНТ: просмотр детальных сведений об узлах устройств в диспетчере устройств
   По умолчанию апплет Device Manager (Диспетчер устройств), доступный с вкладки Hardware (Оборудование) окна свойств системы, не показывает детальных сведений об узле устройств. Однако в Windows XP и Windows Server 2003 вы можете активизировать вкладку Details (Сведения), создав переменную окружения devmgr_show_details и присвоив ей значение 1. Ha этой вкладке отображается целый набор полей, в том числе идентификатор экземпляра устройства для узла, имя сервиса, фильтры и возможности в управлении электропитанием.
   Самый простой способ запустить диспетчер устройств с вкладкой Details – открыть окно командной строки и ввести:
    C:\›set devmgr_show_details=1 C:\›devmgmt.msc
 
   Ha следующем экранном снимке показано, как выглядит содержимое этой вкладки для одного из устройств.
   Параметр ClassGUID позволяет диспетчеру PnP найти раздел класса устройства в HKLM\SYSTEM\CurrentControlSet\Control\Class. Раздел класса клавиатур показан на рис. 9-29. Раздел, созданный для устройства в процессе перечисления, и раздел класса предоставляют диспетчеру PnP всю информацию, на основе которой он загружает драйверы, необходимые для узла данного устройства. Загрузка драйверов происходит в следующем порядке.
   1. Любые низкоуровневые драйверы фильтров, указанные в параметре LowerFilters раздела, созданного для устройства в процессе перечисления.
   2. Любые низкоуровневые драйверы фильтров, указанные в параметре Lo-werFilters раздела класса данного устройства.
   3. Функциональный драйвер, заданный в параметре Service раздела, созданного для устройства в процессе перечисления. Значение этого параметра интерпретируется как имя раздела драйвера в HKLM\SYSTEM\CurrentControlSet\Services.
   4. Любые высокоуровневые драйверы фильтров, указанные в параметре UpperFilters раздела, созданного для устройства в процессе перечисления.
   5. Любые высокоуровневые драйверы фильтров, указанные в параметре UpperFilters раздела класса данного устройства.
 
   Ссылки на драйверы всегда содержат имена их разделов в HKLM\SYSTEM\ CurrentControlSet\Services.
 
    ПРИМЕЧАНИЕ B DDK раздел, созданный для устройства в процессе перечисления, называется аппаратным (hardware key), а раздел класса – программным (software key).
 
   Устройство «клавиатура», представленное на рис. 9-28 и 9-29, не имеет низкоуровневых драйверов фильтров. Его функциональный драйвер – i8042prt; в разделе класса клавиатур указано два высокоуровневых драйвера фильтров – kbdclass и ctrl2cap.
 
Установка драйвера
   Если диспетчер PnP встречает устройство, драйвер которого не установлен, он обращается к диспетчеру PnP пользовательского режима, и тот устанавливает нужный драйвер. Если устройство обнаруживается при загрузке системы, для него определяется узел устройств, но загрузка драйверов откладывается до запуска диспетчера PnP пользовательского режима (он реализован в \Windows\System32\Umpnpmgr.dllи выполняется как сервис в процессе Services.exe).
   Компоненты, участвующие в установке драйвера, показаны на рис. 9-30. Серые блоки на этом рисунке соответствуют компонентам, обычно предоставляемым системой, а остальные блоки – компонентам, предоставляемым установочными файлами. Сначала драйвер шины информирует диспетчер PnP о перечисленном устройстве, сообщая его DIID (1). Диспетчер PnP проверяет, определен ли в реестре подходящий функциональный драйвер. Если нет, он уведомляет диспетчер PnP пользовательского режима (2) о новом устройстве, сообщая его DIID. Диспетчер PnP пользовательского режима пытается автоматически установить драйверы для устройства. Если в процессе установки выводятся диалоговые окна, требующие внимания пользователя, а зарегистрированный в данный момент пользователь имеет привилегии администратора (3), то диспетчер PnP пользовательского режима запускает Rundll32.exe (хост-программу апплетов Control Panel) для выполнения мастера установки оборудования ( \Windows\System32\Newdev.dll). Если зарегистрированный в данный момент пользователь не имеет привилегий администратора (или в системе нет пользователей), а установка устройства требует взаимодействия с пользователем, диспетчер PnP пользовательского режима откладывает установку до того момента, когда в систему войдет привилегированный пользователь. Для поиска INF-файлов, соответствующих драйверам, совместимым с обнаруженным устройством, мастер установки оборудования использует API-функции Setup и CfgMgr (диспетчера конфигурации). При этом пользователю может быть предложено вставить в один из дисководов носитель с нужными INF-файлами; кроме того, просматриваются INF-файлы в \Windows\Driver Cache\i386\Driver.cab, где содержатся драйверы, поставляемые с Windows.
   Чтобы найти драйверы для нового устройства, процесс установки получает от драйвера шины список идентификаторов оборудования (hardware ID) и идентификаторов совместимых устройств (compatible ID). Эти идентификаторы описывают все способы, предусмотренные в установочном файле драйвера (INF-файле) для идентификации устройства. Списки упорядочиваются так, чтобы наиболее специфические характеристики устройства описывались первыми. Если совпадения идентификаторов обнаруживаются в нескольких INF-файлах, предпочтение отдается наиболее полным совпадениям. Аналогичным образом предпочтение отдается INF-файлам с цифровой подписью, а среди них – более новым. Если найденный идентификатор соответствует идентификатору совместимого устройства, мастер установки оборудования может запросить носитель с обновленными драйверами для этого устройства.
   INF-файл определяет местонахождение файлов функционального драйвера и содержит команды, которые вводят нужные данные в раздел перечисления и раздел класса драйвера. INF-файл может указать мастеру установки оборудования запустить DLL установщика класса или компонента, участвующего в установке устройства (4), – эти модули выполняют операции, специфичные для класса или устройства, например выводят диалоговые окна, позволяющие настраивать параметры устройства.
 
    ЭКСПЕРИМЕНТ: просмотр INF-файла драйвера
   При установке драйвера или другого программного обеспечения, у которого есть INF-файл, система копирует этот файл в каталог \Win-dows\Inf. Один из файлов, которые всегда будут в этом каталоге, – Keyboard.inf, поскольку это INF-файл для драйвера класса клавиатур. Просмотрите его содержимое, открыв в Notepad. Вы должны увидеть нечто вроде:
 
   ; Copyright (с) 1993-1996, Microsoft Corporation
   [version]
   signature="$Windows NT$" Class=Keyboard
   ClassGUID={4D36E96B-E325-11CE-BFC1-08002BE10318}
   Provider=XMSX
   LayoutFile=layout.inf
   DriverVer=07/01/2001, 5.1.2600.1106
   [ClassInstall32.NT] AddReg=keyboa rd_class_add reg
 
   Если вы проведете поиск в этом файле по «.sys», то обнаружите запись, указывающую диспетчеру PnP пользовательского режима установить драйверы i8042prt.sys и kbdclass.sys:
   [STANDARD_CopyFiles]
   i8042prt.sys
   kbdclass.sys
 
   Перед установкой драйвера диспетчер PnP пользовательского режима проверяет системную политику проверки цифровых подписей в драйверах. Эта политика хранится в разделе реестра HKLM\SOFTWARE\Microsoft\Driver Signing\Policy, если администратор выбрал общесистемную политику, или в HKCU\Software\Microsoft\Driver Signing\Policy, если в системе применяются политики только по отношению к индивидуальным пользователям. Политика проверки цифровых подписей в драйверах настраивается через диалоговое окно Driver Signing Options (Параметры подписывания драйвера), доступное с вкладки Hardware (Оборудование) окна свойств системы (рис. 9-31). Если указанные параметры заставляют систему блокировать установку неподписанных драйверов или предупреждать о таких попытках, диспетчер PnP пользовательского режима проверяет в INF-файле драйвера запись, указывающую на каталог (файл с расширением .cat), где содержится цифровая подпись драйвера.
    Рис. 9-31. Параметры проверки цифровых подписей в драйверах
   Лаборатория Microsoft WHQL тестирует драйверы, поставляемые с Windows и предлагаемые изготовителями оборудования. Драйвер, прошедший тесты WHQL, «подписывается» Microsoft. Это означает, что создается хэш,или уникальное значение, представляющее файлы драйвера, в том числе его образ, а затем этот хэш подписывается с применением закрытого ключа Microsoft, предназначенного для подписания драйверов. Подписанный хэш помещается в САТ-файл и записывается на дистрибутив Windows или передается изготовителю, который включает его в свой драйвер.
 
    ЭКСПЕРИМЕНТ: просмотр САТ-файлов
   При установке компонента, например драйвера, файлы которого включают САТ-файл, Windows копирует этот файл в подкаталог каталога \Windows\System32\Catroot. Перейдите в этот каталог с помощью Explorer и найдите подкаталог с САТ-файлами. B частности, в Nt5.cat и Nt5inf.cat хранятся подписи для системных файлов Windows.
   Открыв один из САТ-файлов, вы увидите диалоговое окно с двумя вкладками: General (Общие), на которой показывается информация о подписи в данном файле, и Security Catalog (Каталог безопасности), где представлены хэши компонентов, подписанных с использованием этого САТ-файла. Ниже дан пример САТ-файла для видеодрайверов ATI, где приведено содержимое хэша для минипорт-драйверов видеоадаптера. Остальные хэши в этом файле относятся к вспомогательным DLL, поставляемым с данными драйверами.
   При установке драйвера диспетчер PnP пользовательского режима извлекает из САТ-файла подпись драйвера, расшифровывает ее с применением открытого ключа Microsoft и сравнивает полученный в результате хэш с хэшем файла устанавливаемого драйвера. Если хэши совпадают, драйвер считается проверенным на соответствие требованиям WHQL. Если проверка заканчивается неудачно, диспетчер PnP пользовательского режима действует так, как это диктует действующая политика: запрещает установку, предупреждает пользователя о том, что драйвер не подписан, или автоматически устанавливает драйвер.
 
    ПРИМЕЧАНИЕ Наличие подписей у драйверов, устанавливаемых программами установки, которые самостоятельно настраивают реестр и копируют файлы драйвера в систему, а также у драйверов, динамически загружаемых приложениями, не проверяется. Политика проверки подписей драйверов распространяется только на драйверы, устанавливаемые с помощью INF-файлов.
 
   После установки драйвера диспетчер PnP режима ядра (этап 5 на рис. 9-30) запускает драйвер и вызывает его процедуру добавления устройства, чтобы уведомить драйвер о присутствии устройства, для управления которым он был загружен. Далее формируется узел устройства, как мы уже объясняли.
 
    ПРИМЕЧАНИЕ B Windows XP и Windows Server 2003 диспетчер PnP пользовательского режима также проверяет, не включен ли устанавливаемый драйвер в защищенный список драйверов (protected driver list), поддерживаемых Windows Update, и, если включен, блокирует установ ку с выводом предупреждения для пользователя. B этот список вносятся драйверы, которые имеют известные ошибки или просто несовместимы, и их установка блокируется. Детали см. по ссылке www.micro- soft.com/whdc/winlogo/drvsign/drv _protect.mspx.
 
Диспетчер электропитания
   Как и PnP-функции Windows, управление электропитанием требует аппаратной поддержки. Она должна отвечать спецификации Advanced Configuration and Power Interface (ACPI) (см. www.teleport.com^acpi/spechtm ).Согласно этой спецификации BIOS (Basic Input Output System) тоже должна соответствовать стандарту ACPI. Этим требованиям удовлетворяет большинство x86-компьютеров, выпускавшихся с конца 1998 года.
 
    ПРИМЕЧАНИЕ Некоторые компьютеры – особенно те, которые были изготовлены несколько лет назад, – не полностью совместимы со стандартом ACPI. Они соответствуют более старому стандарту Advanced Power Management (АРМ), определяющему меньшее количество функций управления электропитанием, чем ACPI. Windows поддерживает ограниченный набор функций управления электропитанием для АРМ-систем, но мы не будем вдаваться в детали этого стандарта и основное внимание уделим поведению Windows, установленной на ACPI-совместимых компьютерах.
 
   Стандарт ACPI определяет различные уровни энергопотребления для системы и устройств. Шесть состояний для системы – от SO (полностью активное, или рабочее, состояние) до S5 (полное отключение) – перечислены в таблице 9-3. Каждое из них характеризуется следующими параметрами.
    (o) Энергопотребление (power consumption)Количество энергии, потребляемой компьютером.
    (o) Возобновление работы ПО (software resumption)Состояние программного обеспечения при переходе компьютера в «более активное» состояние.
    (o) Аппаратная задержка (hardware latency)Время, необходимое на то, чтобы вернуть компьютер в полностью активное состояние.
 
   B состояния ожидания (S1 -S4) компьютер кажется отключенным, так как потребляет меньше энергии. Ho при этом он сохраняет и в памяти, и на диске всю информацию, необходимую для возврата в состояние S0. B состояниях S1-S3 для сохранения содержимого памяти нужно достаточное количество энергии, поскольку при переходе в S0 (при пробуждении компьютера пользователем или устройством) диспетчер электропитания возобновляет работу системы с той точки, где оно было прервано. Когда система переходит в состояние S4, диспетчер электропитания сохраняет содержимое памяти в сжатой форме в файле спящего режима (Hiberfil.sys), который помещается в корневой каталог системного тома. (Этот файл должен быть такого размера, чтобы в нем могло уместиться несжатое содержимое всей памяти; сжатие используется для того, чтобы свести к минимуму операции ввода-вывода на диске, а также ускорить переход в спящий режим и выход из него.) Сохранив содержимое памяти, диспетчер электропитания отключает компьютер. При последующем включении компьютера происходит обычный процесс загрузки – с тем исключением, что Ntldr проверяет наличие действительного образа памяти, сохраненного в файле спящего режима. Если в этом файле сохранены данные о состоянии системы, Ntldr считывает его содержимое в память и возобновляет выполнение с точки, зафиксированной в Hiberfil.sys.
   Компьютер никогда не переходит напрямую между состояниями S1 и S4, для этого ему нужно сначала перейти в состояние S0. Как показано на рис. 9-32, переход системы из состояний S1-S5 в состояние S0, называется пробуждением(waking), а переход из состояния SO в состояния Sl-S5 – переходом в сон(sleeping).
   Хотя система может пребывать в одном из шести состояний энергопотребления, ACPI определяет для устройств четыре состояния: D0-D3. B состоянии DO устройство полностью включено, а в состоянии D3 полностью отключено. ACPI позволяет драйверам и устройствам самостоятельно определять состояния Dl и D2 с единственным условием, что устройство в состоянии D1 должно потреблять столько же или меньше энергии, чем в состоянии D0, а в состоянии D2 – столько же или меньше, чем в состоянии D1. Microsoft совместно с крупными OEM-производителями определила набор спецификаций управления электропитанием (см.