Наши друзья:
мармелад производство; эклеры |
Виртуальная память с подкачкой страниц по требованию
Виртуальное адресное пространство (virtual address space) процесса - это набор адресов, которые могут использовать потоки процесса, оно равно четырем гигабайтам (232 байт), два из которых предназначены для использования программой, а другие два зарезервированы для ОС.
Во время выполнения потока диспетчер памяти при помощи аппаратных средств транслирует (отображает) виртуальные адреса в физические, по которым данные хранятся на самом деле. Посредством контроля над процессом отображения ОС может гарантировать, что процессы не будут пересекаться друг с другом и не повредят ОС.
Когда физической памяти не хватает, диспетчер памяти выгружает часть содержимого памяти на диск. При обращении потока по виртуальному адресу, соответствующему переписанным на диск данным, диспетчер памяти снова загружает эти данные с диска в память.
В Windows NT код ОС располагается в верхней части виртуального адресного пространства, а пользовательский код и данные - в нижней. Можно выгружать всю пользовательскую память. Код пользовательского режима не может производить запись и чтение системной памяти.
Часть системной памяти, называемая невыгружаемым (резидентным) пулом (nonpaged pool), никогда не выгружается на диск и используется для хранения некоторых объектов и других важных структур данных. Другая часть системной памяти, которая может быть выгружена на диск, называется выгружаемым (нерезидентным) пулом (paged pool).
Симметричная мультипроцессорная обработка
NT поддерживает только архитектуру с симметричной мультипроцессорной обработкой - SMP.
Системы с симметричной мультипроцессорной обработкой позволяют коду операционной системы выполняться на любом свободном процессоре или на всех процессорах одновременно, причем каждому из процессоров доступна вся память. Чтобы гарантировать правильную работу системы, код таких ОС должен следовать строгим правилам. Windows NT обладает свойствами, которые принципиально важны для мультипроцессорной ОС:
· Код ОС может выполняться на любом из доступных процессоров и на нескольких процессорах одновременно. За исключением кода ядра, которое выполняет планировку потоков и обработку прерываний, весь код ОС может быть вытеснен потоком с более высоким приоритетом.
· В одном процессе может быть несколько потоков управления. Потоки позволяют процессу выполнять разные части его программы на нескольких процессорах одновременно.
· Серверные процессы могут иметь несколько потоков для одновременной обработки запросов от нескольких клиентов.
Имеются механизмы совместного использования объектов потоками разных процессов, и гибкие возможности коммуникации между потоками разных процессов, включая совместно используемую память и оптимизированное средство передачи сообщений.
Интегрированная поддержка сети
Windows NT разработана со встроенной сетевой поддержкой и включает широкую поддержку сети, интегрированную с системой ввода/вывода и интерфейсом Win32 API.
Четырьмя основными типами сетевого программного обеспечения являются сетевые сервисы, сетевые API, протоколы и драйверы сетевых карт, располагающиеся друг под другом, формируя сетевой стек.
Windows NT предоставляет хорошо определенные интерфейсы для каждого слоя в стеке, чтобы в дополнение к поставляющемуся с Windows NT множеству различных сетевых интерфейсов API, протоколов и драйверов сетевых карт, пользователи могли расширять сетевые возможности ОС путем разработки собственного сетевого программного обеспечения.
Структура Windows NT
Всю операционную систему Windows NT можно разделить на следующие части (2):
1. 1. защищенные подсистемы (protected subsysterns), работающие в пользовательском режиме, тогда как остальная часть ОС исполняется в режиме ядра;
2. 2. исполнительная система (executive);
3. 3. ядро (kernel);
4. 4. слой абстрагирования от оборудования (Hardware Abstraction Layer, HAL).
Защищенные подсистемы
Серверы Windows NT называются защищенными подсистемами, так как каждый из них - это отдельный процесс, память которого защищена от других процессов системой виртуальной памяти исполнительной системы NT. Каждая защищенная подсистема обеспечивает интерфейс прикладным программам (API) посредством DLLs клиентской стороны. Когда приложение или другой сервер вызывает некоторую процедуру API, соответствующая DLL упаковывает параметры функции API в сообщение и с помощью средства локального вызова процедур (Local Procedure Call, LPC) посылает его серверу, реализующему данную процедуру. Сервер же, выполнив вызов, посылает ответное сообщение вызывающей программе. Передача сообщений остается невидимой для прикладного программиста. Используя такую процедуру, вызывающая программа никогда не получает прямого доступа к адресному пространству подсистемы.
Надо отметить, что далеко не все функции API реализуются сервером, например, большая часть функций API Win32 оптимизирована в DLL клиентской стороны, и в действительности не обращается к подсистеме Win32.
Защищенные подсистемы подразделяются на подсистемы среды (environment subsystems) и неотъемлемые подсистемы (integral subsystems).
Подсистемы среды
Подсистема среды - это сервер пользовательского режима, реализующий API некоторой ОС. Самая важная подсистема среды в Windows NT - это подсистема среды Win32 (рассматриваемая ниже), которая предоставляет прикладным программам интерфейс API 32-разрядной Windows. В Windows NT также имеются подсистемы среды: POSIX, OS/2 и виртуальная DOS машина (virtual DOS machine, VDM), эмулирующая 16-разрядную Windows и MS-DOS.
Данные подсистемы предоставляют свои API, но используют для получения пользовательского ввода и отображения результатов подсистему Win32, то есть перенаправляют видеовывод своих приложений подсистеме Win32 для отображения.
Говоря о подсистемах окружения, необходимо отметить также следующее. Каждая прикладная программа (и даже более того - каждый модуль, будь то exe, dll, sys или что-то другое) может относиться только к какой-то одной подсистеме окружения, либо не относиться ни к одной из них. Эта информация прописывается в любом исполняемом модуле на этапе его компиляции и может быть получена через утилиту «Быстрый просмотр» (Quick View) в пункте «Subsystem» (варианты: The image does not require subsystem, Win32 GUI, Win32 Console, ...).
Подсистема среды Win32
Подсистема среды Win32 делится на серверный процесс (csrss.exe - Client/Server Runtime Subsystem) и клиентские DLLs (user32.dll, gdi32.dll, kerneI32.dll), которые связаны с программой, использующей Win32 API. Win32. API разделен на три категории:
· Управление окнами (windowing) и передача сообщений (messaging). Эти интерфейсы оконных процедур и процедур сообщений включают, например, такие функции, как CreateWindow(), SendMessage(), и предоставляются прикладной программе через библиотеку user32.dll.
· Рисование (drawing). Например, функции BitBitQ и LineTo() являются Win32-функциями рисования и предоставляются библиотекой gdi32.dll.
· Базовые сервисы. Базовые сервисы включают весь ввод/вывод %т32, управление процессами и потоками, управление памятью, синхронизацию и предоставляются библиотекой kernel32.dll.
Когда Win32-приложение вызывает функцию API Win32, управление передается одной из клиентских DLLs подсистемы Win32. Эта DLL может:
· Выполнить функцию самостоятельно без обращения к системным сервисам ОС и вернуть управление вызывающей программе.
· Послать сообщение Win32-cepeepy для обработки запроса в том случае, если сервер должен участвовать в выполнении заданной функции. Так, функция CreateProcess(), экспортируемая библиотекой kernel32.dll, требует взаимодействия с Win32-cepBepOM, который, в свою очередь, вызывает функции «родного» API.
· Вовлечь «родной» интерфейс API для выполнения заданной функции. Последний вариант встречается наиболее часто. В версиях Windows NT ниже 4.0 функции окон (windowing) и рисования (drawing) были расположены в Win32-сервере (csrss.exe). Это означало, что, когда приложение использовало такие функции, посылались сообщения указанному серверу. В версии 4.0 эти функции были перенесены в компонент режима ядра, называемый win32k.sys. Теперь вместо того, чтобы посылать сообщение серверу, клиентская DLL обращается к этому компоненту ядра, уменьшая затраты на создание сообщений и переключение контекстов потоков различных процессов. Это увеличило производительность графического ввода/вывода. Библиотеки gdi32.dll и user32.dll стали вторым «родным» API, но оно менее загадочно, чем первое, так как хорошо документировано.
Функциями библиотеки kernel32.dll, вызывающими «родной» интерфейс API напрямую, являются функции ввода/вывода, синхронизации и управления памятью. Фактически, большинство экспортируемых библиотекой kerael32.dll функций используют «родной» API напрямую. На рис. 3 иллюстрируется передача управления от Win32-приложения, выполнившего вызов Win32-функции CreateFile(), библиотеке kernel32.dll, затем функции NtCreateFile() в ntdll.dll и далее режиму ядра, где управление передается системному сервису, реализующему создание/открытие файла. Подробнее вызов системных сервисов рассматривается в следующем параграфе.
«Родной» API для ОС Windows NT (Native Windows NT API)
«Родной» API для Windows NT является средством, которое реализует контролируемый вызов системных сервисов, исполняемых в режиме ядра. Так, например, если программа, исполняющаяся в пользовательском режиме, захочет выполнить операцию ввода/вывода, зарезервировать или освободить регион в виртуальном адресном пространстве, запустить поток или создать процесс, — она должна запросить (естественно, не напрямую) один или несколько системных сервисов, расположенных в режиме ядра.
Этот интерфейс API является интерфейсом системных вызовов и не предназначается для непосредственного использования пользовательскими программами, кроме того, его документация ограничена. В Windows NT «родной» интерфейс спрятан от прикладных программистов под интерфейсами API более высокого уровня, таких как Win32, OS/2, POSIX, DOS/Win16.
«Родной» API предоставляется коду пользовательского режима библиотекой ntdll.dll. Библиотека ntdll.dll, имеющая точки входа в «родной» API для кода пользовательского режима, содержит также код загрузки модуля и запуска потока процесса. Однако большинство входов в «родной» API являются заглушками, которые просто передают управление режиму ядра. Это осуществляется путем генерации программного исключения, например, ассемблерный код функции NtCreateFile() в библиотеке ntdll.dll, выглядит следующим образом:
mov еах, 0x00000017
lea edx, [esp+04]
int Ox2E
ret Ox2C
Другие вызовы выглядят почти также. Первая инструкция загружает регистр процессора индексным номером конкретной функции «родного» API (каждая функция «родного» API имеет уникальный индексный номер). Вторая инструкция загружает в регистр указатель на параметры вызова. Следующая инструкция - команда генерации программного исключения. ОС регистрирует обработчик ловушки для перехвата управления, переключения из пользовательского режима в режим ядра и передачи управления в фиксированную точку ОС при возникновении прерывания или исключения. В случае вызова системного сервиса (на процессорах х86 программное исключение для вызова системных сервисов генерируется кодом Ох2Е), этот обработчик ловушки передает управление диспетчеру системных сервисов. Последняя инструкция забирает параметры из стека вызывающего потока.
Диспетчер системных сервисов определяет, является ли корректным индексный номер функции «родного» API. Индексный номер, переданный из пользовательского режима, используется для входа в таблицу распределения системных сервисов (KeServiceDescriptorTable). Каждый элемент этой таблицы включает указатель на соответствующий системный сервис и число параметров. Диспетчер системных сервисов берет параметры, переданные в стеке пользовательского режима (указатель стека находится в регистре edx) и помещает их в стек ядра, а затем передает управление для обработки запроса соответствующему системному сервису, который исполняется в режиме ядра и находится в ntoskrnl.exe.
Введенные в Windows NT версии 4.0 интерфейсы API Win32 управления окнами и рисованием управляются тем же диспетчером системных сервисов, но индексные номера Win32^yHKujffl указывают на то, что должен использоваться второй массив указателей системных сервисов. Указатели во втором массиве ссылаются на функции в win32k.sys.
Большинство системных сервисов должно выполнять проверку параметров, переданных им из пользовательского режима. Некоторые параметры являются указателями, а передача неверного указателя в режим ядра без предварительной проверки может привести к краху системы. Проверка параметров обязательна, но оказалось, что некоторые функции «родного» API (13 системных сервисов из win32k.sys) не выполняют обстоятельную проверку, что приводит в некоторых случаях к падению системы. Microsoft закрыла эти дыры в Service Pack I. В дальнейшем оказалось, что при тестировании параметров, соответствующих граничным условиям, вызовы еще 40 функций «родного» API, из которых 25 из win32k.sys, вызвали падение системы. Эти дыры были закрыты в SP4.
После проверки параметров, системные сервисы обычно вызывают функции, реализуемые компонентами исполнительной системы: диспетчером процессов, диспетчером памяти, диспетчером ввода/вывода и средством локального вызова процедур.
Все функции прикладного уровня, вызывающие это прерывание, сосредоточены в модуле ntdll.dll и имеют в своем названии префикс Nt либо Zw, например, NtCreateFile()/ZwCreateFile(). Точка входа для двух таких имен одна. Вызов многих функций различных подсистем рано или поздно приведет к вызову соответствующей функции из ntdll.dll. При этом не все, что есть в ntdll.dll вызывается из подсистемы Win32.
Вызов системных сервисов возможен не только из прикладной программы, но и из ядра ОС, то есть из драйверов. Имена соответствующих функций ядра имеют префикс либо Zw, либо Nt (ZwCreateFile(), NtCreateFile()). Функции с префиксом Zw обращаются к сервисам посредством прерывания 2Е, тогда как функции с префиксом Nt являются собственно точками входа стандартных системных сервисов. Из этого следует, что число функций с префиксом Nt неизменно, а множество этих функций является подмножеством функций с префиксом Zw. Не путайте функции с префиксами Nt и Zw режима ядра и пользовательского режима. В режиме ядра они находятся в модуле ntoskrnl.exe (микроядро), в пользовательском режиме - в модуле ntdll.dll («родной» API, вызывают int 2E).
|