Аппаратные прерывания. контроллер прерываний

Верхняя половина обработчика прерываний

В прошлой статье мы изучили как установить обработчик прерывания, так что осталось написать саму функцию обработчика.
Прототип функции обработчика прерывания уже показывался выше:

   typedef irqreturn_t (*irq_handler_t)( int irq, void *dev );

где:

  • — линия IRQ;
  • — уникальный указатель экземпляра обработчика
    (который передаётся в последнем параметре вызова при регистрации обработчика).

Это именно та функция, которая в первую очередь будет вызываться (верхняя половина) при каждом возникновении
аппаратного прерывания. Но это вовсе не означает, что при возврате из этой функции работа по обработке текущего
прерывания будет завершена (хотя и такой вариант вполне допустим). Из-за этой «неполноты» такой обработчик и
получил название верхней половины обработчика прерывания. Дальнейшие действия по обработке могут быть
запланированы эти обработчиком на более позднее время, используя несколько различных механизмов, обобщённо
называемых нижняя половина.

Важно то, что код обработчика верхней половины выполняется при запрещённых последующих прерываниях
по этой же линии для задействованного локального процессора. Но после возврата из этой функции локальные
прерывания снова разрешаются

Верхняя половина обработчика прерываний может вернуть одно из значений, объявленных
в файле <linux/irqreturn.h>:

   typedef int irqreturn_t;
   #define IRQ_NONE        (0)
   #define IRQ_HANDLED     (1)
   #define IRQ_RETVAL(x)   ((x) != 0)

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

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

Типичная схема обработчика при этом будет выглядеть как показано ниже:

   static irqreturn_t intr_handler ( int irq, void *dev ) {
        if( ! /* проверка того, что обслуживаемое устройство запросило прерывание*/ )
           return IRQ_NONE;
        /* код обслуживания устройства */
        return IRQ_HANDLED;
   }

Пока мы не углубились в дальнейшую обработку, производимую в нижней половине, хотелось бы отметить,
что в ряде случаев оказывается достаточно простого обработчика верхней половины, и нет необходимости
внедрять сложные механизмами отложенной обработки. Это утверждение будет верным при крайне простой обработке и
отсутствии возможности очень быстрого возникновения повторных прерываний.

Стоит также упомянуть самую большую сложность в программировании функции обработчика.
Код функции ни непосредственно, ни косвенно не имеет права вызывать
функции API ядра, которые вызовут переход выполняющегося кода в блокированное
состояние ожидания ( и др.) или даже только предполагают возможность такого
перехода при некоторых условиях ( и др.)! Это связано с тем, что функция обработчика
верхней половины выполняется в контексте прерывания, и после завершения блокированного ожидания
будет просто некуда возвратиться для продолжения её выполнения. Результатом такого ошибочного вызова
скорее всего станет крах всей операционной системы.

Restrictions

is not supported when compiling with
. This is because of the difference between the
generic ARMv7 architecture and the ARMv7 R- and M-profiles in the exception handling model.
This means that when you compile with , the
compiler is unable to generate an instruction sequence that works on all ARMv7 processors
and therefore is not supported. You can use the function prototype with .
The following example shows the difference between compiling for ARMv7-M
and ARMv7-R:

/* test.c */
DisableIrq()
{
  __disable_irq();
}

DisableIrq2()
{
  return __disable_irq();
}
  DisableIrq
    0x00000000:  b672      r.    CPSID    i
    0x00000002:  4770      pG    BX       lr
  DisableIrq2
    0x00000004:  f3ef8010  ....  MRS      r0,PRIMASK
    0x00000008:  f0000001  ....  AND      r0,r0,#1
    0x0000000c:  b672      r.    CPSID    i
    0x0000000e:  4770      pG    BX       lr
  DisableIrq
    0x00000000:  b672      r.    CPSID    i
    0x00000002:  4770      pG    BX       lr
  DisableIrq2
    0x00000004:  f3ef8000  ....  MRS      r0,APSR ; formerly CPSR
    0x00000008:  f00000080 ....  AND      r0,r0,#0x80
    0x0000000c:  b672      r.    CPSID    i
    0x0000000e:  4770      pG    BX       lr

