x86 interrupt stacks
PATCH 1/1 x86 interrupt stacks
This applies cleanly againt 2.5.59. It gets rid of the ugly multi-line C macros in entry.S and cleans up the declarations of the interrupt handler functions.
Something in my previous patches was causing faulures with gcc-3.2. I suspect it was one of the functions using regparm(1) and asmlinkage (which implies regparm(0)) at the same time.
Tested:
UP gcc-3.2
SMP gcc-3.2 and 2.95.4
Signature · 2 lines
Dave Hansen [email protected]
arch/i386/Kconfig +5 -0
@@ -368,6 +368,11 @@ depends on MK8 || MPENTIUM4 default y +config X86_CMOV + bool + depends on M686 || MPENTIUMII || MPENTIUMIII || MPENTIUM4 || MK8 || MCRUSOE + default y + config HUGETLB_PAGE bool "Huge TLB Page Support" help
arch/i386/kernel/apic.c +10 -4
@@ -1038,7 +1038,8 @@* interrupt as well. Thus we cannot inline the local irq ... ] */ -void smp_apic_timer_interrupt (struct pt_regs regs) +struct pt_regs *IRQHANDLER (smp_apic_timer_interrupt (struct pt_regs * regs)); +struct pt_regs *smp_apic_timer_interrupt (struct pt_regs * regs) {int cpu =smp_processor_id ();
@@ -1058,14 +1059,16 @@* interrupt lock, which is the WrongThing (tm) to do. */ irq_enter (); -smp_local_timer_interrupt (®s); +smp_local_timer_interrupt (regs);irq_exit (); +return regs; }/* * This interrupt should _never_ happen with our APIC/SMP architecture */ -asmlinkage void smp_spurious_interrupt(void) +struct pt_regs *IRQHANDLER (smp_spurious_interrupt (struct pt_regs * regs)); +struct pt_regs *smp_spurious_interrupt (struct pt_regs * regs) {unsigned long v;
@@ -1083,13 +1086,15 @@printk (KERN_INFO "spurious APIC interrupt on CPU#%d, should never happen.\n" ,smp_processor_id ());irq_exit (); +return regs; }/* * This interrupt should never happen with our APIC/SMP architecture */ -asmlinkage void smp_error_interrupt(void) +struct pt_regs *IRQHANDLER (smp_error_interrupt (struct pt_regs * regs)); +struct pt_regs *smp_error_interrupt (struct pt_regs * regs) {unsigned long v, v1;
@@ -1114,6 +1119,7 @@printk (KERN_INFO "APIC error on CPU%d: %02lx(%02lx)\n" ,smp_processor_id (), v , v1);irq_exit (); +return regs; }/*
arch/i386/kernel/cpu/mcheck/p4.c +3 -1
@@ -61,11 +61,13 @@/* Thermal interrupt handler for this CPU setup */ static void (*vendor_thermal_interrupt)(struct pt_regs *regs) = unexpected_thermal_interrupt; -asmlinkage void smp_thermal_interrupt(struct pt_regs regs) +struct pt_regs *IRQHANDLER (smp_thermal_interrupt (struct pt_regs * regs)); +struct pt_regs *smp_thermal_interrupt (struct pt_regs * regs) {irq_enter ();vendor_thermal_interrupt (®s);irq_exit (); +return regs; }/* P4/Xeon Thermal regulation detect and init */
arch/i386/kernel/entry.S +62 -1
79 lines not on this page · raw message
arch/i386/kernel/init_task.c +4 -0
@@ -13,6 +13,10 @@static struct signal_struct init_signals =INIT_SIGNALS (init_signals);struct mm_struct init_mm =INIT_MM (init_mm); +union thread_union init_irq_union + __attribute__((__section__(".data.init_task"))); + +/* * Initial thread structure. *
arch/i386/kernel/irq.c +5 -4
@@ -311,7 +311,8 @@* SMP cross-CPU interrupts have their own specific * handlers). */ -asmlinkage unsigned int do_IRQ(struct pt_regs regs) +struct pt_regs *IRQHANDLER (do_IRQ (struct pt_regs *regs)); +struct pt_regs *do_IRQ (struct pt_regs *regs) {/* * We ack quickly, we don't want the irq controller
@@ -323,7 +324,7 @@* 0 return value means that this irq is already being * handled by some other CPU. (or is disabled) */ -int irq = regs.orig_eax &0xff ;/* high bits used in ret_from_ code */ +int irq = regs->orig_eax &0xff ;/* high bits used in ret_from_ code */ int cpu =smp_processor_id ();irq_desc_t *desc = irq_desc + irq;struct irqaction * action;
@@ -388,7 +389,7 @@*/ for (;;) {spin_unlock (&desc->lock); -handle_IRQ_event (irq, ®s, action); +handle_IRQ_event (irq, regs, action);spin_lock (&desc->lock);if (likely (!(desc->status &IRQ_PENDING )))
@@ -407,7 +408,7 @@irq_exit (); -return 1 ; +return regs; }/**
arch/i386/kernel/process.c +1 -0
@@ -432,6 +432,7 @@/* never put a printk in __switch_to... printk() calls wake_up*() indirectly */ + next_p->thread_info->irq_stack = prev_p->thread_info->irq_stack;unlazy_fpu (prev_p);/*
arch/i386/kernel/smp.c +9 -3
@@ -305,7 +305,8 @@* 2) Leave the mm if we are in the lazy tlb mode. */ -asmlinkage void smp_invalidate_interrupt (void) +struct pt_regs *IRQHANDLER (smp_invalidate_interrupt (struct pt_regs *regs)); +struct pt_regs *smp_invalidate_interrupt (struct pt_regs *regs) {unsigned long cpu;
@@ -336,6 +337,7 @@ out:put_cpu_no_resched (); +return regs; } static void flush_tlb_others (unsigned long cpumask, struct mm_struct *mm,
@@ -576,12 +578,15 @@* all the work is done automatically when * we return from the interrupt. */ -asmlinkage void smp_reschedule_interrupt(void) +struct pt_regs *IRQHANDLER (smp_reschedule_interrupt (struct pt_regs *regs)); +struct pt_regs *smp_reschedule_interrupt (struct pt_regs *regs) {ack_APIC_irq (); +return regs; } -asmlinkage void smp_call_function_interrupt(void) +struct pt_regs *IRQHANDLER (smp_call_function_interrupt (struct pt_regs *regs)); +struct pt_regs *smp_call_function_interrupt (struct pt_regs *regs) {void (*func) (void *info) = call_data->func;void *info = call_data->info;
@@ -605,5 +610,6 @@mb ();atomic_inc (&call_data->finished); } +return regs; }
arch/i386/kernel/smpboot.c +29 -0
@@ -71,6 +71,11 @@/* Per CPU bogomips and other parameters */ struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned; +/* Per CPU interrupt stacks */ +extern union thread_union init_irq_union; +union thread_union *irq_stacks[NR_CPUS] __cacheline_aligned = + { &init_irq_union, }; +/* Set when the idlers are all forked */ int smp_threads_ready;
@@ -772,6 +777,28 @@ }#endif /* WAKE_SECONDARY_VIA_INIT */ +static void __init setup_irq_stack (struct task_struct *p,int cpu) +{ +unsigned long stk; + + stk =__get_free_pages (GFP_KERNEL ,THREAD_ORDER ); +if (!stk) +panic ("I can't seem to allocate my irq stack. Oh well, giving up." ); + + irq_stacks[cpu] = (void *)stk; +memset (irq_stacks[cpu],0 ,THREAD_SIZE ); + irq_stacks[cpu]->thread_info.cpu = cpu; + irq_stacks[cpu]->thread_info.preempt_count =1 ; +/* interrupts are not preemptable */ + p->thread_info->irq_stack = &irq_stacks[cpu]->thread_info; + +/* If we want to make the irq stack more than one unit +* deep, we can chain then off of the irq_stack pointer +* here. +*/ +} + +extern unsigned long cpu_initialized;static int __init do_boot_cpu (int apicid)
@@ -795,6 +822,8 @@ idle =fork_by_hand ();if (IS_ERR (idle))panic ("failed fork for CPU %d" , cpu); + +setup_irq_stack (idle, cpu);/* * We remove it from the pidhash and the runqueue
include/asm-i386/linkage.h +1 -0
@@ -3,6 +3,7 @@#define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0)))#define FASTCALL (x) x __attribute__((regparm(3))) +#define IRQHANDLER (x) x __attribute__((regparm(1)))#ifdef CONFIG_X86_ALIGNMENT_16 #define __ALIGN .align 16,0x90
include/asm-i386/thread_info.h +16 -12
@@ -30,9 +30,11 @@__s32 preempt_count;/* 0 => preemptable, <0 => BUG */ mm_segment_t addr_limit;/* thread address space: +0 for interrupts: illegal 0-0xBFFFFFFF for user-thead 0-0xFFFFFFFF for kernel-thread */ +struct thread_info *irq_stack;/* pointer to cpu irq stack */ struct restart_block restart_block;__u8 supervisor_stack[0 ];
@@ -47,7 +49,8 @@#define TI_CPU 0x0000000C#define TI_PRE_COUNT 0x00000010#define TI_ADDR_LIMIT 0x00000014 -#define TI_RESTART_BLOCK 0x0000018 +#define TI_IRQ_STACK 0x00000018 +#define TI_RESTART_BLOCK 0x0000022#endif
@@ -63,17 +66,18 @@#ifndef __ASSEMBLY__ -#define INIT_THREAD_INFO (tsk) \ -{ \ - .task = &tsk, \ - .exec_domain = &default_exec_domain, \ - .flags = 0, \ - .cpu = 0, \ - .preempt_count = 1, \ - .addr_limit = KERNEL_DS, \ - .restart_block = { \ - .fn = do_no_restart_syscall, \ - }, \ +#define INIT_THREAD_INFO (tsk) \ +{ \ + .task = &tsk, \ + .exec_domain = &default_exec_domain, \ + .flags = 0, \ + .cpu = 0, \ + .preempt_count = 1, \ + .addr_limit = KERNEL_DS, \ + .irq_stack = &init_irq_union.thread_info, \ + .restart_block = { \ + .fn = do_no_restart_syscall, \ + } \ }#define init_thread_info (init_thread_union.thread_info)