In the 3.16-RC4 kernel source, the kernel stack size allocated to each process is 8KB. This kernel stack is called the exception stack, when the kernel space of the process is running or the exception handler is executed, the exception stack is used to see the code of the exception stack (include/linux/sched.h):
1 Union thread_union {2 struct Thread_info Thread_info; 3 long stack[thread_size/sizeof(long)]; 4 };
The Thread_size value is 8KB, so the kernel allocates two page box sizes (page box size 4KB) for the process exception stack (kernel stack). In addition, the THREAD_INFO structure of the process is saved at the top of the stack.
In addition, the kernel allocates a hard interrupt stack and a soft interrupt stack for each CPU (both stacks are also kernel stacks), which is used to perform interrupt service routines and the lower half (soft interrupts) and see the Code (ARCH/X86/KERNEL/IRQ_32.C). These two stacks belong to the CPU and are not part of the process, which is different from the exception stack.
1 define_per_cpu (struct irq_stack *, hardirq_stack); 2 define_per_cpu (struct irq_stack *, softirq_stack);
Defines two arrays hardirq_stack and Softirq_stack, each of which corresponds to a CPU, pointing to the CPU's hard interrupt stack or soft interrupt stack. Then look at the struct irq_stack struct (arch/x86/include/asm/processor.h):
1 struct Irq_stack {2 u32 stack[thread_size/sizeof(u32)]; 3 } __aligned (thread_size);
It can be seen that both the hard interrupt stack and the soft interrupt stack are 8KB in size.
When the kernel executes an interrupt handler, the HANDLE_IRQ function is called in the DO_IRQ function, and a stack switch is performed in the HANDLE_IRQ function as follows (ARCH/X86/KERNEL/IRQ_32.C):
1 BOOLHANDLE_IRQ (unsigned IRQ,structPt_regs *regs)2 {3 structIRQ_DESC *desc;4 intoverflow;5 6overflow =Check_stack_overflow ();7 8desc =Irq_to_desc (IRQ);9 if(Unlikely (!desc))Ten return false; One A if(USER_MODE_VM (regs) | |!execute_on_irq_stack (overflow, desc, IRQ)) { - if(Unlikely (overflow)) - Print_stack_overflow (); theDesc->HANDLE_IRQ (IRQ, DESC); - } - - return true; +}
The Execute_on_irq_stack function is executed in line 12th to determine if a stack switch is required, and if not, the if body is executed, that is, the interrupt service routine is executed on the current stack, and if a stack is needed, the if body is not executed. Below is a look at the execute_on_irq_stack Code (ARCH/X86/KERNEL/IRQ_32.C):
1 StaticInlineint2Execute_on_irq_stack (intOverflowstructIrq_desc *desc,intIRQ)3 {4 structIrq_stack *CURSTK, *Irqstk;5U32 *isp, *Prev_esp, Arg1, arg2;6 7CURSTK = (structIrq_stack *) Current_stack ();8IRQSTK =__this_cpu_read (hardirq_stack);9 Ten /* One * This is where we switch to the IRQ stack. However, if we are A * already using the IRQ stack (because we interrupted a HARDIRQ - * Handler) we can ' t do and just has to keep using the - * Current stack (which are the IRQ stack already after all) the */ - if(Unlikely (Curstk = =irqstk)) - return 0; - +ISP = (U32 *) ((Char*) IRQSTK +sizeof(*irqstk)); - + /*Save the next ESP at the bottom of the stack*/ APREV_ESP = (U32 *) Irqstk; at*prev_esp =Current_stack_pointer; - - if(Unlikely (overflow)) - Call_on_stack (Print_stack_overflow, ISP); - -Asmvolatile("Xchgl%%ebx,%%esp \ n" in "Call *%%edi \ n" - "movl%%ebx,%%esp \ n" to:"=a"(ARG1),"=d"(ARG2),"=b"(ISP) +:"0"(IRQ),"1"(DESC),"2"(ISP), - "D"(desc->HANDLE_IRQ) the:"Memory","cc","ecx"); * return 1; $}
Line 7th Gets a pointer to the current stack, the 8th row gets the hard interrupt stack pointer for the local CPU, the 16th line compares the two, and if it is equal, there is no need to switch the stack (indicating that the current stack is the hard interrupt stack and that there is an interrupt in the interrupt handler). If they are not equal, a stack switch is performed, and the 第22-23 row holds the current stack pointer in the stack that will be switched to (to return). 第28-34 line, in the inline assembly to make a stack switch and perform the corresponding interrupt service routine, the 33rd line of the interrupt Service routine function name is stored in%edi, the 29th row jumps to the interrupt service routine.