информационная безопасность
без паники и всерьез
 подробно о проектеRambler's Top100
Портрет посетителяСетевые кракеры и правда о деле Левина
BugTraq.Ru
Русский BugTraq
 Анализ криптографических сетевых... 
 Модель надежности двухузлового... 
 Специальные марковские модели надежности... 
 Бэкдор в xz/liblzma, предназначенный... 
 Три миллиона электронных замков... 
 Doom на газонокосилках 
главная обзор RSN блог библиотека закон бред форум dnet о проекте
bugtraq.ru / форум / programming
Имя Пароль
ФОРУМ
если вы видите этот текст, отключите в настройках форума использование JavaScript
регистрация





Легенда:
  новое сообщение
  закрытая нитка
  новое сообщение
  в закрытой нитке
  старое сообщение
  • Напоминаю, что масса вопросов по функционированию форума снимается после прочтения его описания.
  • Новичкам также крайне полезно ознакомиться с данным документом.
Все несколько сложнее, но уже работает 24.06.04 13:17  Число просмотров: 1737
Автор: leo <Леонид Юрьев> Статус: Elderman
Отредактировано 24.06.04 17:24  Количество правок: 2
<"чистая" ссылка>
Все несколько сложнее. KeStallExecutionProcessor() просто старается приостановить текущий CPU на заданное количество микросекунд. А мне нужна пауза при запрещенных прерываниях, поэтому проше просто запретить прерывания и зациклить "не нужные" процессоры while(flag != done){DoCpuPause();}. Реализация самой паузы тривиальна, самое главное войти в режим паузы, тут и начинаются хитрости.

Сложность в том, что прерывания нужно запрещать синхронно и одновременно на всех процессорах, либо использовать IPI для взаимодействия между CPU. Само ядро конечно использует второй вариант, но мне IPI не доступен.

Одновременно запрещать прерывания (cli) нужно потому, что обработка прерывания на одном процессоре может потребовать IPI-обращения к другому. Например для постановки DPC в очередь или для вызова обработчита прерывания драйвера устройства. Кроме того, постановка моих "пусковых" DPC в очередь также требует IPI. Если при этом на "другом" процессоре прерывания уже запрещены, то IPI-запрос не будет обслуживаться, а первый процессор будет ждать сего факта (причем в это время на нём самом прерывания уже будут запрещены). В итоге cli на одном процессоре может легко остановить всё остальное.

Запретить прерывания на всех CPU одновременно конечно невозможно, но можно организовать кратковременное ожидание факта выполения всеми CPU нужного кода при cli. И соответственно повтор неудачных попыток. Вот так сейчас и работает, см. картинку.

Еще одна хитрость в том, что пользоваться штатным отладчиком нельзя. Даже просто вызов DbgPrint() может намертво завесить систему. Работать может только а-ля softice с аппаратным прицепом.

итоговая DPC-функция
<programming>
w2k-kernel, блокировка прерываний на всех cpu для smp 22.06.04 15:05  
Автор: leo <Леонид Юрьев> Статус: Elderman
<"чистая" ссылка>
--- Прошу прощенья за кросс-постинг, но в [hacking] многие не заглядывают.

Нужно пройтись по регистрам чипсета, поэтому необходимо заблокировать прерывания на всех процессорах. На SMP-системах это не совсем просто...

Я пока сделал через interlocked-зацикливание в DPC, на "идеальном" SMP это всегда работаеет. Но на многих SMP-системах не каждый процессор может непосредственно послать IPI (поставить DPC в очередь) к любому другому, и в результате система может зациклиться.

