Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Некоторые драйверы в режиме ядра, такие как последовательные и параллельные драйверы, не должны быть резидентами памяти, если устройства, которыми они управляют, не открыты. Однако до тех пор, пока существует активное соединение или порт, часть кода драйвера, управляющая этим портом, должна оставаться резидентной для обслуживания устройства. Если порт или подключение не используется, код драйвера не требуется. В отличие от этого, драйвер для диска, содержащего системный код, код приложения или файл системного разбиения на страницы, всегда должен быть резидентом памяти, так как драйвер постоянно передает данные между устройством и системой.
Драйвер для нерегулярно используемого устройства (например, модема) может освободить системное пространство, когда устройство, которым он управляет, неактивно. Если вы разместите в одном разделе код, который должен быть резидентным для обслуживания активного устройства, и если ваш драйвер блокирует код в памяти во время использования устройства, вы можете объявить этот раздел страничным. Когда устройство драйвера открывается, операционная система переносит раздел страницы в память, и драйвер блокирует его до тех пор, пока не не потребуется.
В коде звукового драйвера системы CD используется этот метод. Код драйвера сгруппирован на отдельные секции в соответствии с производителем CD-устройства. Некоторые бренды никогда не могут присутствовать в данной системе. Кроме того, даже если CD-ROM существует в системе, он может использоваться редко, поэтому разбиение кода на страничные секции по типу CD гарантирует, что код для устройств, которые не существуют на конкретном компьютере, никогда не загружается. Однако при доступе к устройству система загружает код для соответствующего cd-устройства. Then the driver calls the MmLockPagableCodeSection routine, as described later in this article, to lock its code into memory while its device is being used.
Чтобы изолировать страничный код в именованном разделе, отметьте его с помощью следующей директивы компилятора:
#pragma alloc_text(PAGE*Xxx***, *RoutineName***)
The name of a pageable code section must start with the four letters "PAGE" and can be followed by up to four characters (represented here as Xxx) to uniquely identify the section. Первые четыре буквы имени раздела (т. е. page) должны быть прописными буквами. The RoutineName identifies an entry point to be included in the pageable section.
Самое короткое допустимое имя для раздела кода с возможностью разбиения на страницы в файле драйвера — это просто PAGE. Например, директива pragma в следующем примере кода идентифицирует RdrCreateConnection как точку входа в разделяемом на страницы разделе кода под названием PAGE.
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, RdrCreateConnection)
#endif
MmLockPagableCodeSection locks in the whole contents of the section that contains the routine referenced in the call. In other words, this call makes every routine associated with the same PAGEXxx identifier resident and locked in memory. In other words, this call makes every routine associated with the same PAGEXxx identifier resident and locked in memory.
MmLockPagableCodeSection returns a handle to be used when unlocking the section (by calling the MmUnlockPagableImageSection routine) or when the driver must lock the section from additional locations in its code.
Драйвер также может рассматривать редко используемые данные как поддающиеся выгрузке в файл подкачки, чтобы их можно было выгрузить, пока поддерживаемое устройство не активно. Например, драйвер системного миксера использует страничные данные. Устройство миксера не имеет с ним связанного асинхронного ввода-вывода, поэтому этот драйвер может сделать свои данные размещаемыми на страницах.
Имя раздела данных, который может использоваться по страницам, должно начинаться с четырех букв "PAGE", за которыми могут следовать до четырех символов для уникальной идентификации раздела. Первые четыре буквы имени раздела (т. е. page) должны быть прописными буквами.
Избегайте назначения идентичных имен разделам кода и данных. Чтобы сделать исходный код более читаемым, разработчики драйверов обычно назначают имя PAGE разделу кода с возможностью страницы, так как это имя короткое, и оно может отображаться в многочисленных директивах pragma alloc_text. Затем более длинные имена назначаются любым разделам данных, которые могут размещаться на страницах (например, PAGEDATA для data_seg, PAGEBSS для bss_seg и т. д.), которые могут понадобиться драйверу.
Например, первые две директивы pragma в следующем примере кода определяют два раздела данных, PAGEDATA и PAGEBSS. PAGEDATA объявляется с помощью директивы pragma data_seg и содержит инициализированные данные. PAGEBSS объявляется с помощью директивы pragma bss_seg и содержит неинициализированные данные.
#pragma data_seg("PAGEDATA")
#pragma bss_seg("PAGEBSS")
INT Variable1 = 1;
INT Variable2;
CHAR Array1[64*1024] = { 0 };
CHAR Array2[64*1024];
#pragma data_seg()
#pragma bss_seg()
В этом примере Variable1 и Array1 явно инициализированы, поэтому они помещаются в раздел PAGEDATA.
Variable2 и Array2 неявно инициализированы и помещаются в раздел PAGEBSS.
Неявно инициализация глобальных переменных до нуля уменьшает размер исполняемого файла на диске и предпочтительнее явной инициализации до нуля. Явные нулевые инициализации следует избегать, за исключением случаев, когда это необходимо для размещения переменной в определенном разделе данных.
To make a data section memory-resident and lock it in memory, a driver calls MmLockPagableDataSection, passing a data item that appears in the pageable data section. MmLockPagableDataSection returns a handle to be used in subsequent locking or unlocking requests.
To restore a locked section's pageable status, call MmUnlockPagableImageSection, passing the handle value returned by MmLockPagableCodeSection or MmLockPagableDataSection, as appropriate. A driver's Unload routine must call MmUnlockPagableImageSection to release each handle it obtains for lockable code and data sections.
Блокировка раздела является дорогой операцией, так как диспетчер памяти должен искать свой загруженный список модулей, прежде чем блокировать страницы в память. If a driver locks a section from many locations in its code, it should use the more efficient MmLockPagableSectionByHandle after its initial call to MmLockPagableXxxSection.
The handle passed to MmLockPagableSectionByHandle is the handle returned by the earlier call to MmLockPagableCodeSection or MmLockPagableDataSection.
The memory manager maintains a count for each section handle and increments this count every time that a driver calls MmLockPagableXxx for that section. A call to MmUnlockPagableImageSection decrements the count. Хотя счетчик для любого дескриптора секции ненулевой, данный раздел остается заблокированным в памяти.
Дескриптор раздела действителен до загрузки драйвера. Therefore, a driver should call MmLockPagableXxxSection only one time. If the driver requires more locking calls, it should use MmLockPagableSectionByHandle.
Если раздел выгружен из памяти при вызове подпрограммы блокировки, менеджер памяти подгружает этот раздел и устанавливает его счетчик ссылок на единицу. If the section is paged out when the lock routine is called, the memory manager pages in the section and sets its reference count to one.
Использование этого метода сводит к минимуму влияние драйвера на системные ресурсы. При запуске драйвера он может заблокировать в памяти код и данные, которые должны быть резидентами. Если для устройства отсутствуют незавершенные запросы ввода-вывода (то есть, когда устройство закрыто или если устройство никогда не было открыто), драйвер может разблокировать тот же код или данные, что делает его доступным для вывода.
Однако после того, как драйвер подключает прерывания, любой код драйвера, который можно вызывать во время обработки прерываний, всегда должен быть резидентом памяти. Хотя некоторые драйверы устройств могут быть странично или загружены в память по требованию, некоторые основные части кода и данных такого драйвера должны быть постоянно резидентными в системном пространстве.
Рассмотрим следующие рекомендации по реализации для блокировки кода или раздела данных.
The primary use of the Mm(Un)LockXxx routines is to enable normally nonpaged code or data to be made pageable and brought in as nonpaged code or data. Драйверы, такие как серийный драйвер и параллельный драйвер, являются хорошими примерами: если на устройстве нет открытых дескрипторов, управляемых драйвером, части кода не требуются и могут оставаться на странице. Средство перенаправления и сервер также являются хорошими примерами драйверов, которые могут использовать этот метод. Если активные подключения отсутствуют, оба этих компонента могут быть выгружены из памяти.
Весь раздел, доступный для страниц, заблокирован в память.
Один раздел кода и один для данных для каждого драйвера является эффективным. Многие именованные разделы, подлежащие выгрузке в память, обычно неэффективны.
Держите отдельными полностью выгружаемые разделы и выгружаемые, но блокируемые по требованию разделы.
Эти подпрограммы могут привести к интенсивному выполнению операций ввода-вывода при загрузке раздела диспетчером памяти. If a driver must lock a section from several locations in its code, it should use MmLockPagableSectionByHandle. If a driver must lock a section from several locations in its code, it should use MmLockPagableSectionByHandle.