In all cases, the intrinsic can only be executed in
privileged modes, that is, in non-user modes. In User mode this intrinsic does not change
the interrupt flags in the .

Пример обработчика прерываний

Довольно сложно продемонстрировать работающий код обработчика прерываний, потому что такой код
должен быть связан с реальным аппаратным расширением, и, поэтому будет перенасыщен специфическими
деталями, затемняющими суть происходящего. Но удачный оригинальный пример приведён в уже упоминавшейся
ранее книге «Writing Linux Device Drivers» Джерри Купперстайна (Jerry Cooperstein). Также его можно
найти в архиве IRQ.tgz в разделе «Материалы для скачивания».

Листинг 1. Простейший обработчик прерываний.
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>

#define SHARED_IRQ 17

static int irq = SHARED_IRQ, my_dev_id, irq_counter = 0;
module_param( irq, int, S_IRUGO );

static irqreturn_t my_interrupt( int irq, void *dev_id ) {
   irq_counter++;
   printk( KERN_INFO "In the ISR: counter = %d\n", irq_counter );
   /* IRQ_NONE возвращается так фактически мы только наблюдаем за процессом */
   return IRQ_NONE;
}

static int __init my_init( void ) {
   if ( request_irq( irq, my_interrupt, IRQF_SHARED, "my_interrupt", &my_dev_id ) )
      return -1;
   printk( KERN_INFO "Successfully loading ISR handler on IRQ %d\n", irq );
   return 0;
}

static void __exit my_exit( void ) {
   synchronize_irq( irq );
   free_irq( irq, &my_dev_id );
   printk( KERN_INFO "Successfully unloading, irq_counter = %d\n", irq_counter );
}

module_init( my_init );
module_exit( my_exit );
MODULE_AUTHOR( "Jerry Cooperstein" );
MODULE_DESCRIPTION( "LDD:1.0 s_08/lab1_interrupt.c" );
MODULE_LICENSE( "GPL v2" );

Логика этого примера состоит в том, что обработчик включается в цепочку с другим обработчиком
прерываний, уже существующим в системе. Новый обработчик не нарушает работу существующего и
фактически ничего не делает, только подсчитывает число обработанных прерываний. В оригинале
предлагается опробовать его с установкой на IRQ сетевой платы, но более наглядный результат будет
получен при установке на IRQ клавиатуры (IRQ 1) или мыши (IRQ 12) на интерфейсе PS/2.

 $ cat /proc/interrupts
           CPU0
  0:   20329441          XT-PIC  timer
  1:        423          XT-PIC  i8042
...
$ sudo /sbin/insmod lab1_interrupt.ko irq=1
$ cat /proc/interrupts
           CPU0
  0:   20527017          XT-PIC  timer
  1:        572          XT-PIC  i8042, my_interrupt
...
$ sudo /sbin/rmmod lab1_interrupt
$ dmesg | tail -n5
In the ISR: counter = 33
In the ISR: counter = 34
In the ISR: counter = 35
In the ISR: counter = 36
Successfully unloading, irq_counter = 36
$ cat /proc/interrupts
           CPU0
  0:   20568216          XT-PIC  timer
  1:        622          XT-PIC  i8042
...

Польза этого примера заключается ещё и в том, что на его основе можно начать разработку кода модуля
для любого реального устройства, даже не имея самого устройства, но используя один из штатных существующих
источников прерываний компьютера в качестве имитатора прерываний от отрабатываемого устройства. А позже с минимальными
потерями весь наработанный код переключить на работу с реальной линией прерывания, используемой проектируемым устройством.

1.4. Device Initialization Steps¶

As noted in the introduction, most PCI drivers need the following steps
for device initialization:

The driver can access PCI config space registers at any time.
(Well, almost. When running BIST, config space can go away…but
that will just result in a PCI Bus Master Abort and config reads
will return garbage).

1.4.1. Enable the PCI device

Before touching any device registers, the driver needs to enable
the PCI device by calling . This will:

Note

can fail! Check the return value.

Warning

OS BUG: we don’t check resource allocations before enabling those
resources. The sequence would make more sense if we called
pci_request_resources() before calling .
Currently, the device drivers can’t detect the bug when two
devices have been allocated the same range. This is not a common
problem and unlikely to get fixed soon.

