uawikipc.ru

Об`єкти переривань

Ядро надає стерпний механізм - керуючий об`єкт ядра, званий об`єктом переривання, який дозволяє драйверампристроїв реєструвати процедури обробки переривань (ISR) для своїх пристроїв.

Об`єкт переривання містить всю інформацію, необхідну ядру для того, щоб зв`язати ISR пристрої з конкретним рівнем переривання, включаючи адресу ISR, IRQL-рівень, на якому переривається пристрій, і запис в таблиці диспетчеризації переривань ядра (IDT), з якої потрібно зіставити ISR. При ініціалізації об`єкта переривання в ньому зберігаються кілька інструкцій на мові асемблера, так званий код диспетчеризації, копіюється з шаблону обробки переривання, KiInterruptTemplate. Цей код виконується при виникненні переривання.

Цей резидентний код об`єкта переривання викликає справжній диспетчер переривання, яким зазвичай є або процедура KiInterruptDispatch, або процедура KiChainedDispatch, передаючи йому покажчик на об`єкт переривання.

KiInterruptDispatch є процедурою, використовуваної для векторів переривання, для яких зареєстрований тільки один об`єкт переривання. KiChainedDispatch є процедурою для векторів, спільно використовуваних декількома об`єктами переривань. Об`єкт переривання містить інформацію, яка потрібна цій другій процедурі диспетчера для виявлення і правильного виклику ISR-процедури, що надається драйвером пристрою.

Об`єкт переривання також зберігає в собі IRQL, пов`язаний з перериванням, щоб процедура KiInterruptDispatch або KiChainedDispatch перед викликом ISR змогла підняти IRQL на правильний рівень, а потім, після повернення управління з ISR, відповідним чином знизити IRQL.

Цей процес, що виконується в два етапи, потрібен тому, що при початковій диспетчеризації способів передачі покажчика (або якого-небудь іншого аргументу на цей випадок) об`єкту переривання не існує, оскільки початкова диспетчеризація здійснюється обладнанням. На мультипроцессорной системі ядро виділяє і ініціалізує об`єкт переривання для кожного центрального процесора, дозволяючи локальному APIC цього процесора приймати конкретне переривання.

На Windows-системах x64 ядро оптимізує диспетчер переривань, використовуючи спеціальні процедури, що зберігають цикли процесора, пропускаючи непотрібні функції, наприклад, функцію KiInterruptDispatchNoLock, використовувану для переривань, які не мають пов`язану з ними і керовану ядром спін-блокування (зазвичай використовується драйверами, які вимагають синхронізації з їх ISR-процедурами), і функцію KiInterruptDispatchNoEOI.

Функція KiInterruptDispatchNoEOI використовується для переривань, котрі запрограмували APIC в режим автоматичного завершення переривання - «Auto-End-of-Interrupt» (Auto-EOI), - оскільки контролер переривань пошле сигнал EOI автоматично, ядру не потрібно виконувати додатковий код для самостійного здійснення EOI. І нарешті, саме для переривання профілювання продуктивності (performance / profiling) використовується обробник KiInterruptDispatchLBControl, що підтримує регістр управління останнім умовним переходом Last Branch Control MSR, доступний на сучасних центральних процесорах.

Цей регістр дозволяє ядру відстежувати або зберігати інструкцію умовного переходу при трассіровке- при перериванні ця інформація буде втрачена, оскільки вона не зберігається в контексті регістра звичайного переривання, тому для його збереження повинен бути доданий спеціальний код. Ця функція використовується, наприклад, перериваннями продуктивності і профілювання HAL, в той час як інші процедури переривань HAL користуються «Неблокована» кодом диспетчеризації, оскільки HAL не вимагає від ядра синхронізації з його ISR.

Ще один обробник переривання ядра KiFloatingDispatch використовується для переривань, які потребують збереження стану в форматі числа з плаваючою крапкою. На відміну від коду режиму ядра, яким зазвичай не дозволяється використовувати операції з плаваючою точкою (MMX, SSE, 3DNow!), Оскільки пов`язані з ним регістру не будуть зберігатися при перемиканні контексту, ISR-процедури можуть потребувати використання цих регістрів (наприклад, ISR відеокарти, яка виконує швидку операцію малювання).

При підключенні переривання драйвери можуть встановити аргумент FloatingSave в TRUE, вимагаючи від ядра використання процедури диспетчеризації з числами з плаваючою точкою, яка збереже регістри, що використовуються для цих чисел (це істотно збільшує час обробки переривання). Слід зауважити, що ця функція підтримується тільки на 32-розрядних системах.

На малюнку показана типова схема управління переривань, пов`язаними з об`єктами переривань.

типова-схема-управління-перериваннями

Експеримент: Вивчення внутрішнього устрою переривань

Використовуючи відладчик ядра, можна переглянути деталі об`єкта переривання, включаючи його IRQL, адреса ISR і спеціалізований код диспетчеризації переривання. Спочатку потрібно запустити команду! Idt і виявити запис, що включає посилання на I8042KeyboardInterruptService, ISR-процедуру для PS2-клавіатури:

