In the linux kernel how to determine whether an interrupt is disabled ? Because enable the interrupt need to balance,if there is api, not irqs_disabled().
Because enable the interrupt need to balance,if I force to enable the kernel will report a warning.I know the depth -- or ++ may be useful.
Every interrupt service routine and every kernel code which disables interrupts is required to reenable interrupts. There should be exactly a one to one ratio.
Reenabling interrupts should not be conditional. If it is, there are some deep problems in the logic of added components.
Related
I try to stop interrupts from user space for a specific isolated core,
so I set CPU affinity:
cpu_set_t set;
CPU_ZERO(&set);
CPU_SET(2, &set);
assert(sched_setaffinity(getpid(),sizeof(set),&set)==0);
and useiopl(3) to execute privileged instruction cli/sti in user space:
iopl(3);
__asm__("cli;");
// busy looping for a while
__asm__("sti;");
and there are two phenomenons I can't explain:
1 cli can't actually stop interrupts (at least not all interrupts), and interrupt, such as LOC (Local Timer Interrupt) comes out every now and then;
I notice lasted kernel patches prevent cli in user space (reference) , but this result can be reproduced in kernel 4.19.0.
2 AFAIK, cli only clear interrupt flag of CPU on which the program is running, but in practice, my whole system is stuck, not responding to my mouse or keyboard.
(2): Many parts of the Linux kernel depend on communicating with other cores, including RCU depending on for each core: run_on(core) and stuff like that. (https://lwn.net/Articles/262464/). Any kernel code doing that will get stuck when this core doesn't respond to the IPI that other cores send to ask the kernel on this core to switch to a certain task, or perhaps to do TLB shootdowns.
I don't know what exact thing would tend to lead to getting stuck, but I don't find it surprising at all that other parts of the kernel are waiting for something that depends on hearing back from the kernel on this core, and that blocks progress of something involved in getting keyboard/mouse events to an X server and to user-space. (Or even to a text console? That might have more hope, fewer layers of software.)
Or it's always possible that some keyboard or mouse interrupts get distributed to this core, and ignored.
As for (1): do you leave the NMI watchdog enabled, or other source of NMIs? That could get the kernel running temporarily in a state where (other?) interrupts are enabled.
I use kernel/nmi_watchdog = 0 in /etc/sysctl.d/99-local.conf to free up an extra perf counter, but the default is enabled.
(cli doesn't stop Non-Maskable Interrupts, as you might guess from the name.)
Other than that guess, I don't know why you'd still be occasional LOCal timer interrupts; maybe someone more familiar with modern x86 interrupts would know.
In the IDT each line has some bits called "DPL" - Descriptor Privileg Level, 0 for kernel and 3 for normal users(maybe there are more levels). I don't understand 2 things:
this is the level required to run the interrupt handler code? or to the trigger the event that leads to it?. because system_call has DPL=3, so in user-mode we can do "int 0x80". but in linux only the kernel handle interrupts, so we can trigger the event but not handle it? even though we have the right CPL.
In linux only the kernel handle interrupts, but when an interrupt(or trap) happens, what get us into the kernel mode?
Sorry for any mistakes, I am new to all this stuff and just trying to learn.
The IDT has 3 types of entries - trap gates, interrupt gates and task gates (which nobody uses). For trap gates and interrupt gates; the entry mostly describes the target CS and EIP of the interrupt handler.
The DPL field in an IDT entry determines the privilege level required to use the gate (or, to switch to the target CS and EIP described by the gate). Software can only use a gate via. a software interrupt (e.g. int 0x80).
For IRQs and exceptions hardware uses the gate and not software. Hardware has no privilege level and is always able to use a gate (regardless of which privilege level software is currently using and regardless of the gate's DPL). This means that IRQ handlers should have DPL=0 (to ensure that software running at CPL=3 can't use them via. software interrupts).
When an interrupt handler is started, the CPU determines if there will be a privilege level change or not (based on the privilege level that was in use beforehand and the target privilege level that's almost always zero) and automatically switches privilege level where necessary. This is what causes the switch to CPL=0. Note: CPU will also switch stacks and save "return SS:ESP" on the new stack if a privilege level change was necessary.
I am going to write a PCIe base serial I/O card driver in Linux.
As per my knowledge through the configuration space, it provides the interrupt line, and through the IRQF_SHARED flag we are able to share the interrupt handler with that corresponding IRQ line.
But my confusion is how can I know which line is shared or not shared?
For a device driver, there is no useful way (and especially no portable way) to find out if the interrupt line is actually shared, and this could change at any time by loading/unloading other drivers.
PCI drivers must always assume that their interrupt might be shared.
Note: PCI Express devices are supposed to support MSIs (message-signaled interrupts), which are never shared.
Your driver should enable MSIs if at all possible.
However, it is not guaranteeed that the system supports them.
Kernel-assisted probing
The Linux kernel offers a low-level facility for probing the interrupt number. It works
for only nonshared interrupts, but most hardware that is capable of working in a
shared interrupt mode provides better ways of finding the configured interrupt num-
ber anyway. The facility consists of two functions, declared in <linux/interrupt.h>
(which also describes the probing machinery):
unsigned long probe_irq_on(void);
This function returns a bit mask of unassigned interrupts. The driver must pre-
serve the returned bit mask, and pass it to probe_irq_off later. After this call, the
driver should arrange for its device to generate at least one interrupt.
int probe_irq_off(unsigned long);
After the device has requested an interrupt, the driver calls this function, passing
as its argument the bit mask previously returned by probe_irq_on. probe_irq_off
returns the number of the interrupt that was issued after “probe_on.” If no inter-
rupts occurred, 0 is returned (therefore, IRQ 0 can’t be probed for, but no cus-
tom device can use it on any of the supported architectures anyway). If more than
one interrupt occurred (ambiguous detection), probe_irq_off returns a negative
value.
The programmer should be careful to enable interrupts on the device after the call to
probe_irq_on and to disable them before calling probe_irq_off. Additionally, you
must remember to service the pending interrupt in your device after probe_irq_off.
Run cat /proc/interrupt. In the rightmost column of the output you should see your device on one of the interrupts lines. If it's shared you'll see other devices assigned to that interrupt as well.
I'm using the Luminary LM3S8962 micro-controller and its included Library Guide, but this should be relevant to any ARM Cortex-M3s that have Nested Vector Interrupts.
You can only register one interrupt service routine function with an entire GPIO Port. A GPIO port typically has 8 pins on it, each of which can be configured with an interrupt. For each pin, you can test whether or not an interrupt "happened" on it (is pending), right? and for each pin you can clear a pending interrupt, right?
If a pin on the GPIO port triggers the ISR then the processor is in the ISR. Then what happens if another pin on the same port triggers an interrupt while we're in the ISR? We assume the code detects what pins have pending interrupts.
- Is this ISR interrupted and a new one begins, with the same code, but an updated PinInterruptStatus register ? (I hope not)
- Is this ISR executed until completion, immediately executing the interrupt for the other pin right afterward? (I know ARM Cortex M3 implements tail-chaining of interrupts)
- Or must there be a while loop that loops until all the pins have been cleared, clearing a pin after it has been processed?
maybe this will help:
http://www.ti.com/lit/gpn/lm3s8962
As stated in the comment: generally ISRs should take steps to prevent reentrancy. In something like a PIC, this could be as simple as disabling the interrupt at the "top" of the ISR, and enabling the interrupt at the "bottom". The M3's NVIC is a bit more complicated. This white paper (http://www.arm.com/files/pdf/IntroToCortex-M3.pdf) states the following on p.7:
The NVIC supports nesting (stacking) of interrupts, allowing an
interrupt to be serviced earlier by exerting higher priority. It also
supports dynamic reprioritisation of interrupts. Priority levels can
be changed by software during run time. Interrupts that are being
serviced are blocked from further activation until the interrupt
service routine is completed, so their priority can be changed without
risk of accidental re-entry.
The above discussion directly addresses the possibility of same interrupt reentrancy, and it also introduces the concept of prioritization to handle interrupts of higher priority interrupting your ISR.
This reference is pretty good: http://infocenter.arm.com/help/topic/com.arm.doc.dui0552a/DUI0552A_cortex_m3_dgug.pdf. On p. 4-9, you'll find instructions to enable/disable interrupts. On page 4-6, you'll find a description of the Interrupt Clear-pending Registers. Using these, you can determine what interrupts are pending. If you really want to get fancy with interrupt enable/disable control, check out the BASEPRI and BASEPRO_MAX registers.
Having said that, I'm not sure I agree with your statement that your question is relevant to any Cortex-M3. Keil (my flavor of Cortex-M3) mentions that the EXTI (external interrupt controller) handles GPIO pin interrupts. Interestingly, the ARM documentation briefly discusses "EXTI", but does not refer to it as a "controller" like the Keil STM32 documentation. A quick google on "STM32 EXTI" yeilds lots of hits, a similar search on "Luminary EXTI" does not yield much. Given that, I'm guessing that this particular controller is one of the peripheral devices that ARM leaves to 3rd parties.
This document
bolsters that view: http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/REFERENCE_MANUAL/CD00171190.pdf. There are several AFIO_EXTI registers mentioned here. These permit the mapping of GPIO lines to interrupts. Unfortunately, I can't find anything similar in the Luminary documentation.
So...what does this mean? It looks like you only have port-level granularity for your interrupt. Thus, your ISR will have to determine which pin transitioned (assuming your are looking for edges). Good luck!
In Cortex-M3, if two interrupts are the same priority (for all GPIO pins), the former will not be interrupted. The interrupt comes later will be in pending state.
When a GPIO interrupt occurs you can check the GPIO Interrupt Status for Rising/Falling IO0IntEnR/IO0IntEnF (depending on ) for the corresponding bit to find the pin that causes the interrupt.
In Linux, what are the options for handling device interrupts in user space code rather than in kernel space?
Experience tells it is possible to write good and stable user-space drivers for almost any PCI adapter. It just requires some sophistication and a small proxying layer in the kernel. UIO is a step in that direction, but If you want to correctly handle interrupts in user-space then UIO might not be enough, for example if the device doesn't support the PCI-spec's interrupt disable bit which UIO relies on.
Notice that process wakeup latencies are a few microsecs so if your implementation requires very low latency then user-space might be a drag on it.
If I were to implement a user-space driver, I would reduce the kernel ISR to just a "disable & ack & wakeup-userpace" operation, handle the interrupt inside the waked-up process, and then re-enable the interrupt (of course, by writing to mapped PCI memory from the userspace process).
There is Userspace I/O system (UIO), but handling should still be done in kernelspace. OTOH, if you just need to notice the interrupt, you don't need the kernel part.
You may like to take a look at CHAPTER 10: Interrupt Handling from Linux Device Drivers, Third Edition book.
Have to trigger userland code indirectly.
Kernel ISR indicates interrupt by writing file / setting register / signalling. User space application polls this and goes on with the appropriate code.
Edge cases: more or less interrupts than expected (time out / too many interrupts per time interval)
Linux file abstraction is used to connect kernel and user space. This is performed by character devices and ioctl() calls. Some may prefer sysfs entries for this purpose.
This can look odd because event triggered device notifications (interrupts) are hooked with 'time triggered' polling, but it is actually asyncronous blocking (read/select). Anyway some questions are arising according to performance.
So interrupts cannot be directly handled outside the kernel.
E.g. shared memory can be in user space and with some I/O permission settings addresses can be mapped, so U-I/O works, but not for direct interrupt handling.
I have found only one 'minority report' in topic vfio (http://lxr.free-electrons.com/source/Documentation/vfio.txt):
https://stackoverflow.com/a/21197797/5349798
Similar questions:
Running user thread in context of an interrupt in linux
Is it possible in linux to register a interrupt handler from any user-space program?
Linux Kernel: invoke call back function in user space from kernel space
Linux Interrupt vs. Polling
Linux user space PCI driver
How do I inform a user space application that the driver has received an interrupt in linux?