This has been discussed before but not changed as of 2.6.19:
https://lore.kernel.org/r/20060302180025.GC28895@flint.arm.linux.org.uk/

will enable DMA by setting the bus master bit
in the PCI_COMMAND register. It also fixes the latency timer value if
it’s set to something bogus by the BIOS. will
disable DMA by clearing the bus master bit.

If the PCI device can use the PCI Memory-Write-Invalidate transaction,
call . This enables the PCI_COMMAND bit for Mem-Wr-Inval
and also ensures that the cache line size register is set correctly.
Check the return value of as not all architectures
or chip-sets may support Memory-Write-Invalidate. Alternatively,
if Mem-Wr-Inval would be nice to have but is not required, call
to have the system do its best effort at enabling
Mem-Wr-Inval.

1.4.2. Request MMIO/IOP resources

Memory (MMIO), and I/O port addresses should NOT be read directly
from the PCI device config space. Use the values in the pci_dev structure
as the PCI “bus address” might have been remapped to a “host physical”
address by the arch/chip-set specific kernel support.

See Documentation/driver-api/io-mapping.rst for how to access device registers
or device memory.

The device driver needs to call to verify
no other device is already using the same address resource.
Conversely, drivers should call AFTER
calling .
The idea is to prevent two devices colliding on the same address range.

Tip

See OS BUG comment above. Currently (2.6.19), The driver can only
determine MMIO and IO Port resource availability _after_ calling
.

Generic flavors of are request_mem_region()
(for MMIO ranges) and request_region() (for IO Port ranges).
Use these for address resources that are not described by “normal” PCI
BARs.

Also see below.

1.4.3. Set the DMA mask size

Note

If anything below doesn’t make sense, please refer to
Dynamic DMA mapping using the generic device. This section is just a reminder that
drivers need to indicate DMA capabilities of the device and is not
an authoritative source for DMA interfaces.

While all drivers should explicitly indicate the DMA capability
(e.g. 32 or 64 bit) of the PCI bus master, devices with more than
32-bit bus master capability for streaming data need the driver
to “register” this capability by calling pci_set_dma_mask() with
appropriate parameters. In general this allows more efficient DMA
on systems where System RAM exists above 4G _physical_ address.

Drivers for all PCI-X and PCIe compliant devices must call
pci_set_dma_mask() as they are 64-bit DMA devices.

Similarly, drivers must also “register” this capability if the device
can directly address “consistent memory” in System RAM above 4G physical
address by calling pci_set_consistent_dma_mask().
Again, this includes drivers for all PCI-X and PCIe compliant devices.
Many 64-bit “PCI” devices (before PCI-X) and some PCI-X devices are
64-bit DMA capable for payload (“streaming”) data but not control
(“consistent”) data.

1.4.4. Setup shared control data

Once the DMA masks are set, the driver can allocate “consistent” (a.k.a. shared)
memory. See Dynamic DMA mapping using the generic device for a full description of
the DMA APIs. This section is just a reminder that it needs to be done
before enabling DMA on the device.

1.4.5. Initialize device registers

Some drivers will need specific “capability” fields programmed
or other “vendor specific” register initialized or reset.
E.g. clearing pending interrupts.

Программные прерывания

Программное прерывание вызвано либо исключительным состоянием в самом процессоре, либо специальной инструкцией в наборе команд, которая вызывает прерывание, когда инструкция выполняется (см. рисунок 1). Первую часто называют ловушкой или исключением и используют для ошибок или событий, происходящих во время выполнения программы, которые настолько исключительны, что не могут быть обработаны в самой программе. Например, исключение деления на ноль будет выдано, если арифметическо-логическому блоку процессора приказано будет делить число на ноль, поскольку эта инструкция является ошибкой и невозможной. Операционная система поймает это исключение и сможет решить, что с этим делать: как правило, прерывать процесс и отображать соответствующее сообщение об ошибке. Инструкции программного прерывания могут функционировать аналогично вызовам подпрограмм и используются для различных целей, таких как запрос служб от драйверов устройств, например прерывания, отправляемые на контроллер диска и с контролера диска для запроса чтения или записи данных на диск и с диска.

Рисунок 1 – Программное прерывание процесса