81: fffffa80045bae10 i8042prt! I8042KeyboardInterruptService (KINTERRUPT fffffa80045bad80)

Для перегляду вмісту об`єкта переривання, пов`язаного з даними перериванням, потрібно запустити команду dt nt! _kinterrupt з адресою, наступним за KINTERRUPT:

lkd> dt nt! _KINTERRUPT fffffa80045bad80

+0x000 Type: 22

+0x002 Size: 160

+0x008 InterruptListEntry: _LIST_ENTRY [0x00000000`00000000 - 0x0]

+0x018 ServiceRoutine: 0xfffff880`0356ca04 unsigned char

i8042prt! I8042KeyboardInterruptService + 0

+0x020 MessageServiceRoutine: (null)

+0x028 MessageIndex: 0

+0x030 ServiceContext: 0xfffffa80`02c839f0

+0x038 SpinLock: 0

+0x040 TickCount: 0

+0x048 ActualLock: 0xfffffa80`02c83b50 -> 0

+0x050 DispatchAddress: 0xfffff800`01a7db90 void nt! KiInterruptDispatch + 0

+0x058 Vector: 0x81

+0x05c Irql: 0x8 ``

+0x05d SynchronizeIrql: 0x9 ``

+0x05e FloatingSave: 0 ``

+0x05f Connected: 0x1 ``

+0x060 Number: 0

+0x064 ShareVector: 0 ``

+0x065 Pad: [3] ""

+0x068 Mode: 1 (Latched)

+0x06c Polarity: 0 (InterruptPolarityUnknown)

+0x070 ServiceCount: 0

+0x074 DispatchCount: 0



+0x078 Rsvd1: 0

+0x080 TrapFrame: 0xfffff800`0185ab00 _KTRAP_FRAME

+0x088 Reserved: (null)

+0x090 DispatchCode: [4] 0x8d485550

В даному прикладі IRQL, який присвоюється Windows переривання, дорівнює 8. Хоча прямого відображення вектора переривання на IRQ немає, Windows відстежує це перетворення при управлінні ресурсами пристрою через механізм так званих арбітрів. Для кожного типу ресурсів арбітр підтримує зв`язок між віртуальним використанням ресурсів (наприклад, вектором переривання) і фізичними ресурсами (наприклад, лінією переривання).

Таким чином можна запросити або кореневої IRQ-арбітр (на системах без ACPI), або ACPI IRQ-арбітр і отримати це відображення.

Для отримання інформації про ACPI IRQ-арбітра потрібно скористатися командою! Apciirqarb:

lkd>! acpiirqarb

Відео: Розробка на Java (весна 2016)

Processor 0 (0, 0):

Device Object: 0000000000000000

Current IDT Allocation:

...

0000000000000081 - 0000000000000081 D fffffa80029b4c20 (i8042prt)

A: 0000000000000000 IRQ: 0

Відео: 5. JAVA. Колекції і параметризація | Технострим

...

Якщо використовується система без ACPI, можна скористатися командою! Arbiter 4 (Цифра 4 змусить відладчик показати тільки IRQ-арбітри):

lkd>! arbiter 4

DEVNODE fffffa80027c6d90 (HTREE ROOT 0)

Interrupt Arbiter "RootIRQ" at fffff80001c82500

Allocated ranges:

0000000000000081 - 0000000000000081 Owner fffffa80029b4c20 (i8042prt)

В обох випадках вам буде надано власник вектора по типу об`єкта пристрою. Потім ви можете скористатися командою! Devobj, щоб отримати в цьому прикладі інформацію про пристрій i8042prt (яке відповідає драйверу PS / 2):

lkd>! devobj fffffa80029b4c20

Device object (fffffa80029b4c20) is for:

00000061 Driver ACPI DriverObject fffffa8002888e70

Current Irp 00000000 RefCount 1 Type 00000032 Flags 00003040

Dacl fffff9a100096a41 DevExt fffffa800299f740 DevObjExt fffffa80029b4d70 DevNode

fffffa80029b54b0

Об`єкт пристрої пов`язаний з вузлом пристрою, що зберігає всі фізичні ресурси цього пристрою.

Тепер за допомогою команди! Devnode можна вивести дамп цих ресурсів і скористатися ключем 6, щоб запросити інформацію про ресурсах:

lkd>! devnode fffffa80029b54b0 6

DevNode 0xfffffa80029b54b0 for PDO 0xfffffa80029b4c20

Parent 0xfffffa800299b390 Sibling 0xfffffa80029b5230 Child 0000000000

InstancePath is "ACPI PNP0303 417aa870d0"

ServiceName is "i8042prt"

...

CmResourceList at 0xfffff8a00185bf40 Version 1.1 Interface 0xf Bus # 0

Entry 0 - Port (0x1) Device Exclusive (0x1)

Flags (0x11) - PORT_MEMORY PORT_IO 16_BIT_DECODE

Range starts at 0x60 for 0x1 bytes

Entry 1 - Port (0x1) Device Exclusive (0x1)

Flags (0x11) - PORT_MEMORY PORT_IO 16_BIT_DECODE

Range starts at 0x64 for 0x1 bytes

Entry 2 - Port (0x1) Device Exclusive (0x1)

Flags (0x11) - PORT_MEMORY PORT_IO 16_BIT_DECODE

Range starts at 0x62 for 0x1 bytes

Entry 3 - Port (0x1) Device Exclusive (0x1)

Flags (0x11) - PORT_MEMORY PORT_IO 16_BIT_DECODE

Range starts at 0x66 for 0x1 bytes

Entry 4 - Interrupt (0x2) Device Exclusive (0x1)

Flags (0x01) - LATCHED

Level 0x1, Vector 0x1, Group 0, Affinity 0xffffffff

Вузол пристрої повідомляє, що у даного пристрою є перелік ресурсів з чотирма записами, одна з яких є записом переривання, відповідного IRQ 1. (Номери рівня і вектора представляють вектор IRQ, а не вектор переривання.) IRQ 1 є традиційним номером PC / ATIRQ, пов`язаним з клавіатурою PS / 2, отже, це цілком очікуване значення. (У USB-клавіатури буде інше переривання.)

На ACPI-системах цю інформацію можна отримати більш легким шляхом, прочитавши розширений висновок раніше поданої команди! Acpiirqarb.

В якості частини свого висновку ця команда показує таблицю відображення IRQ на IDT:

Interrupt Controller (Inputs: 0x0-0x17 Dev: 0000000000000000):

(00) Cur: IDT-a1 Ref-1 edg hi Pos: IDT-00 Ref-0 edg hi

(01) Cur: IDT-81 Ref-1 edg hi Pos: IDT-00 Ref-0 edg hi

(02) Cur: IDT-00 Ref-0 edg hi Pos: IDT-00 Ref-0 edg hi

(03) Cur: IDT-00 Ref-0 edg hi Pos: IDT-00 Ref-0 edg hi

(04) Cur: IDT-00 Ref-0 edg hi Pos: IDT-00 Ref-0 edg hi

(05) Cur: IDT-00 Ref-0 edg hi Pos: IDT-00 Ref-0 edg hi

(06) Cur: IDT-00 Ref-0 edg hi Pos: IDT-00 Ref-0 edg hi

(07) Cur: IDT-00 Ref-0 edg hi Pos: IDT-00 Ref-0 edg hi

(08) Cur: IDT-71 Ref-1 edg hi Pos: IDT-00 Ref-0 edg hi

(09) Cur: IDT-b1 Ref-1 lev hi Pos: IDT-00 Ref-0 edg hi

(0a) Cur: IDT-00 Ref-0 edg hi Pos: IDT-00 Ref-0 edg hi

(0b) Cur: IDT-00 Ref-0 edg hi Pos: IDT-00 Ref-0 edg hi

(0c) Cur: IDT-91 Ref-1 edg hi Pos: IDT-00 Ref-0 edg hi

(0d) Cur: IDT-61 Ref-1 edg hi Pos: IDT-00 Ref-0 edg hi

(0E) Cur: IDT-82 Ref-1 edg hi Pos: IDT-00 Ref-0 edg hi

(0f) Cur: IDT-72 Ref-1 edg hi Pos: IDT-00 Ref-0 edg hi

(10) Cur: IDT-51 Ref-3 lev low Pos: IDT-00 Ref-0 edg hi

(11) Cur: IDT-b2 Ref-1 lev low Pos: IDT-00 Ref-0 edg hi

(12) Cur: IDT-a2 Ref-5 lev low Pos: IDT-00 Ref-0 edg hi

(13) Cur: IDT-92 Ref-1 lev low Pos: IDT-00 Ref-0 edg hi

(14) Cur: IDT-62 Ref-2 lev low Pos: IDT-00 Ref-0 edg hi

(15) Cur: IDT-a3 Ref-2 lev low Pos: IDT-00 Ref-0 edg hi

(16) Cur: IDT-b3 Ref-1 lev low Pos: IDT-00 Ref-0 edg hi

(17) Cur: IDT-52 Ref-1 lev low Pos: IDT-00 Ref-0 edg hi

Як і очікувалося, IRQ 1 пов`язаний з IDT-записом 0x81.

Адреса ISR-процедури для об`єкта переривання зберігається в поле ServiceRoutine (яке команда! Idt показує в своєму висновку), а код переривання, що виконується при його виникненні, зберігається в масиві DispatchCodeв кінці об`єкта переривання. Що зберігається там код переривання запрограмований на створення фрейма системного переривання в стеку і на наступний виклик функції, чию адресу зберігається в поле DispatchAddress (KiInterruptDispatchв даному прикладі), з передачею цієї функції покажчика на об`єкт переривання.

Поділитися в соц мережах:
Схожі
» » Об`єкти переривань