Xiao Ming went to BAT Company for an interview.

Interviewer: What’s your name

Xiao Ming: Xiao Ming

Interviewer: What is a clock interrupt?

Xiaoming: It’s just that the watch is broken and won’t run

Interviewer:?? This also line

The interviewer then asks: What if a page-missing interrupt occurs in the clock interrupt handler?

Xiaoming grumbled: zha watch is broken will be short of fluid, this what watch… Hydraulic watches? What kind of oil do you want?

Interviewer: Xiao Ming, get out of here…

If you don’t have a thorough understanding of interrupts and exceptions, you won’t be able to succeed in linux-related development. If you can figure out the ins and outs of this problem, you will have no problem interviewing BAT or other big companies.

Coincidentally, today in the VIP running group of Uncle Benoit, someone asked such a question, in the interrupt handling function ISR, can miss page interrupt occur? What happens when a page miss interrupts?

[If you also want to participate in the VIP running group to communicate with uncle Ben, please click”Read the original“Subscribe to flagship”]

01 What is a page miss interrupt?

First, let’s get two things straight:

  1. One is interruption
  2. The other is a page break

Are they interrupts all the same?

The answer is clearly no. Interrupts and page-missing interrupts are brothers, but not the same person. In most architectures, the Page Fault is actually a Page Fault, which is called “Page Fault”. In fact, the translation of “Page Fault” is more appropriate, otherwise students still naive to think that the Page Fault and ordinary peripheral interrupts are no different.

In ARM32 processor interrupt and exception is divided more clearly, interrupt has IRQ and FIQ interrupt, we often say that the common peripheral interrupt is IRQ interrupt. Exceptions are classified into data abort, undefine abort, and prefetch exceptions. As you can see from the exception direction scale, when interrupts and exceptions occur, their processing entry is different.

When a peripheral interrupt occurs, it is handled like this:

  1. I’m going to go into IRQ’s vector list

  2. The vector_IRQ assembler function saves the current LR and SPSR to the interrupt stack

  3. Switch to the SVC mode

  4. In SVC mode, determine whether the interrupt occurred in kernel or user mode

  5. Save the context at which the interrupt occurred to the kernel stack of the process (SVC mode)

  6. Jump to do_IRQ to execute the interrupt handler

  7. Determine whether preemption is required

  8. Interrupt return

  9. Above is a summary of what happens when an IRQ interrupt occurs, and what happens when the upper part of the IRQ interrupt is handled (we ignore the lower part of the interrupt here). The question that the friend asked this time was that there was a page break at step 6. In the do_IRQ function, the memory is not present, or the page attributes are not correct, which causes a page missing exception.

    After the above analysis, we get to the essence of the problem.

    For the full process of interrupt handling, I recommend you to see Chapter 5.1 of Running Linux Kernel.

                                           **不可以哟**
    Copy the code

Suppose a page miss exception occurs at step 6 of the interrupt process, and you stir up a hornet’s nest by accessing memory that should not be accessed? There are two types of missing page exceptions in ARM processors, one is do_page_fault for the process address space, and the other is do_translation_fault for vMALloc. Vmalloc page break simply copies the page table of init_task into the current process, and we’ll consider the more complex former for now.

First, the assembly code portion of exception handling is similar to that of interrupts, passing through the exception mode stack and then jumping into the kernel stack of the current process. But the exception pattern is different in that the processing is interrupt-enabled and allows sleep and scheduling.

Therefore, when an exception occurs during peripheral interrupt ISR processing, the following situation occurs.

As shown in the figure, the kernel stack of the current process in which the interrupt occurred appears one after the other, with the context at the spot where the interrupt occurred at the top, followed by the do_IRQ stack, followed by the ISR handler for the specific hardware peripherals. Next is the stack box saved when an exception occurs.

Because in the exception handler, it is allowed to open interrupts and sleep, so “nested”, the path is too deep, monkey years to return to the original interrupt context?

As shown in the figure, interrupt A occurs at ① and then saves the context of the scene. Then an exception occurs at ②, and the context of the scene is saved. At ③, an interrupt B occurs, and the context of the interrupt B is saved. \

  1. Suppose that the dispatch occurs when interrupt B returns, then the monkey year can return to the place ③?
  2. Suppose that the scheduling occurred during exception handling, and the same is true, can the monkey years return to ③ here?

When will interrupt A return if the above scenario occurs? Because the interrupt controller is still waiting for a kiss from the debugger, this kiss is called “EOI,” or “end of Interrupt.” Maybe too long to wait for this kiss…

If the above scenario occurs in the clock interrupt, we think about what the consequences will be?

So, to prevent the pitfalls of exception handling, let’s take a look at what restrictions the Linux kernel puts in place.

In the do_page_fault() function, there is an in_atomic() function to determine whether the current context is in the interrupt context. If it is in the interrupt context, it is in do_kernel_fault, usually printing oops.

How does in_atomic() tell if it is currently in an interrupt context?

The main thing here is to determine the preempt_count count in thread_info.

Preempt_count = preempt_count = preempt_count = preempt_count = preempt_count = preempt_count

Does the interrupt handler set the preempt_count count? \

IRQ processing: irq_handle-> gIC_HANDLE_IRq ()-> HANDle_domain_irq ()-> IRq_enter -> _IRq_enter

Now we finally know the HARDIRQ_OFFSET field that sets preempt_count at IRQ intersections.

[For those who are not sure about this part, please see section 5.1.5 of Running the Linux kernel.]

Running Linux community adhere to the original article, original, never reproduced! If you like, remember to tip and forward, thank you!

Subscribe to the running Linux Community flagship video to talk and run with uncle Ben!