Совместимость с Nucleus RTOS

Служебные вызовы Nucleus RTOS API для прерывания

  • управление (активирование/деактивирование) прерыванием (локально и глобально);
  • установка вектора прерывания.
  • создание/удаление высокоуровневых прерываний;
  • активация высокоуровневого прерывания;
  • получение количества высокоуровневых прерываний в приложении (на данный момент);
  • получение указателей на блоки управления всех высокоуровневых прерываний;
  • получение указателей на блоки управления текущего высокоуровневого прерывания;
  • получение информации о высокоуровневом прерывании.

Глобальное управление прерыванием

new_levelNU_DISABLE_INTERRUPTSNU_ENABLE_INTERRUPTSЛокальное управление прерываниемNU_Control_Interrupts()

new_levelNU_DISABLE_INTERRUPTSNU_ENABLE_INTERRUPTSУстановка вектора прерывания

vectornewРегистрация низкоуровневого прерывания

vectorlisr_entryNU_NULLold_lisrNU_SUCCESSNU_INVALID_VECTORNU_NOT_REGISTEREDisr_entryNO_MORE_LISRSСоздание высокоуровневого обработчика прерывания

hisrnamehisr_entryprioritystack_pointerstack_sizeNU_SUCCESSNU_INVALID_HISRNULLNU_INVALID_ENTRYNULLNU_INVALID_PRIORITYNU_INVALID_MEMORYNU_INVALID_SIZEУдаление высокоуровневого обработчика прерывания

hisrNU_SUCCESSNU_INVALID_HISRАктивация высокоуровневого обработчика прерывания

hisrNU_SUCCESSNU_INVALID_HISRПолучение количества высокоуровневых обработчиков прерывания в системе

Получение указателей на блоки управления высокоуровневых обработчиков прерывания

pointer_listNU_HISRmaximum_pointersNU_HISRpointer_listПолучение указателя на текущий высокоуровневый обработчик прерывания

NU_NULLПолучение информации о высокоуровневом обработчике прерываний

hisrnamescheduled_countprioritystack_basestack_sizeminimum_stackNU_SUCCESSNU_INVALID_HISR

Вызовы API из обработчиков прерывания

Служебные вызов API из низкоуровневых обработчиков прерывания

Служебные вызовы API из высокоуровневых обработчиков прерыванияNU_NO_SUSPENDОб авторе:блог Колина

System Wakeup Interrupts, enable_irq_wake() and disable_irq_wake()¶

System wakeup interrupts generally need to be configured to wake up the system
from sleep states, especially if they are used for different purposes (e.g. as
I/O interrupts) in the working state.

That may involve turning on a special signal handling logic within the platform
(such as an SoC) so that signals from a given line are routed in a different way
during system sleep so as to trigger a system wakeup when needed. For example,
the platform may include a dedicated interrupt controller used specifically for
handling system wakeup events. Then, if a given interrupt line is supposed to
wake up the system from sleep sates, the corresponding input of that interrupt
controller needs to be enabled to receive signals from the line in question.
After wakeup, it generally is better to disable that input to prevent the
dedicated controller from triggering interrupts unnecessarily.

The IRQ subsystem provides two helper functions to be used by device drivers for
those purposes. Namely, enable_irq_wake() turns on the platform’s logic for
handling the given IRQ as a system wakeup interrupt line and disable_irq_wake()
turns that logic off.

Calling enable_irq_wake() causes suspend_device_irqs() to treat the given IRQ
in a special way. Namely, the IRQ remains enabled, by on the first interrupt
it will be disabled, marked as pending and “suspended” so that it will be
re-enabled by resume_device_irqs() during the subsequent system resume. Also
the PM core is notified about the event which causes the system suspend in
progress to be aborted (that doesn’t have to happen immediately, but at one
of the points where the suspend thread looks for pending wakeup events).

From the PIC’s perspective

There are actually two PICs on most systems, and each has 8 different inputs, plus one output signal that’s used to tell the CPU that an IRQ occurred. The slave PIC’s output signal is connected to the master PIC’s third input (input #2); so when the slave PIC wants to tell the CPU an interrupt occurred it actually tells the master PIC, and the master PIC tells the CPU. This is called «cascade». The master PIC’s third input is configured for this and not configured as a normal IRQ, which means that IRQ 2 can’t happen.

A device sends a PIC chip an interrupt, and the PIC tells the CPU an interrupt occurred (either directly or indirectly). When the CPU acknowledges the «interrupt occurred» signal, the PIC chip sends the interrupt number (between 00h and FFh, or 0 and 255 decimal) to the CPU. When the system first starts up, IRQs 0 to 7 are set to interrupts 08h to 0Fh, and IRQs 8 to 15 are set to interrupts 70h to 77h. Therefore, for IRQ 6 the PIC would tell the CPU to service INT 0Eh, which presumably has code for interacting with whatever device is connected to the master PIC chip’s «input #6». Of course, there can be trouble when two or more devices share an IRQ; if you wonder how this works, check out Plug and Play. Note that interrupts are handled by priority level: 0, 1, 2, 8, 9, 10, 11, 12, 13, 14, 15, 3, 4, 5, 6, 7. So, if IRQ 8 and IRQ 3 come in simultaneously, IRQ 8 is sent to the CPU. When the CPU finishes handling the interrupt, it tells the PIC that it’s OK to resume sending interrupts:

mov al,20h
out 20h,al

or if the interrupt came from the slave PIC:

mov al, 20h
out A0h, al
out 20h, al

and the PIC sends the interrupt assigned to IRQ 3, which the CPU handles (using the IDT to look up the handler for that interrupt).

Alert readers will notice that the CPU has reserved interrupts 0-31, yet IRQs 0-7 are set to interrupts 08-0Fh. Now the reserved interrupts are called when, for example, a dreadful error has occurred that the OS must handle. Now when the computer first starts up, most errors of this type won’t occur. However, when you enter protected mode (and every OS should use protected mode, real mode is obsolete), these errors may occur at any time, and the OS needs to be able to handle them. How’s the OS going to tell the difference between INT 9, Exception: Coprocessor segment overrun, and INT 9: IRQ 1? Well, it can ask the device whether there is really an interrupt for that device. But this is slow, and hackish, and not all devices are able to do this type of thing. The best way to do it is to tell the PIC to map the IRQs to different interrupts, such as INT 78h-7Fh. For information on this, see the PIC FAQ. Note that IRQs can only be mapped to INTs that are multiples of 08h: 00h-07h, 08h-0Fh, 10h-17h, 17h-1Fh. And you probably want to use 20h-27h, or greater, since 00h-1Fh are reserved by the CPU. Also, each PIC has to be programmed separately. You can tell the Master PIC to map IRQs 0-7 to INTs 20h-27h, but IRQs 8-F will still be INTs 70h-77h, unless you tell the Slave PIC to put them elsewhere as well.

See for detailed information.

Прерывания и их обработка

IRQ

  1. Приостанавливается текущий поток управления, сохраняется контекстная информация для возврата в поток.
  2. Выполняется функция-обработчик (ISR) в контексте отключенных аппаратных прерываний. Обработчик должен выполнить действия, необходимые для данного прерывания.
  3. Оборудованию сообщается, что прерывание обработано. Теперь оно сможет генерировать новые прерывания.
  4. Восстанавливается контекст для выхода из прерывания.
  • Непосредственно ISR, которая вызывается при прерывании, выполняет только самую минимальную работу, которую невозможно отложить на потом: она собирает информацию о прерывании, необходимую для последующей обработки, как-то взаимодействует с аппаратурой, например, блокирует или очищает IRQ от устройства (спасибо jcmvbkbc и Zyoma за ) и планирует вторую часть.
  • Вторая часть, где выполняется основная обработка, запускается уже в другом контексте процессора, где аппаратные прерывания разрешены. Вызов этой части обработчика будет совершен позже.

Tasklet

tasklet

  • tasklet’ы атомарны, так что из них нельзя использовать sleep() и такие примитивы синхронизации, как мьютексы, семафоры и прочее. Но, например, spinlock (крутящуюся или циклическую блокировку) использовать можно;
  • вызываются в более “мягком” контексте, чем ISR. В этом контексте разрешены аппаратные прерывания, которые вытесняют tasklet’ы на время исполнения ISR. В ядре Linux этот контекст зовется softirq, и помимо запуска tasklet’ов, он используется еще несколькими подсистемами;
  • tasklet исполняется на том же ядре, что и планирует его. А точнее, успело запланировать его первым, вызвав softirq, обработчики которого всегда привязаны к вызывающему ядру;
  • разные tasklet’ы могут выполняться параллельно, но при этом сам с собой он одновременно не вызывается, поскольку исполняется только на одном ядре, первым запланировавшим его исполнение;
  • tasklet’ы выполняются по принципу невытесняющего планирования, один за другим, в порядке очереди. Можно планировать с двумя разными приоритетами: normal и high.

<linux/interrupt.h>

TASKLET_STATE_SCHED<linux/list.h>TASKLET_STATE_RUNTASKLET_STATE_SCHED

TASKLET_STATE_RUNв своей статьеinclude/linux/interrupt.hkernel/softirq.c

Продолжение следует

следующей частиP.S. На правах рекламы. Ещё я хочу пригласить всех, кому интересен наш проект, на встречу, организованную codefreeze.ru (анонс на хабре). На ней можно будет пообщаться вживую, задать интересующие вопросы главному злодею abondarev и покритиковать в лицо, в конце концов 🙂

Standard CMOS Features (Стандартные настройки BIOS)

Рис.2: Стандартные настройки BIOS

Date (Дата)

Формат даты: <день недели>, <месяц>, <число>, <год>.

День недели — день недели определяется BIOS по введенной дате; его нельзя изменить непосредственно.

Месяц —  название месяца, с января по декабрь.

Число —  день месяца, от 1 до 31 (или максимального числа дней в месяце).

Год  — год, от 1999 до 2098.

Time (Время)

Формат времени: <часы> <минуты> <секунды>. Время вводится в 24-часовом формате, например, 1 час дня записывается как 13:00:00.

IDE Primary Master, Slave / IDE Secondary Master, Slave (Дисковые накопители IDE)

В этом разделе определяются параметры дисковых накопителей, установленных в компьютере (от С до F). Возможны два варианта задания параметров: автоматически и вручную. При определении вручную параметры накопителя задаёт пользователь, а в автоматическом режиме параметры определяются системой. Имейте в виду, что введенная информация должна соответствовать типу вашего диска.

Если вы укажете неверные сведения, диск не будет нормально работать. При выборе варианта User Туре (Задается пользователем) вам потребуется заполнить приведенные ниже пункты. Введите данные с клавиатуры и нажмите <Enter>. Необходимая информация должна содержаться в документации к жесткому диску или компьютеру.

CYLS — Количество цилиндров

HEADS —  Количество головок

PRECOMP —  Предкомпенсация при записи

LANDZONE — Зона парковки головки

SECTORS  — Количество секторов

Если один из жестких дисков не установлен, выберите пункт NONE и нажмите <Enter>.

Drive А / Drive В (Флоппи-дисководы)

В этом разделе задаются типы флоппи-дисководов А и В, установленных в компьютере. —

None  —  Флоппи-дисковод не установлен360К, 5.25 in. Стандартный 5.25-дюймовый флоппи-дисковод типа PC емкостью 360 Кбайт1.2М, 5.25 in. 5.25-дюймовый флоппи-дисковод типа АТ с высокой плотностью записи емкостью 1,2 Мбайт
(3.5-дюймовый дисковод, если включена поддержка режима 3).720К, 3.5 in. 3.5-дюймовый дисковод с двусторонней записью; емкость 720 Кбайт

1.44М, 3.5 in. 3.5-дюймовый дисковод с двусторонней записью; емкость 1.44 Мбайт

2.88М, 3.5 in. 3.5-дюймовый дисковод с двусторонней записью; емкость 2.88 Мбайт.

Floppy 3 Mode Support (for Japan Area) (Поддержка режима 3 — только для Японии)

Disabled Обычный флоппи-дисковод. (Настройка по умолчанию)Drive А Флоппи-дисковод А поддерживает режим 3.Drive В Флоппи-дисковод В поддерживает режим 3.Both    Флоппи-дисководы А и В поддерживают режим 3.

Halt on (Прерывание загрузки)

Данная настройка определяет, при обнаружении каких ошибок загрузка системы будет остановлена.

NO Errors    Загрузка системы будет продолжена несмотря на любые ошибки. Сообщения об ошибках выводятся на экран.All Errors    Загрузка будет прервана, если BIOS обнаружит любую ошибку.All, But Keyboard    Загрузка будет прервана при любой ошибке, за исключением сбоя клавиатуры. (Настройка по умолчанию)Ail, But Diskette    Загрузка будет прервана при любой ошибке, за исключением сбоя флоппи-дисковода.All, But Disk/Key    Загрузка будет прервана при любой ошибке, за исключением сбоя клавиатуры или диска.

Memory (Память)

В этом пункте выводятся размеры памяти, определяемые BIOS при самотестировании системы. Изменить эти значения вручную нельзя.Base Memory (Базовая память)
При автоматическом самотестировании BIOS определяет объем базовой (или обычной) памяти, установленной в системе.
Если на системной плате установлена память объемом 512 Кбайт, на экран выводится значение 512 К, если же на системной плате установлена память объемом 640 Кбайт или более, выводится значение 640 К.Extended Memory (Расширенная память)
При автоматическом самотестировании BIOS определяет размер установленной в системе расширенной памяти. Расширенная память — это оперативная память с адресами выше 1 Мбайт в системе адресации центрального процессора.

Примеры существующих реализаций с комментариями

Sitara am335x

более известна в составе платы beagleboneРазработчик:Документация: AM335x Sitara Processors Technical Reference Manual Соответствующий ему драйвер gpio:linux/drivers/gpio/gpio-omap.cСоответствующий заголовок:linux/include/linux/platform_data/gpio-omap.hКоличество входов/выходов:Примечание: GPIO_IRQSTATUS_N также используется для IRQ ACK. Управление дребезгом, а так же питанием выходит за рамки данной статьи.

  • Стандартный: Чтение запись регистра полностью по основному адресу
  • Задание и очистка (рекомендуемый производителем): Для задания и очистки соответствующего контакта как выхода используются два соответствующих регистра, то же самое относится к управлению прерываниями.

ep9301

Разработчик:Документация: EP9301 User’s Guide Соответствующий ему драйвер gpio:linux/drivers/gpio/gpio-ep93xx.cСоответствующий заголовок:linux/arch/arm/mach-ep93xx/include/mach/gpio-ep93xx.hКоличество входов/выходов:Примечание: Из них для доступны 7 портов по 8, 8, 1, 2, 3, 2, 4 входов/выходов причем регистрами прерываний обладают только первый, второй и пятый порты.В таблице рассмотрен только порт A.Одной из особенностей ep9301, является то что тип прерываний both на аппаратном уровне не поддерживается, в драйвере происходит переключение в момент срабатывания прерывания. Другая интересная особенность — на порту F каждый контакт имеет свое собственное прерывание.

Bt848

Последний пример: pci плата Bt848, с gpio.Разработчик:Документация: Bt848/848A/849A Соответствующий драйвер gpio:linux/drivers/gpio/gpio-bt8xx.cСоответствующий заголовок:linux/drivers/media/pci/bt8xx/bt848.hКоличество входов/выходов:Bt848 является платой видеозахвата.Поддержки прерываний нет. Всего два регистра — состояние и настройка in/out.

Заключение

С одной стороны, представленная схема достаточно проста, и её вполне достаточно для реализации кода.
С другой стороны, представленный алгоритм кажется громоздким, особенно в сравнении с альтернативными методами,
которые будут рассматриваться далее. Эта сложность во многом объясняется тем, что главная причина использования
отложенных прерываний — их превосходная масштабируемость на несколько процессоров. Это становится
особенно актуально сегодня, когда рядовой настольный компьютер может обладать 8 ядрами, и значимость подобного
масштабирования будет только расти.

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

Похожие темы

  • Обслуживание периферии в коде модулей ядра: Часть 58. Создание «верхней половины» обработчика прерываний.
  • Обслуживание периферии в коде модулей ядра: Часть 60. Тасклеты и очереди отложенных действий
  • Испытайте программное обеспечение от IBM. Загружайте пробные версии, используйте online демо-версии, работайте с продуктами в sandbox или облачной среде. Вам доступны для изучения более 100 продуктов от IBM.
Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock
detector