Linux interrupt implementation method (I): Establishment of Interrupt registration method and abnormal vector table

Source: Internet
Author: User

Linux interrupt implementation method (I): Establishment of Interrupt registration method and abnormal vector table

I have read some articles about Linux interrupt implementation on the internet, and I feel that some of them are very well written. Here I would like to thank them for their selfless efforts, then I want to add my understanding of some problems. Start with function registration.

I. Method of interrupted Registration
In the Linux kernel, The request_irq () function is used to request interruption. The function prototype is defined in kernel/IRQ/manage. C:
Int request_irq (unsigned int IRQ, irq_handler_t handler,
Unsigned long irqflags, const char * devname, void * dev_id)

IRQ is the hardware interrupt number to be applied.
Handler is the interrupt handler registered to the system. It is a callback function. When an interrupt occurs, the system calls this function and the dev_id parameter is passed to it.
Irqflags is the attribute of Interrupt Processing. If ir1__disabled (sa_interrupt in earlier versions, which is not supported by zhon in current version) is set, the interrupt processing program is a fast processing program, when a fast processing program is called, all interrupts are blocked, and the slow processing program is not blocked. If ir1__shared (sa_shirq in earlier versions) is set, multiple devices are interrupted to share the shared information, if irqf_sample_random (sa_sample_random in earlier versions) is set, it contributes to the system entropy and is good for the system to obtain random numbers. (These flags can be used in the same way or)
Dev_id is used when sharing is interrupted. It is usually set to the device structure or null of the device.
Devname: Specifies the interrupt name, which can be seen in CAT/proc/interrupts.
Request_irq () returns 0, indicating success. Returns-inval, indicating that the interrupt number is invalid or the pointer to the processing function is null. Returns-ebusy, indicating that the interrupt is occupied and cannot be shared.

For the example of interrupted registration, you can search for request_irq in the kernel.
In the process of writing the driver, it is easy to get confused about the following:
1. Where is the interrupt vector table? How is it created?
2. How does the system execute the function I have registered from the start of the interruption?
3. How is the interrupt number determined? How can I determine the interrupt number with a sub-interrupt on the hardware?
4. What is the interruption of sharing? What is the role of dev_id?

This article uses the 2.6.26 kernel and the S3C2410 processor as an example to explain these issues.

Ii. Establishment of an abnormal vector table
In most arm V4 and later v4t processors, the interrupt vector table can have two locations: 0 and 0xffff0000. It can be controlled through the V bit (bit [13]) in the C1 register of the CP15 coprocessor. The relationship between V and the interrupt vector table is as follows:
V = 0 ~ 0x00000000 ~ 0x0000001c
V = 1 ~ 0xffff0000 ~ 0xffff001c

ARCH/ARM/MM/proc-arm920.S in

. Section ". Text. init", # alloc, # execinstr
_ Arm920_setup:
...... ORR r0, R0, #0x2100 @... 1... 1... 11... 1

// Bit13 = 1 the base address of the interrupt vector table is 0xffff0000. The R0 value will be paid to C1.

In Linux, the vector table function is:
Init/Main. C-> start_kernel ()-> trap_init ()
Void _ init trap_init (void)
{
Unsigned long vectors = config_vectors_base;
......
Memcpy (void *) vectors, _ vectors_start, _ vectors_end-_ vectors_start );
Memcpy (void *) vectors + 0x200, _ stubs_start, _ stubs_end-_ stubs_start );
....
}

In kernel 2.6.26, config_vectors_base was initially set in the configuration files of various platforms, for example:
ARCH/ARM/configs/s3c2410_defconfig
Config_vectors_base = 0xffff0000
The abnormal vector table is between _ vectors_end and _ vectors_start.
Located in arch/ARM/kernel/entry-armv.S
. Globl _ vectors_start
_ Vectors_start:
SWI sys_error0:
B vector_und + stubs_offset // reset exception:
Ldr pc,. lcvswi + stubs_offset // Unknown command exception:
B vector_pabt + stubs_offset // software interruption exception:
B vector_dabt + stubs_offset // Data Exception:
B vector_addrexcptn + stubs_offset // Reserved:
B vector_irq + stubs_offset // normal interrupt exception:
B vector_fiq + stubs_offset // an exception occurred during the fast interruption:
. Globl _ vectors_end:
_ Vectors_end:
Between _ stubs_end and _ stubs_start is the location for exception handling. Also located in the file ARCH/ARM/kernel/entry-armv.S. Vector_und, vector_pabt, vector_irq, and vector_fiq are all in the middle of them.
The stubs_offset value is as follows:
. Equ stubs_offset, _ vectors_start + 0x200-_ stubs_start
How is stubs_offset determined? (Refer to a detailed explanation on the network)

When the assembler sees the B command, it will convert the tag to the offset (± 32 m) relative to the current PC and write the instruction code. From the code above, we can see that both the interrupt vector table and stubs have moved the code. Therefore, if the interrupt vector table is still written as B vector_irq, the actual execution cannot jump to the vector_irq after the removal, because the original offset is written in the script code, you need to write the offset in the script code as the Offset after moving. We record the IRQ entry address in the interrupt vector table before moving to irq_pc. Its offset in the interrupt vector table is the irq_PC-vectors_start, And the offset of vector_irq In the stubs is the vector_irq-stubs_start, the two offsets remain unchanged before and after the migration. After moving, vectors_start is at 0xffff0000, while stubs_start is at 0xffff0200. Therefore, the offset of the migrated vector_irq to the interrupt entry address in the interrupt vector is, the offset of 200 + vector_irq in stubs minus the offset of the interrupt entry in the vector table, that is, 200 + vector_irq-stubs_start-irq_PC + vectors_start = (vector_irq-irq_PC) + vectors_start + 200-stubs_start, the value in the brackets is actually the vector_irq written in the interrupt vector table. The irq_pc minus the value is completed by the assembler, And the vectors_start + 200-stubs_start following should be stubs_offset, it is actually defined in entry-armv.S as well.

This article from: dz3w. com original URL: http://www.dz3w.com/mcu/linux/0078342.html

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.