Кто-нибудь знает про готовые решения?

    // мой код пока примерно такой:

    class TSingleProcessorMode
    {
        KDPC DpcTraps[MAXIMUM_PROCESSORS];
        volatile LONG Stall;
        KIRQL SavedIrql;
        CCHAR CpuCount;
        KPRIORITY SavedPriority;
        static void DpcRoutine(KDPC *pDpc, void *pContext, void *pArg1, void *pArg2);
    public:
        void Initialize();
        void Enter();
        void Exit();
    };

    void TSingleProcessorMode::Initialize()
    {
        RtlZeroMemory(this, sizeof(TSingleProcessorMode));
        CpuCount = (CCHAR) GetNumberOfProcessors();
        if(CpuCount > 1)
        {
            for(CCHAR i = 0; i < CpuCount; i++)
            {
                KeInitializeDpc(&DpcTraps[i], DpcRoutine, this);
                KeSetImportanceDpc(&DpcTraps[i], LowImportance);
                KeSetTargetProcessorDpc(&DpcTraps[i], i);
            }
        }
    }

    void TSingleProcessorMode::DpcRoutine(KDPC *pDpc, void *pContext, void *pArg1, void *pArg2)
    {
        TSingleProcessorMode *pThis = (TSingleProcessorMode *) pContext;

        InterlockedDecrement(&pThis->Stall);
        do
            __Crt::ProcessorPause();
        while(pThis->Stall > 0);

        if(pThis->Stall >= 0)
        {
            KIRQL Irql;
            KeRaiseIrql(HIGH_LEVEL, &Irql);
            DbgPrint("SingleProcessorMode: cpu %d stalled\n", KeGetCurrentProcessorNumber());
            do
                __Crt::ProcessorPause();
            while(pThis->Stall >= 0);
            KeLowerIrql(Irql);
        }
    }

    void TSingleProcessorMode::Enter()
    {
        DbgPrint("SingleProcessorMode: entering\n");
        if(CpuCount > 1)
        {
            SavedPriority = KeSetPriorityThread(KeGetCurrentThread(), HIGH_PRIORITY);
            KAFFINITY ActiveProcessors = KeQueryActiveProcessors();
            KeRaiseIrql(DISPATCH_LEVEL, &SavedIrql);
            CCHAR CurrentProcessor = (CCHAR) KeGetCurrentProcessorNumber();
            Stall = 1;
            for(CCHAR i = CpuCount - 1; i >= 0; i--)
                if(i != CurrentProcessor && (ActiveProcessors & (1u << i)) != 0)
                {
                    InterlockedIncrement(&Stall);
                    KeInsertQueueDpc(&DpcTraps[i], 0, 0);
                }
            KeLowerIrql(SavedIrql);
            InterlockedDecrement(&Stall);
            __Crt::ProcessorPause();
            KeRaiseIrql(HIGH_LEVEL, &SavedIrql);
            if(Stall > 0)
            {
                DbgPrint("SingleProcessorMode: wait for %d cpu\n", Stall);
                KeLowerIrql(SavedIrql);
                do
                    __Crt::ProcessorPause();
                while(Stall > 0);
                KeRaiseIrql(HIGH_LEVEL, &SavedIrql);
            }
        }
        else
            KeRaiseIrql(HIGH_LEVEL, &SavedIrql);
    }

    void TSingleProcessorMode::Exit()
    {
        if(CpuCount > 1)
        {
            InterlockedExchange(&Stall, -1);
            KeLowerIrql(SavedIrql);
            KeSetPriorityThread(KeGetCurrentThread(), SavedPriority);
        }
        else
            KeLowerIrql(SavedIrql);
        DbgPrint("SingleProcessorMode: exit\n");
    }

---
Я могу ошибаться, но если я правильно понял, то достаточно... 09.07.04 14:38  
Автор: maggres Статус: Незарегистрированный пользователь
<"чистая" ссылка>
> --- Прошу прощенья за кросс-постинг, но в [hacking] многие
> не заглядывают.
>
> Нужно пройтись по регистрам чипсета, поэтому необходимо
> заблокировать прерывания на всех процессорах. На
> SMP-системах это не совсем просто...
>
> Я пока сделал через interlocked-зацикливание в DPC, на
> "идеальном" SMP это всегда работаеет. Но на многих
> SMP-системах не каждый процессор может непосредственно
> послать IPI (поставить DPC в очередь) к любому другому, и в
> результате система может зациклиться.
>
> Кто-нибудь знает про готовые решения?
Я могу ошибаться, но если я правильно понял, то достаточно поднять IRQL(Level) до необходимого тебе уровня тогда все прерывания приоритетом ниже буду заблокированны.
Если поднять irql до high_level на всех процессорах - то... 09.07.04 14:58  
Автор: leo <Леонид Юрьев> Статус: Elderman
<"чистая" ссылка>
> Я могу ошибаться, но если я правильно понял, то достаточно
> поднять IRQL(Level) до необходимого тебе уровня тогда все
> прерывания приоритетом ниже буду заблокированны.

Если поднять IRQL до HIGH_LEVEL на всех процессорах - то конечно да. Но KeRaiseIrql() делает это только для текущего процессора. Поэтому для UP проблем нет никаких, а на MP совсем не просто.

