Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: По поводу SpinLock  (Прочитано 317 раз)
0 Пользователей и 6 Гостей смотрят эту тему.
WWX
Постоялец

ru
Offline Offline

« : 09-01-2025 14:09 » 

В одном из примеров, прилагаемых к книге У. Они, замечен следующий код:
Код: (C++)
NTSTATUS DispatchControl(PDEVICE_OBJECT fdo, PIRP Irp)
        {
        PAGED_CODE();
...
        KeAcquireSpinLock(&pdx->eventlock, &oldirql);
...
        }
Но в описании ф-ции KeAcquireSpinLock:
The code within a critical region guarded by an spin lock must neither be pageable nor make any references to pageable data.

Вроде бы можно предположить, что часть расположенного после захвата спин-блокировки кода может отсутствовать в памяти. И т. к. IRQL после захвата будет слишком высок для страничного сбоя, то будет просто сбой?
Вероятность этого конечно очень мала, но всё же...

(Скорее всего я что-то упускаю из вида, и хотелось бы понять что именно...)
Записан
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #1 : 10-01-2025 12:01 » 

доброго!
Вообще этого не корректно. в смысле макрос проверки PAGED_CODE() поставлен некорректно...
PAGED_CODE — это контроль того, что функция выполняется на IRQL < DISPATCH_LEVEL, это работает только в checked-версии. просто немного упрощает отлов ошибок, связанных с выполнением кода на недопустимо высоком IRQL. Ну и вообще код более читабельный, видим макрос в начале функции, и ясно, что на DISPATCH_LEVEL ее вызывать не надо.

А главное при компиляции необходимо указать, что функцию DispatchControl() необходимо разместить в nonpaged секции (.text называлась). Делал при помощи #pragma:

Код: (C)
#pragma alloc_text(INIT, DriverEntry)
#pragma alloc_text(PAGE, DriverUnload)
#pragma alloc_text(PAGE, AddDevice)
#pragma alloc_text(PAGE, DispatchSystemControl)
#pragma alloc_text(PAGE, CommonDispatch)
#pragma alloc_text(TEXT, HwInt_01)
последний - как раз размещение функции обработчика прерывания HwInt_01( IN PKINTERRUPT Interrupt,  IN PDEVICE_EXTENSION_MY devExt) в nonpaged секции(.text).
ну и в ключах линкера необходимо так же указать слияние секций...
Код:
 -MERGE:_PAGE=PAGE -MERGE:_TEXT=.text -SECTION:INIT,d 
-MERGE:.rdata=.text -optidata -driver -align:0x20 -osversion:5.00 -subsystem:native,1.10 -driver:WDM -debug:notmapped,MINIMAL
это копипаста из моего старого проекта pci драйвера там помоему в отдельной строке было задано.
вот тут чуть подробнее наверное Блокировка страничного кода или данных на microsoft.com

ЗЫ Making Drivers Pageable
Цитата
By default, the linker assigns names such as ".text" and ".data" to the code and data sections of a driver image file. When the driver is loaded, the I/O manager makes these sections nonpaged. A nonpaged section is always memory-resident.
ЗЗЫ Locking Pageable Code or Data
Цитата
To isolate the pageable code into a named section, mark it with the following compiler directive:

#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. The first four letters of the section name (that is, "PAGE") must be capitalized. The RoutineName identifies an entry point to be included in the pageable section.
« Последнее редактирование: 10-01-2025 12:13 от Ochkarik » Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
WWX
Постоялец

ru
Offline Offline

« Ответ #2 : 10-01-2025 14:45 » 

Ух, большое спасибо за развёрнутый ответ.

Я не указал, что перед этой ф-цией у него стоит директива:
Код: (C++)
#pragma LOCKEDCODE
чем по идее и обеспечивается невыгружаемость; но, похоже, сути дела это не меняет.

На самом деле эта ф-ция, говоря простым языком, – обработчик IOCTL'ов и вызывается, как я понимаю, на уровне PASSIVE_LEVEL.
Т. е. с одной стороны когда управление "проходит" по этому (PAGED_CODE) макросу – IRQL не слишком высокий, но ненадолго повысится вдальнейшем внутри этой ф-ции.
(Похоже что, почти нашёл почти ошибку у самого Они.)

Как я понял по вашим ссылкам, по-умолчанию ф-ция и так размещается в неперемещаемой памяти, если не указывать чего-то вроде:
Код: (C)
#pragma alloc_text(PAGE, DispatchControl)

Правда у меня возникла небольшая параноя:
Если переменная oldirql (в которой сохраняется старый IRQL) объявлена как локальная в этой (DispatchControl) ф-ции (а где бы ей ещё быть?), так вот, если она объявлена как локальная, то может ли так получиться, что на момент вызова
Код: (C++)
KeReleaseSpinLock(..., oldirql);
она (переменная) будет выгружена из памяти?

Т. е. сама ф-ция вроде бы помещается в .text который будет гарантированно в невыгружаемой памяти. А есть ли гарантия, что её локальные данные также будут в невыгружаемой памяти? (Ведь на момент вызова KeReleaseSpinLock – IRQL должен быть DISPATCH_LEVEL.)
Записан
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #3 : 10-01-2025 15:38 » 

WWX, Если переменная объявлена в теле функции - она размещается в стеке (текущего контекста - читай процесса).
А стек.... хороший вопрос.... Стек процесса наверное должен быть в несвопируемой области. По крайней мере пока процесс активен. Тем более он обычно небольшой, три страницы всего...
Using the Kernel Stack
да, вроде пишут что при активном процессе - его стек в памяти. в неактивном - может быть выгружен, но это можно отключить при помощи KeSetKernelStackSwapEnable().
еще вот тут пишут про флаг какой то Disable paging of kernel stacks - FLG_DISABLE_PAGE_KERNEL_STACKS . видимо это какой то флаг, только непонятно чего. процесса наверное? и наверное это не очень хорошая практика.
Цитата
Stack swapping can occur only if the thread is in a wait state that was caused by a request from a user-mode application. Stack swapping never occurs for wait states that are initiated by kernel-mode components, regardless of whether stack swapping is enabled.
« Последнее редактирование: 10-01-2025 15:44 от Ochkarik » Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
WWX
Постоялец

ru
Offline Offline

« Ответ #4 : 14-01-2025 12:54 » 

Ну, то что локальные переменные размещаются на стеке я знал, а вот всё остальное... не знал. Буду знать – одной параноей меньше.
Спасибо в любом случае.
В общем-то иначе вообще не понятно как жить – например, обработчики прерываний (ISR'ы) тогда бы не могли безопасно иметь своих локальных переменных, учитывая на каких IRQL им приходится выполняться.
Насчёт флага, я так понял, что это флаг некоторой тулзы для отладки или типа того... Могу ошибаться...
Записан
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #5 : 14-01-2025 13:15 » new

WWX,
Цитата
To edit the Registry and disable paging kernel-mode stacks

Click Start > Run and type regedit.
In the left pane of the Registry Editor, navigate to HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager.
In the right pane, right‐click GlobalFlag and select Modify.
With Base Hexadecimal, type value 80000, which corresponds to FLG_DISABLE_PAGE_KERNEL_STACKS.
Click OK and exit the Registry Editor.
Reboot the guest system for this change to take effect.
https://learn.microsoft.com/ru-ru/windows-hardware/drivers/debugger/gflags-flag-table
оказывается. чем люблю такие вопросы - сам образовываюсь)))
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines