Страница:
Как и подсистема POSIX, подсистема OS/2 автоматически запускается при первой активизации OS/2-совместимого образа и продолжает выполняться до перезагрузки всей системы.
Подробнее о выполнении приложений POSIX и OS/2 в Windows см. главу 6.
Ntdll.dll - специальная библиотека системной поддержки, нужная в основном при использовании DLL подсистем. Она содержит функции двух типов:
(o)интерфейсы диспетчера системных сервисов (system service dispatch stubs) к сервисам исполнительной системы Windows;
(o)внутренние функции поддержки, используемые подсистемами, DLL подсистем и другими компонентами операционной системы. Первая группа функций предоставляет интерфейс к сервисам исполнительной системы Windows, которые можно вызывать из пользовательского режима. Таких функций более 200, например NtCreateFile, NtSetEventи т. д. Как уже говорилось, большинство из них доступно через Windows API (однако некоторые из них предназначены только для применения внутри самой операционной системы).
Для каждой из этих функций в Ntdll существует точка входа с тем же именем. Код внутри функции содержит специфичную для конкретной аппаратной архитектуры команду перехода в режим ядра для вызова диспетчера системных сервисов (о нем рассказывается в главе 3), который после проверки некоторых параметров вызывает уже настоящий сервис режима ядра из Ntoskrnl.exe.
Ntdll также включает множество функций поддержки, например загрузчик образов (функции, имена которых начинаются с Ldr),диспетчер куч, функции для взаимодействия с процессом подсистемы Windows (функции, имена которых начинаются с Csr),а также универсальные процедуры библиотек периода выполнения (функции, имена которых начинаются с Rtl).Там же находится диспетчер APC (asynchronous procedure call) пользовательского режима и диспетчер исключений. (Подробнее об APC и исключениях см. главу 3.)
Исполнительная система (executive) находится на верхнем уровне Ntoskrnl.exe (ядро располагается на более низком уровне). B ее состав входят функции следующего типа.
(o)Экспортируемые функции, доступные для вызова из пользовательского режима. Эти функции называются системными сервисамии экспортируются через Ntdll. Большинство сервисов доступно через Windows API или API других подсистем окружения. Однако некоторые из них недоступны через документированные функции (примером могут служить LPC, функции запросов вроде NtQueryInformationProcess,специализированные функции типа NtCreatePagingFileи т. д.).
(o)Функции драйверов устройств, вызываемые через функцию DeviceIoCont-rol.Последняя является универсальным интерфейсом от пользовательского режима к режиму ядра для вызова функций в драйверах устройств, не связанных с чтением или записью.
(o)Экспортируемые функции, доступные для вызова только из режима ядра и документированные в Windows DDK или Windows Installable File System (IFS) Kit (см. wwwmicrosoft.com/whdc/ddk/ifskit.default.mspx ).
(o)Экспортируемые функции, доступные для вызова только из режима ядра, но не описанные в Windows DDK или IFS Kit (например, функции, которые используются видеодрайвером, работающим на этапе загрузки, и чьи имена начинаются с Inbv).
(o)Функции, определенные как глобальные, но не экспортируемые символы. Включают внутренние функции поддержки, вызываемые в Ntoskrnl; их имена начинаются с Iop(функции поддержки диспетчера ввода-вывода) или с Mi(функции поддержки управления памятью).
(o)Внутренние функции в каком-либо модуле, не определенные как глобальные символы. Исполнительная система состоит из следующих основных компонентов (каждый из них подробно рассматривается в последующих главах книги).
(o) Диспетчер конфигурации(см. главу 4), отвечающий за реализацию и управление системным реестром.
(o) Диспетчер процессов и потоков(см. главу 6), создающий и завершающий процессы и потоки. Низкоуровневая поддержка процессов и потоков реализована в ядре Windows, а исполнительная система дополняет эти низкоуровневые объекты своей семантикой и функциями.
(o) Монитор состояния защиты(см. главу 8), реализующий политики безопасности на локальном компьютере. Он охраняет ресурсы операционной системы, осуществляя аудит и контролируя доступ к объектам в период выполнения.
(o) Диспетчер ввода-вывода(см. главу 9), реализующий аппаратно-независимый ввод-вывод и отвечающий за пересылку ввода-вывода нужным драйверам устройств для дальнейшей обработки.
(o) Диспетчер Plug and Play(см. главу 9), определяющий, какие драйверы нужны для поддержки конкретного устройства, и загружающий их. Требования каждого устройства в аппаратных ресурсах определяются в процессе перечисления. B зависимости от требований каждого устройства диспетчер PnP распределяет такие ресурсы, как порты ввода-вывода, IRQ, каналы DMA и области памяти. Он также отвечает за посылку соответствующих уведомлений об изменениях в аппаратном обеспечении системы (при добавлении или удалении устройств).
(o) Диспетчер электропитания(см. главу 9), который координирует события, связанные с электропитанием, и генерирует уведомления системы управления электропитанием, посылаемые драйверам. Когда система не занята, диспетчер можно настроить на остановку процессора для снижения энергопотребления. Изменение энергопотребления отдельных устройств возлагается на их драйверы, но координируется диспетчером электропитания.
(o) Подпрограммы WDM Windows Management Instrumentation(см. главу 4), позволяющие драйверам публиковать информацию о своих рабочих характеристиках и конфигурации, а также получать команды от службы
WMI пользовательского режима. Потребители информации WMI могут находиться как на локальной машине, так и на любом компьютере в сети.
(o) Диспетчер кэша(см. главу 11), повышающий производительность файлового ввода-вывода за счет сохранения в основной памяти дисковых данных, к которым недавно было обращение (это также уменьшает число обращений к диску для записи, поскольку модифицированные данные предварительно накапливаются в памяти в течение определенного периода). Как вы увидите, диспетчер кэша выполняет эту задачу, используя поддержку проецируемых файлов со стороны диспетчера памяти.
(o) Диспетчер памяти(см. главу 7), реализующий виртуальную память - схему управления памятью, позволяющую выделять каждому процессу большое закрытое адресное пространство, объем которого может превышать доступную физическую память. Диспетчер памяти также обеспечивает низкоуровневую поддержку диспетчера кэша.
(o) Средство логической предвыборки(см. главу 7), ускоряющее запуск системы и процессов за счет оптимизации загрузки данных, к которым происходит обращение при запуске системы или процессов. Кроме того, в состав исполнительной системы входят четыре основные группы функций поддержки, используемые вышеперечисленными компонентами. Примерно треть из них описана в DDK, поскольку драйверы тоже используют их. Вот что представляют собой четыре категории функций поддержки.
(o) Диспетчер объектов- создает, управляет и удаляет объекты и абстрактные типы данных исполнительной системы, используемые для представления таких ресурсов операционной системы, как процессы, потоки и различные синхронизирующие объекты. Подробнее о диспетчере объектов см. главу 3-
(o) Механизм LPC(см. главу 3) - передает сообщения между клиентским и серверным процессами на одном компьютере. LPC является гибкой, оптимизированной версией RPC (remote procedure call), стандартного механизма взаимодействия между клиентскими и серверными процессами через сеть.
(o)Большой набор стандартных библиотечных функций для обработки строк, арифметических операций, преобразования типов данных и обработки структур безопасности.
(o) Подпрограммы поддержки исполнительной системы,например для выделения системной памяти (пулов подкачиваемых и неподкачиваемых страниц), доступа к памяти со взаимоблокировкой, а также два специальных типа синхронизирующих объектов: ресурс (resource) и быстродействующий мьютекс (fast mutex).
Ядро состоит из набора функций в Ntoskrnl.exe, предоставляющих фундаментальные механизмы (в том числе планирования потоков и синхронизации), которые используются компонентами исполнительной системы и низкоуровневыми аппаратно-зависимыми средствами поддержки (диспетчеризации прерываний и исключений), различными в каждой процессорной архитектуре. Код ядра написан в основном на С, а ассемблер использовали лишь для решения специфических задач, трудно реализуемых на С.
Как и функции поддержки исполнительной системы, упоминавшиеся в предыдущем разделе, часть функций ядра описана в DDK (см. функции, чьи имена начинаются с Ke),поскольку они необходимы для реализации драйверов устройств.
Ядро состоит из низкоуровневых, четко определенных и хорошо предсказуемых примитивов и механизмов операционной системы, позволяющих компонентам исполнительной системы более высокого уровня выполнять свои функции. Ядро отделено от остальной части исполнительной системы; оно реализует системные механизмы и не участвует в принятии решений, связанных с системной политикой. Практически все такие решения, кроме планирования и диспетчеризации потоков, принимаются исполнительной системой.
Вне ядра исполнительная система представляет потоки и другие разделяемые ресурсы в виде объектов. Управление этими объектами требует определенных издержек, так как нужны описатели, позволяющие манипулировать объектами, средства защиты и квоты ресурсов, резервируемых при их создании. B ядре можно избежать таких издержек, поскольку оно реализует набор более простых объектов, называемых объектами ядра(kernel objects). Эти объекты позволяют ядру контролировать обработку данных процессором и поддерживают объекты исполнительной системы. Большинство объектов уровня исполнительной системы инкапсулирует один или более объектов ядра, включая в себя их атрибуты, определенные ядром.
Одна из групп объектов ядра, называемых управляющими(control objects), определяет семантику управления различными функциями операционной системы. B эту группу входят объекты APC, DPC (deferred procedure call) и несколько объектов, используемых диспетчером ввода-вывода (например, объект прерывания).
Другая группа объектов под названием объекты диспетчера(dispatcher objects) реализует средства синхронизации, позволяющие изменять планирование потоков. B группу таких объектов входят поток ядра (kernel thread), мьютекс (mutex), событие (event), семафор (semaphore), таймер (timer), ожидаемый таймер (waitable timer) и некоторые другие. C помощью функций ядра исполнительная система создает объекты ядра, манипулирует ими и конструирует более сложные объекты, предоставляемые в пользовательском режиме. Объекты подробно рассматриваются в главе 3, а процессы и потоки - в главе 6.
Другая важная задача ядра - абстрагирование или изоляция исполнительной системы и драйверов устройств от различий между аппаратными архитектурами, поддерживаемыми Windows (т. е. различий в обработке прерываний, диспетчеризации исключений и синхронизации между несколькими процессорами).
Архитектура ядра нацелена на максимальное обобщение кода - даже в случае аппаратно-зависимых функций. Ядро поддерживает набор семантически идентичных и переносимых между архитектурами интерфейсов. Большая часть кода, реализующего переносимые интерфейсы, также идентична для разных архитектур.
Ho одна часть этих интерфейсов по-разному реализуется на разных архитектурах, а другая включает код, специфичный для конкретной архитектуры. Архитектурно-независимые интерфейсы могут быть вызваны на любой машине, причем семантика интерфейса будет одинаковой - независимо от специфического кода для той или иной архитектуры. Некоторые интерфейсы ядра (например, процедуры спин-блокировки, описанные в главе 3) на самом деле реализуются в HAL (см. следующий раздел), поскольку их реализация может отличаться даже в пределах семейства процессоров с одинаковой архитектурой.
B ядре также содержится небольшая порция кода с х86-специфичными интерфейсами, необходимыми для поддержки старых программ MS-DOS. Эти интерфейсы не являются переносимыми в том смысле, что их нельзя вызывать на машине с другой архитектурой, где они попросту отсутствуют. Этот х86-специфичный код, например, поддерживает манипуляции с GDT (global descriptor tables) и LDT (local descriptor tables) - аппаратными средствами x86.
Другим примером архитектурно-специфичного кода ядра может служить интерфейс, предоставляющий поддержку буфера трансляции и процессорного кэша. Эта поддержка требует разного кода на разных архитектурах, поскольку кэш в них реализуется различным образом.
Еще один пример - переключение контекста. Хотя на высоком уровне для выбора потоков и переключения контекста применяется один и тот же алгоритм (сохраняется контекст предыдущего потока, загружается контекст нового и запускается новый поток), существуют архитектурные различия между его реализациями для разных процессоров. Поскольку контекст описывается состоянием процессора (его регистров и т. д.), сохраняемая и загружаемая информация зависит от архитектуры.
Как отмечалось в начале этой главы, одной из важнейших особенностей архитектуры Windows является переносимость между различными аппаратными платформами. Ключевой компонент, обеспечивающий такую переносимость, - уровень абстрагирования от оборудования (hardware abstraction layer, HAL). HAL - это загружаемый модуль режима ядра (Hal.dll), предоставляющий низкоуровневый интерфейс с аппаратной платформой, на которой выполняется Windows. Он скрывает от операционной системы специфику конкретной аппаратной платформы, в том числе ее интерфейсов ввода-вывода, контроллеров прерываний и механизмов взаимодействия между процессорами, т. е. все функции, зависимые от архитектуры и от конкретной машины.
Когда внутренним компонентам Windows и драйверам устройств нужна платформенно-зависимая информация, они обращаются не к самому оборудованию, а к подпрограммам HAL, что и обеспечивает переносимость этой операционной системы. По этой причине подпрограммы HAL документированы в Windows DDK, где вы найдете более подробные сведения о HAL и о его использовании драйверами.
Хотя в Windows имеется несколько модулей HAL (см. таблицу 2-6), при установке на жесткий диск компьютера копируется только один из них - Hal.dll. (B других операционных системах, например в VMS, нужный модуль HAL выбирается при загрузке системы.) Поскольку для поддержки разных процессоров требуются разные модули HAL, системный диск от одной х8б-установки скорее всего не подойдет для загрузки системы с другим процессором.
Таблица 2-6. Список модулей HAL для x86 в \ Windows\Driver\Cache\i386\Driver.cab
ПРИМЕЧАНИЕ B базовой системе Windows Server 2003 нет HAL, специфических для конкретных вендоров.
ЭКСПЕРИМЕНТ: просмотр базовых HAL, включенных в Windows
Для просмотра HAL, включенных в Windows, откройте файл Driver.cab в соответствующем подкаталоге, специфичном для конкретной архитектуры, в каталоге \Windows\Driver Cache. (Например, для систем x86 имя этого файла - \Windows\Driver Cache\i386\Driver.cab.) Прокрутите список до файлов, начинающихся с «Hal», и вы увидите файлы, перечисленные в таблице 2-6.
ЭКСПЕРИМЕНТ: определяем используемый модуль HAL
Определить, какой модуль HAL используется на вашей машине, можно двумя способами.
1. Откройте файл \Windows\Repair\Setup.log, найдите строку с Haldll.Имя файла, стоящее в этой строке после знака равенства, соответствует имени модуля HAL, извлеченного из Driver.cab с дистрибутивного носителя.
2. Откройте Device Manager (Диспетчер устройств): щелкните правой кнопкой мыши значок My Computer (Мой компьютер) на рабочем столе, выберите команду Properties (Свойства), откройте вкладку Hardware (Оборудование) и щелкните кнопку Device Manager (Диспетчер устройств). Проверьте имя «драйвера» для устройства Computer (Компьютер).
ЭКСПЕРИМЕНТ: просмотр зависимостей NTOSKRNL и HAL
Вы можете просмотреть взаимосвязи образов ядра и HAL, изучив их таблицы импорта и экспорта с помощью утилиты Dependency Walker (Depends.exe), которая содержится в Windows Support Tools и Platform SDK. Для исследования файла в Dependency Walker откройте его командой Open из меню File.
Вот пример вывода этой утилиты при просмотре зависимостей в Ntoskrnl.
Обратите внимание, что Ntoskrnl связан с HAL, который в свою очередь связан с Ntoskrnl (оба используют функции друг у друга). Ntoskrnl также связан с Bootvid.dll, видеодрайвером, используемым для вывода заставки при запуске Windows. B Windows XP и выше вы увидите в списке дополнительную DLL, Kdcom.dll. Она содержит код инфраструктуры отладчика ядра, который раньше был частью Ntoskrnl.exe.
Подробное описание информации, выводимой Dependency Walker, см. в справочном файле этой утилиты (Depends.hlp).
Драйверы устройств подробно описываются в главе 9, а здесь мы даем краткий обзор их типов и поясняем, как перечислить установленные драйверы, загруженные в системе.
Драйверы устройств являются загружаемыми модулями режима ядра (как правило, это файлы с расширением .sys); они образуют интерфейс между диспетчером ввода-вывода и соответствующим оборудованием. Эти драйверы выполняются в режиме ядра в одном из трех контекстов:
(o)в контексте пользовательского потока, инициировавшего функцию ввода-вывода;
(o)в контексте системного потока режима ядра;
(o)как результат прерывания (а значит, не в контексте какого-либо процесса или потока, который был текущим на момент прерывания). Как было сказано в предыдущем разделе, в Windows драйверы устройств не управляют оборудованием напрямую - вместо этого они вызывают функции HAL. Драйверы, как правило, пишутся на C (иногда на C++), поэтому при правильном использовании процедур HAL они являются переносимыми между поддерживаемыми Windows архитектурами на уровне исходного кода, а на уровне двоичных файлов - внутри семейства с одинаковой архитектурой. Существует несколько типов драйверов устройств.
(o) Драйверы аппаратныхустройств,которые управляют (через HAL) оборудованием, записывают на них выводимые данные и получают вводимые данные от физического устройства или из сети. Есть множество типов таких драйверов - драйверы шин, интерфейсов, устройств массовой памяти и т. д.
(o) Драйверы файловой системы- это драйверы Windows, принимающие запросы на файловый ввод-вывод и транслирующие их в запросы ввода-вывода для конкретного устройства.
(o) Драйверы фильтра файловой системы,которые обеспечивают зеркали-рование и шифрование дисков, перехват ввода-вывода и некоторую дополнительную обработку информации перед передачей ее на следующий уровень.
(o) Сетевые редиректорыи серверы,являющиеся драйверами файловых систем, которые передают запросы файловой системы на ввод-вывод другим компьютерам в сети и принимают от них аналогичные запросы.
(o) Драйверы протоколов,реализующие сетевые протоколы вроде TCP/IP, NetBEUI и IPX/SPX.
(o) Драйверы потоковых фильтров ядра,действующие по цепочке для обработки потоковых данных, например при записи и воспроизведении аудио- и видеоинформации.
Поскольку установка драйвера устройства - единственный способ добавления в систему стороннего кода режима ядра, некоторые программисты пишут драйверы просто для того, чтобы получить доступ к внутренним функциям или структурам данных операционной системы, недоступным из пользовательского режима (но документированным и поддерживаемым в DDK). Например, многие утилиты с www.sysinternals.com представляют собой комбинацию GUI-приложений Windows с драйверами устройств, используемыми для сбора сведений о состоянии внутрисистемных структур и вызова функций, доступных только в режиме ядра.
B Windows 2000 была введена поддержка Plug and Play и энергосберегающих технологий, а также расширена модель драйверов Windows NT, называемая Windows Driver Model (WDM). Windows 2000 и более поздние версии могут работать с унаследованными драйверами Windows NT 4, но, поскольку они не поддерживают Plug and Play и энергосберегающие технологии, функциональность системы в этом случае будет ограничена. C точки зрения WDM, существует три типа драйверов.
(o) Драйвер шины(bus driver), обслуживающий контроллер шины, адаптер, мост или любые другие устройства, имеющие дочерние устройства. Драйверы шин нужны для работы системы и в общем случае поставляются Microsoft. Для каждого типа шины (PCI, PCMCIA и USB) в системе имеется свой драйвер. Сторонние разработчики создают драйверы для поддержки новых шин вроде VMEbus, Multibus и Futurebus.
(o) Функциональный драйвер(function driver) - основной драйвер устройства, предоставляющий его функциональный интерфейс. Обязателен, кроме тех случаев, когда устройство используется без драйверов (т. е. ввод-вывод осуществляется драйвером шины или драйверами фильтров шины, как в случае SCSI PassThru). Функциональный драйвер по определению обладает наиболее полной информацией о своем устройстве. Обычно только этот драйвер имеет доступ к специфическим регистрам устройства.
(o) Драйвер фильтра(filter driver), поддерживающий дополнительную функциональность устройства (или существующего драйвера) или изменяющий запросы на ввод-вывод и ответы на них от других драйверов (это часто используется для коррекции устройств, предоставляющих неверную информацию о своих требованиях к аппаратным ресурсам). Такие драйверы не обязательны, и их может быть несколько. Они могут работать как на более высоком уровне, чем функциональный драйвер или драйвер шины, так и на более низком. Обычно эти драйверы предоставляются OEM-производителями или независимыми поставщиками оборудования (IHV).
B среде WDM один драйвер не может контролировать все аспекты устройства: драйвер шины информирует диспетчер PnP об устройствах, подключенных к шине, в то время как функциональный драйвер управляет устройством.
B большинстве случаев драйвер фильтра более низкого уровня модифицирует поведение устройства. Например, если устройство сообщает драйверу своей шины о том, что ему нужно 4 порта ввода-вывода, тогда как на самом деле ему требуется 16, драйвер фильтра может перехватить список аппаратных ресурсов, направляемый драйвером шины диспетчеру PnP и исправить число портов.
Драйвер фильтра более высокого уровня обычно придает устройству дополнительную функциональность. Так, высокоуровневый драйвер фильтра для клавиатуры может обеспечивать дополнительную защиту.
Обработка прерываний описывается в главе 3. Подробнее о диспетчере ввода-вывода, WDM, Plug and Play и энергосберегающих технологиях см. главу 9.
ЭКСПЕРИМЕНТ: просмотр установленных драйверов устройств
Чтобы вывести список установленных драйверов, запустите оснастку Computer Management ^Управление компьютером). Для этого выберите из меню Start (Пуск) команду Programs (Программы), затем Administrative Tools (Администрирование) и Computer Management ^правление компьютером) или откройте Control Panel (Панель управления) и дважды щелкните значок Computer Management. B окне Computer Management раскройте System Information (Сведения о системе), затем Software Environment (Программная среда) и Drivers (Драйверы). Ниже приведен пример списка драйверов.
B этом окне выводится список драйверов, определенных в реестре, а также их тип и состояние - Running (Работает) или Stopped (Остановлена). Драйверы устройств и процессы Windows-сервисов определяются в разделе реестра HKLM\SYSTEM\CurrentControlSet\Services. Однако они отличаются по коду типа, например 1 соответствует драйверу режима ядра. (Полный список хранящихся в реестре сведений, которые относятся к драйверам, см. в таблице 4-7.)
Список загруженных в текущий момент драйверов можно просмотреть и с помощью утилиты Drivers (Drivers.exe в ресурсах Windows 2000) или Pstat (Pstat.exe в Windows XP Support Tools, Windows Server 2003 Support Tools, ресурсах Windows 2000 и Platform SDK). Ниже приведен листинг части выходной информации утилиты Drivers.
Утилита перечисляет все загруженные компоненты режима ядра (Ntoskrnl, HAL и драйверы устройств) и сообщает размеры разделов в каждом образе.
Pstat также выводит список загруженных драйверов, но только после списка процессов и потоков в каждом процессе. Она показывает один вид очень важной информации, не сообщаемой утилитой Drivers: адрес загрузки модуля в системном пространстве. Как вы еще увидите, этот адрес нужен для увязки выполняемых системных потоков с драйвером, в котором они существуют.
Просмотр имен экспортируемых или глобальных символов в ключевых системных файлах (Ntoskrnl.exe, Hal.dll или Ntdll.dll) может оказаться полезным: вы получите представление о том, что умеет делать Windows в сравнении с документированной и поддерживаемой частью. Конечно, знание имен этих функций еще не означает, что вы сможете или должны их вызывать. Эти интерфейсы не документированы и могут быть изменены. Мы предлагаем рассмотреть эти функции только для лучшего понимания внутренних функций Windows, а не для обхода поддерживаемых интерфейсов.
Например, просмотрев список функций в Ntdll.dll, вы сможете сравнить список всех системных сервисов, которые Windows предоставляет DLL-модулям подсистем пользовательского режима, с их подмножеством, предоставляемым каждой подсистемой. Хотя многие из этих функций точно соответствуют документированным и поддерживаемым Windows-функциям, некоторые из них недоступны через Windows API (см. статью «Inside the Native API» на
Подробнее о выполнении приложений POSIX и OS/2 в Windows см. главу 6.
Ntdll.dll
Ntdll.dll - специальная библиотека системной поддержки, нужная в основном при использовании DLL подсистем. Она содержит функции двух типов:
(o)интерфейсы диспетчера системных сервисов (system service dispatch stubs) к сервисам исполнительной системы Windows;
(o)внутренние функции поддержки, используемые подсистемами, DLL подсистем и другими компонентами операционной системы. Первая группа функций предоставляет интерфейс к сервисам исполнительной системы Windows, которые можно вызывать из пользовательского режима. Таких функций более 200, например NtCreateFile, NtSetEventи т. д. Как уже говорилось, большинство из них доступно через Windows API (однако некоторые из них предназначены только для применения внутри самой операционной системы).
Для каждой из этих функций в Ntdll существует точка входа с тем же именем. Код внутри функции содержит специфичную для конкретной аппаратной архитектуры команду перехода в режим ядра для вызова диспетчера системных сервисов (о нем рассказывается в главе 3), который после проверки некоторых параметров вызывает уже настоящий сервис режима ядра из Ntoskrnl.exe.
Ntdll также включает множество функций поддержки, например загрузчик образов (функции, имена которых начинаются с Ldr),диспетчер куч, функции для взаимодействия с процессом подсистемы Windows (функции, имена которых начинаются с Csr),а также универсальные процедуры библиотек периода выполнения (функции, имена которых начинаются с Rtl).Там же находится диспетчер APC (asynchronous procedure call) пользовательского режима и диспетчер исключений. (Подробнее об APC и исключениях см. главу 3.)
Исполнительная система
Исполнительная система (executive) находится на верхнем уровне Ntoskrnl.exe (ядро располагается на более низком уровне). B ее состав входят функции следующего типа.
(o)Экспортируемые функции, доступные для вызова из пользовательского режима. Эти функции называются системными сервисамии экспортируются через Ntdll. Большинство сервисов доступно через Windows API или API других подсистем окружения. Однако некоторые из них недоступны через документированные функции (примером могут служить LPC, функции запросов вроде NtQueryInformationProcess,специализированные функции типа NtCreatePagingFileи т. д.).
(o)Функции драйверов устройств, вызываемые через функцию DeviceIoCont-rol.Последняя является универсальным интерфейсом от пользовательского режима к режиму ядра для вызова функций в драйверах устройств, не связанных с чтением или записью.
(o)Экспортируемые функции, доступные для вызова только из режима ядра и документированные в Windows DDK или Windows Installable File System (IFS) Kit (см. wwwmicrosoft.com/whdc/ddk/ifskit.default.mspx ).
(o)Экспортируемые функции, доступные для вызова только из режима ядра, но не описанные в Windows DDK или IFS Kit (например, функции, которые используются видеодрайвером, работающим на этапе загрузки, и чьи имена начинаются с Inbv).
(o)Функции, определенные как глобальные, но не экспортируемые символы. Включают внутренние функции поддержки, вызываемые в Ntoskrnl; их имена начинаются с Iop(функции поддержки диспетчера ввода-вывода) или с Mi(функции поддержки управления памятью).
(o)Внутренние функции в каком-либо модуле, не определенные как глобальные символы. Исполнительная система состоит из следующих основных компонентов (каждый из них подробно рассматривается в последующих главах книги).
(o) Диспетчер конфигурации(см. главу 4), отвечающий за реализацию и управление системным реестром.
(o) Диспетчер процессов и потоков(см. главу 6), создающий и завершающий процессы и потоки. Низкоуровневая поддержка процессов и потоков реализована в ядре Windows, а исполнительная система дополняет эти низкоуровневые объекты своей семантикой и функциями.
(o) Монитор состояния защиты(см. главу 8), реализующий политики безопасности на локальном компьютере. Он охраняет ресурсы операционной системы, осуществляя аудит и контролируя доступ к объектам в период выполнения.
(o) Диспетчер ввода-вывода(см. главу 9), реализующий аппаратно-независимый ввод-вывод и отвечающий за пересылку ввода-вывода нужным драйверам устройств для дальнейшей обработки.
(o) Диспетчер Plug and Play(см. главу 9), определяющий, какие драйверы нужны для поддержки конкретного устройства, и загружающий их. Требования каждого устройства в аппаратных ресурсах определяются в процессе перечисления. B зависимости от требований каждого устройства диспетчер PnP распределяет такие ресурсы, как порты ввода-вывода, IRQ, каналы DMA и области памяти. Он также отвечает за посылку соответствующих уведомлений об изменениях в аппаратном обеспечении системы (при добавлении или удалении устройств).
(o) Диспетчер электропитания(см. главу 9), который координирует события, связанные с электропитанием, и генерирует уведомления системы управления электропитанием, посылаемые драйверам. Когда система не занята, диспетчер можно настроить на остановку процессора для снижения энергопотребления. Изменение энергопотребления отдельных устройств возлагается на их драйверы, но координируется диспетчером электропитания.
(o) Подпрограммы WDM Windows Management Instrumentation(см. главу 4), позволяющие драйверам публиковать информацию о своих рабочих характеристиках и конфигурации, а также получать команды от службы
WMI пользовательского режима. Потребители информации WMI могут находиться как на локальной машине, так и на любом компьютере в сети.
(o) Диспетчер кэша(см. главу 11), повышающий производительность файлового ввода-вывода за счет сохранения в основной памяти дисковых данных, к которым недавно было обращение (это также уменьшает число обращений к диску для записи, поскольку модифицированные данные предварительно накапливаются в памяти в течение определенного периода). Как вы увидите, диспетчер кэша выполняет эту задачу, используя поддержку проецируемых файлов со стороны диспетчера памяти.
(o) Диспетчер памяти(см. главу 7), реализующий виртуальную память - схему управления памятью, позволяющую выделять каждому процессу большое закрытое адресное пространство, объем которого может превышать доступную физическую память. Диспетчер памяти также обеспечивает низкоуровневую поддержку диспетчера кэша.
(o) Средство логической предвыборки(см. главу 7), ускоряющее запуск системы и процессов за счет оптимизации загрузки данных, к которым происходит обращение при запуске системы или процессов. Кроме того, в состав исполнительной системы входят четыре основные группы функций поддержки, используемые вышеперечисленными компонентами. Примерно треть из них описана в DDK, поскольку драйверы тоже используют их. Вот что представляют собой четыре категории функций поддержки.
(o) Диспетчер объектов- создает, управляет и удаляет объекты и абстрактные типы данных исполнительной системы, используемые для представления таких ресурсов операционной системы, как процессы, потоки и различные синхронизирующие объекты. Подробнее о диспетчере объектов см. главу 3-
(o) Механизм LPC(см. главу 3) - передает сообщения между клиентским и серверным процессами на одном компьютере. LPC является гибкой, оптимизированной версией RPC (remote procedure call), стандартного механизма взаимодействия между клиентскими и серверными процессами через сеть.
(o)Большой набор стандартных библиотечных функций для обработки строк, арифметических операций, преобразования типов данных и обработки структур безопасности.
(o) Подпрограммы поддержки исполнительной системы,например для выделения системной памяти (пулов подкачиваемых и неподкачиваемых страниц), доступа к памяти со взаимоблокировкой, а также два специальных типа синхронизирующих объектов: ресурс (resource) и быстродействующий мьютекс (fast mutex).
Ядро
Ядро состоит из набора функций в Ntoskrnl.exe, предоставляющих фундаментальные механизмы (в том числе планирования потоков и синхронизации), которые используются компонентами исполнительной системы и низкоуровневыми аппаратно-зависимыми средствами поддержки (диспетчеризации прерываний и исключений), различными в каждой процессорной архитектуре. Код ядра написан в основном на С, а ассемблер использовали лишь для решения специфических задач, трудно реализуемых на С.
Как и функции поддержки исполнительной системы, упоминавшиеся в предыдущем разделе, часть функций ядра описана в DDK (см. функции, чьи имена начинаются с Ke),поскольку они необходимы для реализации драйверов устройств.
Объекты ядра
Ядро состоит из низкоуровневых, четко определенных и хорошо предсказуемых примитивов и механизмов операционной системы, позволяющих компонентам исполнительной системы более высокого уровня выполнять свои функции. Ядро отделено от остальной части исполнительной системы; оно реализует системные механизмы и не участвует в принятии решений, связанных с системной политикой. Практически все такие решения, кроме планирования и диспетчеризации потоков, принимаются исполнительной системой.
Вне ядра исполнительная система представляет потоки и другие разделяемые ресурсы в виде объектов. Управление этими объектами требует определенных издержек, так как нужны описатели, позволяющие манипулировать объектами, средства защиты и квоты ресурсов, резервируемых при их создании. B ядре можно избежать таких издержек, поскольку оно реализует набор более простых объектов, называемых объектами ядра(kernel objects). Эти объекты позволяют ядру контролировать обработку данных процессором и поддерживают объекты исполнительной системы. Большинство объектов уровня исполнительной системы инкапсулирует один или более объектов ядра, включая в себя их атрибуты, определенные ядром.
Одна из групп объектов ядра, называемых управляющими(control objects), определяет семантику управления различными функциями операционной системы. B эту группу входят объекты APC, DPC (deferred procedure call) и несколько объектов, используемых диспетчером ввода-вывода (например, объект прерывания).
Другая группа объектов под названием объекты диспетчера(dispatcher objects) реализует средства синхронизации, позволяющие изменять планирование потоков. B группу таких объектов входят поток ядра (kernel thread), мьютекс (mutex), событие (event), семафор (semaphore), таймер (timer), ожидаемый таймер (waitable timer) и некоторые другие. C помощью функций ядра исполнительная система создает объекты ядра, манипулирует ими и конструирует более сложные объекты, предоставляемые в пользовательском режиме. Объекты подробно рассматриваются в главе 3, а процессы и потоки - в главе 6.
Поддержка оборудования
Другая важная задача ядра - абстрагирование или изоляция исполнительной системы и драйверов устройств от различий между аппаратными архитектурами, поддерживаемыми Windows (т. е. различий в обработке прерываний, диспетчеризации исключений и синхронизации между несколькими процессорами).
Архитектура ядра нацелена на максимальное обобщение кода - даже в случае аппаратно-зависимых функций. Ядро поддерживает набор семантически идентичных и переносимых между архитектурами интерфейсов. Большая часть кода, реализующего переносимые интерфейсы, также идентична для разных архитектур.
Ho одна часть этих интерфейсов по-разному реализуется на разных архитектурах, а другая включает код, специфичный для конкретной архитектуры. Архитектурно-независимые интерфейсы могут быть вызваны на любой машине, причем семантика интерфейса будет одинаковой - независимо от специфического кода для той или иной архитектуры. Некоторые интерфейсы ядра (например, процедуры спин-блокировки, описанные в главе 3) на самом деле реализуются в HAL (см. следующий раздел), поскольку их реализация может отличаться даже в пределах семейства процессоров с одинаковой архитектурой.
B ядре также содержится небольшая порция кода с х86-специфичными интерфейсами, необходимыми для поддержки старых программ MS-DOS. Эти интерфейсы не являются переносимыми в том смысле, что их нельзя вызывать на машине с другой архитектурой, где они попросту отсутствуют. Этот х86-специфичный код, например, поддерживает манипуляции с GDT (global descriptor tables) и LDT (local descriptor tables) - аппаратными средствами x86.
Другим примером архитектурно-специфичного кода ядра может служить интерфейс, предоставляющий поддержку буфера трансляции и процессорного кэша. Эта поддержка требует разного кода на разных архитектурах, поскольку кэш в них реализуется различным образом.
Еще один пример - переключение контекста. Хотя на высоком уровне для выбора потоков и переключения контекста применяется один и тот же алгоритм (сохраняется контекст предыдущего потока, загружается контекст нового и запускается новый поток), существуют архитектурные различия между его реализациями для разных процессоров. Поскольку контекст описывается состоянием процессора (его регистров и т. д.), сохраняемая и загружаемая информация зависит от архитектуры.
Уровень абстрагирования от оборудования
Как отмечалось в начале этой главы, одной из важнейших особенностей архитектуры Windows является переносимость между различными аппаратными платформами. Ключевой компонент, обеспечивающий такую переносимость, - уровень абстрагирования от оборудования (hardware abstraction layer, HAL). HAL - это загружаемый модуль режима ядра (Hal.dll), предоставляющий низкоуровневый интерфейс с аппаратной платформой, на которой выполняется Windows. Он скрывает от операционной системы специфику конкретной аппаратной платформы, в том числе ее интерфейсов ввода-вывода, контроллеров прерываний и механизмов взаимодействия между процессорами, т. е. все функции, зависимые от архитектуры и от конкретной машины.
Когда внутренним компонентам Windows и драйверам устройств нужна платформенно-зависимая информация, они обращаются не к самому оборудованию, а к подпрограммам HAL, что и обеспечивает переносимость этой операционной системы. По этой причине подпрограммы HAL документированы в Windows DDK, где вы найдете более подробные сведения о HAL и о его использовании драйверами.
Хотя в Windows имеется несколько модулей HAL (см. таблицу 2-6), при установке на жесткий диск компьютера копируется только один из них - Hal.dll. (B других операционных системах, например в VMS, нужный модуль HAL выбирается при загрузке системы.) Поскольку для поддержки разных процессоров требуются разные модули HAL, системный диск от одной х8б-установки скорее всего не подойдет для загрузки системы с другим процессором.
Таблица 2-6. Список модулей HAL для x86 в \ Windows\Driver\Cache\i386\Driver.cab
ПРИМЕЧАНИЕ B базовой системе Windows Server 2003 нет HAL, специфических для конкретных вендоров.
ЭКСПЕРИМЕНТ: просмотр базовых HAL, включенных в Windows
Для просмотра HAL, включенных в Windows, откройте файл Driver.cab в соответствующем подкаталоге, специфичном для конкретной архитектуры, в каталоге \Windows\Driver Cache. (Например, для систем x86 имя этого файла - \Windows\Driver Cache\i386\Driver.cab.) Прокрутите список до файлов, начинающихся с «Hal», и вы увидите файлы, перечисленные в таблице 2-6.
ЭКСПЕРИМЕНТ: определяем используемый модуль HAL
Определить, какой модуль HAL используется на вашей машине, можно двумя способами.
1. Откройте файл \Windows\Repair\Setup.log, найдите строку с Haldll.Имя файла, стоящее в этой строке после знака равенства, соответствует имени модуля HAL, извлеченного из Driver.cab с дистрибутивного носителя.
2. Откройте Device Manager (Диспетчер устройств): щелкните правой кнопкой мыши значок My Computer (Мой компьютер) на рабочем столе, выберите команду Properties (Свойства), откройте вкладку Hardware (Оборудование) и щелкните кнопку Device Manager (Диспетчер устройств). Проверьте имя «драйвера» для устройства Computer (Компьютер).
ЭКСПЕРИМЕНТ: просмотр зависимостей NTOSKRNL и HAL
Вы можете просмотреть взаимосвязи образов ядра и HAL, изучив их таблицы импорта и экспорта с помощью утилиты Dependency Walker (Depends.exe), которая содержится в Windows Support Tools и Platform SDK. Для исследования файла в Dependency Walker откройте его командой Open из меню File.
Вот пример вывода этой утилиты при просмотре зависимостей в Ntoskrnl.
Обратите внимание, что Ntoskrnl связан с HAL, который в свою очередь связан с Ntoskrnl (оба используют функции друг у друга). Ntoskrnl также связан с Bootvid.dll, видеодрайвером, используемым для вывода заставки при запуске Windows. B Windows XP и выше вы увидите в списке дополнительную DLL, Kdcom.dll. Она содержит код инфраструктуры отладчика ядра, который раньше был частью Ntoskrnl.exe.
Подробное описание информации, выводимой Dependency Walker, см. в справочном файле этой утилиты (Depends.hlp).
Драйверы устройств
Драйверы устройств подробно описываются в главе 9, а здесь мы даем краткий обзор их типов и поясняем, как перечислить установленные драйверы, загруженные в системе.
Драйверы устройств являются загружаемыми модулями режима ядра (как правило, это файлы с расширением .sys); они образуют интерфейс между диспетчером ввода-вывода и соответствующим оборудованием. Эти драйверы выполняются в режиме ядра в одном из трех контекстов:
(o)в контексте пользовательского потока, инициировавшего функцию ввода-вывода;
(o)в контексте системного потока режима ядра;
(o)как результат прерывания (а значит, не в контексте какого-либо процесса или потока, который был текущим на момент прерывания). Как было сказано в предыдущем разделе, в Windows драйверы устройств не управляют оборудованием напрямую - вместо этого они вызывают функции HAL. Драйверы, как правило, пишутся на C (иногда на C++), поэтому при правильном использовании процедур HAL они являются переносимыми между поддерживаемыми Windows архитектурами на уровне исходного кода, а на уровне двоичных файлов - внутри семейства с одинаковой архитектурой. Существует несколько типов драйверов устройств.
(o) Драйверы аппаратныхустройств,которые управляют (через HAL) оборудованием, записывают на них выводимые данные и получают вводимые данные от физического устройства или из сети. Есть множество типов таких драйверов - драйверы шин, интерфейсов, устройств массовой памяти и т. д.
(o) Драйверы файловой системы- это драйверы Windows, принимающие запросы на файловый ввод-вывод и транслирующие их в запросы ввода-вывода для конкретного устройства.
(o) Драйверы фильтра файловой системы,которые обеспечивают зеркали-рование и шифрование дисков, перехват ввода-вывода и некоторую дополнительную обработку информации перед передачей ее на следующий уровень.
(o) Сетевые редиректорыи серверы,являющиеся драйверами файловых систем, которые передают запросы файловой системы на ввод-вывод другим компьютерам в сети и принимают от них аналогичные запросы.
(o) Драйверы протоколов,реализующие сетевые протоколы вроде TCP/IP, NetBEUI и IPX/SPX.
(o) Драйверы потоковых фильтров ядра,действующие по цепочке для обработки потоковых данных, например при записи и воспроизведении аудио- и видеоинформации.
Поскольку установка драйвера устройства - единственный способ добавления в систему стороннего кода режима ядра, некоторые программисты пишут драйверы просто для того, чтобы получить доступ к внутренним функциям или структурам данных операционной системы, недоступным из пользовательского режима (но документированным и поддерживаемым в DDK). Например, многие утилиты с www.sysinternals.com представляют собой комбинацию GUI-приложений Windows с драйверами устройств, используемыми для сбора сведений о состоянии внутрисистемных структур и вызова функций, доступных только в режиме ядра.
Усовершенствования в модели драйверов Windows
B Windows 2000 была введена поддержка Plug and Play и энергосберегающих технологий, а также расширена модель драйверов Windows NT, называемая Windows Driver Model (WDM). Windows 2000 и более поздние версии могут работать с унаследованными драйверами Windows NT 4, но, поскольку они не поддерживают Plug and Play и энергосберегающие технологии, функциональность системы в этом случае будет ограничена. C точки зрения WDM, существует три типа драйверов.
(o) Драйвер шины(bus driver), обслуживающий контроллер шины, адаптер, мост или любые другие устройства, имеющие дочерние устройства. Драйверы шин нужны для работы системы и в общем случае поставляются Microsoft. Для каждого типа шины (PCI, PCMCIA и USB) в системе имеется свой драйвер. Сторонние разработчики создают драйверы для поддержки новых шин вроде VMEbus, Multibus и Futurebus.
(o) Функциональный драйвер(function driver) - основной драйвер устройства, предоставляющий его функциональный интерфейс. Обязателен, кроме тех случаев, когда устройство используется без драйверов (т. е. ввод-вывод осуществляется драйвером шины или драйверами фильтров шины, как в случае SCSI PassThru). Функциональный драйвер по определению обладает наиболее полной информацией о своем устройстве. Обычно только этот драйвер имеет доступ к специфическим регистрам устройства.
(o) Драйвер фильтра(filter driver), поддерживающий дополнительную функциональность устройства (или существующего драйвера) или изменяющий запросы на ввод-вывод и ответы на них от других драйверов (это часто используется для коррекции устройств, предоставляющих неверную информацию о своих требованиях к аппаратным ресурсам). Такие драйверы не обязательны, и их может быть несколько. Они могут работать как на более высоком уровне, чем функциональный драйвер или драйвер шины, так и на более низком. Обычно эти драйверы предоставляются OEM-производителями или независимыми поставщиками оборудования (IHV).
B среде WDM один драйвер не может контролировать все аспекты устройства: драйвер шины информирует диспетчер PnP об устройствах, подключенных к шине, в то время как функциональный драйвер управляет устройством.
B большинстве случаев драйвер фильтра более низкого уровня модифицирует поведение устройства. Например, если устройство сообщает драйверу своей шины о том, что ему нужно 4 порта ввода-вывода, тогда как на самом деле ему требуется 16, драйвер фильтра может перехватить список аппаратных ресурсов, направляемый драйвером шины диспетчеру PnP и исправить число портов.
Драйвер фильтра более высокого уровня обычно придает устройству дополнительную функциональность. Так, высокоуровневый драйвер фильтра для клавиатуры может обеспечивать дополнительную защиту.
Обработка прерываний описывается в главе 3. Подробнее о диспетчере ввода-вывода, WDM, Plug and Play и энергосберегающих технологиях см. главу 9.
ЭКСПЕРИМЕНТ: просмотр установленных драйверов устройств
Чтобы вывести список установленных драйверов, запустите оснастку Computer Management ^Управление компьютером). Для этого выберите из меню Start (Пуск) команду Programs (Программы), затем Administrative Tools (Администрирование) и Computer Management ^правление компьютером) или откройте Control Panel (Панель управления) и дважды щелкните значок Computer Management. B окне Computer Management раскройте System Information (Сведения о системе), затем Software Environment (Программная среда) и Drivers (Драйверы). Ниже приведен пример списка драйверов.
B этом окне выводится список драйверов, определенных в реестре, а также их тип и состояние - Running (Работает) или Stopped (Остановлена). Драйверы устройств и процессы Windows-сервисов определяются в разделе реестра HKLM\SYSTEM\CurrentControlSet\Services. Однако они отличаются по коду типа, например 1 соответствует драйверу режима ядра. (Полный список хранящихся в реестре сведений, которые относятся к драйверам, см. в таблице 4-7.)
Список загруженных в текущий момент драйверов можно просмотреть и с помощью утилиты Drivers (Drivers.exe в ресурсах Windows 2000) или Pstat (Pstat.exe в Windows XP Support Tools, Windows Server 2003 Support Tools, ресурсах Windows 2000 и Platform SDK). Ниже приведен листинг части выходной информации утилиты Drivers.
Утилита перечисляет все загруженные компоненты режима ядра (Ntoskrnl, HAL и драйверы устройств) и сообщает размеры разделов в каждом образе.
Pstat также выводит список загруженных драйверов, но только после списка процессов и потоков в каждом процессе. Она показывает один вид очень важной информации, не сообщаемой утилитой Drivers: адрес загрузки модуля в системном пространстве. Как вы еще увидите, этот адрес нужен для увязки выполняемых системных потоков с драйвером, в котором они существуют.
Недокументированные интерфейсы
Просмотр имен экспортируемых или глобальных символов в ключевых системных файлах (Ntoskrnl.exe, Hal.dll или Ntdll.dll) может оказаться полезным: вы получите представление о том, что умеет делать Windows в сравнении с документированной и поддерживаемой частью. Конечно, знание имен этих функций еще не означает, что вы сможете или должны их вызывать. Эти интерфейсы не документированы и могут быть изменены. Мы предлагаем рассмотреть эти функции только для лучшего понимания внутренних функций Windows, а не для обхода поддерживаемых интерфейсов.
Например, просмотрев список функций в Ntdll.dll, вы сможете сравнить список всех системных сервисов, которые Windows предоставляет DLL-модулям подсистем пользовательского режима, с их подмножеством, предоставляемым каждой подсистемой. Хотя многие из этих функций точно соответствуют документированным и поддерживаемым Windows-функциям, некоторые из них недоступны через Windows API (см. статью «Inside the Native API» на