Блокировка прерываний броликует и IPI (Inter-Processor Interrupt), поэтому "общение" между процессорами тоже блокируется. Заблокировать прерывания одновременно на всех CPU не возможно в принципе, а обработка прерывания на одном процессоре может потребовать IPI к другому. Об этом я уже писал в других постах.
надо создать нужное число потоков (по количеству... 10.07.04 19:57  
Автор: cb <cb> Статус: Member
Отредактировано 10.07.04 19:59  Количество правок: 1
<"чистая" ссылка>
> Если поднять IRQL до HIGH_LEVEL на всех процессорах - то
> конечно да. Но KeRaiseIrql() делает это только для текущего
> процессора. Поэтому для UP проблем нет никаких, а на MP
> совсем не просто.

надо создать нужное число потоков (по количеству процессоров) с такими affinity mask чтобы каждый из них выполнялся на своем процессоре после чего синхронно поднять на них irql до нужного уровня. один из потоков нагрузить еще и бизнес логикой - после поднятия irql выполнить то что тебе надо... мне попадалась когда-то реализация этой идеи...

cb.
имхо на threads хуже чем на dpc 10.07.04 20:17  
Автор: leo <Леонид Юрьев> Статус: Elderman
Отредактировано 10.07.04 20:20  Количество правок: 1
<"чистая" ссылка>
> надо создать нужное число потоков (по количеству
> процессоров) с такими affinity mask чтобы каждый из них
> выполнялся на своем процессоре после чего синхронно поднять
> на них irql до нужного уровня. один из потоков нагрузить
> еще и бизнес логикой - после поднятия irql выполнить то что
> тебе надо... мне попадалась когда-то реализация этой
> идеи...

Во-первых создавать несколько threads - довольно ресурсоёмкая задача. Во-вторых, affinity в user-mode не совсем тоже самое что в kernel-mode. Через документированные функции affininy для kernel-thread не поставить... На ядре с realtime можно нарваться на bugcheck. А самое главное - это никак не решает проблему с необходимой синхронностью блокировки прерываний.

Поэтому я остановился на DPC. Пока работает без проблем, недостаток только один - немаленькая (100-1000 loops) interlocked-вертушка при блокировки прерываний. Но имхо по-другому без доступа к IPI никак.
да. 10.07.04 21:45  
Автор: cb <cb> Статус: Member
Отредактировано 10.07.04 22:01  Количество правок: 1
<"чистая" ссылка>
> Во-первых создавать несколько threads - довольно
> ресурсоёмкая задача.

да.
возможно что та реализация которую я когда то видел использовала именно dpc - я просто уже не помню...

> Во-вторых, affinity в user-mode не
> совсем тоже самое что в kernel-mode.

это как минимум странно. что же это означает в km?

> Через документированные функции affininy для kernel-thread не
> поставить...

вполне вероятно.
однако требование документированности при подобной задаче можно не учитывать.

> А самое главное - это никак не решает проблему с
> необходимой синхронностью блокировки прерываний.

видимо я не очень правильно понял Вашу задачу (невнимательно прочел исходное сообщение). наверное в данном случае Ваше решение более правильно.

cb.
km affinity 12.07.04 14:26  
Автор: leo <Леонид Юрьев> Статус: Elderman
<"чистая" ссылка>
Существует два поля affinity, одно um другое km. Насколько я понял (но не проверял) um affinity не учитывается при переключении контекстов в km, если не задано km-affinity.

ZwSetInformationThread() и KeSetAffinityThread() ставят um-affinity учитывая process-affinity для процесса данного thread. Именно KeSetAffinityThread() вызывает KeBugCheck(INVALID_AFFINITY_SET).

Еще есть KeSetSystemAffinityThread() и KeRevertToUserAffinityThread().
А если остановить «ненужные» процессоры через HAL.KeStallExecutionProcessor(), а дальше делать, как обычно? 23.06.04 16:06  
Автор: HandleX <Александр М.> Статус: The Elderman
Отредактировано 23.06.04 16:10  Количество правок: 1
<"чистая" ссылка>
Все несколько сложнее, но уже работает 24.06.04 13:17  
Автор: leo <Леонид Юрьев> Статус: Elderman
Отредактировано 24.06.04 17:24  Количество правок: 2
<"чистая" ссылка>
Все несколько сложнее. KeStallExecutionProcessor() просто старается приостановить текущий CPU на заданное количество микросекунд. А мне нужна пауза при запрещенных прерываниях, поэтому проше просто запретить прерывания и зациклить "не нужные" процессоры while(flag != done){DoCpuPause();}. Реализация самой паузы тривиальна, самое главное войти в режим паузы, тут и начинаются хитрости.

Сложность в том, что прерывания нужно запрещать синхронно и одновременно на всех процессорах, либо использовать IPI для взаимодействия между CPU. Само ядро конечно использует второй вариант, но мне IPI не доступен.

Одновременно запрещать прерывания (cli) нужно потому, что обработка прерывания на одном процессоре может потребовать IPI-обращения к другому. Например для постановки DPC в очередь или для вызова обработчита прерывания драйвера устройства. Кроме того, постановка моих "пусковых" DPC в очередь также требует IPI. Если при этом на "другом" процессоре прерывания уже запрещены, то IPI-запрос не будет обслуживаться, а первый процессор будет ждать сего факта (причем в это время на нём самом прерывания уже будут запрещены). В итоге cli на одном процессоре может легко остановить всё остальное.

Запретить прерывания на всех CPU одновременно конечно невозможно, но можно организовать кратковременное ожидание факта выполения всеми CPU нужного кода при cli. И соответственно повтор неудачных попыток. Вот так сейчас и работает, см. картинку.

Еще одна хитрость в том, что пользоваться штатным отладчиком нельзя. Даже просто вызов DbgPrint() может намертво завесить систему. Работать может только а-ля softice с аппаратным прицепом.

итоговая DPC-функция
1




Rambler's Top100
Рейтинг@Mail.ru


  Copyright © 2001-2024 Dmitry Leonov   Page build time: 0 s   Design: Vadim Derkach